ArrayList和LinkedList的简介,以及对比
恩,由于面向面试所以比较简洁。
基于链表实现的方式使得 LinkedList 在插入和删除时更优于 ArrayList,而随机访问则比 ArrayList 逊色些。ArrayList不适合在具体的index下插入元素,那样需要移动数组。
ArrayList
动态数组,初始长度可以通过构造函数设定,默认为10(jdk1.6以后),允许null值。
ArrayList相当于在没指定initialCapacity时就是会使用延迟分配对象数组空间,当第一次插入元素时才分配10(默认)个对象空间。假如有20个数据需要添加,那么会分别在第一次的时候,将ArrayList的容量变为10;之后扩容会按照1.5倍增长。也就是当添加第11个数据的时候,Arraylist继续扩容变为10*1.5=15;当添加第16个数据时,继续扩容变为15 * 1.5 =22个。:
插入一个元素时数组大小为10
插入10个元素时数组大小还为10
插入11个元素时数组大小变为15
每次扩容都是通过Arrays.copyOf(elementData, newCapacity) 这样的方式实现的。在构造 ArrayList 时可以给 ArrayList 指定一个初始容量,这样就会减少扩容时数据的拷贝问题。当然在添加大量元素前,应用程序也可以使用 ensureCapacity 操作来增加 ArrayList 实例的容量,这可以减少递增式再分配的数量。
为什么每次扩容处理会是 1.5 倍,而不是 2.5、3、4 倍呢?通过 google 查找,发现 1.5 倍的扩容是最好的倍数。因为一次性扩容太大(例如 2.5 倍)可能会浪费更多的内存(1.5 倍最多浪费 33%,而 2.5 被最多会浪费 60%,3.5 倍则会浪费 71%……)。但是一次性扩容太小,需要多次对数组重新分配内存,对性能消耗比较严重。所以 1.5 倍刚刚好,既能满足性能需求,也不会造成很大的内存消耗。
线程不安全
LinkedList
同样实现List接口,不过底层是链表实现的。
双端链表,适合添加删除操作。不适合查找,尤其是远离两头的元素。
不是线程安全的,这里就不展开了
常用方法
- get(int index):返回此列表中指定位置处的元素。
- getFirst():返回此列表的第一个元素。
- getLast():返回此列表的最后一个元素。
- indexOf(Object o):返回此列表中首次出现的指定元素的索引,如果此列表中不包含该元素,则返回 -1。
- lastIndexOf(Object o):返回此列表中最后出现的指定元素的索引,如果此列表中不包含该元素,则返回 -1。