throwable四参构造_ArrayList内部实现原理

数组在创建的时候长度是固定的,那么就有往ArrayList中不断添加对象的时候,那么ArrayList是如何管理这些数组的?

ArrayList内部通过Object[]实现,我们通过分析ArrayList的构造和add和remove和clear方法来分析

一、构造函数

1)空参构造

/**

* Constructs a new {@code ArrayList} instance with zero initial capacity.

*/

public ArrayList() {

array = EmptyArray.OBJECT;

}

array是一个Object[]类型。当我们new一个空参构造时系统调用了EmptyArray.OBJECT属性,EmptyArray仅

仅是一个系统的类库,该类源码如下:

public final class EmptyArray {

private EmptyArray() {}

public static final boolean[] BOOLEAN = new boolean[0];

public static final byte[] BYTE = new byte[0];

public static final char[] CHAR = new char[0];

public static final double[] DOUBLE = new double[0];

public static final int[] INT = new int[0];

public static final Class>[] CLASS = new Class[0];

public static final Object[] OBJECT = new Object[0];

public static final String[] STRING = new String[0];

public static final Throwable[] THROWABLE = new Throwable[0];

public static final StackTraceElement[] STACK_TRACE_ELEMENT = new StackTraceElement[0]; }

也就是说当我们new 一个空参ArrayList的时候,系统内部使用了一个new Object[0]数组。

2)带参构造1

/**

* Constructs a new instance of {@code ArrayList} with the specified

* initial capacity.

*

* @param capacity

* the initial capacity of this {@code ArrayList}.

*/

public ArrayList(int capacity) {

if (capacity < 0) {

throw new IllegalArgumentException("capacity < 0: " + capacity);

}

array = (capacity == 0 ? EmptyArray.OBJECT : new Object[capacity]);

}

该构造函数传入一个int值,该值作为数组的长度值。如果该值小于0,则抛出一个运行时异常。如果等于0,则

使用一个空数组,如果大于0,则创建一个长度为该值的新数组。

3)带参构造2

/**

* Constructs a new instance of {@code ArrayList} containing the elements of

* the specified collection.

*

* @param collection

* the collection of elements to add.

*/

public ArrayList(Collection extends E> collection) {

if (collection == null) {

throw new NullPointerException("collection == null");

}

Object[] a = collection.toArray();

if (a.getClass() != Object[].class) {

Object[] newArray = new Object[a.length];

System.arraycopy(a, 0, newArray, 0, a.length);

a = newArray;

}

array = a;

size = a.length;

}

若调用构造函数的时候传入了一个Collection的子类,那么先判断集合是否为null,为null则抛出空指针异常.如果不是则将集合转换为数组a,然后将该数组赋值为成员变量array,将该数组的长度作为成员变量size.这里面它先判断a.getClass是否等于Object[].class,一般都是相等的,判断是为了增加安全性,toArray方法是Collection接口定义的,因此其所有的子类都是这样的方法,list集合的toArray和Set集合的toArray返回的都是Object[]数组.

二、add方法

add方法有两个重载,这里只研究最简单的那个.

/**

* Adds the specified object at the end of this {@code ArrayList}.

*

* @param object

*

the object to add.

* @return always true

*/

@Override public boolean add(E object) {

Object[] a = array;

int s = size;

if (s == a.length) {

Object[] newArray = new Object[s +

(s < (MIN_CAPACITY_INCREMENT / 2) ?

MIN_CAPACITY_INCREMENT : s >> 1)];

System.arraycopy(a, 0, newArray, 0, s);

array = a = newArray;

}

a[s] = object;

size = s + 1;

modCount++;

return true;

}

1、首先将成员变量array赋值给局部变量a,将成员变量size赋值给局部变量s。

2、判断集合的长度s是否等于数组的长度(如果集合的长度已经等于数组的长度了,说明数组已经满了,该重新

分配新数组了),重新分配数组的时候需要计算新分配内存的空间大小,如果当前的长度小于

MIN_CAPACITY_INCREMENT/2(这个常量值是12,除以2就是 6,也就是如果当前集合长度小于6)则分配12个

长度,如果集合长度大于6则分配当前长度s的一半长度。这里面用到了三元运算符和位运算,s >> 1,意思就是将

s往右移1位,相当于s=s/2,只不过位运算是效率最高的运算。

3、将新添加的object对象作为数组的a[s]个元素。

4、修改集合长度size为s+1

5、modCotun++,该变量是父类中声明的,用于记录集合修改的次数,记录集合修改的次数是为了防止在用迭代

器迭代集合时避免并发修改异常,或者说用于判断是否出现并发修改异常的。

6、return true,这个返回值意义不大,因为一直返回true,除非报了一个运行时异常。

三、remove方法

remove方法有两个重载,这里只研究remove(int index)方法。

/*** Removes the object at the specified location from this list.

*

*@paramindex

* the index of the object to remove.

*@returnthe removed object.

*@throwsIndexOutOfBoundsException

* when {@codelocation < 0 || location >= size()}*/@Overridepublic E remove(intindex) {

Object[] a=array;int s =size;if (index >=s) {

throwIndexOutOfBoundsException(index, s);

}

@SuppressWarnings("unchecked")

E result=(E) a[index];

System.arraycopy(a, index+ 1, a, index, --s -index);

a[s]= null; //Prevent memory leak

size =s;

modCount++;returnresult;

}

1、先将成员变量array和size赋值给局部变量a和s。

2、判断形参index是否大于等于集合的长度,如果成了则抛出运行时异常

3、获取数组中脚标为index的对象result,该对象作为方法的返回值

4、调用System的arraycopy函数

5、接下来就是很重要的一个工作,因为删除了一个元素,而且集合整体向前移动了一位,因此需要将集合最后一个元素设置为null,否则就可能内存泄露。

6、重新给成员变量array和size赋值

7、记录修改次数

8、返回删除的元素

四、clear方法

/**

* Removes all elements from this {@code ArrayList}, leaving it empty.

*

* @see #isEmpty

* @see #size

*/

@Override public void clear() {

if (size != 0) {

Arrays.fill(array, 0, size, null);

size = 0;

modCount++;

}

}

如果集合长度不等于0,则将所有数组的值都设置为null,然后将成员变量size 设置为0即可,最后让修改记录加1.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值