• Java Hashtable 源码(JDK8)


    记录了HashMap也来看看Hashtable吧,最近打算换份实习,所以想看看书回顾一下,不然就快记不得了.....囧啊囧啊,记性太差怎么破???

    Hashtable里面的一些变量:

    Entry<?,?>[] table : HashTable采用"拉链法"实现哈希表,每一个Entry代表了一个键值对(key-value)。

    transient int count:hashtable里面键值对的个数;

    private int threshold:hashtable的阀值(threshols = capacity * loadFactor);

    float loadFactor:加载因子;

    transient int modCount :hashtable被修改的次数,用来实现fast-fail机制。fast-fail机制就是在并发集合中,其进行迭代操作时,若有其他线程对其进行结构性的修改,这时迭代器会立马感知到,并且立即抛出              ConcurrentModificationException异常。

    Hashtable的定义如下:

    1 public class Hashtable<K,V>
    2     extends Dictionary<K,V>
    3     implements Map<K,V>, Cloneable, java.io.Serializable {
    4     ...
    5 }

    可以看出Hashtable实现了Map接口,同时继承了Dictionary类。Map接口是将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。Dictionary 类是任何可将键映射到相应值的类(如 Hashtable)的抽象父类。每个键和每个值都是一个对象。在任何一个 Dictionary 对象中,每个键至多与一个值相关联。给定一个 Dictionary 和一个键,就可以查找所关联的元素。任何非 null 对象都可以用作键或值。

    看看Hashtable常用的构造函数的实现:

    默认的构造函数:容量为11,加载因子为0.75

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

    用指定的初始容量和默认的加载因子构造:

    1 public Hashtable(int initialCapacity) {
    2         this(initialCapacity, 0.75f);
    3     }

    用指定的初始容量和指定的加载因子构造:

     1  public Hashtable(int initialCapacity, float loadFactor) {
     2              // 参数合法性验证
     3             if (initialCapacity < 0)
     4                 throw new IllegalArgumentException("Illegal Capacity: "+
     5                                                    initialCapacity);
     6             if (loadFactor <= 0 || Float.isNaN(loadFactor))
     7                 throw new IllegalArgumentException("Illegal Load: "+loadFactor);
     8             
     9             if (initialCapacity==0)
    10                 initialCapacity = 1;
    11             this.loadFactor = loadFactor;
    12             //用指定容量初始化table数组
    13             table = new Entry<?,?>[initialCapacity];
    14             //计算table的阀值
    15             threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
    16         }

    再来看看Put方法和get方法:

      首先是put方法,put方法的整个处理流程是:计算key的hash值,根据hash值获得key在table数组中的索引位置,然后迭代该key处的Entry链表(我们暂且理解为链表),若该链表中存在一个这个的key对象,那么就直接替换其value值即可,否则在将改key-value节点插入该index索引位置处。注意,hashtable是不允许null值的。

    int index = (hash & 0x7FFFFFFF) % tab.length——>键的hash值可能为负数,通过一个“与”操作,先将hash值都转化正数,然后将得到的hash值与Hashtable的长度求余

     1  //同步实现
     2      public synchronized V put(K key, V value) {
     3             // check value值是否为null
     4             if (value == null) {
     5                 throw new NullPointerException();
     6             }
     7 
     8             // Makes sure the key is not already in the hashtable.
     9             Entry<?,?> tab[] = table;
    10             //计算key的hash值
    11             int hash = key.hashCode();
    12             //通过hash值来计算在table数组中的下表
    13             int index = (hash & 0x7FFFFFFF) % tab.length;
    14             @SuppressWarnings("unchecked")
    15             Entry<K,V> entry = (Entry<K,V>)tab[index];
    16             //遍历,寻找该key,找到则替换旧值
    17             for(; entry != null ; entry = entry.next) {
    18                 if ((entry.hash == hash) && entry.key.equals(key)) {
    19                     V old = entry.value;
    20                     entry.value = value;
    21                     return old;
    22                 }
    23             }
    24             //没有找到,则将该key加入
    25             addEntry(hash, key, value, index);
    26             return null;
    27         }
    28          private void addEntry(int hash, K key, V value, int index) {
    29                  //修改链表,modCount自增
    30                 modCount++;
    31     
    32                 Entry<?,?> tab[] = table;
    33                 if (count >= threshold) {
    34                     // Rehash the table if the threshold is exceeded
    35                     rehash();
    36                     tab = table;
    37                     hash = key.hashCode();
    38                     index = (hash & 0x7FFFFFFF) % tab.length;
    39                 }
    40     
    41                 // Creates the new entry.
    42                 @SuppressWarnings("unchecked")
    43                 Entry<K,V> e = (Entry<K,V>) tab[index];
    44                 tab[index] = new Entry<>(hash, key, value, e);
    45                 count++;
    46         }

    get方法也是同步的,具体的实现如下:

     1  public synchronized V get(Object key) {
     2             Entry<?,?> tab[] = table;
     3             //计算key的hash值
     4             int hash = key.hashCode();
     5             //通过hash值来计算在table数组中的下表
     6             int index = (hash & 0x7FFFFFFF) % tab.length;
     7             //遍历查找key,找到则返回key值所对应的的value
     8             for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
     9                 if ((e.hash == hash) && e.key.equals(key)) {
    10                     return (V)e.value;
    11                 }
    12             }
    13             return null;
    14         }
  • 相关阅读:
    多态问题----针对方法
    画了个Android——Canvas类的使用(转)
    设计模式之策略模式
    Listview多种布局的使用
    Activity的退出和進入效果
    java.lang.ClassNotFoundException
    台球小游戏
    线性表
    堆栈
    动态内存管理
  • 原文地址:https://www.cnblogs.com/hfczgo/p/4036659.html
Copyright © 2020-2023  润新知