8) java.lang 패키지3 - 기본형

dev-mage·2022년 11월 14일
0

Hello Java World!

목록 보기
24/32
post-thumbnail

Java에서 기본형을 객체처럼 다루기

래퍼(Wrapper) 클래스

객체지향 프로그래밍에서는 모든 것을 객체로 다루어야 하는데 자바는 성능을 위해 8가지 기본형이라는 예외를 두었다. 그렇지만 기본형 변수도 때로 객체처럼 다루어야 하는 경우가 생긴다. 가령 매개변수로 객체를 요구하거나, 기본형 값이 아닌 객체로 저장해야 하거나, 객체간의 비교가 필요할 경우에는 기본형 값을 객체로 변환하여 작업을 수행해야 한다. 이럴 때 사용되는 것이 래퍼 클래스이며 기본형 데이터를 객체로 포장(wrap)해주는 8개의 래퍼 클래스가 있다. 래퍼 클래스는 각 자료형에 해당하는 값을 인자로 받아 해당 값을 가지는 객체로 만들어 준다. 8가지 기본형에 대응하는 래퍼 클래스는 다음과 같다.

기본형래퍼 클래스
byteByte
shortShort
intInteger
longLong
charCharacter
floatFloat
doubleDouble
booleanBoolean

오토박싱(autoboxing)과 언박싱(unboxing)

JDK 5 이전에는 기본형과 참조형 간의 연산이 불가능했기 때문에 래퍼 클래스로 기본형을 객체로 변환 후 연산해야 했다.

int int1 = 10;
Integer int2 = new Integer(10);

int int3 = int1 + int2; // JDK 5 이전: 에러! 기본형과 참조형 간의 연산 불가

그러나 JDK 5부터 기본형과 참조형 간의 연산이 자동적으로 되게끔 컴파일러가 동작한다. 기본형 값을 래퍼 클래스의 객체로 자동 변환해주는 것을 오토박싱이라고 하며 그 반대로 변환하는 것을 언박싱이라고 한다.

int int1 = 10;
Integer int2 = new Integer(10);

int1 = int2;
int2 = int1;

위 코드에서 int1 = int2;는 intValue()로 언박싱을, int2 = int1;는 valueOf()로 오토박싱을 컴파일러가 자동적으로 수행한 것을 볼 수 있다.

또한 래퍼 클래스는 모두 객체가 가지고 있는 값을 비교하도록 equals 메서드를 오버라이딩하고 있다. 기본형과 비교가 아닌 객체끼리의 비교는 equals 메서드를 사용해야 한다.

int int1 = 10;
Integer int2 = 10;
Integer int3 = new Integer(10);

System.out.println(int1 == int3); // true
System.out.println(int2 == int3); // false
System.out.println(int2.equals(int3)); // true

char char1 = 'a';
Character char2 = 'a';
Character char3 = new Character('a');

System.out.println(char1 == char3); // true
System.out.println(char2 == char3); // false
System.out.println(char2.equals(char3)); // true

boolean bool1 = true;
Boolean bool2 = true;
Boolean bool3 = new Boolean(true);

System.out.println(bool1 == bool3); // true
System.out.println(bool2 == bool3); // false
System.out.println(bool2.equals(bool3)); // true

valueOf 메서드

public static void main(String[] args) {
    int int1 = 10;

    Integer int2_1 = 10;
    Integer int2_2 = Integer.valueOf(10);

    Integer int3 = new Integer(10);
}

위 코드의 바이트코드를 확인해보면 int2_1int2_2가 똑같이 valueOf 메서드를 호출하는 것으로 컴파일된 사실을 알 수 있다. new 연산자를 사용해 Integer 객체를 생성하지 않고 바로 정수형 리터럴을 할당하는 경우 컴파일러가 내부적으로 valueOf 메서드를 추가하는데, 이는 valueOf 메서드가 자주 쓰이는 값의 캐싱을 통해 성능적인 측면에서 생성자보다 나아 높은 우선순위를 가지기 때문이다.

Integer와 Short 클래스의 valueOf 메서드는 다른 정수형 래퍼 클래스들과 다른 점을 하나 가지고 있다. 아래 코드에서 int1int2의 동등비교 결과는 true이지만 int3int4의 결과는 false이다.

Integer int1 = 10;
Integer int2 = 10;

System.out.println(int1 == int2); // true

Integer int3 = 10000;
Integer int4 = 10000;

System.out.println(int3 == int4); // false

API를 확인해보면 -128 ~ 127까지의 값은 항상 캐싱돼 있어 같은 값을 가져와 쓰게 되기 때문에 int1int2는 같은 값을 참조하게 된다. 따라서 동등비교 결과가 true인 것이다.

Character 클래스의 valueOf 메서드도 u0000 ~ u007F까지의 값을 캐싱한다.


References

0개의 댓글