(JAVA) equals에 대해서(5) - hashCode 재정의
equals를 재정의한 클래스 모두에서 hashCode도 재정의해야 한다.
만약 위의 원칙을 어긴다면 hashCode의 일반 규약을 어기게 된다. (HashMap, HashSet에 해당 인스턴스를 사용 시 문제 발생)
https://jwdeveloper.tistory.com/159
(JAVA) 자바에서 hashCode의 사용
자바에서 hashCode를 사용하는 이유 Collection을 사용하는 단순한 연산이 특정 상황에서 비효율적일 수 있기 때문에 hashCode를 사용한다. 예를 들자면 List words = Arrays.asList("Welcome", "to", "j..
jwdeveloper.tistory.com
equals(Obj) 가 두 객체를 같다고 판단하였으면, 두 객체의 hashCode는 똑같은 값을 반환해야 한다.
객체를 Key 로 두고 Value를 junwoo 라고 하였다.
get 을 이용해서 해당 Key를 호출하였지만 결과는 junwoo가 아닌 null이이다.
/**
* Project : EffectiveStudy
* Created by InteliJ IDE
* Developer : junwoochoi
* Date : 09/02/2020
* Time : 10:32 오후
*/
public class equalsWithHashcode {
public static void main(String[] args) {
Map<PhoneNumber, String> m = new HashMap<>();
m.put(new PhoneNumber(707,867,5309),"junwoo");
String result = m.get(new PhoneNumber(707, 867, 5309));
System.out.println(result);
}
}
이유는 객체를 두번 생성하였기 때문에 각각의 객체의 주소가 다르기 때문이다.
또 다른 이유는 hashCode를 재정의하지 않았기 때문에 Object 클래스의 정의된 hashCode의 디폴트 값을 참조하기 때문이다.
만약 객체 생성시 hashCode를 확인하여 출력한다면 알맞은 결과를 확인할 수 있다.
public class equalsWithHashcode {
public static void main(String[] args) {
Map<Integer, String> m = new HashMap<>();
m.put(new PhoneNumber(707,867,5309).hashCode(),"junwoo");
Iterator iterator = m.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry entry = (Map.Entry) iterator.next();
System.out.println("key :: "+ entry.getKey());
}
String result2 = m.get(1927950199);
System.out.println(result2);
}
}
두개의 인스턴스를 같은 버킷에 담았다고 하더라도 해시코드는 다르기에 여전히 null을 반환한다.
똑같은 해시코드를 리턴한다면 결과는 어떻게 될까?
42를 리턴하는 hashCode를 재정의하자
@RunWith(JUnit4.class)
public class equalsWithHashcodeTest {
@Test
public void hashCodeOverride() {
HashMap<ExtendedPhoneNumber, String> map = new HashMap<>();
map.put(new ExtendedPhoneNumber(707,867,5307), "제니");
System.out.println("HashCode of Instance 1 :: "+ new ExtendedPhoneNumber(707,867,5307).hashCode());
System.out.println("HashCode of Instance 2 :: "+ new ExtendedPhoneNumber(707,867,5301).hashCode());
Assert.assertEquals(map.get(new ExtendedPhoneNumber(707,867,5301)),"제니");
}
public static class PhoneNumber {
protected int firsrtNumber;
protected int secondeNumber;
protected int thirdNumber;
public PhoneNumber(int firsrtNumber, int secondeNumber, int thirdNumber) {
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof PhoneNumber))
return false;
PhoneNumber p = (PhoneNumber)obj;
return this.firsrtNumber == p.firsrtNumber &&
this.secondeNumber == p.secondeNumber &&
this.thirdNumber == p.thirdNumber;
}
}
public static class ExtendedPhoneNumber extends PhoneNumber {
public ExtendedPhoneNumber(int firsrtNumber, int secondeNumber, int thirdNumber) {
super(firsrtNumber, secondeNumber, thirdNumber);
}
@Override
public int hashCode() {
return 42;
}
}
}
오류가 나지 않는 것을 보면 같은 해쉬코드를 key로 가지면 같은 value를 참조한다는 것을 볼 수 있다.
만일 우리가 ExtendedPhoneNumber 클래스의 인스턴스를 HashMap의 Key값으로 사용한다면 hashCode 메소드를 재정의 해야한다.
재정의 시 "똑같은 객체는 똑같은 hashCode를 리턴한다" 라는 기준을 생각하면서 정의하자!
@Override
public final int hashCode() {
int result = 17;
if (city != null) {
result = 31 * result + city.hashCode();
}
if (department != null) {
result = 31 * result + department.hashCode();
}
return result;
}
https://www.baeldung.com/java-hashcode
Guide to hashCode() in Java | Baeldung
Learn how hashCode() works and how to implement it correctly.
www.baeldung.com
https://www.baeldung.com/java-equals-hashcode-contracts
Java equals() and hashCode() Contracts | Baeldung
Learn about the contracts that equals() and hasCode() need to fulfill and the relationship between the two methods
www.baeldung.com
https://www.techiedelight.com/override-equals-hashcode-method-java/
Override equals and hashCode method in Java - Techie Delight
In this post, we will see how to override equals and hashCode method in Java. The general contract for overriding equals is proposed in Josh Bloch's Effect
www.techiedelight.com