hashtable源码分析
2015-03-09 20:56
267 查看
虽然hashtable已经不经常用了,但是面试时候还会有很多人问道他与HashMap之间的区别,下来简单看下他和HashMap有什么区别吧~~
看看put方法:
在这里,如果count的数量大于阈值,会先rehash(),看下rehash函数:
在rehash扩展table的算法中可以看见,每次扩充为 以前的2倍+1,而hashmap中为2倍;并且hashmap要求table的长度为2的幂,而hashtable中却不需要。
hashtable中的hash算法:
这与hashmap中的hash算法也不一样~~~
并且:下面两种方法返回值Enumeration的方法,是hashmap中没有的。
此外,在遍历数据的时候,hashmap采用iterator,hashtable采用了iterator和Enumeration;
具体如下表:
其他代码可以自己参考源码~~
首先定义:
public class Hashtable<K,V> extends Dictionary<K,V> implements Map<K,V>, Cloneable, java.io.Serializable 在定义部分可以看见,<span style="color:#ff0000;">HashMap集成的AbstractMap,而HashTable继承的Dictionary的类</span>
常量定义:
<span style="white-space:pre"> </span>private transient Entry<K,V>[] table;
private transient int count;
private int threshold;
private float loadFactor;
private transient int modCount = 0;
private static final long serialVersionUID = 1421746759512286392L;
//默认的阈值
static final int ALTERNATIVE_HASHING_THRESHOLD_DEFAULT = Integer.MAX_VALUE;
在常量的定义方面,基本和HashMap大同小异
构造方法:4个
和HashMap的类型基本一样。除了名字不一样~~~除了无参的构造默认大小为11,hashmap为16.
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);
}
常见方法:常见的方法里面,hashtable所有的普通方法都加了synchronized关键字,说明它是线程安全的,而hashmap是现成不安全的。
看看put方法: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 = 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)) { V old = e.value; e.value = value; return old; } } modCount++; if (count >= threshold) { // Rehash the table if the threshold is exceeded rehash(); tab = table; hash = hash(key); index = (hash & 0x7FFFFFFF) % tab.length; } // Creates the new entry. Entry<K,V> e = tab[index]; tab[index] = new Entry<>(hash, key, value, e); count++; return null; }这里和HashMap明显有区别的地方在与如何放入hashtable中的元素value为null,则会抛出异常,而hashmap则不会
在这里,如果count的数量大于阈值,会先rehash(),看下rehash函数:
protected void rehash() { int oldCapacity = table.length; Entry<K,V>[] 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<K,V>[] newMap = new Entry[newCapacity]; modCount++; threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1); 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; } } }
在rehash扩展table的算法中可以看见,每次扩充为 以前的2倍+1,而hashmap中为2倍;并且hashmap要求table的长度为2的幂,而hashtable中却不需要。
hashtable中的hash算法:
private int hash(Object k) { // hashSeed will be zero if alternative hashing is disabled. return hashSeed ^ k.hashCode(); }
这与hashmap中的hash算法也不一样~~~
并且:下面两种方法返回值Enumeration的方法,是hashmap中没有的。
public synchronized Enumeration<K> keys() { return this.<K>getEnumeration(KEYS); }
public synchronized Enumeration<V> elements() { return this.<V>getEnumeration(VALUES); }
此外,在遍历数据的时候,hashmap采用iterator,hashtable采用了iterator和Enumeration;
具体如下表:
HashMap | Hashtable | |
出现时间 | JDK1.2,所以代码质量更高,更容易明白 | JDK1.0 |
并发控制 | 没有考虑并发 | 所有方法都加了synchronized,即使有些我认为不需要的也加了 |
是否接受值为null的Key 或Value | 接受 | 不接收。put等方法里面:if (value == null) { 显示throw new NullPointerException(); };int hash=key.hashcode隐示throw NullPointerException(); |
初始化table | 缺省容量16。初始化时可以指定initial capacity,若不是2的次方,HashMap将选取第一个大于initial capacity 的2的次方值作为其初始长度 | 缺省容量11。初始化时可以指定initial capacity |
扩容 | 添加Entry后判断是否该扩容。扩容至2*oldCapacity | 先判断是否扩容再添加Entry。扩容至2*oldCapacity + 1 |
数据遍历的方式 | Iterator | Iterator 和 Enumeration |
是否支持fast-fail | 支持fast-fail | 用Iterator遍历,支持fast-fail 用Enumeration不支持fast-fail. |
hash算法和index算法 | 优于Hashtable,通过对Key的hash做移位运算和位的与运算,使其能更广泛地分散到数组的不同位置 | 当数组长度较小,并且Key的hash值低位数值分散不均匀时,不同的hash值计算得到相同下标值的几率较高 |
实现和继承 | extends AbstractMap 骨架结构的体现,代码质量上去了 | extends Dictionary implements Map 直接实现Map接口。多基础了一个已过时的经Dictionary类,就不用去管了 |
相关文章推荐
- memcached源码分析之hashtable
- memcached源码分析之hashtable
- Java集合:Hashtable使用详解及源码分析
- Java集合框架之Map--Hashtable源码分析
- 史上最详细的Hashtable详解--源码分析
- HashTable & HashSet 源码分析
- HashMap与HashTable的区别(源码分析),不喜欢背概念
- jdk源码分析之HashTable
- 源码分析—HashMap、HashSet、HashTable
- HashTable 和 HashSet 的源码分析
- PHP源码分析之HashTable
- Linux c 开发 - Memcached源码分析之HashTable(4)
- STL源码分析之hashtable
- java 并发 ConcurrentHashMap 与 HashTable源码分析总结
- HashMap HashTable ConcurrentHashMap key和value是否可以null的问题 源码分析
- Hashtable 源码分析
- [Java] Hashtable 源码简要分析
- 源码分析四(HashMap与HashTable的区别 )
- Java-HashTable源码分析
- 源码分析——HashMap和HashTable区别