1. 程式人生 > >HashMap什麼時候重寫hashcode和equals方法,為什麼需要重寫

HashMap什麼時候重寫hashcode和equals方法,為什麼需要重寫

HashSet  set = new HashSet
set.put(new Student(1,"aa") );
set.put(new Student(1,"aa") );
set.put(new Student(2,"aa") );
結果set內的元素為3個,沒有去處重複的new Student(1,"aa") ?為什麼呢?
這裡由於兩個new Student(1,"aa")是不一樣的Student物件。而預設的Student類的hashcode是根據物件的引用算的。所以直接認為是兩個不一樣的物件,直接put進去了。所以需要重寫hashcode方法,如果hashcode不一樣則直接認為是不同物件,如下:
class Student {
        private int code;
        private Stirng name;
        public int hashcode() {
            return code*name.hashcode();
        }
    }

發現還是不對,還是put進去了呢?
這裡重寫的hashcode是一樣的,所以還是put進去了。所以還需要重新equals方法。其實是有這樣一個規定,如果hahscode一樣時,則還需要繼續呼叫equals方式看看物件是否相等。如下即可實現:
public boolean equals(Object o) {
     Student s = (Student ) o;
     if (name.equals(s.getName) && code == o.getCode()) {
          return true;
     }
     return false;
}

可以看到如果hashcode不一樣就直接認為是不一樣的物件,不需要再去equal比較,更加節省時間。
如果new Student(1,"aa")、new Student(1,"bb")。通過code和name算出的hashcode就可以算是不一樣的物件,就不需要再去equals比較。
往往HashSet中存放的物件是否相等的邏輯都需要自己定義,而並不會直接用預設的引用來算,即一般都會重新hashcode和equals方法,而且同時需要重寫。以後要注意哦。

HashMap的put和get也類似。
HashMap是底層實現時陣列加連結串列。
       A.當put元素時:
              1.首先根據put元素的key獲取hashcode,然後根據hashcode算出陣列的下標位置,如果下標位置沒有元素,直接放入元素即可。
              2.如果該下標位置有元素(即根據put元素的key算出的hashcode一樣即重複了),則需要已有元素和put元素的key物件比較equals方法,如果equals不一樣,則說明可以放入進map中。這裡由於hashcode一樣,所以得出的陣列下標位置相同。所以會在該陣列位置建立一個連結串列,後put進入的元素到放連結串列頭,原來的元素向後移動。       
        B.當get元素時:

             根據元素的key獲取hashcode,然後根據hashcode獲取陣列下標位置,如果只有一個元素則直接取出。如果該位置一個連結串列,則需要呼叫equals方法遍歷連結串列中的所有元素與當前的元素比較,得到真正想要的物件。
可以看出如果根據hashcdoe算出的陣列位置儘量的均勻分佈,則可以避免遍歷連結串列的情況,以提高效能。
所以要求重寫hashmap時,也要重寫equals方法。以保證他們是相同的比較邏輯