equals은 객체의 타입이 String인 경우를 제외하고
참조값을 동일한지를 판단한다.
CASE : String
StringMember member3 = new StringMember("kim");
StringMember member4 = new StringMember("kim");
String s = "kim";
System.out.println("member3.hashcode() = " + member3.hashCode());
System.out.println("member4.hashcode() = " + member4.hashCode());
System.out.println("s.hashCode() = " + s.hashCode());
System.out.println("객체간 비교 : member3.equals(member4) = " + member3.equals(member4));
/**
* 두 경우 모두 String이기 때문에 값을 비교한다.
*/
System.out.println("객체의 값 비교 : member3.getName().equals(member4.getName()) = " + member3.getName().equals(member4.getName()));
/**
* 이 경우도 마찬가지이다.
*/
System.out.println("StringMember의 객체의 name 필드 값과 String 비교 : member3.getName().equals(s) = " + member3.getName().equals(s));
member3.hashcode() = 1032616650
member4.hashcode() = 75457651
s.hashCode() = 106191
객체간 비교 : member3.equals(member4) = false
객체의 값 비교 : member3.getName().equals(member4.getName()) = true
StringMember의 객체의 name 필드 값과 String 비교 : member3.getName().equals(s) = true
equals는 기본적으로 객체의 참조값을 비교한다. 그렇기 때문에 new로 생성된 인스턴스인 member3/member4가 다르다고 판단한다. 하지만 객체의 타입이 String인 경우에는 내용을 비교한다.
그래서 StringMember 객체 인스턴스들의 name 필드(타입 String)들에 equals을 걸면 true라고 반환한다.
우리는 값을 비교하고 싶을때가 많다. 그래서 equals을 재정의한다. member3/member4가 동일하다고 하고 싶다.
그래서 equals을 재정의한다.
StringMember 클래스의 equals 메서드를 아래와 같이 재정의했다고 해보자.
@Getter
class StringMember {
private String name;
public StringMember(String name) {
this.name = name;
}
@Override
public boolean equals(Object o) {
StringMember m = (StringMember) o;
return (this.getName() == m.getName());
}
}
public class StudyEqualAndHashcode {
public static void main(String[] args) {
StringMember member3 = new StringMember("kim");
StringMember member4 = new StringMember("kim");
String s = "kim";
/**
* 이 경우 equals 메서드를 재정의 했기 때문에 멤버변수인 name의 참조값이 같으면 true를 반환함
*/
System.out.println("객체의 값 비교 : member3.getName().equals(member4.getName()) = " + member3.getName().equals(member4.getName()));
}
}
Output
객체의 값 비교 : member3.getName().equals(member4.getName()) = true
좀 전과 다르게 객체의 값을 비교해도 true라고 뜬다.
하지만 이 경우 치명적인 문제가 있다.
객체가 동일하다고 판단하지만 사실은 두 객체의 멤버변수인 name 같은 것이다.
그래서 객체는 서로 다른 주소값을 가지고 이로 인해 서로 다른 해시코드를 가진다. 그래서 동일 객체를 제외할 수 있는 Set같은 경우 문제가 생기게 된다.
Set<StringMember> memberSet = new HashSet<>();
memberSet.add(member3);
memberSet.add(member4);
System.out.println(memberSet.size());
HashSet<Integer> hashSet = new HashSet<>();
hashSet.add(1);
hashSet.add(1);
System.out.println(hashSet.size());
우리는 위에서 equals 메서드를 재정의했기 때문에 memberSet의 size 1을 기대할 것이다. 하지만 결과는 2이다.
Output
2
1
오류를 바로잡기 위해서는 해시코드 메서드를 재정의해야한다.
@Override
public int hashCode() {
final int PRIME = 31;
return PRIME * getName().hashCode(); //올바른 사용법인지는 잘 모르겠다..
}
Output
1
1
잘못된 내용이 있다면 지적 부탁드립니다.
'Java' 카테고리의 다른 글
쓰레드 - 1. 쓰레드란? (0) | 2022.07.03 |
---|---|
JAVA - 함수 호출 방식 call by value, call by reference (0) | 2022.06.29 |
JVM의 메모리 관리, 클래스와 인스턴스 (0) | 2022.06.29 |
연산자 == /equals() 그리고 equals()와 hashCode()를 같이 재정의해야 하는 이유 (0) | 2022.06.18 |
Java - equals 재정의시 주의점 (0) | 2022.05.09 |