java容器源碼分析(五)——HashMap(續)

續前一篇java容器源碼分析(四)——HashMap,繼續分析HashMap的源碼。java

containsValue(Object 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;
}

能夠看出,這裏對table作了一次線性遍歷纔可以獲取出value,複雜度爲O(n)。app

再看一下Map遍歷用到的方法entrySet()
函數

public Set<Map.Entry<K,V>> entrySet() {
    return entrySet0();
}

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

entrySet調用了entrySet0,entrySet0返回了EntrySet對象,有點重複的樣子!源碼分析

看來主要的內容在EntrySet中,EntrySet是一個內部類。ui

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();
    }
}

並無什麼屬性!其實它是一個代理類,而且由於它是HashMap的內部類,因此能夠直接調用HashMap的方法、屬性。這個set並無add方法。EntrySet的迭代器,是經過newEntryIterator返回。this

Iterator<Map.Entry<K,V>> newEntryIterator()   {
    return new EntryIterator();
}

繼續往下看:設計

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

EntryIterator是繼承了HashIterator類。代理

private abstract class HashIterator<E> implements Iterator<E>

HashIterator是HashMap的內部抽象類,實現了Iterator接口。code

其構造函數

HashIterator() {
    expectedModCount = modCount;
    if (size > 0) { // advance to first entry
        Entry[] t = table;
        while (index < t.length && (next = t[index++]) == null)
            ;
    }
}

遍歷table數組,找到第一個不爲空的槽。

hasNext方法

public final boolean hasNext() {
    return next != null;
}

若是next不爲空,則存在下一個元素。

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;
}

remove方法是調用了HashMap的removeEntryForKey方法。沒看到next方法,這是由於HashMap想複用HashIteraotr這個類,咱們看到HashMap有三個迭代器:

private final class ValueIterator extends HashIterator<V> {
    public V next() {
        return nextEntry().value;
    }
}

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();
    }
}

ValueIterator是給values()用的迭代器,KeyIterator是給KeySet用的迭代器,EntryIterator是提供給EntrySet使用的迭代器。

這裏有能夠看出一個很是常見的設計:接口實現規範,抽象類實現大部分工做,具體類實現差別化內容!

看下HashIterator的nextEntry方法

final Entry<K,V> nextEntry() {
    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
    Entry<K,V> e = next;
    if (e == null)
        throw new NoSuchElementException();

    if ((next = e.next) == null) {
        Entry[] t = table;
        while (index < t.length && (next = t[index++]) == null)
            ;
    }
    current = e;
    return e;
}

對table一個槽一個槽的鏈表遍歷。

在看下keySet()方法

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

private final class KeySet extends AbstractSet<K> {
    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();
    }
}

額,和EntrySet基本同樣。繼續看Values()

public Collection<V> values() {
    Collection<V> vs = values;
    return (vs != null ? vs : (values = new Values()));
}

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();
    }
}

仍是差很少。

從分析Iterator的實現中能夠看到,iterator是要遍歷整個table的,因此不要將capacity的值設置得過高,也不要把loadfactor的值設置得過低。看HashMap的這句註釋:

Iteration over collection views requires time proportional to the "capacity" of the HashMap instance (the number of buckets) plus its size (the number of key-value mappings). Thus, it's very important not to set the initial capacity too high (or the load factor too low) if iteration performance is important.

HashMap的分析到這裏也差很少了,對於HashMap,仍是對其hash方法不太明白。

相關文章
相關標籤/搜索