講解:為什么重寫equals時必須重寫hashCode方法


一 :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
		
	} 

  

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM