[JAVA] Integer 비교 시 ==가 아닌 equals() 를 사용하는 이유
int, Integer 차이와 Integer 비교 시 ==가 아닌 equlas()를 사용하는 이유를 함께 알아보고자한다.
보통 정수형은 ==를 사용하여 비교한다. String 객체는 equals를 사용하여 비교하는데, int는 보통 ==를 사용하여 비교했다.
기본타입을 wrapper class로 바꾸면 아래와 같이 된다.
| 기본타입 | Wrapper Class |
| byte | Byte |
| short | Short |
| int | Integer |
| long | Long |
| float | Float |
| double | Double |
| char | Character |
| boolean | Boolean |
기본 타입은 산술연산이 가능하며 null로 초기화 할 수 없다.
Wrapper 클래스는 Unboxing 없이는 산술연산이 불가능하고 null 값을 처리할 수 있다.
Integer 객체들끼리 산술연산이 가능한 것은 JDK 1.5 이후 자바에서 AutounBoxing 을 지원하기 때문.
아래 프로그램의 결과를 확인해보면 셋 다 TRUE 로 나올 것으로 예상하지만 TRUE, FALSE, TRUE 로 출력된다.
Integer A= 300;
int B = 300;
Integer C= 300;
Integer X = 10;
Integer Y = 10;
if (A == B) {
System.out.println("true");
} else {
System.out.println("false");
}
// true 출력됨
if (A == C) {
System.out.println("true");
} else {
System.out.println("false");
}
// FALSE 출력됨
if (X == Y) {
System.out.println("true");
} else {
System.out.println("false");
}
// TRUE 출력됨
여기서 A와 B 중, B가 int 기본형이기 때문에 A와 B 모두가 int로 변환되어 int형끼리의 연산으로 생각하고 비교한다. int형이 하나 있으면 int형으로 연산하는 것이다.
A와 C는 모두 참조 타입으로, 매번 새로 생성되기 때문에 주소 값이 다르다. 때문에 비교 시 주소값이 다르기 때문에 FALSE가 반환된다. (예외 상황은 아래 서술)
여기서 참조 타입이란 실제 객체가 아닌 객체의 주소를 저장하고 있다.
int 값을 반환하는 메서드에 관해 확인해보자면,
parseInt()
string 형 객체에서 int형 값을 추출하는 메서드. static으로 Integer 생성 없이 파라미터만 넣어주면 메서드 실행 가능. Wrapper 클래스를 생성하지 않고 내용물만 string에서 int로 교체한다.
Integer.parseInt("문자"); 와 같이 사용한다.
리턴값이 int형으로, 산술 연산이 가능하다.
valueOf()
Integer 클래스를 리턴해주기 때문에 산술 연산이 불가능하다.
intValue()
Integer 객체에서 int형 값을 추출하는 메서드. static이 아니므로 객체가 필요하며 Object 타입을 int로 변환한다.
int x = Integer객체.intValue(); 로 사용한다.
리턴값이 int 형으로, 산술 연산이 가능하다.
다시 문제로 돌아가서,
Integer A = 300; -> Integer A = Integer.valueOf(300); 으로 변환하는데 (원시타입을 참조타입으로 변환)
이 때 Integer.valueOf() 메소드는 -128에서 127 사이의 int형 리터럴을 넘겨줄 때, 새로운 Integer 객체를 생성하지 않고 내부에 있는 IntegerCache 객체에서 Integer 객체를 반환한다.
-128~-127 범위는 정수 객체를 캐싱하기 때문에 주소값이 같으며, int형끼리 비교하는 것과 같은 결과가 나온다.
X 와 Y는 둘 다 10으로, 캐싱된 INTEGER 객체를 가져오기 때문에 주소값이 같아, == (주솟값 비교) 시 TRUE이지만,
A와 C는 둘 다 300으로, 값만 봐서는 같아 보이지만 신규 생성된 INTEGER 객체로 주소값이 달라 FALSE 가 출력되는 것.
따라서 INTEGER 끼리의 비교에서는 == 사용 시, 의도한 결과가 나오지 않을 수 있다. (나도 디버깅 하면서 INTEGER == 가 제대로 되지 않고 있다는걸 알았다.)
String을 비교 시에만 equals를 사용하는 것이 아닌, 참조 타입, Integer 값끼리의 비교 시에도 equals 를 사용하여야 한다.