Java集合类之Collection

news2024/9/20 12:36:58

文章目录

  • 1 准备部分
    • 1.1 数据结构
      • 1.1.1 数组
      • 1.1.2 链表
    • 1.2 集合是什么
  • 2 Collection
    • 2.1 特点
    • 2.2 常用API
    • 2.3 遍历Collection的方法
      • 2.3.1 toArray方法
      • 2.2.2 iterator方法
      • 2.3.3 foreach
      • 2.3.4 总结
  • 3 List 接口
    • 3.1 内容提要
    • 3.2 特点
    • 3.3 List的API
      • 3.3.1 listIterator方法
      • 3.3.4 subList方法
    • 3.4 ArrayList
      • 3.4.1 特点
      • 3.4.2 构造方法
      • 3.4.3 ArrayList的API
    • 3.5 LinkedList
      • 3.5.1 特点
      • 3.5.2 LinkedList的构造方法
      • 3.5.3 LinkedList的API
    • 3.6 Vector
    • 3.7 Stack
  • 4 Queue
    • 4.1 内容提要
    • 4.2 特点
    • 4.3 API
    • 4.4 Deque
      • 4.4.1 特点
      • 4.4.2 API
    • 4.5 ArrayDeque
      • 4.5.1 特点
      • 4.5.2 构造方法
    • 4.6 BlockingQueue
  • 5 Set
    • 5.1 内容提要
    • 5.1 特点
    • 5.2 Set的API
    • 5.3 HashSet
      • 5.3.1 HashSet的特点
      • 5.3.2 HashSet的构造方法
      • 5.3.3 HashSet的API
    • 5.4 LinkedHashSet
      • 5.4.1 LinkedHashSet的特点
      • 5.4.2 LinkedHashSet的构造方法
      • 5.4.3 LinkedHashSet的API
    • 5.5 TreeSet
      • 5.5.2 TreeSet的特点
      • 5.5.3 TreeSet的构造方法
      • 5.5.4 TreeSet的API

1 准备部分

1.1 数据结构

  • 数据结构:数据的组织方式, 数据+结构
  • 常见的数据结构:
    • 集合: 一堆无序的数据
    • 线性表: 描述的是一个有序序列, 在这有序序列中除了头和尾数据以外, 每一个数据有唯一的前驱和后继
    • 操作受限的线性表: 栈和队列。都是线性表。 只允许在特定的位置进出数据。
    • 树: 一对多的关系
      • 一个节点,连接多个节点。二叉树: 一个节点,最多连接两个节点
    • 图: 多对多的关系

1.1.1 数组

数组就是一片连续的内存空间,且存储的类型都是一致的。这就说明什么?

int[] numbers = new int[10]; 类型一致说明空间大小一致。

说明每一个格子的大小是固定的。我们只要知道头一个地址,后方的地址都可以算出来

Q1: 数组我们都很熟悉,那你理解的数组是什么样的呢?它的最主要特点是什么呢?
A1:数组是在内存上连续存储, 所以可以随机访问;
对应数组下标的物理地址 = 数组首地址 + 下标 * 每一个内存单元大小

Q2: 为什么数组的效率比链表高?
因为数组是连续存储可以做到随机访问, 但是链表是非连续存储不能做到随机访问

1.1.2 链表

链表是一个线型的。

基础的结构是这样的。

// data可以用  泛型。 
// 泛型的主要目的:  保证数据类型的可变性,比如下一次要存储Integer了。如果现在写成String,就不行
public class Node<T> {
    T data;
    Node<T> next;
}

请添加图片描述

1.2 集合是什么

在Java中,指的就是存放数据的容器,是一个载体,可以一次容纳多个对象。请添加图片描述
Java中的集合类分为两大类:一类是实现了Collection接口的类,另一类是实现了Map接口的类。

Collection:先理解为一个袋子,往里面装数据。有各种各样的子实现。

在Java中,Collection是一个接口,它是所有集合类的顶层接口。它定义了一组通用的方法,用于操作集合中的元素。

Java中的Collection接口定义了一些常用的方法,例如add()、remove()、contains()等,还有用于获取集合大小、判断集合是否为空、清空集合等方法。Java中的集合类包括List、Set和Queue等,它们都是实现了Collection接口的子接口。

Collection是最基本的集合接口,一个 Collection 代表一组 Object,即 Collection 的元素, Java不提供直接继承自Collection的类,只提供继承于的子接口(如List和set)。

  • 比如存储一组学生
  • 比如存储一组手机号码

主要存储的就是单列数据。比如一个学生,一个老师。这种都叫单列数据。

Map:存储key-value结构的数据。key-value结构:就是可以根据一个key,找到一个对应的value。

Map 接口存储一组键值对象,提供key(键)到value(值)的映射。

  • 比如根据手机号,快速获取到姓名

  • 比如根据身份证号,快速获取到人的信息

2 Collection

2.1 特点

  1. Collection是顶级接口,用描述数据存储的接口.
  2. Collection的一些子实现有序,一些无序
  3. 一些子实现允许存储重复的数据,一些不允许
  4. 一些子实现允许存储null,一些不允许

传统的三件套。 数据存储是否有序。

  • 什么叫有序,什么叫无序?

指的是存储和读取的顺序,比如存入进去的是 1 2 3 4 9。读取出来的是1 2 3 4 9。或者 9 4 3 2 1 均称为有序。存进去的顺序和读取出来的顺序完全一致或者完全相反。

2.2 常用API

//    ---------------------------------增删改查方法---------------------------------
// 需要熟练使用,清楚特点。 
//    boolean add(E e): 添加一个元素进入Collection
//    boolean addAll(Collection<? extends E> c): 添加一个Collection进目标Collection
//    boolean remove(Object o): 删除元素, 只删除第一个出现的(如果存在多个)
//    boolean removeAll(Collection<?> c): 删除Collection中的所有存在的元素,会全部删除,如果存在多个
//    boolean contains(Object o): 判断是否存在指定元素
//    boolean containsAll(Collection<?> c): 判断给定的collection中是否全部存在于目标Collection
//    boolean retainAll(Collection<?> c): 将原有collection只保留传入的collection。

//    ---------------------------------特殊方法---------------------------------
//    void clear(): 清空collection
//    boolean equals(Object o) : 判断是否相等
//    int hashCode(): 计算hashCode
//    boolean isEmpty(): 是否为空
//    int size(): collection里面的元素个数
//
//    ---------------------------------方便遍历方法---------------------------------
//    Object[] toArray(): 将collection转成一个数组,方便遍历
//    <T> T[] toArray(T[] a):类似,只是传入了一个数组
//    Iterator<E> iterator():返回一个迭代器

遍历:对一个集合中的元素,按照一定的顺序,访问且仅访问一遍。对集合的元素,挨个访问

  • 添加方法

    boolean add(E e): 添加一个元素进入Collection
    
    boolean addAll(Collection<? extends E> c): 添加一个Collection进目标Collection
    

example

@Test
public void addDemo1() {
    // Collection的add方法
    // ArrayList是Collection接口的一个子实现。ArrayList的底层是一个数组。
    Collection<String> collection = new ArrayList<>();

    // 往Collection中添加了两个数据。  zs   景天叔叔
    collection.add("zs");
    collection.add("景天叔叔");

    // ArrayList重写了toString()
    System.out.println(collection); // [zs, 景天叔叔]
}

@Test
public void addAllDemo1() {
    Collection<Integer> c1 = new ArrayList<>();
    c1.add(10);
    c1.add(6);
    c1.add(2);
    c1.add(8);

    Collection<Integer> c2 = new ArrayList<>();
    // 将c1中的所有元素 添加到c2
    // 是将数据添加到c2中
    c2.addAll(c1);

    System.out.println(c2);
}
  • 删除方法

    boolean remove(Object o): 删除元素, 只删除第一个出现的(如果存在多个)
      
    boolean removeAll(Collection<?> c): 删除Collection中的所有存在的元素,会全部删除,如果存在多个
    
@Test
public void removeDemo1() {
    Collection<String> collection = new ArrayList<>();

    collection.add("zs");
    collection.add("ls");
    collection.add("wu");
    collection.add("zs");
    collection.add("ls");

    // 现在collection中有 五个元素.
    System.out.println(collection); // [zs, ls, wu, zs, ls]

    // 删除 zs;  删除第一个 zs。有多个 zs,只会删除第一个
    collection.remove("zs");
    System.out.println(collection); // [ls, wu, zs, ls]
}

@Test
public void removeAllDemo1() {
    Collection<String> c1 = new ArrayList<>();
    c1.add("zs");
    c1.add("ls");
    c1.add("wu");
    c1.add("zs");
    c1.add("ls");

    Collection<String> c2 = new ArrayList<>();
    c2.add("zs");

    // 会从c1中删除所有的c2,无论c1中有多少个元素
    c1.removeAll(c2);
    System.out.println(c1); //[ls, wu, ls]
}
  • 查询方法

    boolean contains(Object o): 判断是否存在指定元素
      
    boolean containsAll(Collection<?> c): 判断给定的collection中是否全部存在于目标Collection
    
@Test
public void containsDemo1() {
    Collection<String> collection = new ArrayList<>();
    collection.add("zs");
    collection.add("ls");
    collection.add("wu");

    // 判断 Collection中,是否包含元素 “zs”; 如果包含,返回true;否则返回false
    boolean contains = collection.contains("zs");
    System.out.println(contains); // true

    boolean contains1 = collection.contains("景天叔叔");
    System.out.println(contains1); // false
}

@Test
public void containsAllDemo1() {
    Collection<String> collection = new ArrayList<>();
    collection.add("zs");
    collection.add("ls");
    collection.add("wu");
    collection.add("zl");

    // 新建一个Collection,里面的元素是 zs  zhou
    // Arrays.asList 是一个创建集合的方法。但是需要注意,创建出来的集合,不能添加和删除数据
    Collection<String> collection1= Arrays.asList("zs", "zhou");

    boolean containsAll = collection.containsAll(collection1);
    System.out.println(containsAll); // 判断 collection中 是否包含 collection1里面的所有元素

    Collection<String> collection2= Arrays.asList("zs");
    boolean containsAll1 = collection.containsAll(collection2); // 判断 collection中 是否包含
    // collection2里面的所有元素
    System.out.println(containsAll1);
}

2.3 遍历Collection的方法

2.3.1 toArray方法

使用toArray()方法将Collection转成Array数组,然后使用遍历数组的方法来遍历Collection。

无参方法

就是直接拷贝一份数据,创建一个新的数组。

请添加图片描述

// 底层是数组的实现
class ArrayList{
    //elementData: 存储数据的数组 
    Object[] elementData;

    // 数组列表的大小(它包含的元素数)
    int size;
}

有参方法

请添加图片描述

// ArrayList底层是数组

class ArrayList{
    // elementData就是底层用来存储数据的数组
    Object[] elementData;
    
    // size : ArrayList底层实际存储的数据的长度。
    // 比如最开始 初始化 长度10;  elementData = new Object[10];
    // size = 0;    size=1; 
    int size;
    
    
    //是ArrayList的toArray实现
    //  a = new String[3]
    // ArrayList里面,实际存了3个元素
    public <T> T[] toArray(T[] a) {
        // a.length(3)   <   size(3)
        if (a.length < size)
            // 如果你传入的数组长度,小于集合的长度。  这时候,会直接 复制底层存储的数据,只使用类型。
            return (T[]) Arrays.copyOf(elementData, size, a.getClass());
        
        // 只要走到这一行。说明  a.length >= size 。 传进来的数组长度,大于等于  元素个数
        // arraycopy 就是把一个数组 copy。 
        // 把elementData的所有数据 拷贝到  a(传进来的数组)
        System.arraycopy(elementData, 0, a, 0, size);
        
        // 传入的数组长度,大于size(实际存储的数据长度)
        if (a.length > size)
            // 直接把elementData后面的位置,赋了null。
            a[size] = null;
        return a;
    }
}
// 这是系统提供的一个数组拷贝方法。  --》 把一个数组复制到另外一个数组
// src 源数组
// srcPos 从什么地址开始复制(starting position in the source array.)
// dest 目标数组
// destPos 粘贴到的下标位置
// length 复制的长度(the number of array elements to be copied.)
public static native void arraycopy(Object src, int  srcPos, Object dest, int destPos, int length);
// a是什么东西?   是我们放进来的数组
// elementData   是ArrayList底层的数组,  size  是元素的个数
public <T> T[] toArray(T[] a) {
    
    // a.length  (传入的数组长度)   <   元素个数
    if (a.length < size) {
        // 如果传入的数组,长度不够。 我直接复制一下,只使用你传入的数组类型。 
        return (T[]) Arrays.copyOf(elementData, size, a.getClass());
    }
    
    // 将elementData的数据拷贝到  a 里面。  拷贝size长度
    System.arraycopy(elementData, 0, a, 0, size);
   
    if (a.length > size)
        // 把它赋值为null
        a[size] = null;
    return a;
}

有参构造方法

传入的数组长度与集合长度的对比。

1.如果数组长度小于集合长度。只会使用传入的数组的类型,不会使用这个数组
2.如果数组长度等于集合长度,会直接使用这个数组
3.如果数组长度大于集合长度,也会使用这个数组,并且将数组的index=length位置的元素设置为null

直接使用toArray这个有什么弊端?

toArray是将原Collection直接copy了一份。

对于遍历来说,一般主要是干什么?一般就是想统计一下符合条件的。

  • 耗费时间,需要将原有collection全部拷贝一遍
  • 耗费空间,两倍的collection占有空间
  • 后续使用完毕,还需要gc

我们一般遍历一个集合,有时候是想统计个数,有时候是想找出符合条件的,如果每次都复制一次,不仅耗费时间,而且使用完后,还需要gc

在处理大量数据时,使用toArray方法需要谨慎考虑,因为它会将集合中的所有元素都复制到新的数组中,占用大量的内存空间。如果数据量非常大,可能会导致内存溢出的风险。

在处理大量数据时,建议使用迭代器进行遍历,而不是将集合转换为数组。迭代器可以逐个访问集合中的元素,并且不需要将所有元素都复制到新的数组中,从而减少内存的占用。

2.2.2 iterator方法

迭代器(iterator),有时又称光标(cursor)是程序设计的软件设计模式,可在容器对象(container,例如链表或数组)上遍历的接口,设计人员无需关心容器对象的内存分配的实现细节。

是用来遍历这个容器对象所有数据的接口。

迭代器相当于只保留了一个标识,标识我可以怎么拿到这个数据,不copy数据。所有操作的数据都是针对的原有的Collection。

好处是什么?

Iterator是个接口,接口只定义规范,我们获取到了iterator,就可以使用这个对象对数据进行遍历。把接口与实现隔离。

//    boolean hasNext(): 是否有下一个元素
//    E next(): 获取下一个元素
//    void remove(): 删除刚刚遍历过的元素

比如Collection底层有的是数组,有的是链表。

数组的Iterator里面维护的是下标

链表的Iterator里面维护的是指针。

所有的具体实现都交给具体的子类。接口只定义一个规范。

请添加图片描述
请添加图片描述

迭代器是个游标,它遍历的时候,被别的线程,把原集合中加了几个元素,减了几个元素,那这时候这次遍历的意义大吗?

JDK采用了存储一个值的方式,去保证在迭代器使用过程中,原有的集合不被修改(当前线程、其他线程)。

在Collection内部,有一个modCount,用来标识结构变化的次数(get/contains 这种查询不叫结构变化)

生成迭代器的时候,存储这个expectedModCount=modCount,在调用 next remove时候,会检查

使用迭代器过程中,如果原结构发生了变化,会报并发修改异常(ConcurrentModificationException)

如果见到了,需要检查,是不是在迭代器使用过程中,修改了原有集合。

迭代器怎样使用

//    boolean hasNext(): 是否有下一个元素
//    E next(): 获取下一个元素
//    void remove(): 删除刚刚遍历过的元素

    @Test
    public void iteratorDemo1() {
        Collection<String> collection = new ArrayList<>();
        collection.add("zs");
        collection.add("ls");
        collection.add("wu");

        // 现有collection里面有 三个元素。 [zs, ls, wu]
        System.out.println(collection);

        // 调用iterator()方法,生成一个迭代器。迭代器本身不存储数据。所以它操作的数据都是原有集合的
        Iterator<String> iterator = collection.iterator();

        // 现在的迭代器和数据 示意图:
        //  数据:   [     zs           ls           wu   ]
        //  迭代器位置: |

        // 迭代器后是否有元素。
        System.out.println(iterator.hasNext());

        // 将指针往后挪动,并返回刚刚经过的元素
        String next = iterator.next();
        System.out.println(next);
        
        // 现在的迭代器和数据 示意图:
        //  数据:   [     zs           ls           wu   ]
        //  迭代器位置: ------- |
    }

怎么解决会出现并发修改异常问题?

不要在迭代器迭代过程中,去修改原集合。要不就是在迭代器生成之前,要不就在迭代器使用完成之后,再去修改原有集合。

    Collection<String> collection = new ArrayList<>();

    collection.add("zs");
    collection.add("ls");
    collection.add("wu");
	collection.add("zs");

	// ========================= 这个位置之前叫做迭代器生成之前 =========================
    Iterator<String> iterator = collection.iterator();

    while (iterator.hasNext()) {
       // 不能边使用,边修改原有集合。
      // collection.remove("zs");

      String next = iterator.next();
      System.out.println(next);
    }

	// ========================= 这个位置之前叫做迭代器生成之后 =========================

2.3.3 foreach

工作中一般使用foreach居多。底层也是iterator。

所以需要注意,在foreach中,不要去改变Collection的结构。

Collection<String> collection = new ArrayList<>();

collection.add("zs");
collection.add("ls");
for (String s : collection) {
    System.out.println(s);
}

2.3.4 总结

怎样去遍历Collection接口

  • 使用 iterator
  • 使用 foreach
  • toArray
// 使用 iterator  
Collection<String> collection = new ArrayList<>();

collection.add("zs");
collection.add("ls");
collection.add("wu");

// 使用的时候,先生成一个迭代器
Iterator<String> iterator = collection.iterator();

while (iterator.hasNext()) {
    String next = iterator.next();
    System.out.println(next);
}


// 使用foreach
for (String next : collection) {
    System.out.println(next);
}

String[] strings = collection.toArray(new String[0]);
// 数组的foreach 底层就是fori
for (String string : strings) {
    System.out.println(string);
}

// 三种 迭代器,foreach,toArray

如何删除Collection中所有的zs和ls数据?

// 遍历,删除
// 1.方式1  
// 创建一个新的集合;
// 遍历原有集合。
//		判断。是否 zs  ls ; 是的话,添加到新集合
// removeAll()
// 遍历新集合 --》  remove()

// 2.方式2
// 迭代器
// 创建一个迭代器。遍历这个迭代器(while hasNext() next() )
// 判断, 是不是zs  或者 ls 。 是的话,remove  iterator.remove()
// 切记,不能通过原有集合的remove()


// 使用一个集合类,把所有的zs 和ls 都存起来。然后遍历集合类,再调用原有集合类的remove方法

// 使用一个集合类,存储 zs  ls  调用removeAll方法

// 使用迭代器的删除方法

遍历Collection接口的时候,有什么需要注意的事项

注意并发修改异常。出现的原因,以及解决的办法。

3 List 接口

3.1 内容提要

  • List接口的特点,及其使用场景(存储数据有序,允许存储重复元素,允许存储null。)
  • List接口特殊的方法。(相对Collection,新增了很多下标的操作。 add(int index, E e) remove(int index), set(int index, E e ), get(index) indexOf lastIndexOf)
  • List接口的特有遍历方式。(iterator foreach toArray) fori
  • ArrayList的底层结构。初始化容量,扩容策略.(数组, 10, 1.5倍)
  • LinkedList的底层结构(双向链表)。
  • (面试)Vector和ArrayList的区别?为什么被替换掉
  • Stack是什么?在Java中想使用栈,应该怎么创建(Deque)

一定要注意: 面试官如果和你强调 ArrayList和LinkedList的区别.你一定要知道,他是在问你数组和链表的区别。

使用的时候,一般的使用方式

// 一般这样用
List<String> list = new ArrayList<>();

// 不会这样用
Collection<String> collection = new ArrayList<>();
ArrayList<String> collection = new ArrayList<>();

3.2 特点

  1. List是Collection的子接口。(父子继承关系,想对原有接口进行增强。)
  2. 数据结构表现为线性表。
  3. 存储数据有序。(存储进去的顺序和读取出来的顺序。 完全一致或者完全相反)
  4. 可以存储重复元素
  5. 可以存储null

线性表

线性表,全名为线性存储结构。使用线性表存储数据的方式可以这样理解,即“把所有数据用一根线儿串起来,再存储到物理空间中”。

线性表是一对一的数据结构。一个数据元素,除了第一个元素和最后一个元素,都只有一个前驱一个后继。

3.3 List的API

ListCollection的子接口。所有肯定有Collection的所有方法。

Collection的API我们已经学习过,所以直接学习List所特有的。

//  List是线性表的实现,所以它相对于Collection增加了很多下标相关的API
//    void add(int index, E element): 在指定位置添加元素。list添加的位置,只能在[0,length之间]
//    boolean addAll(int index, Collection<? extends E> c): 在指定位置添加一个Collection的所有元素
//    E remove(int index):删除指定下标的元素,只能删除下标的位置[0, lenth-1]。返回的是删除的元素
//    E set(int index, E element): 设置指定下标的元素为element.   array[index] = element; 
//    E get(int index): 获取指定下标元素
//    int indexOf(Object o): 获取元素首次出现的下标。如果元素不存在。 返回的是-1
//    int lastIndexOf(Object o): 获取元素最后一次出现的下标。

//    ListIterator<E> listIterator(): 
//    ListIterator<E> listIterator(int index)
//    List<E> subList(int fromIndex, int toIndex)

3.3.1 listIterator方法

返回一个ListIterator的对象。这个与迭代器类似,只是可以前后移动,可以返回index。

  • 有参构造,返回的迭代器对象,调用next返回的是指定下标的元素。所以传入的index应该在什么范围?

[0,length]

public interface ListIterator<E> extends Iterator<E>
        //boolean hasNext() : 判断后面是否还有元素可以遍历
        //E next()    : 向后遍历
        //void remove()   : 删除刚刚遍历的数据

        //boolean hasPrevious()    : 向前是否可以遍历
        //E previous() : 向前遍历

        //int nextIndex() : 向后遍历的数据的下标
        //int previousIndex() :  向前遍历的下标
        //void add(E e) : 添加一个数据到当前遍历位置,并且把指针往后挪一下
        //void set(E e) : 修改刚刚遍历过的元素位置

3.3.4 subList方法

看名字,会误认为是: 子/截取 生成一个新的List

但是其实是,返回列表中指定的 fromIndex(包括 )和 toIndex(不包括)之间的部分视图

视图:只是原表的一个映射,并没有把数据复制一份。它和iterator很相似,只是维护了几个标记。操作subList产生的对象,会影响原来的对象。

注意:它也会存在并发修改的问题。当生成了subList之后,如果再修改原集合。再访问subList的对象,会报错。

注意一些坑:

  • 注意oom,因为subList只是一个视图,它保留了原始的数组。所以如果错误估计,可能会oom
    请添加图片描述
怎么出现oom,设置小堆内存。切记不要直接跑,可能会导致电脑死机
IDEA中,可以针对当前代码,设置最大的运行内存
Edit Configurations --> Add VM options -->
-Xmx500m -Xms500m
    
  -Xmx500m 最大堆内存 500m
  -Xms500m 初始堆内存 
  • 注意并发修改异常

3.4 ArrayList

写代码的时候,Collection、List、ArrayList采用哪种方式写得多

Collection<String> collection = new ArrayList<>();  // 第一种,尽量不要使用。因为Collection和ArrayList还隔了一层。 
List<String> list = new ArrayList<>();   // 在工作过程中,最常用的一种写法。
ArrayList<String> list = new ArrayList<>();  // 也有人用。但不建议。 

ArrayList是Java集合框架中的一种,它实现了List接口,可以动态地添加、删除和修改元素。与传统的数组不同,ArrayList的大小可以根据需要自动增长,因此非常适用于需要频繁添加或删除元素的场景。

ArrayList内部实际上是一个动态数组,它可以存储任意类型的对象。当创建一个ArrayList时,它的初始容量是10个元素,当元素数量超过容量时,ArrayList会自动增加容量,以便能够容纳更多的元素。

ArrayList提供了一系列方法,可以方便地操作其中的元素,例如add()方法可以在末尾添加元素,remove()方法可以删除指定位置的元素,get()方法可以获取指定位置的元素,set()方法可以修改指定位置的元素等等。

3.4.1 特点

  1. ArrayList是List的实现
  2. ArrayList数据结构表现为线性表
  3. 底层结构是数组
  4. 存储元素,有序
  5. 可以存储重复元素
  6. 可以存储null

3.4.2 构造方法

怎么创建这个类的。

ArrayList() 构造一个初始容量为 10 的空列表。
ArrayList(Collection<? extends E> c):构造一个包含指定 collection 的元素的列表,这些元素是按照该 collection 的迭代器返回它们的顺序排列的。
ArrayList(int initialCapacity):构造一个具有指定初始容量的空列表。 

// List是接口,接口没有构造方法

3.4.3 ArrayList的API

// 返回此 ArrayList 实例的浅表副本
 Object clone()

// 如有必要,增加此 ArrayList 实例的容量,以确保它至少能够容纳最小容量参数所指定的元素数
void ensureCapacity(int minCapacity)

// 将此 ArrayList 实例的容量调整为列表的当前大小
void trimToSize()

3.5 LinkedList

LinkedList是Java集合框架中的一种,它实现了List和Deque接口,是一个双向链表。与ArrayList不同的是,LinkedList在内部并不使用数组来存储元素,而是使用一个链表来存储元素,因此可以高效地进行插入和删除操作。

LinkedList的每个节点都包含了一个指向前一个节点和后一个节点的指针,因此可以方便地进行双向遍历。在向LinkedList中添加元素时,只需要创建一个新的节点,并将其插入到链表中即可。同样,在删除元素时,只需要将该元素的前后节点的指针重新指向即可,不需要像ArrayList一样将其后面的元素全部向前移动。

LinkedList提供了一系列方法,可以方便地操作其中的元素。例如add()方法可以在指定位置添加元素,remove()方法可以删除指定位置的元素,get()方法可以获取指定位置的元素,set()方法可以修改指定位置的元素等等。除此之外,LinkedList还提供了一些特殊的方法,例如offer()和poll()方法用于在链表的首尾添加和删除元素,push()和pop()方法用于在链表的首部添加和删除元素等等。

3.5.1 特点

  1. LinkedList是List的子实现
  2. LinkedList数据结构表现为线性表
  3. LinkedList底层结构是双向链表
  4. 存储元素有序
  5. 可以存储null
  6. 可以存储重复元素

3.5.2 LinkedList的构造方法

//  构造一个空列表
LinkedList() 

//构造一个包含指定 collection 中的元素的列表,这些元素按其 collection 的迭代器返回的顺序排列。 
LinkedList(Collection<? extends E> c) 

3.5.3 LinkedList的API

LinkedList里面的API分两类。第一类,是List接口继承过来的; 第二类,是Deque接口。

队列:先进先出,从队尾进,队头出。

双端队列:队头和队尾都可以进出。

栈:先进后出。

//        来自Collection
//        来自List的
//    ----------------------------来自普通队列
//    boolean offer (E e)
//    将指定元素添加到此列表的末尾(最后一个元素)。
//    E peek () 获取但不移除此列表的头(第一个元素)。
//    E poll () 获取并移除此列表的头(第一个元素)

//    ---------------------------- 作为Stack的
//        E pop(): 从此列表所表示的堆栈处弹出一个元素。
//        void push(E e): 将元素推入此列表所表示的堆栈。

//    ---------------------------- 作为双端队列
//    boolean offerFirst (E e)
//    在此列表的开头插入指定的元素。
//    boolean offerLast (E e)
//    在此列表末尾插入指定的元素。
//
//    E peekFirst () 获取但不移除此列表的第一个元素;如果此列表为空,则返回 null。
//    E peekLast () 获取但不移除此列表的最后一个元素;如果此列表为空,则返回 null。
//
//    E pollFirst () 获取并移除此列表的第一个元素;如果此列表为空,则返回 null。
//    E pollLast () 获取并移除此列表的最后一个元素;如果此列表为空,则返回 null。

//    ----------------------------以下的API了解即可
//    void addFirst (E e): 将指定元素插入此列表的开头。
//    void addLast (E e): 将指定元素添加到此列表的结尾。
//    E removeFirst () 移除并返回此列表的第一个元素。
//    E removeLast () 移除并返回此列表的最后一个元素
//    E getFirst () 返回此列表的第一个元素。
//    E getLast () 返回此列表的最后一个元素。
//    boolean removeFirstOccurrence (Object o)
//    从此列表中移除第一次出现的指定元素(从头部到尾部遍历列表时)。
//    boolean removeLastOccurrence (Object o)
//    从此列表中移除最后一次出现的指定元素(从头部到尾部遍历列表时)。
//    Iterator<E> descendingIterator () 返回以逆向顺序在此双端队列的元素上进行迭代的迭代器。
//    E element () 获取但不移除此列表的头(第一个元素)。

链表特点:插入和删除快。真的吗?

查找也需要时间,所以算起来和ArrayList类似。一般需要使用,直接使用ArrayList。除非在极个别情况下,才会用LinkedList。

List<String> list = new ArrayList<>();

3.6 Vector

  1. Vector是List的子实现
  2. Vector的数据结构表现是线性表
  3. 底层结构是数组
  4. 存储的数据有序,可重复,可存储null。
  5. 线程安全。

Vector是JDK1.0出现,ArrayList是JDK1.2出现。

为什么被弃用

Vector为啥被替代。因为效率低,因为它所有的方法都有锁。

效率低,在所有的接口上都加了synchronized关键字。线程安全是没问题了,但是效率却有问题。因为绝大部分都不涉及到多线程情况,所以jdk1.2采用了ArrayList来替代Vector

在工作中,禁止使用Vector,面试专用。

面试一般会怎么问: 1.了不了解Vector。2.是否了解ArrayList和Vector的区别。3.是否了解最开始的一个线程安全的List。

一般这样答:

1.Vector是List的子实现。 List的底层是线性表。

2.存储数据是否有序,是否允许存储重复元素,是否允许存储null

3.线程安全问题。Vector是线程安全的,ArrayList是线程不安全的。

4.ArrayList是在JDK1.2出现,出现就是为了替代Vector。所以写代码的时候,我们不用Vector.

补充: 什么叫线程安全问题?

当多个线程同时对一个变量进行操作时,结果的预期与单线程下是一致的。这就是线程安全的。

比如多个线程对i进行操作,i初始值是0,有5个线程,每个线程累加10000次。最终结果应该是50000。 但真实情况不是这样的,这就是线程安全问题。

3.7 Stack

  1. Stack是Vector的子实现
  2. 栈,是先进后出的数据容器。但是不建议使用这个来完成,效率是大问题。使用Deque来替代Stack --》 见jdk源码

请添加图片描述
在Java中,要用栈,能不能使用Stack这个类? 不要用。因为在Stack类的上面,明确告诉你了,要用栈,使用Deque。

4 Queue

4.1 内容提要

  • Queue的结构,以及Queue是什么。(操作受限的线性表)

  • Queue两组增删查API及区别(add remove element | offer poll peek 极端情况下表现不一致)

  • Deque的结构(offerFirst offerLast addFirst addLast .使用API成组使用)

  • ArrayDeque的循环数组,是什么,以及为什么使用这种形式。

    • ArrayDeque是一个循环数组。底层是一个数组,使用两个int值来代表头和尾。避免从队列中获取数据的时候,频繁挪动数据,使用int值,就可以只操作int值,来模拟头和尾,提高了效率。
  • ArrayDeque的初始化容量及扩容策略。 如果传入一个非2的幂次方,它是怎么把它变成2的幂次方的。

  • BlockingQueue是什么。

Queue:在Java中,队列(Queue)是一种数据结构,用于存储元素并支持在队列的末尾添加元素和从队列的头部移除元素。队列的工作方式类似于排队等待服务的过程。

Java中的队列通常是先进先出(FIFO)的数据结构,这意味着最先添加的元素将最先被移除。Java中的队列接口(java.util.Queue)定义了队列的基本操作,如添加元素、移除元素、获取队列头部元素等。

只能从队头出队列,从队尾进队列。

4.2 特点

  1. Queue是Collection的子接口。
  2. 数据结构表现为:队列。一定要知道什么是队列。
  3. 存储元素有序
  4. 存储元素可重复
  5. 不能存储null(除了LinkedList子实现)

4.3 API

boolean add(E e): 将指定的元素插入此队列(如果立即可行且不会违反容量限制),在成功时返回 true,如果当前没有可用的空间,则抛出 IllegalStateExceptionE remove():获取并移除此队列的头。
E element() :获取,但是不移除此队列的头。

boolean offer(E e):将指定的元素插入此队列(如果立即可行且不会违反容量限制),当使用有容量限制的队列时,此方法通常要优于 add(E),后者可能无法插入元素,而只是抛出一个异常。
E poll():获取并移除此队列的头,如果此队列为空,则返回 nullE peek(): 获取但不移除此队列的头;如果此队列为空,则返回 null

在极端情况下,两组API的表现不一致。极端情况指的是

  • 插入的时候,队列满了
  • 删除或者获取的时候,队列空了。
抛出异常返回特殊值
插入add(e)offer(e)
移除remove()poll()
检查element()peek()

4.4 Deque

双端队列(Deque),是一种可以在队列的两端添加或删除元素的数据结构。

双端队列支持在队列的头部和尾部进行插入、删除和获取元素的操作,因此它可以同时用作栈和队列,是一种比较灵活的数据结构。在Java中,Deque接口提供了双端队列的实现,具有以下特点:

  1. 可以在队列的头部或尾部添加或删除元素。
  2. 可以获取队列头部或尾部的元素。
  3. 可以用作栈或队列来进行数据操作。

从队头可以进出,从队尾也可以进出。

4.4.1 特点

  1. Deque是Queue的子接口
  2. 数据结构表现:队列,栈,双端队列
  3. 存储元素有序
  4. 可存储重复元素
  5. 不能存储null(LinkedList除外)

4.4.2 API

// ------------- 作为Queue的
//        E peek(): 获取队头元素,但不移除它
//        E poll():从队头移除元素
//        boolean offer(E e): 添加一个元素到队尾

// ------------- 作为Stack的
//        E pop(): 从此列表所表示的堆栈处弹出一个元素。
//        void push(E e): 将元素推入此列表所表示的堆栈。

// ------------- 作为双端队列
//        boolean offerFirst(E e):  从第一个位置插入指定元素
//        boolean offerLast(E e): 从最后一个位置插入指定元素
//        E peekFirst(): 获取但是不移除第一个元素,如果列表为空,返回null
//        E peekLast(): 获取但是不移除最后一个元素,如果列表为空,返回null
//        E pollFirst(): 从第一个位置移除元素
//        E pollLast(): 从最后一个位置移除元素,如果列表为空,返回null

// -------------- 作为普通List的
//    boolean add(E e):将指定元素添加到此列表的结尾。
//    E remove():获取并移除此列表的头(第一个元素)。

//        void addFirst(E e): 将指定元素插入此列表的开头。
//        void addLast(E e): 将指定元素添加到此列表的结尾。
//        E getFirst(): 返回此列表的第一个元素。
//        E getLast(): 返回此列表的最后一个元素。
//        E removeFirst(): 移除并返回此列表的第一个元素。
//        E removeLast(): 移除并返回此列表的最后一个元素。

// 这个API,大家觉得应不应该出现在Deque这个接口里面。 
//        boolean removeFirstOccurrence(Object o): 从此列表中移除第一次出现的指定元素
//        boolean removeLastOccurrence(Object o): 从列表中移除最后一次出现的指定元素
//        Iterator<E> descendingIterator():获取一个倒序的迭代器
//        E element():获取元素
第一个元素(头部)第一个元素(头部)最后一个元素(尾部)最后一个元素(尾部)
抛出异常特殊值抛出异常特殊值
插入addFirst(e)offerFirst(e)addLast(e)offerLast(e)
移除removeFirst()pollFirst()removeLast()pollLast()
获取getFirst()peekFirst()getLast()peekLast()

4.5 ArrayDeque

循环数组(Cyclic Array),也称为环形数组,是一种数据结构,是数组的一种特殊形式。在循环数组中,数组的最后一个元素与第一个元素相邻,形成了一个环,因此可以通过数组下标进行循环遍历。

在循环数组中,每次增加数组下标时,需要考虑到下标越界的情况。一般来说,可以将下标对数组长度取模,实现在下标增加到数组最后一个元素时,返回到数组的第一个元素。同样地,当下标减小到数组的第一个元素时,可以通过将下标加上数组长度来返回到最后一个元素。

循环数组在实际应用中具有一定的优势,例如在循环队列、循环缓冲区等场景中,循环数组可以有效地实现元素的循环存储和遍历。同时,循环数组的空间利用率也相对较高,因为数组的最后一个元素可以直接连接到第一个元素,不需要额外的空间进行维护。

使用两个int值来存储头和尾的位置,来避免每一次出队列都需要让所有数据都挪动一遍,提高效率。

4.5.1 特点

  1. ArrayDeque是Deque的子实现
  2. 数据结构表现:队列,栈,双端队列
  3. 底层实现: 循环数组。要理解一下循环数组的好处。
  4. 存储元素有序
  5. 存储元素可重复
  6. 不可存储null

4.5.2 构造方法

//  构造一个初始容量能够容纳 16 个元素的空数组双端队列。  扩容机制 *2 
ArrayDeque() 
     
 //  构造一个包含指定 collection 的元素的双端队列,这些元素按 collection 的迭代器返回的顺序排列。     
ArrayDeque(Collection<? extends E> c) 
     
 //  构造一个初始容量能够容纳指定数量的元素的空数组双端队列。    
ArrayDeque(int numElements) 
             
容量问题。如果传入的初始化容量小于8,则直接分配8个空间,如果传入的数字大于等于8,则直接找到(大于)数字的最近一个2的幂次方。

循环数组。tail 的计算公式是 tail = (tail +1) % length

4.6 BlockingQueue

什么叫阻塞队列。一个大小有限的队列。

  • 插入时,当队列满了,插入线程阻塞住

  • 从队列中获取元素时,当队列空了,获取线程阻塞住

请添加图片描述

5 Set

5.1 内容提要

  • Set接口存储数据的特点
  • Set的子类。HashSet,LinkedHashSet,TreeSet存储数据的特点
    • 是否有序
    • 对重复的定义
    • 是否允许存储null
  • Set子类的实现方式
  • Set的使用场景

5.1 特点

  1. Set是Collection的子接口
  2. Set数据结构是: 集合(不能存储重复元素)
  3. 有些子实现无序(HashSet), 有些子实现是有序的(LinkedHashSet, TreeSet大小有序)
  4. 所有子实现都不允许存储重复元素(什么叫重复。 HashSet或者LinkedHashSet hashCode相同& equals 为true TreeSet是Comparable接口返回0,叫重复。)
  5. 有些子实现允许存储null(HashSet, LinkedHashSet), 有些子实现不允许存储null(TreeSet)

5.2 Set的API

// -------------------------set接口, 没有在Collection的基础上额外定义什么api---------

//    ---------------------------------增删改查方法---------------------------------
//    boolean add(E e): 添加一个元素进入Collection
//    boolean addAll(Collection<? extends E> c): 添加一个Collection进指定的Collection
//    boolean remove(Object o): 删除元素, 只删除第一个出现的(如果存在多个)
//    boolean removeAll(Collection<?> c): 删除Collection中的所有存在的元素,会全部删除,如果存在多个
//    boolean contains(Object o): 判断是否存在指定元素
//    boolean containsAll(Collection<?> c): 判断给定的collection中是否全部存在于目标Collection
//    boolean retainAll(Collection<?> c): 将原有collection只保留传入的collection。

//    ---------------------------------特殊方法---------------------------------
//    void clear(): 清空collection
//    boolean equals(Object o) : 判断是否相等
//    int hashCode(): 计算hashCode
//    boolean isEmpty(): 是否为空
//    int size(): collection里面的元素个数
//
//    ---------------------------------方便遍历方法---------------------------------
//    Object[] toArray(): 将collection转成一个数组,方便遍历,
//    <T> T[] toArray(T[] a):类似,只是传入了一个数组
//    Iterator<E> iterator():返回一个迭代器

5.3 HashSet

5.3.1 HashSet的特点

  1. HashSet是Set接口的子实现
  2. HashSet底层持有了一个HashMap对象
    1. 我们存储到HashSet中的数据, 实际上都存储到底层持有的HashMap的key上
    2. HashSet的特点和HashMap对key的特点保持一致
  3. HashSet存储数据无序
  4. HashSet不允许存储重复数据。注意这个重复的定义。
  5. HashSet允许存储null元素

5.3.2 HashSet的构造方法

HashSet():构造一个新的空 set,其底层 HashMap 实例的默认初始容量是 16,加载因子是 0.75HashSet(Collection<? extends E> c):构造一个包含指定 collection 中的元素的新 set。 

HashSet(int initialCapacity):构造一个新的空 set,其底层 HashMap 实例具有指定的初始容量和默认的加载因子(0.75)。 

HashSet(int initialCapacity, float loadFactor):构造一个新的空 set,其底层 HashMap 实例具有指定的初始容量和指定的加载因子。 

5.3.3 HashSet的API

// ----------HashSet ,    set接口, 没有在Collection的基础上额外定义什么api---------

5.4 LinkedHashSet

5.4.1 LinkedHashSet的特点

  1. LinkedHashSet是HashSet一个子类
  2. LinkedHashSet底层持有一个LinkedHashMap对象
    1. LinkedHashSet的特点和LinkedHashMap的key保持一致
  3. LinkedHashSet存储数据有序
  4. LinkedHashSet 不允许存储重复数据
  5. LinekdHashSet允许存储null
  6. 线程不安全

与HashSet唯一的不同:存储数据有序

5.4.2 LinkedHashSet的构造方法

LinkedHashSet():构造一个带默认初始容量 (16) 和加载因子 (0.75) 的新空链接哈希 set。 

LinkedHashSet(Collection<? extends E> c):构造一个与指定 collection 中的元素相同的新链接哈希 set。 

LinkedHashSet(int initialCapacity):构造一个带指定初始容量和默认加载因子 (0.75) 的新空链接哈希 set。 

LinkedHashSet(int initialCapacity, float loadFactor):构造一个带有指定初始容量和加载因子的新空链接哈希 set。 

5.4.3 LinkedHashSet的API

// --LinkedHashSet, HashSet ,    set接口, 没有在Collection的基础上额外定义什么api---------

5.5 TreeSet

5.5.2 TreeSet的特点

  1. TreeSet是Set接口的子实现
  2. TreeSet底层持有了一个TreeMap对象
    1. TreeSet存储数据的特点和TreeMap的key保持一致
  3. TreeSet存储数据大小有序(大小有序 不是存储的顺序)
  4. TreeSet不允许存储重复数据: ( Comparable接口返回的 是0 ;大小重复)
  5. TreeSet不允许存储null
  6. 线程不安全

5.5.3 TreeSet的构造方法

TreeSet():构造一个新的空 set,该 set 根据其元素的自然顺序进行排序。 

TreeSet(Collection<? extends E> c):构造一个包含指定 collection 元素的新 TreeSet,它按照其元素的自然顺序进行排序。 

TreeSet(Comparator<? super E> comparator):构造一个新的空 TreeSet,它根据指定比较器进行排序。 

TreeSet(SortedSet<E> s):构造一个与指定有序 set 具有相同映射关系和相同排序的新 TreeSet

5.5.4 TreeSet的API

// --TreeSet ,    set接口, 没有在Collection的基础上额外定义什么api---------

NavigableSet<E> subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) 
  返回此 set 的部分视图,其元素范围从 fromElement 到 toElement。 
SortedSet<E> subSet(E fromElement, E toElement) 
  返回此 set 的部分视图,其元素从 fromElement(包括)到 toElement(不包括)。 
SortedSet<E> tailSet(E fromElement) 
  返回此 set 的部分视图,其元素大于等于 fromElement。 
NavigableSet<E> tailSet(E fromElement, boolean inclusive) 
  返回此 set 的部分视图,其元素大于(或等于,如果 inclusive 为 true)fromElement。 

有序

  • LinkedHashSet (有序的):它的有序,指的是 add 顺序。添加进去的顺序

  • TreeSet (有序的):是根据 Comparable 返回的结果。

重复

  • LinkedHashSet HashSet : hashCode && (equals)

  • TreeSet: Comparable 返回0

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

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

相关文章

【RabbitMQ应用篇】常见应用问题

1. 消息幂等性保障 1.1 幂等性介绍 幂等性&#xff1a;这个概念在数学和计算机领域中相当常见&#xff0c;表示可以被应用多次但是不会改变初始应用结果的性质。 应用程序的幂等性&#xff1a;指的是在一个应用系统中&#xff0c;重复调用多次请求&#xff08;相同参数&#…

【Python机器学习】神经网络的组成

目录 感知机 数字感知机 认识偏置 Python版神经元 “课堂时间” 有趣的逻辑学习问题 下一步 代价函数 反向传播算法 求导 误差曲面 不同类型的误差曲面 多种梯度下降算法 Keras&#xff1a;用Python实现神经网络 展望 归一化&#xff1a;格式化输入 神经网络对…

C语言 面向对象编程

注意事项 在使用面向对象编程的时候&#xff0c;我们得问自己&#xff1a;任务中有什么对象&#xff0c;对象应该怎么使用 项目中文档体系 我们可以规划一下任务得文档&#xff0c;可以为每一个对象的类单独编写源码&#xff0c;并发布对应的头文件作为接口&#xff0c;主控…

Android CCodec Codec2 (六)C2InterfaceHelper

通过前面几篇文章的学习&#xff0c;我们知道了Codec2参数结构&#xff0c;以及如何定义一个Codec2参数。接下来的几篇文章我们将简单了解上层是如何请求组件支持的参数、如何配置参数&#xff0c;以及参数是如何反射给上层的。本篇文章我们将了解接口参数实例化。 1、C2Interf…

Linux零基础到精通(二)-vmware虚拟机使用教程及Centos7操作系统安装

目录 前言Linux 操作系统运用领域vmware虚拟机安装与使用电脑硬件环境要求vmware虚拟机软件安装创建一个虚拟机配置vmware的虚拟化网络 通过vmware虚拟机安装操作系统下载Centos7系统镜像安装Centos7操作系统配置网络和主机名称信息配置系统分区软件包选择设置用户密码进入Cent…

入门Java编程的知识点—>静态方法(day11)

重点掌握final关键字特点&#xff1f;final的语法使用?重点掌握静态变量是什么&#xff1f;静态变量的语法与使用?了解方法区内存图执行过程?重点掌握静态方法是什么&#xff1f;静态方法的语法特点与使用?重点掌握常量语法如何定义与使用? final(最终) final可以用于修…

IT运维问题深度剖析与一体化解决方案探索

在当今信息化高速发展的时代&#xff0c;IT运维作为保障企业业务连续性和稳定性的关键环节&#xff0c;其重要性日益凸显。然而&#xff0c;随着企业规模的扩大和业务的复杂化&#xff0c;IT运维面临着诸多挑战和问题。本文旨在深度剖析当前IT运维中的紧迫性问题与需求&#xf…

C++学习, 指针的指针

指针的指针&#xff1a; 是一种间接寻址的形式&#xff0c;指针的指针就是将指针的地址存放在另一个指针里面。一般&#xff0c;指针包含一个变量的地址&#xff0c;当定义一个指向指针的指针时&#xff0c;第一个指针包含了第二个指针的地址&#xff0c;第二个指针指向实际值…

day35-测试之性能测试JMeter的测试报告、并发数计算和性能监控

目录 一、JMeter的测试报告 1.1.聚合报告 1.2.html报告 二、JMeter的并发数计算 2.1.性能测试时的TPS&#xff0c;大都是根据用户真实的业务数据&#xff08;运营数据&#xff09;来计算的 2.2.运营数据 2.3.普通计算方法 2.4.二八原则计算方法 2.5.计算稳定性测试并发量 2.6…

Java性能优化传奇之旅--Java万亿级性能优化之Java 性能优化传奇:热门技术点亮高效之路

💖💖💖亲爱的朋友们,热烈欢迎你们来到 青云交的博客!能与你们在此邂逅,我满心欢喜,深感无比荣幸。在这个瞬息万变的时代,我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的博客,正是这样一个温暖美好的所在。在这里,你们不仅能够收获既富有趣味又极为实…

MOELoRA —— 多任务医学应用中的参数高效微调方法

人工智能咨询培训老师叶梓 转载标明出处 在医疗场景中&#xff0c;LLMs可以应用于多种不同的任务&#xff0c;如医生推荐、诊断预测、药物推荐、医学实体识别、临床报告生成等。这些任务的输入和输出差异很大&#xff0c;给统一模型的微调带来了挑战。而且LLMs的参数众多&…

Nginx 维护与应用:最佳实践

文章目录 引言安装与基础维护macOS 上安装 NginxUbuntu 上安装 NginxCentOS 上安装 NginxWindows 上安装 Nginx查看 Nginx 运行状态与日志信息&#xff08;Linux&#xff09;版本升级与配置备份&#xff08;Linux&#xff09; Nginx 应用场景Web 服务器反向代理动静分离负载均衡…

“线程池中线程异常后:销毁还是复用?”

目录 一、验证execute提交线程池中 测试 结论 二、验证submit提交线程池中 测试 结论 三、源码解析 查看submit方法的执行逻辑 查看execute方法的执行逻辑 为什么submit方法&#xff0c;没有创建新的线程&#xff0c;而是继续复用原线程&#xff1f; 四、总结 需要说…

Android AOSP定制默认输入法为讯飞输入法

Android AOSP定制默认输入法为讯飞输入法 前言&#xff1a; ​ 最近在公司的项目中发现默认的输入法非常不好用&#xff0c;而且默认输入法中英文切换非常麻烦&#xff0c;被用户吐槽定制的AOSP镜像体验不好&#xff0c;于是查找资料&#xff0c;研究了一番&#xff0c;尝试了…

【C++】日期类函数(时间计数器)从无到有实现

欢迎来到HarperLee的学习笔记&#xff01; 博主主页传送门&#xff1a;HarperLee的博客主页 个人语录&#xff1a;他强任他强&#xff0c;清风拂山岗&#xff01; 一、前期准备 1.1 检查构造的日期是否合法 bool Date::CheckDate() {if (_month < 1 || _month > 12|| _d…

vercel免费在线部署TodoList网页应用

参考&#xff1a; TodoList网页应用&#xff1a;https://blog.csdn.net/weixin_42357472/article/details/140909096 1、项目首先上传github 直接vscode自带的上传项目&#xff0c;commit后在创建项目上传即可 2、vercel部署项目 1&#xff09;先注册 2&#xff09;impor…

基于PHP评论区的存储型XSS漏洞

评论区的XSS漏洞是指攻击者在评论区输入恶意脚本&#xff0c;当其他用户浏览该页面时&#xff0c;这些恶意脚本会被执行&#xff0c;从而造成安全威胁。这种漏洞通常出现在网站没有对用户输入进行充分过滤和转义的情况下&#xff0c;为存储型XSS。存储型XSS攻击是指攻击者在目标…

【MCAL】TC397+EB-tresos之SPI配置实战 - (同步/异步)

本篇文章首先从理论讲起&#xff0c;从AUTOSAR规范以及MCAL手册两个不同角度&#xff08;前者偏理论&#xff0c;后者偏实践&#xff09;介绍了SPI模块的背景概念与理论&#xff0c;帮助读者在实际配置之前能有个理论的框架。然后详细的介绍了在TC397平台使用EB tresos对SPI驱动…

数智化粮仓综合监控管理系统设计方案WORD-2023

关注智慧方案文库&#xff0c;学习9000多份智慧城市智慧医院&#xff0c;智慧水利&#xff0c;智能制造&#xff0c;数字化转型&#xff0c;智慧工厂&#xff0c;智慧矿山&#xff0c;智慧交通&#xff0c;智慧粮仓&#xff0c;工业互联网&#xff0c;数字孪生......持续更新热…

SpringCloud Alibaba】(十三)学习 RocketMQ 消息队列

目录 1、MQ 使用场景与选型对比1.1、MQ 的使用场景1.2、引入 MQ 后的注意事项1.3、MQ 选型对比 2、下载、安装 RocketMQ 及 RocketMQ 控制台2.1、下载安装 RocketMQ2.2、测试 RocketMQ 环境2.3、RocketMQ 控制台【图形化管理控制台】2.3.1、下载、安装2.3.2、验证 RocketMQ 控制…