HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
🛁
공부기록
/
📚
책 정리
/
🥏
Item61 - 박싱된 기본 타입보다는 기본 타입을 사용하라
🥏

Item61 - 박싱된 기본 타입보다는 기본 타입을 사용하라

속성
9장
1️⃣  박싱된 기본 타입이란?자바의 데이터 타입 2가지기본타입과 박싱된 참조타입의 차이점은?2️⃣  기본 타입 vs 박싱된 기본 타입주의사항1 - 박싱된 기본 타입의 == 연산주의사항2 - 박싱된 기본 타입과 기본 타입의 연산주의사항3 - 박싱된 기본 타입과 기본 타입의 혼합반드시 박싱된 기본 타입을 사용해야하는 경우🧑🏻‍⚖️  결론
 

1️⃣  박싱된 기본 타입이란?

  • Integer, Long, Double 등 기본 타입에 대응하는 참조타입을 박싱된 기본타입이라고 한다.

자바의 데이터 타입 2가지

  • 기본타입 : int, long, float, double 등등등
  • 참조타입 : String, Integer, List 등등등
  • 기본타입은 모두 대응되는 참조타입이 있으며, 이를 박싱된 기본 타입이라고 부른다.
    • 개발을 하다보면 오토박싱, 오토언박싱 덕분에 두 타입을 구분하지 않고 사용하지만 둘의 차이는 알고 있어야함

기본타입과 박싱된 참조타입의 차이점은?

  1. 기본타입은 값만 가질 수 있다. 반면 박싱 타입은 값 자체와는 구별되는 식별성을 갖게된다.
  1. 기본타입은 완전한 함수적 값이지만, 박싱 타입은 하나의 함수적이지 않은 값, null 취급이 가능하다.
  1. 기본타입은 박싱 타입보다 시간 효율성과 공간 효율성이 높다.

2️⃣  기본 타입 vs 박싱된 기본 타입

  • 기본 타입은 값만 가지고 있지만 박싱된 기본 타입은 값과 식별성을 가진다.
final int num1 = 100; final int num2 = 100; sout(num1==num2); // TRUE final Integer num3 = 100; final Integer num4 = 100; sout(num3==num4) // TRUE sout(num3.equals(num4) // TRUE final Integer num5 = new Integer(100); final Integer num6 = new Integer(100); sout(num5==num6); // FALSE sout(num5.equals(num6); // TRUE
용훈님의 질문
  • 자바는 실행 시 Integer같은 경우는 리터럴로 값을 할당해줄 때 Integer.valueOf() 를 통해서 값이 저장되게 됩니다.
    • Integer.valueOf() 는 자주 사용하는 숫자 -128~127까지는 미리 캐시에 등록되어 있는 것을 사용하게 됩니다. 따라서 -128 ~127 까지의 == 비교는 같다는 결과를 얻을 수 있어요 🙂
notion image
notion image
notion image
  • 기본 타입의 값은 항상 유효하지만 박싱된 기본 타입은 null을 가질 수 있다.
int num = null // 요것은 안되겠쥬? Integer num = null // 요것은 가능하겠쥬?
  • 기본 타입이 박싱된 기본 타입보다 시간과 메모리 측면에서 효율적이다.
🧐
세가지 차이점 때문에 주의하지 않으면 문제나 성능 이슈가 생길 수 있음 !
 

주의사항1 - 박싱된 기본 타입의 == 연산

  • 박싱된 기본 타입의 == 연산은 식별성 검사를 하게된다.
    • 아래의 코드는 제대로 동작하는 것처럼 보이지만 문제가 존재한다. 그것은 Integer를 new 예약어로 같은 값을 넣어서 사용하게 된다면 value1==value2 는 false로 나오게 된다.
    • 이 부분은 String을 new 키워드로 생성하지 않고 리터럴로 생성하는 이유와 같으며 이러한 부분때문에 박싱된 타입은 ==으로 비교하는게 아니라 eqauls로 비교해야 한다.
Comparator<Integer> natureOrder = (value1, value2) -> (value1 < value2) ? -1 : (value1 == value2 ? 0 : 1); natureOrer.compare(new Integer(40), new Integer(40)); // 결과는 1이나온다. // 굳이 해결하자면 ? // 아래처럼 오토언박싱을 사용하면 되긴 하지만 굳이 라는 생각이 든다. Comparator<Integer> natureOrder = (value1, value2) -> { int num1 = value1; int num2 = value2; (num1 < num2) ? -1 : (num1 == num2 ? 0 : 1); }

주의사항2 - 박싱된 기본 타입과 기본 타입의 연산

  • 박싱된 기본 타입과 기본 타입의 연산에서는 대부분 박싱된 기본 타입을 오토 언박싱 한다.
    • 이때, 박싱된 기본 타입이 null이면 NullPointerException이 발생한다.
public class Unbelievable { static Integer i; public static void main(String[] args) { if (i == 42) System.out.println("믿을 수 없군!"); } }

주의사항3 - 박싱된 기본 타입과 기본 타입의 혼합

  • 기본타입을 오토박싱으로 바꾸거나 박싱된 타입을 다시 기본타입으로 변경하는 작업은 불필요한 객체가 생성되며 이런 작업이 반복된다면 성능저하가 일어날 수 있다.
public static void main(String[] args) { Long sum = 0L; for(long i = 0; i <= Integer.MAX_VALUE; i++) { sum += i; // 오토박싱 } System.out.println(sum); }
용훈님의 질문
notion image

반드시 박싱된 기본 타입을 사용해야하는 경우

  1. 컬렉션의 원소, 키, 값으로 사용할 경우
    1. 이 부분은 컬렉션을 사용할 때 어쩔 수 없이 기본타입을 사용하지 못하기 때문에 사용해야합니다.
  1. 매개변수화 타입이나 매개변수화 메서드의 타입 매개변수(제네릭)
    1. 제네릭에서도 기본타입을 지원하지 않기 때문
  1. 리플렉션을 통해 메서드를 호출할 경우
 

🧑🏻‍⚖️  결론

  • 기본 타입과 박싱된 기본 타입 중 하나를 선택해야 한다면 가능하면 기본 타입을 사용하자.
  • 박싱된 기본 타입을 == 연산자로 비교하면 식별성 비교가 이루어진다.
    • 박싱된 기본 타입은 equals를 사용하자.
  • 박싱된 기본 타입과 기본 타입을 혼용하면 언박싱이 일어나며, 그 과정에서 NPE가 발생할 수 있다.
  • 기본 타입을 박싱, 언박싱하는 작업은 필요없는 객체를 생성하는 부작용을 만들고 성능 이슈를 만들 수 있다.