不同点:
1. HashMap允许空(null)键值(key),Hashtable不行
HashMap map = new HashMap(); //HashMap
map.put("a", null);
map.put(null, "b");
map.put(null, null); //编译运行,都可以
Hashtable table = new Hashtable(); //HashTable
table.put("a", null); //编译正常,运行时空指针异常,键或值都不能为空
table.put(null, "123"); //同上
2. HashMap把Hashtable的contains方法去掉了。也有 containsvalue和containsKey方法
map.containsValue(""); //查询是否有值为""的数据
map.containsKey(""); //查询键
table.contains(""); //查询值,和下面的重复,容易造成误解,所以HashMap去掉了
table.containsValue(""); //查询值
table.containsKey(""); //查询键 都返回false或true
3. 历史原因:Hashtable是基于陈旧的Dictionary类的,HashMap是Java 1.2引进的Map接口的一个实现
Hashtable是Dictionary的子类,HashMap是Map接口的一个实现类
HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable
Hashtable<K,V> extends Dictionary<K,V>
implements Map<K,V>, Cloneable, Serializable
4. 最大的不同是,Hashtable的方法是Synchronize的,而HashMap不是,在多个线程访问Hashtable时,不需要自己为它的方法实现同步,而HashMap 就必须为之提供外同步。
Map m = Collections.synchronizedMap(new HashMap()); //HashMap同步的方法,使在多线程中也安全
(这个方法返回一个同步的Map,这个Map封装了底层的HashMap的所有方法)
(线程同步,安全;线程不同步,不安全)
<!--[if !vml]-->
<!--[endif]--> |
HashMap
|
Hashtable
|
继承,实现
|
HashMap
<K,V>
extends
AbstractMap<K,V>
implements
Map<K,V>, Cloneable, Serializable
|
Hashtable
<K,V>
extends
Dictionary<K,V>
implements
Map<K,V>, Cloneable,Serializable
|
多线程,同步
|
未同步的,可以使用
Colletcions
进行同步
Map Collections.synchronizedMap(Map m)
|
已经同步过的可以安全使用
|
对null的处理
|
HashMap map =
new
HashMap();
map.put(
null
,
"Null"
);
map.put(
"Null"
,
null
);
map.containsKey(
null
);
map.containsValue(
null
);
以上这
5
条语句无论在编译期,还是在运行期都是没有错误的
.
在HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。当get()方法返回null值时,即可以表示 HashMap中没有该键,也可以表示该键所对应的值为null。因此,在HashMap中不能由get()方法来判断HashMap中是否存在某个键, 而应该用containsKey()方法来判断。
|
Hashtable table = new Hashtable();
table.put(null, "Null");
table.put("Null", null);
table.contains(null);
table.containsKey(null);
table.containsValue(null);
后面的
5
句话在编译的时候不会有异常,可在运行的时候会报空指针异常
具体原因可以查看源代码
public synchronized V put(K key, V value) {
// Make sure the value is not null
if (value == null) {
throw new NullPointerException();
}
………….
|
增长率
|
void
addEntry(
int
hash, K key, V value,
int
bucketIndex) {
Entry<K,V> e =
table
[bucketIndex];
table
[bucketIndex] =
new
Entry<K,V>(hash, key, value, e);
if
(
size
++ >=
threshold
)
resize(2 *
table
.
length
);
}
|
protectedvoid
rehash() {
int
oldCapacity =
table
.
length
;
Entry[] oldMap =
table
;
int
newCapacity = oldCapacity * 2 + 1;
Entry[] newMap =
new
Entry[newCapacity];
modCount
++;
threshold
= (
int
)(newCapacity *
loadFactor
);
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
;
int
index = (e.
hash
& 0x7FFFFFFF) % newCapacity;
e.
next
= newMap[index];
newMap[index] = e;
}
}
}
|
哈希值的使用
|
HashMap
重新计算
hash
值,而且用与代替求模
publicboolean
containsKey(Object key) {
Object k = maskNull(key);
int
hash = hash(k.hashCode());
int
i = indexFor(hash, table.length);
Entry e = table[i];
while
(e !=
null
) {
if
(e.hash == hash && eq(k, e.key))
returntrue
;
e = e.next;
}
return false
;
}
|
HashTable
直接使用对象的
hashCode
,代码是这样的:
publicsynchronizedboolean
containsKey(Object key) {
Entry tab[] =
table
;
int
hash = key.hashCode();
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
;
}
|