본문 바로가기

카테고리 없음

(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