0
点赞
收藏
分享

微信扫一扫

Java LinkedList与ArrayList源码解析:根本区别和表面区别的详解

在Java中,LinkedList和ArrayList是两个常见的集合类。它们都实现了List接口,但它们在实现方式上有很大的区别。本篇博客将详细解析LinkedList和ArrayList的源码,解释它们的根本区别和表面区别,并提供详细的代码解释。

  1. LinkedList与ArrayList的根本区别:
  • 数据结构:LinkedList是基于链表实现的,而ArrayList是基于数组实现的。
  • 数据访问:LinkedList通过节点之间的链接进行数据访问,而ArrayList直接通过索引访问数组中的元素。
  1. LinkedList与ArrayList的表面区别: 2.1 内存占用:
  • LinkedList:由于需要存储节点本身和节点之间的链接,LinkedList的内存消耗比较大。
  • ArrayList:只需存储数组和元素本身,所以ArrayList相对较省内存。

2.2 插入和删除操作:

  • LinkedList:由于是基于链表的数据结构,插入或删除元素时只需要调整节点之间的链接,因此插入和删除操作的时间复杂度为O(1)。
  • ArrayList:由于是基于数组的数据结构,插入或删除元素时需要移动数组中的元素,时间复杂度为O(n)。

2.3 随机访问操作:

  • LinkedList:由于需要从头节点开始遍历链表直到达到目标节点,所以随机访问元素的时间复杂度为O(n)。
  • ArrayList:由于使用数组实现,可以通过索引直接访问数组中的元素,所以随机访问元素的时间复杂度为O(1)。
  1. LinkedList源码解析: LinkedList的底层实现是一个双向链表,其中的每个节点(Node)都包含了元素值、前驱节点和后继节点。它通过节点之间的链接来实现数据的添加、删除和访问操作。下面是LinkedList源码的详细解释及关键方法解析:
public class LinkedList<E> extends AbstractSequentialList<E>
        implements List<E>, Deque<E>, Cloneable, java.io.Serializable {
    private Node<E> first; // 链表的第一个节点
    private Node<E> last; // 链表的最后一个节点
    private int size; // 链表的大小

    private static class Node<E> {
        E item; // 节点元素值
        Node<E> next; // 后继节点
        Node<E> prev; // 前驱节点

        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }
    
    // 添加元素到链表末尾
    public boolean add(E e) {
        linkLast(e);
        return true;
    }

    // 在链表指定位置插入元素
    public void add(int index, E element) {
        if (index == size)
            linkLast(element);
        else
            linkBefore(element, node(index));
    }

    // 删除链表指定位置的元素
    public E remove(int index) {
        checkElementIndex(index);
        return unlink(node(index));
    }

    // 获取链表指定位置的元素
    public E get(int index) {
        checkElementIndex(index);
        return node(index).item;
    }
    
    // 省略其他方法...
}

解释:上述代码展示了LinkedList类的部分源码。LinkedList的底层是一个双向链表,其中每个节点(Node)都包含了元素值、前驱节点和后继节点。通过addremoveget等方法,可以实现对链表的增删改查操作。

  1. ArrayList源码解析: ArrayList的底层实现是一个动态数组,使用数组来保存元素。在添加元素时,如果数组容量不足,ArrayList会进行扩容操作。下面是ArrayList源码的详细解释及关键方法解析:
public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
    private static final int DEFAULT_CAPACITY = 10; // 默认初始容量
    private static final Object[] EMPTY_ELEMENTDATA = {};
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    private transient Object[] elementData; // 真实存储元素的数组
    private int size; // 数组的大小

    // 构造方法
    public ArrayList() {
        this.elementData = EMPTY_ELEMENTDATA;
    }
    
    // 添加元素到数组末尾
    public boolean add(E e) {
        ensureCapacityInternal(size + 1); // 确保数组容量足够
        elementData[size++] = e; // 将元素添加到数组末尾
        return true;
    }

    // 在数组指定位置插入元素
    public void add(int index, E element) {
        rangeCheckForAdd(index); // 检查插入位置是否合法
        ensureCapacityInternal(size + 1); // 确保数组容量足够
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index); // 移动元素,腾出插入位置
        elementData[index] = element; // 在指定位置插入元素
        size++; // 数组大小加1
    }

    // 删除数组指定位置的元素
    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; // 释放最后一个元素
        return oldValue;
    }

    // 获取数组指定位置的元素
    public E get(int index) {
        rangeCheck(index); // 检查索引是否合法
        return elementData(index);
    }
    
    // 省略其他方法...
}

解释:上述代码展示了ArrayList类的部分源码。ArrayList的底层是一个动态数组,通过addremoveget等方法,可以实现对数组的增删改查操作。当数组容量不足时,ArrayList会进行扩容以确保数组大小的合适。

  1. 性能比较和适用场景:
  • LinkedList适用于频繁的插入和删除操作,尤其是在列表的中间位置。它的插入和删除操作效率高。
  • ArrayList适用于频繁的随机访问操作,尤其是在列表的末尾位置。它的随机访问效率高。

总结: 通过以上内容,您了解了LinkedList和ArrayList的根本区别和表面区别,并提供了详细的代码解释。LinkedList适用于频繁的插入和删除操作,而ArrayList适用于频繁的随机访问操作。根据实际需求,选择合适的集合类可以提高代码的效率和性能。

希望本篇博客对您理解和应用LinkedList和ArrayList有所帮助。如有更多问题,请参考Java官方文档和其他相关资源,以加深您的学习。祝您在应用LinkedList和ArrayList时取得成功!

举报

相关推荐

0 条评论