Java 集合 - 集合框架概述

news2024/11/28 12:38:57

文章目录

    • 1.集合框架体系结构
    • 2.Collection 接口
      • 2.1 Iterator
        • 2.1.1 使用迭代器遍历集合
        • 2.1.2 使用迭代器删除集合元素
        • 2.1.3 Iterator 迭代器的 fail-fast 机制
      • 2.2 Iterable
      • 2.3 List 集合
      • 2.4 Set 集合
      • 2.5 Queue
    • 3.Map 集合

Java 集合框架(Java Collections Framework)是 Java 标准类库中的一个重要组成部分,用于存储、操作和管理数据。它提供了一系列的接口、抽象类和实现类,用于表示和操作不同类型的集合数据结构。

集合和数组既然都是容器,它们有什么区别呢?

  • 数组的长度是固定的,集合的长度是可变的;
  • 数组中可以存储基本数据类型值,也可以存储对象,而集合中只能存储对象。

1.集合框架体系结构

先来看看一个简单的集合框架类图:

可见,Java 集合框架定义了两个顶层的接口 Collection(存储对象的集合) 和 Map(存储键值对,也成为映射关系),用于表示不同类型的集合。

2.Collection 接口

Collection 接口是 Java 集合框架的根接口,它代表了一组对象的集合,这些对象也称为 collection 的元素。一些 collection 允许有重复的元素,而另一些则不允许。一些 collection 是有序的,而另一些则是无序的。JDK 不提供此接口的任何直接实现,它只负责定义常见的集合操作,如添加元素、删除元素、遍历元素等。

该接口源码如下:

public interface Collection<E> extends Iterable<E> {
    // Query Operations(查询操作)

    /**
     * 返回此集合中的元素数。
     * 说明:如果此集合包含的元素多于 Integer.MAX_VALUE,则返回 Integer.MAX_VALUE。
     */
    int size();

    /**
     * 返回true如果此集合不包含元素。
     */
    boolean isEmpty();

    /**
     * 返回true如果此集合包含指定的元素。
     */
    boolean contains(Object o);

    /**
     * 返回此集合中的元素上的迭代器。没有关于元素返回的顺序的保证(除非此集合是某个类的实例,该类提供保证)。
     */
    Iterator<E> iterator();

    /**
     * 返回包含此集合中所有元素的数组。
     * 说明:
     * 1.如果此集合对其元素由其迭代器返回的顺序有任何保证,则此方法必须以相同的顺序返回元素。返回的数组的运行时组件类型为Object。
     * 2.返回的数组将是“安全的”,因为此集合不维护对它的任何引用。(换句话说,即使此集合由数组支持,此方法也必须分配一个新数组)。
     */
    Object[] toArray();

    /**
     * 返回包含此集合中所有元素的数组;返回数组的运行时类型是指定数组的类型。
     * 说明:
     * 1.如果此集合适合指定的数组,则返回该数组。否则,将使用指定数组的运行时类型和此集合的大小分配新数组。
     * 2.如果此集合适合指定的数组并有剩余空间(即数组中的元素多于此集合),则紧接此集合结束的数组中的元素将设置为null。
     * 3.如果此集合对其元素由其迭代器返回的顺序有任何保证,则此方法必须以相同的顺序返回元素。
     */
    <T> T[] toArray(T[] a);

    /**
     * 返回包含此集合中所有元素的数组,使用提供的生成器函数来分配返回的数组。
     * 说明:
     * 1.如果此集合对其元素由其迭代器返回的顺序有任何保证,则此方法必须以相同的顺序返回元素。
     * 2.返回的数组的运行时组件类型是由提供的生成器函数的返回类型确定的。
     * 3.像{@link #toArray()}一样,此方法充当基于数组和基于集合的API之间的桥梁。
     */
    default <T> T[] toArray(IntFunction<T[]> generator) {
        return toArray(generator.apply(0));
    }

    // Modification Operations(修改操作)

    /**
     * 向此集合中添加指定的元素。
     * 说明:
     * 1.如果此集合因调用而更改,则返回true。
     * 2.如果此集合不允许重复,并且已经包含指定的元素,则返回false。
     * 3.如果此集合由于其容量而拒绝添加指定的元素,则抛出 IllegalStateException。
     */
    boolean add(E e);

    /**
     * 移除此集合中的单个实例指定的元素(如果存在)。
     * 说明:
     * 1.如果此集合包含指定的元素,则返回true(或者等效地,如果此集合因调用而更改)。
     * 2.如果此集合包含多个指定的元素,则仅删除第一个。
     */
    boolean remove(Object o);


    // Bulk Operations(批量操作)

    /**
     * 返回true如果此集合包含指定集合中的所有元素。
     */
    boolean containsAll(Collection<?> c);

    /**
     * 添加指定集合中的所有元素到此集合。(即 this = this ∪ c)
     */
    boolean addAll(Collection<? extends E> c);

    /**
     * 移除此集合中包含在指定集合中的所有元素。
     */
    boolean removeAll(Collection<?> c);

    /**
     * 移除此集合中满足给定谓词的所有元素。迭代或谓词抛出的错误或运行时异常被中继给调用者。
     */
    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();


    // Comparison and hashing(比较和哈希)

    /**
     * 比较指定的对象与此集合是否相等。
     * 说明:当且仅当指定的对象也是一个集合,并且两个集合中包含相同的元素(时,返回true。
     */
    boolean equals(Object o);

    /**
     * {@code c1.hashCode()==c2.hashCode()}.
     * 返回此集合的哈希码值。
     * 说明:
     * 虽然Collection接口对Object.hashCode方法没有添加规定,但是程序员应该注意,
     * 任何重写Object.equals方法的类也必须重写Object.hashCode方法,以满足Object.hashCode方法的一般合同。
     */
    int hashCode();

    /**
     * 创建此集合中元素的Spliterator。
     */
    @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);
    }
}

2.1 Iterator

2.1.1 使用迭代器遍历集合

迭代是一种通用的获取集合元素的方式。在获取元素之前,需要先判断集合中是否有元素。如果有,就取出这个元素,并继续判断是否还有元素。如果有,就继续取出。重复这个过程直到集合中的所有元素都被取出。

想要遍历 Collection 集合,那么就要获取该集合迭代器完成迭代操作,在上面的源码中提供有一个 Iterator<E> iterator() 方法专门用来获取集合对应的迭代器,用来遍历集合中的元素。

java.util.Iterator 接口的源码如下:

public interface Iterator<E> {
    /**
     * 如果迭代器还有元素,返回true
     */
    boolean hasNext();

    /**
     * 返回迭代器的下一个元素
     */
    E next();

    /**
     * 移除迭代器最后一个元素
     * 说明:
     * 1. 这个方法是可选的,不是所有的迭代器都支持这个方法
     * 2. 这个方法只能在next方法之后调用一次,如果再次调用会抛出IllegalStateException异常
     * 3. 如果在调用next方法之前调用remove方法,也会抛出IllegalStateException异常
     * 4. 如果在调用remove方法之后,再次调用remove方法,也会抛出IllegalStateException异常
     */
    default void remove() {
        throw new UnsupportedOperationException("remove");
    }

    /**
     * 对剩余的每个元素执行给定的操作,直到所有元素都被处理或操作抛出异常。
     * 说明:如果指定了顺序,操作将按迭代顺序执行。
     */
    default void forEachRemaining(Consumer<? super E> action) {
        Objects.requireNonNull(action);
        while (hasNext())
            action.accept(next());
    }
}

下面通过一个案例来演示迭代器的使用方式:

public class IteratorTest {
    public static void main(String[] args) {
        // 创建集合
        Collection<String> collection = new ArrayList<>();

        // 添加元素
        collection.add("张三");
        collection.add("李四");
        collection.add("王五");

        // 从集合中获取迭代器
        Iterator<String> iterator = collection.iterator();
        // 遍历集合,条件为迭代器中还有元素
        while (iterator.hasNext()) {
            // 获取迭代器中的下一个元素
            String next = iterator.next();
            // 输出元素
            System.out.println(next);
        }
    }
}

程序执行结果如下:

张三
李四
王五

其底层迭代原理是通过一个指针(或称游标)来指向当前遍历到的元素,每次调用 next() 方法时,指针向后移动一位,并返回当前指向的元素。当指针遍历到集合末尾时,hasNext() 方法返回 false,表示遍历结束。

例如,ArrayList 的迭代器实现中,指针指向当前元素的下标,每次调用 next() 方法时,返回当前下标对应的元素,并将下标加一。而 LinkedList 的迭代器实现中,则需要保存一个指向当前节点的引用,每次调用 next() 方法时,返回当前节点的值,并将指针指向下一个节点。

2.1.2 使用迭代器删除集合元素

java.util.Iterator 中还提供了一个 void remove() 方法,既然 Collection 已经有 remove(Object o) 方法了,为什么 Iterator 迭代器还要提供删除方法呢?这是因为因为在 JDK1.8 之前 Collection 接口没有 removeIf(Predicate<? super E> filter) 方法,即无法根据条件进行删除。

例如要删除以下集合元素中的偶数:

public class IteratorTest02 {
    public static void main(String[] args) {
        // 创建集合
        Collection<Integer> collection = new ArrayList<>();

        // 添加元素
        collection.add(1);
        collection.add(2);
        collection.add(3);
        collection.add(4);

        // collection.remove(?) JDK 1.8 以前没有 removeIf 方法,没办法删除集合中的 “偶数” 元素

        // 方式一:通过迭代器删除集合中的偶数元素
        Iterator<Integer> iterator = collection.iterator();
        while (iterator.hasNext()) {
            // 获取迭代器中的下一个元素
            Integer next = iterator.next();
            // 判断元素是否为偶数
            if (next % 2 == 0) {
                // 删除偶数元素
                iterator.remove();
            }
        }
        
        // 方式二:通过增强for循环删除集合中的偶数元素(底层还是迭代器)
        for (Integer integer : collection) {
            if (integer % 2 == 0) {
                collection.remove(integer);
            }
        }
        
        // 方式三:通过 removeIf 方法删除集合中的偶数元素
        collection.removeIf(integer -> integer % 2 == 0);
    }
}

2.1.3 Iterator 迭代器的 fail-fast 机制

“fail-fast” 是 Java 集合框架中迭代器的一个特性。它主要指的是,当多个线程同时修改一个集合时,如果一个线程正在通过迭代器遍历集合,而另一个线程修改了集合(如添加、删除或修改元素),那么正在遍历的线程会立即抛出 ConcurrentModificationException 异常。

这种机制的设计原因是为了防止在遍历过程中由于集合的结构发生改变,导致结果的不可预见性。对于 fail-fast 系统,如果有错误发生,系统会立即对错误进行响应,而不是尝试在错误的状态下继续运行。这有助于避免在运行时发生更严重的错误,也更容易找出问题的原因。

要注意的是,fail-fast 机制并不能保证在所有情况下都能发现并防止并发修改,它只能在迭代过程中尽可能地检测出错误。另外,Java 的并发包 java.util.concurrent 中的一些集合类,如 CopyOnWriteArrayListConcurrentHashMap,则提供了 fail-safe 的迭代器,这种迭代器在遍历时不会抛出 ConcurrentModificationException 异常,因为它们在迭代时工作在集合的一个副本上,而不是直接在集合上。

下面基于 ArrayList 分析实现原理,可暂时跳过,有基础的可以直接继续阅读。

迭代器如何实现快速失败机制?以 ArrayList 为例,它继承了一个变量 protected transient int modCount = 0; 用于记录集合的结构修改次数。当进行新增、删除等操作时,modCount++ 将记录数量加1。在使用 Iterator 迭代器遍历集合时,创建集合迭代器的对象时,记录当前集合的 modCount,例如:int expectedModCount = modCount;。之后,每次使用迭代器的 next() 方法迭代元素时,都要检查 expectedModCount 是否等于当前的 modCount,如果不相等,则说明集合结构被修改了,可能是在使用迭代器的同时使用了集合的 add、remove 等方法,导致 modCount++,最终会抛出 ConcurrentModificationException 异常。

下面来看一看 ArrayList 中的 Itr 迭代器的具体实现:

/**
* 返回一个迭代器,按照正确的顺序遍历此列表中的元素。
*/
public Iterator<E> iterator() {
return new Itr();
}

/**
* 一个优化版本的AbstractList.Itr
*/
private class Itr implements Iterator<E> {
// 下一个元素的索引
int cursor;
// 最后一个元素的索引(如果没有,则为-1)
int lastRet = -1;
// 期望的修改次数(modCount 继承自 AbstractList),创建迭代器时记录
int expectedModCount = modCount;

// prevent creating a synthetic constructor
Itr() {
}

// 判断是否有下一个元素
public boolean hasNext() {
    // cursor < size 表示还有元素
    return cursor != size;
}

// 获取下一个元素
@SuppressWarnings("unchecked")
public E next() {
    // 检查是否有并发修改,即modCount是否等于expectedModCount
    checkForComodification();
    // 获取下一个元素的索引
    int i = cursor;
    // 如果下一个元素的索引大于等于元素的个数,抛出异常(因为没有元素了)
    if (i >= size)
        throw new NoSuchElementException();
    // 获取ArrayList的数组
    Object[] elementData = ArrayList.this.elementData;
    // 如果下一个元素的索引大于等于数组的长度,抛出异常(因为容量不够了)
    if (i >= elementData.length)
        throw new ConcurrentModificationException();
    // 将下一个元素的索引加1
    cursor = i + 1;
    // 返回下一个元素(其实就是elementData[i])
    return (E) elementData[lastRet = i];
}

::: warning

迭代器的快速失败行为不能得到保证。通常,在存在不同步的并发修改时,不可能对其进行坚决的保证。快速失败迭代器会尽最大努力抛出 ConcurrentModificationException 异常。因此,将依赖于此异常的程序编写是错误的。正确的方法是,使用迭代器的快速失败行为来检测 bug,而不应将其用于其他用途。

:::

2.2 Iterable

通过该接口的声名,我们也看到了 Collection 接口继承了 java.lang.Iterable 接口,因此它的实现类可以使用 for-each 循环进行遍历。

该接口源码如下:

/**
 * {@code for} statement (sometimes called the "for-each loop" statement).
 * 实现此接口允许对象成为增强的{@code for}语句(有时称为“for-each循环”语句)的目标。
 */
public interface Iterable<T> {
    /**
     * 返回一个迭代器,用于遍历此集合中的元素。
     */
    Iterator<T> iterator();

    /**
     * 对于{@code Iterable}的每个元素执行给定的操作,直到处理完所有元素或操作抛出异常。
     *
     * @param action 要对每个元素执行的操作
     * @throws NullPointerException 如果指定的操作为 null
     */
    default void forEach(Consumer<? super T> action) {
        // 进行非空判断
        Objects.requireNonNull(action);
        // 遍历集合
        for (T t : this) {
            // 对每个元素执行给定的操作
            action.accept(t);
        }
    }

    /**
     * 创建一个{@link Spliterator},用于遍历此{@code Iterable}描述的元素。
     * 说明:
     * 1. Spliterator是Java 8中新增的接口,它是支持并行遍历的迭代器。
     * 2. Spliterator是splitable iterator的简称,它是可分割迭代器。
     */
    default Spliterator<T> spliterator() {
        return Spliterators.spliteratorUnknownSize(iterator(), 0);
    }
}

可见其中的 Iterator<T> iterator() 方法就是上一节中所讲的内容,从源码中也不难看出,其实 for-each 循环底层其实就是使用 Iterator 迭代器来完成元素的遍历的。

下面是一个简单案例:

public class IterableTest {
    public static void main(String[] args) {
        // 创建集合
        Collection<String> collection = new ArrayList<>();

        // 添加元素
        collection.add("张三");
        collection.add("李四");
        collection.add("王五");
        
        // 使用增强for循环遍历集合
        for (String s : collection) {
            System.out.println(s);
        }
    }
}

通过查看编译后的 class 文件,我们便能证实上述结论:

2.3 List 集合

List 接口继承自 Collection 接口,它表示一个有序的集合,可以包含重复的元素List 接口定义了一些与索引相关的操作,如按索引访问元素、按索引插入元素、按索引删除元素等。

下面是一个简单的总结表格:

特性ArrayListVectorLinkedListStack
元素的顺序插入顺序插入顺序插入顺序LIFO(先进后出)
允许 null
线程安全
性能中等中等
基于动态数组动态数组双链表Vector
特殊功能双端操作出栈入栈

2.4 Set 集合

Set 接口继承自 Collection 接口,它表示一个不允许包含重复元素的集合。Set 接口定义了一些与集合操作相关的方法,如判断元素是否存在、添加元素、删除元素等。

下面是一个简单的总结表格:

特性HashSetLinkedHashSetTreeSet
元素的顺序无序插入顺序有序
允许 null
性能中等较低
基于HashMapLinkedHashMapTreeMap
特殊功能记录插入顺序排序

2.5 Queue

Queue 接口是 Java 中表示队列的一种抽象数据类型,它遵循**先进先出(FIFO)**的原则,提供了在队尾插入元素、在队头删除元素以及查看队头元素等操作,常用于实现消息传递、任务调度等场景。

下面是一个简单的总结表格:

特性 / 类型LinkedListArrayDequePriorityQueue
底层数据结构双向链表动态数组(环形)堆(Heap)
顺序FIFO(First-In-First-Out)FIFO(First-In-First-Out)按照自然排序或比较器排序
允许null元素
多线程安全
主要功能队列操作、栈操作、列表操作队列操作、栈操作优先级队列操作

3.Map 集合

Map 接口表示一组键值对的集合,每个键对应一个值。Map 接口中的键是唯一的,但值可以重复Map 接口定义了一些与键值对操作相关的方法,如根据键获取值、添加键值对、删除键值对等。

下面是一个简单的总结表格:

特性HashMapHashtableLinkedHashMapTreeMapProperties
Key 的顺序无序无序插入顺序(或访问顺序)有序(自然排序、定制排序)无序
允许 null
线程安全
性能较高中等
基于Hash表Hash表Hash表+链表红黑树Hash表
特殊功能记录插入顺序排序存储字符串

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/576817.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java 集合 - Set 接口

文章目录 1.概述2.HashSet3.LinkedHashSet4.TreeSet5.选择合适的 Set 实现6.总结 1.概述 Set 接口的定义非常简单。它本质上是一个 Collection&#xff0c;但是要求该集合不能有重复的元素。换句话说&#xff0c;如果尝试将一个元素添加到 Set 中&#xff0c;而该元素已经存在…

FPGA实现ESP8266驱动且进行数据包收发

一. 简介 本次将使用正点原子的ESP8266 WIFI模块&#xff0c;来实现PC与FPGA之间的TCP通讯&#xff0c;其中ESP8266与FPGA之间的接口是UART。 二. 正点原子的ESP8266 WIFI模块介绍 模块实物图如下&#xff0c;到手就可以使用了&#xff0c;RST和IO_0两个IO口不接或者接高电平…

C++布隆过滤器和哈西切分

文章目录 一、布隆过滤器的提出二、布隆过滤器的概念三、布隆过滤器的实现布隆过滤器的插入布隆过滤器的判断在不在布隆过滤器的删除布隆过滤器的优点布隆过滤器的缺点 四、布隆过滤器的应用场景五、布隆过滤器的扩展[面试题]六、哈西切分 一、布隆过滤器的提出 我们在使用新闻…

GO 语言核心编程-全文版

第 1 章 1.1Golang的学习方向 Go语言&#xff0c;我们可以简单的写成Golang. Golang开山篇 1.2Golang的应用领域 1.2.1区块链的应用开发 1.2.2后台的服务应用 1.2.3云计算/云服务后台应用 1.3学习方法的介绍 1.4讲课的方式的说明 努力做到通俗易懂注重Go语言体系&#xff…

K8s之零故障升级Pod健康探测详解

文章目录 一、Pod健康探测介绍1、三种容器探测方法2、常用三种探测探针3、探针相关属性说明 二、探测案例1、Pod启动探测案例-startupProbe2、Pod存活探测案例-livenessProbe3、Pod就绪探测案例-readinessProbe4、启动、存活、就绪探测混合使用案例 三、总结 一、Pod健康探测介…

【MySQL新手到通关】第五章 多表查询

文章目录 1. 笛卡尔积1.1 避免笛卡尔积1.2 笛卡尔积&#xff08;或交叉连接&#xff09;的理解1.3 案例分析与问题解决笛卡尔积的错误会在下面条件下产生&#xff1a; 2. 多表查询分类讲解2.1 多表联查分类方式1&#xff1a;2.2 多表联查分类方式2&#xff1a;2.3 多表联查分类…

Eclipse教程 Ⅴ

Eclipse 创建 Java 类 打开新建 Java 类向导 你可以使用新建 Java 类向导来创建 Java 类&#xff0c;可以通过以下途径打开 Java 类向导&#xff1a; 点击 "File" 菜单并选择 New > Class在 Package Explorer 窗口中右击鼠标并选择 New > Class点击类的下拉…

c++输入输出文件操作stream

系列文章目录 C IO库 文章目录 系列文章目录前言一、文件IO概述coutcin其他istream类方法 文件输入和输出内核格式化总结 前言 一、文件IO 概述 c程序把输入和输出看作字节流。输入时&#xff0c;程序从输入流中抽取字节&#xff1a;输出时&#xff0c;程序将字节流插入到输…

springboot+ssm+java校园二手物品交易系统vxkyj

样需要经过市场调研&#xff0c;需求分析&#xff0c;概要设计&#xff0c;详细设计&#xff0c;编码&#xff0c;测试这些步骤&#xff0c;基于Java语言、Jsp技术设计并实现了校园二手物品交易系统。系统主要包括个人中心、商家管理、用户管理、商品分类管理、商品信息管理、商…

中间件SOME/IP简述

SOME/IP SOME/IP 不是广义上的中间件&#xff0c;严格的来讲它是一种通信协议&#xff0c;但中间件这个概念太模糊了&#xff0c;所以我们也一般称 SOME/IP 为通信中间件。 SOME/IP 全称是 Scalable service-Oriented MiddlewarE over IP。也就是基于 IP 协议的面向服务的可扩…

调用华为API实现身份证识别

调用华为API实现身份证识别 1、作者介绍2、调用华为API实现身份证识别2.1 算法介绍2.1.1OCR简介2.1.2身份证识别原理2.1.3身份证识别应用场景 2.2 调用华为API流程 3、代码实现3.1安装相关的包3.2代码复现3.3实验结果 1、作者介绍 雷千龙&#xff0c;男&#xff0c;西安工程大…

Spring Boot如何实现配置文件的自动加载和刷新?

Spring Boot如何实现配置文件的自动加载和刷新&#xff1f; 在使用Spring Boot开发应用程序时&#xff0c;配置文件是非常重要的组成部分。在不同的环境中&#xff0c;我们可能需要使用不同的配置文件&#xff0c;例如在开发、测试和生产环境中使用不同的配置文件。而且&#…

功能测试转到自动化测试,我的测试之路“狂飙”~20k...

前言 Python自动化测试&#xff1a;Python自动化测试&#xff0c;7天练完这60个实战项目&#xff0c;年薪过35w。 手动功能测试人员应该权衡测试自动化相对于功能测试的好处&#xff0c;并且即可开始行动。现在随着测试行业的发展&#xff0c;自动化测试已经成为每个测试人的标…

nodejs+vue大学生招聘网站应聘系统设计与实现5b14b

目前&#xff0c;伴随着Internet技术的日益成熟&#xff0c;互联网需要提供更多的服务&#xff0c;发达国家已形成以信息技术为核心&#xff0c;招聘网站支撑的现代化招聘公司技术格局。这便是今天为大家所熟悉的管理信息系统,网络发展为招聘网站实现信息化、自动化、智能化和集…

牛客小白月赛73DE

问题很好转化&#xff0c;但是对区间的处理没把握好&#xff0c;一直在纠结怎么o&#xff08;n&#xff09; 一开始想到二分了&#xff0c;但是没细想&#xff0c;结果看了讲解发现&#xff0c;其实就是一个前缀数组上对区间的查询的操作&#xff0c;以后再遇到此类问题直接向…

Git提交提交代码报错 Push failed unable to access

目录 场景 环境&#xff1a; Git配置 场景 Push failed unable to access https://github.com/1790753131/remotRepository3.git/: Failed to connect to github.com port 443 after 21114 ms: Couldnt connect to server Push failed unable to ac…

计算节点与存储设备是如何连接的?

本文是《数据存储通识课》合集的一部分,本合集希望通过一系列文章科普数据存储相关技术内容。同时,本系列文章不仅仅是科普,还会进行有深度解析,理论结合实现,从代码实现层面进行剖析。欢迎关注“数据存储张”,老张是深耕存储十几载,就业于存储No1公司的资深工程师。 无…

Keil 5 MDK 发律师函警告了,如何用STCubeIDE开发标准库的程序(STM32F103C8T6为例)

用STCubeIDE进行标准库开发 1、CubeIDE介绍 https://www.stmcu.com.cn/ecosystem/Cube/STM32CubeIDE 2、CubeIDE下载 点击上面的链接&#xff0c;登录即可下载 3、搭建Demo工程 新建一个工作空间 创建一个工程 选择芯片-STM32F103C8T6 填写工程信息 添加标准库到工程 标…

【数据结构与算法】图论及其相关算法

文章目录 图的基本介绍图的表示方式邻接矩阵邻接表 图的深度优先遍历(DFS)概述实现步骤代码实现 图的广度优先遍历(BFS)概述实现步骤代码实现 图的常用代码汇总最小生成树算法普里姆&#xff08;Prim&#xff09;算法算法实践 克鲁斯卡尔&#xff08;Kruskal&#xff09;算法并…

西南交通大学智能监测 培训课程练习2

2023.05.27培训 task1&#xff1a;spring、springboot task2&#xff1a;mybatis 目录 一、使用IDEA创建工程 1.1新建 ​编辑 1.2选择Maven 1.3创建包 二、添加相关依赖 2.1添加依赖 2.2更新Maven 三、配置application.yaml文件 四、相关注解的使用和理解 4.1Componen…