`
wu.sheng
  • 浏览: 65817 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

jdk6标准类库源码解读 之 数据结构 (三) HashMap<K,V>

阅读更多

HashMap<K,V>

  • 此哈希表采用数组+单向链表的方式进行存储。数组中的每个元素,对应哈希算法下的一个哈希值。哈希值重复时,采用链表处理。
    /**
     * The table, resized as necessary. Length MUST Always be a power of two.
     */
    transient Entry[] table;

    /**
     * The number of key-value mappings contained in this map.
     */
    transient int size;

    static class Entry<K, V> implements Map.Entry<K, V> {
        final K key;

        V value;

        Entry<K, V> next;

        final int hash;
    }
  •  哈希算法基于key的hashCode的返回值进行运算。通过hash和indexFor两个函数运算,得到table数组中的索引序号。
    //获取table数组的索引序号i
    int hash = hash(key.hashCode());
    int i = indexFor(hash, table.length);

    static int hash(int h) {
        h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);
    }

    static int indexFor(int h, int length) {
        return h & (length - 1);
    }
  •  哈希表存储新元素,put方法,先根据hashCode计算索引序号。首先判断当前hash值有没有存在的对象,有则进行重复处理,将当前值放在链表中;没有则在当前的table当前hash值对应的索引位置,如果需要,可能进行table的容量扩充,扩充算法为直接*2。扩容后,hashMap中的各元素会重新存储分布。(hash值算法不变,但是hash值对应的数组索引会发生变化)。
    public V put(K key, V value) {
        if (key == null)
            return putForNullKey(value);
        int hash = hash(key.hashCode());
        int i = indexFor(hash, table.length);
        //当前存在此hash值对象
        for (Entry<K, V> e = table[i]; e != null; e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }

        modCount++;
        //不存在此hash值对象
        addEntry(hash, key, value, i);
        return null;
    }

    void addEntry(int hash, K key, V value, int bucketIndex) {
        Entry<K, V> e = table[bucketIndex];
        table[bucketIndex] = new Entry<K, V>(hash, key, value, e);
        if (size++ >= threshold)
            //进行扩容处理,过程中,整个hashMap会重新分布。
            resize(2 * table.length);
    }

    void resize(int newCapacity) {
        Entry[] oldTable = table;
        int oldCapacity = oldTable.length;
        if (oldCapacity == MAXIMUM_CAPACITY) {
            threshold = Integer.MAX_VALUE;
            return;
        }

        Entry[] newTable = new Entry[newCapacity];
        transfer(newTable);
        table = newTable;
        threshold = (int) (newCapacity * loadFactor);
    }

    void transfer(Entry[] newTable) {
        Entry[] src = table;
        int newCapacity = newTable.length;
        for (int j = 0; j < src.length; j++) {
            Entry<K, V> e = src[j];
            if (e != null) {
                src[j] = null;
                do {
                    Entry<K, V> next = e.next;
                    int i = indexFor(e.hash, newCapacity);
                    e.next = newTable[i];
                    newTable[i] = e;
                    e = next;
                } while (e != null);
            }
        }
    }
  •  哈希表获取存储的元素,get方法。先根据hashCode计算索引序号。然后顺序逐一比较key值,等号比较和equal比较,查询到需要的对象值。
    public V get(Object key) {
        if (key == null)
            return getForNullKey();
        int hash = hash(key.hashCode());
        for (Entry<K, V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
                return e.value;
        }
        return null;
    }
  • HashTable扩展自Dictionary<K, V>,而非相关的Map接口。同时HashTable是线程同步的。
  • LinkedHashMap是基于HashMap的有序哈希表。其中存在一个双向循环链表,元素按照加入到哈希表中的顺序排列。
    void init() {
        header = new Entry<K, V>(-1, null, null, null);
        header.before = header.after = header;
    }

    void createEntry(int hash, K key, V value, int bucketIndex) {
        HashMap.Entry<K, V> old = table[bucketIndex];
        Entry<K, V> e = new Entry<K, V>(hash, key, value, old);
        table[bucketIndex] = e;
        //循环链表尾部加入一个新的元素
        e.addBefore(header);
        size++;
    }
  •  ConcurrentHashMap使用了多个segments,每个Segment中使用了类似HashMap的存储结构,进行了存储,不同的是,对于put操作,使用了ReentrantLock进行锁定操作。get操作,没有锁操作。此哈希表,在保证线程安全的前提下,如果存储值在当前hash算法下不过于集中到某个segment中,此容器具有不错的性能。
    //ConcurrentHashMap的put方法
    public V put(K key, V value) {
        if (value == null)
            throw new NullPointerException();
        int hash = hash(key.hashCode());
        return segmentFor(hash).put(key, hash, value, false);
    }

    //Segment的put方法
    V put(K key, int hash, V value, boolean onlyIfAbsent) {
            lock();
            try {
                int c = count;
                if (c++ > threshold) // ensure capacity
                    rehash();
                HashEntry<K, V>[] tab = table;
                int index = hash & (tab.length - 1);
                HashEntry<K, V> first = tab[index];
                HashEntry<K, V> e = first;
                while (e != null && (e.hash != hash || !key.equals(e.key)))
                    e = e.next;

                V oldValue;
                if (e != null) {
                    oldValue = e.value;
                    if (!onlyIfAbsent)
                        e.value = value;
                } else {
                    oldValue = null;
                    ++modCount;
                    tab[index] = new HashEntry<K, V>(key, hash, first, value);
                    count = c; // write-volatile
                }
                return oldValue;
            } finally {
                unlock();
            }
        }

 

1
3
分享到:
评论

相关推荐

    JDK6API中文参考手册[完美版][chm格式][修正重新上传]---part1

    一个2个文件 &lt;br/&gt;Java 2 SE 6 Documentation.part1.rar &lt;br/&gt;size: 28.6 MB &lt;br/&gt;MD5: 87E7B5D6C9A10C544D6401F324C8A187&lt;br/&gt;&lt;br/&gt;Java 2 SE 6 Documentation.part2.rar &lt;br/&gt;size: 20.1 MB&lt;br/&gt;MD5: EAF657FBCC...

    二级(Java语言程序设计)考试大纲

    &lt;font size="3"&gt;&lt;font color="#ff0000"&gt;考试内容 &lt;br /&gt;&lt;/font&gt;&lt;strong&gt;一、Java语言的特点和实现机制&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;二、Java体系结构&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;1.JDK目录结构。&lt;br /&gt;2.Java的API结构...

    aspose-words-18.8-jdk16-crack.jar

    &lt;Signature&gt;sNLLKGMUdF0r8O1kKilWAGdgfs2BvJb/2Xp8p5iuDVfZXmhppo+d0Ran1P9TKdjV4ABwAgKXxJ3jcQTqE/2IRfqwnPf8itN8aFZlV3TJPYeD3yWE7IT55Gz6EijUpC7aKeoohTb4w2fpox58wWoF3SNp6sK6jDfiAUGEHYJ9pjU=&lt;/Signature&gt; ...

    JDK8HashMap源码

    精确的版本号是jdk-8u181。想不通,竟然很多人都收费,这个明明可以在安装JDK的目录中找到啊!自己下一个JDK就可以得到。

    JDK7HashMap源码

    精确的版本号是jdk-7u80。想不通,竟然很多人都收费,这个明明可以在安装JDK的目录中找到啊!自己下一个JDK就可以得到。

    jdk6 源码 SRC

    jdk6 源码jdk6 源码jdk6 源码jdk6 源码jdk6 源码jdk6 源码

    spring boot2快速导出excel的java工具类demo源码:export-excel

    spring boot2快速导出excel的示例源码 操作系统:windows10 JAVA jdk:1.8 开发工具:IDEA java架构:spring boot 2.1.6 gitHub:https://github.com/cn-h-jar/exportexcel 作者:jar 运行提示: 启动项目...

    aspose-words-16.8.0-jdk16.jar 亲测可用版,无水印

    &lt;Signature&gt;sNLLKGMUdF0r8O1kKilWAGdgfs2BvJb/2Xp8p5iuDVfZXmhppo+d0Ran1P9TKdjV4ABwAgKXxJ3jcQTqE/2IRfqwnPf8itN8aFZlV3TJPYeD3yWE7IT55Gz6EijUpC7aKeoohTb4w2fpox58wWoF3SNp6sK6jDfiAUGEHYJ9pjU=&lt;/Signature&gt; ...

    Java集成京东接口的完整idea项目源码

    1.导入SpringBootJD\doc\springbootjd.sql,会自动创建库和表结构&lt;br/&gt; 2.修改SpringBootJD\src\main\resources\application.yml中的MySQL的账号和密码&lt;br/&gt; 3.修改SpringBootJD\src\main\java\...

    jdk源码 jdk源码

    jdk源码, jdk源码 jdk源码, jdk源码, jdk源码, jdk源码 jdk源码 jdk源码 jdk源码

    JDK6HashMap源码

    精确的版本号是jdk-6u45。想不通,竟然很多人都收费,这个明明可以在安装JDK的目录中找到啊!自己下一个JDK就可以得到。

    jdk6.0和tomcat6.0经典配置

    &lt;br&gt;&lt;br&gt;&lt;br&gt;安装和配置jdk6.0和tomcat6.0&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;调试(jsp):&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;1.到Tomcat的安装目录的webapps目录,可以看到ROOT,examples, tomcat-docs之类Tomcat自带的的目录.&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;2.在...

    基于JSP的办公自动化系统

    &lt;br&gt;&lt;br&gt;本系统是Web模式的办公自动化系统&lt;br&gt;&lt;br&gt;运行环境:Tomact+JDK&lt;br&gt;编程模式:JSP+JavaBean+JavaServlet&lt;br&gt;后台数据库:MS-Access&lt;br&gt;&lt;br&gt;系统主要功能简介:&lt;br&gt;&lt;br&gt;.信息中心 &lt;br&gt;&lt;br&gt;.内部电子邮件&lt;br&gt;...

    JSP图书管理系统

    &lt;td height="33" colspan="3" valign="middle" bgcolor="#F7F7F7"&gt;&lt;span style="font-size: medium"&gt;新进图书&lt;/span&gt;&lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td height="10"&gt;&lt;/td&gt; &lt;td&gt;&lt;/td&gt; &lt;td&gt;&lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td height=...

    jce_policy-JDK6 7 8.zip

    * 说明:异常java.security.InvalidKeyException:illegal Key Size的解决方案  * &lt;ol&gt; ... * &lt;li&gt;如果安装了JDK,将两个jar文件放到%JDK_HOME%\jre\lib\security目录下覆盖原来文件&lt;/li&gt;  * &lt;/ol&gt;

    java反编译工具jad 1.5.8g(可以反编译jdk1.5,1.6)

    For example:&lt;br&gt;&lt;br&gt; jad -o -dtest -sjava *.class&lt;br&gt;&lt;br&gt; (or jad -o -d test -s java *.class, which has the same effect)&lt;br&gt;&lt;br&gt;This command decompiles all .class files in the current directory &lt;br&gt;...

    基于JSP的实验室教学管理系统

    三层结构设计 程序逻辑结构分用户界面、业务逻&lt;br&gt; 辑处理和数据存储&lt;br&gt;.面向对象设计&lt;br&gt;.人性化设计&lt;br&gt;&lt;br&gt;系统主要功能简介:&lt;br&gt;&lt;br&gt;.前台&lt;br&gt;.浏览实验信息 .预约实验 .查询实验成绩 &lt;br&gt;.预约实验审核 .批改...

    基于JSP的在线考试系统

    &lt;br&gt;&lt;br&gt;本系统是Web模式的在线考试管理系统&lt;br&gt;&lt;br&gt;运行环境:Tomact+JDK&lt;br&gt;&lt;br&gt;编程模式:JSP+JavaBean+JavaServlet&lt;br&gt;&lt;br&gt;后台数据库:MS-Access&lt;br&gt;&lt;br&gt;系统主要完成的功能如下:&lt;br&gt;&lt;br&gt;.基本信息管理 考生...

    实验室教学管理系统

    三层结构设计 程序逻辑结构分用户界面、业务逻&lt;br&gt; 辑处理和数据存储&lt;br&gt;.面向对象设计&lt;br&gt;.人性化设计&lt;br&gt;&lt;br&gt;系统主要功能简介:&lt;br&gt;&lt;br&gt;.前台&lt;br&gt;.浏览实验信息 .预约实验 .查询实验成绩 &lt;br&gt;.预约实验审核 .批改...

Global site tag (gtag.js) - Google Analytics