集合框架源码分析(jdK1.7)(二)HashTable

目录

1.数据结构

2.主要参数

3.HashTable的核心构造方法

3.1初始化容量

3.HashTable的Put方法

3.1扩容方法rehash();

4.HashTable的get方法

5.remove方法

6.总结:


1.数据结构

HashTable的数据结构和HashMap的数据结构相同,都是有散列表构成的,内部都是由Entry<K,V>来维护的。

2.主要参数

private transient Entry<K,V>[] table;//数据结构

private transient int count;// Entry<K,V>[] table已用长度(每次创建一个Entry,count+1

private int threshold;//用于扩容比价的临界值(和已用容量进行比较)

private float loadFactor;//负载因子

private transient int modCount = 0;

static final int ALTERNATIVE_HASHING_THRESHOLD_DEFAULT = Integer.MAX_VALUE;//最大容量

 


3.HashTable的核心构造方法

public Hashtable() {
   
this(11, 0.75f);
}

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;

//初始化的时候就创建Entry类型数组table
    table = new Entry[initialCapacity];

//用于扩容的临界值(和已用容量进行比较)
    threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
   
initHashSeedAsNeeded(initialCapacity);
}

 

3.1初始化容量

Hashtable的initialCapacity(初始化容量默认11)loadFactor(负载因子0.75f);
初始化时赋值threshold的为扩展比较初始容量(0.75f*initialCapacity)和最大容量Integer.MAX_VALUE中较小的一个
(HashTable的容量不足时用于对容量扩展)

3.HashTable的Put方法

public synchronized V put(K key, V value) {
   
// Make sure the value is not null
   
if (value == null) {   //HashTable不可以存Null
        throw new NullPointerException();
   
}

    // Makes sure the key is not already in the hashtable.
   
Entry tab[] = table;
   
int hash = hash(key);
   
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 old = e.value;
           
e.value = value;
           
return old;
       
}
    }

    modCount++;
   
if (count >= threshold) { //默认空间不足容量的75%开始扩容
        // Rehash the table if the threshold is exceeded
       
rehash();
       
tab = table;
       
hash = hash(key);
        index = (hash & 0x7FFFFFFF) % tab.length;
   
}

    // Creates the new entry.
   
Entry<K,V> e = tab[index];
   
tab[index] = new Entry<>(hash, key, value, e);
   
count++;
   
return null;
}

 


HashTable中的方法都使用了关键字sychronized修饰。所以是线程安全的。

并且HashTable的不可以存NULL值

通过参数key的hash值进行(hash & 0x7FFFFFFF)% tab.length运算得到数组的位置进行添加

3.1扩容方法rehash();

//默认空间不足容量的75%开始扩容

//每次扩大到原来的容量的2

protected void rehash() {
   
int oldCapacity = table.length;//table长度
    Entry<K,V>[] oldMap = table;

   
// overflow-conscious code
   
int newCapacity = (oldCapacity << 1) + 1; //长度扩大到原来的2倍+1 最大为MAX_ARRAY_SIZE
    if (newCapacity - MAX_ARRAY_SIZE > 0) {
       
if (oldCapacity == MAX_ARRAY_SIZE)
           
// Keep running with MAX_ARRAY_SIZE buckets
           
return;
       
newCapacity = MAX_ARRAY_SIZE;
   
}
    Entry<K,V>[] newMap = new Entry[newCapacity];

   
modCount++;
   
threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
   
boolean rehash = initHashSeedAsNeeded(newCapacity);

   
table = newMap;
//for循环.外层循环桶位,内层循环链表元素,对每个元素进行重新计算在新数组中的桶位
    for (int i = oldCapacity ; i-- > 0 ;) {
       
for (Entry<K,V> old = oldMap[i] ; old != null ; ) {
           
Entry<K,V> e = old;
           
old = old.next;

           
if (rehash) {
               
e.hash = hash(e.key);  //
            }
            int index = (e.hash & 0x7FFFFFFF) % newCapacity;//计算新的桶位
            e.next = newMap[index];
           
newMap[index] = e;
        }
    }
}

 

Rehash(扩容方法)首先新建一个Entry<?,?> oldMap数组对象.

最重要的是其中的两层for循环.外层循环桶位,内层循环链表元素,对每个元素进行重新计算在新数组中的桶位.

(扩容机制是把所有元素重新计算桶位,放入新的Entry中)

int index = (e.hash & 0x7FFFFFFF) % newCapacity 由于Hash Table的桶位基于最大容量,每次扩容都要重新计算一遍桶位

 

4.HashTable的get方法

public synchronized V get(Object key) {
   
Entry tab[] = table;
   
int hash = hash(key);
   
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;
}


hashtable的寻找方式是(hash &0x7FFFFFFF)% tab.length,其实就是. hash值对table中元素个数的求模运算

5.remove方法

public synchronized V remove(Object key) {
   
Entry tab[] = table;
   
int hash = hash(key);
   
int index = (hash & 0x7FFFFFFF) % tab.length;
   
for (Entry<K,V> e = tab[index], prev = null ; e != null ; prev = e, e = e.next) {
       
if ((e.hash == hash) && e.key.equals(key)) {
           
modCount++;
           
if (prev != null) {
               
prev.next = e.next;
           
} else {
               
tab[index] = e.next;
           
}
            count--;
           
V oldValue = e.value;
           
e.value = null;
           
return oldValue;
       
}
    }
    return null;
}

 

 

这个方法也很简单.先通过hash值计算得出桶位,然后遍历桶位上的链表.从链表中remove掉目标元素.

6.总结:

1..维护Hashtable内部的是一个Entry,Hashmap的默认容量为11,负载因子为0.75,

2.扩容方式当Entry已用空间>=总空间的75%,总空间扩大到原来的2倍。(因为每次扩容都要计算桶位,这样扩容可以减少扩容次数)

3.Hashtable所有的方法都有synchronized修饰线程安全

4. Hashtable不可以存Null值,

5.HashTable的容量指的是Entry<K,V>[] table的长度

6.计算桶位的方式int index= (hash & 0x7FFFFFFF) % tab.length;

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值