[Java] HashMap 源码简要分析
特性
* 允许null作为key/value。
* 不保证按照插入的顺序输出。使用hash构造的映射一般来讲是无序的。
* 非线程安全。
* 内部原理与Hashtable类似。
源码简要分析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | 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链表。
1 2 3 4 5 6 | Map<String, String[]> paraMap = new HashMap<String, String[]>(); for ( Map.Entry<String, String[]> entry : paraMap.entrySet() ) { String appFieldDefId = entry.getKey(); String[] values = entry.getValue(); } |
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步