List、Set、Map三者区别

  • List:List接口可存储重复数据,有序对象。
  • Set:不允许重复的集合,无序存储。
  • Map:使用键值对存储。Map会维护与Key有关联的值。两个Key可以引用相同的对象,但Key不能重复。

ArrayList与LinkedList的区别?

是否保证线程安全

ArrayListLinkedList 都是不同步的,也就是不保证线程安全。

底层数据结构

ArrayList 底层使用的是 Object 数组。
LinkedList 底层使用的是双向链表的数据结构。

插入和删除是否受元素位置的影响

ArrayList 采用数组存储,所以插入和删除的位置受元素位置影响。如果是 add(E e) 方法,会插入到集合的末尾,时间复杂度为 O(1) ,如果是 add(int index, E e) 方法。这种情况下要进行元素迁移,时间复杂度为 O(n)
LinkedList 采用链表存储,所以对 add(E e) 方法的插入,删除元素的时间复杂度不受元素影响,近似O(1),如果要在指定位置插入和删除的话,执行 add(int index, E e) ,时间复杂度近似为 O(n) ,因为需要先移动到指定位置再插入。

是否支持快速随机访问

LinkedList 不支持高效的随机元素访问,而 ArrayList 支持,快速随机访问时通过元素的序号快速获取元素对象( get(int index) 方法)

内存空间占用

ArrayList 的空间主要浪费在List列表的结尾会预留一定的容量空间。而 LinkedList 的空间花费在每一个元素都需要存放数据,前驱节点和后继节点。

关于 RandomAccess 接口

  1. public interface RandomAccess {
  2. }
  3. RandomAccess接口并没有什么方法定义,其实只是一个标识而已,主要用来标识实现了这个接口的类具有随机访问功能。

在集合实现类当中,方法 binarySearch() ,会判断传入的list是否有 RandomAccess 的实例,如果有,调用 indexedBinarySearch() 方法,如果没有,调用 iteratorBinarySearch() 方法。

  1. public static <T> int binarySearch(List<? extends Comparable<? super T>> list, T key) {
  2. if (list instanceof RandomAccess || list.size()<BINARYSEARCH_THRESHOLD)
  3. return Collections.indexedBinarySearch(list, key);
  4. else
  5. return Collections.iteratorBinarySearch(list, key);
  6. }

ArrayList 实现了 RandomAccess 接口, LinkedList 没有实现。
因为 ArrayList 底层就是基于数组实现的,数组本身在查询的时候,就具有随机访问的能力,时间复杂度为O(1)。 而 LinkedList 底层是基于链表实现的,链表需要遍历到特定的的位置才能访问指定位置的元素,时间复杂度为O(n)。
ArrayList 实现了 RandomAccess 接口,就表明他有快速访问的能力。

关于List遍历的选择

  • 实现了 RandomAccess 接口的list,优先选择普通for循环,其次是foreach。
  • 未实现 RandomAccess 接口的list,有限选择iterator遍历(foreach遍历底层也是通过iterator实现的),大size的数据,千万不要使用普通的for循环。