数据结构之Hashtable

来源:互联网 发布:windows10怎么隐藏软件 编辑:程序博客网 时间:2024/05/20 19:46

直接上JDK源码

Hashtable<K,V>源代码

public class Hashtable    extends Dictionary    implements Map, Cloneable, java.io.Serializable {    private transient Entry[] table;    private transient int count;    private int threshold;    private float loadFactor;    private transient int modCount = 0;    private static final long serialVersionUID = 1421746759512286392L;    public Hashtable(int initialCapacity, float loadFactor) {        if (initialCapacity < 0)            throw new IllegalArgumentException("Illegal Capacity: "+                                               initialCapacity);        if (loadFactor <= 0 || Float.isNaN(loadFactor))            throw new IllegalArgumentException("Illegal Load: "+loadFactor);        if (initialCapacity==0)            initialCapacity = 1;        this.loadFactor = loadFactor;        table = new Entry[initialCapacity];        threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);    }    public Hashtable(int initialCapacity) {        this(initialCapacity, 0.75f);    }    public Hashtable() {        this(11, 0.75f);    }    public Hashtable(Map t) {        this(Math.max(2*t.size(), 11), 0.75f);        putAll(t);    }    public synchronized int size() {        return count;    }    public synchronized boolean isEmpty() {        return count == 0;    }    public synchronized Enumeration keys() {        return this.getEnumeration(KEYS);    }    public synchronized Enumeration elements() {        return this.getEnumeration(VALUES);    }    public synchronized boolean contains(Object value) {        if (value == null) {            throw new NullPointerException();        }        Entry tab[] = table;        for (int i = tab.length ; i-- > 0 ;) {            for (Entry e = tab[i] ; e != null ; e = e.next) {                if (e.value.equals(value)) {                    return true;                }            }        }        return false;    }    public boolean containsValue(Object value) {        return contains(value);    }    public synchronized boolean containsKey(Object key) {        Entry tab[] = table;        int hash = key.hashCode();        int index = (hash & 0x7FFFFFFF) % tab.length;        for (Entry e = tab[index] ; e != null ; e = e.next) {            if ((e.hash == hash) && e.key.equals(key)) {                return true;            }        }        return false;    }    @SuppressWarnings("unchecked")    public synchronized V get(Object key) {        Entry tab[] = table;        int hash = key.hashCode();        int index = (hash & 0x7FFFFFFF) % tab.length;        for (Entry e = tab[index] ; e != null ; e = e.next) {            if ((e.hash == hash) && e.key.equals(key)) {                return (V)e.value;            }        }        return null;    }    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;    @SuppressWarnings("unchecked")    protected void rehash() {        int oldCapacity = table.length;        Entry[] oldMap = table;        // overflow-conscious code        int newCapacity = (oldCapacity << 1) + 1;        if (newCapacity - MAX_ARRAY_SIZE > 0) {            if (oldCapacity == MAX_ARRAY_SIZE)                // Keep running with MAX_ARRAY_SIZE buckets                return;            newCapacity = MAX_ARRAY_SIZE;        }        Entry[] newMap = new Entry[newCapacity];        modCount++;        threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);        table = newMap;        for (int i = oldCapacity ; i-- > 0 ;) {            for (Entry old = (Entry)oldMap[i] ; old != null ; ) {                Entry e = old;                old = old.next;                int index = (e.hash & 0x7FFFFFFF) % newCapacity;                e.next = (Entry)newMap[index];                newMap[index] = e;            }        }    }    private void addEntry(int hash, K key, V value, int index) {        modCount++;        Entry tab[] = table;        if (count >= threshold) {            // Rehash the table if the threshold is exceeded            rehash();            tab = table;            hash = key.hashCode();            index = (hash & 0x7FFFFFFF) % tab.length;        }        // Creates the new entry.        @SuppressWarnings("unchecked")        Entry e = (Entry) tab[index];        tab[index] = new Entry<>(hash, key, value, e);        count++;    }    public synchronized V put(K key, V value) {        // Make sure the value is not null        if (value == null) {            throw new NullPointerException();        }        // Makes sure the key is not already in the hashtable.        Entry tab[] = table;        int hash = key.hashCode();        int index = (hash & 0x7FFFFFFF) % tab.length;        @SuppressWarnings("unchecked")        Entry entry = (Entry)tab[index];        for(; entry != null ; entry = entry.next) {            if ((entry.hash == hash) && entry.key.equals(key)) {                V old = entry.value;                entry.value = value;                return old;            }        }        addEntry(hash, key, value, index);        return null;    }    public synchronized V remove(Object key) {        Entry tab[] = table;        int hash = key.hashCode();        int index = (hash & 0x7FFFFFFF) % tab.length;        @SuppressWarnings("unchecked")        Entry e = (Entry)tab[index];        for(Entry prev = null ; e != null ; prev = e, e = e.next) {            if ((e.hash == hash) && e.key.equals(key)) {                modCount++;                if (prev != null) {                    prev.next = e.next;                } else {                    tab[index] = e.next;                }                count--;                V oldValue = e.value;                e.value = null;                return oldValue;            }        }        return null;    }    public synchronized void putAll(Map t) {        for (Map.Entry e : t.entrySet())            put(e.getKey(), e.getValue());    }    public synchronized void clear() {        Entry tab[] = table;        modCount++;        for (int index = tab.length; --index >= 0; )            tab[index] = null;        count = 0;    }    public synchronized Object clone() {        try {            Hashtable t = (Hashtable)super.clone();            t.table = new Entry[table.length];            for (int i = table.length ; i-- > 0 ; ) {                t.table[i] = (table[i] != null)                    ? (Entry) table[i].clone() : null;            }            t.keySet = null;            t.entrySet = null;            t.values = null;            t.modCount = 0;            return t;        } catch (CloneNotSupportedException e) {            // this shouldn't happen, since we are Cloneable            throw new InternalError(e);        }    }    public synchronized String toString() {        int max = size() - 1;        if (max == -1)            return "{}";        StringBuilder sb = new StringBuilder();        Iterator> it = entrySet().iterator();        sb.append('{');        for (int i = 0; ; i++) {            Map.Entry e = it.next();            K key = e.getKey();            V value = e.getValue();            sb.append(key   == this ? "(this Map)" : key.toString());            sb.append('=');            sb.append(value == this ? "(this Map)" : value.toString());            if (i == max)                return sb.append('}').toString();            sb.append(", ");        }    }    private  Enumeration getEnumeration(int type) {        if (count == 0) {            return Collections.emptyEnumeration();        } else {            return new Enumerator<>(type, false);        }    }    private  Iterator getIterator(int type) {        if (count == 0) {            return Collections.emptyIterator();        } else {            return new Enumerator<>(type, true);        }    }    private transient volatile Set keySet = null;    private transient volatile Set> entrySet = null;    private transient volatile Collection values = null;    public Set keySet() {        if (keySet == null)            keySet = Collections.synchronizedSet(new KeySet(), this);        return keySet;    }    private class KeySet extends AbstractSet {        public Iterator iterator() {            return getIterator(KEYS);        }        public int size() {            return count;        }        public boolean contains(Object o) {            return containsKey(o);        }        public boolean remove(Object o) {            return Hashtable.this.remove(o) != null;        }        public void clear() {            Hashtable.this.clear();        }    }    public Set> entrySet() {        if (entrySet==null)            entrySet = Collections.synchronizedSet(new EntrySet(), this);        return entrySet;    }    private class EntrySet extends AbstractSet> {        public Iterator> iterator() {            return getIterator(ENTRIES);        }        public boolean add(Map.Entry o) {            return super.add(o);        }        public boolean contains(Object o) {            if (!(o instanceof Map.Entry))                return false;            Map.Entry entry = (Map.Entry)o;            Object key = entry.getKey();            Entry[] tab = table;            int hash = key.hashCode();            int index = (hash & 0x7FFFFFFF) % tab.length;            for (Entry e = tab[index]; e != null; e = e.next)                if (e.hash==hash && e.equals(entry))                    return true;            return false;        }        public boolean remove(Object o) {            if (!(o instanceof Map.Entry))                return false;            Map.Entry entry = (Map.Entry) o;            Object key = entry.getKey();            Entry[] tab = table;            int hash = key.hashCode();            int index = (hash & 0x7FFFFFFF) % tab.length;            @SuppressWarnings("unchecked")            Entry e = (Entry)tab[index];            for(Entry prev = null; e != null; prev = e, e = e.next) {                if (e.hash==hash && e.equals(entry)) {                    modCount++;                    if (prev != null)                        prev.next = e.next;                    else                        tab[index] = e.next;                    count--;                    e.value = null;                    return true;                }            }            return false;        }        public int size() {            return count;        }        public void clear() {            Hashtable.this.clear();        }    }    public Collection values() {        if (values==null)            values = Collections.synchronizedCollection(new ValueCollection(),                                                        this);        return values;    }    private class ValueCollection extends AbstractCollection {        public Iterator iterator() {            return getIterator(VALUES);        }        public int size() {            return count;        }        public boolean contains(Object o) {            return containsValue(o);        }        public void clear() {            Hashtable.this.clear();        }    }    public synchronized boolean equals(Object o) {        if (o == this)            return true;        if (!(o instanceof Map))            return false;        Map t = (Map) o;        if (t.size() != size())            return false;        try {            Iterator> i = entrySet().iterator();            while (i.hasNext()) {                Map.Entry e = i.next();                K key = e.getKey();                V value = e.getValue();                if (value == null) {                    if (!(t.get(key)==null && t.containsKey(key)))                        return false;                } else {                    if (!value.equals(t.get(key)))                        return false;                }            }        } catch (ClassCastException unused)   {            return false;        } catch (NullPointerException unused) {            return false;        }        return true;    }    public synchronized int hashCode() {        int h = 0;        if (count == 0 || loadFactor < 0)            return h;  // Returns zero        loadFactor = -loadFactor;  // Mark hashCode computation in progress        Entry[] tab = table;        for (Entry entry : tab) {            while (entry != null) {                h += entry.hashCode();                entry = entry.next;            }        }        loadFactor = -loadFactor;  // Mark hashCode computation complete        return h;    }    @Override    public synchronized V getOrDefault(Object key, V defaultValue) {        V result = get(key);        return (null == result) ? defaultValue : result;    }    @SuppressWarnings("unchecked")    @Override    public synchronized void forEach(BiConsumer action) {        Objects.requireNonNull(action);     // explicit check required in case                                            // table is empty.        final int expectedModCount = modCount;        Entry[] tab = table;        for (Entry entry : tab) {            while (entry != null) {                action.accept((K)entry.key, (V)entry.value);                entry = entry.next;                if (expectedModCount != modCount) {                    throw new ConcurrentModificationException();                }            }        }    }    @SuppressWarnings("unchecked")    @Override    public synchronized void replaceAll(BiFunction function) {        Objects.requireNonNull(function);     // explicit check required in case                                              // table is empty.        final int expectedModCount = modCount;        Entry[] tab = (Entry[])table;        for (Entry entry : tab) {            while (entry != null) {                entry.value = Objects.requireNonNull(                    function.apply(entry.key, entry.value));                entry = entry.next;                if (expectedModCount != modCount) {                    throw new ConcurrentModificationException();                }            }        }    }    @Override    public synchronized V putIfAbsent(K key, V value) {        Objects.requireNonNull(value);        // Makes sure the key is not already in the hashtable.        Entry tab[] = table;        int hash = key.hashCode();        int index = (hash & 0x7FFFFFFF) % tab.length;        @SuppressWarnings("unchecked")        Entry entry = (Entry)tab[index];        for (; entry != null; entry = entry.next) {            if ((entry.hash == hash) && entry.key.equals(key)) {                V old = entry.value;                if (old == null) {                    entry.value = value;                }                return old;            }        }        addEntry(hash, key, value, index);        return null;    }    @Override    public synchronized boolean remove(Object key, Object value) {        Objects.requireNonNull(value);        Entry tab[] = table;        int hash = key.hashCode();        int index = (hash & 0x7FFFFFFF) % tab.length;        @SuppressWarnings("unchecked")        Entry e = (Entry)tab[index];        for (Entry prev = null; e != null; prev = e, e = e.next) {            if ((e.hash == hash) && e.key.equals(key) && e.value.equals(value)) {                modCount++;                if (prev != null) {                    prev.next = e.next;                } else {                    tab[index] = e.next;                }                count--;                e.value = null;                return true;            }        }        return false;    }    @Override    public synchronized boolean replace(K key, V oldValue, V newValue) {        Objects.requireNonNull(oldValue);        Objects.requireNonNull(newValue);        Entry tab[] = table;        int hash = key.hashCode();        int index = (hash & 0x7FFFFFFF) % tab.length;        @SuppressWarnings("unchecked")        Entry e = (Entry)tab[index];        for (; e != null; e = e.next) {            if ((e.hash == hash) && e.key.equals(key)) {                if (e.value.equals(oldValue)) {                    e.value = newValue;                    return true;                } else {                    return false;                }            }        }        return false;    }    @Override    public synchronized V replace(K key, V value) {        Objects.requireNonNull(value);        Entry tab[] = table;        int hash = key.hashCode();        int index = (hash & 0x7FFFFFFF) % tab.length;        @SuppressWarnings("unchecked")        Entry e = (Entry)tab[index];        for (; e != null; e = e.next) {            if ((e.hash == hash) && e.key.equals(key)) {                V oldValue = e.value;                e.value = value;                return oldValue;            }        }        return null;    }    @Override    public synchronized V computeIfAbsent(K key, Function mappingFunction) {        Objects.requireNonNull(mappingFunction);        Entry tab[] = table;        int hash = key.hashCode();        int index = (hash & 0x7FFFFFFF) % tab.length;        @SuppressWarnings("unchecked")        Entry e = (Entry)tab[index];        for (; e != null; e = e.next) {            if (e.hash == hash && e.key.equals(key)) {                // Hashtable not accept null value                return e.value;            }        }        V newValue = mappingFunction.apply(key);        if (newValue != null) {            addEntry(hash, key, newValue, index);        }        return newValue;    }    @Override    public synchronized V computeIfPresent(K key, BiFunction remappingFunction) {        Objects.requireNonNull(remappingFunction);        Entry tab[] = table;        int hash = key.hashCode();        int index = (hash & 0x7FFFFFFF) % tab.length;        @SuppressWarnings("unchecked")        Entry e = (Entry)tab[index];        for (Entry prev = null; e != null; prev = e, e = e.next) {            if (e.hash == hash && e.key.equals(key)) {                V newValue = remappingFunction.apply(key, e.value);                if (newValue == null) {                    modCount++;                    if (prev != null) {                        prev.next = e.next;                    } else {                        tab[index] = e.next;                    }                    count--;                } else {                    e.value = newValue;                }                return newValue;            }        }        return null;    }    @Override    public synchronized V compute(K key, BiFunction remappingFunction) {        Objects.requireNonNull(remappingFunction);        Entry tab[] = table;        int hash = key.hashCode();        int index = (hash & 0x7FFFFFFF) % tab.length;        @SuppressWarnings("unchecked")        Entry e = (Entry)tab[index];        for (Entry prev = null; e != null; prev = e, e = e.next) {            if (e.hash == hash && Objects.equals(e.key, key)) {                V newValue = remappingFunction.apply(key, e.value);                if (newValue == null) {                    modCount++;                    if (prev != null) {                        prev.next = e.next;                    } else {                        tab[index] = e.next;                    }                    count--;                } else {                    e.value = newValue;                }                return newValue;            }        }        V newValue = remappingFunction.apply(key, null);        if (newValue != null) {            addEntry(hash, key, newValue, index);        }        return newValue;    }    @Override    public synchronized V merge(K key, V value, BiFunction remappingFunction) {        Objects.requireNonNull(remappingFunction);        Entry tab[] = table;        int hash = key.hashCode();        int index = (hash & 0x7FFFFFFF) % tab.length;        @SuppressWarnings("unchecked")        Entry e = (Entry)tab[index];        for (Entry prev = null; e != null; prev = e, e = e.next) {            if (e.hash == hash && e.key.equals(key)) {                V newValue = remappingFunction.apply(e.value, value);                if (newValue == null) {                    modCount++;                    if (prev != null) {                        prev.next = e.next;                    } else {                        tab[index] = e.next;                    }                    count--;                } else {                    e.value = newValue;                }                return newValue;            }        }        if (value != null) {            addEntry(hash, key, value, index);        }        return value;    }    private void writeObject(java.io.ObjectOutputStream s)            throws IOException {        Entry entryStack = null;        synchronized (this) {            s.defaultWriteObject();            s.writeInt(table.length);            s.writeInt(count);            for (int index = 0; index < table.length; index++) {                Entry entry = table[index];                while (entry != null) {                    entryStack =                        new Entry<>(0, entry.key, entry.value, entryStack);                    entry = entry.next;                }            }        }        while (entryStack != null) {            s.writeObject(entryStack.key);            s.writeObject(entryStack.value);            entryStack = entryStack.next;        }    }    private void readObject(java.io.ObjectInputStream s)         throws IOException, ClassNotFoundException    {        s.defaultReadObject();        int origlength = s.readInt();        int elements = s.readInt();        int length = (int)(elements * loadFactor) + (elements / 20) + 3;        if (length > elements && (length & 1) == 0)            length--;        if (origlength > 0 && length > origlength)            length = origlength;        table = new Entry[length];        threshold = (int)Math.min(length * loadFactor, MAX_ARRAY_SIZE + 1);        count = 0;        // Read the number of elements and then all the key/value objects        for (; elements > 0; elements--) {            @SuppressWarnings("unchecked")                K key = (K)s.readObject();            @SuppressWarnings("unchecked")                V value = (V)s.readObject();            // synch could be eliminated for performance            reconstitutionPut(table, key, value);        }    }    private void reconstitutionPut(Entry[] tab, K key, V value)        throws StreamCorruptedException    {        if (value == null) {            throw new java.io.StreamCorruptedException();        }        int hash = key.hashCode();        int index = (hash & 0x7FFFFFFF) % tab.length;        for (Entry e = tab[index] ; e != null ; e = e.next) {            if ((e.hash == hash) && e.key.equals(key)) {                throw new java.io.StreamCorruptedException();            }        }        @SuppressWarnings("unchecked")            Entry e = (Entry)tab[index];        tab[index] = new Entry<>(hash, key, value, e);        count++;    }    private static class Entry implements Map.Entry {        final int hash;        final K key;        V value;        Entry next;        protected Entry(int hash, K key, V value, Entry next) {            this.hash = hash;            this.key =  key;            this.value = value;            this.next = next;        }        @SuppressWarnings("unchecked")        protected Object clone() {            return new Entry<>(hash, key, value,                                  (next==null ? null : (Entry) next.clone()));        }        public K getKey() {            return key;        }        public V getValue() {            return value;        }        public V setValue(V value) {            if (value == null)                throw new NullPointerException();            V oldValue = this.value;            this.value = value;            return oldValue;        }        public boolean equals(Object o) {            if (!(o instanceof Map.Entry))                return false;            Map.Entry e = (Map.Entry)o;            return (key==null ? e.getKey()==null : key.equals(e.getKey())) &&               (value==null ? e.getValue()==null : value.equals(e.getValue()));        }        public int hashCode() {            return hash ^ Objects.hashCode(value);        }        public String toString() {            return key.toString()+"="+value.toString();        }    }    private static final int KEYS = 0;    private static final int VALUES = 1;    private static final int ENTRIES = 2;    private class Enumerator implements Enumeration, Iterator {        Entry[] table = Hashtable.this.table;        int index = table.length;        Entry entry = null;        Entry lastReturned = null;        int type;        boolean iterator;        protected int expectedModCount = modCount;        Enumerator(int type, boolean iterator) {            this.type = type;            this.iterator = iterator;        }        public boolean hasMoreElements() {            Entry e = entry;            int i = index;            Entry[] t = table;            /* Use locals for faster loop iteration */            while (e == null && i > 0) {                e = t[--i];            }            entry = e;            index = i;            return e != null;        }        @SuppressWarnings("unchecked")        public T nextElement() {            Entry et = entry;            int i = index;            Entry[] t = table;            /* Use locals for faster loop iteration */            while (et == null && i > 0) {                et = t[--i];            }            entry = et;            index = i;            if (et != null) {                Entry e = lastReturned = entry;                entry = e.next;                return type == KEYS ? (T)e.key : (type == VALUES ? (T)e.value : (T)e);            }            throw new NoSuchElementException("Hashtable Enumerator");        }        public boolean hasNext() {            return hasMoreElements();        }        public T next() {            if (modCount != expectedModCount)                throw new ConcurrentModificationException();            return nextElement();        }        public void remove() {            if (!iterator)                throw new UnsupportedOperationException();            if (lastReturned == null)                throw new IllegalStateException("Hashtable Enumerator");            if (modCount != expectedModCount)                throw new ConcurrentModificationException();            synchronized(Hashtable.this) {                Entry[] tab = Hashtable.this.table;                int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length;                @SuppressWarnings("unchecked")                Entry e = (Entry)tab[index];                for(Entry prev = null; e != null; prev = e, e = e.next) {                    if (e == lastReturned) {                        modCount++;                        expectedModCount++;                        if (prev == null)                            tab[index] = e.next;                        else                            prev.next = e.next;                        count--;                        lastReturned = null;                        return;                    }                }                throw new ConcurrentModificationException();            }        }    }}
Dictionary<K,V>源代码

public abstractclass Dictionary {    public Dictionary() {    }    abstract public int size();    abstract public boolean isEmpty();    abstract public Enumeration keys();    abstract public Enumeration elements();    abstract public V get(Object key);    abstract public V put(K key, V value);    abstract public V remove(Object key);}
Map的源代码就不再叙述了
Hashtable是非泛型的集合,所以在检索和存储值类型时通常会发生装箱与拆箱的操作。 
当把某个元素添加到 Hashtable 时,将根据键的哈希代码将该元素放入存储桶中,由于是散列算法所以会出现一个哈希函数能够为两个不同的键生成相同的哈希代码,该键的后续查找将使用键的哈希代码只在一个特定存储桶中搜索,这将大大减少为查找一个元素所需的键比较的次数。
Hashtable 的加载因子确定元素与Hashtable 可拥有的元素数的最大比率。加载因子越小,平均查找速度越快,但消耗的内存也增加。默认的加载因子 0.72通常提供速度和大小之间的最佳平衡。当创建 Hashtable 时,也可以指定其他加载因子。元素总量/ Hashtable 可拥有的元素数=加载因子 
当向 Hashtable 添加元素时,Hashtable 的实际加载因子将增加。当实际加载因子达到指定的加载因子时,Hashtable 中存储桶的数目自动增加到大于当前 Hashtable 存储桶数两倍的最小素数。
扩容时所有的数据需要重新进行散列计算。虽然Hash具有O(1)的数据检索效率,但它空间开销却通常很大,是以空间换取时间。所以Hashtable适用于读取操作频繁,写入操作很少的操作类型。

原创粉丝点击