public class HashTable
extends Dictionary
implements Map, Cloneable, java.io.Serializable
继承自Dictionary,Dictionary是一个抽象父类,功能和Map一样,但过时了,官方推荐用实现Map接口来取代。
HashTable键(key)和值(value)均不能为null。
/**
* 将key和value加入到map中,明显标明,
* value不能为null。如果key为null,则会报nullPointer异常 */
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 = key.hashCode();
//很直接的利用hashcode去除table.length,然后取长度。
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)) {
//hash相同且equals,那么就连在后面,是用链表的方式。
V old = entry.value;
entry.value = value;
return old;
}
}
//第一个,链表后面没有数据。
addEntry(hash, key, value, index);
return null;
}
关于value,明显有if判断,不能为null,
如果key为null,则也直接在计算hashCode的时候就会报空指针。
int hash = key.hashCode(); //直接用hashcode % n
int index = (hash & 0x7FFFFFFF) % tab.length;
而hashmap int index=e.hash % n ;
hash值的计算方式不同! 很直接的利用hashcode去除table.length,然后取长度。
因为HashTable中大部分方法都是加了synchronized关键字,所以同一时刻,只能有一个线程进入其方法故是线程安全的。
Java8,HashMap中,当出现冲突时,
而在HashTable中, 则都是以链表方式存储。
Java8中, HashMap:
一旦扩容,都是扩展到2的倍数,因为这样有利于计算数组索引值,即和计算数组索引结合起来。
HashTable: 一次性扩展为oldCapacity*2+1。
/**
* 一次扩展是,old*2+1
*/
@SuppressWarnings("unchecked")
protected void rehash() {
int oldCapacity = table.length;
Entry,?>[] 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,?>[] newMap = new Entry,?>[newCapacity];
modCount++;
//新的threshold值。取newCapacity*loadFactor的小值。
threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
table = newMap;
for (int i = oldCapacity ; i-- > 0 ;) {
for (Entry old = (Entry)oldMap[i] ; old != null ; ) {
Entry e = old;
old = old.next;
int index = (e.hash & 0x7FFFFFFF) % newCapacity;
e.next = (Entry)newMap[index];
newMap[index] = e;
}
}
}
先扩展,再把旧数组里面元素一个一个加到新的里面。
注意, 这里取hash不是e.hash,而仍然是key.hashCode计算保留下来的值。
参考:
https://blog.csdn.net/anla_/article/details/78298484
https://blog.csdn.net/zldeng19840111/article/details/6703104