概述:尽管已经将java核心编程中的集合看了好几遍了,但是还是感觉心里没有低;所以今天特别将集合这块常见的面试题进行总结,一边加深自己对java集合的理解;
<1>:谈谈你对HashMap具体实现的理解:
首先,hashMap是一个键值对类型的集合,他的键和值都可以为null;
使用hashMap存储数据时,首先我们键会先调用它的hashCode方法生成一个hashCode值,然后对这个的hashCode值再进一次移位的运算;
//java中的抖动函数
static final int hash(Object Key){
int h;
if(key== null){
return null
}else{
return key==null ? 0:((h=h.hashCode) ^ h>>>16)
}
}
当然这样得到的hash值是不能直接作为数组的索引存储的;太大的;改进后的hashMap初始容量才是16;所以我们还需要对这个得到的值进行一次模运算:
static int indexFor(int hash, int length) {
return hash & (length-1);
}
得到的结果便是我们想要存储的bucket的位置;此时如果篮子中没有值,我们直接将值放进这个bucket中键即可;如果有值即产生了我们所谓的hash冲突了;
散列表要解决的一个问题就是散列值的冲突问题,通常是两种方法:链表法和开放地址法。
链表法就是将相同hash值的对象组织成一个链表放在hash值对应的槽位;
开放地址法是通过一个探测算法,当某个槽位已经被占据的情况下继续查找下一个可以使用的槽位。java.util.HashMap采用的链表法的方式,链表是单向链表。形成单链表的核心代码如下:
void addEntry(int hash, K key, V value, int bucketIndex) {
if ((size >= threshold) && (null != table[bucketIndex])) {
resize(2 * table.length);
hash = (null != key) ? hash(key) : 0;
bucketIndex = indexFor(hash, table.length);
}
createEntry(hash, key, value, bucketIndex);
}
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++;
}