Java 中 ArrayList 和 LinkedList 有什么区别

在Java中,ArrayList和LinkedList是两种常见的集合类。它们都实现了List接口,提供了类似数组的功能,可以存储任意类型的对象。虽然它们都可以实现相同的功能,但是它们的底层实现方式有所不同,因此在性能和用途上也存在一些差异。

在这里插入图片描述

ArrayList

ArrayList是一个基于数组实现的动态数组,它可以自动扩展容量以容纳新的元素。在ArrayList中,元素存储在一个Object数组中,可以通过索引访问数组中的元素。

底层原理

ArrayList底层使用数组实现,每个ArrayList实例都包含一个Object类型的数组elementData,用于存储元素。当ArrayList中的元素数量超过数组容量时,ArrayList会自动扩容,创建一个新的数组,并将原数组中的元素复制到新数组中。

private transient Object[] elementData;

在ArrayList中,添加元素的操作可以分为两种情况:

  • 如果数组容量足够,直接将元素添加到数组末尾。
  • 如果数组容量不足,需要先对数组进行扩容,然后将元素添加到数组末尾。
public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}

private void ensureCapacityInternal(int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    ensureExplicitCapacity(minCapacity);
}

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

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

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

在ArrayList中,删除元素的操作可以分为两种情况:

  • 如果要删除的元素在数组中间,需要将后续的元素向前移动,覆盖要删除的元素。
  • 如果要删除的元素在数组末尾,直接将数组长度减一即可。
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;
}

特点

  • ArrayList是一个基于数组实现的动态数组,可以自动扩容以容纳新的元素。
  • 在ArrayList中,元素可以通过索引访问,因此随机访问效率较高。
  • 在ArrayList中,插入和删除操作可能需要移动后续的元素,因此效率较低。

源码

ArrayList的源码可以在JDK中找到,位于java.util包中。

LinkedList

LinkedList是一个基于链表实现的双向链表,它可以动态地添加、删除元素。在LinkedList中,元素存储在一个节点(Node)中,每个节点包含一个元素和前后指针。

底层原理

LinkedList底层使用双向链表实现,每个LinkedList实例都包含一个Node类型的first和last节点,用于表示链表的头和尾。

java

Copy

private transient Node<E> first;
private transient Node<E> last;

在LinkedList中,添加元素的操作可以分为三种情况:

  • 如果链表为空,将新节点设置为first和last节点。
  • 如果要添加的元素在链表头部,将新节点设置为first节点,并将原first节点作为新节点的后继。
  • 如果要添加的元素在链表尾部,将新节点设置为last节点,并将原last节点作为新节点的前驱。
public boolean add(E e) {
    linkLast(e);
    return true;
}

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中,删除元素的操作可以分为三种情况:

  • 如果要删除的元素是first节点,将first节点设置为原first节点的后继。
  • 如果要删除的元素是last节点,将last节点设置为原last节点的前驱。
  • 如果要删除的元素在链表中间,将要删除的节点的前驱和后继节点连接起来,然后将要删除的节点的前驱和后继节点分别指向要删除节点的前驱和后继节点。
public E remove(int index) {
    checkElementIndex(index);
    return unlink(node(index));
}

E unlink(Node<E> x) {
    final E element = x.item;
    final Node<E> next = x.next;
    final Node<E> prev = x.prev;

    if (prev == null) {
        first = next;
    } else {
        prev.next = next;
        x.prev = null;
    }

    if (next == null) {
        last = prev;
    } else {
        next.prev = prev;
        x.next = null;
    }

    x.item = null;
    size--;
    modCount++;
    return element;
}

特点

  • LinkedList是一个基于链表实现的双向链表,可以动态地添加、删除元素。
  • 在LinkedList中,元素不能通过索引访问,因此随机访问效率较低。
  • 在LinkedList中,插入和删除操作只需要改变相邻节点的指针,因此效率较高。

源码

LinkedList的源码可以在JDK中找到,位于java.util包中。

ArrayList和LinkedList的比较

从底层实现上来看,ArrayList和LinkedList有以下区别:

  • ArrayList底层使用数组实现,LinkedList底层使用链表实现。
  • 在ArrayList中,元素可以通过索引访问,因此随机访问效率较高,但是插入和删除操作效率较低。在LinkedList中,元素不能通过索引访问,因此随机访问效率较低,但是插入和删除操作效率较高。
  • 在ArrayList中,添加和删除操作需要移动后续的元素,因此效率较低。在LinkedList中,添加和删除操作只需要改变相邻节点的指针,因此效率较高。
  • 在ArrayList中,扩容时需要创建一个新的数组,并将原数组中的元素复制到新数组中,效率较低。在LinkedList中,不需要扩容,因为链表可以动态地添加、删除节点。

由于ArrayList和LinkedList的底层实现方式不同,因此它们适用的场景也不同:

  • 如果需要频繁访问集合中的元素,并且集合的大小不会经常改变,选择ArrayList会更加合适,因为ArrayList可以通过索引快速访问元素,效率较高。
  • 如果需要频繁添加、删除集合中的元素,选择LinkedList会更加合适,因为LinkedList可以快速地添加、删除节点,效率较高。

总结

ArrayList和LinkedList是Java中常见的集合类,它们都实现了List接口,提供了类似数组的功能,可以存储任意类型的对象。ArrayList底层使用数组实现,LinkedList底层使用链表实现。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Python徐师兄

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值