Java-Collection源码分析(十)——hashTable
来源:互联网 发布:淘宝新店铺一天刷几单 编辑:程序博客网 时间:2024/05/22 06:15
Hashtable同样是基于哈希表实现的,同样每个元素是一个key-value对,不允许value值为null,采用单向链表的形式。具体操作与单向链表相同。
源码分析
public class Hashtable<K,V> extends Dictionary<K,V> implements Map<K,V>, Cloneable, java.io.Serializable { //hashtable 的数据 private transient Entry<?,?>[] table; //哈希表中的条目总数。 private transient int count; //当其大小超过此阈值时,表被重新打开。 (该字段的值为(int)(capacity * loadFactor)。) 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); } //构造一个新的空的散列表,具有指定的初始容量和默认负载因子(0.75)。 public Hashtable(int initialCapacity) { this(initialCapacity, 0.75f); } //构造一个新的,空的散列表,默认的初始容量(11)和负载因子(0.75)。 public Hashtable() { this(11, 0.75f); } //使用与给定地图相同的映射构造新的散列表。 创建散列表的初始容量足以容纳给定地图中的映射和默认负载因子(0.75)。 public Hashtable(Map<? extends K, ? extends V> t) { this(Math.max(2*t.size(), 11), 0.75f); putAll(t); } //返回此哈希表中的key的数量 public synchronized int size() { return count; } //测试这个哈希表是否将值映射到值。 public synchronized boolean isEmpty() { return count == 0; } //返回此散列表中键的枚举。 public synchronized Enumeration<K> keys() { return this.<K>getEnumeration(KEYS); } //返回此散列表中值的枚举。 对返回的对象使用枚举方法来顺序获取元素。 public synchronized Enumeration<V> elements() { return this.<V>getEnumeration(VALUES); }//测试一些键映射到这个散列表中的指定值。 此操作比containsKey方法更昂贵。//请注意,此方法的功能与containsValue(它是集合框架中的Map接口的一部分)的功能相同。 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; } //如果此哈希表将一个或多个键映射到此值,则返回true。 //请注意,此方法的功能与contains的功能相同。 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; } //返回指定键映射到的值,如果此映射不包含该键的映射,则返回null。 //更正式地,如果该映射包含从key到value的映射,使得(key.equals(k)),则该方法返回value; 否则返回null。(最多可以有一个这样的映射。) public synchronized V get(Object key) { Entry<?,?> tab[] = table; int hash = key.hashCode(); //计算索引值 int index = (hash & 0x7FFFFFFF) % tab.length; //在key对应的Entry链表下,找到hash和key值与输入可以都相等的元素 for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { return (V)e.value; } } return null; } //要分配的数组的最大大小。 一些虚拟机在阵列中保留一些头文字。 //尝试分配较大的数组可能会导致OutOfMemoryError:请求的数组大小超过VM限制 private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; //增加这个散列表的内部重组能力,从而更有效地适应和访问其条目。 //当哈希表中的键数超过此散列表的容量和负载因子时,将自动调用此方法。 protected void rehash() { int oldCapacity = table.length; Entry<?,?>[] oldMap = table; //新容量的大小设置为旧容量的两倍加一 int newCapacity = (oldCapacity << 1) + 1; //如果旧容量等于最大容量,新容器容量超过最大容量,将容量保持到最大容量 if (newCapacity - MAX_ARRAY_SIZE > 0) { if (oldCapacity == MAX_ARRAY_SIZE) return; newCapacity = MAX_ARRAY_SIZE; } //创建新的Entry链表 Entry<?,?>[] newMap = new Entry<?,?>[newCapacity]; //统计数+1 modCount++; //重新计算阙值大小 threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1); table = newMap;//将旧的hashtable的内容复制到新的hashtable中 for (int i = oldCapacity ; i-- > 0 ;) { for (Entry<K,V> old = (Entry<K,V>)oldMap[i] ; old != null ; ) { Entry<K,V> e = old; //将next往前移动一个位置 old = old.next;//重新计算索引值 int index = (e.hash & 0x7FFFFFFF) % newCapacity; //将e的next元素指向新的hashtable中索引链表的首元素 e.next = (Entry<K,V>)newMap[index]; //将e复制到新的hashtable中,作为链表的首元素,之前新hashtable中的元素往后移动一个位置 newMap[index] = e; } } } private void addEntry(int hash, K key, V value, int index) { modCount++;//获取hashtable Entry<?,?> tab[] = table; if (count >= threshold) { //如果超过阈值,则重新排列表 rehash(); tab = table; hash = key.hashCode(); index = (hash & 0x7FFFFFFF) % tab.length; } //创建一个新的Entry Entry<K,V> e = (Entry<K,V>) tab[index]; //将e连接在插入Entry的next tab[index] = new Entry<>(hash, key, value, e); count++; } /将指定的key映射到此散列表中指定的value。 key和value都不能是null。 //可以通过使用等于原始key的key调用get方法来检索该值。 public synchronized V put(K key, V value) { //确保value不为null if (value == null) { throw new NullPointerException(); } //确保key不在哈希表中。 Entry<?,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; 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; } } //如果没有key和hash匹配的元素,则创建并添加新的entry 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; 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(Map<? extends K, ? extends V> t) { for (Map.Entry<? extends K, ? extends V> 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); } } //根据Map界面中的定义,将指定的对象与此Map进行比较以相等。 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; }//将每个条目的value替换为对该条目调用给定函数的结果,直到所有条目都被处理或该函数抛出异常。 public synchronized void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) { Objects.requireNonNull(function); // 需要明确检查 final int expectedModCount = modCount; Entry<K, V>[] tab = (Entry<K, V>[])table; for (Entry<K, V> entry : tab) { while (entry != null) { entry.value = Objects.requireNonNull( function.apply(entry.key, entry.value)); entry = entry.next; if (expectedModCount != modCount) { throw new ConcurrentModificationException(); } } } } //如果指定的key还没有与value相关联(或映射到null)将其与给定value相关联并返回null,否则返回当前value。 public synchronized V putIfAbsent(K key, V value) { Objects.requireNonNull(value); Entry<?,?> tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; 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; if (old == null) { entry.value = value; } return old; } } addEntry(hash, key, value, index); return null; } //只有当目标映射到指定的值时,才能删除指定key的条目。 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<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) && 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; } //仅当当前映射到指定的value时,才能替换指定key的条目。 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<K,V> e = (Entry<K,V>)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; } //只有当目标映射到某个值时,才能替换指定键的条目。 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<K,V> e = (Entry<K,V>)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; } //如果指定的键尚未与值相关联(或映射到null),则尝试使用给定的映射函数计算其值,并将其输入到此映射中,除非为null。 public synchronized V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) { Objects.requireNonNull(mappingFunction); 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 (; 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; } //如果指定的键的值存在且非空,则尝试计算给定键的新映射及其当前映射的值。 public synchronized V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) { Objects.requireNonNull(remappingFunction); 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)) { 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; } //尝试计算指定key及其当前映射value的映射(如果没有当前映射,则为null)。 public synchronized V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) { Objects.requireNonNull(remappingFunction); 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 && 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; } //如果指定的key尚未与value相关联或与null相关联,则将其与给定的非空值相关联。 public synchronized V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) { Objects.requireNonNull(remappingFunction); 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)) { 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 static class Entry<K,V> implements Map.Entry<K,V> { final int hash; final K key; V value; Entry<K,V> next; protected Entry(int hash, K key, V value, Entry<K,V> 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<K,V>) next.clone())); } // Map.Entry Ops 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(); } } // Types of Enumerations/Iterations private static final int KEYS = 0; private static final int VALUES = 1; private static final int ENTRIES = 2; //一个哈希表枚举器类。 此类实现了枚举和迭代器接口,但是可以使用禁用Iterator方法创建单个实例。 //这是必要的,以避免无意中通过传递枚举来增加用户授予的功能。 private class Enumerator<T> implements Enumeration<T>, Iterator<T> { Entry<?,?>[] table = Hashtable.this.table; int index = table.length; Entry<?,?> entry; Entry<?,?> lastReturned; int type; //指示此枚举器是否用作迭代器或枚举。 (true - >迭代器)。 boolean iterator; //迭代器认为后台Hashtable应该具有的modCount值。 如果这个期望被违反,迭代器就检测到并发修改。 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(); } } }}rehash过程中,hashtable旧元素的复制过程:
阅读全文
0 0
- Java-Collection源码分析(十)——hashTable
- Java基础——HashTable源码分析
- java collection——源码分析
- Java-Collection源码分析(四)——ArrayList
- Java-Collection源码分析(六)——Map接口
- Java-Collection源码分析(七)——HashMap
- Java-Collection源码分析(八)——LinkedHashMap
- Java-Collection源码分析(九)——WeakHashMap
- Java-Collection源码分析(十一)—— IdentityHashMap
- Java-Collection源码分析(十三)——TreeMap
- Java-Collection源码分析(一)——Collection接口和AbstractCollection类
- Java-HashTable源码分析
- 《Java源码分析》:Hashtable
- 《Java源码分析》:Hashtable
- java集合框架09——HashTable和源码分析
- Java 集合框架源码分析(六)——HashTable
- Java多线程系列(十)—Semaphore源码分析
- [Java] Hashtable 源码简要分析
- 解决IE下JS的new Date('yyyy-MM-dd HH:mm:ss')的值为NaN-NaN的问题
- gogland跨平台编译
- java线程池练习
- ADF使用搜索提示
- Android Target/Minimum/Compile
- Java-Collection源码分析(十)——hashTable
- 【BigHereo 15】-----Arquillian Junit && javaEE单元测试实践
- 自定义View向右滑动解锁
- 企业网站要不要写原创文章,您怎么看?
- 表单
- FreeRTOS入门学习记录1——任务管理
- 大数据中简化数据的几种方式
- The SDK platform-tools version (24.0.4) is too old to check APIs compiled with API 25
- MyBatis入门(四)