美文网首页Java 杂谈java新手学习
Java之Collection接口介绍与剖析,看完后再也忘不掉

Java之Collection接口介绍与剖析,看完后再也忘不掉

作者: Python编程社区 | 来源:发表于2019-03-22 10:20 被阅读0次

    一、Collection接口概述

    Collection是一个接口,继承自Iterable。我们先看一下Iterable接口的源码。

    1.1 Iterable接口

    Iterable接口源码

    package java.lang;

    import java.util.Iterator;

    import java.util.Objects;

    import java.util.Spliterator;

    import java.util.Spliterators;

    import java.util.function.Consumer;

    /**

    *实现这个接口的的类允许使用"for-each loop"语句来遍历。

    */

    public interface Iterable {

    /**

    *返回一个元素类型为T的迭代器

    */

    Iterator iterator();

    /**

    jdk1.8新增的遍历方式

    */

    default void forEach(Consumer action) {

    Objects.requireNonNull(action);

    for (T t : this) {

    action.accept(t);

    }

    }

    /**

    * 暂不研究

    */

    default Spliterator spliterator() {

    return Spliterators.spliteratorUnknownSize(iterator(), 0);

    }

    }

    Iterable接口有一个Iterator iterator()方法,而Collection继承Iterable,所以我们说Collection依赖Iterator。

    1.2 Collection接口

    Collection是一个高度封装的集合接口,它提供了所有集合要实现的默认方法接口,我们再看一下Collection接口关系类图。

    我们看一下接口源码,了解它有哪些接口和默认实现。

    Collection接口源码

    package java.util;

    import java.util.function.Predicate;

    import java.util.stream.Stream;

    import java.util.stream.StreamSupport;

    /**

    *这是一个集合分层的根接口。集合代表了一组包含元素的对象。有些集合允许有重复的元素,有些不允许。

    *有些集合是有序的有些无序的。jdk不对这个接口提供任何直接的实现,但是再一些直接子接口例如Set和List有实现了某些接口方法。

    *所有继承Collection的类必须提供两个默认的构造函数,一个不带参数的、一个带Collection类型参数。

    */

    public interface Collection extends Iterable {

    // 查询操作

    /**

    *返回集合大小,也就是集合中元素的数量

    */

    int size();

    /**

    * 如果集合包含元素返回true,即判断集合是否为空

    */

    boolean isEmpty();

    /**

    * 判断集合是否存在某个对象,注意这里参数是个Object,并没有限制为E或其子类

    */

    boolean contains(Object o);

    /**

    * 返回一个迭代器iterator。并没有说明元素的迭代顺序,除非特别的集合有这个要求。

    */

    Iterator iterator();

    /**

    *将集合转为对象数组,注意这里不是元素数组而是一个Object数组。

    *如果集合保证是有序的,那么通过迭代器返回数组有相同顺序

    *返回的数组是安全的,也就是说集合有自己的引用,数组开辟新的堆内存,也有自己的引用。所以调

    *用者可以随意操作返回的数组。

    *这个方法是数组和列表之间的桥梁

    */

    Object[] toArray();

    /**

    * 返回一个集合元素类型的数组。如果集合满足指定的数组并且有足够的空间,则在其中返回此集合

    * 否则返回此集合大小的新数组。

    * 如果集合有序,那么返回此集合迭代器遍历顺序的数组

    * 如果数组大小比集合元素多,那么在数组满足集合元素后在末尾设置为null

    * 如果在这个集合中指定数组运行时类型不是运行时元素类型的超类,那么抛ArrayStoreException异常

    * 如果指定数组为空,则抛出NullPointerException

    */

    T[] toArray(T[] a);

    // 修改操作

    /**

    * 确保此集合包含特定的元素类型。

    * 如果此集合增加元素成功返回true。

    * 如果此集合不允许有重复元素并且已经包含所传参数,那么返回false

    *

    * 支持此操作的集合可能会限制向该集合添加哪些元素。特别的,有些集合会拒绝null元素,有些

    * 会对要增加的元素强加一些限制。

    * Collection实现类应该在文档中明确指出所有的限制。

    * 如果集合以除已经包含元素之外的任何原因拒绝添加特定元素,则必须抛出异常

    *(而不是返回false)。这保留了集合在此调用返回后始终包含指定元素的不变式。

    */

    boolean add(E e);

    /**

    * 如果此集合中存在此元素,那么移除一个特定元素类型的实例。更正式的说,如果集合中包含一个或多个这样的元素,

    * 那么删除这样的元素(o==null?e==null:o.equals(e))。如果集合包含指定的元素(或集合因调用而发生改变),那么返回true。

    *

    * 如果指定元素的类型和集合不相容,抛出ClassCastException异常(可选的限制条件)

    * 如果指定元素是null并且这个集合不允许null元素存在,那么抛出NullPointerException异常(可选的限制条件)

    * 如果此集合不支持remove操作那么抛出UnsupportedOperationException异常(可选的限制条件)

    */

    boolean remove(Object o);

    // 容量操作

    /**

    * 如果this集合包含指定集合的所有元素,返回true

    * c集合必须要检查是否被包含在this集合

    * 如果指定元素的类型和集合不相容,抛出ClassCastException异常(可选的限制条件)

    * 如果指定元素是null并且这个集合不允许null元素存在,那么抛出NullPointerException异常(可选的限制条件)

    */

    boolean containsAll(Collection c);

    /**

    * 将指定集合的所有元素到this集合中(可选的操作)。

    * 如果指定的集合在操作进行时被修改了,那么此操作行为未定义。

    * (这意味着如果指定的集合是这个集合,并且这个集合是非空的,那么这个调用的行为是未定义的。)

    *

    * @参数:c集合包含了要被添加到这个集合的元素

    * @返回:如果调用结果改变了this集合返回true

    * @throws:如果 addAll操作不被此集合支持,那么抛出UnsupportedOpertaionException异常

    * @throws: 如果指定集合包含了空元素而this集合不允许有空元素,那么抛出NullPointerException异常

    * @throws:如果this集合阻止hiding集合元素类型添加,那么抛出ClassCastException异常

    * @throws:如果指定集合的元素的某些属性阻止将其添加到此集合,则抛出IllegalArgumentException

    * @throws:由于插入限制,如果不是所有元素都可以在此时添加,则抛出IllegalStateException异常

    */

    boolean addAll(Collection c);

    /**

    * 移除此集合中所有的包含在指定集合中的元素(可选的操作)。调用过此函数之后,那么此集合和指定集合将不再包含相同元素。

    * @param:包含要从该集合中删除的元素的c集合

    * @return:如果此集合因调用而更改那么返回true

    * @throws:如果此集合不支持removeAll方法,则抛出UnsupportedOperationException

    * @throws:如果集合中一个或多个元素的类型与指定集合不兼容,则抛出ClassCastException(可选的操作)

    * @throws:如果该集合包含一个或多个空元素,且指定的集合不支持空元素(optional),或者指定的集合为空,

    * 则抛出NullPointerException异常

    */

    boolean removeAll(Collection c);

    /**

    * 移除此集合中所有符合给定Predicate的元素。在迭代期间或由Predicate引发的错误或运行时异常将被转发给调用方

    * @implSpec

    * 默认实现使用其迭代器遍历集合的所有元素。每一个匹配的元素使用iterator.remove()来移除。

    * 如果集合的iterator不支持移除将会抛出UnsupportedOperationException异常在匹匹厄到

    * 第一个元素时。

    * @param 过滤一个predicate

    * @param 筛选要删除的元素返回true的Predicate

    * @return 如果任何一个元素被删除返回true

    * @throws 指定过滤器为空,抛出NullPointerException

    * @throws 如果元素没有被删除,或者移除操作不支持,

    * 则立即抛出UnsupportedOperationException异常

    * @since 1.8

    */

    default boolean removeIf(Predicate filter) {

    //如果filter为null抛出NullPointerException

    Objects.requireNonNull(filter);

    boolean removed = false;

    final Iterator each = iterator();

    //通过迭代器遍历删除,只要删除一个removed就为true

    while (each.hasNext()) {

    if (filter.test(each.next())) {

    each.remove();

    removed = true;

    }

    }

    return removed;

    }

    /**

    * 只保留此集合中包含在指定集合中的元素(可选的操作)。

    * 也就是说,此集合中不包含在指定集合中的所有元素。

    * @param:要保留的元素的集合c

    * @return:如果此集合改变了返回true

    * @throws:如果此集合不支持retainAll,则抛出UnsupportedOperationException异常

    * @throws:如果集合中一个或多个元素的类型与指定集合不兼容,则抛出ClassCastException(可选的操作)

    * @throws:如果该集合包含一个或多个空元素,且指定的集合不支持空元素(optional),或者指定的集合为空

    */

    boolean retainAll(Collection c);

    /**

    * 移除此集合中所有元素(可选操作),调用此方法后集合里将为空。

    * @throws: 如果此集合clear操作不支持将会抛出UnsupportOperationException异常。

    */

    void clear();

    // 比较和hash

    /**

    * 比较指定的对象与此集合是否相等

    *

    */

    boolean equals(Object o);

    /**

    *返回这个集合的hashCode。当集合接口没有对Object.hashCode方法的一般协议做任何规定,编程

    *人员应该注意在重写equals方法时必须重写hashCode方法,以便满足一般协议对这个

    *Object.hashCode方法。特别的,c1.equals(c2)表明c1.hashCode()==c2.hashCode()。

    */

    int hashCode();

    /**

    *一下1.8新增的Spliterator,暂不研究

    */

    @Override

    default Spliterator spliterator() {

    return Spliterators.spliterator(this, 0);

    }

    default Stream stream() {

    return StreamSupport.stream(spliterator(), false);

    }

    default Stream parallelStream() {

    return StreamSupport.stream(spliterator(), true);

    }

    }

    1.3 AbstractCollection类

    AbstractCollection是一个实现了Collection接口的抽象类,除了iterator()和size()接口,它提供了一些其他接口的默认实现,其他集合类可以继承此类来复用。

    AbstractCollection源码

    package java.util;

    public abstract class AbstractCollection implements Collection {

    /*唯一的构造函数*/

    protected AbstractCollection() {

    }

    // 查询操作

    public abstract Iterator iterator();

    public abstract int size();

    /**

    * 返回size()==0

    */

    public boolean isEmpty() {

    return size() == 0;

    }

    /**

    * 实现的contains方法,通过迭代器遍历

    */

    public boolean contains(Object o) {

    Iterator it = iterator();

    if (o==null) {

    while (it.hasNext())

    if (it.next()==null)

    return true;

    } else {

    while (it.hasNext())

    if (o.equals(it.next()))

    return true;

    }

    return false;

    }

    /**

    * 此默认实现,考虑到数组在迭代器遍历过程中大小可能会改变,

    * 也就是可能会增加或减少元素怒

    */

    public Object[] toArray() {

    // 估计数组大小,并做好变小或变大的准备

    Object[] r = new Object[size()];

    Iterator it = iterator();

    for (int i = 0; i < r.length; i++) {

    if (! it.hasNext()) //比期望的元素少,那么调用Arrays.copyOf()方法返回一个新的数组

    //Arrays.copyOf方法在Arrays中讲解

    return Arrays.copyOf(r, i);

    r[i] = it.next();

    }

    // 判断集合有没有被增加(迭代器改变),如果没有返回数组,如果有调用finishToArray()方法返回数组

    return it.hasNext() ? finishToArray(r, it) : r;

    }

    /**

    *

    */

    @SuppressWarnings("unchecked")

    public T[] toArray(T[] a) {

    // Estimate size of array; be prepared to see more or fewer elements

    int size = size();

    T[] r = a.length >= size ? a :

    (T[])java.lang.reflect.Array

    .newInstance(a.getClass().getComponentType(), size);

    Iterator it = iterator();

    for (int i = 0; i < r.length; i++) {

    if (! it.hasNext()) { // fewer elements than expected

    if (a == r) {

    r[i] = null; // null-terminate

    } else if (a.length < i) {

    return Arrays.copyOf(r, i);

    } else {

    System.arraycopy(r, 0, a, 0, i);

    if (a.length > i) {

    a[i] = null;

    }

    }

    return a;

    }

    r[i] = (T)it.next();

    }

    // more elements than expected

    return it.hasNext() ? finishToArray(r, it) : r;

    }

    /**

    * 一些VM会在数组中保留头信息,所以要占用8字节空间,头信息大小不能超过8

    * 重新分配更大的长度给数组,如果要求的数组大小超过VM限制,会抛出OutOfMemoryError

    * 默认值 2147483647 - 8;

    */

    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    /**

    * 重新在toArray方法中,如果iterator返回了比期望中的大小更多的元素时,重新给数组分配空间来完成填充数组。

    * @param 之前的已经被填满的数组

    * @param 操作中集合的iterator

    * @return 除了给定的数组之外,增加了从迭代器中获取的元素,并修正数组长度

    */

    @SuppressWarnings("unchecked")

    private static T[] finishToArray(T[] r, Iterator it) {

    int i = r.length; //被填充满的数组长度(原始集合大小)

    while (it.hasNext()) {

    int cap = r.length;

    if (i == cap) { //第一次(刚进来的时候)一定为true,那么分配新的数组大小

    int newCap = cap + (cap >> 1) + 1; //右移一位+1再加上原大小

    if (newCap - MAX_ARRAY_SIZE > 0)

    //新数组大小大于集合默认最大值,调用hugeCapacity()方法重新分配,值为Integer.MAX_VALUE

    newCap = hugeCapacity(cap + 1);

    r = Arrays.copyOf(r, newCap);

    }

    r[i++] = (T)it.next();

    }

    // 修正数组多余的空间,如果正好直接返回,否则调用Arrays.copyOf()方法

    return (i == r.length) ? r : Arrays.copyOf(r, i);

    }

    private static int hugeCapacity(int minCapacity) {

    if (minCapacity < 0) // 内存溢出

    throw new OutOfMemoryError

    ("Required array size too large");

    return (minCapacity > MAX_ARRAY_SIZE) ?

    Integer.MAX_VALUE :

    MAX_ARRAY_SIZE;

    }

    // 修改操作

    /**

    * 此操作总是抛出 UnsupportedOperationException

    * @throws UnsupportedOperationException {@inheritDoc}

    * @throws ClassCastException {@inheritDoc}

    * @throws NullPointerException {@inheritDoc}

    * @throws IllegalArgumentException {@inheritDoc}

    * @throws IllegalStateException {@inheritDoc}

    */

    public boolean add(E e) {

    throw new UnsupportedOperationException();

    }

    /**

    * 通过集合迭代器查找元素,如果找到调用iterator.remove()方法删除元素。

    * 删除一个就返回true

    */

    public boolean remove(Object o) {

    Iterator it = iterator();

    if (o==null) {

    while (it.hasNext()) {

    if (it.next()==null) {

    it.remove();

    return true;

    }

    }

    } else {

    while (it.hasNext()) {

    if (o.equals(it.next())) {

    it.remove();

    return true;

    }

    }

    }

    return false;

    }

    // Bulk Operations

    /**

    * 判断此集合是否包含指定集合所有元素,有一个没有返回false

    */

    public boolean containsAll(Collection c) {

    for (Object e : c)

    if (!contains(e))

    return false;

    return true;

    }

    /**

    * 调用add(E e)方法添加指定集合到此集合中

    *

    * @see #add(Object)

    */

    public boolean addAll(Collection c) {

    boolean modified = false;

    for (E e : c)

    if (add(e))

    modified = true;

    return modified;

    }

    /**

    * 这个方法将从此集合中删除指定集合的所有元素,通过迭代器删除。

    * @throws UnsupportedOperationException {@inheritDoc}

    * @throws ClassCastException {@inheritDoc}

    * @throws NullPointerException {@inheritDoc}

    *

    * @see #remove(Object)

    * @see #contains(Object)

    */

    public boolean removeAll(Collection c) {

    Objects.requireNonNull(c);

    boolean modified = false;

    Iterator it = iterator();

    while (it.hasNext()) {

    if (c.contains(it.next())) {

    it.remove();

    modified = true;

    }

    }

    return modified;

    }

    /**

    * 此集合中保留指定集合的所有元素,也就是说调用此方法之后,此集合中删除了不存在指定集合中

    *的元素

    *

    */

    public boolean retainAll(Collection c) {

    Objects.requireNonNull(c);

    boolean modified = false;

    Iterator it = iterator();

    while (it.hasNext()) {

    if (!c.contains(it.next())) {

    it.remove();

    modified = true;

    }

    }

    return modified;

    }

    /**

    * 清空集合中所有元素

    * @throws UnsupportedOperationException {@inheritDoc}

    */

    public void clear() {

    Iterator it = iterator();

    while (it.hasNext()) {

    it.next();

    it.remove();

    }

    }

    // String conversion

    /**

    * 集合的toString方法,所有继承AbstractCollection的类都有此方法

    */

    public String toString() {

    Iterator it = iterator();

    if (! it.hasNext())

    return "[]";

    StringBuilder sb = new StringBuilder();

    sb.append('[');

    for (;;) {

    E e = it.next();

    //如果将自己这个集合添加到自己,就会打印(this Collection)

    sb.append(e == this ? "(this Collection)" : e);

    if (! it.hasNext())

    return sb.append(']').toString();

    sb.append(',').append(' ');

    }

    }

    AbstractCollection类默认实现的方法,在上面源代码中我都已经讲解过了,很多常用的集合都会使用 默认实现,比如常用的toString方法,我们在输出ArrayList时调用的就是此方法。

    我做开发十多年的时间,如果大家对于学习java的学习方法,学习路线以及你不知道自己应该是自学还是培训的疑问,都可以随时来问我,大家可以加我的java交流学习qun:四九四,八零一,九三一,qun内有学习教程以及开发工具。

    相关文章

      网友评论

        本文标题:Java之Collection接口介绍与剖析,看完后再也忘不掉

        本文链接:https://www.haomeiwen.com/subject/ciflvqtx.html