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

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体系去分别介绍其实现类以及实现类的作用!

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值