<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    zhyiwww
    用平實的筆,記錄編程路上的點點滴滴………
    posts - 536,comments - 394,trackbacks - 0

    Set 中的元素為什么不允許重復(fù)

    ?????? 版權(quán)所有,轉(zhuǎn)載請聲明出處 zhyiwww@163.com

    ?

    為了弄清楚這個問題 , 我又看了一遍 Collection 部分 , 并且看了些其中的源碼 , 覺得對其中的實現(xiàn)又明白了一點 , 現(xiàn)在說出來和大家共享 .

    我們先看一下 Set 類的關(guān)系圖:

    hashset.png
    現(xiàn)在我們就從
    Set 說起。

    Set 接口為我們提供了一個 add() 方法,以讓我們添加元素。所以我們看一下在其實現(xiàn)類 HashSet 中是如何實現(xiàn)的呢?

    我們看 HashSet 中的 add() 方法實現(xiàn);

    ??? public boolean add( E o ) {

    ?????? ?????? return? map.put(o, PRESENT)==null;

    }

    你可能回問怎么回出來 map 了呢?

    Map 又是一個什么變量呢?

    我們來看 map 是在在哪定義的。原來,在 HashSet 中定義了這樣的兩個變量:

    ??? private transient HashMap<E,Object> map;

    ??? private static final Object PRESENT = new Object();

    我們再看一下上面的 add() 方法。

    map.put(o, PRESENT)==null

    實際執(zhí)行的是 map 的方法,并且我們添加的對象是 map 中的 key,value 是執(zhí)行的同一個對象 PRESENT.

    因為map中的key是不允許重復(fù)的,所以set中的元素不能重復(fù)。

    ?

    下面我們再看一下, map 又是如何保證其 key 不重復(fù)的呢?

    ?hashmap.png

    現(xiàn)在我們看一下 map 中的 put() 方法的實現(xiàn):

    HashMap 實現(xiàn)了 map ,在 HashMap 中是這樣實現(xiàn)的:

    ??? public V put(K key, V value) {

    ????? K k = maskNull(key);

    ??????? int hash = hash(k);

    ??????? int i = indexFor(hash, table.length);

    ??????? for (Entry<K,V> e = table[i]; e != null; e = e.next) {

    ??????????? if (e.hash == hash && eq(k, e.key)) {

    ??????????????? V oldValue = e.value;

    ??????????????? e.value = value;

    ??????????????? e.recordAccess(this);

    ??????????????? return oldValue;

    ??????????? }

    ??????? }

    ?

    ??????? modCount++;

    ??????? addEntry(hash, k, value, i);

    ??????? return null;

    ??? }

    我們我們按照方法的執(zhí)行一步一步的來看一下,其實現(xiàn)的過程。

    K k = maskNull(key);

    這一步是要判斷當(dāng)前的要添加的對象的 key 是否為空,如果為空的話,那么就生成一個新的對象作為其 key 。實現(xiàn)如下:

    ??? static final Object NULL_KEY = new Object();

    ???? * Returns internal representation for key. Use NULL_KEY if key is null.

    ??? static <T> T maskNull(T key) {

    ??????? return key == null ? (T)NULL_KEY : key;

    ??? }

    之后

    int hash = hash(k);

    我們看一下 hash() 方法的實現(xiàn):

    ??? static int hash(Object x) {

    ??????? int h = x.hashCode();

    ??????? h += ~(h << 9);

    ??????? h ^=? (h >>> 14);

    ??????? h +=? (h << 4);

    ??????? h ^=? (h >>> 10);

    ??????? return h;

    ??? }

    這一步其實是要得到當(dāng)前要添加對象的 hashcode, 方法中,首先通過 int h = x.hashCode() 取得了當(dāng)前的要添加對象的 hashcode, 然后

    ??????? h += ~(h << 9);

    ??????? h ^=? (h >>> 14);

    ??????? h +=? (h << 4);

    ??????? h ^=? (h >>> 10);

    生成一個新的 hashcode.

    接著執(zhí)行的是

    (從此處開始,我理解的比較膚淺,請看到此出的朋友多多指點)

    int i = indexFor(hash, table.length);

    這個方法是要 Returns index for hash code h.

    ??? static int indexFor(int h, int length) {

    ??????? return h & (length-1);

    ??? }

    ????? 下面就要根據(jù) hashmap 中的元素逐個的比較,看是否相同,如果不同就回添加一個新的元素。是通過循環(huán)判斷來實現(xiàn)的。

    ??????? for (Entry<K,V> e = table[i]; e != null; e = e.next) {

    ??????????? if (e.hash == hash && eq(k, e.key)) {

    ??????????????? V oldValue = e.value;

    ??????????????? e.value = value;

    ??????????????? e.recordAccess(this);

    這句我的理解是:在內(nèi)存中的可以訪問元素又多了一個。也就是說,添加之后,可以通過hashmap來訪問此元素了。

    ???????? ???????return oldValue;

    ??????????? }

    ??????? }

    通過循環(huán)判斷是否有完全相同的對象,包括 hashcode value 值。如果已經(jīng)存在就返回其值,如果不存在就執(zhí)行一下操作。

    ??????? modCount++;

    ??????? addEntry(hash, k, value, i);

    ??????? return null;

    對象不存在,首先修改 hashmap 的修改次數(shù),即 modCount 1. 然后將對象添加到數(shù)組中。

    ??? void addEntry(int hash, K key, V value, int bucketIndex) {

    ????? Entry<K,V> e = table[bucketIndex];

    ??????? table[bucketIndex] = new Entry<K,V>(hash, key, value, e);

    ??????? if (size++ >= threshold)

    ??????????? resize(2 * table.length);

    }

    仍然是數(shù)組,我們來看一下 , hashmap 中用來存放對象的數(shù)組的定義:

    ?? ?transient Entry[] table;

    至此,我想大家也許應(yīng)該明白了,為什么在 set 中是不允許存放重復(fù)值的。

    通過才的分析,我們可以看到, map 的一些特征:

    1.?????? map 中也是不能存放完全相同的元素的

    2.?????? 如果你存入的對象的 key 值已經(jīng)存在的話,那么新的 value 將會取代老的 value 值,但是并不會添加新的元素進去。

    我們可以通過一個測試程序來證明這一點:

    ? public void mapTest() {

    ??? Map m = new HashMap();

    ??? /**

    ???? * we? can? put? the? int? 1 and the? value? 1? into? the? map

    ???? * but? we? cannot? get? the? 1 as? int? from the map

    ???? * why ?

    ???? * we? only? get? the? 1? as? integer? from? the map,

    ???? * so? we? only? get the object? from the map,if we? put the? value? into

    ???? * the map,we? will get one? instance of? the wrapper? of? that

    ???? */

    ??? m.put(1, 1);

    ??? //int i = m.get(1);

    ??? Integer i = (Integer) m.get(1);

    ??? System.out.println(i);

    ?

    ??? m.put(1, 1);

    ??? m.put(1, 1);

    ??? System.out.println("map?? :??? " + m);

    ??? System.out.println("map? size??? :?? " + m.size());

    ??? m.put(1, 2);

    ??? System.out.println("map?? :??? " + m);

    ??? System.out.println("map? size??? :?? " + m.size());

    ? }

    運行的結(jié)果是:

    map?? :??? {1=1}

    map? size??? :?? 1

    map?? :??? {1=2}

    map? size?? ?:?? 1

    希望此文能大家有所幫助。



    |----------------------------------------------------------------------------------------|
                               版權(quán)聲明  版權(quán)所有 @zhyiwww
                引用請注明來源 http://m.tkk7.com/zhyiwww   
    |----------------------------------------------------------------------------------------|
    posted on 2006-03-30 09:41 zhyiwww 閱讀(3660) 評論(0)  編輯  收藏 所屬分類: java basic
    主站蜘蛛池模板: 亚洲人成电影在线观看青青| 亚洲人成伊人成综合网久久久| 亚洲国产精品无码一线岛国| 一级毛片不卡免费看老司机| 免费精品国产自产拍观看| 亚洲第一街区偷拍街拍| 日韩免费观看视频| 亚洲精品理论电影在线观看| 啦啦啦高清视频在线观看免费| 亚洲中文字幕无码一去台湾| 成人免费一区二区三区在线观看| 久久精品国产亚洲AV忘忧草18| 国产精品久久久久免费a∨| 2020年亚洲天天爽天天噜| 夜夜嘿视频免费看| 亚洲精华液一二三产区| 国产成人免费网站在线观看| 免费人成动漫在线播放r18| 亚洲国产精品成人| 青柠影视在线观看免费| 久久亚洲私人国产精品vA | 亚洲XX00视频| 51午夜精品免费视频| 亚洲av日韩av无码| 97在线线免费观看视频在线观看 | 亚洲Av无码国产一区二区| 啊灬啊灬别停啊灬用力啊免费看| 一级毛片正片免费视频手机看| 区久久AAA片69亚洲| 一级毛片免费不卡在线| 国产成人精品日本亚洲18图| 国产伦精品一区二区三区免费迷| 男女交性无遮挡免费视频| 久久久久亚洲AV无码专区首| 日韩一区二区a片免费观看| 特级aaaaaaaaa毛片免费视频| 亚洲中久无码永久在线观看同 | 91情侣在线精品国产免费| 无遮挡国产高潮视频免费观看 | 亚洲免费在线视频观看| 国产免费人成视频在线观看|