먼저 결론을 말씀드리겠습니다.
equal을 다시 작성하는 데 반드시 해시코드가 필요한 것은 아니며 실제 상황에 따라 다르다는 점을 먼저 분명히 해야 합니다. 예를 들어 컨테이너를 사용하지 않는 경우에는 필요하지 않지만 HashMap과 같은 컨테이너를 사용하고 사용자 정의 개체를 Key로 사용하는 경우 다시 작성해야 합니다.
(동영상 공유 학습: java 동영상 튜토리얼)
같음 다시 작성은 인스턴스가 비즈니스 로직에서 동일한지 여부를 확인하는 것입니다. hascode를 다시 작성하는 목적은 컬렉션의 가중치를 빠르게 결정하는 것입니다.
HashCode() 및 equals() 규정:
1. 두 개체가 동일하면 해시 코드도 동일해야 합니다.
2. 두 개체가 동일하면 equals() 메서드는 두 개체 모두에 대해 true를 반환합니다. 객체는 동일한 해시코드 값을 가지며 반드시 동일하지는 않습니다
4. 요약하자면, equals() 메서드가 재정의된 경우 hashCode() 메서드도 재정의되어야 합니다
5. 객체는 고유한 값을 생성합니다. hashCode()가 재정의되지 않으면 이 클래스의 두 객체는 어쨌든 동일하지 않습니다(두 객체가 동일한 데이터를 가리키는 경우에도).
public class Test { static class Order { private Long orderId; public Order(Long orderId) { this.orderId = orderId; } public Long getOrderId() { return orderId; } public void setOrderId(Long orderId) { this.orderId = orderId; } @Override public boolean equals(Object obj) { if (obj != null && !(obj instanceof Order)) { return false; } return Objects.equals(this.orderId, ((Order) obj).orderId); } @Override public String toString() { return "Order{" + "orderId=" + orderId + '}'; } } public static void main(String[] args) { Map<Order, String> map = new HashMap<>(); Order order1 = new Order(1000000001L); Order order2 = new Order(1000000001L); map.put(order1, ""); map.put(order2, ""); System.out.println(map); } }
{Order{orderId=1000000001}=, Order{orderId=1000000001}=}
equals 재작성 논리는 orderId가 동일한 한 두 개체가 동일하다는 것입니다.
실행 결과에 따르면 동일한 orderId를 가진 두 개체가 성공적으로 맵에 추가되었습니다. 논리적으로 예상되는 결과는 맵에서 단 하나의 Order여야 하기 때문에 이는 논리적 오류입니다.
해시맵의 소스코드를 살펴보겠습니다
댓글로 판단만 봐주세요
public V put(K key, V value) { return putVal(hash(key), key, value, false, true); } static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); } final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Node<K,V>[] tab; Node<K,V> p; int n, i; if ((tab = table) == null || (n = tab.length) == 0) n = (tab = resize()).length; // 通过hash算出索引 通过索引取值==null的话 直接直接插入到索引位置。 if ((p = tab[i = (n - 1) & hash]) == null) tab[i] = newNode(hash, key, value, null); else { Node<K,V> e; K k; if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) e = p; else if (p instanceof TreeNode) e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value); else { for (int binCount = 0; ; ++binCount) { if ((e = p.next) == null) { p.next = newNode(hash, key, value, null); if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st treeifyBin(tab, hash); break; } if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) break; p = e; } } if (e != null) { // existing mapping for key V oldValue = e.value; if (!onlyIfAbsent || oldValue == null) e.value = value; afterNodeAccess(e); return oldValue; } } ++modCount; if (++size > threshold) resize(); afterNodeInsertion(evict); return null; }
public class TestHash { static class Order { private Long orderId; public Order(Long orderId) { this.orderId = orderId; } public Long getOrderId() { return orderId; } public void setOrderId(Long orderId) { this.orderId = orderId; } @Override public boolean equals(Object obj) { if (obj != null && !(obj instanceof Order)) { return false; } return Objects.equals(this.orderId, ((Order) obj).orderId); } @Override public int hashCode() { // 这里简单重写下 实际开发根据自己需求重写即可。 return this.orderId.intValue() >> 2; } @Override public String toString() { return "Order{" + "orderId=" + orderId + '}'; } } public static void main(String[] args) { Map<Order, String> map = new HashMap<>(); Order order1 = new Order(1000000001L); Order order2 = new Order(1000000001L); map.put(order1, ""); map.put(order2, ""); System.out.println(map); } }
{Order{orderId=1000000001}=}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Node<K,V>[] tab; Node<K,V> p; int n, i; if ((tab = table) == null || (n = tab.length) == 0) n = (tab = resize()).length; // 重写hashCode之后两个对象的orderId相同,hashCode也肯定相同。 // 通过hash算出索引 通过索引取值 有值不进入if。 if ((p = tab[i = (n - 1) & hash]) == null) tab[i] = newNode(hash, key, value, null); else { Node<K,V> e; K k; // 由于重写了hashCode 旧对象的hashCode和新的肯定相等 if (p.hash == hash && // (k = p.key) == key == false 因为比较的是对象地址 // (key != null && key.equals(k)) == true 因为重写了equals orderId相等则相等 ((k = p.key) == key || (key != null && key.equals(k)))) // 保存旧Node e = p; ....... if (e != null) { // existing mapping for key V oldValue = e.value; if (!onlyIfAbsent || oldValue == null) // value覆盖旧Node的值 e.value = value; afterNodeAccess(e); return oldValue; } } ........ }
왜 평등을 판단해야 하나요? hashCode를 기준으로 찾은 것은 연결리스트이므로, 같음을 기준으로 한 연결리스트에서 동일한 Key를 갖는 값을 찾아야 합니다.
public class Test { static class Coordinate { public Coordinate(int x, int y) { this.x = x; this.y = y; } private int x; private int y; public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } } public static void main(String[] args) { Map<Coordinate, String> map = new HashMap<>(); map.put(new Coordinate(22, 99), "手机"); map.put(new Coordinate(44, 48), "电脑"); } }
위 내용은 같음을 다시 작성할 때 Java에서 해시코드를 다시 작성해야 하는 이유는 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!