`
wu.sheng
  • 浏览: 67009 次
  • 性别: 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
分享到:
评论

相关推荐

    Java JDK实例宝典

    &lt;br&gt;第1章 Java基础 &lt;br&gt;1.1 转换基本数据类型 &lt;br&gt;1.2 Java的运算符 &lt;br&gt;1.3 控制程序的流程 &lt;br&gt;1.4 计算阶乘 &lt;br&gt;1.5 实现命令行程序 &lt;br&gt;第2章 Java面向对象程序设计 &lt;br&gt;2. 1 复数类 &lt;br&gt;2. 2 equals.chashCode...

    jdk源码 jdk源码

    - **集合框架**: 研究ArrayList、LinkedList、HashMap、HashSet等数据结构的实现。 - **I/O流**: 理解字节流、字符流、缓冲流、对象序列化等概念。 - **网络编程**: 学习Socket通信,HTTP、FTP协议的实现。 - **国际...

    jdk1.8 rt.jar 源码

    2. **集合框架**:`java.util`包中的`ArrayList`、`LinkedList`、`HashMap`、`HashSet`等数据结构的实现,这些是日常编程中最常用的工具。源码可以帮助理解它们的性能特性,比如插入、删除、查找的时间复杂度。 3. ...

    jdk1.6 源码jdk1.6 源码

    深入理解JDK 1.6的源码对于Java开发者来说至关重要,因为它揭示了语言核心库的工作原理,有助于优化代码、理解和解决潜在问题。 1. **Java虚拟机(JVM)**:JDK 1.6中的JVM是Java程序执行的基础,它的主要职责是...

    jdk1.8 sun源码

    6. **集合框架**:`java.util`包中的集合类,如ArrayList、HashMap、LinkedList等,其内部实现细节对于理解数据结构和算法有很大帮助。 7. **I/O流**:`java.io`和`java.nio`包提供了丰富的输入/输出流接口和类,...

    JDK1.6源码

    源码分析能够揭示ArrayList、HashMap、HashSet等数据结构的内部实现,帮助理解其性能特点和适用场景。 8. **网络编程** JDK 1.6的Socket和ServerSocket类提供了基础的网络通信功能。通过源码,我们可以学习到连接...

    jdk源码jdk1.8.0_181

    `java.util`中的ArrayList和HashMap,是常用数据结构的实现;还有`java.io`中的File类,用于文件操作。 5. **launcher**: Java启动器(Java Launcher)是JVM(Java Virtual Machine)启动应用程序的关键组件。在JDK...

    jdk1.6源码包

    在JDK 1.6中,你可以在这里找到如Object、String、ArrayList、HashMap等基础类的源代码,这些是构建任何Java程序的基础。 **6. org 文件夹** org目录通常包含开源组织或标准组织提供的库。在JDK 1.6中,org可能包含...

    jdk1.7源码

    通过阅读这些类的源码,可以学习到各种设计模式,如工厂模式、单例模式、装饰器模式等,同时也能理解Java内置数据结构(如`ArrayList`, `HashMap`)的实现细节,这对于提升编程技能和解决问题具有极大帮助。...

    jdk1.8 src源码包

    - **选择主题**: 针对特定感兴趣的领域,如并发、网络编程或数据结构,深入研究相关源码。 - **阅读文档**: 结合Javadoc了解类和方法的用途和参数,这是理解源码的基础。 - **调试与实验**: 使用IDE的源码浏览功能...

    JAVA JDK实例开发宝典源码

    6. **输入输出流**:Java的I/O流系统是处理数据传输的关键,源码会涵盖文件读写、网络通信、序列化等场景,让你了解InputStream、OutputStream、Reader、Writer等类的使用。 7. **反射机制**:反射是Java的高级特性...

    jdk的部分源码(jdk)

    通过源码,我们可以学习这些类和接口的实现,例如ArrayList和HashMap的工作原理,线程同步的细节,以及Socket通信的底层实现。 4. **异常处理**: 源码中展示了Java如何处理异常,包括检查性异常和运行时异常。理解...

    jdk1.6源码

    这些类的源码展示了如何实现数据结构和算法,对于提升算法和数据结构理解有很大帮助。 10. **异常处理** `java.lang.Throwable`及其子类定义了Java的异常处理机制。通过查看源码,我们可以了解到异常的抛出、捕获...

    jdk1.6源码Ecplise添加

    `java.util.ArrayList`和`java.util.HashMap`是常用的集合类,它们的实现涉及动态数组和哈希表的数据结构;`java.io`包下的类则涵盖了输入输出流的处理,如`FileInputStream`和`PrintWriter`。 通过阅读和学习这些...

    JDK1.8源码完整版

    再者,JDK1.8对HashMap和HashSet等数据结构进行了优化,尤其是并发性能的提升。例如,ConcurrentHashMap在1.8版本中采用了分段锁策略,提高了并发访问的效率。此外,新版本的TreeMap和TreeSet使用了Fork/Join框架下...

    jdk src 源码 压缩包提取

    在源码中,你可以看到`java.lang`、`java.util`、`java.io`等包中的各种基础类是如何实现的,例如`String`、`ArrayList`、`HashMap`等常用数据结构。 首先,`java.lang`包包含了Java语言的基础类和接口,如`Object`...

    jdk1.8source源码

    Java Development Kit (JDK) 1.8 是Java编程语言的一个关键版本,它引入了许多重要的特性和改进。...对于希望深入理解Java并成为更好的开发者的程序员来说,JDK 1.8源码的探索是一次不可或缺的学习之旅。

    Android-jdk源码阅读

    "Android-jdk源码阅读"这个主题聚焦于分析Java标准库中的`TreeMap`类,这是一个基于红黑树数据结构实现的有序映射。在这个主题中,我们将探讨`TreeMap`的内部工作原理,特别是它如何利用红黑树来实现高效的插入、...

    jdk1.7源码包含util

    通过阅读和分析JDK 1.7的源码,我们可以深入了解这些类和接口的实现细节,这对于优化代码性能、排查问题以及设计自己的数据结构和算法都有很大帮助。同时,这也是学习Java语言和提升编程能力的重要途径。

    jdk1.8.0源码 src.zip

    java.util.*包中的ArrayList、HashMap等集合类,是日常开发中频繁使用的数据结构;而java.io.*包则涵盖了输入/输出操作,包括文件、网络和内存流。 最后,org目录通常用于存放开源组织或标准组织的代码,如org.w3c....

Global site tag (gtag.js) - Google Analytics