目录
1、arrayList 与linkedList的区别?
他们都是继承自List,不同的是
arraylist的底层实现是基于数组,linkedList的底层实现是基于链表,
因此对于随机访问,get,set,arrayList要优于linkedList
对于新增和删除,linkedList 要优于 arrayList。
此外,linkedList还提供了list中没有的方法,专门用于操作表头和表尾,可用于堆栈、队列和双向队列使用。
2、HashMap和hashTable的区别?
① 父类不同:
HashMap继承自 abstractMap类,hashTable继承自direction类
二者都实现了Map,cloneable、serializable接口
② 对外提供的接口不同:
hashtable比hashMap多提供了两个接口 elements() 和contains
③ 对null的支持不同
hashtable 键值都不能为null,hashmap 键值可以为null,但为null的键只能有一个
④ 安全性不同:
hashMap非线程安全,jdk1.8之前多线程情况下会发生死锁,会发生数据丢失
hashtable线程安全,所有的方法都是用了sychonized关键字修饰
由此可引申一点。hashtable的21效率比hashmap低
⑤ 初始容量和每次扩容的大小不同
⑥ 计算hash值的方法不同
3、collection与 collections的区别?
1、 collection是集合类的上层接口,List 、Set、都继承于他
2、collections是集合类的一个帮助类。内部包含了操作集合的一些静态方法。不能实例化,就想一个工具类。
4、List、Set、Map的区别?
List用于存储一组不唯一、有序的对象
Set用于存储无序、唯一的对象。
Map存储键值对,键唯一。
5、Map有什么特点?
1、以键值对存储数据
2、元素存储是无序的
3、不允许重复键
6、Vector和arrayList的区别?
1、Vector是线程安全的,ArrayList是非线程安全的
2、扩容大小不同,扩容时arrayList默认扩展50%,Vector默认扩展一倍。
7、HashSet如何保证值不重复的?
看源码可知,HashSet存储元素实际上用的是内部维护的一个HashMap,把元素作为Key,存储到HashMap中,HashMap特性可知,key是不允许重复的,所以HashSet值不会重复。如果还要再细问,那实际上就是在问HashMap的Key为啥不重复了,太熟了。八股巴拉巴。
8、HashSet的6个核心方法?
add、remove、clear、size、contains、isEmpty、
9、HashMap、linkedHashMap、TreeMap的区别?
1、hashMap存储无序。2、LinkedHashMap
是HashMap
的一个子类,它在HashMap
的基础上维护了一个双向链表,用于记录插入的顺序。以此输出时可以按插入顺序输出。而且还可以通过设置accessOrder = true, 实现每次get都将元素放在尾部,实现了LRU的效果。
3、TreeMap对key进行了排序,可以按照默认顺序或自定义键的顺序。
10、JUC包有哪些好用的数据结构?
ConcurrentHashMap : 线程安全的 HashMap
CopyOnWriteArrayList : 线程安全的 List,在读多写少的场合性能非常好,远远好于 Vector。
ConcurrentLinkedQueue : 高效的并发队列,使用链表实现。可以看做一个线程安全的 LinkedList,这是一个非阻塞队列。
BlockingQueue : 这是一个接口,JDK 内部通过链表、数组等方式实现了这个接口。表示阻塞队列,非常适合用于作为数据共享的通道。
ConcurrentSkipListMap : 跳表的实现。这是一个 Map,使用跳表的数据结构进行快速查找
11、ConcurrentHashMap 为什么不允许插入null值?而HashMap可以
原作者指出,主要目的是防止并发场景下的歧义问题。HashMap是单线程场景下,所以不受限制
12、ArrayList的自动扩容过程?
初始化:在jdk版本(<=jdk6中)无参构造方法创建一个 ArrayList 对象时,会分配一个初始容量的数组,通常是 10 个元素。在jdk版本(>jdk6)中 ,容量为0,通过add方法加入后容量会自动扩容为10。
添加元素:当添加元素到 ArrayList 时,会检查当前数组的容量是否足够。如果容量足够,直接将元素添加到数组中。
扩容检查:如果当前数组的容量不够,ArrayList 会检查是否需要扩容。
扩容:如果需要扩容,ArrayList 会创建一个新的数组,大小是当前数组大小的 1.5 倍。然后,将当前数组的所有元素复制到新的数组中。
更新容量:更新 ArrayList 的容量为新的数组大小。
13、HashMap是线程安全的吗?多线程下有什么问题?
1、扩容死循环。jdk1.7中,使用头插法插入元素,多线程同事进行扩容操作时,可能形成环形链表,从而死循环。1.8后改成了尾插法,避免了死循环的问题。
2、元素丢失。多线程同时执行put操作,如果hash冲突了,会造成前一个key被后一个取代的情况
3、get为null. 当一个put操作导致扩容时,另一个线程执行get操作,可能导致get为null的情况。
如何解决?
使用currentHashMap
使用synchonized 关键字修饰hashMap
使用其他锁
14、HashMap的put流程?
1、初始化数组resize()
2、创建node,计算数组下标,看该位置是否有数据,不存在直接放入数组。
3、如果存在,判断hash值和key是否相等,相等,直接替换value
4、如果不相等,看是红黑树结构还是链表结构,是树结构,则调用树的add操作
5、如果是链表结构,则放入链表尾部,如果长度大于8,则树化。
6、树化条件,数组长度大于等于64,不够则扩容。
15、HashMap的扩容流程
16、链表转红黑树的条件?
数组长度大于等于64,链表长度大于等于8
17、为什么要用红黑树不用其他数据结构?
1、不上来就直接使用红黑树是因为如果没有hash冲突的话,数组的直接查询速度是更高的。红黑树需要进行复杂的循环操作,效率不高。
2、之所以选择在链表长度为8时进行转化,是一个大量数据统计测试后得出的性能最佳方案。
3、之所以不用B树等其他树结构是因为在极端情况下,其他树会出现树倾斜的问题,造成查询效率大大下降。或者某些严格平衡树那样,造成put效率过低。最终择优选择了红黑树。
18、