HashMap源碼解析

public class HashMap<K,V>
    extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable
{

    //默認初始化大小,若是沒有給初始化值的話,大小就是16(2的n次冪),後面的擴容也是2的N次冪
    static final int DEFAULT_INITIAL_CAPACITY = 16;

    //最大容量,2的30次方
    static final int MAXIMUM_CAPACITY = 1 << 30;

    //系統默認的負載因子(沒懂其意義)
    static final float DEFAULT_LOAD_FACTOR = 0.75f;

    //存放數據的實體(重要)
    transient Entry[] table;

    //實際存放數據的量
    transient int size;

   //閾值(沒懂),大小爲Entry的長度*loadFactor
    int threshold;

   //哈希表的負載因子(沒懂)
    final float loadFactor;

   //修改次數
    transient volatile int modCount;

   //構建函數(初始化容量和hash表的負載)
    public HashMap(int initialCapacity, float loadFactor) {
        if (initialCapacity < 0)//小於零拋異常
            throw new IllegalArgumentException("Illegal initial capacity: " +
                                               initialCapacity);
         //保證Entry[]的大小不會超過最大值
        if (initialCapacity > MAXIMUM_CAPACITY)
            initialCapacity = MAXIMUM_CAPACITY;
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal load factor: " +
                                               loadFactor);

        // 初始化各個值,除非initialCapacity恰好是2的N次冪,不然初始化Entry[]的容量確定比傳入的initialCapa        //city值要大,而且應該是比initialCapacity大的第一個2的N次冪
        int capacity = 1;
        while (capacity < initialCapacity)
            capacity <<= 1;

        this.loadFactor = loadFactor;
        threshold = (int)(capacity * loadFactor);
        table = new Entry[capacity];
        init();
    }

    //構造函數
    public HashMap(int initialCapacity) {
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }

    //構造函數
    public HashMap() {
        this.loadFactor = DEFAULT_LOAD_FACTOR;
        threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
        table = new Entry[DEFAULT_INITIAL_CAPACITY];
        init();
    }

   //構造函數
    public HashMap(Map<? extends K, ? extends V> m) {
    //初始化新map的大小等參數
        this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,
                      DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR);
        //copy數據,把m中的數據複製到新的集合裏面,putAllForCreate的細節在方法內解析
        putAllForCreate(m);
    }


  
    void init() {
    }

   //一個自定義的hash算法
    static int hash(int h) {
        h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);
    }

   //自定義的算法,返回的結果就是在Entry[]數組中的位置
    static int indexFor(int h, int length) {
        return h & (length-1);
    }

   //返回具體數據的數量
    public int size() {
        return size;
    }

    //判斷是否爲空
    public boolean isEmpty() {
        return size == 0;
    }

   //獲取數據
    public V get(Object key) {
    //key==null的話就找尋是否有key爲空值對應的value
        if (key == null)
            return getForNullKey();
        int hash = hash(key.hashCode());
        //這個for循環挺有意思,因爲hashmap是數組+鏈表,因此此循環其實是找到在Entry[]上的位置,而後循環這個        //位置上的鏈表,很像XY軸,定位到X軸後再循環在X軸上Y軸的數據
        for (Entry<K,V> e = table[indexFor(hash, table.length)];
             e != null;
             e = e.next) {
            Object k;
            //e內存儲的hash要和傳入的key的hash值相同(e內存儲的hash就是e中key的hash值),而且e中的key要和             //傳入的key相等,此時返回e的value
            if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
                return e.value;
        }
        //不然爲空
        return null;
    }

   //返回空鍵的值,按照以前的算法,傳入的key爲空的時候,因爲存放數值的函數處理的時候把key爲空時放到0處,因此    //搜尋地址在0處的鏈表就好了
    private V getForNullKey() {
        for (Entry<K,V> e = table[0]; e != null; e = e.next) {
            if (e.key == null)
                return e.value;
        }
        return null;
    }

    //看是否有哪一個Entry內的key等於傳入的key,有的話爲true,不然爲false
    public boolean containsKey(Object key) {
        return getEntry(key) != null;
    }

   //獲取key對應的Entry
    final Entry<K,V> getEntry(Object key) {
    //key爲空的時候直接給0,不然計算會拋空指針異常
        int hash = (key == null) ? 0 : hash(key.hashCode());
        //遍歷整個鏈表
        for (Entry<K,V> e = table[indexFor(hash, table.length)];
             e != null;
             e = e.next) {
            Object k;
            //e的key與傳入的相等就返回此Entry
            if (e.hash == hash &&
                ((k = e.key) == key || (key != null && key.equals(k))))
                return e;
        }
        //不然爲空
        return null;
    }


    //存入數據
    public V put(K key, V value) {
    //key爲空的時候特殊處理
        if (key == null)
            return putForNullKey(value);
          //計算key的hash值
        int hash = hash(key.hashCode());
        //經過key定位到數組的位置
        int i = indexFor(hash, table.length);
        //遍歷i上的鏈表
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
            //若是找到有同樣的(同一個key),就替換此處的值,只替換此處Entry內的value屬性值
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                //不知道幹啥的
                e.recordAccess(this);
                //返回之前的value  PS:有些API手冊上沒註明會返回原來的值
                return oldValue;
            }
        }
        //修改次數+1
        modCount++;
        //發現Entry[]的i位置上的鏈表沒有一樣的key,就在i上添加值,具體的添加細節看下面的方法註釋
        addEntry(hash, key, value, i);
        //而後返回NULL
        return null;
    }

    //key爲空的時候存放value
    private V putForNullKey(V value) {
    //遍歷Entry[]0處的鏈表
        for (Entry<K,V> e = table[0]; e != null; e = e.next) {
        //功能同上個方法
            if (e.key == null) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }
        //同上,0處沒發現有等於null的key就添加一個值
        modCount++;
        addEntry(0, null, value, 0);
        return null;
    }

   //最後一個構造函數new Map(map)的業務方法
    private void putForCreate(K key, V value) {
    //若key爲空仍然用0,不然就計算出hash值
        int hash = (key == null) ? 0 : hash(key.hashCode());
        //在Entry[]上的位置
        int i = indexFor(hash, table.length);
       //遍歷此位置上的鏈表
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
            //替換value
            if (e.hash == hash &&
                ((k = e.key) == key || (key != null && key.equals(k)))) {
                e.value = value;
                return;
            }
        }
      //沒找到同樣的key就建立一個Entry
        createEntry(hash, key, value, i);
    }
    
    //第四個構造函數直接調用的方法
    private void putAllForCreate(Map<? extends K, ? extends V> m) {
    //用迭代器(感受能夠用while(i.hasNext())),遍歷m內的全部元素
        for (Iterator<? extends Map.Entry<? extends K, ? extends V>> i = m.entrySet().iterator(); i.hasNext(); ) {
            Map.Entry<? extends K, ? extends V> e = i.next();
            //把每一個迭代的值用如下方法處理,具體看下面方法的註釋
            putForCreate(e.getKey(), e.getValue());
        }
    }

   //從新修改map的大小
    void resize(int newCapacity) {
    //將當前的Entry[]拿出來
        Entry[] oldTable = table;
        //舊數組的長度(數組的長度,不是數值的數量)
        int oldCapacity = oldTable.length;
        //若就數組的長度是最大值
        if (oldCapacity == MAXIMUM_CAPACITY) {
        //修改臨界值
            threshold = Integer.MAX_VALUE;
            return;
        }
        //用新的傳入長度構建一個Entry[]
        Entry[] newTable = new Entry[newCapacity];
        //複製,把原來Entry[]內的數據都複製到新的Entry[]內
        transfer(newTable);
        //替換掉舊的數組
        table = newTable;
        //修改閾值
        threshold = (int)(newCapacity * loadFactor);
    }

   //複製,把原來Entry[]內的數據都複製到新的Entry[]內
    void transfer(Entry[] newTable) {
    //把當前數組(舊數組)「存盤」
        Entry[] src = table;
        //新數組的長度
        int newCapacity = newTable.length;
        //遍歷舊的數組
        for (int j = 0; j < src.length; j++) {
        //舊數組的數據「存盤」
            Entry<K,V> e = src[j];
            if (e != null) {
            //清空位置爲j上的全部數據
                src[j] = null;
                //開始循環以前j位置上的鏈表
                do {
                //這個循環有點意思,文字表述有點困難,後續補圖
                //首先Entry是個鏈表,它內部的next指向另外一個Entry
                //理解以上的東西后,如下循環以這個鏈表上的第一個數據爲例:
                //先把鏈表從第二個值開始的鏈表(當前循環值的後一個)「存盤」(1),而後在新的數組上計算出此鏈表                 //上第一個值應該存放的位置i(2),而後把這個數組i上的數據拼接到此鏈表第一個數據以後,造成一個新                //的鏈表(3),再把拼接後的鏈表放到數組的i處(4),而後把從第二個值開始的鏈表賦給e(5),接下                //來就是繼續循環,知道e==null爲止(6)。而後再循環此數組上的下一個鏈表
                    Entry<K,V> next = e.next;  //1
                    int i = indexFor(e.hash, newCapacity);//2
                    e.next = newTable[i];//3
                    newTable[i] = e;//4
                    e = next;//5
                } while (e != null);//6
            }
            //copy完以後數據的位置是有變化的,先不說在新數組上的位置變了,連在鏈表上的位置也變了
            //總體的調整容量思路就是:建立一個具備新容量的數組,而後把舊數組的值所有複製到新的數組裏面,同時清             //空舊數組的值(消除指針),等待回收
        }
    }

    
    //把m的值copy到原來的數組內,若是key相同就替換掉原來的value,若是key不一樣則加入
    public void putAll(Map<? extends K, ? extends V> m) {
        int numKeysToBeAdded = m.size();
        //傳入的m爲空,就返回空
        if (numKeysToBeAdded == 0)
            return;

       //若是m的size大於當前的閾值,則經過計算擴大後的m.size()會不會比table.length大,若是大則執行後續操做
       //ps:小小的計算了一下,發現只要m.size>閾值,newCapacity < targetCapacity就幾乎是恆成立的
       //大概就是4/3*m.size<table.length<4/3*m.size+1,在這種狀況下newCapacity 纔可能大於targetCapacity
        if (numKeysToBeAdded > threshold) {
            int targetCapacity = (int)(numKeysToBeAdded / loadFactor + 1);
            if (targetCapacity > MAXIMUM_CAPACITY)
                targetCapacity = MAXIMUM_CAPACITY;
            int newCapacity = table.length;
            while (newCapacity < targetCapacity)
            //給原來的table.length擴容
                newCapacity <<= 1;
            if (newCapacity > table.length)
            //調整容量的大小
                resize(newCapacity);
        }
         //開始迭代
        for (Iterator<? extends Map.Entry<? extends K, ? extends V>> i = m.entrySet().iterator(); i.hasNext(); ) {
            Map.Entry<? extends K, ? extends V> e = i.next();
            //把迭代的值扔進原來的put中,執行結果很像jquery的深拷貝(有就替換,沒有就添加)
            put(e.getKey(), e.getValue());
        }
    }

    //移除Entry[]上e.key=key的Entry,並返回此Entry處的value    
    public V remove(Object key) {
        Entry<K,V> e = removeEntryForKey(key);
        return (e == null ? null : e.value);
    }

    //按照Key移除的業務方法
    final Entry<K,V> removeEntryForKey(Object key) {
    //key爲空hash直接給0
        int hash = (key == null) ? 0 : hash(key.hashCode());
        //數組的地址
        int i = indexFor(hash, table.length);
        //存幾個盤
        Entry<K,V> prev = table[i];
        Entry<K,V> e = prev;

        //開始循環i處的鏈表,先不看if語句,先理解這個循環,其實很簡單,設兩個指針,以e爲標準,prev一直是e的         //前一個指針,循環一輪這倆指針就日後移動一格
        while (e != null) {
            Entry<K,V> next = e.next;
            Object k;
            //找到對應的值
            if (e.hash == hash &&
                ((k = e.key) == key || (key != null && key.equals(k)))) {
                //修改次數+1
                modCount++;
                //數量-1
                size--;
                //若是e==prev(這種狀況只會是刪除i處的鏈表的第一個值),就把鏈表上的第二個值放到第一個上
                if (prev == e)
                    table[i] = next;
                else
                //不然的話,就把prev指向下一個數據的指針移到第三個值身上(跳過第二個值e)
                    prev.next = next;
                e.recordRemoval(this);
                //返回這個Entry
                return e;
            }
            向後移動指針
            prev = e;
            e = next;
        }

        return e;
    }

    //同上,只不過此時傳入的是Object對象,還要判斷一下,若是此對象不是Entry格式的,就返回空
    final Entry<K,V> removeMapping(Object o) {
        if (!(o instanceof Map.Entry))
            return null;

        Map.Entry<K,V> entry = (Map.Entry<K,V>) o;
        Object key = entry.getKey();
        int hash = (key == null) ? 0 : hash(key.hashCode());
        int i = indexFor(hash, table.length);
        Entry<K,V> prev = table[i];
        Entry<K,V> e = prev;

        while (e != null) {
            Entry<K,V> next = e.next;
            if (e.hash == hash && e.equals(entry)) {
                modCount++;
                size--;
                if (prev == e)
                    table[i] = next;
                else
                    prev.next = next;
                e.recordRemoval(this);
                return e;
            }
            prev = e;
            e = next;
        }

        return e;
    }

    //清倉
    public void clear() {
        modCount++;
        Entry[] tab = table;
        for (int i = 0; i < tab.length; i++)
            tab[i] = null;
        size = 0;
    }

    //找找是不有這個value這個值
    public boolean containsValue(Object value) {
    //等於空時特殊處理
   if (value == null)
            return containsNullValue();
    //遍歷數組的每一個值
   Entry[] tab = table;
        for (int i = 0; i < tab.length ; i++)
        //遍歷每一個鏈表上的每一個值
            for (Entry e = tab[i] ; e != null ; e = e.next)
                if (value.equals(e.value))
                    return true;
   return false;
    }

    //跟上面同樣,只不過專門找尋value爲空的value,而後返回boolen值
    private boolean containsNullValue() {
   Entry[] tab = table;
        for (int i = 0; i < tab.length ; i++)
            for (Entry e = tab[i] ; e != null ; e = e.next)
                if (e.value == null)
                    return true;
   return false;
    }

    //返回一個hashmap對象,這個對象自己是新的,內部的Entry[]數組也是新的,可是,key和value是引用過來的
    //實際上,putAllForCreate(this)這個方法也是引用各變量的地址,內部屬性並無在堆內存中開闢新的空間
    public Object clone() {
        HashMap<K,V> result = null;
   try {
   //在內存中開闢空間,用於存放一個新的hashmap
       result = (HashMap<K,V>)super.clone();
   } catch (CloneNotSupportedException e) {
       
   }
       //初始化長度等各類屬性
        result.table = new Entry[table.length];
        result.entrySet = null;
        result.modCount = 0;
        result.size = 0;
        result.init();
        //this指當前的Hashmap,就是舊的hashmap,此方法上面有註釋,只是把key,value,hash和i存入新的hashmap內
        result.putAllForCreate(this);

        return result;
    }

    //這就是Entry的真面目,內部類,也叫桶,我以爲叫鏈條更有意思 - -||
    static class Entry<K,V> implements Map.Entry<K,V> {
        final K key;
        V value;
        //就是由於每一個桶裏都有另外一個桶,至關於指向(其實就是指向),另外一個桶,這樣就把整個鏈條穿起來
        Entry<K,V> next;
        final int hash;

         //構造方法
        Entry(int h, K k, V v, Entry<K,V> n) {
            value = v;
            next = n;
            key = k;
            hash = h;
        }

        //沒啥說的
        public final K getKey() {
            return key;
        }

        //沒啥說的
        public final V getValue() {
            return value;
        }

        //沒啥說的
        public final V setValue(V newValue) {
       V oldValue = value;
            value = newValue;
            return oldValue;
        }

        //自定義equels方法
        public final boolean equals(Object o) {
        //判斷類型
            if (!(o instanceof Map.Entry))
                return false;
                //強轉一個
            Map.Entry e = (Map.Entry)o;
            //當前key
            Object k1 = getKey();
            //傳入的key
            Object k2 = e.getKey();
            //判斷key和value是否相同,此處要求內存地址或者內容相同
            if (k1 == k2 || (k1 != null && k1.equals(k2))) {
                Object v1 = getValue();
                Object v2 = e.getValue();
                if (v1 == v2 || (v1 != null && v1.equals(v2)))
                    return true;
            }
            return false;
        }

        //重寫hashcode方法,爲了equals準備
        public final int hashCode() {
            return (key==null   ? 0 : key.hashCode()) ^
                   (value==null ? 0 : value.hashCode());
        }

        //沒啥說的
        public final String toString() {
            return getKey() + "=" + getValue();
        }

        //沒啥說的,沒懂有什麼用
        void recordAccess(HashMap<K,V> m) {
        }

       
        void recordRemoval(HashMap<K,V> m) {
        }
    }

    //建立新的桶
    void addEntry(int hash, K key, V value, int bucketIndex) {
    //原來bucketIndex處的鏈表存盤
   Entry<K,V> e = table[bucketIndex];
   //建立新的桶,而後把以前的鏈表鏈接到新的桶上,造成新的鏈表
        table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
        //數據量超過閾值以後就擴大table.length,而後要從新計算閾值,老規矩仍是大於等於2 * table.length的第        //一個2的n次冪*3/4
        if (size++ >= threshold)
            resize(2 * table.length);
    }

   //建立新的桶,和上個方法差很少,只是不用擴大閾值,由於調用這個方法的方法都知道,建立的桶是不會超過閾值的
    void createEntry(int hash, K key, V value, int bucketIndex) {
   Entry<K,V> e = table[bucketIndex];
        table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
        size++;
    }

    //實現迭代器
    private abstract class HashIterator<E> implements Iterator<E> {
        Entry<K,V> next;   //下一個值
        int expectedModCount;  // 用來存儲改變的次數
        int index;    //當前指針
        Entry<K,V> current;    //當前值

        //構造方法
        HashIterator() {
        //存儲修改次數
            expectedModCount = modCount;
            if (size > 0) { // advance to first entry
                Entry[] t = table;
                //看起來是用來循環數組上的每個鏈表,可是不知道爲何在構造器裏這樣寫
                while (index < t.length && (next = t[index++]) == null)
                    ;
            }
        }

        //經常使用迭代器判斷方法
        public final boolean hasNext() {
            return next != null;
        }

        //返回迭代的下一個桶的值
        final Entry<K,V> nextEntry() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            //next賦給一個新的桶(next在構造器裏被賦值過)
            Entry<K,V> e = next;
            if (e == null)
                throw new NoSuchElementException();
           //next的指針日後移一個單位,並判斷這個鏈表是否到最後一個值
            if ((next = e.next) == null) {
            //若是是最後一個值,則index指向下一個數組的位置,next則指向下一個數組的第一個桶
                Entry[] t = table;
                while (index < t.length && (next = t[index++]) == null)
                    ;
            }
            //e賦給當前值
       current = e;
       //返回當前值
            return e;
        }

        //移除當前值
        public void remove() {
            if (current == null)
                throw new IllegalStateException();
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            Object k = current.key;
            current = null;
            HashMap.this.removeEntryForKey(k);
            expectedModCount = modCount;
        }

    }

   //把以上的類當父類繼承,next()只返回value
    private final class ValueIterator extends HashIterator<V> {
        public V next() {
            return nextEntry().value;
        }
    }
    
    //一樣繼承,可是隻返回桶的key
    private final class KeyIterator extends HashIterator<K> {
        public K next() {
            return nextEntry().getKey();
        }
    }

    //返回桶
    private final class EntryIterator extends HashIterator<Map.Entry<K,V>> {
        public Map.Entry<K,V> next() {
            return nextEntry();
        }
    }

    //沒加訪問權限符,默認是friendly,只有同類和同包中的類才能訪問
    Iterator<K> newKeyIterator()   {
        return new KeyIterator();
    }
    Iterator<V> newValueIterator()   {
        return new ValueIterator();
    }
    Iterator<Map.Entry<K,V>> newEntryIterator()   {
        return new EntryIterator();
    }


    
   //生命一個Set
    private transient Set<Map.Entry<K,V>> entrySet = null;

   //賦值ks一個new KeySet()
    public Set<K> keySet() {
        Set<K> ks = keySet;
        return (ks != null ? ks : (keySet = new KeySet()));
    }

   //繼承抽象Set,一個Set的視圖
    private final class KeySet extends AbstractSet<K> {
    //實現接口的方法,返回以前寫好的方法,返回桶的key
        public Iterator<K> iterator() {
            return newKeyIterator();
        }
        //下面全是重寫
        public int size() {
            return size;
        }
        public boolean contains(Object o) {
            return containsKey(o);
        }
        public boolean remove(Object o) {
            return HashMap.this.removeEntryForKey(o) != null;
        }
        public void clear() {
            HashMap.this.clear();
        }
    }

    //把桶的value轉化成爲Collection類型,返回Collection類型的視圖
    public Collection<V> values() {
        Collection<V> vs = values;
        return (vs != null ? vs : (values = new Values()));
    }

    //定義一個類,實現AbstractCollection接口,至關於建立一個AbstractCollection類型的類
    private final class Values extends AbstractCollection<V> {
        public Iterator<V> iterator() {
            return newValueIterator();
        }
        public int size() {
            return size;
        }
        public boolean contains(Object o) {
            return containsValue(o);
        }
        public void clear() {
            HashMap.this.clear();
        }
    }

    //返回一個entrySet
    public Set<Map.Entry<K,V>> entrySet() {
   return entrySet0();
    }

    //entrySet的視圖
    private Set<Map.Entry<K,V>> entrySet0() {
        Set<Map.Entry<K,V>> es = entrySet;
        return es != null ? es : (entrySet = new EntrySet());
    }

    //其實和keySet是同樣的,只不過這裏的迭代器中的next方法返回的是entry,keyset中的迭代器方法返回的是key
    private final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
        public Iterator<Map.Entry<K,V>> iterator() {
            return newEntryIterator();
        }
        public boolean contains(Object o) {
            if (!(o instanceof Map.Entry))
                return false;
            Map.Entry<K,V> e = (Map.Entry<K,V>) o;
            Entry<K,V> candidate = getEntry(e.getKey());
            return candidate != null && candidate.equals(e);
        }
        public boolean remove(Object o) {
            return removeMapping(o) != null;
        }
        public int size() {
            return size;
        }
        public void clear() {
            HashMap.this.clear();
        }
    }

   //不懂
    private void writeObject(java.io.ObjectOutputStream s)
        throws IOException
    {
   Iterator<Map.Entry<K,V>> i =
       (size > 0) ? entrySet0().iterator() : null;

  
   s.defaultWriteObject();

   
   s.writeInt(table.length);

   
   s.writeInt(size);

       
   if (i != null) {
       while (i.hasNext()) {
      Map.Entry<K,V> e = i.next();
      s.writeObject(e.getKey());
      s.writeObject(e.getValue());
       }
        }
    }

    private static final long serialVersionUID = 362498820763181265L;

    
    private void readObject(java.io.ObjectInputStream s)
         throws IOException, ClassNotFoundException
    {
  
   s.defaultReadObject();

   
   int numBuckets = s.readInt();
   table = new Entry[numBuckets];

        init();  

   
   int size = s.readInt();

   
   for (int i=0; i<size; i++) {
       K key = (K) s.readObject();
       V value = (V) s.readObject();
       putForCreate(key, value);
   }
    }

    // These methods are used when serializing HashSets
    int   capacity()     { return table.length; }
    float loadFactor()   { return loadFactor;   }
}

最後一段迭代器解釋的不是很清楚,能夠逆向來想,collection和set接口都有定義這些類的方法、入參和返回參數,那若是要返回這些類型的對象,就須要一個類去實現這些接口,而後被返回。而這些接口中都有定義迭代器的方法,那就須要返回一個迭代器的對象,此時就寫一個HashIterator抽象類,並實現Iterator接口,但又因爲需求的不一樣(有些要返回value,有些要返回key,有些又要返回entry),因此就定義爲抽象類,這樣就不用實現Iterator下的全部方法,下面再寫三個類,繼承HashIterator,並實現next()方法,用來返回不一樣的需求值。而後咱們在定義一個方法,用來返回剛纔編寫的類的對象,將此方法放入collection和set的實現類的Iterator方法中,這樣就返回了相應的視圖java

PS:不是太瞭解爲何要多加一個方法去返回三個迭代器對象,目測應該是出於訪問權限的關係,可能其餘的類中也須要調用到這個方法,因此設置成friendly(沒加訪問權限符,默認爲friendly)。jquery

相關文章
相關標籤/搜索