java源码分析之HashMap

来源:互联网 发布:耳机调音软件 编辑:程序博客网 时间:2024/05/16 14:13
package java.util;import java.io.*;/** * 继承Map的抽象类AbstractMap 实现 Map(集合),Cloneable(实现对象的浅拷贝),serializable(序列化)接口,非线程安全 * hashMap 是一个数组结构,每一个数组元素是一个链表,每一个链表中包含多个Entry类,这些Entry类的key有相同的hash值作为数组的下标 * created by jewhone on 2017年7月3日 */@SuppressWarnings({ "unchecked", "rawtypes" })public class HashMap<K, V> extends AbstractMap<K, V> implements Map<K, V>, Cloneable, Serializable {/** * 默认的初始容量(必须为2的幂) * 容量为2的n次方原因:1.不同的hash值发生碰撞的概率比较小,这样就会使得数据在table数组中分布较均匀,查询速度也较快 */static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // 2^4=16/** * 最大容量为 2^30次幂 */static final int MAXIMUM_CAPACITY = 1 << 30;/** * 默认的负载因子为0.75 决定何时对散列表进行再散列.例:如果负载因子是0.75, 当散列表中已经有75%的位置已经放满,那么将进行散列. */static final float DEFAULT_LOAD_FACTOR = 0.75f;/** * 空的Entry类(Entry类型的数据结构作为内存存储结构) */static final Entry<?, ?>[] EMPTY_TABLE = {};/** * HashMap是一个链表数组结构(包含了key,value),长度必须为2的幂 */transient Entry<K, V>[] table = (Entry<K, V>[]) EMPTY_TABLE;/** * 映射中包含的键值映射个数 */transient int size;/** * 扩容临界值(size>=threshold时需要扩容)(容量*负载因子) */int threshold;/** * 哈希表的负载因子 */final float loadFactor;/** * 哈希表结构更改次数(遍历时用于判断hashmap是否被改变) */transient int modCount;/** * 默认的散列阈值 */static final int ALTERNATIVE_HASHING_THRESHOLD_DEFAULT = Integer.MAX_VALUE;/** * holds values which can't be initialized until after VM is booted. */private static class Holder {/** * Table capacity above which to switch to use alternative hashing. */static final int ALTERNATIVE_HASHING_THRESHOLD;static {String altThreshold = java.security.AccessController.doPrivileged(new sun.security.action.GetPropertyAction("jdk.map.althashing.threshold"));int threshold;try {threshold = (null != altThreshold) ? Integer.parseInt(altThreshold): ALTERNATIVE_HASHING_THRESHOLD_DEFAULT;// disable alternative hashing if -1if (threshold == -1) {threshold = Integer.MAX_VALUE;}if (threshold < 0) {throw new IllegalArgumentException("value must be positive integer.");}} catch (IllegalArgumentException failed) {throw new Error("Illegal value for 'jdk.map.althashing.threshold'", failed);}ALTERNATIVE_HASHING_THRESHOLD = threshold;}}/** * 计算hash值的基础值,保证每次hash值的唯一性 */transient int hashSeed = 0;/** * 指定初始容量和负载因子的构造器,并初始化 预设初始容量能够有效提高hashMap的性能(需重新计算数据位置和复制) *  * @param initialCapacity *            初始容量 * @param loadFactor *            负载因子 */public HashMap(int initialCapacity, float loadFactor) {if (initialCapacity < 0)throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity);if (initialCapacity > MAXIMUM_CAPACITY)initialCapacity = MAXIMUM_CAPACITY;if (loadFactor <= 0 || Float.isNaN(loadFactor))throw new IllegalArgumentException("Illegal load factor: " + loadFactor);this.loadFactor = loadFactor;threshold = initialCapacity;init();}/** * 指定初始容量和默认的负载因子的构造器 * * @param initialCapacity *            初始容量 */public HashMap(int initialCapacity) {this(initialCapacity, DEFAULT_LOAD_FACTOR);}/** * 默认的初始容量和负载因子的构造器 */public HashMap() {this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);}/** * 与指定Map 有相同映射的构造器 */public HashMap(Map<? extends K, ? extends V> m) {this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1, DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR);inflateTable(threshold);// 根据已有的Map 创建对应的EntryputAllForCreate(m);}/** * 取值的大小始终为2^n次幂(取大于指定值最近的2^n的数) */private static int roundUpToPowerOf2(int number) {// assert number >= 0 : "number must be non-negative";int rounded = number >= MAXIMUM_CAPACITY ? MAXIMUM_CAPACITY: (rounded = Integer.highestOneBit(number)) != 0? (Integer.bitCount(number) > 1) ? rounded << 1 : rounded : 1;return rounded;}/** * 扩容 */private void inflateTable(int toSize) {// Find a power of 2 >= toSizeint capacity = roundUpToPowerOf2(toSize);// 指定容量值threshold = (int) Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1);// 指定扩容阈值table = new Entry[capacity];// 定义表结构initHashSeedAsNeeded(capacity);// 初始化hashSeed}/** * 子类初始化方法 */void init() {}/** * 如果哈希种子为0且useAltHashing为true,则根据指定capacity重置哈希种子 且只能重置一次哈希种子,这里和虚拟机的配置有关 */final boolean initHashSeedAsNeeded(int capacity) {boolean currentAltHashing = hashSeed != 0;boolean useAltHashing = sun.misc.VM.isBooted() && (capacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD);boolean switching = currentAltHashing ^ useAltHashing;if (switching) {hashSeed = useAltHashing ? sun.misc.Hashing.randomHashSeed(this) : 0;}return switching;}/** * hash算法,计算对象的hash值 */final int hash(Object k) {int h = hashSeed;if (0 != h && k instanceof String) {return sun.misc.Hashing.stringHash32((String) k);}h ^= k.hashCode();// 尽可能确保产生的hash值不能,减少hash碰撞的机会(approximately 8 at default load factor).h ^= (h >>> 20) ^ (h >>> 12);return h ^ (h >>> 7) ^ (h >>> 4);}/** * 计算对象应该保存在数组的哪个位置(对象的hash值 和 数组长度-1 与运算) */static int indexFor(int h, int length) {// assert Integer.bitCount(length) == 1 : "length must be a non-zero// power of 2";return h & (length - 1);}/** * 返回Map 中键值对的个数. */public int size() {return size;}/** * 判断 Map 是否为空 */public boolean isEmpty() {return size == 0;}/** * 返回指定 key键 对应的 value值,如果key值为空,返回 null键对应的 value值 */public V get(Object key) {if (key == null)return getForNullKey();Entry<K, V> entry = getEntry(key);return null == entry ? null : entry.getValue();}/** * 返回 key 为 null 对应的键值 */private V getForNullKey() {if (size == 0) {return null;}// 遍历哈希表,查找键为 null 的 value值for (Entry<K, V> e = table[0]; e != null; e = e.next) {if (e.key == null)return e.value;}return null;}/** * 判断 Map 中是否包含指定的 key. */public boolean containsKey(Object key) {return getEntry(key) != null;}/** * 返回 HashMap中指定 key对应的键值对,若不存在,则返回null. */final Entry<K, V> getEntry(Object key) {if (size == 0) {return null;}// 计算指定 key 的hash值int hash = (key == null) ? 0 : hash(key);// 遍历哈希值列表,返回hash值与key的hash相等的键值对 key值不可重复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 != null && key.equals(k))))return e;}return null;}/** * 将指定key和value保存为键值对,如果 HashMap中包含 key值,则用 value 替换旧值.有返回值 */public V put(K key, V value) {// 如果哈希表为空,则扩容if (table == EMPTY_TABLE) {inflateTable(threshold);}// 返回key 为null对应的 value值,一直处于table[0].if (key == null)return putForNullKey(value);// 根据键值计算key对应的hash值int hash = hash(key);// 确定指定hash值在table中的索引位置int i = indexFor(hash, table.length);// 检查在索引为i的这条链上有没有key重复的,有则替换原值,返回原值for (Entry<K, V> e = table[i]; e != null; e = e.next) {Object k;// 使用equals方法判断是 key 的哈希值否相等if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {V oldValue = e.value;e.value = value;e.recordAccess(this);return oldValue;// 返回旧的value.}}modCount++;// 如果在table[i]中没找到对应的key,那么就直接在该位置的链表中添加此EntryaddEntry(hash, key, value, i);return null;}/** * 替换原有的null键对应的value值,返回原有的value值 */private V putForNullKey(V value) {for (Entry<K, V> e = table[0]; e != null; e = e.next) {if (e.key == null) {V oldValue = e.value;e.value = value;e.recordAccess(this);return oldValue;}}modCount++;// 如果在table[0]中没找到对应的key为null,那么就直接在该位置的链表中添加此EntryaddEntry(0, null, value, 0);return null;}/** * 更新或创建新的Entry */private void putForCreate(K key, V value) {int hash = null == key ? 0 : hash(key);int i = indexFor(hash, table.length);// 在 索引为 i 的链表中寻找 key值,若有,则更新键值对for (Entry<K, V> e = table[i]; e != null; e = e.next) {Object k;if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) {e.value = value;return;}}// 若在指定索引 i 的链表中无key值,则将其添加到链表中 i 位置createEntry(hash, key, value, i);}/** * 根据已有的Map 创建对应的Entry */private void putAllForCreate(Map<? extends K, ? extends V> m) {for (Map.Entry<? extends K, ? extends V> e : m.entrySet())putForCreate(e.getKey(), e.getValue());}/** * 用新的容量来给数组扩容。(当size达到阈值时) */void resize(int newCapacity) {Entry[] oldTable = table;int oldCapacity = oldTable.length;// 如果旧数组容量等于最大容量,则将扩容临界值增大,不进行扩容操作if (oldCapacity == MAXIMUM_CAPACITY) {threshold = Integer.MAX_VALUE;return;}@SuppressWarnings("rawtypes")Entry[] newTable = new Entry[newCapacity];// 将所有的键值对从现有的表中转移到新表transfer(newTable, initHashSeedAsNeeded(newCapacity));table = newTable;threshold = (int) Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);}/** * 将所有的键值对从现有的表中转移到新表 */void transfer(Entry[] newTable, boolean rehash) {int newCapacity = newTable.length;// 从原表中取出所有 Entryfor (Entry<K, V> e : table) {// 循环将 Entry赋值给 newTablewhile (null != e) {Entry<K, V> next = e.next;if (rehash) {e.hash = null == e.key ? 0 : hash(e.key);}int i = indexFor(e.hash, newCapacity);e.next = newTable[i];// e.next为newTable[i]保存的EntrynewTable[i] = e;// 将e设置为newTable[i]e = next;// 设置e为下一个Entry,继续上面while循环}}}/** * 将指定Map中的所有映射复制到现有的 HashMap中,如果指定Map中的 key键与现有的相同,则替换现有的key对应的value值 */public void putAll(Map<? extends K, ? extends V> m) {int numKeysToBeAdded = m.size();if (numKeysToBeAdded == 0)return;// 如果table为空进行初始化(size*loadFactor与阈值比较)if (table == EMPTY_TABLE) {inflateTable((int) Math.max(numKeysToBeAdded * loadFactor, threshold));}// 如果目标size 大于阈值if (numKeysToBeAdded > threshold) {// 计算所需容量int targetCapacity = (int) (numKeysToBeAdded / loadFactor + 1);if (targetCapacity > MAXIMUM_CAPACITY)targetCapacity = MAXIMUM_CAPACITY;int newCapacity = table.length;while (newCapacity < targetCapacity)newCapacity <<= 1;// newCapacity 等于newCapacity 乘以2的1次方if (newCapacity > table.length)resize(newCapacity);// 重置数组容量}// 复制(将Entry依次放到新 hashMap 中)for (Map.Entry<? extends K, ? extends V> e : m.entrySet())put(e.getKey(), e.getValue());}/** * 删除指定key对应的Entry,返回key对应的value值. */public V remove(Object key) {Entry<K, V> e = removeEntryForKey(key);return (e == null ? null : e.value);}/** * 删除指定key对应的Entry,返回key对应的value值. */final Entry<K, V> removeEntryForKey(Object key) {if (size == 0) {return null;}int hash = (key == null) ? 0 : hash(key);int i = indexFor(hash, table.length);Entry<K, V> prev = table[i];Entry<K, V> e = prev;// 寻找key值,删除对应的键值对while (e != null) {Entry<K, V> next = e.next;Object k;if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) {modCount++;size--;if (prev == e)// 如果删除的是table中的第一项的引用table[i] = next;// 直接将第一项中的next的引用存入table[i]中elseprev.next = next;// 否则将table[i]中当前Entry的前一个Entry中的next置为当前Entry的nexte.recordRemoval(this);return e;}prev = e;e = next;//删除后,将后续Entry向前移一位}return e;}/** * 根据Entry来删除HashMap中的键值对 */final Entry<K, V> removeMapping(Object o) {if (size == 0 || !(o instanceof Map.Entry))return null;Map.Entry<K, V> entry = (Map.Entry<K, V>) o;// 获取Entry的键值Object key = entry.getKey();int hash = (key == null) ? 0 : hash(key);int i = indexFor(hash, table.length);Entry<K, V> prev = table[i];Entry<K, V> e = prev;while (e != null) {Entry<K, V> next = e.next;// 定义next 为 e 的下一节点if (e.hash == hash && e.equals(entry)) {modCount++;size--;if (prev == e)table[i] = next;// 将 e 的下一节点提到链表头上elseprev.next = next;e.recordRemoval(this);return e;}prev = e;e = next;}return e;}/** * 清空 hashMap 中所有的Entry. */public void clear() {modCount++;Arrays.fill(table, null);// 将 table 中存储的Entry全部转为 nullsize = 0;}/** * 判断是否有 key对应的 值为指定的 value */public boolean containsValue(Object value) {if (value == null)return containsNullValue();Entry[] tab = table;// 循环查询是否有 value值为null的键值对for (int i = 0; i < tab.length; i++)for (Entry e = tab[i]; e != null; e = e.next)if (value.equals(e.value))return true;return false;}/** * 判断是否有key 对应的value 值为null */private boolean containsNullValue() {Entry[] tab = table;for (int i = 0; i < tab.length; i++)for (Entry e = tab[i]; e != null; e = e.next)if (e.value == null)return true;return false;}/** * 克隆HashMap实例,这里是浅复制,并没有复制键和值的本身 (复制引用) */public Object clone() {HashMap<K, V> result = null;try {// 根据原table新建了一个newTable,这说明两个hashMap的数组不是指向的同一个对象result = (HashMap<K, V>) super.clone();} catch (CloneNotSupportedException e) {// assert false;}if (result.table != EMPTY_TABLE) {result.inflateTable(Math.min((int) Math.min(size * Math.min(1 / loadFactor, 4.0f),// we have limits...HashMap.MAXIMUM_CAPACITY), table.length));}result.entrySet = null;result.modCount = 0;result.size = 0;result.init();// 将原HashMap中存储的元素复制到新的HashMap里面result.putAllForCreate(this);return result;}/** * Entry 单向链表结构 ,实现了Map.Entry接口  * created by jewhone on 2017年7月4日 */static class Entry<K, V> implements Map.Entry<K, V> {final K key;// 键V value;// 值Entry<K, V> next;// 指向下一个节点int hash;// 哈希值/** * Entry构造器 */Entry(int h, K k, V v, Entry<K, V> n) {value = v;next = n;key = k;hash = h;}public final K getKey() {return key;}public final V getValue() {return value;}public final V setValue(V newValue) {V oldValue = value;value = newValue;return oldValue;}/** * 判断两个Entry是否相等,必须 key和value 值都相等,才返回true. */public final boolean equals(Object o) {if (!(o instanceof Map.Entry))return false;Map.Entry e = (Map.Entry) o;Object k1 = getKey();Object k2 = e.getKey();if (k1 == k2 || (k1 != null && k1.equals(k2))) {Object v1 = getValue();Object v2 = e.getValue();if (v1 == v2 || (v1 != null && v1.equals(v2)))return true;}return false;}/** * 实现hashCode */public final int hashCode() {return Objects.hashCode(getKey()) ^ Objects.hashCode(getValue());}public final String toString() {return getKey() + "=" + getValue();}/** * 当向HashMap中添加元素时,即调用put(k,v)时,  * 对已经在HashMap中key位置进行value的覆盖时,会调用此方法 未做任何处理 */void recordAccess(HashMap<K, V> m) {}/** * 当从HashMap中删除了一个Entry时,会调用该函数  * 未做任何处理 */void recordRemoval(HashMap<K, V> m) {}}/** * 在指定位置添加指定hash,key,value的键值对 */void addEntry(int hash, K key, V value, int bucketIndex) {//判断是否进行扩容if ((size >= threshold) && (null != table[bucketIndex])) {resize(2 * table.length);//2倍扩容hash = (null != key) ? hash(key) : 0;bucketIndex = indexFor(hash, table.length);//重新计算位置}//根据指定值创建一个新的EntrycreateEntry(hash, key, value, bucketIndex);}/** * 在指定位置添加一个新的Entry. */void createEntry(int hash, K key, V value, int bucketIndex) {Entry<K, V> e = table[bucketIndex];table[bucketIndex] = new Entry<>(hash, key, value, e);size++;}/** * hashIterator实现了Iterator接口   * created by jewhone on 2017年7月6日 */private abstract class HashIterator<E> implements Iterator<E> {Entry<K, V> next; // 下一个Entry.int expectedModCount; // 预期值,用于 fast-fail机制int index; // 当前索引Entry<K, V> current; // 当前 entry.//构造器HashIterator() {expectedModCount = modCount;//保存 modCount 用于 fail-fast机制if (size > 0) { // 先入先进原则Entry[] t = table;while (index < t.length && (next = t[index++]) == null);}}/** * 判断是否有下一个 Entry. */public final boolean hasNext() {return next != null;}/** * 获得下一个Entry. */final Entry<K, V> nextEntry() {if (modCount != expectedModCount)throw new ConcurrentModificationException();Entry<K, V> e = next;if (e == null)throw new NoSuchElementException();if ((next = e.next) == null) {Entry[] t = table;while (index < t.length && (next = t[index++]) == null);}current = e;//当前Entry等于下一个Entry对象.return e;}/** * 删除Entry. */public void remove() {if (current == null)throw new IllegalStateException();if (modCount != expectedModCount)throw new ConcurrentModificationException();Object k = current.key;current = null;HashMap.this.removeEntryForKey(k);expectedModCount = modCount;}}/** * 内部class ValueIterator迭代器,它修改了next方法 (value) *  * created by jewhone on 2017年7月6日 */private final class ValueIterator extends HashIterator<V> {public V next() {return nextEntry().value;}}/** * 内部class ValueIterator迭代器,它修改了next方法 (key) *  * created by jewhone on 2017年7月6日 */private final class KeyIterator extends HashIterator<K> {public K next() {return nextEntry().getKey();}}/** * 内部class ValueIterator迭代器,它修改了next方法 (Entry) *  * created by jewhone on 2017年7月6日 */private final class EntryIterator extends HashIterator<Map.Entry<K, V>> {public Map.Entry<K, V> next() {return nextEntry();}}//定义对应上面三个的 next()方法Iterator<K> newKeyIterator() {return new KeyIterator();}Iterator<V> newValueIterator() {return new ValueIterator();}Iterator<Map.Entry<K, V>> newEntryIterator() {return new EntryIterator();}// 定义 entrySet.private transient Set<Map.Entry<K, V>> entrySet = null;/** * 返回此映射中包含的 key 键 的 Set 视图.(返回所有的 key值) * 包含方法 size(),contains(Object o),remove(Object o),clear() */public Set<K> keySet() {Set<K> ks = keySet;return (ks != null ? ks : (keySet = new KeySet()));}private final class KeySet extends AbstractSet<K> {public Iterator<K> iterator() {return newKeyIterator();}public int size() {return size;}public boolean contains(Object o) {return containsKey(o);}public boolean remove(Object o) {return HashMap.this.removeEntryForKey(o) != null;}public void clear() {HashMap.this.clear();}}/** * 返回此映射中包含的 value 值 的 Collection 视图(返回所有的 value值). * 包含方法 size(),contains(Object o),clear() */public Collection<V> values() {Collection<V> vs = values;return (vs != null ? vs : (values = new Values()));}private final class Values extends AbstractCollection<V> {public Iterator<V> iterator() {return newValueIterator();}public int size() {return size;}public boolean contains(Object o) {return containsValue(o);}public void clear() {HashMap.this.clear();}}/** * 返回此映射中包含的 Entry 的 Set 视图(返回所有的 Entry). * 包含方法 iterator(),contains(Object o),remove(Object o),size(),clear() */public Set<Map.Entry<K, V>> entrySet() {return entrySet0();}private Set<Map.Entry<K, V>> entrySet0() {Set<Map.Entry<K, V>> es = entrySet;return es != null ? es : (entrySet = new EntrySet());}private final class EntrySet extends AbstractSet<Map.Entry<K, V>> {public Iterator<Map.Entry<K, V>> iterator() {return newEntryIterator();}public boolean contains(Object o) {if (!(o instanceof Map.Entry))return false;Map.Entry<K, V> e = (Map.Entry<K, V>) o;Entry<K, V> candidate = getEntry(e.getKey());return candidate != null && candidate.equals(e);}public boolean remove(Object o) {return removeMapping(o) != null;}public int size() {return size;}public void clear() {HashMap.this.clear();}}/** * 序列化 */private void writeObject(java.io.ObjectOutputStream s) throws IOException {// Write out the threshold, loadfactor, and any hidden stuffs.defaultWriteObject();// Write out number of bucketsif (table == EMPTY_TABLE) {s.writeInt(roundUpToPowerOf2(threshold));} else {s.writeInt(table.length);}// Write out size (number of Mappings)s.writeInt(size);// Write out keys and values (alternating)if (size > 0) {for (Map.Entry<K, V> e : entrySet0()) {s.writeObject(e.getKey());s.writeObject(e.getValue());}}}private static final long serialVersionUID = 362498820763181265L;/** * 反序列化 */private void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException {// Read in the threshold (ignored), loadfactor, and any hidden stuffs.defaultReadObject();if (loadFactor <= 0 || Float.isNaN(loadFactor)) {throw new InvalidObjectException("Illegal load factor: " + loadFactor);}// set other fields that need valuestable = (Entry<K, V>[]) EMPTY_TABLE;// Read in number of bucketss.readInt(); // ignored.// Read number of mappingsint mappings = s.readInt();if (mappings < 0)throw new InvalidObjectException("Illegal mappings count: " + mappings);// capacity chosen by number of mappings and desired load (if >= 0.25)int capacity = (int) Math.min(mappings * Math.min(1 / loadFactor, 4.0f),// we have limits...HashMap.MAXIMUM_CAPACITY);// allocate the bucket array;if (mappings > 0) {inflateTable(capacity);} else {threshold = capacity;}init(); // Give subclass a chance to do its thing.// Read the keys and values, and put the mappings in the HashMapfor (int i = 0; i < mappings; i++) {K key = (K) s.readObject();V value = (V) s.readObject();putForCreate(key, value);}}// These methods are used when serializing HashSetsint capacity() {return table.length;}float loadFactor() {return loadFactor;}}

总结:1.hashMap是非线程安全的,但速度快,线程安全的有 hashTable(全结构加锁)和concurrentHashMap(分段锁-细粒度)速度相对较慢.

     2.hashMap的同一个链表下 key的hash值相等,但 key值不相同. 当key值 相同,将覆盖前面的 key对应的value值.

     3.当hashMap的容量超过了定义的大小,将产生一个两倍于之前的数组),并根据新的 hash&(length -1)计算出新的位置,并将原有的对象放入新的数组.

     4.重新调整 hashMap 的大小可能产生竞争,在多线程的情况下会使两个及以上的线程同时调整容量大小。一般在多线程的时候使用 hastTable 或concurrentHashMap

             5.使用 String 或 Integer类作为 HashMap的键值主要是因为其不可变性,这样可防止放入和取出的时候key值不一致。同时也能提高查询效率.

     6.hashMap 可以根据如下方式创建同步对象:Map m = Collections.synchronizeMap(hashMap);

     7.hashMap可以接受 key , value值为 null,但hastTable不能.

     8. hashMap的扩容是创建一个比原来的容量更大的新数组,再重新计算 新的位置,将原来的数组元素添加到新数组中,故而相对比较浪费空间成本

     9.HashMap基于hashing原理,我们通过put()和get()方法储存和获取对象。当我们将键值对传递给put()方法时,它调用键对象的hashCode()              方法来计算hashcode,让后找到bucket位置来储存值对象。当获取对象时,通过键对象的equals()方法找到正确的键值对,然后返回值对                  象。HashMap使用链表来解决碰撞问题,当发生碰撞了,对象将会储存在链表的下一个节点中。 HashMap在每个链表节点中储存键值对对象

原创粉丝点击