List、Set、Map三者区别
- List:List接口可存储重复数据,有序对象。
- Set:不允许重复的集合,无序存储。
- Map:使用键值对存储。Map会维护与Key有关联的值。两个Key可以引用相同的对象,但Key不能重复。
ArrayList与LinkedList的区别?
是否保证线程安全
ArrayList
和 LinkedList
都是不同步的,也就是不保证线程安全。
底层数据结构
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
接口
public interface RandomAccess {
}
RandomAccess接口并没有什么方法定义,其实只是一个标识而已,主要用来标识实现了这个接口的类具有随机访问功能。
在集合实现类当中,方法 binarySearch()
,会判断传入的list是否有 RandomAccess
的实例,如果有,调用 indexedBinarySearch()
方法,如果没有,调用 iteratorBinarySearch()
方法。
public static <T> int binarySearch(List<? extends Comparable<? super T>> list, T key) {
if (list instanceof RandomAccess || list.size()<BINARYSEARCH_THRESHOLD)
return Collections.indexedBinarySearch(list, key);
else
return Collections.iteratorBinarySearch(list, key);
}
ArrayList
实现了 RandomAccess
接口, LinkedList
没有实现。
因为 ArrayList
底层就是基于数组实现的,数组本身在查询的时候,就具有随机访问的能力,时间复杂度为O(1)。 而 LinkedList
底层是基于链表实现的,链表需要遍历到特定的的位置才能访问指定位置的元素,时间复杂度为O(n)。ArrayList
实现了 RandomAccess
接口,就表明他有快速访问的能力。
关于List遍历的选择
- 实现了
RandomAccess
接口的list,优先选择普通for循环,其次是foreach。 - 未实现
RandomAccess
接口的list,有限选择iterator遍历(foreach遍历底层也是通过iterator实现的),大size的数据,千万不要使用普通的for循环。