zoukankan      html  css  js  c++  java
  • 数据结构

    简介

    Collection继承自Iterable,Collection接口是Java集合两大分支中的一支,Queue、List、Set都是Collection的扩展;集合大类分为了Collection和Map。

    常见的数据结构:数组(Array)、集(Set)、队列(Queue)、链表(Linkedlist)、树(Tree)、堆(Heap)、栈(Stack)和映射(Map)等结构

    Iterable接口

    实现这个接口的类允许使用 for-each loop 语句来遍历

    复制代码
    public interface Iterable<T> {
        // 返回一个迭代器对象
        Iterator<T> iterator();
        // JDK1.8 新增遍历方式
        default void forEach(Consumer<? super T> action) {
            Objects.requireNonNull(action);
            for (T t : this) {
                action.accept(t);
            }
        }
        // 可分割迭代器
        default Spliterator<T> spliterator() {
            return Spliterators.spliteratorUnknownSize(iterator(), 0);
        }
    }
    复制代码

    Iterable最早出现在JDK 1.5,开始只有iterator()一个抽象方法,需要子类来实现一个内部迭代器Iterator遍历元素。
    后两个方法是Java 8后新添加的,forEach(Consumer action)是为了方便遍历操作集合内的元素,Spliterator(splitable iterator可分割迭代器)接口是Java为了并行遍历数据源中的元素而设计的迭代器,这个可以类比最早Java提供的顺序遍历迭代器Iterator,但一个是顺序遍历,一个是并行遍历。

    Collection 接口

    Collection是一个高度封装的集合接口,它提供了所有集合要实现的默认方法  

    public interface Collection<E> extends Iterable<E>

    基本方法

    复制代码
    // 返回此集合的元素数量
    int size();
    // 返回集合是否为空
    boolean isEmpty();
    // 如果包含元素O则返回为true
    boolean contains(Object o);
    // 返回此集合元素的迭代器
    Iterator<E> iterator();
    // 将此集合转化为数组
    Object[] toArray();
    // 将此集合转化为制定类型数组
    <T> T[] toArray(T[] a);
    // 返回值是boolean,添加一个元素
    boolean add(E e);
    // 删除指定的元素
    boolean remove(Object o);
    // 如果包含集合C返回为true
    boolean containsAll(Collection<?> c);
    // 返回值是boolean类型,将集合C中的所有元素添加到此集合
    boolean addAll(Collection<? extends E> c);
    // 删除包含集合c的所有元素
    boolean removeAll(Collection<?> c);
    // 获取集合c与此集合的交集
    boolean retainAll(Collection<?> c);
    // 删除此集合中的所有元素
    void clear();
    // 将指定的对象O与此集合进行比较
    boolean equals(Object o);
    // 返回此集合的INT类型哈希码
    int hashCode();
    复制代码

    默认实现方法

    复制代码
    // 删除满足条件的所有元素
    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;
    }
    @Override
    // 创建一个Spliterator
    default Spliterator<E> spliterator() {
        return Spliterators.spliterator(this, 0);
    }
    // 返回以此集合作为源的顺序流
    default Stream<E> stream() {
        return StreamSupport.stream(spliterator(), false);
    }
    // 创建一个Spliterator并行流
    default Stream<E> parallelStream() {
        return StreamSupport.stream(spliterator(), true);
    }
    复制代码

    AbstractCollection 抽象类

    AbstractCollection 实现Collection接口,该类是一个抽象类,提供了对集合类操作的一些基本实现。List和Set的具体实现类基本上都直接或间接的继承了该类

    public abstract class AbstractCollection<E> implements Collection<E>

    构造函数

    protected AbstractCollection() {
    }

    未实现的方法

    // 获取迭代器
    public abstract Iterator<E> iterator();
    // 获取集合元素个数
    public abstract int size();

    已实现的方法

    AbstractCollection所有已实现的方法子类都会覆盖掉,官方的说法 “此类提供集合的骨架实现接口,以最小化实现此接口所需的工作”

    判空

    public boolean isEmpty() {
        // 元素个数为0,就为空
        return size() == 0;
    }

    添加

    复制代码
    public boolean add(E object) {
        throw new UnsupportedOperationException();
    }
    ​
    public boolean addAll(Collection<? extends E> c) {
        // 是否添加成功
        boolean modified = false;
        // 迭代参数中每一个元素
        for (E e : c)
            // 添加元素并判断是否添加成功
            if (add(e))
                modified = true;
        // 返回是否添加成功
        return modified;
    }
    复制代码

    直接调用AbstractCollection的add方法会抛出异常,所以我们在实现Collection自定义数据结构时一定要覆盖此方法。

    删除

    复制代码
    public boolean remove(Object object) {
        //获取子类实现的 迭代器
        Iterator<?> it = iterator();
        if (object != null) { // 参数不为空
            // 循环迭代
            while (it.hasNext()) {
                // 对比找到元素
                if (object.equals(it.next())) {
                    // 移除
                    it.remove();
                    return true;
                }
            }
        } else { // 参数为空
            // 循环迭代,参数为空相当于清空
            while (it.hasNext()) {
                if (it.next() == null) {
                    // 移除
                    it.remove();
                    return true;
                }
            }
        }
        return false;
    }
    ​
    public boolean removeAll(Collection<?> c) {
        // 空校验
        Objects.requireNonNull(c);
        // 是否删除成功
        boolean modified = false;
        // 迭代当前集合
        Iterator<?> 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();
            // 单线程使用迭代器的 remove() 方法不会导致 fail-fast
            it.remove();
        }
    }
    复制代码

    包含

    复制代码
    public boolean contains(Object o) {
        // 获取当前迭代器    
        Iterator<E> it = iterator();
        if (o==null) { // 参数为空
            // 迭代查找是否包含空元素
            while (it.hasNext())
                if (it.next()==null)
                    // 包含空返回true
                    return true;
        } else {
            // 迭代每一个元素进行比较
            while (it.hasNext())
                if (o.equals(it.next()))
                    // 元素equals相等返回true
                    return true;
        }
        return false;
    }
    ​
    public boolean containsAll(Collection<?> c) {
        // 遍历参数中每一个元素    
        for (Object e : c)
            // 有一个不包含就返回false
            if (!contains(e))
                return false;
        // 能到这儿说明都包含
        return true;
    }
    复制代码

    取交集

    复制代码
    public boolean retainAll(Collection<?> collection) {
        boolean result = false;
        Iterator<?> it = iterator();
        // 迭代当前集合
        while (it.hasNext()) {
            // 参数集合中不包含,就在当前集合中移除此元素
            if (!collection.contains(it.next())) {
                // 移除
                it.remove();
                // 移除成功,结果置为true
                result = true;
            }
        }
        return result;
    }
    复制代码

    转数组

    复制代码
    public <T> T[] toArray(T[] a) {
        // 获取集合长度
        int size = size();
        // 参数数组长度大于此集合长度就用参数数组,否则创建新数组
        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++) {
            //集合元素大小小于数组的长度
            if (! it.hasNext()) { // fewer elements than expected
                if (a == r) {
                    //如果数组是参数中的数组,则将剩余部分的值都设置为null
                    r[i] = null; // null-terminate
                // 如果传入的数组长度小于集合长度
                } else if (a.length < i) {
                    // 通过Arrays.copyOf将之前数组中的元素复制到新数组中
                    return Arrays.copyOf(r, i);
                } else {//如果传入数组的长度比集合大,则将多的元素设置为空
                    System.arraycopy(r, 0, a, 0, i);
                    if (a.length > i) {
                        a[i] = null;
                    }
                }
                return a;
            }
            r[i] = (T)it.next();
        }
        // more elements than expected
        //集合元素大小大于数组的长度
        return it.hasNext() ? finishToArray(r, it) : r;
    }
    private static <T> T[] finishToArray(T[] r, Iterator<?> it) {
        // 获取新数组长度
        int i = r.length;
        // 接着前面继续迭代
        while (it.hasNext()) {
            int cap = r.length;
            // 起始位置
            if (i == cap) {
                // 新数组扩容,新长度 = 原长度*2 + 1
                int newCap = cap + (cap >> 1) + 1;
                // 新长度小于上限(int最大值-8)
                if (newCap - MAX_ARRAY_SIZE > 0)
                    newCap = hugeCapacity(cap + 1);
                // 创建新数组并拷贝原数组
                r = Arrays.copyOf(r, newCap);
            }
            // 下标加1继续放值
            r[i++] = (T)it.next();
        }
        // 新数组
        return (i == r.length) ? r : Arrays.copyOf(r, i);
    }
    ​
    private static int hugeCapacity(int minCapacity) {
        // 长度小于0抛出越界异常
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError
                ("Required array size too large");
        // 长度超限默认最大值
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }
    复制代码

    对于toArray方法可能很多人会有疑问,toArray方法第二步如果数组长度不够不是已经建了新数组吗,为什么在迭代过程中还要对新数组进行扩容?

    toArray不是线程安全的,在迭代的过程中,没有人能保证数据结构中元素不会增加或减少,减少到没关系,增加后新创建的数组放不下了怎么办?所以只能做扩容处理。

  • 相关阅读:
    SpringMVC参数校验
    SpringBoot2集成Activiti6
    spring boot与activiti集成实战 转
    使用国内阿里maven私服方法
    springboot2.04与activiti 6.0集成
    idea actiBPM插件生成png文件 (解决没有Diagrams或Designer选项问题)
    嵌入式Qt-4.8.6显示中文并且改变字体大小和应用自己制作的字体库
    基于Qt Assistant制作软件帮助文档
    推荐一本书,30天自制操作系统
    Qt5 UI信号、槽自动连接的控件重名大坑(UI生成的槽函数存在一个隐患,即控件重名。对很复杂的控件,不要在 designer 里做提升,而是等到程序启动后,再动态创建,可以避免很多问题)
  • 原文地址:https://www.cnblogs.com/ysd139856/p/12539359.html
Copyright © 2011-2022 走看看