java源码分析之集合框架HashTable 11
来源:互联网 发布:安卓助手for mac 编辑:程序博客网 时间:2024/06/03 21:38
HashTable :
- 此类实现一个哈希表,该哈希表将键映射到相应的值。任何非
null
对象都可以用作键或值。 - 为了成功地在哈希表中存储和获取对象,用作键的对象必须实现
hashCode
方法和equals
方法。 Hashtable
的实例有两个参数影响其性能:初始容量 和加载因子。容量 是哈希表中桶 的数量,初始容量 就是哈希表创建时的容量。注意,哈希表的状态为open:在发生“哈希冲突”的情况下,单个桶会存储多个条目,这些条目必须按顺序搜索。加载因子 是对哈希表在其容量自动增加之前可以达到多满的一个尺度。初始容量和加载因子这两个参数只是对该实现的提示。关于何时以及是否调用 rehash 方法的具体细节则依赖于该实现。- 通常,默认加载因子(0.75)在时间和空间成本上寻求一种折衷。加载因子过高虽然减少了空间开销,但同时也增加了查找某个条目的时间(在大多数Hashtable 操作中,包括get 和put 操作,都反映了这一点)。
- 初始容量主要控制空间消耗与执行
rehash
操作所需要的时间损耗之间的平衡。如果初始容量大于Hashtable 所包含的最大条目数除以加载因子,则永远 不会发生rehash
操作。但是,将初始容量设置太高可能会浪费空间。 - 如果很多条目要存储在一个
Hashtable
中,那么与根据需要执行自动 rehashing 操作来增大表的容量的做法相比,使用足够大的初始容量创建哈希表或许可以更有效地插入条目。(如果存储很多条目,相比HashTable自己再扩容,将初始容量设置大点更速度快)。 - HashTable是线程安全的(等会我们在源码中就能看出)
Hashtable 结构:(注意这里table首字母xiaoxi)
public class Hashtable<K,V> extends Dictionary<K,V> implements Map<K,V>, Cloneable, java.io.Serializable
- Hashtable不仅继承了Dictionary ,还实现了接口Serializable, Cloneable, Map<K,V> 。即HashTable序列化,可复制clone,是键值对保存值。
Dictionary
类是任何可将键映射到相应值的类(如Hashtable
)的抽象父类。每个键和每个值都是一个对象。在任何一个 Dictionary 对象中,每个键至多与一个值相关联。给定一个 Dictionary 和一个键,就可以查找所关联的元素。任何非null
对象都可以用作键或值。通常,应该在此类的实现中使用equals
方法,以决定两个键是否相同。注:此类已过时。新的实现应该实现 Map 接口,而不是扩展此类.
Hashtable 方法:由源码可知HashTable是线程安全的。HashTable之所以是线程安全的,是因为方法上都加了synchronized关键字
synchronized void clear() synchronized Object clone() boolean contains(Object value) synchronized boolean containsKey(Object key) synchronized boolean containsValue(Object value) synchronized Enumeration<V> elements() synchronized Set<Entry<K, V>> entrySet() synchronized boolean equals(Object object) synchronized V get(Object key) synchronized int hashCode() synchronized boolean isEmpty() synchronized Set<K> keySet() synchronized Enumeration<K> keys() synchronized V put(K key, V value) synchronized void putAll(Map<? extends K, ? extends V> map) synchronized V remove(Object key) synchronized int size() synchronized String toString() synchronized Collection<V> values()
Hashtable 数据结构
存储结构:
和HashMap一样,HashTable内部也维护了一个数组,数组中存放的是Entry<K,V>实体,数组定义如下:
private transient Entry<K,V>[] table;
Hashtable逻辑结构:
/** * Entry实体类的定义 */ private static class Entry<K,V> implements Map.Entry<K,V> { int hash;//哈希值 final K key; V value; Entry<K,V> next;//指向的下一个Entry,即链表的下一个节点 //构造方法 protected Entry(int hash, K key, V value, Entry<K,V> next) { this.hash = hash; this.key = key; this.value = value; this.next = next; } //这里是单个Entry复制,深复制 protected Object clone() { return new Entry<>(hash, key, value, (next==null ? null : (Entry<K,V>) next.clone())); } // 重写Map.Entry的全部方法5个 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; } //判断两个Entry是否相等 public boolean equals(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entry<?,?> e = (Map.Entry)o; //必须两个Entry的key和value均相等才行 return key.equals(e.getKey()) && value.equals(e.getValue()); } public int hashCode() { return (Objects.hashCode(key) ^ Objects.hashCode(value));//异或 } public String toString() {//重写Object类的toString方法 return key.toString()+"="+value.toString(); } }
Hashtable属性:
private transient Entry<K,V>[] table; private transient int count;//记录HashTable中有多少Entry实体 //阈值,用于判断是否需要调整Hashtable的容量(threshold = 容量*加载因子) private int threshold; // 加载因子 private float loadFactor; // Hashtable被改变的次数,用于fail-fast private transient int modCount = 0; // 序列版本号 private static final long serialVersionUID = 1421746759512286392L; //最大的阈值,不能超过这个 static final int ALTERNATIVE_HASHING_THRESHOLD_DEFAULT = Integer.MAX_VALUE; //哈希种子,使哈希表分布更均匀 transient int hashSeed;//最大容量private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;//set视图中需要的属性,具体看下面视图方法源码private transient volatile Set<K> keySet = null; private transient volatile Set<Map.Entry<K,V>> entrySet = null; private transient volatile Collection<V> values = null;private static final int KEYS = 0; private static final int VALUES = 1; private static final int ENTRIES = 2;
构造方法:
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); initHashSeedAsNeeded(initialCapacity);//初始化哈希种子 } public Hashtable(int initialCapacity) { this(initialCapacity, 0.75f);//默认加载因子为0.75 } public Hashtable() { this(11, 0.75f);//默认初始容量为11,加载因子为0.75 } public Hashtable(Map<? extends K, ? extends V> t) { //如果Map的2倍容量大于11,则使用新的容量 this(Math.max(2*t.size(), 11), 0.75f); putAll(t); }
存取方法:
put(K key, V value)
put(K key, V value)
将指定 key
映射到此哈希表中的指定 value
。
public synchronized V put(K key, V value) { // 确保value不为空 if (value == null) { throw new NullPointerException(); } // Makes sure the key is not already in the hashtable. Entry tab[] = table; int hash = hash(key);//计算hash值,此处会检测key是否为空 int index = (hash & 0x7FFFFFFF) % tab.length;//计算出值在数组table中的位置 for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) { if ((e.hash == hash) && e.key.equals(key)) {//如果对应的key已经存在 V old = e.value; e.value = value;//替换掉原来的value return old; } } modCount++; //判断是否需要扩容(再散列) if (count >= threshold) { rehash(); tab = table; hash = hash(key); index = (hash & 0x7FFFFFFF) % tab.length; } //如果没有对应的对应的key,新建一个Entry Entry<K,V> e = tab[index]; tab[index] = new Entry<>(hash, key, value, e); count++;//即size++ return null; }
put方法中,首先检测value是否为null,如果为null则会抛出NullPointerException异常。然后往下走,跟HashMap的过程一样,先计算哈希值,再根据哈希值计算在数组中的索引位置,不过这里计算索引位置的方法和HashMap不同,HashMap里使用的是 hash & (length-1)的方法,其实本质上跟这里用的(hash & 0x7FFFFFFF) % table.length一样的效果,但是HashMap中的方法效率要高,至于它们两为啥本质一样的,可以参见我的上一博客:HashMap,那里分析的很详细。
然后便开始往数组中存数据了,如果当前的key已经在里面了,那么直接替换原来旧的value,如果不存在,先判断数组中的Entry数量有没有达到门限值,达到了就要调用rehash方法进行扩容,然后重新计算当前key在新的数组中的索引值,然后在该位置添加进去即可。如下hash() 和rehash()方法:
//jisuan计算hash值zhi private int hash(Object k) { return hashSeed ^ k.hashCode(); } //再散列,扩容 protected void rehash() { int oldCapacity = table.length; Entry<K,V>[] oldMap = table; //扩容为 = 原长度*2+1 int newCapacity = (oldCapacity << 1) + 1; if (newCapacity - MAX_ARRAY_SIZE > 0) { if (oldCapacity == MAX_ARRAY_SIZE) return; newCapacity = MAX_ARRAY_SIZE; } Entry<K,V>[] newMap = new Entry[newCapacity]; modCount++;//重置阕值 threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);//重置hash种子 boolean rehash = initHashSeedAsNeeded(newCapacity); table = newMap;//将旧表的值放到新的表(数组)中 for (int i = oldCapacity ; i-- > 0 ;) { for (Entry<K,V> old = oldMap[i] ; old != null ; ) { Entry<K,V> e = old; old = old.next; if (rehash) { e.hash = hash(e.key); } int index = (e.hash & 0x7FFFFFFF) % newCapacity; e.next = newMap[index]; newMap[index] = e; } } }
到这里put方法就分析完了,还有个putAll方法,是将整个Map加到当前HashTable中,内部也是遍历每个Entry,然后调用上面的put方法:
putAll(Map<? extends K,? extends V> t)
将指定映射的所有映射关系复制到此哈希表中,这些映射关系将替换此哈希表拥有的、针对当前指定映射中所有键的所有映射关系。
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()); }
get(Object key)
get(Object key)
返回指定键所映射到的值,如果此映射不包含此键的映射,则返回 null
. 更确切地讲,如果此映射包含满足 (key.equals(k))
的从键 k
到值 v
的映射,则此方法返回 v
;否则,返回null
。
public synchronized V get(Object key) { Entry tab[] = table; int hash = hash(key);//计算hash值 int index = (hash & 0x7FFFFFFF) % tab.length;//根据hash值计算所在索引 for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { return e.value; } } return null; }
其他方法:
//初始化hash种子 final boolean initHashSeedAsNeeded(int capacity) { boolean currentAltHashing = hashSeed != 0; boolean useAltHashing = sun.misc.VM.isBooted() && (capacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD); boolean switching = currentAltHashing ^ useAltHashing; if (switching) { hashSeed = useAltHashing ? sun.misc.Hashing.randomHashSeed(this) : 0; } return switching; }//返回此哈希表中的键的数量。public synchronized int size() { return count; }//测试此哈希表是否没有键映射到值。public synchronized boolean isEmpty() { return count == 0; }//返回此哈希表中的键的枚举。public synchronized Enumeration<K> keys() { return this.<K>getEnumeration(KEYS); }private <T> Enumeration<T> getEnumeration(int type) { if (count == 0) {//返回一个空的枚举类型 return Collections.emptyEnumeration(); } else { return new Enumerator<>(type, false); } }//返回此哈希表中的值的枚举。 public synchronized Enumeration<V> elements() { return this.<V>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<K,V> e = tab[i] ; e != null ; e = e.next) { if (e.value.equals(value)) { return true; } } } return false; }//如果此 Hashtable 将一个或多个键映射到此值,则返回 true。public boolean containsValue(Object value) { return contains(value); }//测试指定对象是否为此哈希表中的键。public synchronized boolean containsKey(Object key) { Entry tab[] = table; int hash = hash(key); int index = (hash & 0x7FFFFFFF) % tab.length; for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { return true; } } return false; }//从哈希表中移除该键及其相应的值。public synchronized V remove(Object key) { Entry tab[] = table; int hash = hash(key); int index = (hash & 0x7FFFFFFF) % tab.length; for (Entry<K,V> e = tab[index], 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 {//如果该值是表头,表头并不代表index=0 tab[index] = e.next;//换表头 } count--; V oldValue = e.value; e.value = null; return oldValue; } } return null; }//将此哈希表清空,使其不包含任何键。public synchronized void clear() { Entry tab[] = table; modCount++;//按照table数组顺序分别将值至空 for (int index = tab.length; --index >= 0; ) tab[index] = null; count = 0; }//创建此哈希表的浅表副本。public synchronized Object clone() { try { Hashtable<K,V> t = (Hashtable<K,V>) super.clone(); t.table = new Entry[table.length]; for (int i = table.length ; i-- > 0 ; ) { t.table[i] = (table[i] != null) ? (Entry<K,V>) 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(); } }//返回此 Hashtable 对象的字符串表示形式,其形式为 ASCII 字符 ", " (逗号加空格)分隔开的、括在括号中的一组条目。public synchronized String toString() { int max = size() - 1; if (max == -1) return "{}"; StringBuilder sb = new StringBuilder();//返回此映射中包含的键的 Set 视图的iterator迭代器。 Iterator<Map.Entry<K,V>> it = entrySet().iterator(); //将HashTable的key和value用StringBuilder拼接起来 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(", "); } }private <T> Iterator<T> getIterator(int type) { if (count == 0) {//得到迭代器 return Collections.emptyIterator(); } else {//得到枚举 return new Enumerator<>(type, true); } }/*-------------视图------------------*/private transient volatile Set<K> keySet = null; private transient volatile Set<Map.Entry<K,V>> entrySet = null; private transient volatile Collection<V> values = null;private static final int KEYS = 0; private static final int VALUES = 1; private static final int ENTRIES = 2;/*++++++++++++++++键的 Set 视图+++++++++++++++++++*/public Set<K> keySet() { if (keySet == null)//指定 set 支持的同步(线程安全的)set。 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(); } }/*++++++++++++++++映射关系Entry的 set 视图+++++++++++++++++++*/public Set<Map.Entry<K,V>> entrySet() { if (entrySet==null)//指定 set 支持的同步(线程安全的)set。 entrySet = Collections.synchronizedSet(new EntrySet(), this); return entrySet; } private class EntrySet extends AbstractSet<Map.Entry<K,V>> { public Iterator<Map.Entry<K,V>> iterator() { return getIterator(ENTRIES);//得到映射关系Entry的枚举或者空迭代器 } public boolean add(Map.Entry<K,V> 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 = hash(key); 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<K,V> entry = (Map.Entry<K,V>) o; K key = entry.getKey(); Entry[] tab = table; int hash = hash(key); int index = (hash & 0x7FFFFFFF) % tab.length; for (Entry<K,V> e = tab[index], 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//如果该值是表头(表头并不代表index=0) tab[index] = e.next; count--; e.value = null; return true; } } return false; } public int size() { return count; } public void clear() { Hashtable.this.clear(); } }/*++++++++++++++++value值的 set 视图+++++++++++++++++++*/public Collection<V> values() { if (values==null)//指定 collection 支持的同步(线程安全的)collection values = Collections.synchronizedCollection(new ValueCollection(), this); return values; } private class ValueCollection extends AbstractCollection<V> { public Iterator<V> iterator() { return getIterator(VALUES);//得到value值的枚举或者空迭代器 } public int size() { return count; } public boolean contains(Object o) { return containsValue(o); } public void clear() { Hashtable.this.clear(); } }/*------------ 比较与hash------------------*///按照 Map 接口的定义,比较指定 Object 与此 Map 是否相等。public synchronized boolean equals(Object o) { if (o == this) return true; if (!(o instanceof Map)) return false; Map<K,V> t = (Map<K,V>) 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; }//按照 Map 接口的定义,返回此 Map 的哈希码值。public synchronized int hashCode() { int h = 0;//若HashTable的实际大小为0或者加载因子<0,则返回0 if (count == 0 || loadFactor < 0) return h; // Returns zero loadFactor = -loadFactor; // 使hashCode在程序中可计算(此处不懂为什么这样做) Entry[] tab = table;//返回“HashTable中的每个Entry的key和value的异或值的总和” for (Entry<K,V> entry : tab) while (entry != null) { h += entry.hashCode(); entry = entry.next; } loadFactor = -loadFactor; // 使hashCode在程序中计算完成 return h; }// java.io.Serializable的写入函数 // 将Hashtable的“总的容量,实际容量,所有的Entry”都写入到输出流中 private void writeObject(java.io.ObjectOutputStream s) throws IOException { Entry<K, V> entryStack = null; synchronized (this) { // Write out the length, threshold, loadfactor s.defaultWriteObject(); // Write out length, count of elements s.writeInt(table.length); s.writeInt(count); // Stack copies of the entries in the table for (int index = 0; index < table.length; index++) { Entry<K,V> entry = table[index]; while (entry != null) { entryStack = new Entry<>(0, entry.key, entry.value, entryStack); entry = entry.next; } } } // Write out the key/value objects from the stacked entries while (entryStack != null) { s.writeObject(entryStack.key); s.writeObject(entryStack.value); entryStack = entryStack.next; } }// java.io.Serializable的读取函数:根据写入方式读出 // 将Hashtable的“总的容量,实际容量,所有的Entry”依次读出 private void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException { // Read in the length, threshold, and loadfactor s.defaultReadObject(); // Read the original length of the array and number of elements int origlength = s.readInt(); int elements = s.readInt(); // Compute new size with a bit of room 5% to grow but // no larger than the original size. Make the length // odd if it's large enough, this helps distribute the entries. // Guard against the length ending up zero, that's not valid. int length = (int)(elements * loadFactor) + (elements / 20) + 3; if (length > elements && (length & 1) == 0) length--; if (origlength > 0 && length > origlength) length = origlength; Entry<K,V>[] newTable = new Entry[length]; threshold = (int) Math.min(length * loadFactor, MAX_ARRAY_SIZE + 1); count = 0; initHashSeedAsNeeded(length); // Read the number of elements and then all the key/value objects for (; elements > 0; elements--) { K key = (K)s.readObject(); V value = (V)s.readObject(); // synch could be eliminated for performance reconstitutionPut(newTable, key, value); } this.table = newTable; }private void reconstitutionPut(Entry<K,V>[] tab, K key, V value) throws StreamCorruptedException { if (value == null) { throw new java.io.StreamCorruptedException(); } // Makes sure the key is not already in the hashtable. // This should not happen in deserialized version. int hash = hash(key); int index = (hash & 0x7FFFFFFF) % tab.length; for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { throw new java.io.StreamCorruptedException(); } } // Creates the new entry. Entry<K,V> e = tab[index]; tab[index] = new Entry<>(hash, key, value, e); count++; }//枚举型迭代器(主要是keys() ,elements()两个函数调用)//非线程安全的(除了该类的remove())private class Enumerator<T> implements Enumeration<T>, Iterator<T> { Entry[] table = Hashtable.this.table; int index = table.length; Entry<K,V> entry = null; Entry<K,V> lastReturned = null; int type; boolean iterator; protected int expectedModCount = modCount;/*----------实现Enumeration接口的方法----------*/ Enumerator(int type, boolean iterator) { this.type = type; this.iterator = iterator; } public boolean hasMoreElements() { Entry<K,V> e = entry; int i = index; Entry[] t = table; /* 在本地实现迭代器,速度更快 *///此处循环遍历是按照数组table索引从后向前遍历,找不为null的值 while (e == null && i > 0) { e = t[--i]; } entry = e; index = i; return e != null; } public T nextElement() { Entry<K,V> et = entry; int i = index; Entry[] t = table; /* 在本地实现迭代器,速度更快 *///此处循环遍历是按照数组table索引从后向前遍历,找不为null的值 while (et == null && i > 0) { et = t[--i]; } entry = et; index = i; if (et != null) { Entry<K,V> 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接口的方法----------*/ 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; for (Entry<K,V> e = tab[index], prev = null; e != null; prev = e, e = e.next) { if (e == lastReturned) { modCount++; expectedModCount++; if (prev == null)//如果当前entry是表头 tab[index] = e.next; else//如果当前entry不是表头 prev.next = e.next; count--; lastReturned = null; return; } } throw new ConcurrentModificationException(); } } }
Hashtable 的迭代
hashtable遍历有两种方式:
1、返回以哈希表的枚举方式;
①keys()
返回此哈希表中的键的枚举。
②elements()
返回此哈希表中的值的枚举。
2、返回以哈希表的Set方式;
①keySet()
返回此映射中包含的键的
Set
视图。
②values()
返回此映射中包含的键的
Collection
视图。
③entrySet()
返回此映射中包含的键的
Set
视图。
详细看代码:
package wn.comeOn.java.test;import java.util.Enumeration;import java.util.Hashtable;import java.util.Iterator;public class Test{public static void main(String[] args) { //初始化HashtableHashtable<Integer , Integer> tab = init();//迭代以哈希表的枚举方式;System.out.println("-------------枚举方式:-------------");keysHashtable(tab);elementsHashtable(tab);//迭代以哈希表的Set方式;System.out.println("-------------Set方式:-------------");keySetHashtable(tab);valuesHashtable(tab);entrySetHashtable(tab); }//初始化private static Hashtable<Integer, Integer> init() {Hashtable<Integer, Integer> table = new Hashtable<>();for(int i=0; i<1000000; i++){table.put(i, i);}return table;}//枚举:keys()遍历keyprivate static void keysHashtable(Hashtable<Integer, Integer> tab) {long start = System.currentTimeMillis();Enumeration<Integer> iterator = tab.keys();while(iterator.hasMoreElements()){iterator.nextElement();}long end = System.currentTimeMillis();System.out.println("枚举:keys()遍历key:" + (end-start));}//枚举:elements()遍历valueprivate static void elementsHashtable(Hashtable<Integer, Integer> tab) {long start = System.currentTimeMillis();Enumeration<Integer> iterator = tab.elements();while(iterator.hasMoreElements()){iterator.nextElement();}long end = System.currentTimeMillis();System.out.println("枚举:elements()遍历value:" + (end-start));}//Set:keySet()遍历keyprivate static void keySetHashtable(Hashtable<Integer, Integer> tab) {long start = System.currentTimeMillis();Iterator iterator = tab.keySet().iterator();while(iterator.hasNext()){iterator.next();}long end = System.currentTimeMillis();System.out.println("Set:keySet()遍历key:" + (end-start));}//Collection:values()遍历valueprivate static void valuesHashtable(Hashtable<Integer, Integer> tab) {long start = System.currentTimeMillis();Iterator iterator = tab.values().iterator();while(iterator.hasNext()){iterator.next();}long end = System.currentTimeMillis();System.out.println("Collection:values()遍历value:" + (end-start));}//Set:entrySet()遍历entryprivate static void entrySetHashtable(Hashtable<Integer, Integer> tab) {long start = System.currentTimeMillis();Iterator iterator = tab.entrySet().iterator();while(iterator.hasNext()){iterator.next();}long end = System.currentTimeMillis();System.out.println("Set:entrySet()遍历entry:" + (end-start));}}输出结果:
-------------枚举方式:-------------枚举:keys()遍历key:23枚举:elements()遍历value:13-------------Set方式:-------------Set:keySet()遍历key:15Collection:values()遍历value:14Set:entrySet()遍历entry:15
由代码可知,总体是这样:
枚举的keys() 慢于 Set的keySet();
枚举的elements() 与 Collection的values() 遍历快慢取决于数据量
这是几组数据测试,代码还是上面的代码,只是更改了数据总量:
- java源码分析之集合框架HashTable 11
- Java集合框架之Map--Hashtable和Properties源码分析
- java集合框架09——HashTable和源码分析
- Java 集合框架源码分析(六)——HashTable
- Java集合框架08--Hashtable和源码分析
- 《Java源码解析》集合框架Map之HashTable
- 深入集合框架之Hashtable源码剖析
- Java集合框架源码分析之ArrayList
- Java集合框架源码分析之LinkedList
- java之集合框架源码分析
- Java 集合系列11之 Hashtable源码解析
- Java集合之Hashtable源码解析
- 【Java集合类源码分析】Hashtable源码分析
- java集合11--HashTable源码详解
- java集合11--HashTable源码详解
- java 集合框架之LinkedList及ListIterator实现源码分析
- java核心之集合框架——HashMap源码分析
- java核心之集合框架——ArrayList源码分析
- List<Object>根据Object里的2个属性排序
- 第四周项目4-建设双链表算法库
- 事物
- php重写函数
- 第四周项目3—单链表的应用(3)
- java源码分析之集合框架HashTable 11
- 用Spring Boot & Cloud,Angular2快速搭建微服务web应用 - 增加代理服务器
- 关于websocket和socket
- 第4周项目5-循环双链表应用
- Android 对5.0+的外置SD卡删除操作
- Windows 下计划任务 PHP示例代码
- 【codeforces 500C 】
- 微信小程序开发系列(2)----Hello 小程序 分析篇(上)
- Java junit测试模块