ArrayList源码分析

ArrayList 实现了List接口,list接口继承了collection类

面试问题:

ArrayList插入数据一定慢吗?
ArrayList插入删除数据性能的快慢取决于下标距离数组末端的距离,ArrayList可以作为堆栈很合适,push和pop操作完全不涉及数据移动操作。

ArrayList list = new ArrayList(20); 中的list扩充几次?
答案是0次,他的构造方法又写

ArrayList的优点是:可以根据下标快速的查找出数据
缺点是:增删操作非常的消耗性能

1.首先从创建开始:

ArrayList提供了三个构造方法
1.无参构造

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
 }

即创建一个长度为0的Object数组

2.参数为int

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

判断int值的大小
大于0创建一个长度为int值的Object类型的数组
等于0 创建一个长度为0的Object数组(相当于无参构造)
小于0 抛出异常

3.参数为 Collection对象

    public ArrayList(Collection<? extends E> c) {
        // 先将传入的对象转化为数组
        elementData = c.toArray();
        // 判断size大小
        if ((size = elementData.length) != 0) {
            if (elementData.getClass() != Object[].class)
            	// 如果不为空,深拷贝
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;
            // Object[] EMPTY_ELEMENTDATA = {};
        }
    }

三步:
1.将传入的Collection转化为数组
2.判断数组的长度
小于0,将一个长度为0的Object数组赋值给他
3.大于0,深拷贝

2. 提供的方法:

add:
提供的add方法有两个:

 public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

因为在初始化的时候创建的都是大小为0的数组,则第一次添加元素的时候this.size+1 = 1

    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        // elementData = {}
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        	// 参数(10,1) 返回最大的数
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }

返回10

    private void ensureExplicitCapacity(int minCapacity) {
        // 修改次数+1    开始为0
        modCount++;
        // 数组需要的最小长度-数组长度
        if (minCapacity - elementData.length > 0)
        // 扩容
            grow(minCapacity);
    }

返回的是10(数组存储所需要的最小的size) – 数组现在的size > 0

扩容

    private void grow(int minCapacity) {
        int oldCapacity = elementData.length;
        // 扩容1.5倍
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        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);
    }

总结:
添加之前先将数组size+1,用来判断数组能否存储的下,假如是第一次add初始化数组的长度为10,
否则扩容 1.5倍

Arrays.copyOf(elementData, newCapacity);

两个参数的add

    public void add(int index, E element) {
       	// 判断index的数是否大于size或者小于0
        rangeCheckForAdd(index);
		
		// size+1  判断够不够存储
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        elementData[index] = element;
        size++;
    }

步骤:
先判断index下标副不符合规定,然后size+1 看够不够存,不够1.5扩容 ,
充足就是用arraycopy进行数组的复制(从index的位置复制,然后将传入的数加到index中)

3. 获取数据

get方法

    public E get(int index) {
        rangeCheck(index);

        return elementData(index);
    }

    E elementData(int index) {
        return (E) elementData[index];
    }

4.删除元素

remove();

    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);
        elementData[--size] = null; // clear to let GC do its work

        return oldValue;
    }

需要留意的是remove 是将位置+1后面的元素向前移动一位,最后一位设置为null

其他的不看了哈哈阿

总结

ArrayList 的add,remove都需要将数组copy然后移动,,非常 的耗费性能
但是get(index)非常的快捷

ArrayList 的remove方法并不会减少数组的长度

ArrayList底层是一个数组,可以扩容 1.5倍

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值