我在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.rhkb.cn/news/385081.html

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

相关文章

.net 连接达梦数据库开发环境部署

.net 开发环境部署 1. 环境准备 测试工具 Visual Studio2022 数据库版本 dm8 2. 搭建过程 1 &#xff09;创建新项目 2 &#xff09;选择创建空项目 3 &#xff09;配置新项目 4 &#xff09;右键 DM1 新建一个项 5 &#xff09;加 载 驱 动 &#xff0c; 新 建 …

SQL labs-SQL注入(五,使用sqlmap进行cookie注入)

本文仅作为学习参考使用&#xff0c;本文作者对任何使用本文进行渗透攻击破坏不负任何责任。 引言&#xff1a; Cookie 是一些数据, 存储于你电脑上的文本文件中。当 web 服务器向浏览器发送 web 页面时&#xff0c;在连接关闭后&#xff0c;服务端不会记录用户的信息。Cookie…

加速决策过程:企业级爬虫平台的实时数据分析

摘要 在当今数据驱动的商业环境中&#xff0c;企业如何才能在海量信息中迅速做出精准决策&#xff1f;本文将探讨企业级爬虫平台如何通过实时数据分析加速决策过程&#xff0c;实现数据到决策的无缝衔接。我们聚焦于技术如何赋能企业&#xff0c;提升数据处理效率&#xff0c;…

RK3568 Linux 平台开发系列讲解(内核入门篇):从内核的角度看外设芯片的驱动

在嵌入式 Linux 开发中,外设芯片的驱动是实现操作系统与硬件之间交互的关键环节。对于 RK3568 这样的处理器平台,理解如何从内核的角度构建和管理外设芯片的驱动程序至关重要。 1. 外设驱动的基础概念 外设驱动(Device Driver)是操作系统与硬件设备之间的桥梁。它负责控…

mysql面试(六)

前言 本章节详细讲解了一下mysql执行计划相关的属性释义&#xff0c;以及不同sql所出现的不同效果 执行计划 一条查询语句经过mysql查询优化器的各种基于成本和各种规则优化之后&#xff0c;会生成一个所谓的 执行计划&#xff0c;这个执行计划展示了这条查询语句具体查询方…

【计算机网络】TCP协议详解

欢迎来到 破晓的历程的 博客 ⛺️不负时光&#xff0c;不负己✈️ 文章目录 1、引言2、udp和tcp协议的异同3、tcp服务器3.1、接口认识3.2、服务器设计 4、tcp客户端4.1、客户端设计4.2、说明 5、再研Tcp服务端5.1、多进程版5.2、多线程版 5、守护进程化5.1、什么是守护进程5.2…

基于 HTML+ECharts 实现智慧安防数据可视化大屏(含源码)

构建智慧安防数据可视化大屏&#xff1a;基于 HTML 和 ECharts 的实现 随着科技的不断进步&#xff0c;智慧安防系统已经成为保障公共安全的重要工具。通过数据可视化&#xff0c;安防管理人员可以实时监控关键区域的安全状况、人员流动以及设备状态&#xff0c;从而提高应急响…

【element ui】input输入控件绑定粘贴事件,从 Excel 复制的数据粘贴到输入框(el-input)时自动转换为逗号分隔的数据

目录 1、需求2、实现思路:3、控件绑定粘贴事件事件修饰符说明: 4、代码实现&#x1f680;写在最后 1、需求 在 Vue 2 和 Element UI 中&#xff0c;要实现从 Excel 复制空格分隔的数据&#xff0c;并在粘贴到输入框&#xff08;el-input&#xff09;时自动转换为逗号分隔的数据…

代码随想录训练第三十天|01背包理论基础、01背包、LeetCode416.分割等和子集

文章目录 01背包理论基础01背包二维dp数组01背包一维dp数组(滚动数组) 416.分割等和子集思路 01背包理论基础 背包问题的理论基础重中之重是01背包&#xff0c;一定要理解透&#xff01; leetcode上没有纯01背包的问题&#xff0c;都是01背包应用方面的题目&#xff0c;也就是…

领略诗词之妙,发觉生活之美。

文章目录 引言落霞与孤鹜齐飞,秋水共长天一色。野渡无人舟自横。吹灭读书灯,一身都是月。我醉欲眠卿且去,明朝有意抱琴来。赌书消得泼茶香,当时只道是寻常。月上柳梢头,人约黄昏后。最是人间留不住,朱颜辞镜花辞树。山中何事?松花酿酒,春水煎茶。似此星辰非昨夜,为谁风…

Github 2024-07-26开源项目日报 Top10

根据Github Trendings的统计,今日(2024-07-26统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Java项目2TypeScript项目2C++项目2HTML项目1Python项目1C#项目1Lua项目1JavaScript项目1Vue项目1C项目1免费编程学习平台:freeCodeCamp.org 创…

vuepress搭建个人文档

vuepress搭建个人文档 文章目录 vuepress搭建个人文档前言一、VuePress了解二、vuepress-reco主题个人博客搭建三、vuepress博客部署四、vuepress后续补充 总结 vuepress搭建个人文档 所属目录&#xff1a;项目研究创建时间&#xff1a;2024/7/23作者&#xff1a;星云<Xing…

c++语言学习注意事项

当学习C语言时&#xff0c;有几个重要的注意事项可以帮助初学者更有效地掌握这门强大的编程语言&#xff1a; 1. 理解基本概念和语法 C 是一门复杂且功能强大的编程语言&#xff0c;因此理解其基本概念和语法至关重要。初学者应该重点掌握以下几个方面&#xff1a; 基本语法和…

WordPress原创插件:自定义文章标题颜色

插件设置截图 文章编辑时&#xff0c;右边会出现一个标题颜色设置&#xff0c;可以设置为任何颜色 更新记录&#xff1a;从输入颜色css代码&#xff0c;改为颜色选择器&#xff0c;更方便&#xff01; 插件免费下载 https://download.csdn.net/download/huayula/89585192…

网络基础之(11)优秀学习资料

网络基础之(11)优秀学习资料 Author&#xff1a;Once Day Date: 2024年7月27日 漫漫长路&#xff0c;有人对你笑过嘛… 全系列文档可参考专栏&#xff1a;通信网络技术_Once-Day的博客-CSDN博客。 参考文档&#xff1a; 网络工程初学者的学习方法及成长之路&#xff08;红…

02、爬虫数据解析-Re解析

数据解析的目的是不拿到页面的全部内容&#xff0c;只拿到部分我们想要的内容内容。 Re解析就是正则解析&#xff0c;效率高准确性高。学习本节内容前需要学会基础的正则表达式。 一、正则匹配规则 1、常用元字符 . 匹配除换行符以外的字符 \w 匹配字母或数字或下划…

我当初装anaconda的时候浏览器默认下载路径在d盘,现在想用ipython的时候用不了了咋办?...

点击上方“Python爬虫与数据挖掘”&#xff0c;进行关注 回复“书籍”即可获赠Python从入门到进阶共10本电子书 今 日 鸡 汤 红豆生南国&#xff0c;春来发几枝。 大家好&#xff0c;我是Python进阶者。 一、前言 前几天在Python白银交流群【041】问了一个Python环境的问题&am…

Vue中el的两种写法

大家好我是前端寄术区博主PleaSure乐事。今天了解到了Vue当中有关el的两种写法&#xff0c;记录下来与大家分享&#xff0c;希望对大家有所帮助。 方法一 解释 第一种方法我们直接用new创建并初始化一个新的 Vue 实例&#xff0c;并定义了 Vue 实例的数据对象&#xff0c;在给…

postman请求响应加解密

部分接口&#xff0c;需要请求加密后&#xff0c;在发动到后端。同时后端返回的响应内容&#xff0c;也是经过了加密。此时&#xff0c;我们先和开发获取到对应的【密钥】&#xff0c;然后在postman的预执行、后执行加入js脚本对明文请求进行加密&#xff0c;然后在发送请求&am…