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方法不太明白。

相关文章
相关标签/搜索