본문으로 건너뛰기
개발 머꼬
개발 노트Java
hohyeon.dev15

Java Integer를 ==로 비교했더니 결과가 오락가락하는 이유

  • #Autoboxing
  • #Common Pitfall
  • #Engineering Note
  • #Java

문제 발생

Integer a = 100;
Integer b = 100;
System.out.println(a == b); // true

Integer c = 200;
Integer d = 200;
System.out.println(c == d); // false

같은 방식으로 만든 Integer인데 100은 ==가 true, 200은 false가 나와 당황하는 경우가 흔합니다.

원인 분석

Integer a = 100;처럼 primitive intInteger에 대입하면 오토박싱(autoboxing)이 일어나며, 내부적으로 Integer.valueOf(100)이 호출됩니다. Integer.valueOf()-128부터 127까지의 값을 미리 캐싱해두고, 이 범위 안의 값은 항상 같은 캐시된 객체를 반환합니다. 그래서 100은 같은 객체를 참조해 ==가 true가 됩니다.

하지만 200은 캐시 범위를 벗어나므로 valueOf()가 호출될 때마다 새 Integer 객체를 생성합니다. 겉보기엔 값이 같아도 서로 다른 객체이므로 ==(참조 비교)는 false입니다.

==는 객체의 참조를 비교하고, equals()는 객체가 정의한 을 비교합니다. Integer.equals()는 값을 비교하도록 오버라이드되어 있으므로 항상 올바른 결과를 줍니다.

해결 방안

  1. 박싱된 타입(Integer, Long, Character 등)을 비교할 때는 항상 .equals()를 씁니다.
System.out.println(c.equals(d)); // true
  1. Objects.equals()를 쓰면 둘 중 하나가 null이어도 NullPointerException 없이 안전하게 비교할 수 있습니다.
System.out.println(Objects.equals(c, d));
  1. 가능하면 박싱 타입 대신 primitive 타입(int, long)을 쓰는 것이 이런 함정 자체를 피하는 가장 확실한 방법입니다. primitive는 ==가 항상 값 비교입니다.
  2. 캐시 범위(-128~127)에 의존하는 코드를 짜지 않습니다 — 이 범위는 JVM 구현에 따라 늘어날 수 있지만(-XX:AutoBoxCacheMax 같은 옵션), 그 범위 자체에 의존하는 로직은 언제든 깨질 수 있는 우연한 동작입니다.

공식 문서

마지막 수정

좋아요북마크

댓글0

아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.