HashMap要点总结
HashMap分析
线性表:ArrayList
ArrayList:进行节点的添加与删除的代价是非常高的:原因在于,当删除节点的时候他要把相应的节点后边的元素往前移一位覆盖掉之前的元素。增加一个节点同样如此。
它的特殊导致我们经常犯一些错误:
for (int i = 0; i < arrayList.size(); i++) {
arrayList.remove(i);
}
这个例子就是典型的由于不够了解底层数据结构导致的错误。
// 正确的操作 尾删除法,也可以使用头删法(删除index=0) 但是 头删法每次删除以后都要做一次前移操作很消耗资源
int size = arrayList.size();
for (int i = 0; i < size; i++) {
arrayList.remove(arrayList.size() - 1);
}
在Hashmap中定位元素在顺序表中的index采用了
static int indexFor(int h, int length) { //jdk1.7的源码,jdk1.8没有这个方法,但是实现原理一样的
return h & (length-1); //第三步 取模运算
}
顺序表的长度一般都为素数,这样做可以最大程度减小冲突发生的概率。
但是为什么hashMap中的顺序表为2的倍数?
这样做就是因为当它的长度为2的倍数时直接对长度-1 & hash 结果等于求模运算,这样效率更高。
在JDK1.8的实现中,优化了高位运算的算法,通过hashCode()的高16位异或低16位实现的:(h = k.hashCode()) ^ (h >>> 16),主要是从速度、功效、质量来考虑的,这么做可以在数组table的length比较小的时候,也能保证考虑到高低Bit都参与到Hash的计算中,同时不会有太大的开销。
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}