ArrayList源码解析

来看一下源码

public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable {
    //序列化ID,跟数据库的主键角色差不多
    private static final long serialVersionUID = 8683452581122892189L;
    //实体,arrayList中实际用来存储数据的东西,其实就一集合。但是此集合用transient来修饰,也就是说这东西没法     序列化,但是arrayList实际上是可以把数据持久化的,后续咱们慢慢看。
    private transient Object[] elementData;
    //arrayList中存数的对象个数(注意是对象个数,不是arrayList的长度)
    private int size;

    //构造方法,实例化的时候会构造一个集合,集合长度就是传入的数据长度
    public ArrayList(int var1) {
        if(var1 < 0) {
            throw new IllegalArgumentException("Illegal Capacity: " + var1);
        } else {
            this.elementData = new Object[var1];
        }
    }

    //List list = new arrayList()这样的时候会默认构建一个长度为10的集合(数组)
    public ArrayList() {
        this(10);
    }

    //Collection其实是List接口所继承的,通俗点说就是可以List list = new arrayList(list0);因为list实现了Collection接口
    //接下来再把var1的数据都赋给当前对象,此时的size是var1中的实际长度(对象的个数)
    public ArrayList(Collection<? extends E> var1) {
        this.elementData = var1.toArray();
        this.size = this.elementData.length;
        if(this.elementData.getClass() != Object[].class) {
            this.elementData = Arrays.copyOf(this.elementData, this.size, Object[].class);
        }

    }

    //这方法用来调整大小的,用人话说就是:如果当前数组的长度比数组内对象的个数要大,就把当前数组按照实际大小复制一份,赋给当前数组
    public void trimToSize() {
        ++this.modCount;
        int var1 = this.elementData.length;
        if(this.size < var1) {
            this.elementData = Arrays.copyOf(this.elementData, this.size);
        }

    }

    //这方法有点意思,数组初始化后就无法修改大小,但是arrayList可以,就是因为在使用arrayList的时候可能会创建很多的数组对象
    //看逐句分析
    public void ensureCapacity(int var1) {//传入大小
        ++this.modCount;
        int var2 = this.elementData.length;//获取当前list对象中数组的长度
        if(var1 > var2) {//如果传入的大小比当前数组的长度(不是size)要大,
            Object[] var3 = this.elementData;//声明一个数组,指向当前对象的数组
            int var4 = var2 * 3 / 2 + 1;//扩容算法,结果为当前list的数组的长度*3/2+1,
            if(var4 < var1) {//如果传入的大小比扩容后的大小还要大的话
                var4 = var1;//那就取传入数值好了
            }

            this.elementData = Arrays.copyOf(this.elementData, var4);//按照扩容后的数值或者传入的数值copy一份新的数组赋给当前数组
            
            //综上,使用此方法扩大的容量并不一定就是传入的大小
            //比如,一个list的大小为20,这时候使用ensureCapacity(25),此时list的数组大小为31,而不是传入的25
        }

    }

    //返回数组中实际对象的数量
    public int size() {
        return this.size;
    }

    //判断这list内是否有东西
    public boolean isEmpty() {
        return this.size == 0;
    }

    //判断是否包含var1,
    public boolean contains(Object var1) {
        return this.indexOf(var1) >= 0;
    }

    //如果传入的var1为null的话,他就找到数组内第一个为空的值,然后返回它的位置
    //如果不为空的时候,就返回第一次遇见这个对象的位置
    //很重要一点,这里的equals是Object类中的equals,很抱歉,它并没有重写,用的“==”判断,所以,此处只能判断基本数据类型,而没法判断引用数据类型
    //所以千万不要傻到写indexOf(person1)。
    //而基本数据类型中之所以能判断String,是因为string重写了equals
    public int indexOf(Object var1) {
        int var2;
        if(var1 == null) {
            for(var2 = 0; var2 < this.size; ++var2) {
                if(this.elementData[var2] == null) {
                    return var2;
                }
            }
        } else {
            for(var2 = 0; var2 < this.size; ++var2) {
                if(var1.equals(this.elementData[var2])) {
                    return var2;
                }
            }
        }

        return -1;
    }

    //倒着判断,一回事
    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;
    }

    //克隆,但是super.clone实现的是浅拷贝,也就是在栈里多个声明的数据,但是堆里并没有复制,相当于只拷贝个指针
    //所以,下面需要把这个list的数组拷贝过去,实现深拷贝
    public Object clone() {
        try {
            ArrayList var1 = (ArrayList)super.clone();
            var1.elementData = Arrays.copyOf(this.elementData, this.size);
            var1.modCount = 0;
            return var1;
        } catch (CloneNotSupportedException var2) {
            throw new InternalError();
        }
    }

    //把数组copy一份返回来,返回类型是object,没法定义返回的数组类型
    public Object[] toArray() {
        return Arrays.copyOf(this.elementData, this.size);
    }

    //与上面不同,可以自定义返回的数组类型
    public <T> T[] toArray(T[] var1) {
        if(var1.length < this.size) {//如果传入的数组长度比当前数组长度小
            return (Object[])Arrays.copyOf(this.elementData, this.size, var1.getClass());//就按照当前数组的长度,并转化为传入数组的类型,再返回
        } else {//如果传入的数组长度比当前数组长度要大
            System.arraycopy(this.elementData, 0, var1, 0, this.size);//还是按照当前数组的长度复制一份再返回
            if(var1.length > this.size) {
                var1[this.size] = null;//去小尾巴,因为size是从1开始,而这里是复制从0到size,所以会多出来一个
            }
          
            return var1;//返回var1
        }
        
        //以上有个需要注意的点:如果传入的数组的长度比list中的数组小的话则按照list数组的长度返回,此时返回的数组其实是在堆内存中重新new的一个数组
        //上源码:Object[] var3 = var2 == Object[].class?(Object[])(new Object[var1]):(Object[])((Object[])Array.newInstance(var2.getComponentType(), var1));
        //也就是说,此时返回的数组已经不是传入的那个数组了,它在堆内存中的地址已经变了
    }

    //没啥说的,返回值
    public E get(int var1) {
        this.RangeCheck(var1);
        return this.elementData[var1];
    }

    //跟api文档说的一样,set元素,再把原来的元素返回回来
    public E set(int var1, E var2) {
        this.RangeCheck(var1);
        Object var3 = this.elementData[var1];
        this.elementData[var1] = var2;
        return var3;
    }

    //添加一个元素,也没啥好说的
    public boolean add(E var1) {
        this.ensureCapacity(this.size + 1);
        this.elementData[this.size++] = var1;
        return true;
    }

    //添加数据
    public void add(int var1, E var2) {
        if(var1 <= this.size && var1 >= 0) {//确保添加的位置不逗逼
            this.ensureCapacity(this.size + 1);//保证长度
            System.arraycopy(this.elementData, var1, this.elementData, var1 + 1, this.size - var1);//移动复制数据
            this.elementData[var1] = var2;//放置数据
            ++this.size;//数据个数增加
        } else {
            throw new IndexOutOfBoundsException("Index: " + var1 + ", Size: " + this.size);//否则抛出越界异常
        }
    }

   //删除指定位置上的数据
    public E remove(int var1) {
        this.RangeCheck(var1);//验证var1
        ++this.modCount;
        Object var2 = this.elementData[var1];//记录var1上的数据
        int var3 = this.size - var1 - 1;//计算需要复制的长度
        if(var3 > 0) {
            System.arraycopy(this.elementData, var1 + 1, this.elementData, var1, var3);//后面的数据往前移动复制
        }

        this.elementData[--this.size] = null;//最后一个位置的数据设为空
        return var2;//返回被删除的数据
    }

    //按照内部元素来删除(只删除第一个与它匹配的值)
    public boolean remove(Object var1) {
        int var2;
        if(var1 == null) {//传入的var1为空,就遍历找到为空的值,然后删除
            for(var2 = 0; var2 < this.size; ++var2) {
                if(this.elementData[var2] == null) {
                    this.fastRemove(var2);
                    return true;
                }
            }
        } else {
            for(var2 = 0; var2 < this.size; ++var2) {
                if(var1.equals(this.elementData[var2])) {//同样,object的equals没有被重写,引用数据类型无法这样判断
                    this.fastRemove(var2);
                    return true;
                }
            }
        }

        return false;
    }

    //没啥说的,用来执行案位置删除的一个私有方法,供ArrayList内部调用
    private void fastRemove(int var1) {
        ++this.modCount;
        int var2 = this.size - var1 - 1;
        if(var2 > 0) {
            System.arraycopy(this.elementData, var1 + 1, this.elementData, var1, var2);
        }

        this.elementData[--this.size] = null;
    }

    //没啥说的,全部干掉
    public void clear() {
        ++this.modCount;

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

        this.size = 0;
    }

    //把实现Collection接口的对象内部的元素按顺序添加到当前list的末尾
    public boolean addAll(Collection<? extends E> var1) {
        Object[] var2 = var1.toArray();
        int var3 = var2.length;
        this.ensureCapacity(this.size + var3);
        System.arraycopy(var2, 0, this.elementData, this.size, var3);//从size这个位置开始复制
        this.size += var3;
        return var3 != 0;
    }

    //在指定位置上添加集合数据,其它的数据往后复制移动
    public boolean addAll(int var1, Collection<? extends E> var2) {
        if(var1 <= this.size && var1 >= 0) {
            Object[] var3 = var2.toArray();
            int var4 = var3.length;
            this.ensureCapacity(this.size + var4);//扩充的大小是当前数据量的大小加上var2的长度
            int var5 = this.size - var1;
            if(var5 > 0) {
                System.arraycopy(this.elementData, var1, this.elementData, var1 + var4, var5);//把list的数组中》=var1的数据放到var1+var4的位置上(中间留出var2的长度)
            }

            System.arraycopy(var3, 0, this.elementData, var1, var4);//再把var2转化的数组(var3)复制进刚才腾出的位置上
            this.size += var4;//修改数据长度记录
            return var4 != 0;//看var2中是否有数据,就是看有没改变原list,改变则返回true,否则false
        } else {
            throw new IndexOutOfBoundsException("Index: " + var1 + ", Size: " + this.size);
        }
    }

    //移除此集合中var1到var2之间的数据,其中包括var1但不包括var2
    protected void removeRange(int var1, int var2) {
        ++this.modCount;
        int var3 = this.size - var2;//截取数据后,后面一段数据的长度
        //将后面的数据复制到var1处,具体为何包括var1却不包括var2画图就能搞清楚
        System.arraycopy(this.elementData, var2, this.elementData, var1, var3);
        //将后面多余的数据清空(不懂画图)
        for(int var4 = this.size - (var2 - var1); this.size != var4; this.elementData[--this.size] = null) {
            ;
        }

    }

    //检测是否越界
    private void RangeCheck(int var1) {
        if(var1 >= this.size) {
            throw new IndexOutOfBoundsException("Index: " + var1 + ", Size: " + this.size);
        }
    }

    //序列化相关,具体内容我也不清楚
    private void writeObject(ObjectOutputStream var1) throws IOException {
        int var2 = this.modCount;
        var1.defaultWriteObject();
        var1.writeInt(this.elementData.length);

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

        if(this.modCount != var2) {
            throw new ConcurrentModificationException();
        }
    }

    private void readObject(ObjectInputStream var1) throws IOException, ClassNotFoundException {
        var1.defaultReadObject();
        int var2 = var1.readInt();
        Object[] var3 = this.elementData = new Object[var2];

        for(int var4 = 0; var4 < this.size; ++var4) {
            var3[var4] = var1.readObject();
        }

    }
}






你可能感兴趣的:(ArrayList源码解析)