Java集合源码分析(Collection、List、ArrayList、未完)

集合源码阅读

请添加图片描述

这里的图片罗列了接下来需要学习的内容,我的话首先从List入手

Collection接口

作为Java中所有集合的根接口,Collection中规定的基本内容并不多,我们首先看源码中官方的描述👇

The root interface in the collection hierarchy. A collection represents a group of objects, known as its elements. Some collections allow duplicate elements and others do not. Some are ordered and others unordered. The JDK does not provide any direct implementations of this interface: it provides implementations of more specific subinterfaces like Set and List. This interface is typically used to pass collections around and manipulate them where maximum generality is desired.

集合层次结构中的根接口。集合表示了一组对象,并称其为元素。有些集合允许重复元素(ArrayList,LinkedList…),而有些则不允许(HashMap,TreeSet…),有些是有序的,有些是无序的。JDK并不提供这个接口的任何直接实现: 它提供更具体的子接口(如Set和List)的实现。这个接口通常用于传递集合,并且用在需要最大通用性的地方对其操作

/**
 * 继承Iterable接口,说明支持迭代遍历。这也是集合的一个重要的功能
 */
public interface Collection<E> extends Iterable<E> {
    /**
     * 返回集合中的元素数目 
     */
    int size();
    /**
     * 如果集合不包含元素则返回false,反之为true
     */
    boolean isEmpty();
    /**
     * 如果含有至少一个指定的元素则返回true,否则返回false
     */
    boolean contains(Object o);
    /**
     * 返回该集合的迭代器,对于返回内容的顺序无保证
     */
    Iterator<E> iterator();
    /**
     * 返回包含该集合所有元素的数组,返回的数据是安全的,相当于重新开辟空间,因此无论修改哪一方都对另一方无影响。
     */
    Object[] toArray();
    /**
     * 相比于上一个toArray,这个可以将内容返回到指定的容器中。
     */
    <T> T[] toArray(T[] a);
    /**
     * 追加元素,具体看哪一种。有的允许重复,有的则不允许,有的可以覆盖操作,有的则不行。
     */

    boolean add(E e);
    /**
     * 从集合中移除指定的元素
     */ 
    boolean remove(Object o);
    /**
     * contains的plus版本,可以指定多个
     */ 
    boolean containsAll(Collection<?> c);
    /**
     * add的plus版本
     */   
    boolean addAll(Collection<? extends E> c);
    /**
     * remove的plus版本
     */  
    boolean removeAll(Collection<?> c);

    default boolean removeIf(Predicate<? super E> filter) {
        Objects.requireNonNull(filter);
        boolean removed = false;
        final Iterator<E> each = iterator();
        while (each.hasNext()) {
            if (filter.test(each.next())) {
                each.remove();
                removed = true;
            }
        }
        return removed;
    }
    /**
     * 反向removeAll,保留指定集合的内容,其余全部删掉
     */

    boolean retainAll(Collection<?> c);

    void clear();

    boolean equals(Object o);

    int hashCode();
    /**
     * 不会/(ㄒoㄒ)/~~  以后补充,目前拆分器好像不怎么用得到
     */
    @Override
    default Spliterator<E> spliterator() {
        return Spliterators.spliterator(this, 0);
    }

    default Stream<E> stream() {
        return StreamSupport.stream(spliterator(), false);
    }
    default Stream<E> parallelStream() {
        return StreamSupport.stream(spliterator(), true);
    }
}

List接口作用

请添加图片描述

可以看出List集合直接继承Collection集合,包含了集合的最基本的一些特征方法,我们来看一下官方对List的描述

An ordered collection (also known as a sequence). The user of this interface has precise control over where in the list each element is inserted. The user can access elements by their integer index (position in the list), and search for elements in the list.List

有序的集合(也称为序列)。此界面的用户可以精确控制每个元素在列表中的插入位置。用户可以通过整数索引(在列表中的位置)访问元素,并在列表中搜索元素。

官方对List的描述是不是很像数组,虽然它确实有些地方和数组非常相似,但是还是有非常大的不同,比如有些实现按照索引查找的时间是和索引大小成正比的。是不是很像链表,没错,List的大部分实现都能看见链表的影子,因此站在链表的角度理解可能会更轻松一些。

/**
 *一些与Collection雷同的方法 就不重复了
 */
public interface List<E> extends Collection<E> {
    int size();
    boolean isEmpty();
    boolean contains(Object o);
    Iterator<E> iterator();
    Object[] toArray();
    <T> T[] toArray(T[] a);
    boolean add(E e);
    boolean remove(Object o);
    boolean containsAll(Collection<?> c);
    boolean addAll(Collection<? extends E> c);
    boolean addAll(int index, Collection<? extends E> c);
    boolean removeAll(Collection<?> c);
    boolean retainAll(Collection<?> c);
    /**
     * 
     */
    default void replaceAll(UnaryOperator<E> operator) {
            Objects.requireNonNull(operator);
            final ListIterator<E> li = this.listIterator();
            while (li.hasNext()) {
                li.set(operator.apply(li.next()));
            }
        }
    default void sort(Comparator<? super E> c) {
        Object[] a = this.toArray();
        Arrays.sort(a, (Comparator) c);
        ListIterator<E> i = this.listIterator();
        for (Object e : a) {
            i.next();
            i.set((E) e);
        }
    }
    void clear();
    boolean equals(Object o);
    int hashCode();
    E get(int index);
    E set(int index, E element);
    void add(int index, E element);
    E remove(int index);
    int indexOf(Object o);
    int lastIndexOf(Object o);
    ListIterator<E> listIterator();
    ListIterator<E> listIterator(int index);
    List<E> subList(int fromIndex, int toIndex);
     @Override
    default Spliterator<E> spliterator() {
        return Spliterators.spliterator(this, Spliterator.ORDERED);
    }
}

ArrayList源码分析

请添加图片描述

惯例,看看官方的解释

Resizable-array implementation of the List interface. Implements all optional list operations, and permits all elements, including null. In addition to implementing the List interface, this class provides methods to manipulate the size of the array that is used internally to store the list. (This class is roughly equivalent to Vector, except that it is unsynchronized.)
The size, isEmpty, get, set, iterator, and listIterator operations run in constant time. The add operation runs in amortized constant time, that is, adding n elements requires O(n) time. All of the other operations run in linear time (roughly speaking). The constant factor is low compared to that for the LinkedList implementation.
Each ArrayList instance has a capacity. The capacity is the size of the array used to store the elements in the list. It is always at least as large as the list size. As elements are added to an ArrayList, its capacity grows automatically. The details of the growth policy are not specified beyond the fact that adding an element has constant amortized time cost.

(机翻)列表接口的可调整大小的数组实现。实现所有可选的列表操作,并允许所有元素,包括null。除了实现List接口之外,这个类还提供了一些方法来操纵数组的大小,数组在内部用于存储列表(这个类大致相当于Vector,只是它是不同步的。)
size、isEmpty、get、set、iterator和listIterator操作以固定时间运行。add操作以摊销的固定时间运行,也就是说,添加n个元素需要O(n)时间。所有其他操作都在线性时间内运行(粗略地说)。与LinkedList实现相比,常量因子较低。
每个ArrayList实例都有一个容量。容量是用于存储列表中元素的数组的大小。它总是至少和列表大小一样大。当元素添加到ArrayList时,它的容量会自动增长。除了添加一个元素具有固定的摊余时间成本这一事实之外,增长策略的细节没有被指定。
后面主要说ArrayList是线程不安全的,如果需要在并发情况下使用该集合,需要使用synchronizedList包装起来。达到线程安全的目的,虽然会损失一部分性能。

继承实现关系

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
  • ArrayList继承AbstractList类,实现了List接口, 所有有List的所有功能。
  • ArrayList实现了RandomAccess接口,支持随机访问,可以直接通过下标进行访问。
  • ArrayList实现了Cloneable接口,支持克隆。
  • ArrayList实现了Serializable接口,支持序列化功能。

常量的意义

    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 = {};
    //存储ArrayList元素的数组缓冲区。ArrayList的容量是此数组缓冲区的长度。
    //transient在序列化时不会被序列化,缓冲区不会被保存
    transient Object[] elementData; // non-private to simplify nested class access
    //ArrayList的大小
    private int size;
   

构造方法

/**
 * 指定初始化集合数组大小来实例化集合。如果指定的大小是负数,则抛出IllegalArgumentException
 */
public ArrayList(int initialCapacity) {
    //指定大小大于0 ,就直接实例化。
    if (initialCapacity > 0) {
        this.elementData = new Object[initialCapacity];//指定初始化容量
    } else if (initialCapacity == 0) {
        this.elementData = EMPTY_ELEMENTDATA;//空数组
    } else {
        throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
    }
}

/**
 * Constructs an empty list with an initial capacity of ten.
 * 构造一个初始化容量为10的空列表(注意:根据注释是10,但是源码其实是一个长度为0的空数组)
 */
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

/**
 * 构造一个包含指定集合的List,将指定集合的数据全部添加到当前集合中。
 * 如果指定的集合为null,则会抛出NullPointerException(因为直接调用了c.toArray())
 */
public ArrayList(Collection<? extends E> c) {
    elementData = c.toArray();//如果c为空,则会抛出空指针异常
    if ((size = elementData.length) != 0) {
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    } else {
        this.elementData = EMPTY_ELEMENTDATA;
    }
}

  • 通过构造方法可以看出,如果不指定容量,初始化ArrayList的容量为0
  • 在指定容量时,是根据指定容量大小来实例化集合的,不会采用默认的10

添加元素的方法

public E set(int index, E element) {}
public boolean add(E e) {}
public void add(int index, E element) {}
public boolean addAll(Collection<? extends E> c) {}   
public boolean addAll(int index, Collection<? extends E> c) {}

具体内容

/**
 * 设置值,返回旧值
 */
public E set(int index, E element) {
    //下标检查
    rangeCheck(index);
    E oldValue = elementData(index);
    elementData[index] = element;
    return oldValue;
}

/**
 * 在列表最后添加元素,通过查看源码可以发现,ArrayList()初始化是,数组的大小是0,当我们
 * 添加第一个元素的时候,将大小扩充到了10.
 */
public boolean add(E e) {
    //确保容量足够
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}

private void ensureCapacityInternal(int minCapacity) {
    //计算容量
    int capacity = calculateCapacity(elementData, minCapacity);//10
    ensureExplicitCapacity(capacity);
}

private static int calculateCapacity(Object[] elementData, int minCapacity) {
    //这一个条件成立的情况只有初始化时未指定大小,并且是第一个次添加元素
    //即:ArrayList list = new ArrayList();
    // list.add(1); 能通过这个条件
    // list.add(2); 不能通过这个条件
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        //不明白为什么要在DEFAULT_CAPACITY和minCapacity中选出最大的,理论上能进入  
        //这里就是第一次添加元素,直接默认10不就行了吗?
        return Math.max(DEFAULT_CAPACITY, minCapacity); 1 ==> 10
    }
    return minCapacity;
}
private void ensureExplicitCapacity(int minCapacity) {
    //这个是AbstractList里继承下来的,具体作用和迭代有关
    modCount++;

    // overflow-conscious code
    if (minCapacity - elementData.length > 0)//第一次之后,elementData.length,就是10
        grow(minCapacity);//10
}

private void grow(int minCapacity) {//
    // overflow-conscious code
    int oldCapacity = elementData.length;//
    int newCapacity = oldCapacity + (oldCapacity >> 1);//  按照1.5倍的方法进行扩容
    //这个if是防止有负值的出现,有可能超出int的范围。
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    //private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
    if (newCapacity - MAX_ARRAY_SIZE > 0)    
        newCapacity = hugeCapacity(minCapacity);
    elementData = Arrays.copyOf(elementData, newCapacity);
}

//数组的最大容量不会超过MAX_ARRAY_SIZE
private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow
        throw new OutOfMemoryError();
    return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
}








minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}

//数组的最大容量不会超过MAX_ARRAY_SIZE
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值