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 NumberArrayList<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.hqwc.cn/news/286594.html

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

相关文章

【09】ServiceEntry使用案例

案例背景 为了便于测试&#xff0c;我们用非网格化的名称空间中运行的应用来模拟运行于VM/萝服务上的外部服务&#xff0c;假设&#xff1a; 在网格外部运行nginx服务&#xff0c;有2个实例 Nginx2001:监听地址为172.29.1.201:8091&#xff0c;nginx版本为1.20nginx2002&#x…

c语言编写http服务器(Linux下运行)

参考文章&#xff1a;https://blog.csdn.net/baixingyubxy/article/details/125964986?spm1001.2014.3001.5506 上面是详细讲解&#xff0c;我这篇是总结了他的代码&#xff0c;因为他没给整体代码 所有代码&#xff1a; #include <stdio.h> #include <stdlib.h&g…

DDD领域驱动设计

DDD 领域驱动实践 业务初期由于业务简单 只要简单的crud就可以满足。这个时候系统功能是清晰的。但是随着疯狂的迭代 不断的业务演化。业务逻辑越来越复杂。系统也越来越冗余。模块彼此关联。资深业务开发也很难说清楚这一块会涉及到什么功能。这个时候要基于这个版本去做迭代…

【深度学习目标检测】九、基于yolov5的路标识别(python,目标检测)

YOLOv5是目标检测领域一种非常优秀的模型&#xff0c;其具有以下几个优势&#xff1a; 1. 高精度&#xff1a;YOLOv5相比于其前身YOLOv4&#xff0c;在目标检测精度上有了显著的提升。YOLOv5使用了一系列的改进&#xff0c;如更深的网络结构、更多的特征层和更高分辨率的输入图…

金融数据可视化大屏,开启数字时代的金融新篇章

随着数字化时代的到来&#xff0c;金融行业的数据量正在迅速增长。如何有效处理、分析和呈现这些数据&#xff0c;成为了一个亟待解决的问题。而金融数据可视化大屏的出现&#xff0c;正是为了解决这一问题&#xff0c;让金融行业的数据处理和分析更加直观、高效。 一、金融数据…

网络的发展历史,ip地址

TCP/IP 是获得最广泛支持的通信协议集合 包含了大量internet应用的标准协议 -支持跨网络架构&#xff0c;跨操作系统平台的通信 主机与主机之间通信的三个要素 1.ip地址(ip address) 2.子网掩码(subent mask) 3.ip路由(ip router) ip地址&#xff1a; 作用&#xff1a;用…

实时时钟(RTC)的选择与设计:内置晶体与外置晶体的优缺点对比

实时时钟(RTC)作为一种具备独立计时和事件记录功能的设备&#xff0c;现已广泛应用于许多电子产品中&#xff0c;并对时钟的精度要求越来越高。根据封装尺寸、接口方式、附加功能、时钟精度和待机功耗等因素进行分类&#xff0c;市场上有各种种类的RTC产品可供选择。 而在设计…

webpack知识点总结(基础应用篇)

一、为什么需要webpack 1.为什么使用webpack ①传统的书写方式&#xff0c;加载太多脚本会导致网络瓶颈&#xff0c;如不小心改变JavaScript文件加载顺序&#xff0c;项目会崩溃&#xff0c;还会导致作用域问题、js文件太大无法做到按需加载、可读性和可维护性太低的问题。 ②…

node.js mongoose中间件(middleware)

目录 简介 定义模型 注册中间件 创建doc实例&#xff0c;并进行增删改查 方法名和注册的中间件名相匹配 执行结果 分析 错误处理中间件 手动抛出错误 注意点 简介 在mongoose中&#xff0c;中间件是一种允许在执行数据库操作前&#xff08;pre&#xff09;或后&…

数据结构(Chapter Two -02)—顺序表基本操作实现

在前一部分我们了解线性表和顺序表概念&#xff0c;如果有不清楚可以参考下面的博客&#xff1a; 数据结构(Chapter Two -01)—线性表及顺序表-CSDN博客 首先列出线性表的数据结构&#xff1a; #define MaxSize 50 //定义顺序表最大长度 typedef struct{ElemType data…

Next.js 学习笔记(三)——路由

路由 路由基础知识 每个应用程序的骨架都是路由。本页将向你介绍互联网路由的基本概念以及如何在 Next.js 中处理路由。 术语 首先&#xff0c;你将在整个文档中看到这些术语的使用情况。以下是一个快速参考&#xff1a; 树&#xff08;Tree&#xff09;&#xff1a;用于可…

制造企业可以通过哪些措施改善设备OEE

设备综合效率OEE&#xff08;Overall Equipment Effectiveness&#xff09;是制造企业衡量设备效率的关键指标之一。高效的设备运行对于提高生产效率、降低成本和实现竞争优势至关重要。然而&#xff0c;实现高水平的设备OEE并不是一项简单的任务。本文将介绍一些制造企业可以采…