HashMap主要是用数组来存储数据的.数组存储的是链表,链表是为了解决哈希冲突的. 几个关键的属性 存储数据的数组 transient Entry[] table; 这个上面已经讲到了 默认容量 static final int DEFAULT_INITIAL_CAPACITY = 16; 最大容量 static final int MAXIMUM_CAPACITY = 1 =容量*加载因子时,HashMap会将容量扩容 static final float DEFAULT_LOAD_FACTOR = 0.75f; 当实际数据大小超过threshold时,HashMap会将容量扩容,threshold=容量*加载因子 默认为12 int threshold; 加载因子 final float loadFactor; HashMap的初始过程 构造函数1 Java代码 public HashMap(int initialCapacity, float loadFactor) { if (initialCapacity MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; if (loadFactor = initialCapacity int capacity = 1; while (capacity >> 14); h += (h >> 10); return h; } private static int newHash(int h) { // This function ensures that hashCodes that differ only by // constant multiples at each bit position have a bounded // number of collisions (approximately 8 at default load factor). h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4); } 其实HashMap的哈希函数会一直都是oldHash。 如何扩容? 当put一个元素时,如果达到了容量限制,HashMap就会扩容,新的容量永远是原来的2倍。 上面的put方法里有这样的一段: Java代码 if (size++ >= threshold) resize(2 * table.length); 这是扩容判断,要注意,并不是数据尺寸达到HashMap的最大容量时才扩容,而是达到 threshold指定的值时就开始扩容, threshold=最大容量*加载因子。 看看resize方法 Java代码 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); } 重点看看红色部分的 transfer方法 Java代码 void transfer(Entry[] newTable) { Entry[] src = table; int newCapacity = newTable.length; for (int j = 0; j e = src[j]; if (e != null) { src[j] = null; do { Entry<k> next = e.next; int i = indexFor(e.hash, newCapacity); e.next = newTable[i]; newTable[i] = e; e = next; } while (e != null); } } } tranfer方法将所有的元素重新哈希,因为新的容量变大,所以每个元素的哈希值和位置都是不一样的。 一开始要估计好容量的大小 否则等到自动扩充的时候要将所有元素的hash重算一遍,照成浪费。 总结:应该制衡时间与空间。</k>