본문 바로가기

Java

변수의 종류

728x90

<변수의 종류>

자바 원시 타입의 값을 저장하는 변수와 메모리 주소를 저장하는 변수가 있다.

1) 자바 원시 타입 변수(primitive variable)

정수, 부동소수점, 논리, 문자코드의 값을

2) 레퍼런스 변수(referece variable)

자바 원시 타입의 값을 제외한 모든 값

 

//자바 원시 데이터 타입 변수
//- 정수
    byte b;  // 1바이트 크기의 메모리
    short s; // 2바이트 크기의 메모리 
    int i;   // 4바이트 크기의 메모리 
    long l;  // 8바이트 크기의 메모리
    
//- 부동소수
    float f;   // 4바이트 크기의 메모리
    double d;  // 8바이트 크기의 메모리
    
//- 문자코드
    char c;  // 2바이트 크기의 메모리
    
//- 논리
    boolean bool;  // 자바 언어 명세서에는 메모리의 크기가 정의되어 있지 않다. 다만 JVM 명세서에는 int 로 다룬다고 나와있다.
    
//레퍼런스 변수
    String str; // 자바 언어 명세서에는 메모리의 크기가 정의되어 있지 않다. 메모리 주소를 저장할 만큼 큰 크기
    Date date;  // 자바 언어 명세서에는 메모리의 크기가 정의되어 있지 않다. 메모리 주소를 저장할 만큼 큰 크기

 

<메모리 크기에 따라 저장할 수 있는 값의 범위>

 

1) primitive data type (원시 데이터 타입)

- 정수

- byte : 1byte 메모리 (-128 ~ 127)

- short : 2byte 메모리 (-32768 ~ 32767)

- int : 4byte 메모리 (약 -21억 ~ 21억)

- long : 8byte 메모리 (약 -922경 ~ 922경)

- 부동소수점

- float : 4byte 메모리 (유효자릿수 7자리)

- double : 8byte 메모리 (유효자릿수 15자리)

- 문자

- char : 2byte 메모리 (0 ~ 65535). UCS-2 코드 값 저장.

- 논리값

- boolean : JVM에서 4 바이트 int 메모리를 사용한다. 배열일 경우 1 바이트 byte 메모리를 사용한다.

 

2) reference(레퍼런스)

데이터가 저장된 메모리의 주소를 저장하는 메모리.

- 문자열(주소)

- String : 문자열이 저장된 메모리의 주소를 저장한다.

프로그래밍 입문 단계에서는 그냥 문자열을 저장하는 메모리로 생각하라!

- 날짜(주소)

- Date : 날짜 값이 저장된 메모리의 주소를 저장한다.(날짜를 저장하는 메모리로 생각)

 

 

<정수 변수 - 변수의 메모리 크기>

 

    // 1바이트 크기의 정수 값을 담을 메모리 준비
    byte b;
    
    // 값을 메모리에 저장하려면 1과 0, 2진수 형태로 바꿔야 한다.
    // 정수를 2진수로 바꿀 때 '2의 보수' 방식을 사용한다.  
    // 1 byte(8 bit)에 저장할 수 있는 최대/최소값은 다음과 같다. 
    b = -128; // 10000000
    b = 127;  // 01111111
    
    // 다음과 같이 메모리 크기를 벗어난 값을 저장하려 하면 컴파일 오류가 발생한다.
    //b = -129; // 컴파일 오류! 
    //b = 128; // 컴파일 오류!

    // 2바이트 크기의 정수 값을 담을 메모리 준비
    short s;
    
    // 2바이트 메모리에 담을 수 있는 최소/최대 정수값
    s = -32768; // 10000000 00000000
    s = 32767;  // 01111111 11111111

    // 2바이트 범위를 벗어나면 컴파일 오류!
    //s = -32769; // 컴파일 오류!
    //s = 32768; // 컴파일 오류!

    // 4바이트 크기의 정수 값을 담을 메모리 준비
    int i;

    // 4바이트 메모리에 담을 수 있는 최소/최대 정수값
    i = -2147483648; // 10000000 00000000 00000000 00000000
    i = 2147483647;  // 01111111 11111111 11111111 11111111

    // 다음은 값을 저장할 메모리의 크기 때문에 발생한 오류가 아니다.
    // 리터럴 크기의 문제다.
    // 정수 값 뒤에 L 또는 l을 붙이지 않은 리터럴은 4바이트 크기를 의미하다.
    // 그런데 4바이트를 넘어서는 값을 리터럴로 표현했기 때문에 오류가 발생한 것이다.
    //i = -2147483649; // 컴파일 오류!
    //i = 2147483648; // 컴파일 오류!

    // 해결책?
    // - 4 byte 크기를 벗어나는 정수를 표기할 때는 반드시 숫자 뒤에 L 또는 l을 붙여야 한다.
    //i = -2147483649L; // 컴파일 오류가 발생하는 이유? 메모리의 크기가 4바이트라서 값을 저장할 수 없다.
    //i = 2147483648L;  // 컴파일 오류!

    // 8바이트 크기의 정수 값을 담을 메모리 준비 
    long l;
    
    // 8바이트 메모리에 담을 수 있는 최소/최대 정수값
    l = -9223372036854775808L; // 10000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 
    l = 9223372036854775807L;  // 01111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111

 

<정수 변수 - 변수와 리터럴의 크기>

 

    //4바이트 정수 리터럴 ==> byte, short 변수
    //- 4바이트 리터럴인 경우 메모리 크기에 상관없이 저장할 수만 있다면 
    //  byte(1바이트), short(2바이트) 메모리에 값을 저장해도 컴파일 오류가 발생하지 않는다. 
    //    
    byte b;
    short s;

    b = 127;   // 4바이트 리터럴 ==> 1바이트 메모리
    s = 32767; // 4바이트 리터럴 ==> 2바이트 메모리

    //- 단, 리터럴을 메모리에 저장할 수 없다면 컴파일 오류가 발생한다.
    //    b = 128;   // 1바이트 크기를 초과하는 값
    //    s = 32768; // 2바이트 크기를 초과하는 값

    //8바이트 정수 리터럴 
    //- 8바이트 리터럴인 경우 값이 크고 작음에 상관없이
    //  byte(1바이트), short(2바이트), int(4바이트) 메모리에 값을 저장하려하면 컴파일 오류가 발생한다. 
    //    b = 127L;
    //    s = 32757L;
    //    int i = 100L;

 

<정수 변수 - 크기가 다른 변수끼리 값 할당>

 

    long l = 100;
    int i = 100;
    short s = 100;
    byte b = 100;
    char c = 100;

    //변수의 값을 다른 변수에 저장할 때,
    //- 값의 크기에 상관없이 같거나 큰 크기의 메모리이어야 한다.

    long l2;
    int i2;
    short s2;
    byte b2;
    char c2;

    // long ===> long 이상
    l2 = l;
    //i2 = l; // 컴파일 오류
    //s2 = l; // 컴파일 오류
    //b2 = l; // 컴파일 오류!
    //c2 = l; // 컴파일 오류!

    // int ===> int 이상
    l2 = i;
    i2 = i;
    //s2 = i; // 컴파일 오류!
    //b2 = i; // 컴파일 오류!
    //c2 = i;  // 컴파일 오류!
    
    // short ===> short 이상
    l2 = s;
    i2 = s;
    s2 = s;
    //b2 = s; // 컴파일 오류!
    //c2 = s; // 컴파일 오류! char(0 ~ 65535) | short(-32768 ~ 32767)
    
    // byte ===> byte 이상
    l2 = b;
    i2 = b;
    s2 = b;
    b2 = b;
    //c2 = b; // 컴파일 오류! char(0 ~ 65535) | byte(-128 ~ 127)

 

<부동소수점 변수 - 변수의 메모리 크기>

 

    // 4바이트 부동소수점 변수
    //- 유효자릿수 7자리 부동소수점 저장 가능
    //- 10 진수로 부동소수점을 표현할 경우 소수점을 제외한 숫자가 7 개인 경우 정상적으로 메모리에 저장된다는 의미
    //
    float f;

    f = 9.876545f; // 소수점을 떼면 숫자의 개수가 7개이다.
    System.out.println(f);

    f = 987654.5f; // 소수점을 떼면 숫자의 개수가 7개이다.
    System.out.println(f);

    // 소수점을 뗐을 때 앞에 0만 있을 경우 그 0은 자릿수에서 제외한다.
    f = 0.000009876545f; // 소수점을 떼면 숫자가 13개 이지만, 앞의 0을 제외하면 실제 7개이다.
    System.out.println(f); // OK
    
    // 주의!
    //- 유효자릿수가 7자리를 넘어가면 정상적으로 값을 저장되지 않을 수 있다.
    f = 9.8765456f; // 맨 뒤의 값이 반올림 된다.
    System.out.println(f);
    
    f = 9876545.6f; // 맨 뒤의 값이 반올림 된다.
    System.out.println(f);

 

 

    // 8바이트 부동소수점 변수
    //- 유효자릿수 15자리 부동소수점 저장 가능
    //- 10 진수로 부동소수점을 표현할 경우 소수점을 제외한 숫자가 15 개인 경우 정상적으로 메모리에 저장된다는 의미
    //
    double d;

    d = 9.99999999988888; // 소수점을 떼면 숫자의 개수가 15개이다.
    System.out.println(d);

    d = 9999999.88888888; // 소수점을 떼면 숫자의 개수가 15개이다.
    System.out.println(d);

    d = 99999999998888.8; // 소수점을 떼면 숫자의 개수가 15개이다.
    System.out.println(d);

    // 소수점을 뗐을 때 앞에 0만 있을 경우 그 0은 자릿수에서 제외한다.
    d = 0.00000999999999988888; // 소수점을 떼면 숫자가 21개 이지만, 앞의 0을 제외하면 실제 7개이다.
    System.out.println(d); // OK

    // 주의!
    //- 유효자릿수가 15자리를 넘어가면 정상적으로 값을 저장되지 않을 수 있다.
    d = 9.999999999999997; // 맨 뒤의 값이 반올림 되거나 잘린다.
    System.out.println(d);

    d = 999999999999999.7; // 맨 뒤의 값이 반올림 되거나 잘린다.
    System.out.println(d);
    
    // 주의!
    //'유효자릿수'는 부동소수점의 저장 가능 여부를 간단히 계산하기 위해 나온 개념이다.
    //실제는 유효자릿수에 해당하는 부동소수점이라도 정규화 과정을 통해 2 진수로 변환되는 과정에서 
    //값이 짤리는 경우가 있음을 잊지 말라!
    //
    //
    // 단정도(single precision)와 배정도(double precision)
    //- double 변수는 float 변수에 두 배 정도 더 정밀한 값을 저장할 수 있다.
    //  그래서 '배정도(double precision)'라 한다.
    //- float은 double과 비교하여 한 배 정도 정밀한 값을 저장할 수 있다.
    //  그래서 '단정도(single precision)'이라 한다.

 

<부동소수점 변수 - 변수와 리터럴의 크기>

 

    float f;
    double d;

    // 변수도 크기에 따라 구분되지만, 리터럴도 크기에 따라 구분된다.
    // - 부동소수점 리터럴 값 뒤에 f나 F를 붙이면, 4바이트 크기의 부동소수점 값을 의미한다.
    // - 부동소수점 리터럴 값 뒤에 d나 D를 붙이거나 아무것도 붙이지 않으면, 8바이트 크기의 부동소수점 값을 의미한다.

    f = 9999.888f; // 4바이트 변수 = 4바이트 리터럴
    System.out.println(f);


    d = 99999999.8888888; // 8바이트 변수 = 8바이트 리터럴
    System.out.println(d);
    
    // - float 메모리에 값을 저장할 때는 유효자릿수가 7자리 이하인 4바이트 부동소수점(f 또는 F가 붙은)을 저장하라!
    // - double 메모리에 값을 저장할 때는 유효자릿수가 15자리 이하인 8바이트 부동소수점을 저장하라!

 

    double d;

    // 주의!
    // - 잘못된 리터럴 값을 변수에 저장해봐야 소용없다!
    
    d = 99999.8888877777f;
    System.out.println(d);
    // 4바이트 크기를 넘어가는 부동소수점 리터럴은 이미 짤린 값이기 때문에 제대로 저장될 수 없다.
    
    
    d = 99999.8888877777f;
    System.out.println(d);
    
    // 주의!
    // 정수의 경우 리터럴을 표현할 때 
    // 값이 그 크기를 넘어가면 컴파일 오류가 발생하지만,
    // 부동소수점의 경우 리터럴이 메모리의 크기를 넘어갈 때
    // 컴파일 오류 대신 단지 값이 짤린다.

    
    // 변수의 크기에 맞춰 부동소수점의 리터럴을 지정하라.
    float f = 99999.88f;
    System.out.println(f);
    
    d = 99999.8888877777;
    System.out.println(d);

    // 4바이트 부동소수점을 8바이트 메모리에 저장할 때
    // 계산 방식에 의해 소수점 이하의 수가 근사 값으로 바뀐다.
    // => 8바이트 메모리에 값을 저장할 때는 8바이트 리터럴을 사용하라.
    d = 99999.88f;
    System.out.println(d);

 

    float f1 = 99988.88f;
    float f2 = 11.11111f;

    // 각 변수의 값이 개별적으로 옳은 부동소수점이라도,
    System.out.println(f1);
    System.out.println(f2);
    
    // 주의!
    // 연산 결과가 해당 타입의 크기를 벗어 난다면 그 결과 값이 짤린다.
    float f3 = f1 + f2;
    System.out.println(f3);
    
    // 그래서 부동소수점을 다룰 때는 가능한 float 보다 두 배 더 정밀한 double을 사용하라!
    // 문법에서도 double 리터럴을 기본 부동소수점으로 간주한다.
    // 즉 부동소수점 뒤에 d나 D 표시를 생략할 수 있다.
    double d1 = 99988.88;
    double d2 = 11.11111;
    double d3 = d1 + d2;
    System.out.println(d3);

 

<부동소수점 변수 - 크기가 다른 변수끼리 값 할당>

 

    float f;
    double d;

    d = 3.14;
    
    // 값의 유효 여부에 상관없이 메모리 크기가 큰 변수의 값을 작은 크기에 변수에 저장할 수 없다.
    //f = d; // 문법 오류!

 

 

<문자 변수 - 변수의 메모리 크기>

 

    // 자바는 'UCS(Universal Character Set; ISO 10646)'라는 국제 표준 문자 인코딩 규격에 따라 문자를 다룬다.
    // UCS-2 라고도 부르며, 각 글자를 0 ~ 65535 까지의 16비트 코드 값으로 저장한다.
    
    // 자바는 UCS-2 코드 값을 저장하기 위해 2바이트 크기의 메모리를 사용한다.
    // 다음은 2바이트 크기의 UCS-2 코드 값을 저장할 변수를 선언한다.
    char c;

    c = 0;
    c = 65535;

    // char(2byte) 크기의 메모리 범위를 초과하면 문법 오류이다. 
    //c = -1; // 컴파일 오류 발생!
    //c = 65536; // 컴파일 발생!

 

<문자 변수 - UCS-2 문자 코드 값 저장>

 

    char c1, c2, c3;
    
    // 문자 'A'를 변수에 저장하는 방법?
    //- 문자 'A'의 UCS-2 코드 값을 저장하면 된다.
    //
    
    c1 = 65;            // 문자 'A'의 코드 값을 10진수로 표현한 것.
    c2 = 0x41;          // 문자 'A'의 코드 값을 16진수로 표현한 것.
    c3 = 0b0100_0001;   // 문자 'A'의 코드 값을 2진수로 표현한 것.

    // println()을 통해 문자를 출력할 수 있다.
    //- 변수의 종류가 char 이면 출력할 때 코드 값 대신 문자를 출력한다.
    //- 해당 코드의 문자를 폰트 파일에서 찾아 출력한다.
    //
    System.out.println(c1);
    System.out.println(c2);
    System.out.println(c3);

 

<문자 변수 - 따옴표('', single quotation) 활용하기>

 

    // 문자 코드 값을 모른다면 따옴표를 사용하라!
    // - 문법
    //   '문자' : UCS-2에 정의된 코드 값을 리턴한다.
    //
    char c = 'A';  // c 변수에 저장되는 것은 문자 'A'의 UCS-2 코드 값이다.
    System.out.println(c);
    
    //문자의 UCS-2 코드 값을 확인하기
    //- 정수 변수를 사용하면 문자의 코드 값을 받아서 그래도 출력할 수 있다.
    //  println()은 int 변수의 값은 10진수로 출력한다.
    int i = 'A';
    System.out.println(i);

 

<논리값 변수 - 변수의 메모리 크기>

 

    // 논리 값을 담을 변수는 JVM 내부에서 4바이트 크기의 int 타입 메모리를 사용한다.  
    boolean b1, b2;
    
    b1 = true; // 실제 메모리에는 1을 저장한다.
    b2 = false; // 실제 메모리에는 0을 저장한다.

    System.out.println(b1);
    System.out.println(b2);

    // 주의!
    // - JVM 내부에서 true, false를 정수 값으로 다룬다고 해서 boolean 변수에 직접 1과 0을 저장할 수 없다.
    //b1 = 1; // 컴파일 오류!
    //b2 = 0; // 컴파일 오류!

 

<레퍼런스 변수>

 

    java.util.Date d1 = new java.util.Date();
    java.util.Date d2 = d1;
    
    System.out.printf("%d, %d\n", d1.getDate(), d2.getDate());
    
    d1.setDate(22);
    
    System.out.printf("%d, %d\n", d1.getDate(), d2.getDate());
    // d1에 저장된 일자 값을 변경한 후 
    // d2에 저장된 일자 값을 출력해 보면 d1과 똑같이 변경되어 있다.
    // 이유는?
    // d1과 d2에 저장되는 것은 값이 아니라 (날짜 정보가 저장되어 있는 메모리의) 주소이다.
    // 이렇게 값을 저장하지 않고 값이 저장된 위치(주소)를 저장하는 변수를 
    // "레퍼런스 (변수)"라 부른다.
    // 자바 기본 데이터 타입(byte, short, int, long, float, double, boolean, char)을
    // 제외한 모든 타입의 변수는 레퍼런스이다.

 

'Java' 카테고리의 다른 글

배열, 배열레퍼런스, 배열인스턴스  (0) 2021.10.28
변수  (0) 2021.09.29
예외처리  (0) 2021.09.19
오버로딩  (0) 2021.09.16
생성자는 언제 쓰나?  (0) 2021.09.14