JavaSE 泛型

目录

  • 1 泛型类的定义
    • 1.1 为什么需要泛型
    • 1.2 泛型的概念
    • 1.3 泛型的分类
  • 2 泛型类
    • 2.1 泛型类的定义
    • 2.2 泛型类的例子
    • 2.3 泛型类的实例化
      • 2.3.1 实例化语法
      • 2.3.2 裸类型(Raw Type)
    • 2.4 泛型类的定义-类型边界
    • 2.5 泛型类的使用-通配符(Wildcards)
      • 2.5.1 基本概念
      • 2.5.2 通配符-上界
      • 2.5.3 通配符-下界
    • 2.6 泛型中的父子类型
  • 3 泛型方法
    • 3.1 语法格式
    • 3.2 示例
  • 4 泛型接口
  • 5 类型擦除
    • 5.1 什么是类型擦除
    • 5.2 类型擦除的规则
  • 6 泛型的优缺点

1 泛型类的定义

1.1 为什么需要泛型

假设我们自定义了一个简单的数组类,如下:

package generic2;

import java.util.Stack;
/*
* Object:是所有类的父类
* */
class MyStack{
    public int[] elem;
    public int top;

    public MyStack(){
        this.elem = new int[10];
    }

    public void push(int val){
        this.elem[top] = val;
        top++;
    }

    public int getTop(){
        return this.elem[top-1];
    }
}
public class TestDemo1 {
    public static void main(String[] args) {
       // 创建一个MyStack对象,里面存储int类型的数据
        MyStack myStack = new MyStack();
        myStack.push(1);
       // 但是,如果创建一个MyStack对象,里面想要存储double或者String类型的数据
       // 遗憾的是代码不能通过编译
        myStack.push(1.0);
        myStack.push("feihan");
    }
}

通过上述示例发现,MyStack类中实际只能保存int类型的数据,对于其他类型的数据比如:double、String或者自定义类型的对象,根本无法存储。
想要解决上述问题,最简单的方式就是:对于不同的类型,分别实现各自MyStack类即可,但是估计你可能不愿意。
有大佬是按照如下方式改进的:将上述代码中存储数据的类型全部有int改为Object,因为在Java中Object是所有类的基类。具体代码示例如下所示:

package generic2;

import java.util.Stack;
/*
* Object:是所有类的父类
* */
class MyStack{
    //public int[] elem;
    public Object[] elem;
    public int top;

    public MyStack(){
        //this.elem = new int[10];
        this.elem = new Object[10];
    }

    //public void push(int val){
    public void push(Object val){
        this.elem[top] = val;
        top++;
    }

    //public int getTop(){
    public Object getTop(){
        return this.elem[top-1];
    }
}
public class TestDemo1 {
    public static void main(String[] args) {
        MyStack myStack = new MyStack();
        myStack.push(1);
        myStack.push(1.0);
        myStack.push("feihan");
    }
}

经改过之后的 MyStack终于任意类型都可以存储了,最后:代码只需实现一份,但是任意类型都可以存储,貌似一切都比较美好。
但是大家使用之后,纷纷吐槽:因为Object是所有类的基类,那就意味着可以在一个 MyStack中存储不同种类的数据类型喽:

package generic2;

import java.util.Stack;
/*
* Object:是所有类的父类
* */
class MyStack{
    //public int[] elem;
    public Object[] elem;
    public int top;

    public MyStack(){
        //this.elem = new int[10];
        this.elem = new Object[10];
    }

    //public void push(int val){
    public void push(Object val){
        this.elem[top] = val;
        top++;
    }

    //public int getTop(){
    public Object getTop(){
        return this.elem[top-1];
    }
}
public class TestDemo1 {
    public static void main(String[] args) {
        MyStack myStack = new MyStack();
        myStack.push(1);
        myStack.push(1.0);
        myStack.push("feihan");

        for(int i = 0; i < myStack.size(); ++i){
            String s = (String)myStack.get(i);
            System.out.print(s + " ");
         }
    }
}

虽然代码可以通过编译,但是如果想要遍历MyStack中的数据,怎么遍历啊?
上述代码在运行期间报错:

Exception in thread “main” java.lang.ClassCastException:java.lang.Integer cannot be cast to java.lang.String

运行时出错的原因非常简单:上述代码中,由于MyStack存储数据不都全是String类型的,那如果强转成String类型之后,肯定会发生类型转换异常。

以上就是JDK1.5之前的解决方式,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要作显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以在预知的情况下进行的。对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。为了解决该问题,JDK1.5中引入了泛型。

package generic2;

import java.util.Stack;
/*
* Object:是所有类的父类
* */
class MyStack{
    //public int[] elem;
    public Object[] elem;
    public int top;

    public MyStack(){
        //this.elem = new int[10];
        this.elem = new Object[10];
    }

    //public void push(int val){
    public void push(Object val){
        this.elem[top] = val;
        top++;
    }

    //public int getTop(){
    public Object getTop(){
        return this.elem[top-1];
    }
}
public class TestDemo1 {
    public static void main(String[] args) {
       /*Stack<Integer> stack1 = new Stack<>();
        Stack<String> stack2 = new Stack<>();
        Stack<Double> stack3 = new Stack<>();*/
        
        MyStack myStack = new MyStack();
        myStack.push(1);
        myStack.push(1.0);
        myStack.push("feihan");

        String str = (String) myStack.getTop();
        System.out.println(str);
    }
}

1.2 泛型的概念

泛型是java1.5中增加的一个新特性,通过泛型可以写与类型无关的代码,即编写的代码可以被很多不同类型的对象所重用,经常用在一些通用的代码实现中,比如:java集合框架中的类几乎都是用泛型实现的。

泛型的本质是: 类型参数化。类似函数传参一样,传递不同的实参,函数运行完将会产生不同的结果。

1.3 泛型的分类

泛型主要包含:泛型类、泛型方法和泛型接口,后序逐一进行介绍。

2 泛型类

2.1 泛型类的定义

class 泛型类名称<类型形参列表> {
    // 这里可以使用类型参数
}
class ClassName<T1, T2, ..., Tn> {
    // 类实现体
}

了解: 【规范】类型形参一般使用一个大写字母表示,常用的名称有:

  1. E 表示 Element
  2. K 表示 Key
  3. V 表示 Value
  4. N 表示 Number
  5. T 表示 Type
  6. S, U, V 等等 - 第二、第三、第四个类型

2.2 泛型类的例子

对上述MyStack类进行改造,将其写成泛型类。
注意:以下实现中,没有考虑过多的细节问题,比如插入元素时空间不够如何处理,此处主要演示泛型类的语法规则。
具体代码示例如下所示:

package generic2;

import java.util.Stack;
// 在实现MyStack泛型类时,T具体代表什么类型实现者不关心
// 当对泛型类进行实例化时,编译器才知道T具体代表什么类型
//class MyStack{
class MyStack<T>{
    //public int[] elem;
    //public Object[] elem;
    public T[] elem;
    public int top;

    public MyStack(){
        //this.elem = new int[10];
        //this.elem = new Object[10];
        //this.elem = new T[10];
        // 此处为什么new Object[],为什么需要强转后文中会解释
        this.elem = (T[])new Object[10];
    }

    //public void push(int val){
    //public void push(Object val){
    public void push(T val){
        this.elem[top] = val;
        top++;
    }

    //public int getTop(){
    //public Object getTop(){
    public T getTop(){
        return this.elem[top-1];
    }
}

2.3 泛型类的实例化

2.3.1 实例化语法

泛型类<类型实参> 变量名; 定义一个泛型类引用。
new 泛型类<类型实参>(构造方法实参); 实例化一个泛型类对象。

package generic2;
import java.util.Stack;
/*
* Object:是所有类的父类
*
* 泛型:
* 1.class MyStack<T>  此时的<T>:代表占位符,表示当前这个类是一个泛型类
* 2.this.elem = new T[10]; 此时不能实例化泛型类型的数组对象
* 3.MyStack<Integer> myStack = new MyStack<>();
*   MyStack<Integer> 这里指定当前类可以存放的数据类型
*   new MyStack<>(); 也可以写成new MyStack<Integer>(); 这里的这个Integer写不写都可以
* 4.泛型的意义:
*     a:可以自动进行类型的检查
*     b:可以自动进行类型的转换
* 5.MyStack<int> myStack = new MyStack<>();
*   简单类型不能做泛型类型的参数  包装类型也是引用类型的一种
* 6.泛型到底是怎么编译的? 擦除机制
*   擦除为Object的意义就是:可以放任意类型的数据
*   运行java程序的时候 是没有泛型的概念的
* 7.MyStack<Integer> myStack 泛型类型的参数 不参与类型的组成
* */

// 在实现MyStack泛型类时,T具体代表什么类型实现者不关心
// 当对泛型类进行实例化时,编译器才知道T具体代表什么类型
//class MyStack{
class MyStack<T>{
    //public int[] elem;
    //public Object[] elem;
    public T[] elem;
    public int top;

    public MyStack(){
        //this.elem = new int[10];
        //this.elem = new Object[10];
        //this.elem = new T[10];
        // 此处为什么new Object[],为什么需要强转后文中会解释
        this.elem = (T[])new Object[10];
    }

    //public void push(int val){
    //public void push(Object val){
    public void push(T val){
        this.elem[top] = val;
        top++;
    }

    //public int getTop(){
    //public Object getTop(){
    public T getTop(){
        return this.elem[top-1];
    }
}
public class TestDemo1 {
    public static void main(String[] args) {
        /*Stack<Integer> stack1 = new Stack<>();
        Stack<String> stack2 = new Stack<>();
        Stack<Double> stack3 = new Stack<>();*/

        //MyStack myStack = new MyStack();
        // 将泛型类使用Integer类型来实例化,表明myStack中只能存放Integer类型的对象
        MyStack<Integer> myStack = new MyStack<>();
        myStack.push(1);
        myStack.push(11);
        myStack.push(111);
        //myStack.push(1.0);
        //myStack.push("feihan");

        //String str = (String) myStack.getTop();
        //System.out.println(str);
        // 此处从myStack中获取到的成员,再不需要进行强制类型转换了
        int a = myStack.getTop();
        System.out.println(a);

        MyStack<String> myStack2 = new MyStack<>();
        myStack2.push("feihan");

        //假设不指定泛型的类型参数
        /*
        * 强制压制警告
        * @SuppressWarnings("unchecked")
        * MyStack<String> myStack3 = new MyStack();
        * */
        MyStack myStack3 = new MyStack();
        myStack3.push(1);
        myStack3.push("feihan");
        myStack3.push(1.0);
        //这里为啥三种类型都可以,因为我们发现假设不指定泛型的类型参数,它默认为Object类
    }
}

注意:

  1. 右侧<>中的类型可以省略
MyStack<Integer> myStack = new MyStack<>();

在new MyStack<>()对象时,<>中未明确指明类型,编译器会根据=左侧<>中的类型来推演。

  1. 左侧<>中的类型不能省略
MyStack<> myStack = new MyStack<Integer>();// 省略之后,编译失败

编译器在推演时,是根据左侧类型来推演右侧的。

  1. 虽然右侧<>可以不用写类型,但是<>不能省略
MyStack<String> myStack3 = new MyStack();// 自己永远不要这么用

上述代码,会产生编译警告:

Note: Example.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.

可以使用 @SuppressWarnings 注解进行警告压制:

@SuppressWarnings("unchecked")

2.3.2 裸类型(Raw Type)

裸类型是一个泛型类但没有带着类型实参,例如MyStack就是一个裸类型

MyStack myStack3 = new MyStack();

注意: 我们不要自己去使用裸类型,裸类型是为了兼容老版本的 API 保留的机制。
通过上面代码中的最后myStack3这一部分可以看到:如果类型裸类型时,泛型类中的T会被默认当成Object来处理,那就回到了JDK1.5之前的情况。下面的类型擦除部分,我们也会讲到编译器是如何使用裸类型的。

2.4 泛型类的定义-类型边界

在定义泛型类时,有时需要对传入的类型变量做一定的约束,可以通过类型边界来约束。

class 泛型类名称<E extends U> {
...
}

在实例化时,E只能是U的子类,否则编译会报错。
具体示例代码1:

package generic2;
import java.util.Stack;
/*
* 写一个泛型类算法,找到list当中的最大值
* */

//将来对Algorithm进行实例化时,实例化的类型必须要是Comparable<T>的子类才可以
//class Algorithm<T>{
class Algorithm<T extends  Comparable<T> >{
    public T findMaxVal(T[] array){
        T max = array[0];
        for (int i = 1; i < array.length ; i++) {
            //if(array[i] >= max){   这里为啥会报错?---->因为T类型是一个引用类型,引用类型只能用compareTo来比较大小,用equals来比较相等
            //if(array[i].compareTo(max) >= 0){  T类型引用的擦除机制擦除为Object类型,但Object中没有compareTo这个接口,所以这里会报错
            //修改方法为: class Algorithm<T extends  Comparable<T> >
            if (array[i].compareTo(max) >= 0)
                max = array[i];
        }
        return max;
    }
}
/*
* 泛型方法
* */
class Algorithm2{
    public static<T extends  Comparable<T>> T findMaxVal(T[] array){
        T max = array[0];
        for (int i = 1; i < array.length ; i++) {
            //if(array[i] >= max){   这里为啥会报错?---->因为T类型是一个引用类型,引用类型只能用compareTo来比较大小,用equals来比较相等
            //if(array[i].compareTo(max) >= 0){  T类型引用的擦除机制擦除为Object类型,但Object中没有compareTo这个接口,所以这里会报错
            //修改方法为: class Algorithm<T extends  Comparable<T> >
            if (array[i].compareTo(max) >= 0)
                max = array[i];
        }
        return max;
    }
}
class Person{

}
public class TestDemo1 {
    public static void main(String[] args) {
        Integer[] array = {1,2,3,4,5,6,7};
        System.out.println(Algorithm2.findMaxVal(array));
        System.out.println(Algorithm2.<Integer>findMaxVal(array));
    }
    public static void main3(String[] args) {
        Algorithm<Integer> algorithm = new Algorithm<>();
        Integer[] array = {1,2,3,4,5,6,7};
        System.out.println(algorithm.findMaxVal(array));

        //Algorithm<Person> algorithm1 = new Algorithm<>();
    }}

具体示例代码2:

// 将来对MyArray进行实例化时,实例化的类型必须要是Animal的子类才可以
public class MyArray<E extends Animal> {
    private E[] array = null;
    private int size;
    private int capacity;
    public MyArray(int capacity){
    array = (E[])new Object[capacity];
    size = 0;
    this.capacity = capacity;
   }
   // ...
   public static void main(String[] args) {
      // 编译成功,因为Dog是Animal的子类
      MyArray<Dog> m1 = new MyArray<>(10);
      m1.add(new Dog("旺财"));
      m1.add(new Dog("二哈"));
     // 编译成功,因为Cat是Animal的子类
      MyArray<Cat> m2 = new MyArray<>(10);
      m2.add(new Cat("肥波"));
      m2.add(new Cat("加菲"));
     // 编译失败,因为String不是Animal的子类
      MyArray<String> m3 = new MyArray<>(10);
}
}

注意: 没有指定类型边界 E,可以视为 E extends Object。

2.5 泛型类的使用-通配符(Wildcards)

2.5.1 基本概念

? 用于在泛型的使用,即为通配符。
具体示例代码1:

package generic2;

import java.util.ArrayList;
import java.util.Stack;
/*
* Object:是所有类的父类
*
* 泛型:
* 1.class MyStack<T>  此时的<T>:代表占位符,表示当前这个类是一个泛型类
* 2.this.elem = new T[10]; 此时不能实例化泛型类型的数组对象
* 3.MyStack<Integer> myStack = new MyStack<>();
*   MyStack<Integer> 这里指定当前类可以存放的数据类型
*   new MyStack<>(); 也可以写成new MyStack<Integer>(); 这里的这个Integer写不写都可以
* 4.泛型的意义:
*     a:可以自动进行类型的检查
*     b:可以自动进行类型的转换
* 5.MyStack<int> myStack = new MyStack<>();
*   简单类型不能做泛型类型的参数  包装类型也是引用类型的一种
* 6.泛型到底是怎么编译的? 擦除机制
*   擦除为Object的意义就是:可以放任意类型的数据
*   运行java程序的时候 是没有泛型的概念的
* 7.MyStack<Integer> myStack 泛型类型的参数 不参与类型的组成
* 8.泛型的上界:
*   class Algorithm<T extends  Comparable<T> >{}
*   T:T类型 一定要实现Comparable接口
*
*   class Algorithm<T extends  Animal >{}
*   E:可以是Animal的子类 或者是 Animal自己类本身
* 9.泛型没有下界
* 10.泛型方法(一定是静态的):
*   public static<T> T findMaxVal(T[] array){
*   public static<T extends  Comparable<T>> T findMaxVal(T[] array){
* 11.通配符:通配符实际上也是一种泛型。一般用在源码当中居多一点。
*    泛型一般用于读取和写入
*    通配符一般用于读取
*
*    上界:<? extends E>表示传入的参数? 是上界E的子类或者E自己本身
*    下界:<? super E> 表示传入的参数? 是下界E的父类或者E自己本身
* 12.ArrayList<Integer> list1 和ArrayList<Number> list2 他们直接是否构成父子类关系?
*    不是这样子的:之前说过了<>里面的内容会被擦除
* */


/*
* 写一个泛型方法 打印一个list当中的所有的数据
* 通配符:通配符实际上也是一种泛型。一般用在源码当中居多一点。
* 泛型一般用于读取和写入
* 通配符一般用于读取
*
* 上界:<? extends E>表示传入的参数? 是上界E的子类或者E自己本身
* 下界:<? super E> 表示传入的参数? 是下界E的父类或者E自己本身
* */
class Test{
   /* public static<T> void print(ArrayList<T> list){
        for (T x:list) {
            System.out.println(x);
        }
    }*/
   public static void print(ArrayList<?> list){
       for (Object x:list) {
           System.out.println(x);
       }
   }
}
public class TestDemo1 {
    public static void main(String[] args) {
        //Integer extends Number
        ArrayList<Integer> list1 = new ArrayList<>();
        ArrayList<Number> list2 = new ArrayList<>();
        list2.addAll(list1);
    }
    public static void main5(String[] args) {
        ArrayList<Integer> list1 = new ArrayList<>();
        list1.add(1);
        list1.add(2);
        list1.add(3);
        Test.print(list1);
        ArrayList<Double> list2 = new ArrayList<>();
        list2.add(1.0);
        list2.add(2.0);
        list2.add(3.0);
        Test.print(list2);
    }}

具体示例代码2:

public class MyArray<E> {...}

// 可以传入任意类型的 MyArray
public static void printAll(MyArray<?> m) {
...
}
// 以下调用都是正确的
printAll(new MyArray<String>());
printAll(new MyArray<Integer>());
printAll(new MyArray<Double>());
printAll(new MyArray<Number>());
printAll(new MyArray<Object>());

2.5.2 通配符-上界

语法:

<? extends 上界>

具体示例代码1:

// 传入类型实参是 Animal 子类的任意类型的 MyArray
public static void printAll(MyArray<? extends Animal> m) {
...
}
// 以下调用都是正确的
printAll(new MyArray<Cat>());
printAll(new MyArray<Dog>());
// 以下调用是编译错误的
printAll(new MyArray<String>());
printAll(new MyArray<Object>());

注意: 需要区分 泛型使用中的通配符上界 和 泛型定义中的类型上界。

2.5.3 通配符-下界

语法:

<? super 下界>

具体示例代码1:

// 可以传入类型实参是 Cat 父类的任意类型的 MyArray
public static void printAll(MyArray<? super Cat> list) {
...
}
// 以下调用都是正确的
printAll(new MyArrayList<Cat>());
printAll(new MyArrayList<Animal>());
printAll(new MyArrayList<Object>());
// 以下调用是编译错误的
printAll(new MyArrayList<String>());
printAll(new MyArrayList<Dog>());

2.6 泛型中的父子类型

具体示例代码1:

public class MyArray<E> { ... }
// MyArray<Object> 不是 MyArray<Animal> 的父类型
// MyArray<Animal> 也不是 MyArray<Cat> 的父类型
// 需要使用通配符来确定父子类型
// MyArray<?> 是 MyArray<? extends Animal> 的父类型
// MyArray<? extends Animal> 是 MyArrayList<Dog> 的父类型

3 泛型方法

3.1 语法格式

方法限定符 <类型形参列表> 返回值类型 方法名称(形参列表) { … }

3.2 示例

具体示例代码1:

public class Util {
   public static <E> void swap(E[] array, int i, int j) {
        E t = array[i];
        array[i] = array[j];
        array[j] = t;
    }
}

// 没有显式指定类型,编译期间需要进行类型推到
Integer[] a = { ... };
swap(a, 0, 9);
String[] b = { ... };
swap(b, 0, 9);
// 显式指定类型,编译期间,不用进行类型推导
Integer[] a = { ... };
Util.<Integer>swap(a, 0, 9);
String[] b = { ... };
Util.<String>swap(b, 0, 9);

4 泛型接口

// 与定义泛型类非常相似---该接口主要是用来对对象进行比较的
// 比如sort方法,可以排任意类型的数据,可以排升序也可以排降序
// sort在排序过程中,元素的比较规则就可以通过来实现该 泛型接口 来处理
public interface Comparator<T> {
    int compare(T o1, T o2);
}

5 类型擦除

5.1 什么是类型擦除

Java泛型这个特性是从JDK 1.5才开始加入的,因此为了兼容之前的版本,Java泛型的实现采取了“伪泛型”的策略,即Java在语法上支持泛型,但是在编译阶段会进行所谓的“类型擦除”(Type Erasure),将所有的泛型表示(尖括号中的内容)都“替换”为具体的类型(其对应的原生态类型),就像完全没有泛型一样。 即泛型类和普通类在 java 虚拟机内是没有什么特别的地方。
注意:

  1. 泛型:只存在于编译时期 只是编译时期
  2. 泛型的意义:
    a:自动进行类型的检查
    b:自动进行类型转换
  3. 泛型在编译的时候,并不会进行指定类型的替换,而是拿着指定的类型进行检查,也就是说在编译的时候,拿着你指定的类型进行检查,记住并没有说是替换。
  4. 编译的时候会进行类型擦除,编译的时候 编译都会把泛型擦除为Object,不是替换为Object。

在这里插入图片描述

5.2 类型擦除的规则

泛型的类型擦除原则是:

  1. 消除类型参数声明,即删除<>及其包围的部分。
  2. 根据类型参数的上下界推断并替换所有的类型参数为原生态类型:如果类型参数是无限制通配符或没有上下界限定则替换为Object,如果存在上下界限定则根据子类替换原则取类型参数的最左边限定类型(即父类)。
  3. 为了保证类型安全,必要时插入强制类型转换代码。
  4. 自动产生“桥接方法”以保证擦除类型后的代码仍然具有泛型的“多态性”。
// 1. 无限制类型擦除---<E>和<?>类型参数都被替换为Object
class MyArray<E> {
   // E 会被擦除为 Object
}

// 2. 有限制类型擦除---<T extends Animal>和<? extends Animal>的类型参数被替换为Animal
// <? super Animal>被替换为Object
class MyArray<E extends Animal> {
   // E 被擦除为 Animal
}

// 3. 擦除方法中的类型参数
public class Util {
   public static <E> void swap(E[] array, int i, int j) {
   // ...
   // <E>删除掉 E被擦除为Object
}
}

总结: 即类型擦除主要看其类型边界而定。
注意: 编译器在类型擦除阶段在做什么?

  1. 将类型变量用擦除后的类型替换,即 Object 或者 Comparable;
  2. 加入必要的类型转换语句;
  3. 加入必要的 bridge method 保证多态的正确性。

6 泛型的优缺点

泛型的优点:

  1. 提高代码的复用性;
  2. 提高开发效率;
  3. 可以实现一些通用类型的容器或算法。

泛型的缺点:

  1. 泛型类型参数不支持基本数据类型;
  2. 无法实例化泛型类型的对象;
  3. 无法使用泛型类型声明静态的属性;
  4. 无法使用 instanceof 判断带类型参数的泛型类型;
  5. 无法创建泛型类数组;
  6. 无法 create、catch、throw 一个泛型类异常(异常不支持泛型);
  7. 泛型类型不是形参一部分,无法重载。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

14、Kafka 请求是怎么被处理的

Kafka 请求是怎么被处理的 1、处理请求的 2 种常见方案1.1、顺序处理请求1.2、每个请求使用单独线程处理 2、Kafka 是如何处理请求的&#xff1f;3、控制类请求和数据类请求分离 无论是 Kafka 客户端还是 Broker 端&#xff0c;它们之间的交互都是通过 “请求 / 响应” 的方式完…

Hypervisor Display架构

Hypervisor Display架构部分 1&#xff0c;所有LA侧的APP与显示相关的调用最终都会交由SurfaceFlinger处理 2&#xff0c;SurfaceFlinger会最终调用android.hardware.graphics.composer2.4-service服务 3&#xff0c;android.hardware.graphics.composer2.4-service服务会调用G…

针对企业的泄密,天锐绿盾提出十大解决方案

01 防止公司内部数据泄密 通过动态加解密技术&#xff0c;有效防止公司内部数据泄密。即员工在创建、编辑文档时会被自动加密存放在硬盘上&#xff0c;防止员工故意或由于疏忽而造成泄密或对文件恶意破坏。 管理思路>> ● 不改变员工使用习惯、不改变文件格式、不改变…

APM固件编译和仿真

事情起因 主要想对无人机APM固件进行仿真的算法验证&#xff0c;因实际飞行的过程实际验证太浪费飞机了&#xff0c;所以就先试用仿真对算法进行仿真开发。 一&#xff0c;环境搭建 环境搭建我建议参考官方英文教程&#xff0c;英文教程写的比较全&#xff0c;不懂可以自己使…

科聪控制系统典型应用车型 —— 料箱机器人

料箱机器人即料箱AGV是一种智能化物流搬运设备&#xff0c;它可以代替人力完成出库入库和搬运工作&#xff0c;可根据出入库生产出货需求&#xff0c;将货物从起点运送到终点&#xff0c;自动柔性完成货到人货到点的操作。 提升仓储和物流效率的自动化利器 料箱机器人的投用能…

yolov5单目测距+速度测量+目标跟踪(算法介绍和代码)

要在YOLOv5中添加测距和测速功能&#xff0c;您需要了解以下两个部分的原理&#xff1a; 单目测距算法 单目测距是使用单个摄像头来估计场景中物体的距离。常见的单目测距算法包括基于视差的方法&#xff08;如立体匹配&#xff09;和基于深度学习的方法&#xff08;如神经网…

C语言--字符函数与字符串函数

大家好&#xff0c;我是残念&#xff0c;希望在你看完之后&#xff0c;能对你有所帮助&#xff0c;有什么不足请指正&#xff01;共同学习交流 本文由残念ing 原创CSDN首发&#xff0c;如需要转载请通知 个人主页&#xff1a;残念ing-CSDN博客&#xff0c;欢迎各位→点赞&#…

leetcode---76. 最小覆盖子串 [C++/滑动窗口+哈希表]

原题&#xff1a;76. 最小覆盖子串 - 力扣&#xff08;LeetCode&#xff09; 题目解析&#xff1a; 此题在这道题的基础上进行理解会更简单 leetcode --- 30. 串联所有单词的子串[C 滑动窗口/双指针]-CSDN博客 本题要求在s字符串中找到含有t字符串所有字符的最短子串。 也就是…

【lesson17】MySQL表的基本操作--表去重、聚合函数和group by

文章目录 MySQL表的基本操作介绍插入结果查询&#xff08;表去重&#xff09;建表插入数据操作 聚合函数建表插入数据操作 group by&#xff08;分组&#xff09;建表插入数据操作 MySQL表的基本操作介绍 CRUD : Create(创建), Retrieve(读取)&#xff0c;Update(更新)&#x…

XAgent的部署及运行

源代码clone git clone config 文件的修改 在XAgent源码目录&#xff0c;运行 vi .env&#xff0c; 修改以下配置条目 CONFIG_FILEassets/gpt-3.5-turbo_config.ymlpython环境 python >3.10 安装conda&#xff0c;通过conda激活python3.10的环境 wget https://repo.a…

josef约瑟 跳合位、电源监视继电器 HRTH-Y-2H2D DC220V

系列型号&#xff1a; HRTH-Y-2H2D-X-T跳位监视、合位监视、电源监控继电器&#xff1b; HRTH-Y-2Z-X-T跳位监视、合位监视、电源监控继电器&#xff1b; HRTH-Y-2H-X-T跳位监视、合位监视、电源监控继电器&#xff1b; HRTH-J-2H2D-X-T跳位监视、合位监视、电源监控继电器…

Axure中继器的基本使用

介绍中继器 在 Axure 中&#xff0c;中继器是一种交互设计元素&#xff0c;用于在不同页面之间传递数据或触发特定的事件。它可以帮助模拟真实的用户交互流程和页面之间的传递逻辑&#xff0c;继承关系用于描述两个元件之间的父子关系。通过使用继承关系&#xff0c;您可以创建…

Linux的SSH(远程登录)

SSH定义&#xff1a; SSH&#xff08;Secure Shell 的缩写&#xff09;是一种网络协议&#xff0c;用于加密两台计算机之间的通信&#xff0c;并且支持各种身份验证机制。 实务中&#xff0c;它主要用于保证远程登录和远程通信的安全&#xff0c;任何网络服务都可以用这个协议…

深度学习笔记_7经典网络模型LSTM解决FashionMNIST分类问题

1、 调用模型库&#xff0c;定义参数&#xff0c;做数据预处理 import numpy as np import torch from torchvision.datasets import FashionMNIST import torchvision.transforms as transforms from torch.utils.data import DataLoader import torch.nn.functional as F im…

自定义 spring-boot组件自动注入starter

1&#xff1a;创建maven项目 2&#xff1a;pom文件 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocati…

stm32与Freertos入门(二)移植FreeRTOS到STM32中

简介 注意&#xff1a;FreeRTOS并不是实时操作系统&#xff0c;而是分时复用的&#xff0c;只不过切换频率很快&#xff0c;感觉上是同时在工作。本次使用的单片机型号为STM32F103C8T6,通过CubeMX快速移植。 一、CubeMX快速移植 1、选择芯片 打开CubeMX软件&#xff0c;进行…

轻量封装WebGPU渲染系统示例<53>- 多盏灯灯光照在地面的效果

WebGPU实时渲染实现模拟多盏灯的灯光照在地面的效果灯光效果 。 当前示例源码github地址: https://github.com/vilyLei/voxwebgpu/blob/feature/material/src/voxgpu/sample/MultiLightsTest.ts 当前示例运行效果: 此示例基于此渲染系统实现&#xff0c;当前示例TypeScript源…

Ribbon负载均衡原理、策略、饥饿加载

Ribbon负载均衡原理、策略、饥饿加载 MapperScan("cn.itcast.order.mapper") SpringBootApplication public class OrderApplication {public static void main(String[] args) {SpringApplication.run(OrderApplication.class, args);}/*** 完成创建RestTemplate&am…

虾皮 选品:如何在虾皮平台上进行有效的选品?

在虾皮&#xff08;Shopee&#xff09;这个跨境电商平台上&#xff0c;选品对于卖家来说至关重要。选品决定了店铺的销售额和竞争力。为了帮助卖家进行选品&#xff0c;虾皮平台提供了一些免费的选品工具&#xff0c;如知虾。同时&#xff0c;还有一些第三方选品工具&#xff0…
最新文章