一 :string類型的==和equals的區別:
結論:"=="是判斷兩個字符串的內存地址是否相等,equals是比較兩個字符串的值是否相等,具體就不做擴展了,有興趣的同學可以去查看相關的博客。
String s1 = new String("java");
String s2 = new String("java");
System.out.println(s1==s2); //false
System.out.println(s1.equals(s2)); //true
在Java中,equals和hashCode方法是Object中提供的兩個方法,string類型重寫了equals()方法和hashCod()方法,源碼如下:
public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String)anObject; int n = count; if (n == anotherString.count) { char v1[] = value; char v2[] = anotherString.value; int i = offset; int j = anotherString.offset; while (n-- != 0) { if (v1[i++] != v2[j++]) return false; } return true; } } return false; } /*返回哈希碼,String的哈希碼計算方式為s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]*/ public int hashCode() { int h = hash; if (h == 0) { int off = offset; char val[] = value; int len = count; for (int i = 0; i < len; i++) { h = 31*h + val[off++]; } hash = h; } return h; }
二:對象equals 和hashcode的關系
結論:當對象的equals()方法被重寫時,通常有必要重寫 hashCode() 方法,以維護 hashCode 方法的常規協定,該協定聲明相等對象必須具有相等的哈希碼。如下:
(1)兩個對象相等,hashcode一定相等
(2)兩個對象不等,hashcode不一定不等
(3)hashcode相等,兩個對象不一定相等
(4)hashcode不等,兩個對象一定不等
hashcode是用於散列數據的快速存取,如利用HashSet/HashMap/Hashtable類來存儲數據時,都是根據存儲對象的hashcode值來進行判斷是否相同的。這樣如果我們對一個對象重寫了euqals,意思是只要對象的成員變量值都相等那么euqals就等於true,但 不重寫hashcode,那么我們再new一個新的對象,當原對象.equals(新對象)等於true時,兩者的hashcode卻是不一樣的,由此將產生了理解的不一致。
三 :使用HashMap,如果key是自定義的類,就必須重寫hashcode()和equals()
A.當put元素時:
1.首先根據put元素的key獲取hashcode,然后根據hashcode算出數組的下標位置,如果下標位置沒有元素,直接放入元素即可。
2.如果該下標位置有元素(即根據put元素的key算出的hashcode一樣即重復了),則需要已有元素和put元素的key對象比較equals方法,如果equals不一樣,則說明可以放入進map中。這里由於hashcode一樣,所以得出的數組下標位置相同。所以會在該 數組位置創建一個鏈表,后put進入的元素到放鏈表頭,原來的元素向后移動。
B.當get元素時:
根據元素的key獲取hashcode,然后根據hashcode獲取數組下標位置,如果只有一個元素則直接取出。如果該位置一個鏈表,則需要調用equals方法遍歷鏈表中的所有元素與當前的元素比較,得到真正想要的對象。
C. 采用hashcode的好處:
如果我們不使用hashcode,直接使用equals比較,那么我們有10w個元素,put值或者get值時要比較10w次,如果先通過hashcode判斷后,我們的效率就會提高很多。
我們可以對比實際生活中,如果有一棟教學樓,一樓是1年級,二樓是2年級,以此類推,六樓是6年級,這時我們需要找5年級2班在哪間教室,通過hashcode直接定位到5樓,然后在5樓一間間找就行了,這樣避免從一樓一間一間查看。
四.:代碼展示,為什么重寫equals時必須重寫hashCode方法
我們以一個student 學生類來測試重寫equals()和重寫hashcode()后,map的get()方法返回值結果,讓大家清晰了解為什么重寫equals時必須重寫hashCode方法
package com.sinaif; public class Student { private String name; //姓名 private String sex; //性別 private String idCard;//身份證號 Student(String name,String sex,String idCard){ this.name = name; this.sex = sex; this.idCard = idCard; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getIdCard() { return idCard; } public void setIdCard(String idCard) { this.idCard = idCard; } @Override public boolean equals(Object obj) { // TODO Auto-generated method stub if(obj == null){ return false; } Student obj1 = (Student)obj; if(this.name.equals(obj1.getName()) && this.idCard.equals(obj1.getIdCard())){ return true; } return false; } //@Override public int hashCode() { // TODO Auto-generated method stub String s= this.name + this.idCard; return s.hashCode(); } }
public static void main(String[] args) throws Exception { Map<Student,Student> map = new HashMap<Student,Student>(); Student s1 = new Student("haly","male","110200"); Student s2 = new Student("haly","female","110200"); map.put(s1, s1); System.out.println(map.get(s2)); // 當沒有重寫equals方法和hashcode方法,打印出null // 當重寫equals方法,不重寫hashcode方法時,打印出null // 當重寫equals方法,並且重寫hashcode方法時,打印出com.test.Student@95fb7d6 }