【Java】《On Java》第12章 集合 读书笔记

news2025/2/12 10:48:13

结合JavaGuide和《On Java》的集合笔记。

不要使用时代的眼泪VectorHashTableStack

文章目录

  • 1 泛型与类型安全的集合
  • 2 基本概念
  • 3 添加一组元素★
  • 4 集合的打印
  • 5 List
      • toArray的使用 ★
      • Collection.sort的使用
  • 6 ArrayList
    • 6.1 ArrayList成员变量
    • 6.2 ArrayList构造函数
    • 6.3 ArrayList的插入与删除
    • 6.4 ArrayList的动态扩容:grow ★
  • 7 LinkedList
  • 8 Stack
  • 9 Set
      • 9.1 == 和 equals() 的区别
      • 9.2 HashSet如何检查重复?hashCode有什么用?★
      • 9.3 HashSet的插入
  • 10 Map(看了进阶版以后来填坑)
  • 11 Queue
      • ArrayDeque 与 LinkedList 的区别

1 泛型与类型安全的集合

在Java5之前,编译器允许向集合中插入不正确的类型。

比如,考虑一个Apple对象的集合,它由这条语句创建:

ArrayList apples = new ArrayList();

由于这个示例没有泛型,正常情况下编译器会给出警告:

Raw use of parameterized class 'ArrayList'

但如果我们向这个apples集合中插入一个Orange对象,代码并不会报错。

apples.add(new Orange())

而当我们取出对象时,会出现问题,提示我们Orange cannot be cast to Apple, 得到一个Orange是在我们意料之外的行为。

Apple apple = (Apple) apples.get(0);

所以java提供了泛型,当我们希望指明一个集合中包含的是Apple类型时,只需要定义类型参数AppleArrayList

在Java7之前,我们需要像第二行代码一样,在两侧重复写出类型声明。

程序员观察到,所有的信息都可以在左侧得到,因此没有理由任由编译器强迫我们在右侧再写一遍,因此变成了钻石语法<>的空括号。(解开了我多年的疑惑

ArrayList<Apple> apples = new ArrayList<>();
ArrayList<Apple> apples = new ArrayList<Apple>();

当指定了某个类型为泛型参数时,并不仅限于只能将确切类型的对象放入集合中。向上转型也可以像作用于其他类型一样作用于泛型,其子类对象也可加入集合。

2 基本概念

Java 集合框架概览

Java集合类库从设计上讲,可以分为两个不同的概念,表示为库的两个基本接口:

  • 集合Collection :一个独立元素的序列

  • 映射Map : 一组成对的“键值对”对象

尽管并非总是如此,但在理想情况下,我们编写的大部分代码在与这些接口打交道,只有在创建时才需要指明所使用的确切类型,因此可以这样创建一个List

List<Apple> apples = new ArrayList<>();

当希望修改实现时,只需要更改apples的实例化,而无需更改其他代码。

List<Apple> apples = new LinkedList<>();

当然,因为有些类具有额外的功能,我们有时可能需要使用这些功能,而希望使用更详细的数据类型。

3 添加一组元素★

方法描述说明
Arrays.asList将数组 / 多个元素变为List对象
Collection()构造方法,可接受使用另一个Colletion作为参数浅拷贝(深拷贝需要使用clone)
Collection.addAll()Collection中加入另一个Collection的元素浅拷贝
Collections.addAll()接受数组、Collection、多个元素作为参数浅拷贝
  1. Arrays.asList()方法可以接受一个数组,或者一个用逗号分隔的元素列表(使用可变参数),并将其转换为一个List对象。但是它的底层实现是一个数组,大小无法调整,不能进行add或者remove操作。
// 逗号分隔的元素列表
Arrays.asList(1, 2, 3, 4, 5)
// 接受一个数组
Integer[] moreInts = {6, 7, 8, 9, 10};
Arrays.asList(moreInts)
// 如果想改变数组大小,要像这样再构造一个新对象
List<Integer> arrayList = new ArrayList<>(Arrays.asList(moreInts));
  1. Collection类的构造器可以接受使用另一个Colletion作为参数:
 Collection<Integer> collection = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
  1. Collection类的addAll()函数只能接受使用另一个Colletion作为参数,不如Arrays.asList或者Collections.addAll()方法灵活,二者可以接受可变参数列表。
collection.addAll(Arrays.asList(moreInts));
  1. Collections.addAll()方法接受一个Collection对象、一个数组、或者一个用逗号分隔的列表,将其中所有的元素都加入这个Collection中。Collections.addAll()方法速度要快得多,也更加灵活,因此更推荐这种方式
Collections.addAll(collection, 11, 12, 13, 14, 15);
Collections.addAll(collection, moreInts);
Collections.addAll(collection, Arrays.asList(moreInts));

4 集合的打印

ArrayList LinkedList 都是 List 的类型,从输出中可以看出,它们都按插入顺序保存元素。两者之间的区别不仅在于执行某些类型的操作时的性能,而且 LinkedList 包含的操作多于 ArrayList

HashSet TreeSetLinkedHashSet是 Set 的类型。从输出中可以看到, Set 仅保存每个相同项中的一个,并且不同的 Set 实现存储元素的方式也不同。

  • 如果存储顺序很重要,则可以使用TreeSet,它将按比较结果的升序保存对象。
  • 或使用 LinkedHashSet ,它按照被添加的先后顺序保存对象。

键和值保存在 HashMap 中的顺序不是插入顺序,因为 HashMap 实现使用了非常快速的算法来控制顺序。

  • TreeMap 升序保存键
  • LinkedHashMap 在保持 HashMap 查找速度的同时按键的插入顺序保存键。

5 List

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XBotoEX8-1686725066476)(【Java】On Java读书笔记/image-20230614120133736.png)]

有两种类型的 List

  • 基本的 ArrayList ,底层实现为Object[]数组。擅长随机访问元素,但在List中间插入和删除元素时速度较慢。

  • LinkedList ,底层实现为双向链表。它通过代价较低的在 List 中间进行的插入和删除操作,提供了优化的顺序访问。LinkedList对于随机访问来说相对较慢,但它具有比 ArrayList 更多的功能。

方法说明备注
contains判断某个对象是否在列表中
add加入元素 / 按照指定下标添加元素
remove按照下标删除某个元素 / 删除某个指定元素
indexOf从列表中获取对象的对应下标,如果没查到,返回 -1
subList截取列表, [ s t a r t , e n d ) [start,end) [start,end)subList生成的列表,底层是原始列表。
containsAll是否包含某个集合
Collections.sort(list);对集合进行排序,可以使用自定义的new Comparator重写compareTo方法
A.retainAll(B)求交集,保留A在B中的所有元素。
removeAll删除参数包含的所有对象
toArray转换为数组

toArray的使用 ★

toArray的无参版本会返回一个Object数组;如果向重载的toArray版本传递一个目标类型的数组,它就会生成指定类型的数组。

如果参数数组太小,以至于无法将所有对象保存在这个List中,toArray方法会自动创建一个大小适当的新数组。

// toArray() 将列表转为数组
Object[] o = pets.toArray();

// toArray() 还有一个重载方法,传入一个形参,可以直接返回对应类型的数组,
// 这里的 new Integer[0] 就是起一个模板的作用,指定了返回数组的类型,
// 0是为了节省空间
Integer[] pa = pets.toArray(new Integer[pets.length()]);

ArrayList toArray(T[] a)方法为例:

	@SuppressWarnings("unchecked")
    public <T> T[] toArray(T[] a) {
        if (a.length < size)
            // 新建一个运行时类型的数组,但是ArrayList数组的内容
            return (T[]) Arrays.copyOf(elementData, size, a.getClass());
            //调用System提供的arraycopy()方法实现数组之间的复制
        System.arraycopy(elementData, 0, a, 0, size);
        if (a.length > size)
            a[size] = null;
        return a;
    }

Collection.sort的使用

Comparable 接口和 Comparator 接口都是 Java 中用于排序的接口,它们在实现类对象之间比较大小、排序等方面发挥了重要作用:

  • Comparable 接口实际上是出自java.lang包 它有一个 compareTo(Object obj)方法用来排序
  • Comparator接口实际上是出自 java.util 包它有一个compare(Object obj1, Object obj2)方法用来排序

一般我们需要对一个集合使用自定义排序时,我们就要重写compareTo()方法或compare()方法。

// Comparator定制排序的用法
Collections.sort(arrayList, new Comparator<int[]>() {
    @Override
    public int compare(int[] o1, int[] o2) {
        return o1[0] - o2[0];
    }
});
// 使用Comparabale接口进行排序
public class Person implements Comparable<Person> {
 	...
 	@Override
    public int compareTo(Person o) {
        if (this.age > o.getAge()) {
            return 1;
        }
        if (this.age < o.getAge()) {
            return -1;
        }
        return 0;
    }
}

TreeMap<Person, String> pdata = new TreeMap<Person, String>();

6 ArrayList

ArrayList 的底层是数组队列,相当于动态数组。与 Java 中的数组相比,它的容量能动态增长。在添加大量元素前,应用程序可以使用ensureCapacity操作来增加 ArrayList 实例的容量。

ArrayList 类图

List : 表明它是一个列表,支持添加、删除、查找等操作,并且可以通过下标进行访问。

RandomAccess :这是一个标志接口,表明实现这个接口的 List 集合是支持 快速随机访问 的。在 ArrayList 中,我们即可以通过元素的序号快速获取元素对象,这就是快速随机访问。

Cloneable :表明它具有拷贝能力,可以进行深拷贝或浅拷贝操作。

Serializable : 表明它可以进行序列化操作,也就是可以将对象转换为字节流进行持久化存储或网络传输。

6.1 ArrayList成员变量

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    private static final long serialVersionUID = 8683452581122892189L;

    // 默认初始容量大小
    private static final int DEFAULT_CAPACITY = 10;

    // 空数组(用于空实例)。
    private static final Object[] EMPTY_ELEMENTDATA = {};

    // 用于默认大小空实例的共享空数组实例。
    // 我们把它从EMPTY_ELEMENTDATA数组中区分出来,以知道在添加第一个元素时容量需要增加多少。
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    // 保存ArrayList数据的数组
    transient Object[] elementData; // non-private to simplify nested class access

    // ArrayList 所包含的元素个数
    private int size;
}

6.2 ArrayList构造函数

1、带初始容量的构造函数,将创建initialCapacity大小的数组。

    // 带初始容量参数的构造函数(用户可以在创建ArrayList对象时自己指定集合的初始大小)
    public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            //如果传入的参数大于0,创建initialCapacity大小的数组
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            //如果传入的参数等于0,创建空数组
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            //其他情况,抛出异常
            throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
        }
    }

2、默认无参构造函数,elementData为空数组,第一次加入元素时容量变为默认大小10。

    // 默认无参构造函数,DEFAULTCAPACITY_EMPTY_ELEMENTDATA 为0.初始化为10,
    // 也就是说初始其实是空数组 当添加第一个元素的时候数组容量才变成10
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

3、从一个Collection构造数组Object[],大小与传入的Collection参数相同。

	// 构造一个包含指定集合的元素的列表,按照它们由集合的迭代器返回的顺序。集合类型中元素为E及其子类。
    public ArrayList(Collection<? extends E> c) {
        //将指定集合转换为数组
        elementData = c.toArray();
        //如果elementData数组的长度不为0
        if ((size = elementData.length) != 0) {
            // 如果elementData不是Object类型数据(c.toArray可能返回的不是Object类型的数组)
            if (elementData.getClass() != Object[].class)
                //将原来不是Object类型的elementData数组的内容,赋值给新的Object类型的elementData数组
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // 其他情况,用空数组代替
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

6.3 ArrayList的插入与删除

  • 插入:

    • 头部插入:由于需要将所有元素都依次向后移动一个位置,因此时间复杂度是 O ( n ) O(n) O(n)

    • 尾部插入:当 ArrayList 的容量未达到极限时,往列表末尾插入元素的时间复杂度是 O ( 1 ) O(1) O(1),因为它只需要在数组末尾添加一个元素即可;当容量已达到极限并且需要扩容时,则需要执行一次 O ( n ) O(n) O(n)的操作将原数组复制到新的更大的数组中,然后再执行 O ( 1 ) O(1) O(1) 的操作添加元素。

      	public boolean add(E e) {
              modCount++;
              add(e, elementData, size);
              return true;
          }	
      
      	private void add(E e, Object[] elementData, int s) {
              //  如果空间足够,不需要进行扩容;如果空间不够,就进行grow
              if (s == elementData.length)
                  elementData = grow();
              elementData[s] = e;
              size = s + 1;
          }
      
    • 指定位置插入:需要将目标位置之后的所有元素都向后移动一个位置arraycopy,然后再把新元素放入指定位置。这个过程需要移动平均 n / 2 n/2 n/2 个元素,因此时间复杂度为 O ( n ) O(n) O(n)

      	public void add(int index, E element) {
              rangeCheckForAdd(index);
              modCount++;
              final int s;
              Object[] elementData;
              if ((s = size) == (elementData = this.elementData).length)
                  elementData = grow();
              System.arraycopy(elementData, index, elementData, index + 1, s - index);
              elementData[index] = element;
              size = s + 1;
          }
      
  • 对于删除:

    • 头部删除:由于需要将所有元素依次向前移动一个位置,因此时间复杂度是 O ( n ) O(n) O(n)
    • 尾部删除:当删除的元素位于列表末尾时,时间复杂度为 O ( 1 ) O(1) O(1)
    • 指定位置删除:需要将目标元素之后的所有元素向前移动一个位置以填补被删除的空白位置,因此需要移动平均 n / 2 n/2 n/2 个元素,时间复杂度为 O ( n ) O(n) O(n)

6.4 ArrayList的动态扩容:grow ★

核心函数为grow

如果旧容量为0,创建一个新数组即可。如果旧容量不等于0,则需要判断 m i n C a p a c i t y minCapacity minCapacity 1.5 × o l d C a p a c i t y 1.5 \times oldCapacity 1.5×oldCapacity的大小,将数组容量扩充为更大的那个值,并用ArrayCopy方法复制旧数组。

	private Object[] grow() { return grow(size + 1); }
    
    private Object[] grow(int minCapacity) {
        // 旧容量大小
        int oldCapacity = elementData.length;
        // 如果旧容量不为0
        if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            // 扩容后所需的长度(minCapacity)是否大于当前数组长度的1.5倍
            // 若是则将新的数组容量(newCapacity)设为minCapacity
            // 若不是则将新的数组容量设为当前数组长度的1.5倍(oldCapacity >> 1,位右移运算,表示当前数组长度的0.5倍)
            int newCapacity = ArraysSupport.newLength(oldCapacity,
                    minCapacity - oldCapacity, /* minimum growth */
                    oldCapacity >> 1           /* preferred growth */);
            return elementData = Arrays.copyOf(elementData, newCapacity);
        } 
        // 旧容量为0,建立一个新数组即可
        else {
            return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
        }
    }

此外,在大量加入元素之前,可以通过ensureCapacity手动进行扩容,以减少不断调用grow方法的复制次数。

    public void ensureCapacity(int minCapacity) {
        if (minCapacity > elementData.length
            && !(elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
                 && minCapacity <= DEFAULT_CAPACITY)) {
            modCount++;
            grow(minCapacity);
        }
    }

7 LinkedList

与ArrayList相比,LinkedList执行插入和删除的效率更高 ,不过随机访问操作的表现要差一些。

  • 头部插入/删除:只需要修改头结点的指针即可完成插入/删除操作,因此时间复杂度为 O(1)。

  • 尾部插入/删除:只需要修改尾结点的指针即可完成插入/删除操作,因此时间复杂度为 O(1)。

  • 指定位置插入/删除:需要先移动到指定位置,再修改指定节点的指针完成插入/删除,因此需要移动平均 n/2 个元素,时间复杂度为 O(n)。

更重要的是,LinkedList中加入了一些可以使其用作栈、队列、双端队列的方法。

功能为空抛出异常为空返回null
返回头部getFirst / elementpeek / peekFirst
移除并返回头部removeFirst / remove / poppoll / pollFirst
头部插入元素addFirst / push
返回尾部peekLast
尾部插入元素addLast / add / offer
移除并返回尾部removeLastpollLast

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tbTHauOS-1686725066476)(【Java】On Java读书笔记/image-20230614113300743.png)]

8 Stack

Java1.0就提供了Stack类,但是这个类的设计十分糟糕。它是一个类而不是接口,继承了设计糟糕的Vector类,Vector类可以看成方法名又臭又长但线程安全的ArrayListStack继承了Vector所有的方法与行为。而Java由于向后兼容,没有办法摆脱这种糟糕的设计错误。

Java6加入ArrayDeque,提供了直接实现栈功能的方法pushpoppeek

请不要使用Stack类!

9 Set

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hxgcejcI-1686725066476)(【Java】On Java读书笔记/image-20230614121317455.png)]

Set 不保存重复的元素。查找通常是 Set 最重要的操作,因此通常会选择HashSet实现,该实现针对快速查找进行了优化。Set 具有与 Collection 相同的接口,因此没有任何额外的功能。实际上, Set 就是一个 Collection ,只是行为不同。

  • HashSet(无序): 使用哈希函数,基于 HashMap 实现,底层采用 HashMap 来保存元素。
  • LinkedHashSet: LinkedHashSetHashSet 的子类,并且其内部是通过 LinkedHashMap 来实现的。使用链表和哈希表,按照插入顺序维护元素。
  • TreeSet: 将元素排序存储在红黑树数据结构中。

9.1 == 和 equals() 的区别

== 对于基本类型和引用类型的作用效果是不同的:

  • 对于基本数据类型来说,== 比较的是值。
  • 对于引用数据类型来说,== 比较的是对象的内存地址。

equals()不能用于判断基本数据类型的变量,只能用来判断两个对象是否相等。equals() 方法存在两种使用情况:

  • 类没有重写 equals()方法:通过equals()比较该类的两个对象时,使用的默认是 Objectequals()方法,等价于直接比较this == obj
  • 类重写了 equals()方法:一般我们都重写 equals()方法来比较两个对象中的属性是否相等;若它们的属性相等,则返回 true(即,认为这两个对象相等)。

String 中的 equals 方法是被重写过的,因为 Objectequals 方法是比较的对象的内存地址,而 Stringequals 方法比较的是对象的值。当创建 String 类型的对象时,虚拟机会在常量池中查找有没有已经存在的值和要创建的值相同的对象,如果有就把它赋给当前引用。如果没有就在常量池中重新创建一个 String 对象。

9.2 HashSet如何检查重复?hashCode有什么用?★

⭐当你把对象加入 HashSet 时:

  • HashSet 会先计算对象的 hashCode 值来判断对象加入的位置,同时也会与其他已经加入的对象的 hashCode 值作比较,如果没有相符的 hashCodeHashSet 会假设对象没有重复出现。
  • 如果发现有相同 hashCode 值的对象,这时会调用 equals() 方法来检查 hashCode 相等的对象是否真的相同:
    • 如果两者相同,HashSet 就不会让其加入操作成功。
    • 如果不同的话,就会重新散列到其他位置。

hashCode() 的作用是获取哈希码(int 整数),也称为散列码。这个哈希码的作用是确定该对象在哈希表中的索引位置。

  • 两个对象的hashCode 值相等并不代表两个对象就相等,但是有时可以大大减少equals 的次数,相应提高执行速度。

  • 重写equals()时必须重写 hashCode() 方法,因为两个相等对象的hashCode值必须相等。否则可能导致在进行HashSet插入的类似操作时出现错误。

总结就是:

  1. 如果两个对象的hashCode 值相等,那这两个对象不一定相等(哈希碰撞)。

  2. 如果两个对象的hashCode 值相等并且equals()方法也返回 true,我们才认为这两个对象相等。

  3. 如果两个对象的hashCode 值不相等,我们就可以直接认为这两个对象不相等。

9.3 HashSet的插入

底层为HashTable实现,只是简单的调用了HashMapput()方法,并且判断了一下返回值以确保是否有重复元素。

// Returns: true if this set did not already contain the specified element
// 返回值:当 set 中没有包含 add 的元素时返回真
public boolean add(E e) {
        return map.put(e, PRESENT)==null;
}

10 Map(看了进阶版以后来填坑)

方法说明示例
get()根据键查找值
getOrDefault()根据键查找值,查找不到时使用默认值代替
put()放入键值对
containsKey()是否含某个键
containsValue()是否含某个值
keySet()键的集合
values()值的集合

11 Queue

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ygQQS6k8-1686725066477)(【Java】On Java读书笔记/image-20230614134528570.png)]

Queue 是单端队列,只能从一端插入元素,另一端删除元素,实现上一般遵循 先进先出(FIFO) 规则。

Queue 扩展了 Collection 的接口,根据 因为容量问题而导致操作失败后处理方式的不同 可以分为两类方法: 一种在操作失败后会抛出异常,另一种则会返回特殊值。

Queue 接口抛出异常返回特殊值
插入队尾add(E e)offer(E e)
删除队首remove()poll()
查询队首元素element()peek()

Deque 是双端队列,在队列的两端均可以插入或删除元素。

Deque 扩展了 Queue 的接口, 增加了在队首和队尾进行插入和删除的方法,同样根据失败后处理方式的不同分为两类:

Deque 接口抛出异常返回特殊值
插入队首addFirst(E e)offerFirst(E e)
插入队尾addLast(E e)offerLast(E e)
删除队首removeFirst()pollFirst()
删除队尾removeLast()pollLast()
查询队首元素getFirst()peekFirst()
查询队尾元素getLast()peekLast()

事实上,Deque 还提供有 push()pop() 等其他方法,可用于模拟栈。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1UT1QSjR-1686725066477)(【Java】On Java读书笔记/image-20230614113300743.png)]

ArrayDeque 与 LinkedList 的区别

ArrayDequeLinkedList 都实现了 Deque 接口,两者都具有队列的功能,但两者有什么区别呢?

  • ArrayDeque 是基于可变长的数组和双指针来实现,而 LinkedList 则通过链表来实现。
  • ArrayDeque 插入时可能存在扩容过程, 不过均摊后的插入操作依然为 O(1)。虽然 LinkedList 不需要扩容,但是每次插入数据时均需要申请新的堆空间,均摊性能相比更慢。

从性能的角度上,选用 ArrayDeque 来实现队列要比 LinkedList 更好。

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

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

相关文章

没有公网IP,如何实现数据共享?

数据共享就是让在不同地方使用不同计算机、不同软件的用户能够读取他人数据并进行各种操作、运算和分析。不同层次、不同部门信息系统间&#xff0c;信息和信息产品的交流与共用&#xff0c;就是把信息这一种在互联网时代中重要性越趋明显的资源与其他人共同分享。 数据共享有…

SpeechGen:用提示解锁语音语言模型(Speech LM)的生成能力

论文链接&#xff1a; https://arxiv.org/pdf/2306.02207.pdf Demo: https://ga642381.github.io/SpeechPrompt/speechgen.html Code: https://github.com/ga642381/SpeechGen 引言与动机 大型语言模型 &#xff08;LLMs&#xff09;在人工智能生成内容&#xff08;AIGC…

手动渲染农场和自助云渲染农场的区别

手动渲染农场和自助云渲染农场是两种常见的渲染方式&#xff0c;它们各有优缺点。手动渲染农场指的是在本地使用自己的硬件设备进行渲染&#xff0c;而自助云渲染农场则是利用云服务商提供的计算资源进行渲染。对于需要渲染大规模项目的设计师或工作室来说&#xff0c;选择一种…

网络安全主要学些什么比较重要

网络安全学什么&#xff1f; 第一阶段&#xff1a;基础 入门的第一步是学习当下的一些主流的安全工具和配套的原理基础 第二阶段&#xff1a;学习基础知识 这个阶段的时候对网络安全就有了基本的了解&#xff0c;通过第一步的学习&#xff0c;理论上的知识一定都明白了&…

Python精美图快速上手

seaborn是一个基于Python的数据可视化库&#xff0c;它建立在Matplotlib之上&#xff0c;提供了一种更简单、更美观的方式来创建统计图形。seaborn旨在帮助用户轻松地生成有吸引力和信息丰富的可视化结果。 以下是seaborn库的一些主要特点&#xff1a; 美观的默认样式&#xf…

获取jar包所在路径位置,项目文件夹Path

获取jar包所在路径位置,项目文件夹位置 方法1 new ApplicationHome().getDir().getPath();方法1就是调用了方法2 System.getProperty("user.dir") System.getProperty("user.dir")String源码&#x1f447; private File findHomeDir(File source) {File…

Python 标准库 - 并发执行

Python 标准库 - 并发执行 1. 简单介绍2. 程序示例2.1 threading 编程示例2.2 multiprocessing 编程示例2.3 concurrent.futures 编程示例 1. 简单介绍 Python 标准库 非常庞大&#xff0c;所提供的组件涉及范围十分广泛&#xff0c;官方参考链接https://docs.python.org/zh-cn…

【sentinel】令牌桶算法在Sentinel中的应用

令牌桶算法 令牌桶算法介绍 令牌桶算法&#xff0c;又称token bucket。 从图中我们可以看到&#xff0c;令牌桶算法比漏桶算法稍显复杂。首先&#xff0c;我们有一个固定容量的桶&#xff0c;桶里存放着令牌&#xff08;token&#xff09;。桶一开始是空的&#xff0c;token以…

【深度学习】0-2 深度学习相关数学概念的简单总结-概率与信息论

样本空间 样本空间是一个实验或随机试验所有可能结果的集合&#xff0c;随机试验中的每个可能结果称为样本点。例如投掷一个骰子&#xff0c;那么样本空间就是{1&#xff0c;2&#xff0c;3&#xff0c;4&#xff0c;5&#xff0c;6}。 随机变量 随机变量&#xff0c;顾名思义…

IDEA全局设置JDK、Maven、编码格式

本机已安装JDK版本&#xff1a; 本机已安装Maven版本&#xff1a; 一、IDEA设置全局JDK设置 File---->New Projects Settings---->Structure for New Projects... 先将本地安装的JDK添加到SDK 将项目SDK设置为刚刚添加的本地JDK版本 File---->New Projects Settings-…

Webstorm 加载vue项目时,特别卡顿,完美解决。觉得有用加好友打赏

觉得有用加好友打赏&#xff1a;QQ&#xff1a;854138497 上图cpu直接干满。 根据上图提示&#xff0c;直接 disable hints&#xff0c;或者到下图的settings里面设置。 Code vision取消后&#xff0c;webstorm 明显就不卡了。记得重启webstorm。 还有一种方式&#xff0c;根…

完美解决MacOS关于ld: library not found for -lnetcdff错误

1. 问题描述 在使用Intel版本的Mac编译某个程序时出现了错误&#xff0c;显示如下图。 说明&#xff1a;libnetcdff是netcdf的Fortran的接口&#xff0c;如下ChatGPT解释。 2. 出现的原因 原因是Makefile中定义的静态库链接并没有在系统默认的库路径下找到&#xff0c;默认…

Jmeter HTTP Cookie管理器的使用

目录 前言&#xff1a; 1、在HTTP信息头管理器组件中添加Cookie信息 &#xff08;1&#xff09;测试计划内包含的元件 &#xff08;2&#xff09;请求取样器内容 &#xff08;3&#xff09;HTTP信息头管理器内容 &#xff08;4&#xff09;查看结果 2、使用HTTP Cookie管…

你想知道的 MySQL 性能调优方式,都在这里

前言&#xff1a;对于性能测试来说&#xff0c;数据库的监控是尤为的重要&#xff0c;以及对数据库进行调优&#xff0c;用以提升性能&#xff0c;是能在短期内有显著的效果的&#xff0c;本文针对MySQL数据库进行分析如何定位MySQL数据库的性能问题。 关键 MySQL 统计指标 如…

一张软考系统架构设计师证书到底能证明了什么?

软考证书证明你考过了软考高级架构&#xff0c;拥有了评高级职称的资格&#xff01; 证书的作用还有&#xff1a; 1、以考代评&#xff1a;软考证书可以用来评职称 2、积分落户&#xff1a;可用于积分落户&#xff0c;加相应的分&#xff0c;软考高级职业资格都几乎可以直接…

Tinker 组件修复,踩坑

1、You need to use a Theme.AppCompat theme (or descendant) with this activity. 复现步骤 补丁加载成功之后重启应用&#xff0c;再退出应用重进闪退 日志 TinkerUncaughtHandler catch exception:java.lang.IllegalStateException: You need to use a Theme.AppCompat th…

Cesium教程(十七):淹没分析

Cesium教程(十七):淹没分析 1、什么是淹没分析 淹没分析是根据某片区域的地形及洪水流量速度,动态模拟该地形区域水位逐渐上涨的淹没过程。该功能可适用于山区、丘陵等地形起伏较大区域,模拟洪水涨到安全限定高度的淹没过程,为防洪水救灾提供一定的参考。此外,还可以为河…

红帽认证常见答疑(二):电脑配置、实验环境和考试环境、可以自学吗

学习红帽需要配置什么样的电脑&#xff1f; RHCE推荐学员自己的电脑内存在16G左右&#xff0c;RHCA推荐学员电脑内存在32-64G&#xff0c;且最好配置128G以上的固态硬盘&#xff0c;如果自己没有该配置的电脑&#xff0c;誉天可以提供远程学习环境&#xff0c;可以随时随地连接…

Java中常用的工具类——字符串类

提示&#xff1a;字符串类是编程中最常用的一种数据类型&#xff0c;比较重要❗ 文章目录 前言一、字符串类创建对象方式静态创建动态创建 二、String字符串内容不可改变三、字符串常用方法length方法charAt方法substring方法indexOf与lastIndexOfindexOf方法lastIndexOf方法 替…

企业即时通信软件有哪些?要如何选择?

随着企业数字化转型的加速&#xff0c;即时通信软件已成为企业日常沟通的重要工具。但是市面上的企业即时通信软件种类繁多&#xff0c;如何选择适合自己企业的即时通信软件呢&#xff1f;本文将为大家介绍几款常用的企业即时通信软件以及如何选择。 企业微信 企业微信是腾讯公…