首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

Java 容器源码分析之Map-Set-List(8)

Java 容器源码分析之Map-Set-List(8)

构造方法Hashtable 一共提供了 4 个构造方法:
[url=][/url]
public Hashtable(int initialCapacity, float loadFactor): 用指定初始容量和指定加载因子构造一个新的空哈希表。useAltHashing 为 boolean,其如果为真,则执行另一散列的字符串键,以减少由于弱哈希计算导致的哈希冲突的发生。public Hashtable(int initialCapacity):用指定初始容量和默认的加载因子 (0.75) 构造一个新的空哈希表。public Hashtable():默认构造函数,容量为 11,加载因子为 0.75public Hashtable(Map<? extends K, ? extends V> t):构造一个与给定的 Map 具有相同映射关系的新哈希表。[url=][/url]

[url=][/url]
/**     * Constructs a new, empty hashtable with the specified initial     * capacity and the specified load factor.     *     * @param      initialCapacity   the initial capacity of the hashtable.     * @param      loadFactor        the load factor of the hashtable.     * @exception  IllegalArgumentException  if the initial capacity is less     *             than zero, or if the load factor is nonpositive.     */    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)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);        useAltHashing = sun.misc.VM.isBooted() &&                (initialCapacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD);    }    /**     * Constructs a new, empty hashtable with the specified initial capacity     * and default load factor (0.75).     *     * @param     initialCapacity   the initial capacity of the hashtable.     * @exception IllegalArgumentException if the initial capacity is less     *              than zero.     */    public Hashtable(int initialCapacity) {        this(initialCapacity, 0.75f);    }    /**     * Constructs a new, empty hashtable with a default initial capacity (11)     * and load factor (0.75).     */    public Hashtable() {        this(11, 0.75f);    }    /**     * Constructs a new hashtable with the same mappings as the given     * Map.  The hashtable is created with an initial capacity sufficient to     * hold the mappings in the given Map and a default load factor (0.75).     *     * @param t the map whose mappings are to be placed in this map.     * @throws NullPointerException if the specified map is null.     * @since   1.2     */    public Hashtable(Map<? extends K, ? extends V> t) {        this(Math.max(2*t.size(), 11), 0.75f);        putAll(t);    }[url=][/url]


put 方法put 方法的整个流程为:
  • 判断 value 是否为空,为空则抛出异常;
  • 计算 key 的 hash 值,并根据 hash 值获得 key 在 table 数组中的位置 index,如果 table[index] 元素不为空,则进行迭代,如果遇到相同的 key,则直接替换,并返回旧 value;
  • 否则,我们可以将其插入到 table[index] 位置。
我在下面的代码中也进行了一些注释:
[url=][/url]
public synchronized V put(K key, V value) {        // Make sure the value is not null确保value不为null        if (value == null) {            throw new NullPointerException();        }        // Makes sure the key is not already in the hashtable.        //确保key不在hashtable中        //首先,通过hash方法计算key的哈希值,并计算得出index值,确定其在table[]中的位置        //其次,迭代index索引位置的链表,如果该位置处的链表存在相同的key,则替换value,返回旧的value        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) {            // Rehash the table if the threshold is exceeded            //如果超过阀值,就进行rehash操作            rehash();            tab = table;            hash = hash(key);            index = (hash & 0x7FFFFFFF) % tab.length;        }        // Creates the new entry.        //将值插入,返回的为null        Entry<K,V> e = tab[index];        // 创建新的Entry节点,并将新的Entry插入Hashtable的index位置,并设置e为新的Entry的下一个元素        tab[index] = new Entry<>(hash, key, value, e);        count++;        return null;    }[url=][/url]

通过一个实际的例子来演示一下这个过程:
假设我们现在Hashtable的容量为5,已经存在了(5,5),(13,13),(16,16),(17,17),(21,21)这 5 个键值对,目前他们在Hashtable中的位置如下:

现在,我们插入一个新的键值对,put(16,22),假设key=16的索引为1.但现在索引1的位置有两个Entry了,所以程序会对链表进行迭代。迭代的过程中,发现其中有一个Entry的key和我们要插入的键值对的key相同,所以现在会做的工作就是将newValue=22替换oldValue=16,然后返回oldValue=16.

然后我们现在再插入一个,put(33,33),key=33的索引为3,并且在链表中也不存在key=33的Entry,所以将该节点插入链表的第一个位置。
返回列表