Java 数据结构 -- 06.Java 8 数据结构中的结构接口与类概览

前言

书接上文,上一篇中对 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 数据结构进行分析。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值