Hashtable
来源:互联网 发布:js轮播图代码 编辑:程序博客网 时间:2024/05/23 10:40
Hashtable
Hashtable<K,V> extends Dictionary<K,V> implements Map<K,V>, Cloneable, Serializable{}
这个类实现了一个键值哈希表,其中Key值对象的类要实现hashCode和equals方法。
哈希表有两个重要的参数:初始容量值(initial capacity )和装填因子(load factor),容量值是哈希表中桶(buckets)的数量,容量值默认值为11,装填因子默认值为0.75。哈希表解决哈希碰撞的方法:每个桶中存储多个实体,这些实体需要顺序搜索。当哈希表中的实体数量与容量的比值超过装填因子时,哈希表将自动扩容。
注意:哈希表的容量值一般为质数
装填因子设置为0.75是对时间和空间消费的折中选择。设置太高,则增加时间花费;设置太低,则浪费空间。当哈希表扩容时,需要对原有哈希表中的实体进行重新哈希,会有时间消耗,如果初始容量设置
The iterators returned by the iterator method of the collections returned by all of this class’s “collection view methods” are fail-fast.
fail-fast机制:当Iterator操作时,集合中的元素发生结构性的改变(不是由于Iterator.remove方法引起的),Iterator就会抛出ConcurrentModificationException。在并发模式下,iterator会快速并且干净的失败,而不是在后面某个操作时具有任意的、具有冒险行为的、不确定的。Hashtable的枚举方法所返回的枚举对象不是fail-fast的。
fail-fast的行为不能得到保证,一般来说,在面对不同步的并发修改时是不可能做出任何保证的。itertaor的fail-fast应当只用于检测错误,而不是利用它使得程序的迭代行为运行正确。
Hashtable是同步的、线程安全的,如果程序不需要同步,可以使用HashMap代替。如果需要一个高并发的线程安全的类,则可以使用ConcurrentHashMap。
Hashtable的方法是加了synchronized关键词。
Hashtable成员变量
/*** The hash table data.* 使用Entry数组存储数据*/private transient Entry<?,?>[] table;/*** The total number of entries in the hash table.*/private transient int count;/*** The table is rehashed when its size exceeds this threshold. (The* value of this field is (int)(capacity * loadFactor).)* *重新hash的阈值* @serial*/private int threshold;/*** The load factor for the hashtable.*装填因子* @serial*/private float loadFactor;/*** The number of times this Hashtable has been structurally modified* Structural modifications are those that change the number of entries in* the Hashtable or otherwise modify its internal structure (e.g.,* rehash). This field is used to make iterators on Collection-views of* the Hashtable fail-fast. (See ConcurrentModificationException).* * Hashtable结构改变的次数,用于fail-fast机制*/private transient int modCount=0;/*** The maximum size of array to allocate.* Some VMs reserve some header words in an array.* Attempts to allocate larger arrays may result in* OutOfMemoryError: Requested array size exceeds VM limit* * 分配数组的最大值*/private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
Hashtable方法
/*** 构造函数,默认capacity=11,loadFactor=0.75;* threshold最大值为Integer.MAX_VALUE-8+1;*/public Hashtable(int initialCapacity, float loadFactor);public Hashtable(int initialCapacity);public Hashtable();/*** 注意是两倍的t.size()*/public Hashtable(Map<? extends K, ? extends V> t) { this(Math.max(2*t.size(), 11), 0.75f); putAll(t); }public synchronized int size();public synchronized boolean isEmpty();public synchronized Enumeration<K> keys() { return this.<K>getEnumeration(KEYS); }public synchronized Enumeration<V> elements() { return this.<V>getEnumeration(VALUES);/*** 对每个桶中的链表进行遍历,所以要用到两个for循环* 判断是否存在value值的键值对,比查找是否存在key值的键值对花费要高很多,因为key可以hash查找,而value只能挨个查找对比。*/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);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; } 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; }/*** 以接近两倍的原有容量扩展。* newCapacity = oldCapacity << 1 + 1; 两倍加1,也就是尽可能避免选择能被2整除的数。最多也就是MAX_ARRAY_SIZE.* 在桶中链表插入的时候,插入在头部,头部也是存储有值的。*/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<K,V> old = (Entry<K,V>)oldMap[i] ; old != null ; ) { Entry<K,V> e = old; old = old.next; int index = (e.hash & 0x7FFFFFFF) % newCapacity; //看懂这一点,和C++中的指针不同,这里没有专门的头指针。 e.next = (Entry<K,V>)newMap[index]; newMap[index] = e; } } }/***private函数,在后面几个方法中会调用。*添加一个Entry,Entry类将在稍后介绍*Entry成员变量包含有:hash,key,value,next。*/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<K,V> e = (Entry<K,V>) tab[index]; tab[index] = new Entry<>(hash, key, value, e); count++; }/*** 如果Hashtable中有key值所对应的键值对,则更新key所对应的valu,否则创建并添加一个新的Entry。* key 和 value都不能为null。当key为null时,key.hashCode()抛异常,当value为null时,检查并抛异常。*/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<K,V> entry = (Entry<K,V>)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; }/***注意删除时,要有个保存前一个结点的位置,所以有个prev变量。另外还要注意,删除的是数组中的元素还是数组内链表的元素。**/public synchronized V remove(Object key) { Entry<?,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry<K,V> e = (Entry<K,V>)tab[index]; for(Entry<K,V> 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;/***清除的时候要对数组内的每个对象进行清除。*/ 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); } }/*** 注意String的连接操作尽量用StringBuilder.*/public synchronized String toString() { int max = size() - 1; if (max == -1) return "{}"; StringBuilder sb = new StringBuilder(); Iterator<Map.Entry<K,V>> it = entrySet().iterator(); sb.append('{'); for (int i = 0; ; i++) { Map.Entry<K,V> 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(", "); } }/***type是用于区分返回的是key还是value的枚举*/ private <T> Enumeration<T> getEnumeration(int type) { if (count == 0) { return Collections.emptyEnumeration(); } else { return new Enumerator<>(type, false); } } private <T> Iterator<T> getIterator(int type) { if (count == 0) { return Collections.emptyIterator(); } else { return new Enumerator<>(type, true); } }
/*** Each of these fields are initialized to contain an instance of the* appropriate view the first time this view is requested. The views are* stateless, so there's no reason to create more than one of each.* 有且只有一份,每次访问的时候返回的都是同一份。*/private transient volatile Set<K> keySet;private transient volatile Set<Map.Entry<K,V>> entrySet;private transient volatile Collection<V> values;/** * Returns a {@link Set} view of the keys contained in this map. * The set is backed by the map, so changes to the map are * reflected in the set, and vice-versa. If the map is modified * while an iteration over the set is in progress (except through * the iterator's own <tt>remove</tt> operation), the results of * the iteration are undefined. The set supports element removal, * which removes the corresponding mapping from the map, via the * <tt>Iterator.remove</tt>, <tt>Set.remove</tt>, * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> * operations. It does not support the <tt>add</tt> or <tt>addAll</tt> * operations. * *对于keySet、entrySet、values、iterator等删除、清空操作是会改变Hashtable中的数据,Hashtable中的数据改变时,这些视图中的数据也会改变。 *这些视图对象都是现成同步的。 * @since 1.2 */ public Set<K> keySet() { if (keySet == null) keySet = Collections.synchronizedSet(new KeySet(), this); return keySet; } private class KeySet extends AbstractSet<K> { public Iterator<K> 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(); } }
/*** equals方法三步:1,判断是否是自己;2,判断是否同一类型;3,判断内容是否相等。*/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<Map.Entry<K,V>> i = entrySet().iterator(); while (i.hasNext()) { Map.Entry<K,V> 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() { /* * This code detects the recursion caused by computing the hash code * of a self-referential hash table and prevents the stack overflow * that would otherwise result. This allows certain 1.1-era * applets with self-referential hash tables to work. This code * abuses the loadFactor field to do double-duty as a hashCode * in progress flag, so as not to worsen the space performance. * A negative load factor indicates that hash code computation is * in progress. */ 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; }public synchronized V getOrDefault(Object key, V defaultValue) ;/*** 注意这里用到了modCount的值作为判断数据是否改动的依据。*/public synchronized void forEach(BiConsumer<? super K, ? super V> 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(); } } } } public synchronized void replaceAll; public synchronized V putIfAbsent; public synchronized boolean remove; ...太多了,不一一介绍了。
private static class Entry<K,V> implements Map.Entry<K,V> { final int hash; final K key; V value; Entry<K,V> next; ...
private class Enumerator<T> implements Enumeration<T>, Iterator<T> { Entry<?,?>[] table = Hashtable.this.table; int index = table.length; Entry<?,?> entry; Entry<?,?> lastReturned; int type; /** * Indicates whether this Enumerator is serving as an Iterator * or an Enumeration. (true -> Iterator). */ boolean iterator; /** * The modCount value that the iterator believes that the backing * Hashtable should have. If this expectation is violated, the iterator * has detected concurrent modification. */ 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"); } // Iterator methods 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<K,V> e = (Entry<K,V>)tab[index]; for(Entry<K,V> 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(); } } }
Iterator,Set…等删除操作会影响到原有数据。Iterator在遍历的过程中,原有数据不能发生结构性的改变,否则抛出ConcurrentModificationException,但可以用自己的remove方法使原有数据发生改变。Enumeration没有这种限制,即使原有数据在Enumeration遍历时发生结构性的改变,Enumeration也不会抛出异常,但是遍历结果不太理想,无法把控。Iterator和Enumeration遍历的时候都是从数组的最后开始往前遍历的。
hash值的计算公式
(hashCode() & 0x7FFFFFFF)%Capacity
为什么要&上0x7FFFFFFF,因为要保证计算出来的值为正整数(32位),所以最高位要默认为0,防止溢出,表示是正整数。
- HashTable
- Hashtable
- HashTable
- hashtable
- Hashtable
- HashTable
- hashtable
- HashTable
- Hashtable
- Hashtable
- Hashtable
- Hashtable
- hashtable
- Hashtable
- hashtable
- HashTable
- HashTable
- HashTable
- KissXMLClass isa错误的解决办法
- Java面向对象(下)
- 理解Binder RPC机制
- 数据结构:串的顺序存储实现
- vim+taglist+ctags+cscope+自动补齐
- Hashtable
- Linux操作常用命令
- 使用org.apache.commons.net.ftp包开发FTP客户端,实现进度汇报,实现断点续传,中文支持
- Java对象的浅层复制与深层复制
- Jedis
- 有一个X*Y的网格,只能向右、向下移动,从(0, 0)走到(X-1, Y-1),中间某些位置有障碍物,打印一条路径(优化)
- storage, especially cinder(1)
- javascript中onload的用法
- Nginx详解-服务器集群