三个集合接口的引出?
答:Java集合,从上层接口看出分为了两类,Map和Collection.而Collection接口的子接口又包括了Set和List接口。
Map、List和Set都是Collection的子接口嘛?
答:Map是和Collection并列的集合上层接口,没有继承关系;List和Set是Collection的子接口
说一说Java常见的集合类?
- Map接口和Collection接口是所有集合框架的父接口
- Collection接口的子接口包括Set接口和List接口
- Map接口的实现类主要有:HashMap、TreeMap、HashTable、LinkedHashMap、ConcurrentHashMap以及Properties等
- Set接口的实现类主要有:HashSet、TreeSet、LinkedHashSet等
- List接口的实现类主要有:ArrayList、LinkedList、Stack以及Vercotr等
ArrayList和LinkedList的区别?
说一说HashMap整体的数据结构?
答:HashMap的底层是数组+链表+红黑树的数据结构,主要作用是方便快速查找,时间复杂度为O(1),默认大小是16,数组的下标是通过Key的HashCode计算出来的,数组元素叫做Node,当多个Key的HashCode一致,但是Key值不同时,单个Node就会转换为链表,链表的查询复杂度是O(n),当链表的长度大于等于8并且数组的大小超过64时,链表就会转换为红黑树,红黑树的复杂度是O(log(n)),简单来说,最坏的时间查询次数相当于红黑树的最大深度。
HashMap和HashTable的区别?
- HashMap没有考虑同步,是线程不安全的;HashTable使用了Synchronized关键字,是线程安全的
- HashMap允许null值作为Key;HashTable不允许null作为key,HashTable的Value也不允许为null.HashMap 遇到 key 为 null 的时候,调用 putForNullKey 方法进行处理(统一放入table[0]位置),而对 value 没有处理;Hashtable遇到 null,直接返回 NullPointerException.
HashMap是线程不安全的,那举一个例子?
HashMap线程不安全主要是考虑了多线程环境下进程扩容可能出现HashMap死循环
HashTable线程安全是由于其内部实现在put和remove等方法上使用synchronized进行了同步,所以对于单个方法的使用是线程安全的。但是对于多个方法进程复合操作时,线程安全无法保证。比如一个线程在进行get操作,一个进程在进行remove操作,往往会导致下标越界等异常。
HashMap的初始容量,负载因子,扩容增量是多少?
答:HashMap的初始容量是
16
,加载因子为0.75
,扩容增量是原容量的1倍。 eg:如果HashMap的容量是16,一次扩容后的容量为32,HashMap扩容是指元素个数(包括数组合链表+红黑树)超过了16*0.75=12之后开始扩容。
HashMap的扩容步骤?
答:HashMap里面默认的负载因子大小默认为0.75,也就是说当Map中的元素个数(包括数组合链表+红黑树)超过了160.75=12之后开始扩容。将会创建原来HashMap大小的两倍的bucket数组,来重新挑这个Map的大小,并将原来的对象放入新的bucket数组中。这个过程叫做rehashing,因为它调用hash方法找到新的bucket位置,但是,要注意*多线程环境下,HashMap可能会导致死循环。
①. 空数组是否初始化,没有初始化初始化
②. 如果通过key的hash能够直接找到值,跳转到6否则3
③. 如果hash冲突,两种解决方案:链表 or 红黑树
④. 如果是链表,递归循环,把新元素追加到队尾
⑤. 如果是红黑树,调用红黑树新增方法
通过②④⑤将新元素追加成功,再根据onlfifAbsent哦按段是否需要覆盖<保证key唯一>
判断是否需要扩容,需要扩容进行扩容,结束。
Map的hash算法
首先计算出Key的hashCode值,因为Key是Object,会根据Key的不同类型进行hashCode计算,接着计算h^h>>>16,这样做的好处是在大多数场景下计算出的hash值比较分散。
为什么不用Key%数组大小,而是需要key的Hash值%数组大小?
答:如果Key是数字,直接使用Key%数组大小完全没有问题,但Key有可能是字符串,是复杂对象,这样用字符串或复杂对象%数组大小是不行的。
未解决hash冲突,大概都有哪些方法?
- 拉链法(HashMap使用的方式)
- 线性探测再散列法
- 二次探测再散列法
- 伪随机探测再散列法
哪些类适合作为HashMap的键?
String和Integer这样的包装类很适合作为HashMao的键,因为它们都是final类型的类,而且重写了equals和hashCode方法,避免了键值对改写,有效提高了hashMap的性能。
ConcurrentHashMap和HashTable的区别?
ConcurrentHashMap结合了HashMap和Hashtable二者的优势,HashMap没有考虑到同步,HashTable考虑到了同步的问题,但是HashTable在每次同步执行时都要锁住整个结构。
ConcurrentHashMap锁的方式是细粒度的,ConcurrentHashMap将hash表分为16个桶(默认值),诸如get、put、remove等常用操作只锁在当前需要用的桶上。
ConcurrentHashMap的具体实现方式(分段锁):Segment是一种可重入的锁ReetrantLock,每个Segment守护一个HashEntry数组里的元素,党对HashEntry数组的数据进行修改时,必须首先获得对应的Segment锁。