Posts :coffee: [Java] 이것이 자바다 #2: 변수와 타입
Post
Cancel

:coffee: [Java] 이것이 자바다 #2: 변수와 타입

리터럴

  • 소스코드 내에서 직접 입력된 값을 리터럴이라고 부른다.
  • 정수 리터럴, 실수 리터럴, 문자 리터럴, 논리 리터럴이 있다.
    • 정수 리터럴을 저장할 수 있는 타입: byte, char, short, int, long
  • 사실 리터럴은 상수(constant)와 같은 의미이지만 프로그램에서는 상수를 “값을 한 번 저장하면 변경할 수 없는 변수”로 정의하기 때문에 이와 구분하기 위해 “리터럴”이라는 용어를 사용한다.

Java char 초기화와 String 초기화 구별

1
2
3
4
5
6
7
8
9
// char
char c = null; // 컴파일 에러! (type mismatch)
char c = '\u0000'; // ok!
char c = ''; // 컴파일 에러! (invalid character constant')
char c = ' '; // ok! (유니코드:32)

// String
String str = null; // null 초기화 가능
String str = ""; // 빈문자열 초기화 가능

정수 타입

short 타입

  • C언어와(2byte 메모리 체계의 int자료형)의 호환을 위해 사용된다.

c언어에서 Int는 운영체제의 환경에 맞는 크기로 사용된다. 즉 16bit 운영체제에서는 16bit(2byte), 32bit 운영체제에서는 32bit(4byte)를 사용한다. 64bit운영체제부터는32bit로 고정하여 사용한다.

int 타입

  • 정수 연산을 하기 위한 기본 타입
    • bye 타입 또는 short 타입의 변수를 +연산하면 int 타입으로 변환된 후 연산되고 결과 역시 int타입이 된다. 자바에서 정수 연산을 4byte로 처리하기 때문이다.

long 타입

  • 수치가 큰 데이터를 다루는 프로그램에서는 long타입이 필수적으로 사용된다.
    • ex) 은행, 우주 관련 프로그램
1
2
//long var = 100000000000 => 컴파일 에러!
long var = 100000000000L

실수 타입

  • 정수와 달리 부동소수점(floating-point) 방식으로 저장된다.
1
2
//  +    m   x   10^n
// 부호  가수         지수

자동 타입 변환

  • 작은 크기를 가지는 타입이 큰 크기를 가지는 타입에 저장될 때
  • 예외 : char타입은 음수가 저장될 수 없다. 따라서 음수가 저장될 수 있는 byte타입을 char타입으로 자동 변환시킬 수 없다.
  • byte(1) < short(2) < int(4) < long(8) < float(4) < double(8)
  • 자동 타입 변환 이전의 값은 변환 이후에도 손실 없이 그대로 보존된다. (메모리에서 값이 복사됨)
1
2
3
4
5
6
7
char charValue = '가';
intValue = charValue; // int <- char
System.out.println("가의 유니코드=" + intValue); // 44032

intValue = 200;
double doubleValue = intValue; // double <- int
System.out.println(doubleValue); //200.0

강제 타입 변환(casting)

  • 큰 그릇을 작은 그릇 사이즈로 쪼개어서 한 조각만 작은 그릇에 넣는 것과 같다.
  • 즉 int 타입을 4개의 byte로 쪼갠 다음, 끝에 있는 1byte만 byte타입 변수에 저장
  • 캐스팅 연산자 () 사용
  • 값의 손실이 이루어질 수 있다.

강제 타입 변환 주의점

1) 사용자로부터 입력받은 값을 변환할 때 값의 손실이 발생하면 안 된다.

강제 타입 변환 전 변환될 타입의 최소값과 최대값을 벗어나는 지 검사하고, 벗어난다면 타입 변환을 하지 말아야 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
// 변환으로 인한 데이터 손실이 발생되지 않게 한다.
public class CheckValueBeforeCasting {
    public static void main(String[] args) {
        int i = 128;
        
        if( (i<Byte.MIN_VALUE) || (i > Byte.MAX_VALUE) ) {
            System.out.println("byte 타입으로 변환할 수 없습니다.");
        } else {
            byte b = (byte) i;
            System.out.println(b);
        }
    }
}

wrapper 클래스는 최대값과 최소값 상수를 제공하고 있다. (boolean, char은 없음)

ex) Integer.MIN_VALUE, Double.MAX_VALUE

2) 정수 타입을 실수 타입으로 변환할 때 정밀도 손실을 피해야 한다.

  • float: 부호(1비트) + 지수(8비트) + 가수(32비트)
  • double: 부호(1비트) + 지수(11비트) + 가수(52비트)
1
2
3
4
5
6
7
8
int num1 = 123456780;
int num2 = 123456780;

float num3 = num2;
num2 = (int) num3;

int result = num1 - num2;
System.out.println(result); //-4

int 값을 손실 없이 float타입의 값으로 변환할 수 있으려면 가수 23비트로 표현 가능한 값이어야 한다. 123456780은 23비트로 표현할 수 없기 때문에 근사치로 변환된다. 그렇기 때문에 float값을 다시 Int로 변환하면 원래의 Int값을 얻지 못한다.

  • 해결책: 모든 Int값을 실수 타입으로 안전하게 변환시키는 double타입을 사용하자!
  • int 크기는 32비트이기 때문에 double의 가수 52비트보다는 작기 때문에 어떠한 Int값이라도 안전하게 정밀도 손실 없이 double 타입으로 변환될 수 있다. 그래서 double 값을 원래 Int타입으로 변환해도 손실 없이 복원된다.

연산식에서의 자동 타입 변환

  • 연산은 기본적으로 같은 타입의 피연산자 간에만 수행된다.
  • 따라서 서로 다른 타입의 피연산자가 있을 경우 두 피연산자 중 크기가 큰 타입으로 자동 변환된 후 연산을 수행한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class OperationsPromotionExample {
    public static void main(String[] args){
        byte byteValue1 = 10;
        byte byteValue2 = 20;
        //byte byteValue3 = byteValue1 + byteValue2; //컴파일 에러!
        //type mismatch: cannot convert byte to int
        int intValue1 = byteValue1 + byteValue2;
        System.out.println(intValue1); //30
        
        char charValue1 = 'A';
        char charValue2 = 1;
        //char charValue3 = charValue1 + charValue2; //컴파일 에러!
        int intValue2 = charValue1 + charValue2;
        System.out.println("유니코드=" + intValue2);
        System.out.println("출력문자=" + (char)intValue2);
        
        int intValue3 = 10;
        //int intValue4 = intValue3 / 4.0; //컴파일 에러!
        double doubleValue = intValue3 / 4.0;
        System.out.println(doubleValue); // 2.5
    }
}

byteValue1 = 10은 괜찮으면서 byteValue3 = byteValue1 + byteValue2는 컴파일 에러가 날까? 이는 리터럴 자체가 4바이트인 int타입이 아니라, 연산의 기본단위가 int이기 때문이다. 연산을 하게 되면 각각의 값은 Int로 자동 타입 변환되고, 따라서 그 결과값도 int타입이 된다. 자동 타입 변환은 작은 크기를 가지는 타입이 큰 크기를 가지는 타입에 저장될 때 발생하는 것이니, 이 상황은 자동타입 변환의 상황이 아니다. 따라서 type mismatch 컴파일 오류가 나는 것이다. 정 byte에 넣고 싶다면 캐스팅 연산자로 강제 타입 변환을 해줘서 넣으면 될 것이다.

자바는 리터럴 간의 연산은 타입 변환 없이 해당 타입으로 계산한다.

This post is licensed under CC BY 4.0 by the author.

[JS] 생활코딩 #25: prototype

:coffee: [Java] 이것이 자바다 #3: 연산자

Loading comments from Disqus ...