java arraylist 参数_Java ArrayList 详解

只记录目前为止关注的。JDK1.8

一、基础属性

1.1 内部参数

//空存储实例。直接new ArrayList()便是以该空数组作为实例

private static final Object[] EMPTY_ELEMENTDATA = {};

//默认容量大小,在由空实例进行首次扩容时,扩到到该长度。

//实际使用中,并未实际存在Capacity这个参数,需要扩容时直接根据旧数组的length进行扩容

private static final int DEFAULT_CAPACITY = 10;

//实际存储数组

transient Object[] elementData;

//存储元素个数

private int size;

//该字段用于迭代器的fail-fast机制【参考另一篇文章】

protected transient int modCount = 0;

1.2 三个重载构造方法

//构建一个空实例,elementData指向容量为0的空数组

public ArrayList() {

this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;

}

//以给定容量初始化存储数组

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);

}

}

//以集合初始化创建列表

//步骤:1. 调用toArray(),将给定集合转成数组(以ArrayList为例,toArray()返回的是实际存在元素的那部分数组,即[0,size))

//2. 让size直接等于给定集合的数组长度

//3. 判断size如果为0则直接创建空存储实例,否则使用Arrays.copyOf将给定集合数组复制一份(浅拷贝),作为存储数组

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;

}

}

// ArrayList 的 toArray()源码,复制[0,size)部分返回

public Object[] toArray() {

return Arrays.copyOf(elementData, size);

}

二、操作及策略

2.1 动态扩容

扩容策略:当数组全满了才扩容,新长度=旧长度*1.5

动态扩容有两个入口:供用户调用的显式扩容ensureCapacity()和添加元素时的隐式扩容ensureCapacityInternal(),不过均是调用ensureExplicitCapacity()来根据传入所需容量值决定是否扩容,最终实际扩容操作在grow()方法中。

//显式扩容入口方法

public void ensureCapacity(int minCapacity) {

int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)

// any size if not default element table

? 0

// larger than default for default empty table. It's already

// supposed to be at default size.

: DEFAULT_CAPACITY;

if (minCapacity > minExpand) {

ensureExplicitCapacity(minCapacity);

}

}

//隐式扩容入口方法

//其中参数 minCapacity 值为 size+1,由add方法调用传入

private void ensureCapacityInternal(int minCapacity) {

ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));

}

//添加方法

public boolean add(E e) {

// 传入最小所需容量为size+1

ensureCapacityInternal(size + 1); // Increments modCount!!

elementData[size++] = e;

return true;

}

//计算所需容量,实则不需要计算

//只是单纯判断当前是否是空实例,为空就话返回 "默认容量"与minCapacity之间的较大值,不为空直接返回minCapacity

//参数 minCapacity 只有两种情况:

// 1. 隐式扩容时,如add()传入,其值为 size+1

// 2. 显式扩容,用户指定

private static int calculateCapacity(Object[] elementData, int minCapacity) {

if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {

return Math.max(DEFAULT_CAPACITY, minCapacity);

}

return minCapacity;

}

//在此处,根据最小所需容量来判断是否实际进行扩容

private void ensureExplicitCapacity(int minCapacity) {

modCount++;

// overflow-conscious code

if (minCapacity - elementData.length > 0) //若已经占满,才进行扩容

grow(minCapacity);

}

//实际扩容方法

//可以看到扩容策略为:length + length*0.5(右移1位缩小1倍)

//然后调用Arrays.copyOf浅复制

private void grow(int minCapacity) {

// overflow-conscious code

int oldCapacity = elementData.length;

int newCapacity = oldCapacity + (oldCapacity >> 1); //旧长度+旧长度*2

if (newCapacity - minCapacity < 0)

newCapacity = minCapacity;

if (newCapacity - MAX_ARRAY_SIZE > 0)

newCapacity = hugeCapacity(minCapacity);

// minCapacity is usually close to size, so this is a win:

elementData = Arrays.copyOf(elementData, newCapacity);

}

2.2 删除操作

ArrayList中有两个remove方法public E remove(int index)和public boolean remove(Object o)

源码实现得其实挺简单,本来还在犹豫有没有必要把remove方法记录下来,但发现有个点值得注意以下:

注意点:JDK对于数组内元素统一移动操作,偏好使用System.arraycopy(ary, srcPos, ary, destPos, len)来移动

//通过给定下标来删除元素,并返回删除元素

public E remove(int index) {

rangeCheck(index); // 检查下标范围

modCount++;

E oldValue = elementData(index); // 合理的话,先获取该元素(等会儿用于返回)

int numMoved = size - index - 1; // 计算待移动元素个数(删除元素后,后面的元素要统一往前挪补上)

if (numMoved > 0)

System.arraycopy(elementData, index+1, elementData, index,

numMoved); // 使用System.arraycopyl来移动数组元素

elementData[--size] = null; // clear to let GC do its work // 删除后size-1,并将先前最后一个元素置null

return oldValue; //返回删除元素

}

// 判断下标是否合理(

private void rangeCheck(int index) {

if (index >= size)

throw new IndexOutOfBoundsException(outOfBoundsMsg(index));

}

// 删除首个与给定元素相等的元素,元素判等使用equal方法

// 成功返回true,失败返回false

public boolean remove(Object o) {

if (o == null) { // 可以删除null节点

for (int index = 0; index < size; index++)

if (elementData[index] == null) {

fastRemove(index); // 参考下面方法注释

return true;

}

} else {

for (int index = 0; index < size; index++)

if (o.equals(elementData[index])) { // 从头开始一个个检查,使用equal判等

fastRemove(index);

return true;

}

}

return false;

}

/*

* 官方注释说得很清楚了:删除元素,但跳过边界检查且不返回删除元素。(就是remove(index)的缩略版

* Private remove method that skips bounds checking and does not

* return the value removed.

*/

private void fastRemove(int index) {

modCount++;

int numMoved = size - index - 1;

if (numMoved > 0)

System.arraycopy(elementData, index+1, elementData, index,

numMoved);

elementData[--size] = null; // clear to let GC do its work

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值