博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java ArrayList 详解
阅读量:5332 次
发布时间:2019-06-14

本文共 6011 字,大约阅读时间需要 20 分钟。

只记录目前为止关注的。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
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; //返回删除元素    }    // 判断下标是否合理(
= 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 }

转载于:https://www.cnblogs.com/simpleito/p/10926385.html

你可能感兴趣的文章
前端笔记-bom
查看>>
MATLAB作图方法与技巧(一)
查看>>
上海淮海中路上苹果旗舰店门口欲砸一台IMAC电脑维权
查看>>
Google透露Android Market恶意程序扫描服务
查看>>
给mysql数据库字段值拼接前缀或后缀。 concat()函数
查看>>
迷宫问题
查看>>
【FZSZ2017暑假提高组Day9】猜数游戏(number)
查看>>
泛型子类_属性类型_重写方法类型
查看>>
eclipse-将同一个文件分屏显示
查看>>
mysql5.x升级至mysql5.7后导入之前数据库date出错的解决方法!
查看>>
对闭包的理解
查看>>
练习10-1 使用递归函数计算1到n之和(10 分
查看>>
Oracle MySQL yaSSL 不明细节缓冲区溢出漏洞2
查看>>
windows编程ASCII问题
查看>>
.net webService代理类
查看>>
Code Snippet
查看>>
Node.js Express项目搭建
查看>>
zoj 1232 Adventure of Super Mario
查看>>
1201 网页基础--JavaScript(DOM)
查看>>
组合数学 UVa 11538 Chess Queen
查看>>