/** * Basic hash bin node, used for most entries. (See below for * TreeNode subclass, and in LinkedHashMap for its Entry subclass.) */ staticclassNode<K,V> implementsMap.Entry<K,V> { finalint hash; final K key; V value; Node<K,V> next; } /** * The table, initialized on first use, and resized as * necessary. When allocated, length is always a power of two. * (We also tolerate length zero in some operations to allow * bootstrapping mechanics that are currently not needed.) */ transient Node<K,V>[] table; /** * The number of key-value mappings contained in this map. */ transientint size; /** * The number of times this HashMap has been structurally modified * Structural modifications are those that change the number of mappings in * the HashMap or otherwise modify its internal structure (e.g., * rehash). This field is used to make iterators on Collection-views of * the HashMap fail-fast. (See ConcurrentModificationException). */ transientint modCount; /** * The next size value at which to resize (capacity * load factor). * * @serial */ // (The javadoc description is true upon serialization. // Additionally, if the table array has not been allocated, this // field holds the initial array capacity, or zero signifying // DEFAULT_INITIAL_CAPACITY.) int threshold; /** * The load factor for the hash table. * * @serial */ finalfloat loadFactor;
Node 就是上面说的 Entry 的实现,用来保存键值对,实现了 Map.Entry 接口。其中 hash 的值是通过 hash() 方法计算出来,key 和 value 是存入的值,next 是出现哈希冲突的时候,会使用 next 指向链表中的下一个元素对象。
/** * Computes key.hashCode() and spreads (XORs) higher bits of hash * to lower. Because the table uses power-of-two masking, sets of * hashes that vary only in bits above the current mask will * always collide. (Among known examples are sets of Float keys * holding consecutive whole numbers in small tables.) So we * apply a transform that spreads the impact of higher bits * downward. There is a tradeoff between speed, utility, and * quality of bit-spreading. Because many common sets of hashes * are already reasonably distributed (so don't benefit from * spreading), and because we use trees to handle large sets of * collisions in bins, we just XOR some shifted bits in the * cheapest possible way to reduce systematic lossage, as well as * to incorporate impact of the highest bits that would otherwise * never be used in index calculations because of table bounds. */ staticfinalinthash(Object key){ int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); }
get 操作
get 方法通过 hash 寻找到 Entry 数组下标,找到头节点,然后顺着对应链表的头节点,一个一个向下来查找。由于 JDK8 引用了红黑树结构,在链表元素过多时,JDK8 的实现将比 JDK7 在 get 和 put 操作上效率高上很多。
publicstaticvoidmain(String[] args)throws InterruptedException { HashMap<Integer, Integer> map = new HashMap<>(); ArrayList<Integer> list = new ArrayList<>(); for (int i = 0; i < 10000; i++) { list.add(i); }
list.forEach(i -> map.put(i, i)); new Thread(() -> { for (int i = 10000; i < 20000; i++) { map.put(i, i); } }).start(); new Thread(() -> { for (int i = 20000; i < 30000; i++) { map.put(i, i); } }).start();