简析ArrayList的方法以及手动重写ArrayList,都需要查看底层源码。

 看下ArrayList的继承

public class ArrayList<E> extends AbstractList<E>

        implements List<E>, RandomAccess, Cloneable, java.io.Serializable

AbstractList作为父类不必多讲,接口有:List,RandomAccess,Cloneable,java.io.Serializable 

框架内继承不多说,看下RandomAccess,Cloneable,Serializable三个借口

1.RandomAccess interface

RandomAccess是标记接口,类实现了这个接口,代表可以进行快速随机访问算法

此时for循环比迭代器要快,反之则慢于迭代器

随机访问:访问元素的位置不需要进行从头遍历,直接访问[n]号元素

ArrayList支持,即访问ArrayList的第n号元素直接可以取出来,因为相邻元素是连续存储,存储地址只要知道头号元素地址+n就好了。

如果是LinkedList则需要从头遍历,这是因为LinkedList中元素是随机存储,要访问LinkedList需要从表头一直next(),进行n次后到达n号元素。

2.Cloneable interface

Cloneable同样是标记接口,类实现了这个接口要重写clone方法,访问属性public

By convention, classes that implement this interface should override* {@code Object.clone} (which is protected) with a public method.

可以看到clone方法存在于Object类中,而Object类是所有类的父类,所以实现Cloneable接口就代表可以clone,否则抛出异常,如:

public Object clone() {

        try {

            ArrayList<?> v = (ArrayList<?>) 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(e);

        }

    }

2.1 clone 和 copy的区别

简单的 = 赋值是指向堆中同一片地址,引用传递后改变地址中的值都会导致指向该地址的所有对象都会改变,所以要用到clone

.clone( )方法会克隆对象的属性和方法,若只有基本数据类型直接用即可。

如果类比较复杂,拥有引用类型属性,这样就需要重写clone( )方法。

如:类里面夹着类,这样clone( )方法就需要在类里面重写。

调用的时候外部直接clone,内部再调用类名.clone(),完成内部的类对象的拷贝。

在clone完之后ArrayList里重写的方法就会有modCount=0这样的一句语句,可以看出克隆完的保证是新的对象,无修改的。

3.Serializable - 序列化

transient关键字修饰的变量不参与序列化与反序列化

对于继承了Serializable接口的类最好显式声明serialVersionUID,且用private static final。

其余序列化的总结留置IO流。

4.底层方法fastRemove和grow

此处只举例说明代码风格以及规范的问题,我注意到这些真正对ArrayList的structural modify都是private方法。

remove方法先检查的是index合法性,再调用fastRemove前移复制,最后一位置null

grow方法同样是数组扩容

这里要说明有一个modCount参数

protected transient int modCount = 0;

原注释:

     * Structural modifications are those that change the size of the

     * list, or otherwise perturb it in such a fashion that iterations in

     * progress may yield incorrect results.

这里注意到体到了iterations导致的结构变化,同样是要注意的。

导致结构变化的最底层函数要设置为private属性,且每次调用要modCount+1,记录修改,这也是封装的概念,对于数据保护要当成一个习惯。

02-11 21:20