JAVA/Java

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

100win10 2020. 12. 26. 20:50

목표


  • 자바의 프리미티브 타입, 변수 그리고 배열을 사용하는 방법을 익히기

 

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


Primitive Type?

 

  • 기본자료형 혹은 원시자료형이라고 불리는 프리미티브 타입은 값을 할당할 때 변수의 주소 값에 값이 그 자체로 저장되는 데이터 타입이다.
  • 해당 데이터 타입은 값이 할당되면 앞서 살표 보았던 JVM Runtime Data Area 영역 중 Stack 영역에 값이 저장된다.

 

종류

  • Java에서 프리미티브 타입의 종류는 총 8 가지이다.
  • byte, short, int, long, float, double, char, boolean 타입이 그것이다.
  • 타입의 종류와 값의 범위 기본값을 다음과 같은 표로 정리해 보았다.

 

2. 프리미티브 타입과 레퍼런스 타입


Reference Type?

 

  • 참조자료형이라 불리는 레퍼런스 타입의 종류는 무한하다.
  • 프리미티브 타입과 달리 JVM Runtime Data Area 영역 중 heap 영역에 할당되는데
  • 레퍼런스 타입의 변수 주소 값에는 값이 아닌 heap 영역에 할당된 주소가 저장된다.

 

  • 기본 타입과 참조 타입의 구분은 생각보다 간단하다.
  • 저장되는 값이 실제 값인지 혹은 메모리의 주소 값이냐에 따라 구분 가능하다.

 

1
2
3
4
public static void main(String[] args) {
        String name = "test";
        int age = 20;
    }
cs

 

  • 레퍼런스 타입의 name과 프리미티브 타입의 age 변수는 런타임 스택 영역에 생성된다.
  • 레퍼런스 타입의 값인 주소 값과, 프리미티브 타입의 값 20 역시 런타임 스택 영역에 저장된다.

 

  • 레퍼런스 타입의 값인 주소 값이 가리키는 실제 값은 힙 영역에 객체가 된다.
  • 따라서 값을 복사할 때 조심해야 한다.

 

  • 프리미티브 타입의 경우 실제 값이 아닌 주소 값이 복사된다.
  • 이러한 복사는 또다시 얕은 복사와 깊은 복사로 나뉘게 되는데
  • 얕은 복사는 주소 값을 복사하여 동일한 영역의 객체를 참조하고 깊은 복사는 똑같은 새 객체를 할당한다.

 

3. 리터럴


literal?

  • 리터럴은 변수나 상수에 저장되는 값 그 자체를 의미한다.

 

int a = 10
  • int형에 리터럴은 10이다.

 

  • 고정된 값을 표현하는 리터럴은 정수를 표현하는 리터럴, 실수를 표현하는 리터럴,
  • 문자를 표현하는 리터럴, boolean을 표현하는 리터럴, 문자열을 표현하는 리터럴 등이 있다.

정수 리터럴

 

  • 정수를 표현하는 방법은 여러 가지가 있다.
  • 일반적으로 사용하는 10진법부터 2진법 8진법 과 같은 방법이 있고
  • 자바에서는 다양한 진법을 지원한다. 10진수 26을 다양한 리터럴로 표현해보자.

 

  • Integer Literals
    • long 타입은 L로 끝나거나 l로 끝나는 값
    • 그 외 나머지 숫자는 int
    • 16진수: 0x로 시작
    • 2진수: 0b로 시작
int decimal = 26; // 일반적인 형태 10진법
int ocatal = 032; // 제일 앞에 0이 붙으면 8진법
int heaxaDecimal = 0x1a; // 0x가 붙으면 16진법
int binary = 0b11010; // 0b가 붙으면 2진법

 

  • 정수 리터럴은 기본적으로 int 형이고, long 타입을 표현하려면 l, L을 마지막에 붙여야 한다.

 

 

실수 리터럴

 

  • 실수 타입의 리터럴은 기본적으로 double 타입이고, float 타입으로 표현하려면 f를 명시적으로 붙여야 한다.

 

Floating-Point Literals

  • float 타입은 F로 끝나거나 f로 끝나는 값
  • 그 외 나머지는 double (optional, D 혹은 d로 끝나는 값
double a = 0.1;
double b = 1E-1;
float c = 0.1f;

 

 

문자 리터럴

 

  • 문자는 작은따옴표(') 안에 표현할 수 있다

 

char a = 'a';

 

  • 또 특수문자를 위한 리터럴들도 있다.
  • Character and String Literals
    • Unicode character
    • special escape character
      • \b : 백스페이스
      • \t : 탭
      • \n : new line
      • \f : form feed
      • \r : 캐리지 리턴
      • \" : 큰따옴표
      • \' : 따옴표
      • \\ : 역슬래시

문자열 리터럴

 

  • 문자열은 큰따옴표(") 안에 표현할 수 있다.

 

  • 문자열 리터럴에는 조금 특이한 점이 있다.
  • 다른 리터럴들은 프리미티브 타입의 값을 표현하기 위해 존재한다.
  • 그런데 문자열(String)은 레퍼런스 타입이지, 프리미티브 타입이 아니다.
  • 그럼에도 String 타입은 literal을 지원하는데, literal 방식으로 String에 값을 주면 Heap 영역에서 String constant pool이라는 특수한 영역에 값이 저장된다.
  • 그리고, 동일한 값을 쓰는 경우에 다른 일반적인 레퍼런스 타입처럼 Heap에 또 올라가지 않고, String constant pool에 존재하는 값을 참조하는 방식으로 작동한다.

 

해당 관련 링크 : String Constant Pool

 

 

boolean 리터럴

 

  • true, false로 표현할 수 있다.
boolean a = false;
boolean b = true;

 

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


 

Declaration?

  • 변수를 선언한다는 것은, 저장공간을 확보하겠다는 의미로 해석할 수 있다.

 

int a;

 

  • 위의 코드가 변수를 선언한 것인데, 해석하자면 다음과 같다.
  • int 타입의 값을 저장할 수 있는 공간을 확보했고(int 타입은 4byte) 그 공간을 지칭할 이름은 a이다.

 

Initialization?

 

  • 변수를 초기화한다는 것은, 저장공간에 원하는 값을 저장하는 것을 의미한다.
  • 변수를 선언하고 나면, 해당 공간에는 아무런 의미 없는 쓰레기 값이 들어가 있게 된다.
  • 그리고 그 상태에서 컴파일을 시도하면
  • Error:(10, 28) java: variable a might not have been initialized와 같은 컴파일 에러코드를 볼 수 있을 것이다.
  • 그러므로 변수는 선언 후에 초기화를 해야 하며 위에 선언한 변수에 대한 초기화는 다음과 같이 할 수 있다
a = 10; // 선언 후 초기화
  • 변수의 선언과 초기화를 한 줄에 하는 것도 가능하다.
int a = 10; // 선언 과 초기화

 

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


 

Scope? LifeTime?

  • 변수의 스코프란 해당 변수를 사용할 수 있는 영역 범위를 뜻하고
  • 라이프타임은 해당 변수가 메모리에 언제까지 살아있는지를 의미한다.
  • 변수의 경우 scope에 따라 Instance Variables, Class Variables, Local Variables로 나눌 수 있다.

 

Instance Variables

  • 클래스 안에서 선언되어있고, 어떠한 method나 block안에서 선언되지 않은 변수
  • scope - static method를 제외한 클래스 전체
  • lifetime - 클래스를 인스턴스 화한 객체가 메모리에서 사라질 때까지

 

Class Variables

  • 클래스 안에서 선언되어있고, 어떠한 메서드나 블록 안에서 선언되지 않았으며 static 키워드가 포함되어 선언된 변수
  • scope - 클래스 전체
  • lifetime - 프로그램 종료 시까지

 

Local Variables

  • 인스턴스 변수, 클래스 변수가 아닌 모든 변수
  • scope - 변수가 선언된 block 내부
  • lifetime - control 이 변수가 선언된 block 내부에 있는 동안

 

 

 

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


Type casting?

  • 타입 캐스팅이란 크기가 더 큰 자료형을 크기가 더 작은 자료형에 대입하는 것을 의미한다.
  • 예를 들어 int(4byte) 타입의 데이터를 byte(1byte) 타입에 대입하는 경우가 있을 수 있겠다.
  • 물론, 데이터 크기가 더 크기 때문에 변환 과정에서 데이터의 손실이나 변형이 올 수도 있다.

 

Type promotion?

  • 타입 캐스팅과 반대로 크기가 더 작은 자료형을 더 큰 자료형에 대입하는 것을 의미한다.
  • 예를 들어 byte(1byte) 타입의 데이터를 int(4byte) 타입에 대입하는 경우이다.
  • 그리고 이 경우에는 데이터 손실이나, 변형이 오지 않음으로 캐스팅할 때처럼 명시적으로 적지 않아도 자동으로 변환이 가능하다.

 

  • 위와 같은 타입 변환은 프리미티브 타입뿐만 아니라 레퍼런스 타입에서도 가능하다.
  • 그런데 레퍼런스 타입에도 크기라는 개념으로 캐스팅과 프로모션을 구분 지어 생각하면 헷갈릴 수 있다.
  • 부모 클래스로의 타입 변환은 자동적으로 가능하지만 자식클래스로의 타입변환은 타입 캐스팅이 필요하다.
  • 조금만 생각해보면 당연한 이유인데, 자식 클래스는 부모 클래스의 필드나 메서드를 물려받음으로 자식 클래스 타입의 객체를 부모 클래스 타입으로 바꾼다고 해서 데이터의 손실이나 변형이 일어나진 않기 때문이다

 

 

7. 1차 및 2차 배열 선언하기


1차원 배열

  • oneDimensionArrayEx1 은 Runtime Stack 영역의 힙 영역 주소 값을 가진다.
  • Heap 영역에 int 타입 크기의 요소 5개를 할당하여 사용된다.
  •  

 

2차원 배열

  • Runtime Stack 영역의 twoDimensionArrayEx1 은 2개의 요소 크기(2개 요소에 주소값을 가지고 있음)를 가진 힙 영역 주소값을 가진다.
  • 힙 영역에는 실제 값이 들어있는 요소들과 주소 값이 들어있는 요소들로 존재하게 된다.

 

8. 타입 추론, var


  • 10 버전 이상부터 type inference 기능이 추가되었다.

  • method 호출 및 선언과 variable 혹은 object 선언을 통해 실제 타입을 추론하는 형식

  • Generic type

    • C++의 template과 비슷한 개념으로 보인다.
    • 그러나 Generic 은 primitive type 사용 불가하다.
    • template 과는 다르게 type-erasure 개념이 적용되어 type safe를 최대한 보장하려고 노력한다.
      • type-erasure: 컴파일러가 parameterized type에서는 새로운 클래스들이 생성되지 않는 걸 보장한다.

        • 컴파일러가 unbound type T를 Object로 변환한다.

        • 결국 생성된 바이트코드에는 원래의 class, interface, method 만을 포함하고 있다.

  • var라는 type keyword를 사용하여 실제 타입을 추론

 

  • var 라는 type keyword 를 사용하여 실제 타입을 추론