ArrayList简介
ArrayList 的底层是数组队列,相当于动态数组。与 Java 中的数组相比,它的容量能动态增长。在添加大量元素前,应用程序可以使用ensureCapacity操作来增加 ArrayList 实例的容量。这可以减少递增式再分配的数量。
它继承于 AbstractList,实现了 List, RandomAccess, Cloneable, java.io.Serializable 这些接口。
在我们学数据结构的时候就知道了线性表的顺序存储,插入删除元素的时间复杂度为O(n),求表长以及增加元素,取第 i 元素的时间复杂度为O(1)
ArrayList 继承了AbstractList,实现了List。它是一个数组队列,提供了相关的添加、删除、修改、遍历等功能。
ArrayList 实现了RandmoAccess 接口,即提供了随机访问功能。RandmoAccess 是 Java 中用来被 List 实现,为 List 提供快速访问功能的。在 ArrayList 中,我们即可以通过元素的序号快速获取元素对象,这就是快速随机访问。
ArrayList 实现了Cloneable 接口,即覆盖了函数 clone(),能被克隆。
ArrayList 实现java.io.Serializable 接口,这意味着ArrayList支持序列化,能通过序列化去传输。
和 Vector 不同,ArrayList 中的操作不是线程安全的!所以,建议在单线程中才使用 ArrayList,而在多线程中可以选择 Vector 或者 CopyOnWriteArrayList。
ArrayList核心代码分析
System.arraycopy()和Arrays.copyOf()方法
首先观察先System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length)的声明:
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
src - 源数组。
srcPos - 源数组中的起始位置。
dest - 目标数组。
destPos - 目标数据中的起始位置。
length - 要复制的数组元素的数量。
该方法是用了native关键字,调用的为C++编写的底层函数,可见其为JDK中的底层函数。
再来看看Arrays.copyOf();该方法对于不同的数据类型都有相应的方法重载。
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
@SuppressWarnings("unchecked")
T[] copy = ((Object)newType == (Object)Object[].class)
? (T[]) new Object[newLength]
: (T[]) Array.newInstance(newType.getComponentType(), newLength);
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
由U类型复制为T类型?
original - 要复制的数组
newLength - 要返回的副本的长度
newType - 要返回的副本的类型
public static int[] copyOf(int[] original, int newLength) {
int[] copy = new int[newLength];
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
观察其源代码发现copyOf(),在其内部创建了一个新的数组,然后调用arrayCopy()向其复制内容,返回出去。
总结:
1.copyOf()的实现是用的是arrayCopy();
2.arrayCopy()需要目标数组,对两个数组的内容进行可能不完全的合并操作。
3.copyOf()在内部新建一个数组,调用arrayCopy()将original内容复制到copy中去,并且长度为newLength。返回copy;
ArrayList扩容技术
参考
- ArrayList 动态扩容机制
总结下,ArrayList 有一个初始的容量大小 10,当存储进里面的元素个数超过容量时,就需要增加 ArrayList 存储空间。每次要增加存储空间时,ArrayList 扩容到原来的 1.5 倍,并且进行复制操作,这个是非常伤性能的。如果 ArrayList 很大,执行数百次扩容,那么就会进行更多次数的新数组分配操作,以及更多次数的旧数组回收操作。
自己实现ArrayList
/**
* @desc:自己实现ArrayList
*/
public class CustomArrayList {
//存放元素的数组
private Object[] elementData;
//元素的个数
private int size;
//初始容量
private static final int DEFAULT_CAPACITY = 3;
public CustomArrayList() {
this(DEFAULT_CAPACITY);
}
public CustomArrayList(int initCapacity) {
if (initCapacity < 0) {
throw new IllegalArgumentException("Illegal Capacity: " +
initCapacity);
}
elementData = new Object[initCapacity];
}
/**
* 添加元素
*
* @param o
*/
public void add(Object o) {
ensureCapacity();
elementData[size++] = o;
}
/**
* 指定位置添加元素
*
* @param index
* @param obj
*/
public void add(int index, Object obj) {
rangeCheck(index);
ensureCapacity();
// a b c d
System.arraycopy(elementData, index, elementData, index + 1, size - index);
elementData[index] = obj;
size++;
}
/**
* 获取指定位置元素
*
* @param index
* @return
*/
public Object get(int index) {
rangeCheck(index);
return elementData[index];
}
/**
* /删除指定位置的元素
*
* @param index
*/
public void remove(int index) {
rangeCheck(index);
//a b c d
//移动元素的个数
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index + 1, elementData, index, numMoved);
elementData[--size] = null;//Let gc and its work
}
/**
* 删除指定元素
*
* @param o
*/
public void remove(Object o) {
for (int i = 0; i < size; i++) {
if (get(i).equals(o)) {
remove(i);
}
}
}
/**
* @param index
* @param o
* @return
*/
public Object set(int index, Object o) {
rangeCheck(index);
Object oldValue = elementData[index];
elementData[index] = o;
return oldValue;
}
/**
* 数组扩容
*/
private void ensureCapacity() {
if (size == elementData.length) {
Object[] newArray = new Object[size * 2 + 1];
System.arraycopy(elementData, 0, newArray, 0, elementData.length);
elementData = newArray;
}
}
public int size(){
return size;
}
private void rangeCheck(int index) {
if (index < 0 || index > size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
private String outOfBoundsMsg(int index) {
return "Index: " + index + ", Size: " + size;
}
public static void main(String[] args) {
CustomArrayList list = new CustomArrayList();
list.add("1");
list.add("2");
list.add("3");
list.add("4");
list.add("5");
System.out.println(list.size());
list.add(2,"插入元素");
System.out.println(list.get(2));
list.remove("插入元素");
System.out.println(list.get(2));
}
}