标签:style class blog code java http
http://blog.csdn.net/czh0766/article/details/5260360
昨天看了算法导论对散列表的介绍,今天看了一下Hashtable, HashMap这两个类的源代码,并参考了网上的一些观点,对它们的实现有了大概的理解。原来hashtable里的key-value还是用数组存储的,数组元素是Entry<K,V>类型,同一数组索引下储存的实质是一个Entry链表,Entry中的next值指向下一个Entry.当把key-value放进hashtable时,会根据key的hashcode值来计算应储存的数组索引,根据这一索引寻找Entry链表中是否存在相同key值的entry, 如果有就把该entry里的value代替,否则生成新的entry存储key-value, 并把它放置在链表头。若果entry的数量超出hashtable的容量,hashtable会生成新的更大容量的数组并重新计算原有的entry的位置。
Hashtable和HashMap的主要区别在于Hashtable对数据的操作是线程安全的,但会有一定的额外开销;它们根据key的hashcode计算方法也不同;HashMap的key可以是null, 存储在内部数组的第一个位置里。
在hashtable和hashmap是java里面常见的容器类,
是Java.uitl包下面的类,
那么Hashtable和Hashmap是怎么实现hash键值对配对的呢,我们看看jdk里面的源码,分析下Hashtable的构造方法,put(K, V)加入方法和get(Object)方法就大概明白了。
一、Hashtable的构造方法:Hashtable(int initialCapacity, float loadFactor)
public Hashtable(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal Load: "+loadFactor);if (initialCapacity==0)
initialCapacity = 1;
this.loadFactor = loadFactor;
table = new Entry[initialCapacity];
threshold = (int)(initialCapacity * loadFactor);
}
这个里面米内有什么好说的,要注意的是table一个是实体数组,输入的initialCapacity表示这个数组的大小,而threshold 是一个int值,其中loadFactor默认是0.75,就是说明,当table里面的值到75%的阀值后,快要填满数组了,就会自动双倍扩大数字容 量。
而Entry<K,V> 来自与
private static class Entry<K,V> implements Map.Entry<K,V> {
int hash;
K key;
V value;
Entry<K,V> next;
是一个单项链表,
上图就是Hashtable的表,
二、put(K, V)加入方法
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<K,V> e = tab[index] ; e != null ; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
V ld = 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<K,V> e = tab[index];
tab[index] = new Entry<K,V>(hash, key, value, e);
count++;
return null;
}
这个看看起来很长,只要注意三点就可以了,
1.index,index是键值的hashcode和0x7FFFFFFF的&运算,然后根据数组长度求余值。这样可以定出所在队列名称,
2、
for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
V ld = e.value;
e.value = value;
return old;
}
}
for语句里面是让e在tab某个队列名为index单项链表里面遍历,第几个单项链表的定义由index定义,看看该队列是否已经有同样的值,如果有,就返回该值。
3、如果没有,则加入
Entry<K,V> e = tab[index];
tab[index] = new Entry<K,V>(hash, key, value, e);
三、get(Object),获得
public synchronized V get(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 e.value;
}
}
return null;
}
这个就很好理解了 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 e.value;
}
}
在该队里面遍历,根据hash值获得具体值。
总结下,一个是根据index确定队列,在由hash值获得具体元素值。
看完了hashtable, 我们在来看看hashMap
hashMap可以算作是hashtable的升级版本, 最早从1.2开始有的.
但是, 两者之间最主要的不同有两点.
1. hashMap的读写是unsynchronized, 在多线程的环境中要注意使用
而hashtable是synchronized
这两者的不同是通过在读写方法上加synchronized关键字来实现的.
第二个不同是hashMap可以放空值, 而hashtable就会报错.
Hashtable,HashMap实现原理,布布扣,bubuko.com
标签:style class blog code java http
原文地址:http://www.cnblogs.com/DjangoBlog/p/3795578.html