尽信书不如无书,我今天在看网上的一些资料的时候发现一遍篇《HashMap和Hashtable的区别》的文章,随手就在Eclipse里实验了一下,结果发现很多原来文章中的错误,现在把这个问题修改好以后贴在这里,希望对大家的学习也有帮助。
HashMap
和Hashtable的区别。
错误说法:
<!--[if !supportLists]-->
1.
<!--[endif]-->
HashTable
不允许
null
值
(key
和
value
都不可以
),HashMap
允许
null
值
(key
和
value
都可以
)
。
这句话容易让人误会,到底是怎么个不允许法呢?其实在编译期不会有任何的不一样,会照样执行,只是在运行期的时候 Hashtable 中设置的话回出现空指针异常
这句话容易让人误会,到底是怎么个不允许法呢?其实在编译期不会有任何的不一样,会照样执行,只是在运行期的时候 Hashtable 中设置的话回出现空指针异常
<!--[if !supportLists]-->
2.
<!--[endif]-->
在
HashMap
中,
null
可以作为键,这样的键只有一个;
可以有一个或多个键所对应的值为null
。当get()
方法返回null
值时,即可以表示 HashMap
中没有该键,也可以表示该键所对应的值为null
。因此,在HashMap
中不能由get()
方法来判断HashMap
中是否存在某个键,
而应该用containsKey()
方法来判断。
不用多说,看下面的程序就可以:
HashMap map =
new
HashMap();
map.put(
"Null"
,
null
);
map.put(
null
,
"Null"
);
map.put(
null
,
"Empty"
);
System.
out
.println(map.get(
null
));
System.
out
.println(map.get(
"Null"
));
System.
out
.println(map.get(
"NullThere"
));
System.
out
.println(map.
containsKey
(
"Null"
));
System.
out
.println(map.
containsKey
(
"NullThere"
));
输出结果为:
Empty
null
null
true
false
<!--[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
进行同步
MapCollections.synchronizedMap(Mapm)
|
已经同步过的可以安全使用
|
对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
);
}
|
protected
void
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
值,而且用与代替求模
public
boolean
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))
return
true
;
e = e.next;
}
return
false
;
}
|
HashTable
直接使用对象的
hashCode
,代码是这样的:
public
synchronized
boolean
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
;
}
|