1, 结构图
ArrayList 是android中很常见的一种数据结构,经常用,现在就来分析一下源码吧,结构图如下,
其继承结构从上往下论述。
1.1, Iterable Iterator
这两个都是接口,实现他们的方法就可以对集合进行遍历
public interface Iterable<T> {
Iterator<T> iterator();
}
public interface Iterator<E> {
public boolean hasNext();
public E next();
public void remove();
}
2.2, Collection AbstractCollection
Collection 接口共有15个方法,其中iterator从Iterable 继承而来。如下,
AbstractCollection是一个抽象类,继承了Collection,实现了部分方法。
2.3, List AbstractList
List只是一个接口,提供一些方法, AbstractList实现了部分方法。list中的方法如下,
2, ArrayList分析
首先看看ArrayList的构造方法
2.1, 构造方法
ArrayList一共有三个构造方法,从最简单的开始分析,
public ArrayList() {
array = EmptyArray.OBJECT;
}
Array定义如下,
transient Object[] array;
transient关键字是啥意思?
在序列化对象时,在array前面加上transient关键字是不会进行系列化的。
那么 EmptyArray.OBJECT又是什么呢?
在EmptyArray中的定义如下,
public static final Object[] OBJECT = new Object[0];
原来构造了一个大小为0 的Object数组。
第二个构造方法也挺简单, 构造了一个大小为capacity 的Object数组。
public ArrayList(int capacity) {
if (capacity < 0) {
throw new IllegalArgumentException("capacity < 0: " + capacity);
}
array = (capacity == 0 ? EmptyArray.OBJECT : new Object[capacity]);
}
第三个构造方法将其他集合转化为
ArrayList
。
2.2, add方法
Add有四个方法,
1,在array的最后添加一个元素
2,在任一位置添加一个元素
3,在array的最后添加一个集合(Collection)
4, 在任一位置添加一个集合
这4个方法的本质是一样的,以第一种为例来论述,
@Override public boolean add(E object) {
Object[] a = array;
int s = size;
if (s == a.length) {
Object[] newArray = new Object[s +
(s < (MIN_CAPACITY_INCREMENT / 2) ?
MIN_CAPACITY_INCREMENT : s >> 1)];
System.arraycopy(a, 0, newArray, 0, s);
array = a = newArray;
}
a[s] = object;
size = s + 1;
modCount++;
return true;
}
private static final int MIN_CAPACITY_INCREMENT = 12;
array最开始是大小为0的数组,是怎么添加元素的呢?
Array. Length 表示的是实际申请的数组大小,而size表示Array中已使用的数组大小。并且数组的大小翻倍申请的,太过频繁申请会影响效率。所以,使用的时候一定是size方法而不是Length方法。
Remove 有2种方法,
1,删除任一位置的元素
2,删除特定的元素。
get (intindex) 得到指定位置的元素
size()数组的大小
isEmpty() 判断array中的元素是否为空,
注意: 不要使用array. Length为0来判断。
Contains(Object object) array数组中是否包含对象
indexOf(Object object) 返回对象最开始出现的位置
lastIndexOf(Object object) 返回对象最后出现的位置
trimToSize() 将array数组简单整理
hashCode()array数组的哈希码
set(int index, E object)将第index的元素替换为object
3, 接口实现
3.1, Iterable Iterator
继承Iterable 只是表面的,主要是继承Iterator
@Override public Iterator<E> iterator() {
return new ArrayListIterator();
}
ArrayListIterator是什么?是ArrayList的内部类并且实现了对应的方法,这样就可以使用iterator方法来进行循环了。
private class ArrayListIterator implements Iterator<E> {
/** Number of elements remaining in this iteration */
private int remaining = size;
/** Index of element that remove() would remove, or -1 if no such elt */
private int removalIndex = -1;
/** The expected modCount value */
private int expectedModCount = modCount;
public boolean hasNext() {
return remaining != 0;
}
@SuppressWarnings("unchecked") public E next() {
ArrayList<E> ourList = ArrayList.this;
int rem = remaining;
if (ourList.modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
if (rem == 0) {
throw new NoSuchElementException();
}
remaining = rem - 1;
return (E) ourList.array[removalIndex = ourList.size - rem];
}
public void remove() {
Object[] a = array;
int removalIdx = removalIndex;
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
if (removalIdx < 0) {
throw new IllegalStateException();
}
System.arraycopy(a, removalIdx + 1, a, removalIdx, remaining);
a[--size] = null; // Prevent memory leak
removalIndex = -1;
expectedModCount = ++modCount;
}
}
3.2, Cloneable
继承了Cloneable接口,就必须实现clone方法,这样该类才可以进行clone。但是,
Cloneable接口中没有任何方法?这不符合一般的逻辑啊!
Java有一个特性,就是所有的java类都继承自Object
类,而clone方法是在Object类中定义的,其定义如下,
protected Object clone() throws CloneNotSupportedException {
if (!(this instanceof Cloneable)) {
throw new CloneNotSupportedException("Class " + getClass().getName() +
" doesn't implement Cloneable");
}
return internalClone();
}
原来是这样的, Cloneable只是调用clone方法的一个声明。
1,要想调用Object类的clone方法,必须继承Cloneable接口
2,继承了Cloneable接口不一定非要实现clone方法。
问题:复制在其他地方论述。
3.3, RandomAccess
RandomAccess接口里也没有什么方法,也只是一个标记,标志着什么呢?
直接看ArrayList的equals方法,
@Override public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof List)) {
return false;
}
List<?> that = (List<?>) o;
int s = size;
if (that.size() != s) {
return false;
}
Object[] a = array;
if (that instanceof RandomAccess) {
for (int i = 0; i < s; i++) {
Object eThis = a[i];
Object ethat = that.get(i);
if (eThis == null ? ethat != null : !eThis.equals(ethat)) {
return false;
}
}
} else { // Argument list is not random access; use its iterator
Iterator<?> it = that.iterator();
for (int i = 0; i < s; i++) {
Object eThis = a[i];
Object eThat = it.next();
if (eThis == null ? eThat != null : !eThis.equals(eThat)) {
return false;
}
}
}
return true;
}
从上面的代码中可以看出,如果一个集合继承了RandomAccess接口,那么必然会有get方法,就可以使用其get方法来获取元素,否则只能用iterator。那么可以这样理解,集合类如何继承了RandomAccess接口,那么必然会有一个get方法。
问题: get方法和 iterator 哪一个的效率更高呢?
Equals方法是判断两个集合中的每个元素是不是完全相同。
3.4 Serializable
Serializable简单说就是保存对象的实例变量状态,并且可以将保存的状态读取出来。
Serializable接口也没有任何方法,除了继承之外,还要有一个哈希码,直接看源码
private static final long serialVersionUID = 8683452581122892189L;
private void writeObject(ObjectOutputStream stream) throws IOException {
stream.defaultWriteObject();
stream.writeInt(array.length);
for (int i = 0; i < size; i++) {
stream.writeObject(array[i]);
}
}
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
stream.defaultReadObject();
int cap = stream.readInt();
if (cap < size) {
throw new InvalidObjectException(
"Capacity: " + cap + " < size: " + size);
}
array = (cap == 0 ? EmptyArray.OBJECT : new Object[cap]);
for (int i = 0; i < size; i++) {
array[i] = stream.readObject();
}
}
由此看到,进行系列化和反系列化时,只是简单仅针对array数组值。
问题: Serializable 和 Parcelable 的区别。
4, 横向比较
从源码中看, Vector和ArrayList很像,都是继承AbstractList等,那么他们之间有哪些区别呢?
1, Vector有些方法使用关键字synchronized进行修饰,所以Vector是线程安全的,导致Vector在效率上低于ArrayList。
2,都是采用线性连续空间存储元素,当空间不足时,2个类增加方法是不同的。
ArrayList一次可以增长自身空间的一半,而Vector可以设置增长因子。
现在一般很少使用Vector了。
Stack继承Vector,只是多了几个方法而已,