前言
书接上文,上一篇中对 Java 能力接口与能力器接口进行了介绍,本篇开始正式进入 Java 8 数据结构的分析。
Java 8 数据中业界最佳实现的数据结构接口与类大体上可以分为 4 类,List,Set,Map,Queue,先来看一下这四类数据结构整体的继承关系图
可以看到还是比较庞杂的,其中还涉及到之前所说到的能力/能力器/流式处理/线程安全等诸多概念,所以本篇只是一个概览,接下去将按照 List 篇->Map 篇 -> Set 篇 -> Queue 篇 的顺序逐一拆解介绍。
从这张图中可以看出,List,Set 与 Queue 类似都继承自 Collection 接口,这与它们的特点有关,这三类数据结构都属于一组相同类型的数据的容器,我将它们称为组数据结构,而 Map 并不是一组相同类型的数据的容器,它是字典型的,所以也可以从图中看到它的继承关系是独立的。
接下来将对组数据的继承关系的公共部分,Collection 接口与 AbstractCollection 抽象类进行介绍
Collection
/**Collection 是所有单个对象群的数据结构(List,Set)的顶层接口,Map 类由于不是单个对象群的集合,所以不需要继承这个接口,Collection 继承自 Iterable 接口,拥有通过串行遍历,并行遍历能力(但是真正实现并行遍历的能力需要重写 Iterable 中的 spliterator 方法)**/
public interface Collection<E> extends Iterable<E> {
/**查询操作**/
/**获取元素的个数**/
int size();
/**判断集合是否为空**/
boolean isEmpty();
/**判断集合中是否包含元素**/
boolean contains(Object o);
/**获取迭代器方法**/
Iterator<E> iterator();
/**转换为 Object 数组方法**/
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 removeAll(Collection<?> c);
/**传入一个断言实现,并注意迭代当前数据结构中的对象,如果断言命中,则移除对应对象,并返回 true,否则返回 false**/
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;
}
/**当前集合与传入集合对象取交集,并返回是否需要移除元素**/
boolean retainAll(Collection<?> c);
/**移除所有元素**/
void clear();
/**比较与 hash 方法**/
/**判断两个集合对象是否相等**/
boolean equals(Object o);
/**返回集合对象的 hashCode **/
int hashCode();
/**重写多线程迭代方法**/
@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);
}
}
Collection 中定义了一些组数据结构中的统一都需要使用方法,这种设计屏蔽了不同实现类的实现细节。
AbstractCollection
/**实现了 Collection 接口中的一些方法,目的是在实现 Collection 接口时可以不必再次实现所有方法**/
public abstract class AbstractCollection<E> implements Collection<E> {
/**受保护的构造方法,在别的包中不可以调用这个构造方法**/
protected AbstractCollection() {
}
// 查询操作
/**返回一个覆盖子类所有元素的串行迭代器**/
public abstract Iterator<E> iterator();
/**延续 Collection 中的 size 方法,需要子类自己实现,返回的容量大小只是一个估测值**/
public abstract int size();
/**判空方法**/
public boolean isEmpty() {
return size() == 0;
}
/**实现判断这个组数据容器中是否包含 o 参数**/
public boolean contains(Object o) {
/**首先获得实现类的串行迭代器**/
Iterator<E> it = iterator();
if (o==null) { //如果参数为空
while (it.hasNext()) //如果迭代器中还存在元素
if (it.next()==null) //如果迭代器中下一个元素为 null
return true; //返回 true
} else { //如果参数不为空
while (it.hasNext()) //如果迭代器中还存在元素
if (o.equals(it.next())) //通过对象的 equals 方法判断两个对象是否相等
return true; //如果相等返回 true
}
return false; //其他情况都返回 false
}
/**将组数据结构转换为该元素类型的数组**/
public Object[] toArray() {
Object[] r = new Object[size()]; //估算 array 容量,准备查看更多或者更少的元素,缓存一个容量为估值大小的 Object 数组
Iterator<E> it = iterator(); //获得串行迭代器
for (int i = 0; i < r.length; i++) { //通过 for 遍历数组长度值
if (! it.hasNext()) //如果迭代器中没有下一个值,说明实际元素数量小于预期
return Arrays.copyOf(r, i); //返回一个新的数组,需要做类型判断,其中的元素只是浅拷贝
r[i] = it.next(); //更新数组对应位置元素的值
}
return it.hasNext() ?
finishToArray(r, it) //实际元素数量大于预期,调用 finshToArray 方法
: r; //否则返回数组
}
/**将组数据结构转换为该元素类型的数组,接收一个与该元素类型的数组参数**/
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
int size = size(); //估算 array 容量,准备查看更多或者更少的元素
T[] r = a.length >= size ? a : //如果参数的容量大于等于估值,缓存参数
(T[])java.lang.reflect.Array //否则缓存一个范型类型为参数类型,长度为估值的新数组
.newInstance(a.getClass().getComponentType(), size);
Iterator<E> it = iterator(); //获得串行迭代器
for (int i = 0; i < r.length; i++) { //通过 for 遍历数组长度值
if (! it.hasNext()) { //如果迭代器中没有下一个值,说明实际元素数量小于预期
if (a == r) { //如果两个数组中的元素都相同,也就是前面 a 直接赋值给 r 的情况
r[i] = null; //最后一个元素为 null(比 a 多一个元素)
} 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; //最后一个元素为 null
}
}
return a; //返回浅拷贝后的结果
}
r[i] = (T)it.next(); //步移迭代器,更新 r 数组
}
return it.hasNext() ?
finishToArray(r, it) //实际元素数量大于预期,调用 finshToArray 方法
: r; //否则返回数组
}
/**根据 VM 优化最大数组长度,去掉头描述的长度**/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/**当实际元素数量大于预估值时,重新分配 toArray 方法中的数组,通过迭代器参数来填装它**/
@SuppressWarnings("unchecked")
private static <T> T[] finishToArray(T[] r, Iterator<?> it) {
int i = r.length; //将预估数组的容量缓存到 i 中
while (it.hasNext()) { //判断迭代器中是否还有元素
int cap = r.length; //将现在预估数组的容量缓存到 cap 中,这个判断应该是针对带参的 toArray 方法的,由于 while 是一个延时方法,在多线程的情况下,如果 toArray 的参数可能被某个线程修改了容量,比如进行了删除操作,那么经由它复制的 r 参数就会被改变
if (i == cap) { //如果 r 的容量没有被改变过
int newCap = cap + (cap >> 1) + 1; //新容量 = 3/2 * 旧容量 + 1
//越界感知
if (newCap - MAX_ARRAY_SIZE > 0) //如果新容量大于数组最大容量常量
newCap = hugeCapacity(cap + 1); //新容量 = 尝试获取最大容量,这里可能会抛出 OutOfMemoryError
r = Arrays.copyOf(r, newCap); //否则,用新容量浅拷贝 r 并后赋值给 r
}
r[i++] = (T)it.next(); //步移迭代器元素赋值更新 r
}
//如果过度分配了,这里应该是只 i 小于 r 的容量的意思,进行修剪
return (i == r.length) ? //循环结束后判断 i 是否等于 r 的容量
r //如果是,返回 r
: Arrays.copyOf(r, i); //否则对 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;
}
// 修改操作
/**添加操作,需要实现类重写,否则会抛出 UnsupportedOptionException**/
public boolean add(E e) {
throw new UnsupportedOperationException();
}
/**删除操作,如果找到了参数相等的元素,调用串行迭代器的 remove 方法将它移出**/
public boolean remove(Object o) {
Iterator<E> 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())) { //调用参数类型的 equals 方法判断参数与迭代器的下一个原始是否相等
it.remove(); //调用迭代器的删除方法
return true;
}
}
}
return false; //以上情况都不是,返回 false
}
// 扩展操作
/**判断参数容器中的元素是否完全包含在当前容器中,接收一个容器参数 c,返回判断值**/
public boolean containsAll(Collection<?> c) {
for (Object e : c) //调用 for 方法步移组数据容器
if (!contains(e)) //在每一次步移中调用 contains 方法循环串行迭代器判断参数是否包含在迭代器的元素中
return false; //一旦发现有不存在的,直接返回 false
return true; //全部存在,返回 true
}
/**向当前容器添加所有参数容器中的元素,接收一个容器参数 c,返回添加成功判断值**/
public boolean addAll(Collection<? extends E> c) {
boolean modified = false; //初始操作结果标志为 false
for (E e : c) //调用 for 方法步移组数据容器,注意组数据容器的范型必须是当前容器范型的自己或子类
if (add(e))
modified = true; //若有一个添加成功,则结果标志置为 true
return modified; //返回结果标志
}
/**从当前容器中删除所有参数容器中的元素,接收一个容器参数 c,返回删除成功判断值**/
public boolean removeAll(Collection<?> c) {
Objects.requireNonNull(c); //如果参数为 null,抛出 NullPointerExceprtion 异常
boolean modified = false; //初始操作结果标志为 false
Iterator<?> it = iterator(); //获取容器串行迭代器
while (it.hasNext()) { //判断迭代器中是否有更多的值
if (c.contains(it.next())) { //判断迭代器中的下一个元素是否包含在参数容器中
it.remove(); //调用迭代器删除方法
modified = true; //结果标志置为 true
}
}
return modified; //返沪结果标志
}
/**与删除所有方法正好相反,保留所有方法,从当前容器中删除所有参数容器中不包含的元素,接收一个容器参数 c,返回删除成功判断值**/
public boolean retainAll(Collection<?> c) {
Objects.requireNonNull(c);
boolean modified = false;
Iterator<E> it = iterator();
while (it.hasNext()) {
if (!c.contains(it.next())) { //判断迭代器中的下一个元素是否不包含在参数容器中
it.remove();
modified = true;
}
}
return modified;
}
/**清空方法**/
public void clear() {
Iterator<E> it = iterator(); //获取容器的串行迭代器
while (it.hasNext()) { //循环判断迭代器是否还有更多值
it.next(); //步移迭代器至下一个位置
it.remove(); //调用迭代器的删除方法
}
}
// String 转换
/**AbstractCollection 对 toString 方法重写**/
public String toString() {
Iterator<E> it = iterator(); //获得串行迭代器
if (! it.hasNext()) //如果没有更多元素
return "[]"; //返回 “[]”
StringBuilder sb = new StringBuilder(); //String 的可变操作类
sb.append('[');
for (;;) { //自旋
E e = it.next(); //步移获取迭代器中的下一个元素赋值给 e
sb.append(e == this ? "(this Collection)" : e); //根据迭代器中的对象拼接字符串
if (! it.hasNext())
return sb.append(']').toString(); //如果迭代器不再有更多元素,拼接 “]” 后调用 StringBuilder 的 toString 方法返回
sb.append(',').append(' '); //否则拼接“, ”
}
}
}
AbstractCollection 对于 Collection 中的方法的实现,撇去两个抽象方法,获得串行迭代器方法 public abstract Iterator<E> iterator()
与获得容器容量方法 public abstract int size()
,以及需要子类进一步实现的 public boolean add(E e)
方法,其余都是通过容器自身的串行迭代器来实现的,所以可以说对于容器的操作,就是对于容器的串行迭代器的操作。
下一篇将对 List 数据结构进行分析。