ArrayList详解

本文基于jdk1.7进行分析。 

ArrayList是一个非线程安全的有序集合类,它实现了List<E>, RandomAccess, Cloneable, Serializable接口,继承了AbstractList,类名上的泛型E代表ArrayList所存储的元素的类型。

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

全局变量

ArrayList中元素是存储在对象数组中的,我们对ArrayList的操作都是通过对这个对象数组进行操作来实现的。ArrayList有三个全局变量,elementData对象数组用于存储元素,size用于存储List中当前对象的个数,MAX_ARRAY_SIZE用于存储List集合最大容量。

private transient Object[] elementData;//对象数组,用于存储集合中的对象
private int size;//当前List中对象的个数
private static final int MAX_ARRAY_SIZE = 2147483639;//最大List集合容量

构造方法

ArrayList有三个构造方法

方法一:入参是ArrayList初始化容量,如果容量小于0就抛错,否则实例化一个Object对象数组赋值给全局变量elementData;

方法二:没有入参,调用的是方法一,默认对象数组大小为10;

方法三:传入Collection集合的对象,将传入的集合对象转为数组,然后给size赋值,判断如果传入的对象数组不是Object[],则转为Object[]。

    //一:传入初始化集合的size
    public ArrayList(int var1) {
        if (var1 < 0) {
            //如果size<0.抛错
            throw new IllegalArgumentException("Illegal Capacity: " + var1);
        } else {
            //实例化对象数组赋值给全局对象数组elementData 
            this.elementData = new Object[var1];
        }
    }

    //二:不传入初始size,默认大小为10,调用public ArrayList(int var1)
    public ArrayList() {
        this(10);
    }

    //三:传入Collection集合的实例对象
    public ArrayList(Collection<? extends E> var1) {
        //将传入的集合对象转为对象数组
        this.elementData = var1.toArray();
        //赋值对象数组的长度
        this.size = this.elementData.length;
        //如果转化后的数组类型不是Object[],那就赋值转为Object[]
        if (this.elementData.getClass() != Object[].class) {
            this.elementData = Arrays.copyOf(this.elementData, this.size, Object[].class);
        }

    }

get方法

get方法首先调用rangeCheck方法检查数组下标是否越界,然后通过直接传入的数组下标来获取elementData对象数组中的元素。

    //根据元素的位置下标获取对应的元素
    public E get(int var1) {
        this.rangeCheck(var1);
        return this.elementData(var1);
    }

    //范围检查,检查是否数组下标越界
    private void rangeCheck(int var1) {
        if (var1 >= this.size) {
            throw new IndexOutOfBoundsException(this.outOfBoundsMsg(var1));
        }
    }

    //返回数组下标报错信息
    private String outOfBoundsMsg(int var1) {
        return "Index: " + var1 + ", Size: " + this.size;
    }

set方法

进行范围检查,根据传入的var1下标获取到对应位置的元素var3,再将入参var2元素赋值到var1位置,最后返回var1位置上的原有元素var3。

    public E set(int var1, E var2) {
        this.rangeCheck(var1);
        Object var3 = this.elementData(var1);
        this.elementData[var1] = var2;
        return var3;
    }

add方法

add有两个重载方法,一个是直接将元素添加在数组最后,另一个是在指定位置上添加元素

    //方法一,添加元素至ArrayList最后一位
    public boolean add(E var1) {
        //给ArrayList添加元素之前,确保容量足够大
        this.ensureCapacityInternal(this.size + 1);
        //将元素赋予到数组的最后一位
        this.elementData[this.size++] = var1;
        return true;
    }

    //方法二,添加元素至ArrayList指定下标位置
    public void add(int var1, E var2) {
        //检查传入的下标是否超出范围
        this.rangeCheckForAdd(var1);
        //确保容量是否足够
        this.ensureCapacityInternal(this.size + 1);
        //将var1下标开始(包含var1下标位置上的元素)之后的元素全部后移一位
        System.arraycopy(this.elementData, var1, this.elementData, var1 + 1, this.size - var1);
        //将传入的元素var2赋值到var1下标位置
        this.elementData[var1] = var2;
        //当前容量+1
        ++this.size;
    }

    //确保ArrayList容量足够大
    private void ensureCapacityInternal(int var1) {
        ++this.modCount;
        //如果var1大于ArrayList数组长度,进行扩容
        if (var1 - this.elementData.length > 0) {
            this.grow(var1);
        }
    }

    //ArrayList容量扩容
    private void grow(int var1) {
        //获取当前数组长度var2
        int var2 = this.elementData.length;
        //将var2右移一位加上本身得到var3,var3=1.5var2
        int var3 = var2 + (var2 >> 1);
        //如果var3 < var1,则var3=var1
        if (var3 - var1 < 0) {
            var3 = var1;
        }
        
        //如果var3大于ArrayList的最大容量2147483639,则调用hugeCapacity方法得到新的var3
        if (var3 - 2147483639 > 0) {
            var3 = hugeCapacity(var1);
        }
        
        //最后将原数组复制到var3容量的新数组中并赋值给elementData
        this.elementData = Arrays.copyOf(this.elementData, var3);
    }

    //获取ArrayList最大容量
    private static int hugeCapacity(int var0) {
        if (var0 < 0) {
            //如果小于0,内存溢出
            throw new OutOfMemoryError();
        } else {
            //如果容量大于ArrayList所限制的最大容量214783639,则返回2147483647
            return var0 > 2147483639 ? 2147483647 : 2147483639;
        }
    }

    //给添加方法用的范围检查方法
    private void rangeCheckForAdd(int var1) {
        //如果添加位置的下标大于当前ArrayList数组大小或者小于0,抛错
        if (var1 > this.size || var1 < 0) {
            throw new IndexOutOfBoundsException(this.outOfBoundsMsg(var1));
        }
    }

remove方法

    //方法一,返回被删除的元素
    public E remove(int var1) {
        //范围检查
        this.rangeCheck(var1);
        ++this.modCount;
        //获取要被删除的元素
        Object var2 = this.elementData(var1);
        //获取删除元素后剩下的数组长度
        int var3 = this.size - var1 - 1;
        //如果删除后的数组长度不为0,
        if (var3 > 0) {
            //通过数组复制的方式将要删除的元素覆盖掉
            System.arraycopy(this.elementData, var1 + 1, this.elementData, var1, var3);
        }
        //将最后一位设置为null
        this.elementData[--this.size] = null;
        //返回被删除的元素var2
        return var2;
    }

    //方法二,返回是否删除成功
    public boolean remove(Object var1) {
        int var2;
        //如果传入的元素var1为null
        if (var1 == null) {
            //循环查找为null的元素,若找到使用fastRemove删除,然后返回true
            for(var2 = 0; var2 < this.size; ++var2) {
                if (this.elementData[var2] == null) {
                    this.fastRemove(var2);
                    return true;
                }
            }
        }
        //如果传入的元素不为null 
        else {
            //开始循环查找是否有与var1相同的元素,找到则使用fastRemove删除并且返回true
            for(var2 = 0; var2 < this.size; ++var2) {
                if (var1.equals(this.elementData[var2])) {
                    this.fastRemove(var2);
                    return true;
                }
            }
        }

        return false;
    }

    //被remove方法调用
    private void fastRemove(int var1) {
        ++this.modCount;
        //计算出被删除后所剩的数组长度
        int var2 = this.size - var1 - 1;
        //如果长度大于0
        if (var2 > 0) {
            //通过数组复制的方式将元素覆盖掉以达到删除的效果
            System.arraycopy(this.elementData, var1 + 1, this.elementData, var1, var2);
        }
        //将数组最后的元素位置设置为null
        this.elementData[--this.size] = null;
    }

size方法

获取当前ArrayList的容量大小,size方法很简单,就是返回当前ArrayList中的size变量。

public int size() {
    return this.size;
}

isEmpty方法

判断ArrayList是否为空,通过判断size变量是否为0

public boolean isEmpty() {
    return this.size == 0;
}

contains和indexOf方法

contains方法内部调用indexOf方法,若indexOf返回值>=0,则当前ArrayList包含var1元素;

indexOf方法返回的是传入元素的下标

    public boolean contains(Object var1) {
        return this.indexOf(var1) >= 0;
    }

    public int indexOf(Object var1) {
        int var2;
        //如果传入的var1元素为null
        if (var1 == null) {
            //循环ArrayList,查到为null的元素然后返回其下标
            for(var2 = 0; var2 < this.size; ++var2) {
                if (this.elementData[var2] == null) {
                    return var2;
                }
            }
        }
         //若传入的var1元素不为null
         else {
            //循环ArrayList,通过equals比对数组中是否有var1相同的元素,若有则返回其下标
            for(var2 = 0; var2 < this.size; ++var2) {
                if (var1.equals(this.elementData[var2])) {
                    return var2;
                }
            }
        }
        //如果没找到则返回-1
        return -1;
    }

lastIndexOf方法

与indexOf类似都是返回元素所在下标的方法,但是lastIndexOf是从ArrayList的尾部开始循环查找

    public int lastIndexOf(Object var1) {
        int var2;
        if (var1 == null) {
            for(var2 = this.size - 1; var2 >= 0; --var2) {
                if (this.elementData[var2] == null) {
                    return var2;
                }
            }
        } else {
            for(var2 = this.size - 1; var2 >= 0; --var2) {
                if (var1.equals(this.elementData[var2])) {
                    return var2;
                }
            }
        }

        return -1;
    }

toArray方法

这里的toArray方法从表面上看是将ArrayList集合转化为Array数组,其内部实现是将ArrayList中的元素数组复制一份并返回,这里一开始我有些疑惑,为什么不能直接返回elementData,因为它本身就是一个Object数组,后来想想如果直接返回了,则是返回了ArrayList中数组的引用,会对ArrayList中数组造成影响。

    public Object[] toArray() {
        return Arrays.copyOf(this.elementData, this.size);
    }

 这个toArray的重载方法我不太能够理解,因为它在传入数组长度大于等于ArrayList中数组长度时,将ArrayList中数组元素赋值到传入的数组中,然后如果传入的数组大于ArrayList中数组长度,则将传入的var1数组中的size下标的元素赋值为null,这里的

    public <T> T[] toArray(T[] var1) {
        //如果传入的数组长度小于当前ArrayList中数组长度,则返回整个ArrayList数组
        if (var1.length < this.size) {
            return (Object[])Arrays.copyOf(this.elementData, this.size, var1.getClass());
        }
        //若传入的数组长度大于等于当前ArrayList中数组长度
        else {
            //将ArrayList中数组全部复制到var1数组中
            System.arraycopy(this.elementData, 0, var1, 0, this.size);
            //如果传入的var1数组长度大于当前ArrayList中数组长度size
            if (var1.length > this.size) {
                //将var1数组中的size下标的元素设置为null,这里如果var1的length比size大很多,那么仅仅将size位置上的元素赋值为null又有什么意义呢,size位置后面的元素还是没有变动,这里有点奇怪
                var1[this.size] = null;
            }

            return var1;
        }
    }

clear方法

ArrayList的清空方法,循环ArrayList内置数组设值为null,将size赋值为0

    public void clear() {
        ++this.modCount;

        for(int var1 = 0; var1 < this.size; ++var1) {
            this.elementData[var1] = null;
        }

        this.size = 0;
    }

removeAll和retainAll方法 TODO

removeAll和retainAll调用了同一个私有方法,但是入参不同,removeAll是用于删除ArrayList中所有元素的方法,retainAll方法是用于判断集合之间是否有交集的方法。

    public boolean removeAll(Collection<?> var1) {
        return this.batchRemove(var1, false);
    }

    public boolean retainAll(Collection<?> var1) {
        return this.batchRemove(var1, true);
    }

    //字面意思是批量删除
    private boolean batchRemove(Collection<?> var1, boolean var2) {
        //将var3赋值ArrayList的数组elementData
        Object[] var3 = this.elementData;
        int var4 = 0;
        int var5 = 0;
        boolean var6 = false;

        while(true) {
            boolean var11 = false;

            try {
                var11 = true;
                if (var4 >= this.size) {
                    var11 = false;
                    break;
                }

                if (var1.contains(var3[var4]) == var2) {
                    var3[var5++] = var3[var4];
                }

                ++var4;
            } finally {
                if (var11) {
                    if (var4 != this.size) {
                        System.arraycopy(var3, var4, var3, var5, this.size - var4);
                        var5 += this.size - var4;
                    }

                    if (var5 != this.size) {
                        for(int var9 = var5; var9 < this.size; ++var9) {
                            var3[var9] = null;
                        }

                        this.modCount += this.size - var5;
                        this.size = var5;
                        var6 = true;
                    }

                }
            }
        }

        if (var4 != this.size) {
            System.arraycopy(var3, var4, var3, var5, this.size - var4);
            var5 += this.size - var4;
        }

        if (var5 != this.size) {
            for(int var7 = var5; var7 < this.size; ++var7) {
                var3[var7] = null;
            }

            this.modCount += this.size - var5;
            this.size = var5;
            var6 = true;
        }

        return var6;
    }

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值