ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 자바 데이터 타입, 변수, 배열
    JAVA/Java 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 를 사용하여 실제 타입을 추론

    'JAVA > Java' 카테고리의 다른 글

    JAVA 연산자  (0) 2020.11.29
    Maven에 대해서 알아보자  (0) 2020.08.30
    서블릿 Life Cycle 알아보기  (0) 2020.06.02
    왜 Wrapper 클래스는 쓰이는 걸까?  (1) 2020.05.21
    객체의 해시코드(hashCode())란  (0) 2020.05.19
Designed by Tistory.