ArrayList源码(3)
前两篇写了add和remove相关的源码,现在剩下的是零散的一些和Itr、SubList、ListItr几个相关的代码,这些应用次数也多但是其中相似的代码较多。 先说零散的几个: trimToSize()是减少存储使用的字符序列 ,如果缓冲区大于必要保持其当前的字符序列,那么它可能会调整大小,以成为更加节省空间.
public void trimToSize() {
modCount++;
int oldCapacity = elementData.length;
if (size < oldCapacity) {
elementData = Arrays.copyOf(elementData, size);
}
}
之后contains()方法和indexOf()、lastIndexOf()相关:
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
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;
}
从源码中看出contains()方法是使用indexOf来进行判断是否存在,indexOf()方法是从数组头部开发对比是否有相同的,lastIndexOf()方法是从尾部开发进行对比。
public Object clone() {
try {
@SuppressWarnings("unchecked")
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();
}
}
clone()克隆数组,《Effective Java》的第11条中说“谨慎地覆盖clone”里面讲了很多clone的东西和注意事项,大家可以去看一眼。 我看别的博主写的:如何巧妙的使用ArrayList的Clone方法
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<size; i++)
s.writeObject(elementData[i]);
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
// Read in size, and any hidden stuff
s.defaultReadObject();
// Read in array length and allocate array
int arrayLength = s.readInt();
Object[] a = elementData = new Object[arrayLength];
// Read in all elements in the proper order.
for (int i=0; i<size; i++)
a[i] = s.readObject();
}
ArrayList上重写writeObject和readObject,当其序列化的时候将会映射调用该方法。之后如果有机会学习ObjectOutputStream的源码是再仔细研究里面的具体方法使用。
零散的几个我们看了,现在我们接着看关于ArrayList的Iterator相关的源码:
public ListIterator<E> listIterator(int index) {
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("Index: "+index);
return new ListItr(index);
}
public ListIterator<E> listIterator() {
return new ListItr(0);
}
public Iterator<E> iterator() {
return new Itr();
}
这是其相关的三个创建方法,其中iterator()直接创建Itr类,另外两个是创建ListItr类,这两个类是ArrayList的两个内部类其定义名为:
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
.....
}
private class ListItr extends Itr implements ListIterator<E> {
ListItr(int index) {
super();
cursor = index;
}
.....
}
他们的关系是有关联的,在源码中Itr类内部的方法只有四个而且都相关:
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
因为我看这些方法都简单明了,其中注意一下在remove()方法中的expectedModCount = modCount;
在这里又进行了一次赋值,是因为在remove移除的时候modCount的数值发生了改变所以要重新进行复制,因为在checkForComodification()
方法中如果检测到他们两个值不相同时,这个检查是可以避免一些可能引起跌代错误的add()或remove()等危险操作。在AbstractList中,使用了一个简单的机制来规避这些风险。 这就是modCount和expectedModCount的作用所在。
在ListItr类中,其中的方法都有类似当进行改动ArrayList的时候回调用ArrayList.this.*的方法进行改变。
在subList()方法中产生了一个SubList类该类为ArrayList的内部类,其内方法和ArrayList的各种方法都是大同小异的,相当于将ArrayList的个别数据复制到一个新的List里面进行操作,而其内的方法就是这种操作的内容,但是当修改了该List的内容或者添加了其原来的ArrayList的内容是跟随着改变的,其主要形成的方法:
public List<E> subList(int fromIndex, int toIndex) {
subListRangeCheck(fromIndex, toIndex, size);
return new SubList(this, 0, fromIndex, toIndex);
}
static void subListRangeCheck(int fromIndex, int toIndex, int size) {
if (fromIndex < 0)
throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
if (toIndex > size)
throw new IndexOutOfBoundsException("toIndex = " + toIndex);
if (fromIndex > toIndex)
throw new IllegalArgumentException("fromIndex(" + fromIndex +
") > toIndex(" + toIndex + ")");
}
public void add(int index, E e) {
rangeCheckForAdd(index);
checkForComodification();
parent.add(parentOffset + index, e);
this.modCount = parent.modCount;
this.size++;
}
从该方法中就能看出形成新的SubList还是从原有的ArrayList上进行改变的。