自己写的LIst与ArrayList做add方法的性能对比

自己写的LIst与ArrayList做add方法的性能对比

源码分析

大家都知道,在ArrayList的源码中一开始存储元素的数组长度是0,如果我们要添加元素,添加第一个时,ArrayList存储元素的数组长度会变为10,当我们添加元素超过10的时候,它会将数组长度扩容到15,后面每次我们每次添加元素到超过当前数组长度时,它会进行1.5倍的扩容,以下是源码:

private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        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);
    }

其中第四行代码newCapacity = oldCapacity + (oldCapacity >> 1)这一句意思就是新的数组容量 = 原来的容量右移一位(也就是除以2),再加上原来的数组容量,也就是1.5倍扩容

两个add方法的对比

下面我们自己写一个List类,来模仿ArrayList

public class MyList <E>{
    private int size = 0;
    Object[] obj = new Object[0];
    public void add(E data){
        Object[] newarr = new Object[obj.length+1];
        for (int i = 0; i < obj.length; i++) {
            newarr[i] = obj[i];
        }
        newarr[obj.length] = data;
        obj = newarr;
        size++;


    }
}

我的add方法和 ArrayList一样,先设置一个存贮元素的数组,初始长度为0,由于不清楚要输入的是什么引用类型的元素,所以设置的是Object类型数组,用泛型来适应用户任意的输入类型。不同的是,我们的add方法原理是用户每添加一个元素,就响应的将长度扩容1个单位。
下面是性能对比:

import java.util.ArrayList;
public class ListDemo {
    public static void main(String[] args) {
        MyList<Integer> myList = new MyList<>();
        ArrayList<Integer> myArr = new ArrayList<>();
        int num = 100000;
        long startTime = System.currentTimeMillis();
        for (int i = 0; i <num; i++) {
            myList.add(i);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("myList添加元素用时:"+(endTime-startTime));
        long startTime_ = System.currentTimeMillis();
        for (int i = 0; i < num; i++) {
            myArr.add(i);
        }
        long endTime_ = System.currentTimeMillis();
        System.out.println("ArrayList添加元素用时:"+(endTime_-startTime_));

    }
}

下面是输出结果

com.wc.ListDemo.ListDemo
myList添加元素用时:7508毫秒
ArrayList添加元素用时:3毫秒

总结

可以看出,我们写的add方法性能远不及ArrayList的add方法,这是因为我们每添加一个元素都要重新申请一个新数组,也就是一段新的内存空间,将原来数组的元素拷贝进去,再加入新添加的数据。而ArrayList扩容远没有那么频繁,并且扩招是用的位运算,大家知道位运算是最快的,这也就是ArrayList add方法耗时如此短的原因。

那么,为什么ArrayList是设置的是1.5倍扩容呢,我的理解是:

*1.首先扩容倍率如果大于2,如果用户很多时候只是在原来基础上添了很少的数据,那么过于浪费内存空间。

2.如果倍率过低,极端的情况像我上面写的一样,每添加一个的时候再扩容一次,那么就会过于频繁的申请内存,也会造成过多的时间代价,性能会比较差,就像我上面写的一样,耗时相对大很多。*

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值