== 연산자 : 기본형 비교 시 값을 비교, 객체 비교 시 주소 값으로 비교
equals() 메서드 : 기본적으로 객체의 주소 값으로 비교
값 타입의 동등성 비교에는 == 연산자를 사용할 수 있지만, 객체의 동등성 비교는 기본적으로 메모리 주소값을 기준으로 이루어지므로, 필드 값을 기준으로 객체의 동등성을 판단하려면 equals() 메서드를 오버라이딩하여 사용해야합니다.
equals() 오버라이딩 ⭐
class Person {
String name;
public Person(String name) {
this.name = name;
}
}
public class Example {
public static void main(String[] args) {
Person person1 = new Person("홍길동");
Person person2 = new Person("홍길동");
// false, == 은 객체 타입인 경우 주소값을 비교
System.out.println(person1 == person2);
// false, equals() 또한 객체 타입인 경우 주소값을 비교
System.out.println(person1.equals(person2))
}
}
객체를 비교할 때 주소값이 아니라 필드 값을 비교하도록 동동 비교 기준을 변경하고 싶다면 , equals() 메서드를 오버라이딩하여 재정의해야합니다.
class Person {
String name;
public Person(String name) {
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true; // 자신과 비교하면 true
if (!(o instanceof Person)) return false; // 같은 타입이 아닌 경우 false
// 같은 타입인 경우 다운캐스팅하여 필드 값 비교
Person person = (Person) o;
return Objects.equals(this.name, person.name);
}
}
객체의 고유한 정수 값( 주소 값으로 만든 고유한 숫자 값 )을 반환하는 메서드
자바에는 equals() 비교가 true인 두 객체는 hashCode() 값 또한 같아야한다는 규약이 있으므로, equals()를 재정의한다면 hashCode() 또한 재정의해야합니다.
만약 하지 않는다면 Hash를 사용하는 컬렉션에서는 중복을 검사할 때 hash 값을 사용하기에 문제가 발생할 수 있습니다
equals()만 재정의 한다면, 두 객체의 해시코드가 다르지만, 논리적으로 같은 객체로 판단됨
만약 hashSet에서 논리적으로 같은 두 객체를 추가한다고 할 때, 두 객체는 논리적으로는 같지만 해시 코드가 다르기에 컬렉션에 중복된 데이터가 들어가는 문제가 발생
hashCode 재정의
class Person {
public String name;
public Person(String name) {
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person p = (Person) o;
return Objects.equals(name, p.name);
}
// 주소 값이 아닌, 필드의 값을 통해 해시 값 생성
// Objects.hash(...)를 통한 구현은 내부적으로 배열을 사용하므로 성능적으로 좋지 않음
@Override
public int hashCode() {
return Objects.hash(name); // name 필드의 해시코드를 반환
}
// 성능이 민감한 클래스 hashCode 재정의
@Override
public int hashCode() {
int result = name.hashCode();
result = 31 * result;
return result;
}
}