• 자바의 데이터 타입은 크게 두가지이다
    • int, double, boolean과 같은 기본타입과 String, List 같은 참조타입이다.
  • 그리고 각각의 기본 타입에는 대응하는 참조 타입이 하나씩있으며 이를 박싱된 기본타입이라 한다.
    • int - Integer, double - Double, boolean - Boolean

 

 

기본타입과 박싱된 기본타입의 차이점 세가지

  • 기본 타입은 값만 가지고 있으나 박싱된 기본 타입은 값에 더해 식별성(identity)이란 속성을 갖는다.
    • 박싱된 기본 타입은 값이 같아도 구별이 가능하다.
  • 기본 타입의 값은 언제나 유효하나 박싱된 기본타입은 null을 가질 수 있다.
  • 기본 타입이 박싱된 기본타입보다 시간과 메모리 사용면에서 더 효율적이다.

 

 

주의사항

//잘못 구현된 비교자
Comparator<Integer> naturalOrder =
    (i, j) -> (i < j) ? -1 : (i == j ? 0 : 1);

이것은 Integer값을 오름차순으로 정렬하는 비교자다.

 

naturalOrder.compare(new Integer(42), new Integer(42))의 값을 출력한다면

42와 42를 비교하는 것이기 때문에 우리는 결과값 0을 기대하지만 실제로는 1을 출력한다.

 

그 이유는 == 연산자가 Integer의 value를 확인하는 것이 아닌 같은 객체인지를 확인하기 때문이다.

 

이렇듯 박싱된 기본 타입에 == 연산자를 사용하면 오류가 일어난다.

 

이 문제를 고치려면 지역변수 2개를 두어 각각 박싱된 Integer에 매개변수의 값을 기본 타입 정수로 저장한 다음 모든 비교를 이 기본 타입 변수로 수행해야 한다.

//문제를 수정한 비교자
Comparator<Integer> naturalOrder = (iBoxed, jBoxed) -> {
    int i = iBoxed, int j = jBoxed;//오토박싱
    return (i < j) ? -1 : (i == j ? 0 : 1);
};

 

또 다른 문제

//박싱 타입은 초깃값이 null이다.

public class Unbelievable {
    static Integer i;

    public static void main(String[] args) {
        if (i == 42) {
            System.out.println("믿을 수 없군");
        }
    }
}
  • 기본 타입과 박싱된 기본타입을 혼용한 연산에서는 박싱된 기본 타입이 박싱이 자동으로 풀린다.
  • 그리고 null 참조를 언박싱하면 NullPointerException이 발생한다.
  • i를 int로 선언하면 문제 없다.

 

//성능 저하 문제
public static void main(String[] args) {
    Long sum = 0L;
    for (long i = 0; i <= Integer.MAX_VALUE; i++) {
        sum += i;
    }
}
  • sum은 Long이지만 i는 long이기 때문에 연산시에 박싱-언박싱이 계속 반복된다.
  • 불필요한 Long객체가 계속해서 생성되어 메모리도 낭비된다.

 

 

박싱된 기본 타입 사용하는 경우

  • 컬렉션의 원소, 키, 값으로 사용
    • 컬렉션은 기본타입을 담을 수 없기 때문
  • 리플렉션을 통해 메소드를 호출할 때
    • ITEM 65에서 정리 예정

 

 

정리

  • 기본타입과 박싱된 기본타입 중에서 가는하면 기본타입을 사용하자
  • 오토박싱과 언박싱을 유의할 것

+ Recent posts