ArrayList 和 LinkedList对比

1.ArrayList 和 LinkedList优缺点

ArrayList:

优点:ArrayList 是实现了基于动态数组的数据结构,因为地址连续,一旦数据存储好了,查询操作效率会比较高(在内存里是连着放的)。
缺点:因为地址连续,ArrayList 要移动数据,所以插入和删除操作效率比较低

LinkedList:

优点:LinkedList 基于双向链表的数据结构,地址是任意的,所以在开辟内存空间的时候不需要等一个连续的地址。
对于新增和删除操作,LinkedList 比较占优势。LinkedList 适用于要头尾操作或插入指定位置的场景。
缺点:因为 LinkedList 要移动指针,所以查询操作性能比较低。

2.ArrayList 和 LinkedList 的区别

1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
2.对于随机访问get和set,ArrayList优于LinkedList,因为LinkedList要移动指针。
3.对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。

3.ArrayList 和 LinkedList的add(从尾部插入)方法

LinkedList

void linkLast(E e) {
        final Node<E> l = last;
        final Node<E> newNode = new Node<>(l, e, null);
        last = newNode;
        if (l == null)
            first = newNode;
        else
            l.next = newNode;
        size++;
        modCount++;
    }

LinkedList插入方法较简单,如果当前集合为空,就把新元素当成头节点,否则就让原来的尾节点指向新节点,size是集合元素数量/集合长度,modCount是集合总共修改次数。

ArrayList

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

ArrayList的插入方法分两步,首先确保内部容量(判断是否需要,如果需要扩容则扩容,否则不扩容),然后让将新元素赋值给集合最后一个元素的下一个元素。

private void ensureCapacityInternal(int minCapacity) {
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

没啥好说的,先看最里面的

private static int calculateCapacity(Object[] elementData, int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    return minCapacity;
}
private static final int DEFAULT_CAPACITY = 10;

第一个重点来了,如果集合还没有元素(空集合),就返回新容量和默认容量中最大的那一个,否则直接返回新容量,所以ArrayList第一次方法扩容之后,容量为10,但是初始容量仍是0,这两点要区分开来。

private void ensureExplicitCapacity(int minCapacity) {
    modCount++;

    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

也没啥好说的,直接看里面的扩容方法。overflow-conscious code下边再解释。

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

    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }
 private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

​ oldCapacity >> 1和oldCapacity /2是等价的(不考虑原始容量为负数且不能被2整除),所以ArrayList第二次及之后每次扩容是原始的1.5倍。hugeCapacity方法就是如果扩容后新容量接近了集合最大容量但没超出(Integer最大数-8),再给扩到Integer最大。Arrays.copyOf方法不多展开了,里面主要是调用native方法将原数组内容复制到新数组。

​ 这里解释一下overflow-conscious code,先说结果,因为集合原始容量如果接近了Integer的最大值,扩容后就会溢出,newCapacity就会变成负数,newCapacity - minCapacity(极小负数-极大正数超过Integer下限)结果也会溢出变成正数,此时newCapacity为负,扩容失败。

4.ArrayList和LinkedList使用效率对比

查询效率肯定是ArrayList快,因为ArrayList是根据集合下标查询,LinkedList需要遍历。

但是插入效率就不一定了。

首先,如果是随机插入,肯定是LinkedList快,ArrayList慢,因为ArrayList需要移动元素。

但是实际业务场景中很多情况是使用add方法进行尾插入,尾插入的话两者效率看上去是一样的,但是也有不同。

LinkedList尾插就是每次new一个节点,然后插入。

ArrayList则多一个个扩容的判断,但是不需要new。

在数据量少的时候,ArrayList需要频繁扩容,插入效率肯定是LinkedList高,但是如果数据量大了,ArrayList只需要偶尔扩容,大部分情况是不需要扩容直接赋值,而LinkedList需要一直new一个新的节点,这时候就是ArrayList快,但是这样的扩容机制也造成了一定的空间浪费。

5.使用场景对比

当需要对数据进行对随机访问的时候,选用 ArrayList。
当需要对数据进行多次增加删除修改时,采用 LinkedList。
如果容量固定,并且只会添加到尾部,不会引起扩容,优先采用 ArrayList。

大多数情况下,使用ArrayList足矣,我所做的项目业务场景下List主要是用来承载Mysql查出来的列表数据,然后返回给前端或者foreach遍历或者stream的foreach遍历,将其中的元素取出进行处理后形成新的集合。这种情况下肯定是ArrayList,因为都是尾部插入且容量固定。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值