简单说明:
1、上图中虚线且无依赖字样、说明是直接实现的接口
2、虚线但是有依赖字样、说明此类依赖与接口、但不是直接实现接口
3、实线是继承关系、类继承类、接口继承接口
1、ArrayList是内部是以动态数组的形式来存储数据的、知道数组的可能会疑惑:数组不是定长的吗?这里的动态数组不是意味着去改变原有内部生成的数组的长度、而是保留原有数组的引用、将其指向新生成的数组对象、这样会造成数组的长度可变的假象。
2、ArrayList具有数组所具有的特性、通过索引支持随机访问、所以通过随机访问ArrayList中的元素效率非常高、但是执行插入、删除时效率比较地下、具体原因后面有分析。
3、ArrayList实现了AbstractList抽象类、List接口、所以其更具有了AbstractList和List的功能、前面我们知道AbstractList内部已经实现了获取Iterator和ListIterator的方法、所以ArrayList只需关心对数组操作的方法的实现、
4、ArrayList实现了RandomAccess接口、此接口只有声明、没有方法体、表示ArrayList支持随机访问。
5、ArrayList实现了Cloneable接口、此接口只有声明、没有方法体、表示ArrayList支持克隆。
6、ArrayList实现了Serializable接口、此接口只有声明、没有方法体、表示ArrayList支持序列化、即可以将ArrayList以流的形式通过ObjectInputStream/ObjectOutputStream来写/读。
// Collection中定义的API
boolean add(E object)
boolean addAll(Collection collection)
void clear()
boolean contains(Object object)
boolean containsAll(Collection collection)
boolean equals(Object object)
int hashCode()
boolean isEmpty()
Iterator iterator()
boolean remove(Object object)
boolean removeAll(Collection collection)
boolean retainAll(Collection collection)
int size()
T[] toArray(T[] array)
Object[] toArray()
// AbstractList中定义的API
void add(int location, E object)
boolean addAll(int location, Collection collection)
E get(int location)
int indexOf(Object object)
int lastIndexOf(Object object)
ListIterator listIterator(int location)
ListIterator listIterator()
E remove(int location)
E set(int location, E object)
List subList(int start, int end)
// ArrayList新增的API
Object clone()
void ensureCapacity(int minimumCapacity)
void trimToSize()
void removeRange(int fromIndex, int toIndex)
总结:相对与AbstractCollection而言、多实现了List中新增的通过索引操作元素的方法。
package com.chy.collection.core;
import java.util.Arrays;
import java.util.ConcurrentModificationException;
import java.util.RandomAccess;
public class ArrayList extends AbstractList implements List, RandomAccess, Cloneable, java.io.Serializable {
private static final long serialVersionUID = 8683452581122892189L;
/** 保存ArrayList中元素的数组*/
private transient Object[] elementData;
/** 保存ArrayList中元素的数组的容量、即数组的size*/
private int size;
/** 使用指定的大小创建ArrayList*/
public ArrayList(int initialCapacity) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
this.elementData = new Object[initialCapacity];
}
/** 使用默认的大小创建ArrayList*/
public ArrayList() {
this(10);
}
/**
* 使用指定的Collection构造ArrayList、构造之后的ArrayList中包含Collection中的元素、
* 这些元素的排序方式是按照ArrayList的Iterator返回他们时候的顺序排序的
*/
public ArrayList(Collection c) {
elementData = c.toArray();
size = elementData.length;
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
}
/**
* 将此 ArrayList 实例的容量调整为列表的当前大小
*/
public void trimToSize() {
//此集合总共被修改的次数
modCount++;
int oldCapacity = elementData.length;
if (size < oldCapacity) {
elementData = Arrays.copyOf(elementData, size);
}
}
/**
* 确保此ArrayList的最小容量能容纳下参数minCapacity指定的容量、
* 1、minCapacity大于原来容量、则将原来的容量增加(oldCapacity * 3)/2 + 1;
* 2、若minCapacity仍然大于增加后的容量、则使用minCapacity作为ArrayList容量
* 3、若minCapacity不大于增加后的容量、则使用增加后的容量。
*/
public void ensureCapacity(int minCapacity) {
modCount++;
int oldCapacity = elementData.length;
if (minCapacity > oldCapacity) {
Object oldData[] = elementData;
int newCapacity = (oldCapacity * 3)/2 + 1;
if (newCapacity < minCapacity)
newCapacity = minCapacity;
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
}
/** 返回此列表中的元素的个数*/
public int size() {
return size;
}
/** 如果此列表中没有元素,则返回 true*/
public boolean isEmpty() {
return size == 0;
}
/** 如果此列表中包含指定的元素,则返回 true。*/
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
/** 返回指定对象在ArrayList中存放的第一个位置索引、注意空值的处理和Object.equals(? extends Object o)的返回值、不存在的话返回-1*/
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
/** 返回指定对象在ArrayList中存放最后一个位置的索引、注意空值的处理和Object.equals(? extends Object o)的返回值、不存在的话返回-1*/
public int lastIndexOf(Object o) {
if (o == null) {
for (int i = size-1; i >= 0; i--)
if (elementData[i]==null)
return i;
} else {
for (int i = size-1; i >= 0; i--)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
/** 返回一个当前集合的浅clone对象*/
public Object clone() {
try {
ArrayList v = (ArrayList) super.clone();
v.elementData = Arrays.copyOf(elementData, size);
v.modCount = 0;
return v;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError();
}
}
/** 将当前ArrayList转换成Object数组、注意操作使用此方法转换后的数组有可能抛异常*/
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}
/**
* 将当前ArrayList转换成与传入的T类型相同的数组、当传入的a的length小于ArrayList的size的时候、方法内部会生成一个新的T[]返回
* 如果传入的T[]的length大于ArrayList的size、则T[]从下标size开始到最后的元素都自动用null填充。
*/
public T[] toArray(T[] a) {
if (a.length < size)
// Make a new array of a's runtime type, but my contents:
return (T[]) Arrays.copyOf(elementData, size, a.getClass());
System.arraycopy(elementData, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
}
// Positional Access Operations
/** 获取ArrayList中索引为index位置的元素*/
public E get(int index) {
RangeCheck(index);
return (E) elementData[index];
}
/** 将ArrayList的索引为index处的元素使用指定的E元素替换、返回被替换的原来的元素值*/
public E set(int index, E element) {
RangeCheck(index);
E oldValue = (E) elementData[index];
elementData[index] = element;
return oldValue;
}
/** 将指定元素E添加到ArrayList的结尾处*/
public boolean add(E e) {
//确保ArrayList的容量能够添加新的的元素
ensureCapacity(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
/** 将指定元素添加到指定的索引处 、
* 注意:
* 1、如果指定的index大于Object[] 的size或者小于0、则抛IndexOutOfBoundException
* 2、检测Object[]是否需要扩容
* 3、 将从index开始到最后的元素后移一个位置、
* 4、将新添加的元素添加到index去。
*/
public void add(int index, E element) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(
"Index: "+index+", Size: "+size);
ensureCapacity(size+1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
/** 与add类似、
* 1、将指定index处的元素删除、
* 2、将index之后的所有元素前一一个位置、最后一个
* 3、将最后一个元素设置为null、--size
*
* 返回被删除的元素。
*/
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;
}
/** 删除Object[]中指定的元素Object 类似与contains方法与remove的结合体、只不过这里使用的是fastRemove方法去移除指定元素、移除成功则返回true*/
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; // Let gc do its work
}
/** 清空ArrayList*/
public void clear() {
modCount++;
// Let gc do its work
for (int i = 0; i < size; i++)
elementData[i] = null;
size = 0;
}
/** 将指定集合中的所有元素追加到ArrayList中(从最后开始追加)*/
public boolean addAll(Collection 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;
}
/** 将指定集合中的所有元素插入到idnex开始的后面位置处、原有的元素往后排*/
public boolean addAll(int index, Collection 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;
}
/** 移除列表中索引在 fromIndex(包括)和 toIndex(不包括)之间的所有元素。
* 1、将Object[] 从toIdnex开始之后的元素(包括toIndex处的元素)移到Object[]下标从fromIndex开始之后的位置
* 2、若有Object[]尾部要有剩余的位置则用null填充
*/
protected void removeRange(int fromIndex, int toIndex) {
modCount++;
int numMoved = size - toIndex;
System.arraycopy(elementData, toIndex, elementData, fromIndex,
numMoved);
// Let gc do its work
int newSize = size - (toIndex-fromIndex);
while (size != newSize)
elementData[--size] = null;
}
/** 检测下标是否越界*/
private void RangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(
"Index: "+index+", Size: "+size);
}
/** 将此ArrayList写入到ObjectOutputStream流中、先写ArrayList存放元素的Object[]长度、再将Object[]中的每个元素写入到ObjectOutputStream流中*/
private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException{
// Write out element count, and any hidden stuff
int expectedModCount = modCount;
s.defaultWriteObject();
// Write out array length
s.writeInt(elementData.length);
// Write out all elements in the proper order.
for (int i=0; i
总结:从ArrayList源码可以看出、ArrayList内部是通过动态数组来存储数据、从中我们也可以很容易的找到ArrayList的几个特性:
1、有序:如果不指定元素存放位置、则元素将依次从Object数组的第一个位置开始放、如果指定插入位置、则会将元素插入指定位置、后面的所有元素都后移
2、可重复:从源码中没有看到对存放的元素的校验
3、随机访问效率高:可以直接通过索引定位到我们要找的元素
4、自动扩容:ensureCapacity(int minCapacity)方法中会确保数组的最小size、当不够时会将原来的容量扩增到:(oldCapacity * 3) / 2 + 1。
5、变动数组元素个数(即添加、删除数组元素)效率低、在增删的操作中我们常见的一个函数: System.arraycopy()、他是将删除、或者添加之后、原有的元素进行移位、这是需要较大代价的。
6、 ArrayList不是线程安全的、即当使用多线程操作ArrayList时会有可能出错、后面总结会有。
因为使用集合、我们最关心的就是使用不同集合的不同方法的效率问题、而在这些中、最能体现效率问题的关键点是对集合的遍历、所以对于示例、分为两部分:第一部分是关于集合的不同的遍历方法的耗时示例、第二部分是集合的API的使用示例。
01)使用Iterator遍历ArrayList
for(Iterator iter = list.iterator(); iter.hasNext(); ) {
iter.next();
}
02)使用ListIterator遍历ArrayList
for(Iterator iter = list.listIterator(); iter.hasNext(); ) {
iter.next();
}
03)使用随机访问(即for(int i=0;i 04)使用增强for循环遍历ArrayList 05)示例 结果及说明: 63 ms 从上面可以看出:使用随机访问效率最高、其他的差不多。 对于ArrayList、在记住其特性、有序可重复、便与查找、不便于增删的同时最好是能知道为什么他会有这些特性、其实源码就是最好的说明书、平常所接触的东西都是别人在源码的基础上分析得出的结论、只有自己的才是最适合自己的、别人总结的再好、看过、受教了、但是还是希望自己能动手总结一份、再差也是自己总结的、慢慢改进、只有自己的东西才是最适合自己的! for (int i = 0; i < list.size(); i++){
list.get(i);
}
for(@SuppressWarnings("unused") int i : list);
package com.chy.collection.example;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.ListIterator;
public class EragodicArrayList {
/**
* 测试不同遍历方式的效率
*/
public static void testObtainAllElements(){
//初始化一个较大的ArrayList
ArrayList
78 ms
15 ms
63 ms
62 ms 2、API演示
package com.chy.collection.example;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.ListIterator;
import com.chy.collection.bean.Student;
public class ArrayListTest {
/**
* 测试ArrayList的添加元素方法、以及与size有关的方法
*/
public static void testArrayListSize(){
//use default object array's size 10
ArrayList
总结:
更多内容:java_集合体系之总体目录——00