目录
二、 数据是怎么插入到HashMap里面的?是怎么取出来的?
七、 HashMap与ConcurrentHashMap有什么区别?
八、HashMap、TreeMap和ConcurrentHashMap的key 能为null嘛?
一、什么是哈希表?
答: 哈希表也叫散列表,是一种非常重要的数据结构,许多缓存技术的核心就是内存中一张非常大的哈希表。读取元素的时间复杂度为0(1)。
二、 数据是怎么插入到HashMap里面的?是怎么取出来的?
答:
存值: HashMap的底层在JDK1.8的时候是一个数组+链表+红黑树,数据会通过哈希算法计算出一个哈希值,然后根据哈希值转换为内存的实际存储地址,接着根据地址将元素插入到数组中。在插入元素的时候可能会存在不同元素计算出同一个哈希值的情况,此时就会出现哈希冲突。HashMap是根据链地址法解决哈希冲突,即如果出现冲突,那么会在同前的位置使用链表来将新的元素新增进去。如果链表的长度大于8时,那么就会自动转换成红黑树结构,也就说明啦HashMap的数据结构是数组+链表+红黑树。
取值: HashMap通过get(key)方法将key对应的value取出,实际上是执行get(key)时,会根据该key来做一个哈希计算,求出一个哈希值,然后根据该哈希值找出内存中的实际存储地址,即就能得到数组的下标,如果该位置有值就要比较该位置的元素是否与要取的元素相等,如果不相等,那么就要将指针后移,遍历链表,直到找到该值并返回。如果没有值,那么会返回一个空值。
三、HashMap的默认大小为多大?
答: HashMap的默认长度为16,默认的扩容倍数为2。
四、HashMap最适合的负载因子是多少?
答: 0.75,因为负载因子过大,哈希碰撞冲突的概率会加大,找值效率会降低,设置过小,那么会经常会出现扩容的情况,HashMap的性能会因为经常扩容导致大幅度下降。
五、 HashMap的长度可以为奇数嘛?
答: 不可以。
从key映射到HashMap的数组的对应位置时,会用到一个hash函数:
index = HashCode(Key) & (Length - 1)
如果Length的长度为奇数,假设长度为15, Length-1转换为二进制后为 1110 ,假设此时的hashCode为
101110001110101110 1011, 做&运算得出的index结果为: 101110001110101110 1010, 如果 此时的hashCode为101110001110101110 1010,同样的做&运算,发现得出啦相同的index。看似好像没有很大的问题,因为我们在用hashmap的时候出现哈希值相等的情况还是有的。再看一种情况,如果长度为9,那么Length-1 转换为二进制的结果为1000, 那么只要hashCode的最后三位不相同,计算出来的结果仍然是一样的,那么此时的index会更容易出现,并且此时的index的最后三位永远不会出现111的情况,这样的话,不符合Hash算法的均匀分布原则。
假如长度为16,那么length-1对应的二进制位1111,那么计算哈希code的时不会影响index出现的概率,符合均匀分布的设计原则。 因此HashMap的长度一般为2^n, 默认的长度为16。
六、 HashMap是线程安全的嘛?
答: hashmap是非线程安全的。
七、 HashMap与ConcurrentHashMap有什么区别?
答: concurrentHashMap是线程安全的jdk1.7之前使用分段锁的形式实现的,1.7后使用voliatile+CAS+sysnchronize实现同步。hashmap是非线程安全的。
八、HashMap、TreeMap和ConcurrentHashMap的key 能为null嘛?
答: hashmap能够存null值作为key, treemap和concurrenthashmap都不能存nulll为key。可以查看源代码的putVal()方法,concurrentHashMap的key和value为null时就会抛出空指针异常。
treemap默认初始化不包含comparator , 当key 为null时,抛出空指针异常。
下面是hashtable、concuurentHashMap、TreeMap、HashMap的区别:
九、HashMap 的put()方法返回的结果?
put()方法返回结果有2种情况:
- 如果key在map里不存在,那么返回结果为null。
- 如果key已经在map里,那么返回结果为之前key对应的value,也就是返回的是旧值。