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

HashSet內部是通過HashMap實現。只有使用排序的時候才使用TreeMap。否知使用HashMap。

使用HashSet 舉例子:  情景描述  往HashSet集合中put Student對象實例,要求: code name相同的不重複 放入

HashSet  set = new HashSet

set.add(new Student("1", "aa"));

set.add(new Student("2", "aa"));

set.add(new Student("1", "aa"));

System.out.println("set:===" + set);


結果set集合內的元素爲3個,沒有去處重複的new Student("1","aa") ?爲什麼呢?
這裏由於兩個new Student("1","aa")是不一樣的Student對象實例(都是new 出來的,對象引用不一樣)。而默認的Student類的hashcode是根據對象的引用算的。所以直接認爲是兩個不一樣的對象,直接add進去了。所以需要重寫hashcode方法如果hashcode不一樣則直接認爲是不同對象,如下:

@Data
class Student {
    String code;
    String name;
   
    @Override
    public int hashCode() {
        return code.hashCode() + name.hashCode();
    }
    public Student(String code, String name) {
        this.code = code;
        this.name = name;
    }
}

結果發現還是不對,還是add進去了3個Student  呢?
這裏重寫的hashcode是一樣的,所以還是add進去了。所以還需要重新equals方法。

其實是有這樣一個規定,如果hashcode一樣時,則還需要繼續調用equals方式看看對象是否相等。所以再需要重寫 equals方法如下即可實現:

  @Override
    public boolean equals(Object o) {
        Student s = (Student) o;
        if (name.equals(s.getName()) && code.equals(s.getCode())) {
            return true;
        }
        return false;
    }

完整test demo:

public class MyClass {
    public static void main(String[] args) {
        HashSet set = new HashSet<>();
        set.add(new Student("1", "aa"));
        set.add(new Student("2", "aa"));
        set.add(new Student("1", "aa"));
        System.out.println("set:===" + set);

    }
}

@Data
class Student {
    String code;
    String name;

    @Override
    public int hashCode() {
        return code.hashCode() + name.hashCode();
    }
    public Student(String code, String name) {
        this.code = code;
        this.name = name;
    }
}

可以看到如果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方法。以保證他們是相同的比較邏輯

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章