- ArrayList的继承关系
继承了AbstractCollection AbstractList的类 实现了Iterable Collection List RandomAccess Cloneable Serializable接口
RandomAccess接口作用:发现实现RandomAccess接口的List集合采用一般的for循环遍历,而未实现这接口则采用迭代器
Cloneable接口作用:cloneable其实就是一个标记接口,只有实现这个接口后,在类中重写Object中的clone方法,然后通过类调用clone方法才能克隆成功,如果不实现这个接口,则会抛出CloneNotSupportedException(克隆不被支持)异常
实现这个接口且重写clone()可以实现深度克隆和浅度克隆
浅度克隆:被克隆得到的对象基本类型的值修改了,原对象的值不会改变
深度克隆:被克隆得到的对象基本类型的值修改了,原对象的值改变
protected native Object clone() throws CloneNotSupportedException;
这是本地方法 调用的是jvm具体的方法实现
Serializable接口: 进行序列化和反序列化的时候使用 且标明一个serialVersionUID 在序列化的时候把这个id一同序列化到文件中反序列化的时候会把 serialVersionUID 同文件的id做对比 不一致则表示对象改变 序列化失败
- 关于ArrayList的方法讲解
底层是数组实现的
transient Object[] elementData;
transient 作用 将不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会被序列化。
有三个构造方法 无参 collection类型参数 int类型参数
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
public ArrayList() { //这是jdk1.8版本的 在jdk1.7版本当无参时 默认的数组长度是10
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray(); //集合对象转换为数组
if ((size = elementData.length) != 0) { //判断数组长度
if (elementData.getClass() != Object[].class){ //进行类型校验
elementData = Arrays.copyOf(elementData, size, Object[].class); //创建一个新的的Object数组并返回
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
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;
}
private static final Object[] EMPTY_ELEMENTDATA = {};
public ArrayList(int initialCapacity) { //有参数时创建参数大小的数组 否则不进行指定参数大小
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
ArrayList集合的常用方法
//set方法替换某个下标的值
public E set(int index, E element) {
rangeCheck(index); //大于数组的下标 报出数组越界异常
E oldValue = elementData(index); //获取原来的旧值
elementData[index] = element;//新值赋值
return oldValue;//放回旧值
}
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
public boolean add(E e) {
ensureCapacityInternal(size + 1); // 数组扩容
elementData[size++] = e; //数组最后添加元素
return true;
}
public void add(int index, E element) {
rangeCheckForAdd(index); //数组下标检查
ensureCapacityInternal(size + 1); // 数组扩容
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
private void ensureCapacityInternal(int minCapacity) {
if (elementData == EMPTY_ELEMENTDATA) { //获取最大容量值 DEFAULT_CAPACITY默认为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 void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1); //右移动一位 例如2的5次方右移一位为2的4次方相当于为原来的一半 及增加原来的二分之一
if (newCapacity - minCapacity < 0) //如果增长得长度还是小于原来的长度则还是用原来的长度 例如默认初始值为10 但是数组的长度小于10以内
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity); //判断是否大于整数类型的最大值大于则返回整数最大值作为容量 否则最大值减8作为容量
// 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;
}
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
// 按照指定collection的迭代器所返回的元素顺序,将该collection中的所有元素添加到此列表的尾部。
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacity(size + numNew); // Increments modCount
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
}
// 从指定的位置开始,将指定collection中的所有元素插入到此列表中。
public boolean addAll(int index, Collection<? extends E> c) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(
"Index: " + index + ", Size: " + size);
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacity(size + numNew); // Increments modCount
int numMoved = size - index;
if (numMoved > 0)
System.arraycopy(elementData, index, elementData, index + numNew, numMoved);
System.arraycopy(a, 0, elementData, index, numNew);
size += numNew;
return numNew != 0;
}
// 返回此列表中指定位置上的元素。
public E get(int index) {
RangeCheck(index);
return (E) elementData[index];
}
// 移除此列表中指定位置上的元素。
public E remove(int index) {
RangeCheck(index);
modCount++;
E oldValue = (E) elementData[index];
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index, numMoved);
elementData[--size] = null; // Let gc do its work
return oldValue;
}
// 移除此列表中首次出现的指定元素(如果存在)。这是应为ArrayList中允许存放重复的元素。
public boolean remove(Object o) {
// 由于ArrayList中允许存放null,因此下面通过两种情况来分别处理。
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
// 类似remove(int index),移除列表中指定位置上的元素。
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
3.快速失败
Fail-Fast机制:
ArrayList也采用了快速失败的机制,通过记录modCount参数来实现。在面对并发的修改时,迭代器很快就会完全失败,而不是冒着在将来某个不确定时间发生任意不确定行为的风险。
add、remove操作对于ArrayList其运行时间是O(N),因为在它当中在前端进行添加或移除构造新数组是O(N)操作;get方法的调用为O(1)操作。要是使用一个增强的for循环,对于任意List的运行时间都是O(N),因为迭代器将有效地从一项到下一项推进。