源码阅读之ArrayList

[color=red]常用方法[/color]
1, 其实有两个ArrayList。一个是java.util包下面的。一个java.utils.Collections这个工具类内部类。后者其实只是Collections一系列方法的返回对象.


2,ArrayList继承的接口有List,RandomAccess和Conable和serializable 。换句话说。其没有其他的集合语义。

public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable

3,成员变量只有elementData和size两个成员变量。觉得还是简单的。这也就意味着,elementData是全部存储对象的。没有任何的保存不再的东西的可能性.,也可以看出,ArrayList采用数组的方式存放对象。

/**
* ArrayList底层维护的Object数组
*/
private transient Object[] elementData;

/**
* 数组的长度
*
* @serial
*/
private int size;


4,构造函数分两类。
一类是无参和(int), 其实就是一个初始化elementData的长度。无参的默认长度为10
另一位是(Collection): 用了Collection.toArray进行转换。

//无参构造方法,会直接去调用有参构造方法
public ArrayList() {
this(10);
}


//有参构造方法
public ArrayList(int initialCapacity) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
}


//集合构造方法
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);
}


5,trimToSize:内存紧张的时候会用到。

public void trimToSize() {
modCount++;
int oldCapacity = elementData.length;
if (size < oldCapacity) {
elementData = Arrays.copyOf(elementData, size);
}
}

6.ensureCapacity:扩充数组长度。扩展长度是原长度old×1.5+1。

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);
}
}


7,indexOf和lastIndexOf。重写了一下,直接访问数组。觉得Iterator其实性能上不好。只是语义上与Collection相对.indexOf和lastIndexOf是ArrayList中用于获取对象所在位置的方法,indexOf为从前往后找,lastIndexOf为从后往前找。

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;
}


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;
}

8, 重写了clone方法,其实就是数组copy加上modCount重置。

public Object clone() {
try {
ArrayList<E> v = (ArrayList<E>) 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();
}
}


9,toArray(T[] a)觉得实现有点怪。具体规则为。
如果a的size小于List的size,那么就返回一个新的数组。不影响a。
反之,a的size大于List。那么就是把list全部Copy到a,然后在List的size的位置,把其设为null。后面的数据不变,然后返回a。换句话说影响了a。
所以觉得,还是怎么说呢,创建一个新的a,空的a丢进去。比较保险。因为都是用了复制。就是多了一个创建的性能消耗。toArray();直接调用Arrays的拷贝方法。

public <T> 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;
}

public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}


10,set方法的都有一个rangcheck方法。操作的是就是把删除数组索引位置的值,然后把后面的数据前移动。

public E set(int index, E element) {
RangeCheck(index);

E oldValue = (E) elementData[index];
elementData[index] = element;
return oldValue;
}


11.add(element);方法,首先检查扩充容量,然后把e的值付给当前数据组的size位置上,size+1返回。

public boolean add(E e) {
ensureCapacity(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}

12.add(Index,element)方法,就是会使用System中copy数组的方法。
addAll(collection)只是copy了一次数组,addALL(index,collection)则copy了两次。

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++;
}

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;
}

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;
}



13,remove方法,是用equal进行判断的。remove第一出线的。调用了一个fastRemove的内部方法,其省去了边界检查。其实也还是很System copy。remove(int)的实现比remove(e)多了一个数组范围检测,但少了数组元素的查找,因此性能会更好

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;
}
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
}

14.get(index)方法,在arrayList维护的数组中取出索引为index的值,前提是要保证index的值没有超过数组的最大长度。

public E get(int index) {
RangeCheck(index);

return (E) elementData[index];
}

15.contains(o)判断数组中是否存在某元素。其做法为遍历整个ArrayList中已有元素,如o为null,则直接判断已有元素是否为null,如为null返回true,如果o不为null,则直接通过判断o.equals和元素是否相等,如相等返回true.

public boolean contains(Object o) {
return indexOf(o) >= 0;
}

15.size();直接返回ArrayList中维护的size成员变量。

public int size() {
return size;
}

16.isEmpty();判断ArrayList中维护的size的值是否为0

public boolean isEmpty() {
return size == 0;
}

注意要点:
1.ArrayList基于数组方式实现,无限制容量。添加元素时,就是想ArrayList维护的数组中添加元素。
2.ArrayList在执行插入时可能扩充,在删除元素时候,并不会减小数组的容量(如希望减小数组的容量可以调用ArrayLust的trimToSize()方法,在查找元素要遍历数组时,对于非null元素采用equals的方式寻找)
3.ArrayList是非线程安全的
4.ArrayList删除元素操作时,需要将数组元素向前移动,代价比较高。
5.集合当中放置的是对象的引用,无法放置原生数据类型。我们需要使用原生数据类型的包装类。取出的时候,要进行强制类型转换将其转换成真正的类型(放置进去的类型).
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值