1 java類中HashSet添加對象時,為什么一定要重寫equals方法和HasCode方法?
a Set集合沒有順序,也不允許重復,為什么會這樣?
答:是為了模擬現實的集合。
b 重復這里在現實中和內存中有什么區別?
答:現實中的重復指的是對象的重復,而內存中的重復指的hashCode的重復。
c 由於現實中和內存中的重復不同,存在一種情況,在內存中重復(hashCode)相同,現實中不是同一個對象,這種例子呢?
答:代碼如下,debug可以看到兩個person對象的hash碼相同,其屬性相同:
package com.array.set; import java.util.HashSet; import java.util.Iterator; import java.util.Set; public class TestHashSet2 { public static void main(String[] args) { Person p1 = new Person("a", 1); Person p2 = new Person("b", 0); Set<Person> set = new HashSet<Person>(); set.add(p1); set.add(p2); Iterator<Person> it = set.iterator(); while (it.hasNext()) { System.out.println(it.next().getName()); } } }
package com.array.set; import java.util.HashSet; import java.util.Iterator; import java.util.Set; class Person { private String name; private int id; Person(String name, int id) { this.name = name; this.id = id; } public void setName(String name) { this.name = name; } public String getName() { return name; } public void setId(int id) { this.id = id; } public int getId() { return id; } public int hashCode() { return name.hashCode() + id; // 使用字符串哈希值與Integer的哈希值的組合 // 這樣會產生重碼,實際上重碼率很高 } public boolean equals(Object obj) { if (obj instanceof Person) { // Person p = (Person) obj; return (name.equals(p.name) && id == p.id); } return super.equals(obj); } }
d 為了解決c這種情況(現實中的重復與內存的重復不一致),我們應該怎么做呢?
答:c代碼已經給了明顯的答案。
HashSet添加對象的時候,先用hashCode方法計算出該對象的哈希碼。
比較:
(1),如果該對象哈希碼與集合已存在對象的哈希碼不一致,則該對象沒有與其他對象重復,添加到集合中!
(2),如果存在於該對象相同的哈希碼,那么通過equals方法判斷兩個哈希碼相同的對象是否為同一對象(判斷的標准是:屬性是否相同)
1>,相同對象,不添加。
2>,不同對象,添加!
至此,1問題得到了解答。
-
總思路:hashCode不同時,則必為不同對象。hashCode相同時,根據equlas()方法判斷是否為同一對象。
-
在HashSet,HashMap,HashTable中都存在該問題。
2 為什么重寫Equals方法必須重寫HashCode方法?
答:1、將要傳入的數據根據系統的hash算法得到一個hash值;
2、根據hash值可以得出該數據在hash表中的位置;
3、判斷該位置上是否有值,沒有值則把數據插入進來;如果有值則再次判斷傳入的值與原值是否地址或equals相同,如果相同則不存,否則通過鏈表的方式 存儲到該位置。
如果兩個對象equals,但是沒有重寫hashcode,就會導致集合中可能存儲多個相等的對象!所以必須重寫!
引自:
https://jingyan.baidu.com/article/d5a880eb8fb61d13f147cc99.html
https://www.cnblogs.com/shew/p/11370804.html