基于jdk8的集合源码学习(一):第一篇集合体系一览图

本文以JDK8为蓝本,详细解析Java集合体系结构,包括Iterable接口、Collection接口及其子接口List、Set、Queue,以及Map接口。深入探讨各接口功能、默认方法及内部接口,如迭代器、并行迭代、Stream流等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java集合体系一览图如下:

 

 

java的集合体系机构就是基于上图,接下来我们将逐层分析各个接口的作用

1.Iterable接口:

      一般在java里able结尾的都代表着拥有某种功能,比如Serializable代表着序列化,Cloneable代表着对象复制功能,Comparable代表着可比较(即排序的意思),而Iterable则代表着可迭代,而其内部拥有一个方法iterator(),返回的是Iterator接口,而Iterator接口则正式定义了迭代器的行为规范。

     在JDK1.8中,在Iterable内部除了定义了iterator()接口方法外,还将新添加了两个接口默认方法,分别是forEach(增强for)、spliterator(获取并发迭代器);

forEach的源码如下:

 default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }

从源码中可以看出,该方法需要传入一个Consumer<? super T>类型的参数从该参数类型具有泛型可以推断出,该参数其实一个容器,能容纳泛型指定的数据,而在forEach内部可以看出,其调用了增强for对其内部数据进行了accept操作

 

《《《《《《《《《《《《《《《《《《《《《《《《《 拓展知识开始 》》》》》》》》》》》》》》》》》》》》》

拓展知识:迭代器的发展史

Iterator出现在JDK1.2,该接口最初出现的是伴随着是为了HashMap(jdk1.2被添加的)、ArrayList(jdk1.2出现的)等集合出现,并为其提供遍历接口的接口,其实在JDK1.1的时候,就出现了类似于Iterator功能的接口,叫做Enumeration(枚举类),Enumeration主要为Vector、Hashtable提供遍历功能。Iterator与Enumeration的源码如下:

Enumeration:
package java.util;

public interface Enumeration<E> {

    boolean hasMoreElements();

    E nextElement();
}
Iterator
package java.util;

public interface Iterator<E> {
    boolean hasNext();

    E next();

    void remove();
}

Enumeration和Iterator的区别在于:

(01) 函数接口不同
        Enumeration只有2个函数接口。通过Enumeration,我们只能读取集合的数据,而不能对数据进行修改。
        Iterator只有3个函数接口。Iterator除了能读取集合的数据之外,也能数据进行删除操作。

(02) Iterator支持fail-fast(快速失败是什么意思不再拓展)机制,而Enumeration不支持。

03)按道理讲对于使用Enumeration遍历应该快于Iterator,因为 Iterator有个fail-fast,但是在低于近亿级别的遍历中,两者遍历速度几乎难分伯仲,因此基本上Enumeration 处于鸡肋的位置,不知道在哪个版本就给拿掉了。

 

回归正题,后来随着集合的丰富,而每一个集合都有取出元素的功能,因此在jdk1.5中添加的新接口Iterable, 并作为Collection的父接口,该接口只有一个方法即获取迭代器的方法iterator()可以获取每个容器自身的迭代器Iterator。(Collection)集合容器都需要获取迭代器(Iterator)于是在5.0后又进行了抽取将获取容器迭代器的iterator()方法放入到了Iterable接口中。

但是在JDK1.5中Iterable接口的集合,还具有一个特性,就是可以使用增强for循环,增强for循环本质是一个特殊的Iterator,他的底层有jvm调用迭代器Iterator,其出现只是为了简化代码,让你无需关注游标。

在JDK1.8中,出现了新的关键字default,被该修饰符修饰的方法可以直接写入到接口中,因此Iterable接口中增加了默认的增强for方法。

《《《《《《《《《《《《《《《《《《《《《《《《《 拓展知识结束》》》》》》》》》》》》》》》》》》》》》

 

2.Collection接口

Collection接口是集合的父接口,该接口中定义了集合的基础操作方法,同时其还重写了Iteratable的iterator()方法,在JDK8中新增了4个default方法,分别是removeIf方法(主要功能是:尝试着删除元素)、Spliterator<E>(并行迭代方法)、stream(jdk8中的新特性,stream集合流,其实可以简单把他理解为更高级的迭代)/parallelStream()方法,其实这几个方法都是为了完成一件事情,快速迭代(使用集合流Stream对集合进行快速迭代,关于Stream流与并行迭代的过程太复杂了,拓展起来很困难,到时候出专门文章进行介绍!)

 

接下来就是分别三个重要的接口实现了Collection接口,他们分别是List接口/Set接口/Queue接口,这三个接口是非常非常重要的集合接口,尤其是Queue接口,该接口笔者不常使用,但是该接口在多线程实现/任务调度底层代码中使用的非常广泛,但是我们好像又很少去接触他,记得笔者刚入行的时候,都很少去讲解这个集合!

3.Map接口

Map接口是key,value类型集合的顶级接口,它的内部出了定义k/V集合的一些基本方法外,还持有了内部接口方法以及新增了几个默认实现方法,内部接口就是Entry接口;而默认实现方法分别是:

3.1:getOrDefault方法

default V getOrDefault(Object key, V defaultValue) {

V v;

return (((v = get(key)) != null) || containsKey(key))

? v

: defaultValue;

}

该方法主要是返回默认值,从代码里看该方法的作用是,传入一个key和默认值,看该集合里是否存在该key,或key对应的值是否为null,如果不存在该key或者该key对应的值为null,那么久返回默认值,否则返回key对应的值!

 

3.2 forEach方法

default void forEach(BiConsumer<? super K, ? super V> action) {

Objects.requireNonNull(action);

for (Map.Entry<K, V> entry : entrySet()) {

K k;

V v;

try {

k = entry.getKey();

v = entry.getValue();

} catch(IllegalStateException ise) {

// this usually means the entry is no longer in the map.

throw new ConcurrentModificationException(ise);

}

action.accept(k, v);

}

}

该方法传了一个BiConsumer参数,BiConsumer是函数接口,和consumer一样,即消费者,吃掉两个参数什么也不拉,该方法主要作用,封装了遍历方法,对集合的key/value进行成队的遍历,但是我看出来一点拦截器的意思!

3.3 replaceAll方法

default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {

Objects.requireNonNull(function);

for (Map.Entry<K, V> entry : entrySet()) {

K k;

V v;

try {

k = entry.getKey();

v = entry.getValue();

} catch(IllegalStateException ise) {

// this usually means the entry is no longer in the map.

throw new ConcurrentModificationException(ise);

}

 

// ise thrown from function is not a cme.

v = function.apply(k, v);

 

try {

entry.setValue(v);

} catch(IllegalStateException ise) {

// this usually means the entry is no longer in the map.

throw new ConcurrentModificationException(ise);

}

}

}

和foreach一样的套路,传入一个BiFunction函数接口,BiFunction有三个参数,这两个参数分别是集合的key和value以及被新的value,而内部调用了迭代器进行迭代,该方法最终想要实现的功能就是对集合里的value进行替换。

3.4 putIfAbsent方法

 default V putIfAbsent(K key, V value) {
        V v = get(key);
        if (v == null) {
            v = put(key, value);
        }

        return v;
    }

顾名思义,该方法时尝试插入的意思,从代码来看,该方法最终的作用是对结合中key/value查重

还有剩下来的几个默认实现方法,都比较简单remove(传入key和value,返回删除结果)/replace(传入key和value以及新的value,返回是否替换结果)/replace(重载方法,传入key和新的value,返回新的value)/computeIfAbsent(也是替换方法,该方法是判断新传入的值是否为null,如果为null就会删除key)等方法;

3.5内部接口,Entry

映射项(键-值对)。Map.entrySet 方法返回映射的 collection 视图,其中的元素属于此类。获得映射项引用的唯一 方法是通过此 collection 视图的迭代器来实现。这些 Map.Entry 对象 在迭代期间有效;更确切地讲,如果在迭代器返回项之后修改了底层映射,则某些映射项的行为是不确定的,除了通过 setValue 在映射项上执行操作之外。(JDK文档如此解式,其实该方法主要也是为了加快集合的遍历速度,比如我们遍历集合时,可以获得key的set集合,然后遍历取值,也可以获得该集合的entryset,使用迭代器迭代获取key和value,那么这两种遍历,显然第二种更快)

Entry接口内部有四个静态方法,分别是comparingByKey、comparingByValue()、comparingByKey带参重载方法和comparingByValue带参重载方法,这四个方法的意义是调用函数接口Comparator进行对比

 

 

3.总结:

此篇文章主要以JDK8为原型,分析了集合的继承体系,顶级接口Iterable接口,定义了集合的迭代器方法/增强for方法以及并行迭代的接口方法;而collection方法则是定义了集合的一些基础方法,比如增删改查数量等等!下一篇文章我们会分别从list体系/set体系/Queue体系去分别介绍其实现类以及实现类的作用!

 

 

 

 

 

 

 

 

 

<think>好的,我现在需要分析Java中Collection接口的源码,基于JDK 8版本。首先,我应该从哪里开始呢?记得用户提供的引用中提到了Collection是集合类的根接口,所有集合类都需要继承或实现它的方法。那我应该先查看JDK 8的Collection接口的源码,了解它的结构和方法。 首先,我得确认JDK 8中Collection接口的位置。通常,它应该在java.util包下。打开源码文件,看到Collection接口确实在java.util.Collection。接下来,看看它的声明,根据引用[1]提到,Collection扩展了Iterable接口,对吗?是的,JDK 8中Collection的声明是public interface Collection<E> extends Iterable<E>,所以用户提供的引用可能有误,因为正确的继承关系是继承Iterable,而不是实现Iterator。可能用户引用中的内容有笔误,需要注意这点。 接下来,分析Collection接口的方法。引用[1]提到所有与集合类有关的子接口或类都需要继承或实现它的所有方法。所以这些方法包括基本的添加、删除、大小、包含等操作。比如size(), isEmpty(), contains(Object o), iterator(), toArray(), add(E e), remove(Object o), containsAll(Collection<?> c), addAll(Collection<? extends E> c), removeAll(Collection<?> c), retainAll(Collection<?> c), clear(), equals(Object o), hashCode(),还有JDK 8新增的stream()和parallelStream()方法,这些可能和引用[4]提到的Stream流有关。 需要逐个方法分析吗?比如,查看add方法的定义,返回boolean,可能表示是否成功添加。remove方法返回boolean,表示是否成功移除。iterator()方法返回迭代器,用于遍历集合元素。然后,stream()方法返回个顺序流,parallelStream()返回并行流,这两个是JDK 8新增的,支持函数式编程和流处理,引用[4]可能详细说明这部分源码的实现。 然后,考虑Collection接口的继承关系。它继承自Iterable接口,所以Iterable中的forEach和spliterator方法也被Collection继承。另外,Collection接口是List、Set、Queue等子接口的父接口。比如,List接口扩展了Collection,添加了位置访问等方法;Set接口则强调元素的唯性。 接下来,查看源码中的默认方法。例如,在JDK 8中,接口可以有默认实现。比如,Collection中的removeIf方法是个默认方法,它允许根据条件删除元素。这个方法的实现可能涉及迭代器和条件判断。 然后,分析源码中的注释,了解设计意。例如,Collection的文档说明集合代表组对象,称为元素。有些集合允许重复元素,有些不允许;有些有序,有些无序。这些特性由具体的实现类决定,如ArrayList允许重复且有序,HashSet不允许重复且无序。 另外,需要关注方法的具体实现,但接口中的方法都是抽象的,所以实际实现是在具体类中,如ArrayList、HashSet等。但接口中可能有些默认方法,比如spliterator(),默认实现可能基于iterator()。 关于stream()方法,引用[4]提到从Collection的stream()方法入手,所以需要看Collection中stream()的实现。在JDK 8中,Collection的stream()方法默认实现是调用StreamSupport.stream,传入spliterator()的结果,并且参数false表示是顺序流。parallelStream()则传入true,表示并行流。这涉及到Stream的底层实现,可能利用Spliterator进行元素的分割和遍历。 此外,需要注意源码中的泛型使用,比如Collection<E>,所有方法都使用泛型E来确保类型安全。比如,add(E e)的参数类型是E,但有些方法如contains(Object o)使用Object,这是因为历史原因或者为了兼容性。 还要注意些方法的具体规范,比如add方法在支持添加的集合中应该返回true,如果集合因调用而改变的话。但像不可变集合调用add会抛出异常,或者返回false,这取决于具体实现。 在分析过程中,可能需要参考JDK文档或相关资料,确保理解正确。例如,引用[3]提到了Collection的子接口如Queue、List、Set,以及它们的实现类如ArrayList、LinkedList、HashSet,这些类的源码分析可能也需要涉及,但用户的问题主要集中在Collection接口本身。 总结来说,分析步骤应该是:查看接口声明,方法列表,默认方法,继承的方法,与相关接口的关系,以及关键方法如stream()的实现细节。同时,结合用户提供的引用,特别是引用[1]和引用[4],来补充对源码的理解,注意可能的笔误或误解,比如继承的是Iterable而非实现Iterator接口。</think>### Java Collection接口源码分析(JDK 8) #### 1. **接口声明与继承关系** ```java public interface Collection<E> extends Iterable<E> { // 方法定义... } ``` - **继承关系**:继承自`Iterable<E>`接口,因此默认支持迭代操作[^1][^3]。 - **泛型定义**:`<E>`表示集合元素的类型,确保类型安全。 #### 2. **核心方法分析** | 方法签名 | 功能说明 | |-----------------------------------|--------------------------------------------------------------------------| | `int size()` | 返回集合元素数量(若超过`Integer.MAX_VALUE`,返回`Integer.MAX_VALUE`) | | `boolean isEmpty()` | 判断集合是否为空(等价于`size() == 0`) | | `boolean contains(Object o)` | 判断是否包含指定元素(依赖`equals()`方法实现) | | `Iterator<E> iterator()` | 返回迭代器,支持顺序遍历元素 | | `Object[] toArray()` | 将集合转换为数组(返回新数组) | | `<T> T[] toArray(T[] a)` | 将集合转换为指定类型数组(可复用输入数组) | | `boolean add(E e)` | 添加元素(具体行为由实现类决定,如`ArrayList`允许重复,`Set`可能拒绝) | | `boolean remove(Object o)` | 删除指定元素(返回是否成功) | | `boolean containsAll(Collection<?> c)` | 判断是否包含另集合的所有元素 | | `boolean addAll(Collection<? extends E> c)` | 添加另集合的所有元素 | | `boolean removeAll(Collection<?> c)` | 删除与指定集合交集的所有元素 | | `boolean retainAll(Collection<?> c)` | 仅保留与指定集合交集的元素 | | `void clear()` | 清空所有元素 | #### 3. **JDK 8新增方法** ```java // 返回顺序流(底层调用StreamSupport.stream) default Stream<E> stream() { return StreamSupport.stream(spliterator(), false); } // 返回并行流 default Stream<E> parallelStream() { return StreamSupport.stream(spliterator(), true); } // 根据条件删除元素(默认实现基于迭代器) 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; } ``` - **流处理**:`stream()`和`parallelStream()`通过`Spliterator`分割数据源,支持函数式编程[^4]。 - **默认方法**:`removeIf`通过`Predicate`实现条件删除,无需子类重写即可使用。 #### 4. **与Iterable接口的关系** - `Iterable`提供了`forEach(Consumer<? super E> action)`方法,可通过Lambda遍历集合: ```java default void forEach(Consumer<? super E> action) { Objects.requireNonNull(action); for (E e : this) { action.accept(e); } } ``` - `Spliterator`用于并行遍历和数据分割(影响流处理的性能)。 #### 5. **实现类关键差异** | 实现类 | 特点 | |---------------|----------------------------------------------------------------------| | `ArrayList` | 基于动态数组,支持快速随机访问,允许重复元素 | | `HashSet` | 基于哈希表,元素唯且无序,依赖`hashCode()`和`equals()` | | `LinkedList` | 基于双向链表,插入/删除高效,支持队列操作 | #### 6. **设计模式与规范** - **迭代器模式**:通过`iterator()`实现遍历与操作的分离。 - **契约设计**:方法行为由接口约定(如`add()`在不可变集合中抛出异常)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值