ArrayList原理学习(一)

ArrayList原理学习(一)

ArrayList集合内置属性

// 默认的数组大小
private static final int DEFAULT_CAPACITY = 10;
// 用于空实例的共享空数组实例。
private static final Object[] EMPTY_ELEMENTDATA = {};
// 共享的空数组实例用于默认大小的空实例
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
// 声明一个数组
transient Object[] elementData;
// 用于记录数组里面的元素个数
private int size;
// 数组里面扩容内存的阈值,为Int类型最大范围减去8
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
// 用于记录集合修改的次数 为父类属性
protected transient int modCount = 0;

Serializable接口

​ Serializable接口为标记接口,只有实现该接口的类才能进行序列化,否则无法序列化,若在不实现该接口进行序列化会报NotActiveException异常。

ArrayList内的writeObject()方法

private void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException{
        // 记录当前序列化开始时的数组修改次数
        int expectedModCount = modCount;
        // 将ArrayList中除了transient的其他数据序列化
        s.defaultWriteObject();
        // 将当前数组的元素长度序列化
        s.writeInt(size);
        // 将数组中元素逐一序列化
        for (int i=0; i<size; i++) {
            s.writeObject(elementData[i]);
        }
        // 对比记录的修改次数与当前数组修改次数是否相等,如果相等则表明序列化过程中数组未修改
        // 不相等着表明序列化过程中数组发生了改变,即抛出异常,停止序列化
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
}

ArrayList内的readObject()方法

 private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        // 声明一个空的数组
        elementData = EMPTY_ELEMENTDATA;
        // 将序列化的ArrayList读取出来并反序列化
        s.defaultReadObject();
        // 获取数据长度
        s.readInt(); // ignored
        if (size > 0) {
            // 校验长度 并对数组进行扩容
            ensureCapacityInternal(size);
            // 声明一个方法内元素
            Object[] a = elementData;
            // 通过循环将数据逐一反序列化读取出来
            for (int i=0; i<size; i++) {
                a[i] = s.readObject();
            }
        }
    }

Cloneable接口

​ 该接口为标记接口,实现该接口才能实现克隆方法,否则程序会抛出异常。(克隆的前提:被克隆的对象必须实现Cloneable接口,必须重写clone方法)

public Object clone() {
    try {
    // 当用Object方法里面的clone方法,AbstractList类中是没有clone方法的,该方法的实现是由C
    // 写的
        ArrayList<?> v = (ArrayList<?>) super.clone();
        // 通过调用Arrays.copyOf方法进行数据的copy
        v.elementData = Arrays.copyOf(elementData, size);
        // 指定新的ArrayList集合的修改次数为0
        v.modCount = 0;
        // 返回新集合
        return v;
    } catch (CloneNotSupportedException e) {
        // this shouldn't happen, since we are Cloneable
        throw new InternalError(e);
    }
}
// ---------------------------Arrays类中--------------------------------
   @SuppressWarnings("unchecked")
    public static <T> T[] copyOf(T[] original, int newLength) {
        return (T[]) copyOf(original, newLength, original.getClass());
    }
    // ==============================================
    public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
        @SuppressWarnings("unchecked")
        // 三元校验 用于校验是生产一个默认类型的数组还是一个指定类型的数组
        T[] copy = ((Object)newType == (Object)Object[].class)
            ? (T[]) new Object[newLength]
            : (T[]) Array.newInstance(newType.getComponentType(), newLength);
        // 将原数组中数据copy到新数组中并返回新数组    
        System.arraycopy(original, 0, copy, 0,
                         Math.min(original.length, newLength));
        return copy;
    }

(注意:copy数组的内存容量与其原数组的元素个数相同)

克隆补充知识

浅拷贝和深拷贝

浅拷贝和深拷贝的区别在于拷贝对象中引用类型是否进行了copy。浅拷贝,深拷贝在对基础元素进行copy时效果相同,但在引用类型copy是浅拷贝拷贝的是索引,深拷贝则是copy引用对象后重新指定到新的引用对象。

RandomAccess接口

​ RandomAccess接口为标记接口,实现该接口的类随机遍历效率要高于顺序遍历,ArrayList实现了该接口。

// 随机访问
for (int i = 0; i < list.size(); i++) {
     // 取出集合的每一个元素
     list.get(i);
}
// 顺序访问
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()){
  iterator.next();
}

在ArrayList中随机访问效率高于顺序访问,在LinkedList中顺序访问效率高于随机访问。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值