参考资料:常见数据结构总结_龚礼鹏的博客-CSDN博客
一.谈一谈List、Map和Set的区别?
List:有序、可重复、单列数据。List存储的数据是有序的并且可重复的单列数据的集合。
Set:唯一、不可重复、单列数据。Set存储的数据是唯一的无序的单列数据的集合。
Map:键值对。Map存储的是键值对这样双列数据的集合。
参考:三大集合:List、Map、Set的区别与联系_Star_Li_92的博客-CSDN博客_list map set的区别
二.谈一谈ArrayList和LinkedList的区别?
1.基于的数据结构:ArrayList是基于数组的数据结构,分配的是一段连续的存储空间,存储在栈中。LinkedList是基于双向链表的数据结构,存储在堆中。
2.由于ArrayList是基于数组的数据结构,所以根据index索引查询和修改数据效率高( O(1) ),新增和删除效率低,因为新增数据需要考虑的数组的容量,可能发生扩容操作,删除数据除了最后一个数据删除其他数据都要移动数组中的元素( O(n) )。
3.LinkedList对比ArrayList查询和修改数据效率较低,因为是双向链表数据结构,需要根据节点一个一个往下(或者往上)寻找( O(n) ),新增和删除数据效率较高,因为只需要改动一下指针即可( O(1) )。
4.存储空间:由于LinkedList是双向链表,所以需要更多的存储空间存储前驱和后驱,所以在存储相同多的数据情况下LinkedList占用更多的存储空间。
参考:https://blog.csdn.net/gongjdde/article/details/118977595
https://blog.csdn.net/gongjdde/article/details/118978012
2019-04-23:谈谈ArrayList和LinkedList的区别? · Issue #36 · Moosphan/Android-Daily-Interview · GitHub
三.说一说ArrayList的扩容机制?
无参的构造方法是初始长度为10的数组,有参的构造方法传入数组的初始长度。扩容是在原先的数组长度的1.5倍(此处用到的算法是:int newCapacity = oldCapacity + (oldCapacity >> 1);),如果长度超过Integer.MAX_VALUE-8,则直接是扩容到最大长度Integer.MAX_VALUE。
参考:https://blog.csdn.net/gongjdde/article/details/118977595
四.请说一下HashMap和HashTable的区别?
1.Hashtable不支持null键和值
2.Hashtable使用synchronized来进行同步(有性能开销)
3.Hashtable的迭代器是fail-safe(安全失败)机制,HashMap的迭代器是fail-fast(快速失败)机制
4.Hashtable默认容量为11且不要求底层数组的容量一定要是2的整数次幂,而HashMap则是16,必须是2的整数次幂.
5.hash值使用不同,HashTable是直接使用对象的hash值,HashMap是通过扰动算法重新计算了hash值
参考:https://github.com/Moosphan/Android-Daily-Interview/issues/39
https://blog.csdn.net/gongjdde/article/details/118978149
五.HashMap实现原理?
1.jdk 1.7是数组+链表的数据结构,jdk 1.8是数组+链表(or红黑树)的数据结构。
2.在jdk1.8中大致流程是如果是无参构造方法先初始化长度为16的一个常量,用于后面数组长度使用,注意此时数组还是空的。
3.然后调用put方法添加数据,添加过程比较复杂:
①.首先根据key的hash值计算出一个新的key的hash值,此处jdk1.8用到了两次扰动算法。
②.然后先判断数组是否为空,如果为空则扩容初始化数组(此处如果原先使用的是HashMap无参的构造方法则是数组初始化容量为16,负载因子为0.75)。
③.然后通过key的新hash值与数组容量-1进行位与算法(类似于hash值与数组容量取余,不过位与算法效率更高)计算出此key的数组下标。
④.根据下标然后找到指定桶的位置,如果是空的则直接将数据插入。
⑤.如果发生了hash冲突,则先看此位置的key是否相同,如果相同则直接替换value值;反之,然后判断此处是红黑树数据结构还是链表数据结构,如果是红黑树数据结构,通过红黑树算法插入此数据,如果是链表数据结构则遍历链表查询是否有相同key,如果有则替换value值,如果没有在尾部插入此数据。如果链表数据长度超过8并且总的数组容量达到64则进行树化。
⑥.如果此时hash的长度大于阈值(数组长度*负载因子)则进行扩容,扩容容量是原先的两倍,然后根据旧数组轮询判断在新数组中的位置,三种情况:如果此处索引是空的,根据位与算法计算出在新数组中的位置;如果是红黑树则单独处理;如果是链表则根据hash值&老数组长度为0还是1判断是否需要挪动位置。
参考:面试必问的HashMap,你真的了解吗?
https://blog.csdn.net/gongjdde/article/details/118978149
2019-03-29:HashMap 的实现原理? · Issue #16 · Moosphan/Android-Daily-Interview · GitHub