==
: 변수의 값을 비교하는 연산자.equals()
- 오버라이드 하지 않은 equals()는
==
와 동일하다.- 원하는 대로 오버라이드해서 사용하자.
카드 종류와 숫자를 변수로 가진 카드 클래스가 있다.
class Card {
private String kind;
private int number;
}
같은 값을 가지는 객체를 2개 생성하고 비교연산자 ==
로 두 객체가 같은지 확인한다.
public static void main(String[] args) {
Card card1 = new Card("spade", 1);
Card card2 = new Card("spade", 1);
System.out.println(card1 == card2); // false
}
false
가 출력된다.
먼저 기본형 변수와 참조형 변수의 차이를 알아야 한다.
기본형 타입 변수인 기본형 변수는 메모리에 실제 값을 저장한다.
// 기본형 타입
// boolean, char, byte, short, int, long, float, double - 8개
int i = 1;
boolean bool = true;
기본형 타입을 제외한 모든 타입의 변수인 참조형 변수는 메모리에 인스턴스의 주소를 값으로 갖는다.
// 참조형 타입
String str = "문자열";
Scanner sc = new Scanner(System.in);
변수 card1
과 card2
는 Card
타입의 참조형 변수다.
따라서 변수의 값을 비교하는 ==
연산자는 두 변수가 가지고 있는 인스턴스의 주소를 비교한다.
두 인스턴스는 같은 값("spade", 1)
을 가졌지만 하나의 인스턴스가 아니라 메모리에 독립적으로 자리한 인스턴스다.
System.out.println(System.identityHashCode(card1)); // 883049899
System.out.println(System.identityHashCode(card2)); // 2093176254
// 인스턴스 주소로 생성된 해시코드. 인스턴스의 주소가 같다면 같은 해시코드가 반환된다.
따라서 ==
비교 연산자로는 두 객체가 논리적으로 같은지 확인할 수 없다.
논리적으로 같다?
"두 객체의 id가 같으면 같은 객체다." , "두 객체의 일련번호가 같으면 같은 객체다."
와 같이 물리적으로 같은 객체는 아니지만 조건이 만족한다면 같은 객체로 취급한다.
그러면 어떻게 두 객체가 논리적으로 같은지 알 수 있을까?
Object 클래스에 정의된 equals를 사용하면 된다. 하지만 equals를 사용해도 false
가 나온다.
System.out.println(card1.equals(card2)); // false
그 이유는 Object 클래스에 정의된 equals 메서드를 확인해보면 알 수 있다.
public boolean equals(Object obj) {
return (this == obj);
}
// Object에 정의된 equals 메서드
여기도 ==
연산자를 이용해서 인스턴스 주소를 비교하고 있다.
따라서 equals를 오버라이드 해야 한다. 인스턴스 주소를 비교하지 않고 우리가 원하는 조건을 명시한다.
우리가 원하는 결과는 이렇다. “카드의 종류와 숫자가 같으면 같은 카드다.”
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Card card = (Card) o;
return number == card.number && Objects.equals(kind, card.kind);
}
// equals 오버라이드
System.out.println(card1.equals(card2)); // true
// equals 오버라이드 후 결과 확인
드디어 원하는 결과를 얻었다. :)