暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

HashTable

为自己加点料 2019-04-08
171

HashTable

1.put

  1. public synchronized V put(K key, V value) {

  2. // Make sure the value is not null

  3. if (value == null) {

  4. throw new NullPointerException();

  5. }

  6. // Makes sure the key is not already in the hashtable.

  7. Entry<?,?> tab[] = table;

  8. int hash = key.hashCode();

  9. int index = (hash & 0x7FFFFFFF) % tab.length;

  10. @SuppressWarnings("unchecked")

  11. Entry<K,V> entry = (Entry<K,V>)tab[index];

  12. for(; entry != null ; entry = entry.next) {

  13. if ((entry.hash == hash) && entry.key.equals(key)) {

  14. V old = entry.value;

  15. entry.value = value;

  16. return old;

  17. }

  18. }

  19. addEntry(hash, key, value, index);

  20. return null;

  21. }

  • put是被synchronize修饰的方法,所以是线程安全的。

当第一次使用时,会根据key创建一个entry,并放在对象数组table中,结构如下

并且next执行空。

当第二次put时,

  • 如果经计算后hash值不同,会从新生成一个entry并放在数组table中,结构如下

  • 如经计算后hash相同而key值不相同。 会获取table中hash值相同的entry,假设table[1];然后创建一个新的entry,并让新的entry中的next指向table[1],再把table[1]指向新创建的entry。相当于新的entry把原来的entry顶出数组。结构如下


2.get

  1. public synchronized V get(Object key) {

  2. Entry<?,?> tab[] = table;

  3. int hash = key.hashCode();

  4. int index = (hash & 0x7FFFFFFF) % tab.length;

  5. for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {

  6. if ((e.hash == hash) && e.key.equals(key)) {

  7. return (V)e.value;

  8. }

  9. }

  10. return null;

  11. }

  • 0x7FFFFFFF
    为16进制4个字节的1,最后一位为符号为所以是7。即0111 1111 1111 1111 1111 1111 1111 1111

  • &
     与运算 当同为1时,才为1。在这里是为了防止hash值为负数。不用绝对值函数的原因是最大负数没有正数。

通过for循环遍历列表,找到则返回。

重要提示
:put和get都是用 synchronized
关键字来解决并发问题。

3.rehash

当put时,会判断entry个数是否超出了负载因子,如果超出进行rehash操作。

  1. if (count >= threshold) {

  2. // Rehash the table if the threshold is exceeded

  3. rehash();

  4. tab = table;

  5. hash = key.hashCode();

  6. index = (hash & 0x7FFFFFFF) % tab.length;

  7. }

  • rehash()

  1. protected void rehash() {

  2. int oldCapacity = table.length;

  3. Entry<?,?>[] oldMap = table;

  4. // overflow-conscious code

  5. int newCapacity = (oldCapacity << 1) + 1;

  6. if (newCapacity - MAX_ARRAY_SIZE > 0) {

  7. if (oldCapacity == MAX_ARRAY_SIZE)

  8. // Keep running with MAX_ARRAY_SIZE buckets

  9. return;

  10. newCapacity = MAX_ARRAY_SIZE;

  11. }

  12. Entry<?,?>[] newMap = new Entry<?,?>[newCapacity];

  13. modCount++;

  14. threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);

  15. table = newMap;

  16. for (int i = oldCapacity ; i-- > 0 ;) {

  17. for (Entry<K,V> old = (Entry<K,V>)oldMap[i] ; old != null ; ) {

  18. Entry<K,V> e = old;

  19. old = old.next;

  20. int index = (e.hash & 0x7FFFFFFF) % newCapacity;

  21. e.next = (Entry<K,V>)newMap[index];

  22. newMap[index] = e;

  23. }

  24. }

  25. }

  • intnewCapacity=(oldCapacity<<1)+1;
     扩大两倍加一。加一是为了防止一直为0的现象。

  • 如果超过最大值,则使用最大值做为 newCapacity

  • 通过遍历把old entry重新排序。


文章转载自为自己加点料,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论