Java 单列集合之List

Java 单列集合之List

类的继承关系

Java 单列集合之List_第1张图片

实现子类
ArrayList
LinkedList
Vector

Iterable 接口

Java 单列集合之List_第2张图片

Collection 接口

Java 单列集合之List_第3张图片

List 接口

Java 单列集合之List_第4张图片

ArrayList

属性字段

    private static final long serialVersionUID = 8683452581122892189L;
    // 默认初始容量
    private static final int DEFAULT_CAPACITY = 10;
    // 空的数据
    private static final Object[] EMPTY_ELEMENTDATA = {};
    // 默认的空的数据
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    // 对象数组存储数据
    transient Object[] elementData;
    // List中的元素数量
    private int size;

底层存储

ArrayList使用Object对象存储数据,当ArrayList没有明确指定泛型的类型时,ArrayList可以存放各种类型的对象。

初始化

// 带有初始容量的构造函数
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);
        }
    }

	// 无参构造,默认容量是10,是懒加载的
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

    
    public ArrayList(Collection<? extends E> c) {
        Object[] a = c.toArray();
        if ((size = a.length) != 0) {
            if (c.getClass() == ArrayList.class) {
                elementData = a;
            } else {
                elementData = Arrays.copyOf(a, size, Object[].class);
            }
        } else {
            // replace with empty array.
            elementData = EMPTY_ELEMENTDATA;
        }
    }

扩容机制

    private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }
	
	// 计算当前需要的容量
    private static int calculateCapacity(Object[] elementData, int minCapacity) {
    	// 判断是否是默认大小的List,惰性初始化
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }

	// 判断是否需要扩容
    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // 需要的容量比当前的容量大则需要进行扩容
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

	// 扩容
    private void grow(int minCapacity) {
    	// 保存原先的容量
        int oldCapacity = elementData.length;
        // 计算新的容量 = 1.5 * oldCapacity
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        // 判断新的容量是否能够满足minCapacity
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;	// 不满足则直接更新为minCapacity
        // 判断新的容量是否超过最大容量的限制
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // 通过Arrays.copyOf生成新的数组
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

	// 获取最大容量
	private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        // MAX_ARRAY_SIZE 为 Integer.MAX_VALUE - 8
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

总结

  • 是线程不安全的
  • 底层是通过Object数组存储的
  • 默认容量是10,并且是惰性加载
  • 扩容机制是每次扩容1.5
  • 最大容量是size属性可表示的容量Integer,MAX_VALUE = 2^31 -1
  • 查询操作是O(1)的,支持随机查询
  • 增删操作是O(N)的,需要移动数据

LinkedList

属性字段

	// 大小
    transient int size = 0;
    // 首结点
    transient Node<E> first;
    // 尾结点
    transient Node<E> last;

底层存储

是双向链表结构存储的

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

容量是否有限制

LinkedList到底有没有容量限制值得商讨,在LinkedList的添加操作中并没有容量的检测和限制,理论上来说LinkedList是没有容量限制的,可以一直往里面添加新的结点。

但是由于属性size有一定的范围,最大值为2 ^ 31 -1,如果超过这个大小,list.size()得到的结果将会是不正确的。

以下代码通过两个字节的short类型来模拟这个过程

package com.collection.list;

class LinkedList{
    int size = 0;
    void add(){
        // new Node
        size++;
    }
}


public class LinkedListTest1 {
    public static void main(String[] args) {
        LinkedList list = new LinkedList();
        for (int i = 0; i < Integer.MAX_VALUE; i++) {
            list.add();
        }
        System.out.println("bound_size:" +  list.size);
        list.add();
        System.out.println("error_size:" + list.size);
    }
}

/*
	bound_size:2147483647
	error_size:-2147483648
*/

总结

  • 是线程不安全的
  • 是双向链表存储的
  • 没有容量限制,但由于size可表示的范围最大为2 ^ 31 - 1,超过这个范围会导致获取不到正确的大小
  • 是有序的
  • 查询操作O(N),无法随机查询
  • 增删操作O(1)

Vector

属性字段

// 对象数组存储元素
protected Object[] elementData;
// 元素个数
protected int elementCount;
// 容量增量
protected int capacityIncrement;
private static final long serialVersionUID = -2767605614048989439L;

初始化

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

扩容机制

    private void ensureCapacityHelper(int minCapacity) {
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

    private void grow(int minCapacity) {
        // 保存原数组的大小
        int oldCapacity = elementData.length;
        // 计算新的容量
        //	1. 如果增量大于0,则扩充为 oldCapacity + capacityIncrement
        //	2. 如果增量不大于0,则扩充为 2 * oldCapacity
        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);
    }

总结

  • 是线程安全的
  • 默认容量是10,默认增量是0,没有惰性加载
  • 如果增量大于0则线性扩增oldCapacity + capacityIncrease,如果增量不大于0则指数扩增2 * oldCapacity
  • 最大容量是Integer.MAX_VALUE
  • 是有序的
  • 查询操作O(1),支持随机查询
  • 增删操作O(N),需要移动数组

三个实现子类对比

特点 ArrayList Vector LinkedList
线程安全 不安全 安全 不安全
底层存储 Object数组 Object数组 双向链表
默认容量 10 10 -
最大容量 Integer.MAX Integer.MAX -
惰性加载 默认容量惰性加载 - -
扩容机制 1.5倍 增量 或 2倍 -
是否有序
查询操作 O(N) O(N) O(1)
增删操作 O(1) O(1) O(N)

你可能感兴趣的:(Java,基础,java,list,集合)