ArrayList源码分析(一)

ArrayList源码分析(一)
这是Java源码分析的第一章的第一部分 万事开头难,因此开头写详细一点,后面熟练以后可能会简写。

类定义

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

常量

serialVersionUID

private static final long serialVersionUID = 8683452581122892189L;

实现Serializable接口的目的是为类可持久化,比如在网络传输或本地存储,为系统的分布和异构部署提供先决条件。若没有序列化,现在我们所熟悉的远程调用,对象数据库都不可能存在,类的序列化是通过serialVersionUID 实现的。

DEFAULT_CAPACITY

private static final int DEFAULT_CAPACITY = 10;

默认容量是10,ArrayList刚创建时,容量为0,一旦加入第一个元素时,容量就变为10,当容量满后会自动扩容,每次扩容大小为原来的1.5倍(后文会分析到)。

EMPTY_ELEMENTDATA & DEFAULTCAPACITY_EMPTY_ELEMENTDATA

private static final Object[] EMPTY_ELEMENTDATA = {};
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

elementData

transient Object[] elementData;

elementData是我们的核心数组,即存储和扩容的对象,因此ArrayList的底层是基于数组实现的 所以它访问查询快,增删慢,注意elementData是并不是私有的,源码给出解释是为了简化嵌套类的调用。

size

private int size;

ArrayList的大小

构造方法

public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

这个构造方法可以指定初始容量

public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

这个无参构造,默认容量为10

public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

这个构造函数,参数是一个特定的集合Collection<? extends E> c,elementData = c.toArray();先把c变成数组赋值给核心数组。
但是这里要对elementData 的类型进行判断。看它是不是Object类型。
看下面两行代码:

System.out.println(Object.class);
        System.out.println(Object[].class);

输出结果为:
class java.lang.Object
class [Ljava.lang.Object;
这是属于Object类型,

ArrayList<String> list = new ArrayList<>(5);
        System.out.println(list.getClass());
        System.out.println(list.toArray().getClass());

输出结果为:
class java.util.ArrayList
class [Ljava.lang.Object;
因为toArray()方法返回的是Object[]类型,属于Object类

源码中的注释给出toArray()方法不一定返回Object[]类型
// c.toArray might (incorrectly) not return Object[] (see 6260652)
举例看这行代码:

System.out.println(Arrays.asList("abc").toArray().getClass());

输出结果为:
class [Ljava.lang.String;
发现是String[]类 并不是Object[]类
这样最终会导致ArrayList类中 elementData 更新元素时 无法添加Object类型的元素,要避免这种情况,判断:elementData.getClass() != Object[].class,不行的话调用Arrays.copyOf方法来实现把类型变为Object。

例子说明:

ArrayList<String> list = new ArrayList<>();
        Object o = new Object();
        list.add(o);

报错:
java: 对于add(java.lang.Object), 找不到合适的方法
方法 java.util.Collection.add(java.lang.String)不适用
(参数不匹配; java.lang.Object无法转换为java.lang.String)
父类转化不成子类,加强转也不行

ArrayList<String> list = new ArrayList<>();
        Object o = new Object();
        list.add( (String) o);

报错 java.lang.Object cannot be cast to java.lang.String

反之 父类是可以转化为子类的 下面代码就没有问题。

ArrayList<Object> list = new ArrayList<>();
        String s = new String();
        list.add(s);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值