public class Hashtable
extends Dictionary
implements Map, Cloneable, java.io.Serializable
public class HashMap
extends AbstractMap
implements Map, Cloneable, Serializable
有关区别可以总结如下:
首先可以看一下String类的hashCode()函数
public int hashCode() {
int h = hash;
if (h == 0 && value. length > 0) {
char val[] = value;
for ( int i = 0; i < value. length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
其主要的数学公式是: S[0]*31n-1+S[1] *31 n-2 +S[2] *31 n-3 +…+S[n-1]
举例String str="abc";
hashcode值为:a*31*31+b*31+c
注:为什么是31? 31为素数,是个神奇的数字,因为任何数n * 31都可以被JVM优化为 (n << 5) -n,移位和减法的操作效率要比乘法的操作效率高的多。
HashTable和HashMap的数据存储采用的是哈希表的结构
现摘抄HashTable的源码部分举例
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();
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry 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;
index = (hash & 0x7FFFFFFF) % tab.length;
}
// Creates the new entry.
Entry e = tab[index];
tab[index] = new Entry(hash, key, value, e);
count++;
return null;
}
其中关键点:
for (Entry 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;
}
}
其中这段代码含义:判断当前确定的索引位置是否存在相同hashcode和相同key的元素,如果存在相同的hashcode和相同的key的元素,那么新值覆盖原来的旧值,并返回旧值。
如果存在相同的hashcode,那么他们确定的索引位置就相同,这时判断他们的key是否相同,如果不相同,这时就是产生了hash冲突。
Hash冲突后,那么HashMap的单个bucket里存储的不是一个 Entry,而是一个 Entry 链。
系统只能必须按顺序遍历每个 Entry,直到找到想搜索的 Entry 为止——如果恰好要搜索的 Entry 位于该 Entry 链的最末端(该 Entry 是最早放入该 bucket 中),
那系统必须循环到最后才能找到该元素。
当put时候解决冲突:tab[index]=new Entry(hash, key, value, e);会调用函数
protected Entry(int hash, K key, V value, Entry<K,V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
系统总是将新添加的 Entry 对象放入 table 数组的 bucketIndex 索引处——如果 bucketIndex 索引处已经有了一个 Entry 对象,那新添加的 Entry 对象指向原有的 Entry 对象(产生一个 Entry 链), 如果 bucketIndex 索引处没有 Entry 对象,也就是上面程序代码的 e 变量是 null,也就是新放入的 Entry 对象的next指向 null,也就是没有产生 Entry 链。
if (count >= threshold) {
// Rehash the table if the threshold is exceeded
rehash();
tab = table;
index = (hash & 0x7FFFFFFF) % tab.length;
}
在Hashtable中的index计算方法:
private int hash(Object k) {
if (useAltHashing) {
if (k.getClass() == String.class) {
return sun.misc.Hashing.stringHash32((String) k);
} else {
int h = hashSeed ^ k.hashCode();
// This function ensures that hashCodes that differ only by
// constant multiples at each bit position have a bounded
// number of collisions (approximately 8 at default load factor).
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
} else {
return k.hashCode();
}
}
<2>hashcode%容量即可得index,具体函数为
最后附上摘自jdk中的集合类的源码:http://download.csdn.net/detail/otengyue/7704807