equals & hashcode

sixhustle·2022년 3월 4일
0

Java

목록 보기
1/10

equals재정의할 때, hashCode도 같이 재정의해야 하는 이유를 알아보겠습니다.


Quiz

value1, value2, value3의 값을 맞추시오

public class Item {

    String id;

    public Item(String id) {
        this.id = id;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        Item item = (Item) o;
        return id == item.id && Objects.equals(id, item.id);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }

    public static void main(String args[]) {

        Item item1 = new Item("1");
        Item item2 = new Item("2");

        Map<Item, Integer> map = new HashMap<>();
        map.put(item1, 11111);
        map.put(item2, 22222);

        Map<Item, Integer> map1 = map;

        item1.id = "3";

        Integer value1 = map.get(new Item("1"));
        Integer value2 = map.get(item1);
        Integer value3 = map.get(new Item("3"));

    }
}

.
.
.
.
.
.
.
.
.
.
.

정답

value1 : null
value2 : null
value3 : null

풀이

value1

  1. new Item("1")으로 hashCode=80 객체를 생성
  2. hashCode=80 버킷을 조회, 버킷 안의 hashCode != 80이기 때문에 다른 객체로 판단
  3. 따라서 null

value2싱

  1. item1.id = "3"으로 변경되어 hashCode=82로 변경상태
  2. item1의 hashCode=82 버킷을 조회하면, null

value3

  1. new Item("3")으로 hashCode=82 객체를 생성
  2. hashCode=82 버킷을 조회하지만, null

결론부터

hash값을 사용하는 Collection(HashSet, HashMap, HashTable)은 동등성을 비교할 때,
equals뿐만 아니라 hashCode도 비교하기 때문입니다.

즉, 같은 같은 객체를 판단할 때, equals가 같다면 hashCode도 같아야하기 때문입니다.

HashMap

putVal

  1. hashCode에 맞는 bucket을 찾고
  2. hash 비교
  3. key 비교
final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {    
    ...
    if (((HashMap.Node)e).hash == hash && ((k = ((HashMap.Node)e).key) == key || key != null && key.equals(k)))
    ...    
}

getNode

  1. hashCode에 맞는 bucket찾고
  2. hash 비교
  3. key 비교
final HashMap.Node<K, V> getNode(int hash, Object key) {
    HashMap.Node[] tab;
    HashMap.Node first;
    int n;
    if ((tab = this.table) != null && (n = tab.length) > 0 && (first = tab[n - 1 & hash]) != null) {
        Object k;
        if (first.hash == hash && ((k = first.key) == key || key != null && key.equals(k))) {
            return first;
        }

        HashMap.Node e;
        if ((e = first.next) != null) {
            if (first instanceof HashMap.TreeNode) {
                return ((HashMap.TreeNode)first).getTreeNode(hash, key);
            }

            do {
                if (e.hash == hash && ((k = e.key) == key || key != null && key.equals(k))) {
                    return e;
                }
            } while((e = e.next) != null);
        }
    }

    return null;
}

equals

두 객체가 동일한 객체인지 판단하는 method. 동일한 주소를 가리킬 때 같다고 판단.

public boolean equals(Object obj) {
    return this == obj;
}

hashCode

객체의 메모리 주소를 integer값으로 반환한 값

public class Object {
   ...
   public native int hashCode(); // OS의 메소드 사용
}

System.identityHashCode(obj); // == obj.hashCode()를 출력하는 것. 참고용

Reference

0개의 댓글