文章目录
一、前言
在实际的开发场景中我们经常会用的集合,什么情况下选择什么类型的集合是Java使用过程中开发人员必须掌握的技能,而且在很多面试过程中,这一块的内容也是必考的。在很多技术博客上已经有很多分享和总结,今天我将从各个接口和集合类的源码分析入手,深入了解集合的底层结构。
《Java 集合框架之Set系列源码解析》
《Java集合之Map系列源码解析》
二、总览
三、Collection
Collection集合层次结构中的根接口,继承Iterable接口,也就是迭代器。
那我们先来看一下Iterable接口源码,这个接口又定义了哪些方法。
在源码注释中对这个接口的解释是“实现这个接口允许一个对象作为“for-each循环”语句的目标”
Iterable接口是从jdk1.5版本开始有的,而forEach方法和**spliterator()**方法则是从jdk1.8才有的。
public interface Iterable<T> {
Iterator<T> iterator();
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
//在此迭代器所描述的元素上创建一个Spliterator可分割迭代器
default Spliterator<T> spliterator() {
return Spliterators.spliteratorUnknownSize(iterator(), 0);
}
}
方法中涉及到两个接口Consumer和Spliterator,也是jdk1.8引入的,这里就不展开详细分析了。稍后我们对Spliterator这个接口重点解析,现在回到Collection接口上
public interface Collection<E> extends Iterable<E> {
//返回此集合中的元素数
int size();
//判断是否为空
boolean isEmpty();
//判断是否包含指定元素
boolean contains(Object o);
//返回此集合中元素的迭代器
Iterator<E> iterator();
//返回一个数组,该数组包含此集合中的所有元素
Object[] toArray();
//返回数组的运行时类型是指定数组的运行时类型
<T> T[] toArray(T[] a);
//返回true表示新增元素成功,返回false表示元素已存在
boolean add(E e);
//移除指定元素
boolean remove(Object o);
//判断是否包含指定集合的所有元素
boolean containsAll(Collection<?> c);
//注释中标明optional operation,表示子类可以不实现
boolean addAll(Collection<? extends E> c);
//注释中标明optional operation,表示子类可以不实现
boolean removeAll(Collection<?> c);
//@since 1.8 移除满足条件的所有元素
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;
}
//注释中标明optional operation,表示子类可以不实现
//仅保留此集合中包含在指定集合中的元素
boolean retainAll(Collection<?> c);
注释中标明optional operation,表示子类可以不实现
//从该集合中删除所有元素
void clear();
//具体看Set和List的实现
boolean equals(Object o);
int hashCode();
//@since 1.8 返回可分割迭代器
@Override
default Spliterator<E> spliterator() {
return Spliterators.spliterator(this, 0);
}
//@since 1.8 返回以此集合作为源的Stream
default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}
//since 1.8 返回可能并行的以此集合作为源的Stream
default Stream<E> parallelStream() {
return StreamSupport.stream(spliterator(), true);
}
}
从上面源码中可以看到其中有5个default修饰的方法(default 是 java 8新引入的关键字,也可称为Virtual
extension methods——虚拟扩展方法。是指,在接口内部包含了一些默认的方法实现,也就是接口中可以包含方法体,这打破了Java之前版本对接口的语法限制,从而使得接口在进行扩展的时候,不会破坏与接口相关的实现类代码)
通过stream()方法我们可以知道,所有继承Collection接口的类就都可以支持Stream方法了,继而支持Lambda表达式,继而可以并行执行某个动作。
关于Spliterator接口和Spliterators静态类
Spliterator用于遍历和划分源元素的对象。Spliterator所覆盖的元素的源可以是数组、集合、IO通道或生成器函数;jdk1.8发布后,对于并行处理的能力大大增强,Spliterator就是为了并行遍历元素而设计的一个迭代器,jdk1.8中的集合框架中的数据结构都默认实现了spliterator。在Spliterator接口中内部定义了一个内部接口OfPrimitive,专门用于基础数据的Spliterator。
Spliterators用于操作或创建Spliterator实例的静态类,Spliterators类中又专门针对int,long,double三种数据类型的数据源定义了OfInt、OfLong、OfDouble三个继承OfPrimitive接口的接口。
以下是官方文档的描述
Interface Spliterator<T>
Type Parameters:
T - the type of elements returned by this Spliterator
All Known Subinterfaces:
Spliterator.OfDouble, Spliterator.OfInt, Spliterator.OfLong, Spliterator.OfPrimitive<T,T_CONS,T_SPLITR>
All Known Implementing Classes:
Spliterators.AbstractDoubleSpliterator, Spliterators.AbstractIntSpliterator, Spliterators.AbstractLongSpliterator, Spliterators.AbstractSpliterator
上面已知的实现类均为Spliterators类的内部类。
在Spliterator接口中还定义了Characteristic value 特征值,作为Spliterators静态类创建Spliterator的参数
//元素有序
public static final int ORDERED = 0x00000010;
//元素不重复
public static final int DISTINCT = 0x00000001;
//表示元素顺序按照预定义的顺序,可以通过getComparator 获取排序器,若返回null ,则是按自然排序
public static final int SORTED = 0x00000004;
public static final int SIZED = 0x00000040;
//表示数据源保证元素不会为空
public static final int NONNULL = 0x00000100;
//表示在遍历的过程中不能添加、替换、删除元素
public static final int IMMUTABLE = 0x00000400;
//表示元素可以被多个线程安全并发得修改而不需要外部的同步
public static final int CONCURRENT = 0x00001000;
public static final int SUBSIZED = 0x00004000;
这些特征值将在Set,List等接口中有所体现。