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

news2024/11/15 7:36:03

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; // 编译错误:无法从静态上下文访问泛型类型T
        public void print() {
            // 这里会报编译错误
            // T temp = null; // 编译错误:无法从静态上下文访问泛型类型T
             System.out.println(static-class);
        }
    }

    // 静态代码块
    static{
        // T temp; // 编译错误:无法从静态上下文访问泛型类型T
    }
}
正确示例
public class GenericClass<T> {
    // 实例变量
    private T instanceVar;

    // 静态方法
    public static <U> U staticMethod(U u) { // 使用独立的泛型参数U
        return u;
    }

    // 可以进行正常的构造方法和setter和getter方法

    // 静态内部类
    static class StaticNestedClass<U> { // 使用独立的泛型参数U
        private 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 {
   	// 在方法中单独定义泛型类型T
    public <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<>();

    @Override
    public void add(String item) {
        items.add(item);
    }

    @Override
    public String get(int index) {
        return items.get(index);
    }
}

2.4.2 示例

// 实现泛型接口的类
public class GenericClass implements GenericInterface<String> {
    @Override
    public 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> {
    @Override
    public 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.coloradmin.cn/o/1947026.html

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

相关文章

Python酷库之旅-第三方库Pandas(044)

目录 一、用法精讲 151、pandas.Series.any方法 151-1、语法 151-2、参数 151-3、功能 151-4、返回值 151-5、说明 151-6、用法 151-6-1、数据准备 151-6-2、代码示例 151-6-3、结果输出 152、pandas.Series.autocorr方法 152-1、语法 152-2、参数 152-3、功能 …

c++树(三)重心

目录 重心的基础概念 定义&#xff1a;使最大子树大小最小的点叫做树的重心 树的重心求解方式 例题&#xff1a; 重心的性质 性质1&#xff1a;重心点的最大子树大小不大于整棵树大小的一半。 性质1证明&#xff1a; 性质1的常用推导 推导1&#xff1a; 推导2&#x…

《Milvus Cloud向量数据库指南》——开源许可证的范围:深入解析与选择指南

在开源软件的广阔天地中,开源许可证作为连接开发者与用户之间的重要法律桥梁,其类型多样且各具特色。每一种许可证都精心设计了特定的权限、限制和要求,旨在保护创作者的权益,同时促进软件的创新与共享。对于开发者和用户而言,深入理解并恰当选择适合的开源许可证,是确保…

C++树(四)二叉树

目录 二叉树的定义&#xff1a; 二叉树相关术语&#xff1a; 二叉树的概念与性质 二叉树基本性质 二叉树的节点数量 满二叉树概念&#xff1a; 完全二叉树概念&#xff1a; 完全二叉树性质&#xff1a; 二叉树的存储 二叉树的遍历 在此基础上&#xff0c;二叉树的遍历…

mac下010editor的配置文件路径

1.打开访达&#xff0c;点击前往&#xff0c;输入~/.config 2.打开这个文件夹 把里面的 010 Editor.ini 文件删除即可&#xff0c;重新安装010 Editor即可

有没有下面符合以下条件的电子时钟的代码

&#x1f3c6;本文收录于《CSDN问答解答》专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收藏&…

【React1】React概述、基本使用、脚手架、JSX、组件

文章目录 1. React基础1.1 React 概述1.1.1 什么是React1.1.2 React 的特点声明式基于组件学习一次,随处使用1.2 React 的基本使用1.2.1 React的安装1.2.2 React的使用1.2.3 React常用方法说明React.createElement()ReactDOM.render()1.3 React 脚手架的使用1.3.1 React 脚手架…

PostgreSQL使用(四)——数据查询

说明&#xff1a;对于一门SQL语言&#xff0c;数据查询是我们非常常用的&#xff0c;也是SQL语言中非常大的一块。本文介绍PostgreSQL使用中的数据查询&#xff0c;如有一张表&#xff0c;内容如下&#xff1a; 简单查询 --- 1.查询某张表的全部数据 select * from tb_student…

MSPM0G3507基于keil无法烧录的解决方法

在学习M0的板卡过程中&#xff0c;遇到了诸多玄学问题。网上的教学大多基于CCS开发&#xff0c;对keil的教学几乎没有。 一开始我以为这个问题是没添加这个&#xff0c;但其实并非如此 在群里的网友说的清除flash&#xff0c;插拔USB,这些都不管用,后面也发现先在CCS烧录一遍&…

前端开发知识(二)-css

<head> <style> div{ } </style> </head> div是布局标签&#xff0c; 一般放在head标签内&#xff0c;最下部。 若直接在在.css文件中写css,文件中&#xff0c;直接写就行&#xff0c;如下所示。 div{ }

VLLM代码解读 | VLLM Hack 3

在上一期&#xff0c;我们看到了多个输入如何被封装&#xff0c;然后被塞入llm_engine中&#xff0c;接下来&#xff0c;通过_run_engine,我们要进行输入的处理了。 def _run_engine(self, *, use_tqdm: bool) -> List[Union[RequestOutput, EmbeddingRequestOutput]]:# Ini…

java-poi实现excel自定义注解生成数据并导出

因为项目很多地方需要使用导出数据excel的功能&#xff0c;所以开发了一个简易的统一生成导出方法。 依赖 <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>4.0.1</version…

【LeetCode】201. 数字范围按位与

1. 题目 2. 分析 这题挺难想的&#xff0c;我到现在还没想明白&#xff0c;为啥只用左区间和右区间就能找到目标值了&#xff0c;而不用挨个做与操作&#xff1f; 3. 代码 class Solution:def rangeBitwiseAnd(self, left: int, right: int) -> int:left_bin bin(left).…

五. TensorRT API的基本使用-TensorRT-network-structure

目录 前言0. 简述1. 案例运行2. 代码分析2.1 main.cpp2.2 model.cpp 总结下载链接参考 前言 自动驾驶之心推出的 《CUDA与TensorRT部署实战课程》&#xff0c;链接。记录下个人学习笔记&#xff0c;仅供自己参考 本次课程我们来学习课程第五章—TensorRT API 的基本使用&#x…

java面向对象进阶进阶篇--《接口和接口与抽象类综合案例》(附带全套源代码)

个人主页→VON 收录专栏→java从入门到起飞 抽象类→抽象类和抽象方法 目录 一、初识接口 特点和用途 示例&#xff1a; Animal类 Dog类 Frog类 Rabbit类 Swim接口 text测试类 结果展示&#xff1a; 二、接口的细节 接口中的成员特点&#xff1a; 成员特点与接口的关…

【通信模块】WiFi&Bluetooth简介与对比

学习云里物里科技文章及结合CSDN优秀作者Edison Tao总结笔记&#xff0c;侵权联删&#xff01; 云里物里科技&#xff1a; https://www.minewtech.com/news/industry-2019-01-25-01.html CSDN&#xff1a; https://blog.csdn.net/taotongning/article/details/95215927 WIFI…

EXCEL 排名(RANK,COUNTIFS)

1.单列排序 需求描述&#xff1a;如有下面表格&#xff0c;需要按笔试成绩整体排名。 解决步骤&#xff1a; 我们使用RANK函数即可实现单列整体排名。 Number 选择第一列。 Ref 选择这一整列&#xff08;CtrlShift向下箭头、再按F4&#xff09;。 "确定"即可计算…

C++ | Leetcode C++题解之第284题窥视迭代器

题目&#xff1a; 题解&#xff1a; template <class T> class PeekingIterator : public Iterator<T> { public:PeekingIterator(const vector<T>& nums) : Iterator<T>(nums) {flag Iterator<T>::hasNext();if (flag) {nextElement Ite…

AUTOSAR从入门到精通-CAN-FD

目录 几个高频面试题目 CAN与CAN FD的区别是什么? 一、CAN与CAN FD的概念 二、CAN与CANFD的比较 三、CAN与CANFD的优劣势 为何CANFD还不能大面积取代CAN总线? 算法原理 什么是CAN FD CAN FD的特点 为什么会出现CAN FD? CAN FD和CAN总线协议帧异同 Can FD报文讲解…

调用python-docx 提示出错

&#x1f3c6;本文收录于《CSDN问答解答》专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收藏&…