본문 바로가기

언어/자바

자바 표현식 몰랐던 사실 정리

참고: https://en.wikibooks.org/wiki/Java_Programming/Primitive_Types

참고 서적: 자바 퍼즐러

 

자바 개발자라고 하기에는 자바에 대한 기초 지식이 부족하다고 느낀다.

char가 1바이트 일거라고 생각했는데 2바이트라니.

이 김에 정리하자

 

primitive type

type size (bits) min value max value Precision example
byte 8 -128 127 From +127 to -128 byte b = 65;
char 16 0 2^16-1 All Unicode characters[1] char c = 'A'; 
char c = 65;
short 16 -215 2^15-1 From +32,767 to -32,768 short s = 65;
int 32 -231 2^31-1 From +2,147,483,647 to -2,147,483,648 int i = 65;
long 64 -263 2^63-1 From +9,223,372,036,854,775,807 to -9,223,372,036,854,775,808 long l = 65L;
float 32 2-149 (2-2-23)·2127 From 3.402,823,5 E+38 to 1.4 E-45 float f = 65f;
double 64 2-1074 (2-2-52)·21023 From 1.797,693,134,862,315,7 E+308 to 4.9 E-324 double d = 65.55;
boolean 8 -- -- false, true boolean b = true;
void -- -- -- -- --

 

자바는 c, c++언어완는 다르게 unsigned 자료형이 없다.

따라서 할당 바이트중에 가장 상위 비트 (가장 왼쪽 비트)는 부호 비트이다.

 

%연산에 대한 오해

1%3 의 결과는 무엇일까? 1이다.

그렇다면 -1%3의 결과는 무엇일까?

나는 당연히 1일 것이라고 생각했다.

하지만 결과는 -1이다.

 

a%b의 결과는 a의 부호에 따라간다.

왜냐하면 (a/b)*b + a%b == a 이니까.

 

이 점을 간과하면 아래와 같은 코드를 작성하게 될 수도 있다.

boolean isOdd(int target) {
	return target%2 == 1;
}

 

정수는 기본적으로 int, 실수는 기본적으로 double 자료형으로 표현한다.

그래서 다른 정수 자료형으로 정수를 표현하기 위해서는 자료형 변환을 해야한다.

이 때 long으로 표현하기 위해 제공되는 접미사가 L(소문자도 가능)이다. 가급적 소문자는 쓰지 않도록! (숫자 1이랑 헷갈리니까..)

 

마찬가지로 다른 실수 자료형으로 실수를 표현하기 위해서는 자료형 변환을 해야한다.

이 때 float으로 표현하기 위헤 제공되는 접미사가 F(소문자도 가능)이다.

 

 

자바는 음수 정수를 2의 보수로 표현한다.

2의 보수는 1의 보수에서 1을 더한 값이다.

1의 보수가 비트로 표현하기에는 간단할 수도 있지만 연산을 할 때는 2의보수가 더 편하다.

따라서 자바는 2의 보수로 음수 정수를 표현한다.

 

자료형 확장, 축소

이항 연산자로 연산을 하는데 두 피연산자의 자료형이 다르다면 어떻게 될까?

기본적으론는 큰 자료형으로 변환이 된다.

(예외적으로 두 피연산자 중 하나가 String이면 다른 피연산잔는 String으로 변환되어 연산된다.)

 

이 때 자료형 축소, 변환이라는게 일어나는데 단순하게는 비트수가 늘어나는 것이라고 생각하면 된다.

이 때 주의할 것은, 부호가 있는 연산자(ex. int, short)가 확장이 필요할 때 부호의 확장이 일어나고, 부호가 없는 연산자(ex. char)는 0의 확장이 일어난다.

 

좀 지저분한 문제지만

System.out.println((int)(char)(byte)-1);

이 출력은 65535 == 2^16-1이다.

 

이유는 -1은 2의 보수로 인해 모든 비트가 1이다. 따라서 byte로 표현되면 1이 8개 있는 비트다.

이를 char로 형변환할 때 byte는 부호가 있는 자료형이기 때문이 부호 확장이 일어나서 16비트가 모두 1이 된다. (물론 char는 모두 양수로 표현하기에 값은 2^16-1 이다.)

이를 int로 다시 변환할 때 char는 부호가 없는 자료형이라서 0의 확장이 일어나고 결과적으로 상위 2바이트는 0, 하위 2바이트는 1이 된다.

따라서 결과는 2^16-1인 65535이다.

 

복합연산자

+=과 같은 연산자를 복합 연산자라고 부르는데, 

x +=y는 x = x + y의 결과와 같다

라고 배웠지만, 반틈만 맞는 답 같다.

복합 연산자 또한 대입 연산자이다.

 

만약 x가 int, y가 long 자료형이라면 x+=y는 문제 없이 컴파일 되지만 x = x+y는 컴파일 에러가 발생한다.

이유는 long자료형을 x에 대입할 수 없기 때문이다.

x+=y가 문제가 없는 이유는 복합 연산자는 왼쪽의 연산자로 자동 형변환을 해주기 때문이다.

 

char 형은 사칙연산에서 int로 취급된다.

문자는 사칙연산시에는 2바이트의 숫자로 인식된다. 

따라서 아래의 출력 값은 문자가 아닌 숫자이다.

System.out.println('a'+'a');
// aa 출력이 아닌, 특정 문자 출력도 아닌, 194가 출력된다.