자바 데이터 타입, 변수 그리고 배열 

반응형
반응형

 

프리미티브 타입 종류와 값의 범위 그리고 기본 값

프리미티브 타입은 기본값 타입으로 불립니다.
종류는 크게 정수타입, 실수타입, 불리언타입으로 나눠져있습니다.
정수형에는 byte,short,int,long,char으로 구성되어 있습니다. 어쨰서 정수형에는 종류가 저렿게 많을까요? 그전에 char형에 대해 소개하고 넘어 가겠습니다.

 

char형은 문자코드 값으로 입력되기 때문입니다. 자바에서는 문자코드를 유니코드로 사용한다고 합니다. 메모리에 할당되는 값은  16비트라고 합니다. 유니코드는 0 ~ 65535까지 할당된다고 합니다.

어째서 자바는 유니코드를 사용하는 걸까요? 

출처 : https://whatisthenext.tistory.com/103

d2.naver.com/helloworld/76650

결국, 다른 언어또한 지원하기 위해 이와 같은 선택을 했다고 할 수 있겠군요.

이제 다른 정수형인 byte,short,int,long에 대해 이야기해봅시다. 이들의 가장 큰 차이점은 바로 크기입니다. 위에서 char형이 크기가 16비트라고 했는것이 기억하시나요?

네 맞습니다. 크기와 관련이 있습니다.

그림을 보시면 각각 크기를 확인할 수 있습니다.(기본형이 아니라 참조형을 사용하는 이유는 기본형자체에는 메소드를 호출하는 기능이 없기 때문에 이들을 깜싸는 참조형으로 대체하였습니다.)

근데 의문이 생깁니다. 이렇게 나누는것은 알겠는데 어째서 이렇게 나눌까요? 그냥 엄청큰 숫자까지 받게 하면 편하지 않나 라는 생각이 들 수 있습니다. 예를 들어, 1000조처럼 큰 숫자말이죠.

그 이유는 메모리 때문입니다. 내가 사용하는 정수는 100이 최대 수인데 굳이 더 큰 자료형을 사용할 이유는 없습니다. 100정도면 byte로 해도 충분합니다. 굳이 다른 자료형을 이용할 이유가 없습니다. 다른 자료형을 사용하게 되면 쓸데없이 메모리를 사용하게 됩니다. 하지만 애초에 byte와 short는 잘 이용하지 않습니다. 이들의 범위는 실 생활에 사용하기에는 너무 범위가 작고 int를 사용해도 그렇게 까지 메모리낭비가 없기 때문이죠.(과거에는 메모리 속도 문제로 맞춰서 사용해야한다고 얼핏 들은적이 있네요.;;)  일반적으로 자바에서 정수형을 사용한다고 한다면 int를 사용합니다.

결국, 자바에서 정수형의 기본형은 int라고 말할 수 있습니다. 큰 범위가 필요하면 long을 사용하고 평소에는 int를 사용하면 되기 때문입니다. long을 사용할때는 

long a = 10L;

L을 붙여서 사용하기도 합니다.

다음 글을 읽으시면 이에 대한 내용을 확인 할 수 있을 것 같습니다.

 

[자바 강의]3-2 접미사 L,F

3.상수3-2 접미사 L,FA. 접미사 L저번에 long형 변수에 int형 정수의 범위를 벗어나는 수를 저장할 때...

blog.naver.com

다음은 실수 타입입니다. 여기에는 float와 double이 속해있으며 각각의 크기는 32와 64입니다. 위에서 크기에 대해서는 설명 했으니 바로 의문으로 들어갑시다. 어째서 실수 타입은 크기가 정수형에 비해 클까요? 

실수는 정수와 달리 정밀성에 관련이 있습니다. 애초에 컴퓨터는 0과 1밖에 표현이 불가능합니다. 만약, 컴퓨터가 8을 표현하고 싶다면 1000이라고 외치면 됩니다. 하지만 0.005를 표현하다고 하면 어떻게 해야할까요? 0과 5는 그렇다고 칩시다. 할 수 있다고 합시다. 그렇다고 해도 .은 어떻게 표현할 수 있을 까요?

https://wikidocs.net/81917

지금 보시면 32비트로 표현되어져 있습니다. 그렇다면 float형입니다. 부호는 +,-를 뜻하는 것 같구...
지수는 1.xx,2.xx처럼 . 앞을 말하는 것 같습니다. 자연스럽게 가수는 .뒤를 말합니다.
결국, 지수와 가수의 콜라보라는 건데... 솔직히 이 부분은 조금더 공부해야하는 부분인것 같습니다. 
아무튼 위가 float에 대한 그림인데 이것보다 크기가 큰 double은 당연히 더 정밀성면에서 더 뛰어나겠죠.
왜냐하면 소수(2,3,5.. 아님)라는건 지수 부분보다 가수 부분이 더 중요한데, 가수 부분이 크면 클 수록 더 정확한 값을 표현할 수 있기 때문입니다.

네 실수형의 기본 값은 double입니다. 조금더 정밀한게 좋기 때문이죠.

그러니까 정리하자면 정수는 속도나 메모리 측면에서 가장 우수한 int를 실수는 더 정밀한 double을 사용하는 것 같습니다.

아, 불리언 타입을 빼먹었군요.
이들은 간단히 설명하고 넘어 가겠습니다. false,true로 나눠진다고 합니다. 

프리미티브 타입의 특징

위에 설명한거에 추가하자면 프리미티브 타입은 결정적으로 스택 메모리에 저장이 됩니다.
그리고 초기화 할때 0으로 자동으로 초기화가 됩니다.

레퍼런스 타입

지금까지 프리미티브 타입에 대해 설명하였습니다. 레퍼런스 타입에 종류에는 클래스, 배열, 인터페이스, 이넘등이 있습니다. 또한 프리미티브 타입을 레퍼런스 타입으로 바꾸는 타입을 wrap(래퍼) 클래스라고 합니다. 

또한 이들은 가변적이기 때문에 힙 메모리에 저장 된다고 합니다.

 

기본(Primitive) data type과 참조(Reference) data type

1) 기본(primitive) data type과 참조(reference) data type 자바의 자료형은 크게 기본형(primitive type)...

blog.naver.com

이들은 초기화를 하면 null로 초기화가 됩니다.

짧게 프리미티브 타입과 레퍼런스 타입에 대해 알아봤습니다.

리터럴


리터럴의 정의는 소스코드의 고정된값을 말합니다. 이것으로 미뤄봤을때 적어도 프로그래밍에서는
리터럴 = 상수라고 생각해도 될것같습니다.
그러면 상수는 어느 메모리 공간에 저장될까요?
메소드 영역에 저장이됩니다.
자바에서 리터럴(상수)을 사용하는 방법은
static final 자료형 으로 작성됩니다.
static 과 final의 위치를 바꿔도 같은 동작을 하게되지만
관례상 static을 먼저 작성하고 final이 작성됩니다.
더 자세히 알고싶으면,

 

왜 자바에서 final 멤버 변수는 관례적으로 static을 붙일까?

자바 final, static 키워드와 코딩 best practice 되짚어보기

djkeh.github.io

이 글을 참조하면 좋을 것 같습니다.

변수 선언 및 초기화하는 방법

int a;

자료형을 입력한 다음 그 변수 이름을 작성합니다. 이것이 변수를 선언하는 방법입니다.

현재 int형으로 변수를 선언하였습니다. 그러면 int형은 프리미티브 타입이기 때문에 0으로 초기화가 될까요?
또, int가 아닌 Integer으로 선언한다면 어떻게 될까요?
Integer은 참조형입니다. 

Integer a;
System.out.println(a);

이렇게 하면 nullPointException이 나올까요?
예상과 달리 int a; 는 0으로 출력이 되지 않습니다.

int a = 0;
Integer a = null;

그 이유는 자바에서는 지역변수(메소드 내에서 선언한 변수)를 초기화 하지 않은채 선언했을 경우 발생된다고 합니다. (nullPointException이 나오지 않는 이유 역시, 초기화를 null로 둘경우 null로 출력되는 것을 확인 할 수 있었습니다.) 여기서 얻은 교훈은 절대로 null로 초기화 하지 말자라고 할 수 있겠네요.

그러면 의문이 하나 생깁니다. 분명 위에서는 0으로 초기화된다고 했는데... 밑에서는 되지 않는다고 하니....;;; 뭐가 맞을까요? 사실 지역 변수가 안되는 거지 맴버 변수로는 0으로 자동으로 초기화 됩니다.
그렇다고 해도 위 의문에 대한 확실한 답변은 되지 않는 것 같습니다.;;

더보기
지역 변수는 대부분 일부 계산을 수행하기 위해 선언됩니다. 따라서 변수의 값을 설정하는 프로그래머의 결정이며 기본값을 사용해서는 안됩니다. 프로그래머가 실수로 로컬 변수를 초기화하지 않았고 기본값을 사용하면 출력이 예상치 못한 값이 될 수 있습니다. 따라서 지역 변수의 경우 컴파일러는 정의되지 않은 값의 사용을 피하기 위해 프로그래머가 변수에 액세스하기 전에 일부 값으로 초기화하도록 요청합니다. 

출처 : qastack.kr/programming/415687/why-are-local-variables-not-initialized-in-java

 

변수의 스코프와 라이프타임

변수의 스코프는 일반적으로{}사이에서 동작합니다. 즉, {}범위를 넘어서는 순간 그 변수는 사용이 불가합니다.
맴버 변수는 클래스 변수라고 불리며 클래스 바로밑에 선언됩니다. 

class Main {
  int a;
  int b;
  int c;
}


어떻게 보면 맴버 변수 또한 지역 변수라고 불러도 크게 이상하지는 않을 것 같습니다. 
왜냐하면 가장 밖에있는 {}괄호안에서 자유롭게 사용이 가능하기 때문입니다.

즉, 생성된 변수가 가장 가까운? {} 사이에서 동작한다고 할 수 있을 것 같습니다.
반복문도 마찬가지입니다. 하지만 반복문 처럼 ( ) 안에 변수를 작성하는 문법은 살짝 다른 스코프를 보여줍니다.

근데 의문이 하나 생깁니다. 맴버 변수랑 지역 변수가 동시에 있다면? 
자바는 어느 변수를 선택할까요?

class Main {
int a = 3;

  public static void main(String[] args) {
   int a = 5;
   System.out.print(a);
  }

}

네 정답은 지역 변수입니다. 결국, 범위가 더 좁은곳으로 값이 결정이 됩니다.
위에서 반복문은 조금 다르다고 하였습니다.

for(int i = 0; i<5;i++) {
 System.out.println(i);
}

이 코드 또한 {}사이에서만 i를 사용할 수 있습니다.
그러면 다음의 경우는 어떨까요?

class Main {
  public static void main(String[] args) {
     int a = 3;
  	 for(int a = 0;a <5;a++) {
         System.out.println(a);
    }
  }
}

이 경우는 컴파일에러가 발생합니다. a라는 변수는 이미 지역 변수에서 사용이 되었기 때문입니다. 
결국, ( )에서는 상위 지역 변수의 영향을 받는것으로 있을 것 같습니다.  나는 지역 변수로 a변수를 만들었는데, 이것을 반복문으로 사용하겠다. 라고 해석이 되는 군요.

라이프타임? 라이프타임이 뭘까요? 스코프와 달리 라이프타임은 변수가 메모리상에 남아있는 것을 뜻한다고 합니다. 
크게는 인스턴스 변수, 클래스 변수(맴버 변수), 로컬 변수로 나눠서 설명하겠습니다.

1. 인스턴스 변수는 new 키워드를 통해 만들어진 변수를 뜻하며 (힙에 저장되겠군)

Hello a = new Hello();

이런식으로 만들게 됩니다. 간단히 설명하면 특정 클래스를 이용하기 위해 만드는 변수라고 생각하시면 좋을 것 같습니다. Hello라는 건 클래스고 a는 변수명이 됩니다. 따라서  a는 인스턴스 변수라는 뜻입니다.
그러면 인스턴스 변수의 라이프 타임은 어떻게 될까요?

클래스의 객체가 메모리상에서 사라질때 까지 라고 합니다. 이게 무슨 말일까요? 자바에는 gc라는 쓰레기 수집가가 있습니다.(모든 쓰레기를 치워주지는 않아요.ㅜㅜ) 아마도 GC가 만들어진 객체를 메모리상에서 치워줄때까지라고 정의 내릴 수 있을 것 같습니다.

 2. 클래스 변수 는 프로그램이 종료 될때 까지라고 하네요ㅎㅎ;

3. 지역 변수는 위에서 변수의 스코프를 설명한거와 마찬가지로 {}사이에서만 동작한다고 합니다.;;

위 내용들은 다음 링크를 통해 자세히 알 수 있습니다.

 

Scope and Lifetime of a Variable in Java - Learning Journal

One of the frequent questions, which any programmer comes across in the programming world is, “What is the scope of this variable?” In this article, our main concern is to shed light upon the scope and lifetime of a variable in Java. The scope of a var

www.learningjournal.guru

타입 변환, 캐스팅 그리고 타입 프로모션

타입 변환은 굉장히 간단합니다. 타입을 변환을 시켜주는 것을 의미합니다.

원래 int였던 친구를 같은 정수이지만 크기가 큰 long으로 바꾼다면 어떨까요?

int a = 10;
long b = a;

이런식으로 동작하는것이 타입 변환입니다.
하지만 이렇게 타입을 변환시키는 행위는 굉장히 위험합니다. 지금부터 그 이유에 대해 설명하겠습니다. 
가장 큰 이유는 손실이 일어난다는 점입니다. 조금있다가 설명할 예정이지만, 캐스팅을 하지 않으면, 컴파일에러가 발생합니다. 아무튼 다시 돌아와서 손실이 발생한다는것은 온전히 정한 값들을 사용이 불가능하다는 뜻입니다. 

이러한점을 방지하기 위해서는 위 같은 행위는 하지 않는것이 최우선이지만,
만약, 해야되는 상황이라면, 범위가 큰 변수에서 작은 변수로 타입 변환을 하는것이 좋습니다. 어차피 그 크기로 커버가 가능하기 때문이죠. (코딩테스트에서는 유용하게 사용할 수 있습니다.)

    public static void main(String[] args) {
	    long a = 1000000000000L;
	    int  b = (int)a;
        System.out.println(b);
    }

답이 뭐라고 나올까요?

 

 

이 뜻은 범위를 벗어났기 때문에 마이너스를 표시합니다.

더보기

Math.toIntExact를 사용하게 되면 마이너스값이 더 이상 나오지 않게 됩니다.  
마이너스값은 나오지 않지만

이런식으로 에러가 발생합니다.


굳이 사용해야한다면 이 방법도 고려해야봐야겠네요.ㅎㅎ; 

위에서 잠시 언급 했지만,

캐스팅은 이런식으로 사용합니다.

int a = (int)b;

인스턴스 변수같은 경우는 추후 클래스에서 설명하겠지만, 하위 클래스로 캐스팅은 가능하지만, 상위 혹은 같은 레벨인 클래스는 캐스팅이 불가합니다.

class A extends C{

}

class  B extends C{

}

class C {

}
public class Main {

    public static void main(String[] args) {
	    A a = new A();
	    C b = new C();
	    b = (C)a;
    }
}

캐스팅이란? 큰 데이터 타입에서 작은 데이터 타입으로 형 변환하는것을 뜻합니다. 즉, 명시적으로 형 변환을 하는것을 캐스팅이라고 합니다. 그것을 자바에서는 ( )를 통해 동작합니다.

그러면 프로모션은 무엇일까요? 가장 맨위 코드 기억 하시나요?

int a = 10;
long b = a;

바로 이 코드인데요. 지금 보시면 long에서 int를 받아 사용했습니다. 이제 a의 값은 long이 되었습니다.! 캐스팅을 하지도 않았는데... 되다니... 묵시적, 자바에서 몰래 캐스팅을 해주었네요.;;

클래스에서도 가능합니다.

class A extends C{

}

class  B extends C{

}

class C {

}
public class Main {

    public static void main(String[] args) {
	    A a = new A();
	    C b = a;
    }
}

1차 및 2차 배열 선언하기

자바에서는 배열을 만들기 위해서는 new키워드가 필요합니다. int[] a = new int[5]; 이런식으로 작성됩니다. new키워드는 힙메모리에서 생성이 될것 같습니다. 과연 그럴까요?

다음 그림을 보면서 이야기 해봅시다.

https://stackoverrun.com/ko/q/1778519

제가 해석한게 맞다면, 각각의 값들은 stack메모리에 저장이 됩니다. 하지만 배열 자체를 선언하기 위해서는 new키워드를 사용해야합니다. new 키워드는 heap메모리에 저장이 됩니다. 즉, 전체 배열은 heap메모리에 저장 되지만, 각각의 값들은 stack메모리에 저장이 되지 않을까 추측합니다

다음은 okky글에서 이에 대해서 토론한 내용입니다.

 

OKKY | 배열을 선언 시 메모리에 어케 저장되나욤?

배열을 선언 시 메모리에 어떻게 저장되나요? 음.. 배열은 객체형이고.. int[] a = new int[10]; 를 실행하게 되면 int 형이 10개 힙 메모리에 선언되는건가요? 보통 기본형은 정적메모리(스택메모리) 에

okky.kr

프리미티브 타입이 아닌 객체 타입으로 한다면 당연히 heap메모리에 저장이 되겠죠.;; (참고로 위에서는 프리미티브 타입이라고 가정하였습니다.)

일차원 배열의 크기를 구하는 것은 어렵지 않게 구할 수 있습니다. 일차원 일때는 []사이에 있는 숫자에 할당된 값이 배열의 크기입니다. 이차원 이상이면 어떨까요? 이차원이라고 일차원과 다르게 숫자가 다르게 나오는것은 아닙니다. 

int[][] a = new int[2][3];

이 배열의 크기는 무엇일까요? 정답은 6입니다. 그림을 그려 봅시다.

세로 2줄, 가로 3줄 총 배열의 방이 총 6개가 나오는 군요.
이것은 곱집합과 매우 유사합니다. 여기에서의 곱집합은 행과 열의 크기를 서로 곱한 값을 뜻합니다.

 

곱집합 - 위키백과, 우리 모두의 백과사전

위키백과, 우리 모두의 백과사전. 집합 A = {x, y, z}와 B = {1, 2, 3}의 곱집합 A × B. 52장의 포커 패의 집합은 모양의 집합 {♠, ♥, ♣, ♦}과 숫자의 집합 {2, ..., 10, J, Q, K, A}의 곱집합이라 생각할 수 있

ko.wikipedia.org

자 그러면 3차원 배열은 어떨까요? 

int[][][] a = new int[2][2][2];

 정답은 8입니다.
이것 또한 간단합니다.

보통 3차원 배열은 입체로 생각하지만 저는 다르게 그려봤습니다. 이 삼차원 배열의 뜻은 2*2 이차원 배열이 갯수가 총 2개라는 뜻입니다. 이것을 위 아래로 쌓으면 우리가 생각하는 입체가 됩니다.

이것을 응용하면 4차원 배열도 쉽게 이해할 수 있습니다.

int[][][][] a = new int[2][2][2][3];

감사합니다.

배열의 크기도 24 완벽!

타입 추론, var

타입 추론은 자바자체적으로 어떤 타입인지 예측하고, 그것을 사용하는 것을 말합니다. 마치 자바스크립트 또는 파이썬같은 동적 타입 언어처럼 말이죠.

타입 추론은 대표적으로 제네릭에서 사용됩니다. 그런데 자바는 어떻게 타입 추론을 할 수 있을까요? 

더보기

타입 추론은 각 메소드 호출과 해당 선언을 살펴보고 해당 호출을 적용 할 수있는 타입 인수를 결정하는 Java 컴파일러의 기능입니다. 추론 알고리즘은 인수의 유형과 가능한 경우 결과가 할당되거나 반환되는 유형을 결정합니다. 마지막으로, 추론 알고리즘은 모든 인수와 함께 작동 하는 가장 구체적인 유형을 찾으려고합니다 .

 

Type Inference (The Java™ Tutorials > Learning the Java Language > Generics (Updated))

The Java Tutorials have been written for JDK 8. Examples and practices described in this page don't take advantage of improvements introduced in later releases and might use technology no longer available. See Java Language Changes for a summary of updated

docs.oracle.com

자바 컴파일러에서 자동으로 그 타입이 무엇인지 알려주는 기능인것 같습니다. 
제네릭은 추후에 제네릭을 공부할때 작성하겠습니다.

java10부터 var이 추가되었습니다. 

기존에는

int a = 5;

라고 작성하였습니다.

하지만 java10부터 

var a = 5;

 을 작성해서 사용할 수 있습니다. 이것의 최고의 장점은 프로그래머가 타입이 어떤것인지 신경을 쓸 필요가 없습니다. 하지만 동적 타입 언어의 문제점 중하나가 예상치 못한 에러에 대처하지 못한다는 점입니다. 왜냐하면 런타임시 타입이 결정되기 때문입니다.

다음 3개의 글은 동적타입 언어와 정적 타입언어에 대해 비교한 글들입니다.

 

[펌] 동적타입vs정적타입

프로그래밍 언어에서 타입 시스템은 크게 두가지로 나누어진다. 컴파일시에 타입을 결정하는 Static Type...

blog.naver.com

 

 

정적타입vs동적타입?? 단순한 언어가 최고!!

요즘 재미있게 시청하였던 "알아두면 쓸데 없는 신비한 잡학사전: 알쓸신잡" 이라는 나PD가 만들고 유시민작가등이 출연하는 프로그램에서 따와서 "알아두면 쓸데 없는 재밌는 소프트웨어 지

hamait.tistory.com

 

 

OKKY | 동적 언어 vs 정적 언어 승자는?

아침에 받아본 뉴스레터에 자극적인 제목이 달린 글이 있길래 좀 들여다 봤습니다. The End of Dynamic Languages vs Have Static Languages Won? 다 적기 귀찮아서 대충 몇가지만 적어보자면 최근 나타나는 신생

okky.kr

사용할때는 편하지만, 무분별하게 이 기능을 사용하게 되면 심각한 에러가 발생하여 위험하기 때문에 꼭 필요한 경우에사용하는게 좋을 것 같습니다. 
그러면 언제 사용하는게 좋을까요?

다음 글은 자바10에서 var을 언제 사용하면 좋을지 작성한 글을 소개하겠습니다.

 

Java 10 에서 var 재대로 사용하기

조금 된 일이지만, Java 10부터 var 구문이 생겼다. LTS인 자바 11부터는 이를 통한 람다 타입 지원도 생겼다.하지만 최신 안정화 버전(LTS)인 자바 11로 프로젝트를 시작한들, var 구문에 대한 거부감을

velog.io

 

'프로그래밍 언어 > 자바' 카테고리의 다른 글

백기선님 스터디에서 배운거 2가지 (간략히 정리)  (0) 2020.11.29
연산자  (0) 2020.11.26
자바 데이터 타입, 변수 그리고 배열   (5) 2020.11.18
JVM이란?  (0) 2020.11.13
서블릿과 JSP  (0) 2020.09.24
public , default, protected, private  (0) 2020.07.30

댓글(5)

  • 질문자
    2021.01.09 01:19

    안녕하세요, 다차원 배열에 대한 설명 인상 깊게 읽었습니다.
    4차원 배열 예시로 2*2*2*3인 배열을 드셨는데, 그려주신 그림으로 연상하면 3*2*2*2 이 되는 것 같습니다.
    일반적으로 2*2*2*3인 배열을 연상하면 가장 낮은 레벨의 원소가 트리오로 묶이는 걸 떠올리지 않나요..?
    작성자님께서는 원소를 페어로 연상하셨길래 궁금증이 생겨 질문드립니다!

    • 2021.01.09 01:52 신고

      저는 저걸 생각했을때,
      단순히 왼쪽에서 오른쪽으로 생각했던것 같습니다. 즉, 낮은 원소에 쌓여지는 형태로 생각했던것 같습니다.

      잘못 생각 했었네요.
      저걸 출력하면 전체 크기가 3나오네요..

      점진적으로 쌓여지는 형태가 아니라
      안에 추가 되는 느낌이 었군요 ㅜㅜ

      제보해주셔서 감사합니다.;;
      덕분에 많이 알아가네요 ㅎ;

  • 2021.01.09 02:14 신고

    수정했습니다.

    • 2021.01.12 00:23

      비밀댓글입니다

    • 2021.01.12 00:37

      비밀댓글입니다

Designed by JB FACTORY