我在Vscode学Java泛型(泛型设计、擦除、通配符)

Java泛型

  • 一、泛型 Generics的意义
    • 1.1 在没有泛型的时候,集合如何存储数据
    • 1.2 引入泛型的好处
    • 1.3 注意事项
      • 1.3.1 泛型不支持基本数据类型
      • 1.3.2 当泛型指定类型,传递数据时可传入该类及其子类类型
      • 1.3.3 如果不写泛型,类型默认是Object
  • 二、泛型程序设计
    • 2.1 类型参数的含义
    • 2.2 泛型类(普通类的工厂)
      • 2.2.1 泛型类的格式
      • 2.2.2 注意事项
        • 泛型类与静态成员
          • 错误示例
          • 正确示例
      • 2.2.3 泛型类使用的例子
      • 2.2.4 泛型类的继承
        • (1)子类保持父类的泛型性
        • 2. 子类为父类的泛型类型指定具体类型
      • 3.泛型方法的继承
    • 2.3 泛型方法
      • 2.3.1 格式
      • 2.3.2 可变参数(Varargs)
      • 2.3.3 泛型方法的使用例子
        • 方式1:使用类名后面定义的泛型
        • 方式2:单独定义泛型
        • 区别总结
    • 2.4 泛型接口
      • 2.4.1 格式:
      • 2.4.2 示例
  • 三、类型擦除(Type Erasure)
    • 3.1 为什么使用类型擦除
  • 四、泛型通配符
    • 4.1 ? extends T (上界通配符)
    • 4.2 ? super T(下界通配符)
    • 4.3 无界通配符 `?`
    • 4.4 详细解释
        • `? extends T`
        • `? super T`
        • 无界通配符 `?`
    • 4.5 PECS 原则

一、泛型 Generics的意义

在泛型这个概念出现之前,程序员必须使用Object编写适用于多种类型的代码。

1.1 在没有泛型的时候,集合如何存储数据

在 Java 中,如果我们没有给集合指定类型,默认情况下,集合中的所有数据类型都会被认为是 Object 类型。这意味着我们可以向集合中添加任何类型的数据,例如 IntegerStringDouble 等。

List list = new ArrayList();
list.add(1);       // 添加 Integer 类型
list.add("hello"); // 添加 String 类型
list.add(3.14);    // 添加 Double 类型

虽然这样使用集合很灵活,但也带来了一些问题:

  1. 类型安全问题
    由于集合中可以存储任意类型的数据,我们在取出数据时无法确定其实际类型。这可能会导致类型转换错误(ClassCastException)。

    Object obj = list.get(0); // 获取集合中的第一个元素,类型是 Object
    Integer num = (Integer) obj; // 需要强制类型转换
    
  2. 丧失类型特有行为
    由于所有元素都被视为 Object 类型,我们无法直接调用其特有的方法。

    由于 Object 类型不包含特定类型的方法或行为,所以无法直接调用这些对象的特有方法。需要进行类型转换(强制类型转换)来使用具体类型的方法,这样不仅麻烦,还可能导致运行时错误(如 ClassCastException)。

    // 运行时错误示例:如果类型转换不正确,会抛出 ClassCastException
    // 尝试将 Integer 转换为 String
    String str2 = (String) list.get(1); // 运行时异常:ClassCastException
    

    例如,如果集合中存储的是 String 类型,我们不能直接调用 String 的方法,而必须先进行类型转换。

    Object obj = list.get(1);
    String str = (String) obj;
    System.out.println(str.length()); // 调用 String 的方法
    

1.2 引入泛型的好处

核心意义在于 类属性或方法的参数在定义数据类型时,可以直接使用一个标记进行占位 ,在具体使用时才设置其对应的实际数据类型,这样当设置的数据类型出现错误后,就可以在程序编译时检测 来。

为了克服上述问题,Java 5 引入了泛型。通过使用泛型,我们可以在创建集合时指定其存储的数据类型,从而在编译时就能进行类型检查,确保类型安全。

List<String> stringList = new ArrayList<>();
stringList.add("hello");
// stringList.add(1); // 编译时会报错String str = stringList.get(0); // 不需要强制类型转换
System.out.println(str.length());

使用泛型的好处如下:

  1. 类型安全
    在添加元素时,编译器会检查类型是否匹配,不匹配的类型会在编译时报错,避免了运行时的类型转换错误。

  2. 减少强制类型转换
    在获取集合中的元素时,不需要进行强制类型转换,代码更加简洁和安全。

    (把运行时期的问题提前到了编译期间,避免了强制类型转换可能出现的异常)

  3. 提高可读性
    通过指定集合中元素的类型,代码的可读性和维护性得到提高,因为开发者可以明确知道集合中应该存储什么类型的数据。


总结:

  • 在没有泛型之前,集合可以存储任意类型的对象,但这带来了类型安全和使用上的不便。

  • 泛型允许在编译时指定集合中的元素类型,从而提高了类型安全性和代码的可读性、可维护性。

1.3 注意事项

1.3.1 泛型不支持基本数据类型

泛型的类型参数只能使用引用类型的,其对于基本数据类型(intchardouble)等是不支持直接转化为Object的。

解决方案:

可以使用基本数据类型对应的包装类(如 IntegerCharacter 等)来替代。

1.3.2 当泛型指定类型,传递数据时可传入该类及其子类类型

**泛型的本质是将类型的参数化。**通过将类型作为参数引入,泛型允许在编写代码时不必指定具体的数据类型,而是在使用时才确定具体的类型。

class Animal {}
class Dog extends Animal {}
class Cat extends Animal {}List<Animal> animalList = new ArrayList<>();
animalList.add(new Dog()); // 正确:Dog 是 Animal 的子类
animalList.add(new Cat()); // 正确:Cat 是 Animal 的子类

在这里插入图片描述

1.3.3 如果不写泛型,类型默认是Object

在这里插入图片描述

二、泛型程序设计

泛型不具备继承性,但数据具备

泛型程序设计可以被分为三种:泛型类、泛型接口、泛型方法

2.1 类型参数的含义

在编程中使用字母如 T、E、K、V 等来表示变量通常是为了提高代码的可读性和通用性。

  • T (Type): 用来表示一个类型,可以是任意类型。通常用于泛型编程中。
  • E (Element): 用来表示一个元素类型,通常用于集合类的数据结构(如列表、集合等)。
  • K (Key): 用来表示键的类型,通常用于映射类型的数据结构(如字典、映射等)。
  • V (Value): 用来表示值的类型,通常与 K 一起使用,表示字典或映射中的值。

2.2 泛型类(普通类的工厂)

泛型类是一个允许使用或者多个类型参数(类型变量)的类。

例如:一个简单的泛型类可以表示一个容器类,用于存储和检索不同类型的对象。

2.2.1 泛型类的格式

这个类可以使得我们可以只关注泛型,而可以不再为数据存储的细节而分心

修饰符 class 类名<泛型> {}// 例如
public class ClassName<T1, T2, ..., Tn> {// 类体
}

在类名后面定义泛型,在创建该类对象时确定类型。

public class Box<T> {private T t;public void set(T t) {this.t = t;}public T get() {return t;}
}Box<Integer> integerBox = new Box<>();
integerBox.set(10);
Integer value = integerBox.get();

2.2.2 注意事项

泛型类与静态成员

在Java中,静态成员是指用static关键字修饰的类成员。静态成员包括静态变量(或静态字段)、静态方法、静态块和静态内部类。

  • 静态成员属于类本身,而非类的实例

    由于静态成员在类加载时就存在,而此时泛型参数还未被实例化为具体类型,不与类的实例关联的。

    • 静态成员在类加载时就已经初始化,而此时泛型参数尚未被具体化,静态成员无法知道或引用泛型参数的具体类型。

      因此,静态成员(如静态变量、静态常量、静态方法等)不能直接访问或使用类的泛型参数

    • 静态方法可以有自己的泛型参数,静态内部类也可以定义自己的泛型参数,这些参数独立于外部类的泛型参数。这允许在静态上下文中使用泛型,只要这些泛型参数是在调用静态方法或创建静态内部类的实例时具体化的。

  • 静态的成员不能使用类的泛型

    • 静态成员在类加载时就存在,而此时泛型参数尚未被具体化(因为没有创建实例),因此静态成员无法知道泛型参数的具体类型。
    • 如果静态成员能够使用泛型参数,那么在类加载时就必须确定泛型参数的类型,但这与泛型参数的设计目标相冲突,即在实例化时才确定类型。
错误示例
public class GenericClass<T> {// 静态变量// private static int staticVar; // 这个不是关于泛型的错误// 静态方法public static void staticMethod() {// T temp; // 编译错误:无法从静态上下文访问泛型类型T}// ...// 静态内部类static class StaticNestedClass {// 静态内部类不能使用外部类的泛型类型参数T// T temp; // 编译错误:无法从静态上下文访问泛型类型Tpublic void print() {// 这里会报编译错误// T temp = null; // 编译错误:无法从静态上下文访问泛型类型TSystem.out.println(static-class);}}// 静态代码块static{// T temp; // 编译错误:无法从静态上下文访问泛型类型T}
}
正确示例
public class GenericClass<T> {// 实例变量private T instanceVar;// 静态方法public static <U> U staticMethod(U u) { // 使用独立的泛型参数Ureturn u;}// 可以进行正常的构造方法和setter和getter方法// 静态内部类static class StaticNestedClass<U> { // 使用独立的泛型参数Uprivate U temp;public StaticNestedClass(U temp) {this.temp = temp;}// ...}// 实例方法public void instanceMethod(){T temp = instanceVar;System.out.println(temp);}// 静态代码块static{// 使用原始类型或其他方式初始化静态成员List list = new ArrayList(); // 假设list是静态成员}
}
  • 静态方法:尝试使用类的泛型参数T,这是不允许的。修改后,静态方法使用了一个独立的泛型参数U,这样就避免了依赖于类的泛型参数。

  • 静态内部类:尝试使用外部类的泛型参数T,这也是不允许的。修改后,静态内部类使用了自己的泛型参数U

  • 静态代码块:尝试使用泛型参数T,这是不允许的。修改后,静态代码块中使用了原始类型或其他方式来初始化静态成员,避免了直接使用泛型参数。

2.2.3 泛型类使用的例子

public class Pair<K, V> {private K key;private V value;public Pair(K key, V value) {this.key = key;this.value = value;}public K getKey() {return key;}public V getValue() {return value;}public void setKey(K key) {this.key = key;}public void setValue(V value) {this.value = value;}
}

传入什么样的类型就会转变为该类型输出

在这里插入图片描述

2.2.4 泛型类的继承

(1)子类保持父类的泛型性
// 泛型父类  
class Animal<T> {  private T food;  public Animal(T food) {  this.food = food;  }  public T getFood() {  return food;  }  public void setFood(T food) {  this.food = food;  }  
}  // 泛型子类,保持父类的泛型性  
class Person<T> extends Animal<T> {  public Person(T food) {  super(food);  }  
}  // 使用  
Person<String> person = new Person<>("apple");  
System.out.println(person.getFood()); // 输出: apple
2. 子类为父类的泛型类型指定具体类型
// 泛型父类  
class Animal<T> {  // ...(与上面相同)  
}  // 非泛型子类,为父类的泛型类型指定具体类型  
class Dog extends Animal<String> {  public Dog(String food) {  super(food);  }  
}  // 使用  
Dog dog = new Dog("bone");  
System.out.println(dog.getFood()); // 输出: bone

3.泛型方法的继承

// 父类  
class Parent {  // 泛型方法  public <T> void print(T item) {  System.out.println(item);  }  
}  // 子类  
class Child extends Parent {  // 子类可以调用父类的泛型方法  public void test() {  print("Hello, World!"); // 调用继承自Parent的泛型方法  }  // 如果子类需要定义与父类相同签名的泛型方法,则实际上是覆盖父类的方法  // 但在这个例子中,我们没有这样做  
}  // 使用  
Child child = new Child();  
child.test(); // 输出: Hello, World!

2.3 泛型方法

泛型方法在Java中是用于处理多种数据类型的灵活工具。泛型方法允许在方法定义中使用类型参数
通过使用泛型,可以在方法中处理不同类型的数据,而不需要重载多个方法。

2.3.1 格式

`修饰符 <泛型> 返回值类型 方法名(形参列表){ }`public <T> void show(T t) {}

在修饰符后面定义泛型,在调用该方法时确定类型。

public class GenericMethodExample {public <T> void printArray(T[] array) {for (T element : array) {System.out.println(element);}}
}GenericMethodExample example = new GenericMethodExample();
Integer[] intArray = {1, 2, 3, 4, 5};
example.<Integer>printArray(intArray); // 可以省略 <Integer>

2.3.2 可变参数(Varargs)

可变参数:方法参数个数不固定,用…表示,其底层实现是通过数组来实现的

形参列表中可变参数只能有一个X
可变参数必须放在形参列表的最后面

  • 泛型方法 addAll 来动态地向 ArrayList 中添加不同类型的元素
public class CC {private CC() {}//    可变参数public  static <E> void addAll(ArrayList<E> list, E... e) {for (E e1 : e) {list.add(e1);}}
}public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();CC.addAll(list, "a", "b", "c", "d");System.out.println(list);
}
  • 多个参数加法
public class Test {public static void main(String[] args) {int x=test(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);System.out.println(x);}public static int test(int... args) {int sum=0;//    可变参数for (int arg : args) {sum += arg;System.out.println(arg);}return sum;}
}

2.3.3 泛型方法的使用例子

一个简单的泛型方法可以用来交换两个对象的值。

public class Utils {public static <T> void swap(T[] array, int i, int j) {T temp = array[i];array[i] = array[j];array[j] = temp;}public static void main(String[] args) {Integer[] intArray = {1, 2, 3, 4};swap(intArray, 0, 3);for (int i : intArray) {System.out.print(i + " ");}String[] strArray = {"a", "b", "c", "d"};swap(strArray, 1, 2);for (String s : strArray) {System.out.print(s + " ");}}
}

在这个例子中,swap方法是一个泛型方法,类型参数T在方法定义中声明,可以在调用时指定具体的类型,如IntegerString

泛型方法是Java中用于处理多种数据类型的灵活工具。通过使用泛型,可以在方法中处理不同类型的数据,而不需要重载多个方法。泛型方法有两种定义方式:类名后定义泛型和方法上单独定义泛型。

方式1:使用类名后面定义的泛型

在这种方式中,泛型类型在类定义时声明,并在类的所有方法中可用。适用于需要在类的多个方法中使用相同泛型类型的情况。

// 使用类名后面定义的泛型
public class GenericClass<E> {// 泛型类型E在整个类中可用public void show(E e) {System.out.println(e);}public E getValue(E e) {return e;}public static void main(String[] args) {GenericClass<String> genericClass = new GenericClass<>();genericClass.show("Hello");System.out.println(genericClass.getValue("World"));}
}
方式2:单独定义泛型

这种方式在方法定义时单独声明泛型类型,适用于仅在某个特定方法中需要使用泛型类型的情况。

// 单独定义泛型的方法
public class GenericMethodExample {// 在方法中单独定义泛型类型Tpublic <T> void show(T t) {System.out.println(t);}public <T> T getValue(T t) {return t;}public static void main(String[] args) {GenericMethodExample example = new GenericMethodExample();example.show("Hello");System.out.println(example.getValue("World"));example.show(123);System.out.println(example.getValue(456));}
}
区别总结
  • 作用域不同:类名后定义的泛型类型在整个类中可见和可用,而单独定义的泛型类型仅在当前方法中可见和可用。
  • 适用范围不同:类名后定义的泛型适用于需要在多个方法中使用相同泛型类型的情况,而单独定义的泛型适用于仅在特定方法中需要使用泛型类型的情况。

2.4 泛型接口

可以使接口能够处理多种不同的数据类型,而无需指定具体的数据类型。泛型接口在定义时包含一个或多个类型参数,这些类型参数在接口的实现类中可以具体化为特定的类型。

2.4.1 格式:

修饰符 interface 接口名<泛型> { }// 定义一个泛型接口
public interface GenericInterface<T> {void doSomething(T t);
}

在接口名后面定义泛型,实现类确定类型或实现类延续泛型。

public interface Container<T> {void add(T item);T get(int index);
}public class StringContainer implements Container<String> {private List<String> items = new ArrayList<>();@Overridepublic void add(String item) {items.add(item);}@Overridepublic String get(int index) {return items.get(index);}
}

2.4.2 示例

// 实现泛型接口的类
public class GenericClass implements GenericInterface<String> {@Overridepublic void doSomething(String t) {System.out.println("Doing something with: " + t);}
}public class Main {public static void main(String[] args) {GenericClass gc = new GenericClass();gc.doSomething("Hello, World!");}
}

也可以创建一个泛型类来实现泛型接口

// 定义一个泛型类来实现泛型接口
public class GenericClass<T> implements GenericInterface<T> {@Overridepublic void doSomething(T t) {System.out.println("Doing something with: " + t);}
}public class Main {public static void main(String[] args) {GenericClass<String> gcString = new GenericClass<>();gcString.doSomething("Hello, World!");GenericClass<Integer> gcInteger = new GenericClass<>();gcInteger.doSomething(123);}
}

三、类型擦除(Type Erasure)

它指的是在编译期间,编译器会删除(或擦除)所有泛型类型信息,使得在运行时,程序只能看到原始的类型(即泛型参数被擦除)。

类型擦除:在编译时,Java会将泛型类型信息擦除,将泛型类型替换为其上限类型(默认是0bject)。

List在编译后会被转换为List,这意味着在运行时无法获取到String类型的信息。
在这里插入图片描述

public class Box<T> {private T value;public void setValue(T value) {this.value = value;}public T getValue() {return value;}
}

在编译后,泛型类型 T 会被擦除为 Object

public class Box {private Object value;public void setValue(Object value) {this.value = value;}public Object getValue() {return value;}
}

3.1 为什么使用类型擦除

  1. 兼容性:类型擦除使得泛型代码能够与 Java 1.4 及以前的版本兼容,因为在这些版本中并没有泛型支持。
  2. 简化:通过类型擦除,可以减少对运行时类型信息的需求,从而降低运行时开销。

四、泛型通配符

泛型通配符(wildcards)是泛型编程中的一个重要概念,主要用于在不确定泛型类型时,提供灵活的类型约束。

4.1 ? extends T (上界通配符)

  • 主要用途:用于返回类型限定。

  • 适用场景:主要用于从集合中读取数据。(不能往里存,只能往外取)

  • 限制:不能用于参数类型限定,因为编译器无法确定具体类型,只能接受 null

  • 在这里插入图片描述

  • 定义与使用

    • <? extends T>` 表示通配符类型的上界,即表示参数化类型可以是 `T` 类型或 `T` 的任何子类。
    • 可以安全地从这样的通配符类型中读取数据,因为可以确保获取的元素至少是 T 类型的实例或其子类

  • 不能往里存的原因:与多态的概念的类似

    • 编译器无法确定具体的子类类型,因此不能安全地向这样的列表中添加任何具体的子类实例,只能添加 null

示例

import java.util.ArrayList;
import java.util.List;public class Test {public static void main(String[] args) {List<Dog> dogs = new ArrayList<>();dogs.add(new Dog());dogs.add(new Dog());List<? extends Animal> animalList = dogs;for (Animal animal : animalList) {System.out.println(animal.getClass().getSimpleName()); // 读取时安全}// animalList.add(new Dog()); // 编译错误,不能添加元素}
}class Animal {}
class Dog extends Animal {}
class Cat extends Animal {}

4.2 ? super T(下界通配符)

  • 主要用途:用于参数类型限定。

  • 适用场景:主要用于向集合中写入数据。(不能往外取,只能往外取)

  • 限制:不能用于返回类型限定,因为返回的类型只能用 Object 接收。

  • 在这里插入图片描述

  • 定义与使用

    • <? super T> 表示通配符类型的下界,即表示参数化类型是 T 类型或 T 的任何超类(父类),直至 Object
    • 可以安全地向这样的通配符类型中添加 T 类型及其子类的实例。
  • 往里存的原因

    • 允许添加 Father 类型及其子类的实例,因为可以确保这样的列表至少可以接受 Father 类型的实例。

示例

import java.util.ArrayList;
import java.util.List;public class Test {public static void main(String[] args) {List<Animal> animals = new ArrayList<>();List<? super Animal> animalList = animals;animalList.add(new Dog()); // 可以添加 Dog 类型animalList.add(new Cat()); // 可以添加 Cat 类型animalList.add(new Animal()); // 可以添加 Animal 类型for (Object obj : animalList) {System.out.println(obj.getClass().getSimpleName()); // 读取时只能确保是 Object 类型}}
}class Animal {}
class Dog extends Animal {}
class Cat extends Animal {}

4.3 无界通配符 ?

  • 主要用途:表示未知类型。

  • 适用场景:一般用于参数和返回类型都不重要的情况。

  • 限制:不能用于方法参数传入,也不能用于方法返回。

    • 读操作:可以安全地读取列表中的元素,但因为没有具体类型信息,所以只能读取为 Object 类型。这意味着不能对这些元素进行具体的操作,只能执行泛用的 Object 方法。

    • 写操作:不能向列表中添加元素,除非添加 null。这是因为你不知道列表的具体类型,添加具体类型的元素可能会破坏列表的类型安全性。

示例

import java.util.ArrayList;
import java.util.List;public class Test {public static void main(String[] args) {List<String> strings = new ArrayList<>();strings.add("Hello");strings.add("World");List<?> unknownList = strings;for (Object obj : unknownList) {System.out.println(obj); // 读取时只能确保是 Object 类型}// unknownList.add("hello"); // 编译错误:无法添加元素unknownList.add(null); // 可以添加 null}
}

4.4 详细解释

? extends T

? extends T:用于返回类型限定,适合读取操作,不能用于参数类型限定。

在使用 ? extends T 时,必须确保列表在访问前已经被填充了数据。在读取元素时,编译器能够确保读取到的元素类型为 T 或其子类,但无法确定具体类型,因此不能添加元素。

? super T

? super T:用于参数类型限定,适合写入操作,不能用于返回类型限定。

在使用 ? super T 时,可以安全地向列表中添加 T 类型或其子类的对象,因为编译器知道列表中至少可以容纳 T 类型的对象。但是在读取时,只能确保读取到的元素是 Object 类型,因此需要进行类型转换。

无界通配符 ?

?:表示未知类型,通常用于对类型没有特别要求的场景,不能用于方法参数传入和返回类型。

无界通配符 ? 表示未知类型,可以用于任何类型,但在读取时只能确保类型为 Object,在添加时只能添加 null

4.5 PECS 原则

  1. Producer Extends:如果你有一个生产者方法,它返回泛型类型T的实例,那么你应该使用<? extends T>。这是因为生产者返回的实例可以是T的子类型,因此使用extends通配符可以确保你能处理这些子类型。
  2. Consumer Super:如果你有一个消费者方法,它接收泛型类型T的实例,那么你应该使用<? super T>。这是因为消费者方法接收的实例可以是T的父类型,因此使用super通配符可以确保你可以传递T及其子类型的实例。

在这里插入图片描述

Producer Extends Consumer Super 原则

  • 当你需要从集合中获取【生产、输出】元素时(Producer),使用 <? extends T>
  • 当你需要向集合中添加【消费、输入】元素时(Consumer),使用 <? super T>

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

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

相关文章

Elastic 数据分层策略:为弹性及高效的实施而优化

作者&#xff1a;来自 Elastic Michael Calizo, Tim Lee 在 Elastic&#xff0c;我们大多数成功的客户实施都是从单一用例开始的&#xff0c;旨在满足特定的业务需求。Elastic 最初被采用通常是因为开发人员欣赏它提供的功能。然而&#xff0c;由于其灵活性和可定制性&#xff…

Ubuntu安装QQ教程

Ubuntu安装QQ教程 腾讯更新Linux版的QQ&#xff0c;这里安装一下&#xff1b; 首先&#xff0c;进入官网找到合适对应的安装包&#xff1b; QQLinux版本官网&#xff1a;https://im.qq.com/linuxqq/index.shtml 我们是ubuntu系统选择X86下的deb版本&#xff0c;如果是arm开…

ROS参数服务器增删改查实操C++

ROS参数服务器增删改查实操C 创建功能包参数服务器新增&#xff08;修改&#xff09;参数参数服务器获取参数参数服务器删除参数 ROS通信机制包括话题通信、服务通信和参数服务器三种通信方式&#xff0c;各原理及代码实现如下表 功能博客链接说明VScode配置 ROS 环境VScode创建…

【Vue实战教程】之Vuex状态管理详解

Vuex状态管理 1 Vuex简介 1.1 什么是Vuex Vuex是一个专为Vue.js应用程序开发的状态管理工具。它采用了集中式存储管理应用的所有的状态&#xff0c;并以相应的规则保证状态以一种可预测的方式发生变化。 简单来说&#xff0c;Vuex是一个适用于在Vue项目开发时使用的状态管理…

机器学习 | 回归算法原理——多项式回归

Hi&#xff0c;大家好&#xff0c;我是半亩花海。接着上次的最速下降法&#xff08;梯度下降法&#xff09;继续更新《白话机器学习的数学》这本书的学习笔记&#xff0c;在此分享多项式回归这一回归算法原理。本章的回归算法原理基于《基于广告费预测点击量》项目&#xff0c;…

Adaboost集成学习 | Matlab实现基于LSTM-Adaboost长短期记忆神经网络结合Adaboost集成学习多输入单输出时间序列预测

目录 效果一览基本介绍模型设计程序设计参考资料效果一览 基本介绍 Adaboost集成学习 | Matlab实现基于LSTM-Adaboost长短期记忆神经网络结合Adaboost集成学习时间序列预测(股票价格预测) 模型设计 步骤1: 数据准备 收集和整理历史数据。确保数据集经过适当的预处理,如归一…

【人工智能】Transformers之Pipeline(五):深度估计(depth-estimation)

目录 一、引言 二、深度估计&#xff08;depth-estimation&#xff09; 2.1 概述 2.2 技术路径 2.3 应用场景 2.4 pipeline参数 2.4.1 pipeline对象实例化参数 2.4.2 pipeline对象使用参数 2.4 pipeline实战 2.5 模型排名 三、总结 一、引言 pipeline&#xff08…

mysql JSON特性优化

有朋友问到&#xff0c;mysql如果要根据json中的某个属性过滤&#xff0c;数据量大的话&#xff0c;性能很差&#xff0c;要如何提高性能&#xff1f; 为什么要用json串&#xff1f; 由于一些特定场景&#xff0c;mysql需要用到json串&#xff0c;例如文档&#xff0c;不同的…

详解Stable Diffusion 原理图

参考英文文献&#xff1a;The Illustrated Stable Diffusion – Jay Alammar – Visualizing machine learning one concept at a time. 在这个Stable Diffusion模型的架构图中&#xff0c;VAE&#xff08;变分自编码器&#xff09;模型对应的是图中的 E 和 D 部分。 具体来说…

【BUG】已解决:NameError: name ‘python‘ is not defined

NameError: name ‘python‘ is not defined 目录 NameError: name ‘python‘ is not defined 【常见模块错误】 【解决方案】 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#xff0c;我是博主英杰&#xff0c;211科班出身&#xff0c;就职于…

深入学习STL标准模板库

C STL standard template libaray 标准模板库 目录 C STL standard template libaray 标准模板库 一、标准容器顺序容器vectordequelistvector deque list对比 容器适配器stackqueuepriority_queue 关联容器(1)无序关联容器unordered_setunordered_multisetunordered_mapunorde…

Cxx Primer-chap7

类的基本思想是数据抽象和封装&#xff0c;前者强调interface和implement分离&#xff0c;后者在此基础上&#xff0c;强调访问控制符&#xff08;存疑&#xff09;。同时类的实现者和使用者考虑的角度不同&#xff0c;前者考虑实现效率&#xff0c;后者仅需关注功能即可&#…

C++相关概念和易错语法(23)(set、仿函数的应用、pair、multiset)

1.set和map存在的意义 &#xff08;1&#xff09;set和map的底层都是二叉搜索树&#xff0c;可以达到快速排序&#xff08;当我们按照迭代器的顺序来遍历set和map&#xff0c;其实是按照中序来遍历的&#xff0c;是排过序的&#xff09;、去重、搜索的目的。 &#xff08;2&a…

与众不同的社交体验:Facebook的新功能与新变化

在快速变化的社交媒体领域&#xff0c;Facebook不断引入创新功能和变化&#xff0c;以满足用户日益增长的需求&#xff0c;并提供与众不同的社交体验。从增强现实到数据隐私&#xff0c;Facebook的新功能和更新正在塑造一个全新的社交平台。本文将深入探讨这些新功能和变化&…

arm环境下构建Flink的Docker镜像

准备工作 资源准备 按需下载 flink&#xff0c;我的是1.17.2版本。官方说1.13版本之后的安装包兼容了arm架构&#xff0c;所以直接下载就行。 如需要cdc组件&#xff0c;提前下载好。 服务器准备 可在某云上购买arm服务器&#xff0c;2c/4g即可&#xff0c;按量付费。 带宽…

谷粒商城实战笔记-43-前端基础-Vue-使用Vue脚手架进行模块化开发

文章目录 一&#xff0c;Vue的模块化开发1&#xff0c;目录结构2&#xff0c;单文件组件 (SFC)3&#xff0c;模块化路由4&#xff0c;Vuex 模块5&#xff0c;动态组件和异步组件6&#xff0c;抽象和复用7&#xff0c;构建和打包8&#xff0c;测试9&#xff0c;文档和注释10&…

Nginx反向代理概述

正向代理与反向代理概述 正向代理&#xff1a; 定义&#xff1a;正向代理位于客户端和目标服务器之间&#xff0c;客户端的请求首先发送到代理服务器&#xff0c;然后由代理服务器转发到目标服务器&#xff0c;最后将目标服务器的响应返回给客户端。 作用&#xff1a;正向代理…

Linux - 进程的概念、状态、僵尸进程、孤儿进程及进程优先级

目录 进程基本概念 描述进程-PCB task_struct-PCB的一种 task_struct内容分类 查看进程 通过系统目录查看 通过ps命令查看 通过系统调用获取进程的PID和PPID 通过系统调用创建进程- fork初始 fork函数创建子进程 使用if进行分流 Linux进程状态 运行状态-R 浅度睡眠状态-S…

uni-app:踩坑路---关于使用了transform导致fixed定位不生效的问题

前言&#xff1a; 继续记录&#xff0c;在上篇文章中&#xff0c;弹出框遮罩层在ios上没有正确的铺盖全屏&#xff0c;是因为机型的原因&#xff0c;也和我们的代码结构有相关的问题。今天再来展示另外一个奇葩的问题。 这次我使用了在本篇博客中的弹出框组件CustomDialog.vue…

《昇思25天学习打卡营第19天|基于MobileNetv2的垃圾分类》

基于MobileNetv2的垃圾分类 本文档主要介绍垃圾分类代码开发的方法。通过读取本地图像数据作为输入&#xff0c;对图像中的垃圾物体进行检测&#xff0c;并且将检测结果图片保存到文件中。 1、实验目的 了解熟悉垃圾分类应用代码的编写&#xff08;Python语言&#xff09;&a…