ArrayList
ArrayList就是数组列表,是一个动态数组,其容量能自动增长。
特点:查询效率高,增删效率低,线程不安全,日常使用频率高。
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
//默认容量
private static final int DEFAULT_CAPACITY = 10;
//new ArrayList<>(0)时,就会调用this.elementData=EMPTY_ELEMENTDATA
private static final Object[] EMPTY_ELEMENTDATA = {};
//new ArrayLisT<>()时,即获得这个空数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//数据都存储在Object[] elementData中
transient Object[] elementData; // non-private to simplify nested class access
//size,指的是elementData中含有元素的数量,而不是数组的大小
private int size;
..........
}
ArrayList的构造方法
public ArrayList()//构造一个空数组,在第一次add添加元素的时候,会把该数组扩容成容量为(DEFAULT_CAPACITY=10指定)的数组
public ArrayList(int initialCapacity)//构造一个指定容量大小的数组
public ArrayList(Collection<? extends E> c)//构造一个包含指定 collection 的元素的列表
ArrayList新增方法
1. public boolean add(E e) //在数组的尾部增加元素
2. public void add(int index, E element)//将>=index位置的元素往后移动一位,然后在指定位置index处插入该元素
3. public boolean addAll(Collection<? extends E> c)//在数组尾部添加一个Collection中的所有元素
4. public boolean addAll(int index, Collection<? extends E> c)//原理同2
这里详解一下新增逻辑
public boolean add(E e) {
//校验容量是否够,如果容量不够会进行扩容*
ensureCapacityInternal(size + 1); // Increments modCount!!
//校验完(不足扩容后),再把该元素加入到数组尾部,数组元素个数(size)+1
elementData[size++] = e;
return true;
}
//下面看一下扩容方法(minCapacity指的是要容纳新增 元素 后最小所需的容量)
private void grow(int minCapacity) {
// 获取当前容量大小
int oldCapacity = elementData.length;
// 获取增长1.5倍后容量的大小
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 如果扩大1.5倍后容量 还不足够*
if (newCapacity - minCapacity < 0)
//则新数组的容量大小直接确定为minCapacity
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
//扩容,Arrays.cpoyOf会返回一个新的数组(保留原来数组的值)
elementData = Arrays.copyOf(elementData, newCapacity);
}
常用方法
在数组的尾部增加元素
- public boolean add(E e)
在指定位置处插入元素
- public void add(int index, E element)
在数组尾部添加该Collection中的所有元素
- public boolean addAll(Collection<? extends E> c)
在指定位置插入Collecton中的所有元素
- public boolean addAll(int index, Collection<? extends E> c)
移除此列表中的所有元素(底层实现为for循环遍历数组,给所有值=null,size=0)
- public void clear()
克隆数组列表(tip:
浅克隆
)
- public Object clone()
是否包含该元素
- public boolean contains(Object o)
返回数组列表中指定位置的元素
- public E get(int index)
返回数组列表中
首次出现
指定元素的下标
- public int indexOf(Object o)
返回数组列表中
最后一次出现
指定元素的下标
- public int lastIndexOf(Object o)
数组列表中的元素是否为0
- public boolean isEmpty()
删除指定位置
删除指定元素
删除指定范围[fromIndex,toIndex)内的元素
- public E remove(int index)
- public boolean remove(Object o)
- protected void removeRange(int fromIndex, int toIndex)
替代指定位置的元素
- public E set(int index, E element)
以数组的形式返回数组中所有的元素
- public Object[] toArray()
Vector
Vector
和ArrayList
类似, 区别在于Vector是同步类(synchronized)。故线程安全
特点:线程安全,有增长因子这个概念
构造方法
1. public Vector()
2. public Vector(int initialCapacity)
3. public Vector(Collection<? extends E> c)
//前面三个都和ArrayList的类似,多了第四个构造方法,其中第二个参数capacityIncrement是增长因子
4. public Vector(int initialCapacity, int capacityIncrement)
扩容源码解析
新增逻辑和ArrayList逻辑相同,但是扩容代码有些不同
在JDK1.8中,ArrayList的扩容是1.5倍
`下方源码可知,如果设置了增长因子,则扩容容量=旧容量+增长因子,否则=2*旧容量
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
//如果设置了增长因子,则扩容容量=旧容量+增长因子,否则=2*旧容量
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
LinkedList
双向链表
,在添加和删除元素时具有比ArrayList更好的性能.但在get与set方面弱于ArrayList.
特点:双向链表,继承了Deque接口,所以有peek、pool、pop、push等方法
链表在get和set方面比较耗时
public E get(int index) {
//检查index是否溢出
checkElementIndex(index);
//返回指定位置元素
return node(index).item;
}
//查找index位置的Node
Node<E> node(int index) {
// assert isElementIndex(index);
// index在链表的左半侧
if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
// index在链表的左半侧
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
由上面源码可知,get方法是从0遍历到index,或者从size-1遍历到index的,耗时都是非常高的。