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上进行改变的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值