1 HashMap问题总结
1.1 迭代map的两种方式:
- 通过entrySet() 得到返回类型Set< Map.Entry< K, V > >,引用设为set,然后通过iterator来迭代
- 通过keySet()得到所有的key,再组合map.get(Object K)返回对应的values值。也通过iterator迭代
通过map.toString()可以直接获得键-值集
1.2 为什么加载因子默认值是0.75?
加载因子也叫扩容因子,用于决定HashMap数组何时进行扩容。所谓的扩容指的是重新创建一个指定容量的数组,然后将旧值复制到新的数组里。扩容这个过程非常耗时,会影响程序性能。所以加载因子是基于容量和性能之间平衡的结果
- 当加载因子过大时,扩容阈值也变大,也就是说扩容的门槛提高了,这样容量的占用就会降低。但这时哈希碰撞的几率就会增加,效率下降;
- 当加载因子过小时,扩容阈值变小,扩容门槛降低,容量占用变大。这时候哈希碰撞的几率下降,效率提高。
容量占用和性能是此消彼长的关系,它们的平衡点由加载因子决定,0.75是一个即兼顾容量又兼顾性能的经验值(统计值)。
1.3 如何得到key的哈希值?
通过hash(Object key)方法,返回哈希值
如果key为null,返回0,不为null,则通过 (h = key.hashCode()) ^ (h >>> 16) 公式计算得到哈希值。该公式通过hashCode的高16位异或低16位得到哈希值,主要从性能、哈希碰撞角度考虑,减少系统开销,不会造成因为高位没有参与下标计算从而引起的碰撞。
1.4 如何得到插入元素在数组中的下标
通过公式(n - 1)& hash ,计算出插入元素在数组中的下标 。hash为key的哈希值。 以数组默认长度16为例,得到的下标值都小于16。
1.5 什么情况下会替换掉旧值?
Node<K,V> e; K k;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
由源码可以看出,
- 条件一:新旧元素的hash值相同。(但此时key不一定相等,因为不同的key也可能有相同的hash值。这里使用了短路运算)
- 条件二:新旧元素的key相等。(1."==“相等,即key是数字,并且新旧相等。2.”.equals"相等,即key是字符串,新旧相等)
- 注:为链表结构时的判断方法也与这里替换数组下标元素的方法相同
1.6 链表转换为红黑树的条件?
- 条件一:链表长度大于等于8
- 条件二:数组长度大于等于64
2 hashmap和treemap的区别?
- hashmap底层基于数组+链表+红黑树的实现,treemap底层基于红黑树
- hashmap允许key和value为空 treemap中key不允许为空
- treemap中key的类型必须 要一致
3 List和Set的区别?
- List 允许出现 重复元素 Set不允许出现重复元素
|