惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

K
Kaspersky official blog
Engineering at Meta
Engineering at Meta
D
DataBreaches.Net
Stack Overflow Blog
Stack Overflow Blog
Microsoft Security Blog
Microsoft Security Blog
Y
Y Combinator Blog
B
Blog RSS Feed
GbyAI
GbyAI
P
Proofpoint News Feed
aimingoo的专栏
aimingoo的专栏
MyScale Blog
MyScale Blog
D
Docker
阮一峰的网络日志
阮一峰的网络日志
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Recorded Future
Recorded Future
美团技术团队
The Register - Security
The Register - Security
V
Visual Studio Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
T
Tailwind CSS Blog
爱范儿
爱范儿
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
T
The Blog of Author Tim Ferriss
博客园 - 司徒正美
量子位
B
Blog
F
Fortinet All Blogs
Martin Fowler
Martin Fowler
博客园 - 【当耐特】
MongoDB | Blog
MongoDB | Blog
A
About on SuperTechFans
I
InfoQ
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
有赞技术团队
有赞技术团队
雷峰网
雷峰网
大猫的无限游戏
大猫的无限游戏
J
Java Code Geeks
L
LangChain Blog
Latest news
Latest news
S
SegmentFault 最新的问题
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Blog — PlanetScale
Blog — PlanetScale
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Cisco Talos Blog
Cisco Talos Blog
F
Full Disclosure
C
Cisco Blogs
D
Darknet – Hacking Tools, Hacker News & Cyber Security
W
WeLiveSecurity
T
Tenable Blog
T
Tor Project blog

博客园 - cacard

Android中的内部类引起的内存泄露 Android的消息机制: Message/MessageQueue/Handler/Looper ArrayList/Vector的原理、线程安全和迭代Fail-Fast JVM中的Stack和Frame JVM中的垃圾收集算法和Heap分区简记 无锁编程以及CAS 简述Java内存模型的由来、概念及语义 MQTT协议简记 RabbitMQ的工作队列和路由 RabbitMQ 入门 [Java] LinkedHashMap 源码简要分析 [Java] Hashtable 源码简要分析 CentOS 安装 Hadoop 手记 树莓派(RespberryPi)安装手记 RPC简述 [C++] const与重载 [C++] 左值、右值、右值引用 [C++] 引用 Java线程池 / Executor / Callable / Future
[Java] HashMap 源码简要分析
cacard · 2014-03-07 · via 博客园 - cacard

 特性

* 允许null作为key/value。

* 不保证按照插入的顺序输出。使用hash构造的映射一般来讲是无序的。

* 非线程安全。

* 内部原理与Hashtable类似。

源码简要分析

public class HashMap<K,V>
{
     static final int DEFAULT_INITIAL_CAPACITY = 16 ; // 默认初始容量是16。(必须是2的次方)
     static final int MAXIMUM_CAPACITY = 1 << 30 ; // 即2的30次方
     static final float DEFAULT_LOAD_FACTOR = 0.75f; // 默认装载因子

     Entry[] table;  // Entry表
     int size; // Entry[]实际存储的Entry个数
     int threshold; // reash的阈值,=capacity * load factor
     final float loadFactor;

     // 构造函数
     public HashMap(int initialCapacity, float loadFactor) {
     // 找到一个比initialCapacity大的最小的2的次方数
     int capacity = 1;
     while (capacity < initialCapacity)
            capacity <<= 1;
     }

     this.loadFactor = loadFactor;
     threshold = (int)(capacity * loadFactor);
     table = new Entry[capacity];

     // addEntry()
    void addEntry(int hash, K key, V value, int bucketIndex) {
        Entry<K,V> e = table[bucketIndex];
        table[bucketIndex] = new Entry<>(hash, key, value, e);
        if (size++ >= threshold)
            resize(2 * table.length);
    }

     // put():添加元素
     public V put(K key, V value) {
          int hash = hash(key.hashCode());     // key的hash值
          int i = indexFor(hash,table.length);     // 槽位

          // 寻找是否已经有key存在,如果已经存在,使用新值覆盖旧值,返回旧值
          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;
                return oldValue;
            }
          }

          // 添加Entry
          addEntry(hash,key,value,i);
          return null;
     }

     // resize():重新哈希
    void resize(int newCapacity) {
        Entry[] oldTable = table;
        int oldCapacity = oldTable.length;
        Entry[] newTable = new Entry[newCapacity];
        transfer(newTable);
        table = newTable;
        threshold = (int)(newCapacity * loadFactor);
    }

    /**
     * Transfers all entries from current table to newTable.
     */
    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);
            }
        }
    }

}

遍历方式

* 低效遍历:按照Key进行遍历,则每次都需要按Key查找槽位(不同的Key有重复查找),且可能需要遍历槽位上所在Entry链表(不同的Key有重复遍历)。

* 高效遍历:HashMap的entrySet()返回自定义的EntryIterator,是先按照槽位遍历一次,再遍历一次槽位上Entry链表。

Map<String, String[]> paraMap = new HashMap<String, String[]>();
for( Map.Entry<String, String[]> entry : paraMap.entrySet() )
{
    String appFieldDefId = entry.getKey();
    String[] values = entry.getValue();
}