一、父类不一样
HashMap父类为AbstractMap
public class HashMap<K,V> extends AbstractMap<K,V>
Hashtable父类为Dictionary
public class Hashtable<K,V> extends Dictionary<K,V>
两者实现的接口一致
implements Map<K,V>, Cloneable, Serializable
二、Hashtable是线程安全的,同步的,HashMap不是
以下为截取的一部分Hashtable源码
/**
* Returns the number of keys in this hashtable.
*
* @return the number of keys in this hashtable.
*/
public synchronized int size() {
return count;
}
/**
* Tests if this hashtable maps no keys to values.
*
* @return true
if this hashtable maps no keys to values;
* false
otherwise.
*/
public synchronized boolean isEmpty() {
return count == 0;
}
/**
* Returns an enumeration of the keys in this hashtable.
*
* @return an enumeration of the keys in this hashtable.
* @see Enumeration
* @see #elements()
* @see #keySet()
* @see Map
*/
public synchronized Enumeration keys() {
return this.getEnumeration(KEYS);
}
可以看到,有很多方法都加了synchronized关键字。
以下为截取的一部分HashMap源码
/**
* Returns the number of key-value mappings in this map.
*
* @return the number of key-value mappings in this map
*/
public int size() {
return size;
}
/**
* Returns true if this map contains no key-value mappings.
*
* @return true if this map contains no key-value mappings
*/
public boolean isEmpty() {
return size == 0;
}
然而同步不可避免的是性能会有所下降,所以一般还是用HashMap比较多。
三、Hashtable不允许键值为null,而HashMap则允许
以下为Hashtable的put方法的源码
public synchronized V put(K key, V value) {
if (value == null) {
throw new NullPointerException();
}
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;
}
可以看到,value为null时显式地抛出了NullPointerException异常,而若key为null,执行到key.hashCode()这一句时也会出现NullPointerException异常。
以下为HashMap的put方法的源码
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node[] tab; Node p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
Node e; K k;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
else if (p instanceof TreeNode)
e = ((TreeNode)p).putTreeVal(this, tab, hash, key, value);
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1)
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) {
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
可以看到在调用putVal传参时将key传入hash方法中
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
若key为null,hash方法返回0,不会抛出异常
代码中也没有显式判断value是否为null或者试图调用value的方法,所以value为null也是允许的。
所以,使用HashMap如果想要判断某个key是否存在应该使用containsKey方法而不是通过使用get方法并判断返回是否null来判断某个key是否存在,因为key不存在时与key存在而value为null时返回的值都为null。
其它的内部实现的不同(比如从上面代码可以看出的,在Hashtable中key的哈希值就是key的hashCode,而HashMap还进行了一定的处理)并不影响对HashMap和Hashtable的使用,因此不在此列出,有兴趣的可以看看两者的源码。
有错误的地方望指出,谢谢!
欢迎转载,但请附上原地址http://blog.csdn.net/jiaxingzheng/article/details/48752639,谢谢!