码迷,mamicode.com
首页 > 其他好文 > 详细

JDK源码-ArrayList源码

时间:2015-01-20 15:50:11      阅读:193      评论:0      收藏:0      [点我收藏+]

标签:

1,继承结构图:
     -1,ArrayList继承AbstractList抽象类,实现List、RandomAccess、Cloneable、Serializable接口。
     -2,查看List接口的继承关系,我们看到List接口实现了Collection接口。Collection接口是基本集合类接口。查看Collection接口的说明:
/**
* The root interface in the <i>collection hierarchy</i>. A collection
* represents a group of objects, known as its <i>elements</i>. Some
* collections allow duplicate elements and others do not. Some are ordered
* and others unordered.
     -3,查看AbstractList分支继承关系,AbstractList继承AbstractCollection,实现List接口。
     -4,查看AbstractCollection,可以看到该类实现Collection接口。
     -5,Collection接口最终实现迭代器接口:Iterable。
2,从用自上而下的方式来一步一步查看源码。
3,Iterable接口:
package java.lang;
 
import java.util.Iterator;
 
/** Implementing this interface allows an object to be the target of
* the "foreach" statement.
* @since 1.5
*/
public interface Iterable<T> {
 
/**
* Returns an iterator over a set of elements of type T.
*
* @return an Iterator.
*/
Iterator<T> iterator();
}
Iterable接口类源码很简单,我们知道该接口属于迭代器模式,用来实现迭代遍历集合类。所以Collection接口实现了该接口,标识Collecttion的所有子类都可以使用迭代器方式遍历。
Iterable接口比较重要的子类我们可以看Iterator接口,如下,我摘录出了该接口的方法。
public interface Iterator<E> {
boolean hasNext();
E next();
void remove();
}
4,Collection接口,我们通过JavaDoc文档可以查看对应的子类
* <p>This interface is a member of the
* <a href="{@docRoot}/../technotes/guides/collections/index.html">
* Java Collections Framework</a>.
*
* @author Josh Bloch
* @author Neal Gafter
* @version 1.55, 04/21/06
* @see Set
* @see List
* @see Map
* @see SortedSet
* @see SortedMap
* @see HashSet
* @see TreeSet
* @see ArrayList
* @see LinkedList
* @see Vector
* @see Collections
* @see Arrays
* @see AbstractCollection
* @since 1.2
*/
可以看到对应的都实现此接口,接口中定义了集合类常用到的方法。
5,AbstractCollection
public abstract class AbstractCollection<E> implements Collection<E>
该类主要实现了部分共用的方法,比如:
/**
* {@inheritDoc}
*
* <p>This implementation returns <tt>size() == 0</tt>.
*/
public boolean isEmpty() {
return size() == 0;
}
public boolean contains(Object o) {
Iterator<E> e = iterator();
if (o==null) {
while (e.hasNext())
if (e.next()==null)
return true;
} else {
while (e.hasNext())
if (o.equals(e.next()))
return true;
}
return false;
}
public boolean remove(Object o) {
Iterator<E> e = iterator();
if (o==null) {
while (e.hasNext()) {
if (e.next()==null) {
e.remove();
return true;
}
}
} else {
while (e.hasNext()) {
if (o.equals(e.next())) {
e.remove();
return true;
}
}
}
return false;
}
public boolean addAll(Collection<? extends E> c) {
boolean modified = false;
Iterator<? extends E> e = c.iterator();
while (e.hasNext()) {
if (add(e.next()))
modified = true;
}
return modified;
}
主要实现了以上的方法,我们发现以上方法有个共同特点,就是具体操作是通过其他方法来实现的,比如addAll方法,主要是通过add方法来实现的。
6,List接口,List接口继承了Collection接口,对Collection接口进行了一些扩展。
    -1,因为List存储的是顺序集合类。
An ordered collection (also known as a <i>sequence</i>).
    -2,允许重复元素。
Unlike sets, lists typically allow duplicate elements.
    -3,提供ListIterator来实现元素迭代。ListIterator继承自Iterator接口,并提供一些扩展方法。
The <tt>List</tt> interface provides a special iterator, called a
* <tt>ListIterator</tt>, that allows element insertion and replacement, and
* bidirectional access in addition to the normal operations that the
* <tt>Iterator</tt> interface provides.
    -4,提供一些其他扩展操作方法。
7,ArrayList源码。
    -1,ArrayList是List的可变数组实现方式。实现了所有List接口的方法,大致同Vector类,只不过此类是不同步的。
           size  isEmpty  get  set  iterator  listIterator操作都以固定时间运行。即,添加n个元素需要O(n)事件运行,其他的操作也以线性时间运行。
            每个ArrayList都存在一个capacity的实例,该实例用来存储List对应数组的长度。
            在添加大数据操作时候,可以使用ensureCapacity操作来提前扩展大小。此操作是非线程安全的,如果多个线程同时访问一个ArrayList实例,而至少有一个线程从结构上(增加或者删除元素,或修改底层数组大小,不包含元素值的修改)修改了列表,那么它必须保持外部同步。一般通过封装该列表的对象进行同步操作来完成,如果不存该对象,可以使用Collections.synchronizedList方法包装列表实现。
List list = Collections.synchronizedList(new ArrayList(...));
            使用迭代器遍历元素的时候,在创建迭代器之后,除非通过迭代器自身的remove或add方法从结构上对列表进行修改,否则在任何时间以任何方式修改都会抛出异常。
    以上均为API对ArrayList的描述。我们可以使用代码对以上内容进行测试:
    a. 测试  size  isEmpty  get  set  iterator  listIterator  add方法时间。
    
public class TestAdd {
 
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
List<Integer> lists = new ArrayList<Integer>();
//测试add方法
for(int i = 0 ; i < 1000000; i++){
lists.add(1);
}
long endTime = System.currentTimeMillis();
System.out.println("add添加1000000元素,用时: " + (endTime - startTime));//输出32
//add 一个元素的时间
startTime = System.currentTimeMillis();
lists.add(2);
endTime = System.currentTimeMillis();
System.out.println("add添加1元素,用时: " + (endTime - startTime));//输出0
//get 一个元素
startTime = System.currentTimeMillis();
lists.get(2);
endTime = System.currentTimeMillis();
System.out.println("get元素,用时: " + (endTime - startTime));//输出0
}
}
   b.  使用capacity元素完成初始化操作:
long startTime = System.currentTimeMillis();
List<Integer> lists = new ArrayList<Integer>(1000000);
//测试add方法
for(int i = 0 ; i < 1000000; i++){
lists.add(1);
}
long endTime = System.currentTimeMillis();
System.out.println("add添加1000000元素,用时: " + (endTime - startTime));//输出12
   c.使用迭代器遍历ArrayList
    
startTime = System.currentTimeMillis();
Iterator<Integer> iter = lists.iterator();
int a ;
while(iter.hasNext()){
a = iter.next();
}
endTime = System.currentTimeMillis();
System.out.println("迭代器元素,用时: " + (endTime - startTime));//输出33
-2,成员变量:
    elementData: 数组,用来存储ArrayList对应的元素列表。使用capacity来存储数组长度。
private transient Object[] elementData;
    size:ArrayList存储元素的长度。
    modCount:此变量属于父类AbstractList。该元素记录了从结构上修改次列表的次数。此字段由iterator和listIterator方法返回的迭代器和列表迭代器实现。
    -3,构造函数:
    public ArrayList(int initCapacity):如果初始化参数小于0则抛出异常,否则初始化列表中的数组。
public ArrayList(int initialCapacity) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
}
    public  ArrayList():初始化一个长度为10的数组。
public ArrayList() {
this(10);
}
    public ArrayList(Collection<? extends e> c):构建一个包含c中所有元素的列表,元素顺序按照Iterator返回的顺序排列。
public ArrayList(Collection<? extends E> 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);
}
使用到了Arrays.copyOf方法,我们可以进一步查看该方法:
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
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;
}
查看System.arraycopy源码:
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
    -4,方法:
    add(E e):添加对应元素到数组中。add方法记调用了ensureCapacity方法,保证数组元素不越界,然后对数组元素的末尾增加了当前元素。
public boolean add(E e) {
ensureCapacity(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
    ensureCapacity(int minCapacity):该方法判断数组元素是否已经超过了当前ArrayList中的数组长度,如果超过则增加长度。
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);
}
}
    add(int index, E element):在数组固定位置添加元素。
     remove(int index):移除制定索引的元素。
public E remove(int index) {
RangeCheck(index);//确保索引位置未超出最大size,超出则抛出异常。
 
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;
}
    get(int index):获取制定索引元素
public E get(int index) {
RangeCheck(index);
 
return (E) elementData[index];
}
    set(int index, E e):更换制定索引元素值,使用e替换,并返回原有值。

ArrayList的操作基本都很简单,包括源代码,相对来说还是比较简单。看此处的代码的时候,建议先学习数据结构的线性表后,再来看次部分的代码。

JDK源码-ArrayList源码

标签:

原文地址:http://blog.csdn.net/mergades/article/details/42917301

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!