1. 程式人生 > >HashSet存儲過程中如何排除不同的自定義對象?

HashSet存儲過程中如何排除不同的自定義對象?

code 意思 ner rgs ctrl ava out als ret

HashSet

HashSet存儲過程中如何排除不同的自定義對象?

先看一個小demo

public class Demo1 {
    public static void main(String[] args) {
        //Person4類是一個失血模型,它有姓名和年齡兩個屬性
        HashSet<Person4> set = new HashSet<>();
        set.add(new Person4("張三", 23));
        set.add(new Person4("張三", 23));
        set.add(new Person4("李四", 24));
        set.add(new Person4("李四", 24));
        set.add(new Person4("李四", 24));
        
        /*
         * 直接打印,我們會發現,它把5個元素加入進去了,包括我們認為“重復”的元素
         * 可是,HashSet不是號稱不可重復嗎?這是為什麽?
         */
        System.out.println(set);
    }
}

HashSet在存儲自定義的對象比如Person4(含name和age屬性)時,如果存放name和age值相同的對象時,它都會存放進去。因為我們把它當作是相同的元素是根據它的屬性值判斷,而程序會為每個new出來的對象計算出不同的hashcode碼,所以它認為是不同的對象,都會存放進去。

如何讓它有效排除我們認為的“所有屬性值相同的對象就是同一個對象”在這種定義下的同一種對象呢?

首先我們要去了解它的底層實現,即:
它判斷是否相同的時候,肯定用了equals方法,他在計算hashcode的時候,應該用到了hashCode方法,那麽它的執行流程和內部是怎麽實現的呢?

我們追溯HashSet的源碼,首先我們用到了add方法,它在add的時候肯定會進行是否存在相同對象的判斷。我按住ctrl+鼠標左鍵點進去,一層一層追溯,結果懵逼了,發現裏面涉及了很多以我目前實力看不懂的代碼,怎麽辦?

先不管三七二十一,因為根據之前看源碼的經驗,我發現如果一個方法的底層如果用了equals方法,那麽它調用的是obj的equals方法。什麽意思呢?就是說它其實調用的是被操作對象的方法,我們每一個Person4對象的equals方法,這樣實現的目的應該是為了我們使用者可以方便地重寫equals方法底層實現從而實現我們自己的個性化使用。
我直接在person4裏重寫了equals方法如下:

@Override
    public boolean equals(Object obj) {
        //先把obj強制轉換成person4對象
        Person4 p = (Person4) obj;
        //改成根據各屬性的值判斷是否同一個對象
        return p.name.equals(this.name) && p.age == p.age;
    }

再運行了下程序,發現並不起作用,重復元素還是存在。

我再一咬牙,再把hashCode方法一並改寫了:

@Override
    public int hashCode() {
        return 10;
    }

我讓hashCode方法都返回10,發現重復元素都沒了。

到了這裏,不禁困惑,為什麽這樣就可以了呢?

後來,經過查閱資料,觀看視頻得知,hashSet底層的add方法大概流程是這樣的:先比較hashcode碼,不相同則插入成功,如果相同,則用equals比較。

再反觀我們上面的程序,因為我讓它hashcode都變成了10,所以他們最終都是通過equals比較的,equals被我重寫,它就能夠去掉重復的元素。

但是,實際開發中這樣效率是不高的,我們應該讓它盡可能少調用方法,達到效率的提升,特別是操作的元素數量特別多的時候。

所以,我們就應該讓它在第一關:hashcode碼判斷的時候,就應該讓不同的元素盡量返回不同的hashcode碼,一次判斷就結束。

如果你使用的是eclipse,那麽可以利用它自帶的便捷功能:自動重寫equals和hashcode方法,並且實現了我們上面提的要求(它為我們考慮好了算法)。按住shift+alt+s,點擊generate hashCode( ) and equals( ),他會自動重寫我們的兩個方法。你想學習它的算法怎麽實現的,可以看它生成的代碼。

HashSet存儲過程中如何排除不同的自定義對象?