Java基礎: HashSet 與 hashCode、equals

來源:互聯網
上載者:User

大家都說 Java 很簡單,的確 Java 入門不難,但是要想深入瞭解 Java 那不是一朝一夕能夠做到的!

學習 Java 最重要的一點是要學習其設計思想和設計理念,比如集合架構、IO架構的設計等。

通過一個執行個體談談 HashSet 與 hashCode、equals 的使用,以及在使用時的注意事項。

設計一個 Person 類,如下:

package mark.zhang;public class Person {private String name;private int age;public Person(String name, int age) {super();this.name = name;this.age = age;}public String getName() {return name;}public int getAge() {return age;}public void setName(String name) {this.name = name;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "age=" + age + ", name=" + name;}}

這個類很簡單,兩個成員變數以及 set、get 方法,注意這裡沒有重寫 equals、hashCode 方法。為了在列印的時候方便看出結果,重寫 toString 方法。

測試類別也照樣很簡單,如下:

public class TestPerson {public static void main(String[] args) {Set<Person> set = new HashSet<Person>();Person p1 = new Person("喜洋洋", 25);Person p2 = new Person("懶洋洋", 26);Person p3 = new Person("灰太郎", 27);set.add(p1);set.add(p2);set.add(p3);System.out.println(set.size() + " 個動畫人物!");for (Person person : set) {System.out.println(person);}}}

輸出結果,如下所示:

3 個動畫人物!age=27, name=灰太郎age=26, name=懶洋洋age=25, name=喜洋洋

ok,看懂上面的程式很簡單,只要你不是初學 Java 的話!但是今天的主題不是只討論這段代碼的難易程度。

如果在代碼中刪除一個“人”,很簡單,只需要調用 remove 方法即可,如下所示:

set.remove(p2);

這個時候,我需要修改 Person 這個類,重寫父類 Object 的兩個方法,equals、hashCode,修改之後的代碼:

package mark.zhang;public class Person {private String name;private int age;public Person(String name, int age) {super();this.name = name;this.age = age;}public String getName() {return name;}public int getAge() {return age;}public void setName(String name) {this.name = name;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "age=" + age + ", name=" + name;}@Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + age;result = prime * result + ((name == null) ? 0 : name.hashCode());return result;}@Overridepublic 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 (age != other.age)return false;if (name == null) {if (other.name != null)return false;} else if (!name.equals(other.name))return false;return true;}}

在測試類別中,開始這樣子做:

public class TestPerson {public static void main(String[] args) {Set<Person> set = new HashSet<Person>();Person p1 = new Person("喜洋洋", 25);Person p2 = new Person("懶洋洋", 26);Person p3 = new Person("灰太郎", 27);set.add(p1);set.add(p2);set.add(p3);System.out.println(set.size() + " 個動畫人物!");// 刪除一個對象set.remove(p2);System.out.println("刪除之後," + set.size() + " 個動畫人物!");for (Person person : set) {System.out.println(person);}}}

列印結果:

3 個動畫人物!刪除之後,2 個動畫人物!age=27, name=灰太郎age=25, name=喜洋洋

成功刪除一個對象,再次修改測試類別的代碼:

public class TestPerson {public static void main(String[] args) {Set<Person> set = new HashSet<Person>();Person p1 = new Person("喜洋洋", 25);Person p2 = new Person("懶洋洋", 26);Person p3 = new Person("灰太郎", 27);set.add(p1);set.add(p2);set.add(p3);System.out.println(set.size() + " 個動畫人物!");// 修改對象屬性p2.setName("美人魚");// 刪除一個對象set.remove(p2);System.out.println("刪除之後," + set.size() + " 個動畫人物!");for (Person person : set) {System.out.println(person);}}}

列印結果:

3 個動畫人物!刪除之後,3 個動畫人物!age=26, name=美人魚age=27, name=灰太郎age=25, name=喜洋洋

這次怪了,明明刪除一個了,怎麼還是有三個呢?你會發現,的確刪除一個“懶洋洋”,但是“美人魚”沒有被刪除!

如果你在 Person 類中,不重寫 hashCode 方法,不會有這種現象發生!

這裡說明一個問題:添加到集合的類,不要輕易去修改該類對象的屬性,否則 remove() 方法無效。同理 contains() 方法也會無效。


如果有興趣的話,可以看看其源碼,可以看出這與 hashCode() 方法有很大關係!

再說一個容易讓人誤解的問題:

Collection介面的子介面 List 和 Set,Set (包括其子類)無序不可重複,List (包括其子類)有序可重複,所謂有序無序是相對於 add 的程式執行順序來說的。

換句話說,對於上面的 List、Set 以及其子類等,如果 equals 為 true 的話,就算是重複的對象。這裡的 equals 比較的是內容,不是對象地址。
只不過,對於 Set 來說不可以添加重複對象,對於 List 來說可以添加重複對象!

對於添加對象到Set集合中,從源碼可以看出其流程是這樣子的:

將對象放入到集合中時,首先判斷要放入對象的hashcode值與集合中的任意一個元素的hashcode值是否相等,如果不相等直接將該對象放入集合中。
如果hashcode值相等,然後再通過equals方法判斷要放入對象與集合中的任意一個對象是否相等,如果equals判斷不相等,直接將該元素放入到集合中,否則不放入。

舉個例子,注意:Person 要重寫 hashCode、equals 方法:

public static void main(String[] args) {LinkedList<Person> list = new LinkedList<Person>();Set<Person> set = new HashSet<Person>();Person p1 = new Person("喜喜", 3);Person p2 = new Person("喜喜", 3);System.out.println("stu1 == stu2 : " + (p1 == p2));System.out.println("stu1.equals(stu2) : " + p1.equals(p2));// list可以重複list.add(p1);list.add(p2);System.out.println("list size:" + list.size());// set 不可以重複set.add(p1);set.add(p2);System.out.println("set size:" + set.size());}

列印結果:

stu1 == stu2 : falsestu1.equals(stu2) : truelist size:2set size:1

感謝下面兩篇部落格,我只是在它們的基礎之上添枝加葉。

再次感謝:

hashCode與equals的區別與聯絡

Java集合HashSet的hashcode方法引起的記憶體流失問題

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.