ArrayList和linkedList源码分析

ArrayList源码分析

Arraylist存储内容为一个数组,在获取ArrayList的数据量时时通过获取当中变量size的,而不是数组长度。数组长度默认为10.源码如下

private transient Object[] elementData;

    /**
     * The size of the ArrayList (the number of elements it contains).
     *
     * @serial
     */
    private int size;
取数据量大小时:
 public int size() {
        return size;
    }

添加元素是代码:
 public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }
看源码可知ArrayList是线程不安全的,另外size的大小也可能并不是数据量的真实大小。
ArrayList有一个方法可以调整大小为实际的数据量大小,trimToSize()方法。


LinkedList源码分析

LinkedList存储为一个链表,具体表现形式为。LinkedList存储一个开始节点和结尾节点。
    transient Node<E> first;

    /**
     * Pointer to last node.
     * Invariant: (first == null && last == null) ||
     *            (last.next == null && last.item != null)
     */
    transient Node<E> 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++;
    }
获取数据量和ArrayList一样通过获取size大小来获取

ArrayList和LinkedList区别

除了AarrayList和LinkedList存储方式不同之外,一般选择使用哪种list那使用时效率。
之前一直以为插入操作多的时候使用LinkedList而查询数据多时用ArrayList.。看源码发现并不是这一回事。
分2种情况的插入:

1:顺序插入

如果顺序插入时其实Arraylist更快一点而不是Linkedlist。原因分析:LInkedList顺序添加元素时需要改变最后一个节点元素,另外需要新建一个节点对象。而ArrayList除非数据量长度正好大于数组长度需要增加数组长度。不然的话是直接在数组的size+1的位置对象为新加元素。当然比LinkedList快

2:中间插入

ArrayList中间插入时方法:
public void add(int index, E element) {
        rangeCheckForAdd(index);

        ensureCapacityInternal(size + 1);  // Increments modCount!!
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        elementData[index] = element;
        size++;
    }

LinkedList中间插入的方法:
public void add(int index, E element) {
        checkPositionIndex(index);

        if (index == size)
            linkLast(element);
        else
            linkBefore(element, node(index));
    }

void linkBefore(E e, Node<E> succ) {
        // assert succ != null;
        final Node<E> pred = succ.prev;
        final Node<E> newNode = new Node<>(pred, e, succ);
        succ.prev = newNode;
        if (pred == null)
            first = newNode;
        else
            pred.next = newNode;
        size++;
        modCount++;
    }

    Node<E> node(int index) {
        // assert isElementIndex(index);

        if (index < (size >> 1)) {
            Node<E> x = first;
            for (int i = 0; i < index; i++)
                x = x.next;
            return x;
        } else {
            Node<E> x = last;
            for (int i = size - 1; i > index; i--)
                x = x.prev;
            return x;
        }
    }

先不看ArrayList的中间插入方法。AyyayList的中间插入方法是先找到之前该index数值对应点node节点,然后该节点之前添加新节点,然后改变该节点之前的上一个节点对应下一个节点为新节点。示意图如下:



在看ArrayList的中间插入:
这里涉及到一个方法System.arrayCopy()方法,这个方法是用active修饰的。属于非java实现的底层代码。但c来写的底层无非是数组移位,而且是数组该数值之后的数据全部都要向后移动移位,这里数据量操作会非常大。因此比LinkedList慢。

使用ArrayList注意点

由于ArrayList在添加数据发现数组长度不够时会新建一个数组,会照成额外的计算。因此,当我们知道数据量时最好使用指定长度的ArrayList.。
另外ArrayList在增加数据时发现数组长度不够并不是增加固定长度的而是增加之前数组长度右位移一位的长度,也就是说新的数组长度差不多是原数组长度的2倍。
下面是array当数组长度不够时增加长度代码:
 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);
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值