有上一節可以知道,HashSet底層存儲方式是按照存儲元素的Hash值來確定的,Set集合不能重復,也跟元素的HashCode值不同有關;
使用HashSet來存儲自定義類對象,必須在對象類內部實現HashCode方法和equal方法。
HashSet判斷儲存元素是否重復的方法:
(1)在向Set集合中存放元素時,Set集合根據元素的hashCode()方法來獲取一個int類型的數據,然后根據這個數據來計算元素在集合中的位置。但是在存儲元素時會出現兩個元素的hashCode()方法返回值相同的情況。
(2)如果發生了返回值相同的情況,Set集合會根據發生沖突元素之間調用equals()方法進行比較,如果equals()返回值為true,說明兩個元素為相同的元素,這樣會導致添加操作無效。如果equals()返回值為false,說明兩個元素不相同,這樣Set集合會將該元素進行偏移存儲。
(3)元素hashcode值相同發生的頻率越高,Set集合的性能就越低,要盡可能的避免沖突的發生, 就要在類中重寫hashCode()方法,并且要盡可能的保證hashCode()方法返回值是唯一的。
(4)在重寫hashCode()方法時有個技巧,就是讓對象中的數值屬性和一個素數相乘,并將積相加,獲取對象類型的hashcode,調用其hashCode()方法即可得到。
驗證HashSet存儲基本數據類型元素不可重復性:
public class HashSetDemo {
public static void main(String[] args){
HashSet hs = new HashSet();
hs.add("a");
hs.add("c");
hs.add("d");
hs.add("a");
for(Iterator it = hs.iterator(); it.hasNext();){
System.out.println(it.next());
}//d c a
for(Object str : hs){
System.out.println(str);
}// da c a
}
}
Set存儲自定義類對象,元素重復的現象:
public class HashSetDemo {
public static void main(String[] args){
HashSet hs = new HashSet();
Person p1 = new Person(1, "lili");
Person p2 = new Person(2, "lili");
Person p3 = new Person(2, "lili");
hs.add(p1);
hs.add(p2);
hs.add(p3);
System.out.println(hs.size());
for(Iterator it = hs.iterator(); it.hasNext();){
System.out.println(it.next());
}
}
}
上述例子運行結果為:
3
[ id: 1,name: lili]
[ id: 2,name: lili]
[ id: 2,name: lili]
由此可見,如果我們不再自定義類中中定義元素是否相同的兩個比較方發(HashCode和equals)那么,set集合很可能就判斷不出我們存儲了重復元素;
如果我們在地定義的Person類中覆寫了hashcode和equals方法那么運行結果就不存在重復元素了;
eclipse字節就可以根據我們所需要的屬性值來生成這兩個方法:
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Id;
result = prime * result + ((name == null) ? 0 : name.hashCode());//如果姓名為空則表達式值為0;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (Id != other.Id)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}