Java中主要数据结构的实现原理及扩容机制

说明

  • Java版本:1.8.0_231

ArrayList

  1. 底层由Object数组实现,具有数组的所有特性,实现了RandomAccess接口支持随机访问,非线程安全类型
Object[] elementData;
  1. 构造方法
  • 创建一个空数组
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
  • 具有初试容量的数组
    public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }
  1. add()方法及扩容机制
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);
        // 将元素e添加到末尾
        elementData[size++] = e;
        return true;
    }
  • 数组容量初始化
    private static int calculateCapacity(Object[] elementData, int minCapacity) {
    // 判断是否是为空数组,若为空,返回10;否则将返回arr.length + 1(第一次添加数据肯定是空的,第二次及后续就是arr.length +1)
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }
  • 判断是否到达扩容零界点
    private void ensureExplicitCapacity(int minCapacity) {
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

	// 核心 开始扩容
    private void grow(int minCapacity) {
        // 获取数组长度
        int oldCapacity = elementData.length;
        // 右移位运算得出扩容后的长度
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // 将扩容后的数据赋值给原数组
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

在添加第一个元素时,就会调用grow()方法进行扩容操作,但此时数组长度为0,扩容后的

LinkedList

  1. 底层由双向链表实现,实现了Deque接口,可以双向操作,不支持随机访问,非线程安全类型
	// node节点
    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;
        }
    }
    // 指向上一个节点
	Node<E> first;
	// 指向下一个节点
	Node<E> last;
  1. 两个构造函数
  • 构造一个空List
    public LinkedList() {
    }
  • 一个有参构造函数
    public LinkedList(Collection<? extends E> c) {
        this();
        addAll(c);
    }sdss
  1. 链表追加节点至末尾
    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++;
    }

Vector

  1. 底层有Object数组实现,实现了RandomAccess接口,支持随机访问,线程安全类型
protected Object[] elementData;
  1. 三个构造函数(其实是一个)
  • 赋予初始容量和扩容量
    public Vector(int initialCapacity, int capacityIncrement) {
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        this.elementData = new Object[initialCapacity];
        this.capacityIncrement = capacityIncrement;
    }
  • 使用默认的扩容量0
    public Vector(int initialCapacity) {
        this(initialCapacity, 0);
    }
  • 使用默认的初始容量10和初始容量0
    public Vector() {
        this(10);
    }
  1. 添加元素与扩容机制
    public synchronized void addElement(E obj) {
    	// 扩容
        ensureCapacityHelper(elementCount + 1);
        // 将新增元素添加到数组末尾
        elementData[elementCount++] = obj;
    }
    
     private void ensureCapacityHelper(int minCapacity) {
         // 第一次添加元素时,minCapacity=10,elementData.length = 0,这时不会进行扩容 
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
    
        private void grow(int minCapacity) {
            // 获取数据的长度
        int oldCapacity = elementData.length;
            // 扩容核心:在创建数组时指定了capacityIncrement且大于0,扩容后的值为capacityIncrement+初始容量,反之为初始容量+初始容量,即两倍的初始容量
        int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                         capacityIncrement : oldCapacity);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

List接口主要实现类总结

  1. ArrayList和Vector底层基于数组实现,具有数组的所有特性且支持随机访问,其中Vector时线程安全的;在扩容机制上:
  • ArrayList是1.5倍扩容,关键代码为int newCapacity = oldCapacity + (oldCapacity >> 1); 即 10 --> 15;
  • Vector是2倍扩容,关键代码:int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity);,即:10 --> 20
  1. LinkedList是基于双向链表实现,可双向插入,插入删除快,查找慢

网站原文:https://www.haicheng.website/passages/source-code-analysis-01/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章