国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計 > 正文

HashSet其實就那么一回事兒之源碼淺析

2019-11-14 21:21:12
字體:
供稿:網(wǎng)友
HashSet其實就那么一回事兒之源碼淺析

上篇文章《HashMap其實就那么一回事兒之源碼淺析》介紹了hashMap, 本次將帶大家看看HashSet, HashSet其實就是基于HashMap實現(xiàn), 因此,熟悉了HashMap, 再來看HashSet的源碼,會覺得極其簡單。下面還是直接看源碼吧:

public class HashSet<E>    extends AbstractSet<E>    implements Set<E>, Cloneable, java.io.Serializable{    static final long serialVersionUID = -5024744406713321676L;    //HashMap ? 沒錯,HashSet就是通過HashMap保存數(shù)據(jù), HashSet的值就是HashMap的key    PRivate transient HashMap<E,Object> map;        //HashMap 為<key, value>的鍵值對, 既然HashSet的值就是HashMap的key, 那么HashMap的值呢,當(dāng)然就是這個PRESENT啦    private static final Object PRESENT = new Object();        //下面這一系列的構(gòu)造方法都是創(chuàng)建HashMap, 之前已經(jīng)介紹過HashMap, 這兒就不再詳說了    public HashSet() {        map = new HashMap<>();    }    //將一個已知的collection轉(zhuǎn)換為HashSet    public HashSet(Collection<? extends E> c) {        //這兒的HashMap的參數(shù)為什么這么寫?        //上次介紹HashMap的時候可知,如果沒有指定HashMap的capacity, 那么默認(rèn)的就是16        //根據(jù) threshold = capacity * loadFactor, 可以計算出 capacity        //Math.max((int) (c.size()/.75f) + 1, 16) 這個意思就是capacity如果沒超過16, 那么就直接使用默認(rèn)的16        map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));        //將已知的collection轉(zhuǎn)換為HashSet的方法        //addAll方法是HashSet的父類AbstractCollection的方法,為了便于閱讀,會將代碼粘貼在下面        addAll(c);    }    public HashSet(int initialCapacity, float loadFactor) {        map = new HashMap<>(initialCapacity, loadFactor);    }    public HashSet(int initialCapacity) {        map = new HashMap<>(initialCapacity);    }    HashSet(int initialCapacity, float loadFactor, boolean dummy) {        map = new LinkedHashMap<>(initialCapacity, loadFactor);    }        //addAll方法是HashSet的父類AbstractCollection的方法    public boolean addAll(Collection<? extends E> c) {        boolean modified = false;        for (E e : c)            //此處的add方法由HashSet重寫實現(xiàn)            if (add(e))                modified = true;        return modified;    }        //HashSet的核心方法來了, 沒錯,就這么簡單    public boolean add(E e) {        //應(yīng)證了上面所說的key為HashSet的值        return map.put(e, PRESENT)==null;    }        //剩下這些方法都是跟Map相關(guān)的了,只要熟悉了HashMap, 那就太簡單了,就不說了    public boolean remove(Object o) {        return map.remove(o)==PRESENT;    }    public void clear() {        map.clear();    }    }

就這樣,HashSet的源碼如此簡單。下面還是對HashSet的源碼作一個總結(jié)吧:

1. HashSet基于HashMap實現(xiàn), 以HashSet的值作為HashMap的一個key, 以一個Object對象常量作為HashMap的值。

2. 根據(jù)HashMap的特性,可以推敲出:HashSet允許擁有1個為null的值, HashSet的值不可重復(fù)。

3. 在創(chuàng)建HashSet的時候,如果合適,最好指定其內(nèi)部HashMap的 capacity和loadFactory的值, 至于原因,在介紹HashMap的時候,提到過。

OK, 講完HashSet之后,我覺得是時候提一下這個問題了: 可能在大家初學(xué)java的時候,老師或者書上都推薦大家在重寫對象equals的時候,最好重寫一下hashCode方法,還記得吧? 為什么要這么做? 給大家演示一下,你就能明白了,下面看一個小demo:

先定義一個Person類:

public class Person {    //身份證    private String idCard;        private String name;        public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }        public String getIdCard() {        return idCard;    }    public void setIdCard(String idCard) {        this.idCard = idCard;    }    //重寫equals方法(規(guī)則是:idCard一致,則認(rèn)為是同一個人)    @Override    public boolean equals(Object obj) {        if(obj == this) {            return true;        }        if(!(obj instanceof Person)) {            return false;        }        Person others = (Person) obj;        if(others.getIdCard().equals(idCard)) {            return true;        }        return false;    }}

然后,寫一個測試類,用HashSet去添加Person實例:

public class Test {    public static void main(String[] args) {                Person p1 = new Person();        p1.setIdCard("1234567890");                Person p2 = new Person();        p2.setIdCard("1234567890");                Set<Person> hashSet = new HashSet<Person>();        hashSet.add(p1);        hashSet.add(p2);                System.out.println(hashSet.size());            }    }

我們知道HashSet的元素不可重復(fù),因此,在以上測試代碼中,p1 與 p2對象是equals的,我們本來希望HashSet只保存其中一個對象, 但是,事與愿違,輸出的結(jié)果卻是2, 說明hashSet把這兩個對象都保存了。這是為什么呢? 我們結(jié)合一下HashMap來看吧, 首先,由于我們沒有重寫Person的hashCode方法,會導(dǎo)致p1 與 p2的hash值不一致,這時, HashMap會把hash不一致的元素放在不同的位置, 因此就產(chǎn)生了兩個對象。那么,怎么改善? 當(dāng)然是重寫hashCode方法了。下面,我們在Person類中,重寫hashCode方法:

@Override    public int hashCode() {        return this.idCard.hashCode() * 11;    }

這時候,我們再用上面的測試類測試,發(fā)現(xiàn)輸出為1。OK,終于和我們的想法一致了。這就是為什么強(qiáng)烈推薦在重寫equals方法的時候,同時重寫hashCode方法的原因之一。

好了,本次就寫到此。謝謝大家!


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 泰兴市| 青龙| 许昌市| 林口县| 连云港市| 阜平县| 新野县| 宜章县| 同江市| 宣威市| 枞阳县| 杭州市| 屏南县| 宽甸| 苏尼特右旗| 通道| 廉江市| 丰县| 河池市| 扶余县| 阳西县| 丰台区| 永州市| 华坪县| 四子王旗| 明溪县| 清新县| 即墨市| 武义县| 政和县| 大丰市| 涞源县| 和政县| 崇文区| 扶沟县| 阜康市| 永清县| 潍坊市| 永嘉县| 故城县| 搜索|