首先Array实现的接口
RandomAccess:接口RandomAccess中内容是空的,只是作为标记用。比如List下的ArrayList和LinkedList。其中ArrayList实现了RandomAccess。而LinkedList没有。我们可以利用instanceof来判断哪一个是实现了RandomAccess。分辨出两个集合。其中ArrayList使用for循环遍历快,而LinkedList使用迭代器快。那么通过分辨,不同的集合使用不同的遍历方式。
如下例子
ArrayList
LinkedList
Cloneable:克隆接口,肯定要重写clone()方法
java.io.Serializable:序列化接口
一 基础变量
//数组默认初始容量为10
private static final int DEFAULT_CAPACITY = 10;
//长度为0的空数组
private static final Object[] EMPTY_ELEMENTDATA = {};
//长度为0的空数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//记录list的逻辑长度(存放元素的个数)
private int size;
//集合存储数据的容器(数组)
transient Object[] elementData;
transient干嘛用的?当对象被序列化时(写入字节序列到目标文件)时,transient阻止实例中那些用此关键字声明的变量持久化;当对象被反序列化时(从源文件读取字节序列进行重构),这样的实例变量值不会被持久化和恢复。
因为ArrayList不能序列化和反序列化吗?肯定不是,是因为elementData里面不是所有的元素都有数据,因为容量的问题,elementData里面有一些元素是空的,这种是没有必要序列化的。ArrayList的序列化和反序列化依赖writeObject和readObject方法来实现。可以避免序列化空的元素。
二 无参构造方法
初始化的时候讲空数组赋值给数据容器
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
三 add方法
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
//给缓冲器赋值的同时,记录元素的个数
elementData[size++] = e;
此方法是有返回值的
return true;
}
private void ensureCapacityInternal(int minCapacity) {
//第一次添加元素时 minCapacity=1
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//ArrayList会在第一次添加元素的时候设置数组缓冲器的初始大小为10.
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
//判断是否需要扩容
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
//记录修改次数
modCount++;
// overflow-conscious code
//如果需要容量大于缓冲器容量的时候,进行扩容
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
//扩容方法
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
//新容器的大小,是原容器的长度加上原容器一半的长度,即1.5原容器的大小
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
//MAX_ARRAY_SIZE 是容器的最大容量,为Integer的最大值减8.
if (newCapacity - MAX_ARRAY_SIZE > 0)
//如果扩容后的容量大于Integer的最大值减8,做一个最大容量缓冲器即int的最大值
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
/**
首先创建一个扩容后大小的空对象数组,然后把原来的缓冲数组拷贝到这个新的数组中,最后把
这个新数组的引用指向缓冲数组。
**/
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
//Arrarys.java的方法
public static <T> T[] copyOf(T[] original, int newLength) {
return (T[]) copyOf(original, newLength, original.getClass());
}
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底层是调用C++方法实现
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
四 在指定位置插入数据
public void add(int index, E element) {
//校验插入的位置是否合法
rangeCheckForAdd(index);
//判断是否需要扩容
ensureCapacityInternal(size + 1); // Increments modCount!!
//数组拷贝
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
//插入数据
elementData[index] = element;
size++;
}
//插入位置校验
private void rangeCheckForAdd(int index) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
五 set方法
public E set(int index, E element) {
//index合法性验证
rangeCheck(index);
//去除旧的元素
E oldValue = elementData(index);
//设置新的元素
elementData[index] = element;
//返回旧的元素
return oldValue;
}
六 get方法
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
七 remove方法
public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
}