ArrayList源码分析
2017-01-14 21:23
351 查看
1, 结构图
ArrayList 是android中很常见的一种数据结构,经常用,现在就来分析一下源码吧,结构图如下,
其继承结构从上往下论述。
AbstractCollection是一个抽象类,继承了Collection,实现了部分方法。
public ArrayList() {
array = EmptyArray.OBJECT;
}
Array定义如下,
transient关键字是啥意思?
在序列化对象时,在array前面加上transient关键字是不会进行系列化的。
那么 EmptyArray.OBJECT又是什么呢?
在EmptyArray中的定义如下,
原来构造了一个大小为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。
1,在array的最后添加一个元素
2,在任一位置添加一个元素
3,在array的最后添加一个集合(Collection)
4, 在任一位置添加一个集合
这4个方法的本质是一样的,以第一种为例来论述,
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
@Override public Iterator<E> iterator() {
return new ArrayListIterator();
}
ArrayListIterator是什么?是ArrayList的内部类并且实现了对应的方法,这样就可以使用iterator方法来进行循环了。
Cloneable接口中没有任何方法?这不符合一般的逻辑啊!
Java有一个特性,就是所有的java类都继承自Object
类,而clone方法是在Object类中定义的,其定义如下,
原来是这样的, Cloneable只是调用clone方法的一个声明。
1,要想调用Object类的clone方法,必须继承Cloneable接口
2,继承了Cloneable接口不一定非要实现clone方法。
问题:复制在其他地方论述。
直接看ArrayList的equals方法,
从上面的代码中可以看出,如果一个集合继承了RandomAccess接口,那么必然会有get方法,就可以使用其get方法来获取元素,否则只能用iterator。那么可以这样理解,集合类如何继承了RandomAccess接口,那么必然会有一个get方法。
问题: get方法和 iterator 哪一个的效率更高呢?
Equals方法是判断两个集合中的每个元素是不是完全相同。
Serializable接口也没有任何方法,除了继承之外,还要有一个哈希码,直接看源码
由此看到,进行系列化和反系列化时,只是简单仅针对array数组值。
问题: Serializable 和 Parcelable 的区别。
1, Vector有些方法使用关键字synchronized进行修饰,所以Vector是线程安全的,导致Vector在效率上低于ArrayList。
2,都是采用线性连续空间存储元素,当空间不足时,2个类增加方法是不同的。
ArrayList一次可以增长自身空间的一半,而Vector可以设置增长因子。
现在一般很少使用Vector了。
Stack继承Vector,只是多了几个方法而已,
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,只是多了几个方法而已,
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件