2.1 Java中有哪些容器(集合类)?
2.2Java中的容器,线程安全和线程不安全的分别有哪些?
java.util包下单集合类大部分是线程不安全的,如常见的HashSet、TreeSet、ArrayList、LinkedList、HashMap、TreeMap,它们的优点是性能好。可以使用Collections工具提供的synchronizedXxx()方法,把这些线程不安全的集合类包装成线程安全的。
java.util包下单线程安全的如vector 、HashTable
2.4 描述一下Map put的过程
1.首次扩容:先判断数组是否为空,如数组为空则进行第一次扩容
2.计算索引:通过hash算法,计算键值对在数组中的索引
3.插入数据:
如果当前位置元素为空,则直接插入数据
如果当前位置元素非空,且key已存在,则直接覆盖其value
如果当前元素非空,且Key不存在,则将数据链接到链表的末端
如果链表的长度达到8,则将链表转换为红黑树,并将数据插入到树中
4.再次扩容
如果数组中元素个数(size) 超过threshold,则再次进行扩容操作
2.5 如何得到一个线程安全的Map?
1.使用Collections工具类,将线程不安全的Map包装成线程安全的Map
2.使用java.util.concurrent包下的Map,如ConcurrentHashMap
3.不建议使用Hashtable,虽然线程安全但性能差
2.6 HashMap有什么特点?
线程不安全,K V 可以为null
2.7 JDK7和JDK8中的HashMap有什么区别?
JDK7 数组+链表;链表长度可能巨大,查询效率低O(n);底层Entry数组
JDK8 数组+链表+红黑树;链表长度超过8转红黑树;查询效率高O(logn);底层Node数组
2.8 介绍一下HashMap底层的实现原理
基于hash算法,通过get put获取和存储对象
put时,调用k的hashCode计算哈希值,得到bucket位置,进一步存储。HashMap会根据bucket占用情况自动调整整个容量(超过Load Facotr则resize为原来的两倍);
get时,通过k计算哈希值得到bucket位置,进一步调用equals方法确定键值对;
如果发生哈希冲突时,将冲突的元素用链表(冲突个数<8,超过8自动转为红黑树)或红黑树组织
2.9 介绍一下HashMap的扩容机制
扩容都是以2的次方扩充的(重新计算扩容的新索引快);
判断扩容的条件是:负载因子,默认0.75,可以设置大于1的负载因子,禁止扩容;
当链表长度达到一个阈值(7或8)转换为红黑树 ,当链表长度小于阈值(6)又将红黑树转换为链表;(在进行转换为红黑树前,还会先检测当前数组是否达到阈值64,如果咩有,先扩容)
2.10 HashMap中的循环链表是如何产生的?
在多线程情况下,当重新调整HashMap大小就会存在条件竞争