ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 이펙티브 자바 : 박싱 타입 vs. 기본 타입
    책책책 책을 읽읍시다/프로그래밍 2023. 7. 18. 21:49

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

     기본 타입과 박싱된 기본 타입의 주된 차이는 크게 세 가지이다. 첫 번째, 기본 타입은 값만 가지고 있으나, 박싱된 기본 타입은 값에 더해 식별성(identity)이란 속성을 갖는다. 달리 말하면 박싱된 기본 타입의 두 인스턴스는 값이 같아도 서로 다르다고 식별될 수 있다. 두 번째, 기본 타입의 값은 언제나 유효하나, 박싱된 기본 타입은 유효하지 않은 값, 즉 null을 가질 수 있다. 세 번째, 기본 타입이 박싱된 기본 타입보다 시간과 메모리 사용면에서 더 효율적이다. 이상의 세 가지 차이 때문에 주의하지 않고 사용하면 진짜로 문제가 발생할 수 있다.

    System.out.println(new Integer(42) == new Integer(42));

     위 코드의 결과는 false이다. == 연산자는 두 객체의 참조 식별성을 비교한다.

     박싱된 기본타입은 아래와 같이 기본 타입으로 바꿔주거나, 인스턴스의 값을 비교하는 메서드를 이용해야 한다.

    박싱 타입 비교

     이번엔 아래 코드를 보자.

    NPE와 친한 박싱 타입

     이 프로그램은 i == 42를 검사할 때 NullPointerException을 던진다. 원인은 i가 int가 아닌 Integer이며, 다른 참조 타입 필드와 마찬가지로 i의 초깃값도 null이라는 데 있다. 즉, i == 42는 Integer와 int를 비교하는 것이다. 거의 예외 없이 기본 타입과 박싱된 기본 타입을 혼용한 연산에서는 박싱된 기본 타입의 박싱이 자동으로 풀린다. 그리고 null 참조를 언박싱하면 NullPointerException이 발생한다. 해법은 i를 int로 선언해주면 된다.

     이 프로그램은 실수로 지역 변수 sum을 박싱된 기본타입으로 선언하여 느려졌다. 오류나 경고 없이 컴파일되지만, 박싱과 언박싱이 반복해서 일어나 체감될 정도로 성능이 느려진다. 박싱된 타입은 7.3초, 기본 타입은 1.2초가 걸렸다. 실무에서는 이렇게 뺑뺑이 도는 경우는 없지만 상당한 차이다.

     

     세 경우 모두 문제의 원인은 하나다. 기본 타입과 박싱된 기본 타입의 차이를 무시한 대가다. 그렇다면 박싱된 기본 타입은 언제 써야 하는가? 적절히 쓰이는 경우가 몇가지 있다. 첫 번째, 컬렉션의 원소, 키, 값으로 쓴다. 컬렉션은 기본 타입을 담을 수 없으므로 어쩔 수 없이 박싱된 기본 타입을 써야만 한다. 더 일반화해 말하면, 매개변수화 타입이나 매개변수화 메서드의 타입 매개변수로는 박싱된 기본 타입을 써야 한다. 자바 언어가 타입 매개변수로 기본 타입을 지원하지 않기 때문이다. 예컨대 변수를 ThreadLocal<int> 타입으로 선언하는 건 불가능하며, ThreadLocal<Integer>를 써야 한다. 마지막으로, 리플렉션을 통해 메서드를 호출할 때도 박싱된 기본 타입을 사용해야 한다.

    댓글

Designed by Tistory.