1. 程式人生 > >List去重為什麽要寫equals(),hashCode()方法

List去重為什麽要寫equals(),hashCode()方法

進行 新的 河南 需要 sta 電話 string類 ava reg

一,各個集合的特點:

  •   Collection(集合):容器,用於存放對象(引用類型。基本類型需要自動裝箱)
  •   List(列表):元素有序,元素可以重復 (有索引)。 通過元素的equals()方法判斷是否重復。
  •   Set(集):元素無序,不可重復 (沒有索引)。 遍歷只能用Iterator叠代器和增強for, 不能使用普通for遍歷。
  •   ArrayList(數組列表): 查詢快,增刪慢。
  •   LinkedList(鏈表): 查詢慢,增刪快。
  •   HashSet(哈希表): 查詢快,增刪慢。 (底層其實就是Map) 。 存放的引用類型需重寫hashCode()和equals()方法。
  •   LinkedHashSet(哈希鏈表): 查詢慢,增刪快。 有序的,存放順序和取出順序一致。

1.1,為什麽要去重:

  •   在我們開發中,我們所讀取的數據難免會有重復數據,我們需要的則是不重復數據的引用,所以需要對數據進行去重,
  •   而基本數據類型的去重比較好去重而引用數據類型呢,因為要判斷hashCode運算是否相等,還有equals()是否相等,所以需要去重操作,
  •   我們以一個list集合為例,在該例中,我們將User實體類中姓名和電話號碼作為判斷該對象重復的標識,在User的實體類中我們重寫
  •   這兩個方法如下:
 1 package com.example.pojo;
2 3 public class User { 4 private String name; 5 private String region; 6 private Integer performance; 7 public User(String name, String region, Integer performance) { 8 super(); 9 this.name = name; 10 this.region = region; 11 this.performance = performance;
12 } 13 @Override 14 public String toString() { 15 return "User [name=" + name + ", region=" + region + ", performance=" + performance + "]"; 16 } 17 @Override 18 public int hashCode() { 19 final int prime = 31; 20 int result = 1; 21 result = prime * result + ((name == null) ? 0 : name.hashCode()); 22 result = prime * result + ((performance == null) ? 0 : performance.hashCode()); 23 result = prime * result + ((region == null) ? 0 : region.hashCode()); 24 return result; 25 } 26 @Override 27 public boolean equals(Object obj) { 28 if (this == obj) 29 return true; 30 if (obj == null) 31 return false; 32 if (getClass() != obj.getClass()) 33 return false; 34 User other = (User) obj; 35 if (name == null) { 36 if (other.name != null) 37 return false; 38 } else if (!name.equals(other.name)) 39 return false; 40 if (performance == null) { 41 if (other.performance != null) 42 return false; 43 } else if (!performance.equals(other.performance)) 44 return false; 45 if (region == null) { 46 if (other.region != null) 47 return false; 48 } else if (!region.equals(other.region)) 49 return false; 50 return true; 51 } 52 }
  • 以上實體類中,我們在equals()方法中取出該對象的name與region和performance這三個屬性值去判斷比較,然後在重寫的hashCode()
  • 方法中返回這三個屬性值得equals對象地址值。

1.2,去重操作步驟:

 1 package com.example.arraylist;
 2 
 3 import java.util.ArrayList;
 4 import java.util.Iterator;
 5 import java.util.List;
 6 import com.example.pojo.User;
 7 
 8 /**
 9  * @author Administrator
10  *    思路:
11  *        1.先對其文本文本進行添加,添加到List<User>中
12  *        2.把List<User>用叠代器進行叠代
13  *        3.創建一個新的集合,用來存儲不重復的元素
14  *        4.用while(it.hasNext())有多少元素就循環多少次    
15  *        4.判斷新的集合是否有舊的元素如果沒有則進行添加
16  */
17 public class ListUserRepeat {
18     public static void main(String[] args) {
19         String string="張三,河北,90\n"+
20                 "張三,河南,92\n"+
21                 "李四,湖北,80\n"+
22                 "王五,山西,88\n"+
23                 "張三,河北,90\n"+
24                 "李四,湖北,80\n"+
25                 "馬六,山東,77\n";
26         List<User> list = new ArrayList<>();
27         String[] split = string.split("\n");
28         for(String spl : split) {
29             String[] split2 = spl.split(",");
30             list.add(new User(split2[0], split2[1],Integer.parseInt(split2[2])));
31         }
32         Iterator<User> it = list.iterator();
33         List<User> listOne = new ArrayList<>();
34         while(it.hasNext()) {
35             Object object = it.next();
36             if(!listOne.contains(object)) {
37                 listOne.add((User) object);
38             }
39         }
40         for (User user : listOne) {
41             System.out.println(user);
42         }
43     }
44 }

運行這段代碼之後,就會很明顯的發現,list中重復的用戶名,地區,都相同的對象就被會認為是重復的元素而刪除掉,很明顯運行結果已經達到我們的目的。

二,說一下為什麽需要重寫equals()方法和hashChode方法():

  • 一般情況下我們重寫equals()方法的時候還要重寫hashChode()方法,但是我們用的是list所以不用重寫hashCode,大家不妨
  • 可以試試上面的例子,在實體類將重寫的equals()方法註釋掉,再運行程序,這時就會發現運行結果並不是我們剛剛得到的結果,(圖中 我用的是list集合,
  • 不是set集合,list集合只需要重寫equals()方法就行,而set集合則equals()和hashCode()方法都需要重寫

2.1, String類中的equals()方法的源碼如下:

 1     public boolean equals(Object anObject) {
 2         if (this == anObject) {
 3             return true;
 4         }
 5         if (anObject instanceof String) {
 6             String anotherString = (String)anObject;
 7             int n = value.length;
 8             if (n == anotherString.value.length) {
 9                 char v1[] = value;
10                 char v2[] = anotherString.value;
11                 int i = 0;
12                 while (n-- != 0) {
13                     if (v1[i] != v2[i])
14                         return false;
15                     i++;
16                 }
17                 return true;
18             }
19         }
20         return false;
21     }

通過觀察equals()方法的源碼我們可以看出,該方法去比較兩個對象時,首先先去判斷兩個對象是否具有相同的地址,如果是同一個對象的引用,則直接放回true;如果地址不一樣,則證明不是引用同一個對象,接下來就是挨個去比較兩個字符串對象的內容是否一致,完全相等返回true,否則false。

2.2,String類中hashCode()方法的源碼如下:

 1     public int hashCode() {
 2         int h = hash;
 3         if (h == 0 && value.length > 0) {
 4             char val[] = value;
 5 
 6             for (int i = 0; i < value.length; i++) {
 7                 h = 31 * h + val[i];
 8             }
 9             hash = h;
10         }
11         return h;
12     }

以上是String類中重寫的hashCode()方法,在Object類中的hashCode()方法是返回對象的32位JVM內存地址,也就是說如果我們不去重寫該方法,將會返回該對象的32位JVM內存地址,以上我們測試的例子中,當註釋掉重寫的hashCode()方法時,這時默認返回對象的32JVM中的地址,兩個不同的對象地址顯然是不同的,我們在比較時,雖然通過重寫的equals()方法比較出來name和phoneNumber值是相同的,但是默認的hashCode()方法返回的值他們並不是同一個對象,所以我們通常要將hashCode()方法與equals()方法一起重寫,以維護hashCode方法的常規協定,該協定聲明相等對象必須具有相等的哈希碼。

總結:

  用白話說,通過hashCode判斷對象是否放在同一個桶裏,然後再通過equals方法去判斷這個桶裏的對象是不是相同的。

List去重為什麽要寫equals(),hashCode()方法