Java Integer를 ==로 비교했더니 결과가 오락가락하는 이유
문제 발생
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 int를 Integer에 대입하면 오토박싱(autoboxing)이 일어나며, 내부적으로 Integer.valueOf(100)이 호출됩니다. Integer.valueOf()는 -128부터 127까지의 값을 미리 캐싱해두고, 이 범위 안의 값은 항상 같은 캐시된 객체를 반환합니다. 그래서 100은 같은 객체를 참조해 ==가 true가 됩니다.
하지만 200은 캐시 범위를 벗어나므로 valueOf()가 호출될 때마다 새 Integer 객체를 생성합니다. 겉보기엔 값이 같아도 서로 다른 객체이므로 ==(참조 비교)는 false입니다.
==는 객체의 참조를 비교하고, equals()는 객체가 정의한 값을 비교합니다. Integer.equals()는 값을 비교하도록 오버라이드되어 있으므로 항상 올바른 결과를 줍니다.
해결 방안
- 박싱된 타입(
Integer,Long,Character등)을 비교할 때는 항상.equals()를 씁니다.
System.out.println(c.equals(d)); // trueObjects.equals()를 쓰면 둘 중 하나가null이어도NullPointerException없이 안전하게 비교할 수 있습니다.
System.out.println(Objects.equals(c, d));- 가능하면 박싱 타입 대신 primitive 타입(
int,long)을 쓰는 것이 이런 함정 자체를 피하는 가장 확실한 방법입니다. primitive는==가 항상 값 비교입니다. - 캐시 범위(
-128~127)에 의존하는 코드를 짜지 않습니다 — 이 범위는 JVM 구현에 따라 늘어날 수 있지만(-XX:AutoBoxCacheMax같은 옵션), 그 범위 자체에 의존하는 로직은 언제든 깨질 수 있는 우연한 동작입니다.
댓글0
댓글을 남기려면 로그인이 필요해요. 로그인
아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.