Java高级编程—泛型
文章目录
- 1.为什么要有泛型 (Generic)
- 1.1 泛型的概念
- 1.2 使用泛型后的好处
- 2.在集合中使用泛型
- 3.自定义泛型结构
- 3.1 自定义泛型类、泛型接口
- 3.2 自定义泛型方法
- 4.泛型在继承上的体现
- 5.通配符的使用
- 5.1 基本使用
- 5.2 有限制的通配符的使用
1.为什么要有泛型 (Generic)
Java中的泛型就类似一个标签(Label)。比如在中药店,每个抽屉外面贴着标签,用于标记里面放的药材是什么。又比如在超市购物架上有很多瓶子,每个瓶子装的是什么,也有标签作标识。

泛型的设计背景:
集合容器类在设计阶段/声明阶段不能确定这个容器到底实际存的是什么类型的对象,所以在 JDK1.5 之前只能把元素类型设计为Object,JDK1.5 之后使用泛型来解决。因为这个时候除了元素的类型不确定,其他的部分是确定的,例如关于这个元素如何保存,如何管理等是确定的,因此此时把元素的类型设计成一个参数,这个类型参数叫做泛型。Collection,List,ArrayList, 这个就是类型参数,即泛型。
1.1 泛型的概念
所谓泛型,就是允许在定义类、接口时通过一个标识表示类中某个属性的类型或者是某个方法的返回值及参数类型。这个类型参数将在使用时(例如,继承或实现这个接口,用这个类型声明变量、创建对象时)确定(即传入实际的类型参数,也称为类型实参)。
从JDK1.5以后,Java引入了“参数化类型(Parameterized type)”的概念, 允许我们在创建集合时再指定集合元素的类型,正如:List,这表明 该List只能保存字符串类型的对象。
JDK1.5改写了集合框架中的全部接口和类,为这些接口、类增加了泛型支持,从而可以在声明集合变量、创建集合对象时传入类型实参。
1.2 使用泛型后的好处
直接使用Object也可以存储数据,那么为什么要用泛型呢?
- 解决元素存储的安全性问题,好比商品、药品标签,不会弄错。
- 解决获取数据元素时,需要类型强制转换的问题,好比不用每回拿商品、药品都要辨别。
在集合中没有泛型时:

在集合中有泛型时:

Java泛型可以保证如果程序在编译时没有发出警告,运行时就不会产生 ClassCastException异常。同时,代码更加简洁、健壮。
2.在集合中使用泛型
在这一部分我们来验证一下1.2节中提到的在集合中使用泛型所带来的好处。
首先来看一下在集合中没有使用泛型时的情况:
//在集合中使用泛型之前的情况:
@Test
public void test1(){ArrayList list = new ArrayList();//需求:存放学生成绩list.add(78);list.add(76);list.add(89);list.add(88);//问题一:类型不安全list.add("kaixuan");for(Object score : list){//问题二:强转时,可能出现ClassCastExceptionint stuScore = (Integer) score;System.out.println(stuScore);}
}
在上述代码块中,我们声明了一个ArrayList对象list,(ArrayList的本质:对象引用的“变长”数组),然后往里面添加了4个 int 类型的学生成绩和一个String类型的值"kaixuan"。但是这个时候并不会报编译错误,因为现在list里面可以添加的是Object类型的,因此就会出现前面提到的类型不安全的问题。接着我们去遍历一下 list 集合中的元素,由于我们需要获取到的是 int 类型的值,而 list 里面还存放有别的类型的数据,因此需要强制类型转换。那么在这一步骤就有可能出现“类型转换异常”。
测试结果如下:
可以看到,提示 String类型不能强转成 Integer 类型。
接下来我们来看一下在集合中使用了泛型的情况,以ArrayList为例。
@Test
public void test2(){//泛型是一个类型,它不能是基本数据类型,所以需要使用基本数据类型的包装类//下面的这个是标准的写法//ArrayList<Integer> list = new ArrayList<Integer>();//jdk7新特性:类型推断。 所以后面的泛型类型可以省略不写ArrayList<Integer> list = new ArrayList<>();list.add(78);list.add(99);list.add(100);//编译时,就会进行类型检查,保证数据的安全。//list.add("dabing"); //现在要添加的是一个String类型,不是Integer类型的,所以编译不通过//遍历方式一:for(Integer score : list){//避免了强转操作int stuScore = score;System.out.println(stuScore);}System.out.println("----------------------------------");//方式二:Iterator<Integer> iterator = list.iterator();while (iterator.hasNext()){int stuScore = iterator.next();System.out.println(stuScore);}
}
上述代码块中,我们首先声明了一个存放 Integer 类型数据的 ArrayList类的对象 list。而之所以可以这样声明是因为Java中的集合接口或集合类在 jdk5.0 时都修改为带泛型的结构。如下图所示:

所以我们在实例化集合类时,可以指明具体的泛型类型。指明完以后,在集合类或接口中凡是定义类或接口时,内部结构(比如:方法、构造器、属性等)使用到类的泛型的位置,都指定为实例化的泛型类型。比如:add(E e) —> 实例化以后:add(Integer e)。
接着我们在 list 中添加了三个 int 类型的数据和一个String类型的数据"dabing",那么这个时候编译就会给出警告了,因为我们指定了只能添加Integer类型的数据,现在要添加的是一个String类型的。如下图所示:

所以去除掉不符合要求的数据,这一过程其实就是IDE帮我们做了一个类型检查。最后实现对 list 中的元素的遍历即可,由于使用了泛型,所以在遍历时就避免了强转的操作。我们以两种方式完成遍历:增强 for 循环和 迭代器。
测试结果如下:

注意点:1.泛型的类型必须是类,不能是基本数据类型。需要用到基本数据类型的位置,拿包装类替换。
2.如果实例化时,没有指明泛型的类型。默认类型为java.lang.Object类型。
3.自定义泛型结构
3.1 自定义泛型类、泛型接口
由于类和接口在声明上的相似性,这里把自定义泛型类和自定义泛型接口放在一起讨论。
自定义泛型类的声明:
interface List<T>
自定义泛型接口的声明:
class GenTest<K,V>
其中,T,K,V 不代表值,而是表示类型。这里使用任意字母都可以。 常用 T 表示,是Type的缩写。
泛型类、泛型接口的实例化:
一定要在类名后面指定类型参数的值(类型)。如:
List<String> strList = new ArrayList<String>();
Iterator<Customer> iterator = customers.iterator();
下面来看一个具体的例子:
import java.util.ArrayList;
import java.util.List;/*
* 自定义泛型类
* */
public class Order<T> { //这个T是什么类型现在还不知道,实例化的时候才能知道,所以这里当作是一个参数String orderName;int orderId;//类的内部结构就可以使用类的泛型T orderT;public Order(){}public Order(String orderName, int orderId, T orderT){this.orderName = orderName;this.orderId = orderId;this.orderT = orderT;}public T getOrderT() {return orderT;}public void setOrderT(T orderT) {this.orderT = orderT;}@Overridepublic String toString() {return "Order{" +"orderName='" + orderName + '\'' +", orderId=" + orderId +", orderT=" + orderT +'}';}}
在上述代码块中,我们声明了一个名为 Order 的泛型类。(由于在类名后加了,所以Order 就是一个泛型类,那么在该类的内部就可以使用这个泛型了。)在 Order 类中声明了两个成员变量orderName 和 orderId,同时声明了一个 T 类型的成员变量 orderT,这个 T 是什么类型现在还不知道,只有等到实例化 Order类 的时候才能知道。接着创建了该类的无参和带参的两个构造器,注意到,泛型类的构造器是不能加<>符号的,创建格式如下:
public GenericClass(){
}
最后为orderT属性添加了get 、set方法,重写了toString方法。
下面我们针对声明的泛型类 Order 做出一些测试,首先做一下实例化操作,创建两个Order类的对象。
@Test
public void test1(){//如果定义了泛型类,实例化没有指明类的泛型,则认为此泛型类型为Object类型(不建议这样写)//要求:如果定义了类是带泛型的,建议在实例化时要指明类的泛型。Order order = new Order();order.setOrderT(123);order.setOrderT("ABC");System.out.println(order.getOrderT());//建议:实例化时指明类的泛型 (且实例化的时候后面要补上<>)Order<String> order1 = new Order<>("orderAA", 1001, "order:AA");order1.setOrderT("AA:hello");System.out.println(order1.getOrderT());}
如果在实例化没有指明类的泛型,则认为此泛型类型为Object类型, 也就是类型会被擦除,泛型对应的类型均按照Object处理,但不等价于Object。如上述代码块中创建的order 对象,由于实例化时没有指定泛型的结构,所以在调用setOrderT()时可以传入任意类型的参数。但不建议不指定泛型结构的这种写法。所以一般我们要求:如果定义了的类是带泛型的,建议在实例化时要指明该类的泛型,如上述代码块中创建对象order1 一样,只要我们指定了具体的类型,那么在后续的使用中编译器就会自动帮我们做类型的检查。如下图所示,在指定了 T 为String 后,在需要用到 T 的地方就自动给我们限定了是String 类型的了。

测试结果如下:
下面我们来测试一下继承了泛型类的子类的实例化。
首先声明两个Order类的子类:SubOrder 和 SubOrder1
SubOrder类的设计如下:
public class SubOrder extends Order<Integer> {//因为这个子类已经指明了泛型的结构,所以SubOrder这个子类就不再是泛型类了}
我们在 SubOrder 类中指定了泛型的结构,所以SubOrder这个子类就不再是泛型类了。(即SubOrder类名后就不要跟<>了,而且在实例化SubOrder类时也不再需要指明泛型的类型,只需把它当作普通类去实例化即可。)
下面给出SubOrder的实例化测试:
@Test
public void test2(){SubOrder sub1 = new SubOrder();//由于子类在继承带泛型的类时指明了泛型类型,则实例化子类对象时,不再需要指明泛型。(也可以理解为:此时的子类已经不是泛型类了)sub1.setOrderT(13);System.out.println(sub1.getOrderT().getClass().getName());
}
可见,在实例化时不再需要指明泛型。由于我们指定了SubOrder类中orderT的类型为Intgeger,所以最后输出验证一下该成员变量的类型。
测试结果如下:

SubOrder1类的设计如下:
public class SubOrder1<T> extends Order<T>{ //SubOrder1<T>:仍然是泛型类
}
在SubOrder1类中,没有指明泛型的结构,所以此时SubOrder1类还是一个泛型类。那么实例化的时候就需要像上述Order类那样实现了。下面给出测试程序:
@Test
public void test2(){SubOrder1<String> sub2 = new SubOrder1<>();sub2.setOrderT("order2....");System.out.println(sub2.getOrderT().getClass().getName());
}
测试结果如下:

此外,关于泛型类和泛型接口还有一些别的规定。具体如下所示:
- 泛型不同的引用不能相互赋值。
下面来做一下验证:
@Test
public void test3(){//泛型不同的引用不能相互赋值ArrayList<String> list1 = null;ArrayList<Integer> list2 = null;list1 = list2; //此处会报类型不兼容的错误
}
错误信息如下:

这是因为尽管在编译时ArrayList和ArrayList是两种类型,但是,在运行时只有一个ArrayList被加载到JVM中。
2. 如果泛型结构是一个接口或抽象类,则不可创建泛型类的对象。
这是因为接口和抽象类本就是不能创建对象的。
3. jdk1.7时,对泛型做了简化的操作:
//1.7之前
ArrayList<Fruit> flist = new ArrayList<<Fruit>>();
//1.7之后
ArrayList<Fruit> flist = new ArrayList<>();
- 在类/接口上声明的泛型,在本类或本接口中即代表某种类型,可以作为非静态属性的类型、非静态方法的参数类型、非静态方法的返回值类型。但在静态方法中不能使用类的泛型。
我们在Order类中添加如下的静态方法show():
//静态方法中不能使用类的泛型
public static void show(){System.out.println(orderT);
}
错误信息如下:

这是因为静态结构早于对象的创建,而泛型的指定在实例化的时候。所以在show方法创建的时候,属性orderT还没有指定是什么类型的,而且根本就没有出生,这里可以借助java中静态方法中不能调用非静态变量来辅助理解。
5. 异常类不能是泛型的。

3.2 自定义泛型方法
方法也可以被泛型化,不管此时定义在其中的类是不是泛型类,也就是说,泛型方法所属的类是不是泛型类都没有关系。 在泛型方法中可以定义泛型参数,泛型参数与类的泛型参数没有任何关系。此时,参数的类型就是传入数据的类型。
回顾一下在 Order 类中所定义的几个方法:
public T getOrderT() {return orderT;
}public void setOrderT(T orderT) {this.orderT = orderT;
}@Override
public String toString() {return "Order{" +"orderName='" + orderName + '\'' +", orderId=" + orderId +", orderT=" + orderT +'}';
}
上述的三个方法都使用到了Order类的泛型,但它们都不是泛型方法。
泛型方法的格式如下:
[访问权限] <泛型> 返回类型 方法名([泛型标识 参数名称]) 抛出的异常
举例如下,在Order类中添加一个泛型方法,取名为copyFromArrayToList:
public <E> List<E> copyFromArrayToList(E[] arr){ ArrayList<E> list = new ArrayList<>();for(E e : arr) {list.add(e);}return list;
}
可以看到,泛型方法头部的声明结构与普通方法的区别在于两点:一是形参列表和返回值的类型处多了泛型结构;二是在权限修饰符和返回值类型之间添加了泛型标识,这是因为如果加 public 后面的,编译器会把形参位置“E[] arr”误认为是一个对象数组,即数组元素为类E的对象,但其实并没有名为 E 的类。
接下来我们来调用一下这个泛型方法:
@Test
public void test4(){Order<String> order = new Order<>();Integer[] arr = {1, 3, 4, 9};//泛型方法在调用时,指明泛型参数的类型。这个类型和Order类的泛型没有任何的关系List<Integer> list = order.copyFromArrayToList(arr);System.out.println(list);
}
在实例化 Order 类的时候,指明它的泛型结构为 String,而在为泛型方法copyFromArrayToList() 指定形参的泛型时指定为 Integer,所以再一次验证了泛型参数的类型与类的泛型没有任何的关系。
测试结果如下:

此外,泛型方法可以声明为静态的。因为泛型参数是在调用方法时确定的,并非是在实例化类时确定。设计如下:
public static <E> List<E> copyFromArrayToList(E[] arr){ ArrayList<E> list = new ArrayList<>();for(E e : arr) {list.add(e);}return list;
}
4.泛型在继承上的体现
如果 B 是 A 的一个子类型(子类或者子接口),而G是具有泛型声明的类或接口,则G并不是G的子类型!关系如下图所示:

比如:String 是 Object 的子类,但是List 并不是List 的子类。
下面给出如下的测试:
@Test
public void test1(){List<Object> list1 = null;List<String> list2 = null;//此时的lsit1和list2的类型不再具有父子类关系。//编译不通过// list1 = list2;
}
此时语句 list1 = list2 会编译不通过,警告信息如下:

这就是因为此时的 list1和list2 的类型不再具有父子类关系。
下面以反证法的角度解释一下为什么不能这样赋值。假设 list1 = list2 可以实现,那么现在往 list1中添加一个整形数据,那么这样list2中就会混入非String的数据,所以出错。
此外,如果类A是类B的父类, G是具有泛型声明的类或接口,则 A
给出如下的测试:
@Test
public void test2(){AbstractList<String> list1 = null;List<String> list2 = null;ArrayList<String> list3 = null;list1 = list3;list2 = list3;List<String> list4 = new ArrayList<>(); //这个的本质其实就是把list3赋给了list2
}
测试结果如下:

可以看到,上述的操作是没有问题的。
5.通配符的使用
5.1 基本使用
通配符的符号:?
若类A是类B的父类,则G和G是没有关系的,二者共同的父类是:G<?> 比如 List<?>是List、List等各种泛型List的父类。
下面给出测试程序:
@Test
public void test3(){List<Object> list1 = null;List<String> list2 = null;List<?> list = null;list = list1; list = list2;
}
在上述代码段中,List<?>是list1和list2的父类,所以把list1和list2分别赋值给list是没有问题的,编译通过。 接下来我们写一个参数为List<?>的函数,这样的话,list1和list2都应该能当作实参传进去。
//list1和list2都可以传进这个方法里
public void print(List<?> list){Iterator<?> iterator = list.iterator();while(iterator.hasNext()){Object obj = iterator.next();System.out.println(obj);}
}
由于在形参中使用了通配符,所以在迭代器中也要用到,最后获取的元素类型用Object接收。给出调用print方法的测试如下:
@Test
public void test3(){List<Object> list1 = null;List<String> list2 = null;List<?> list = null;list = list1; //相当于List<?>是list1和list2的父类list = list2;//编译通过print(list1);print(list2);
}
接下来尝试一个添加和读取的操作:
@Test
public void test3(){List<Object> list1 = null;List<String> list2 = null;List<?> list = null;List<String> list3 = new ArrayList<>();list3.add("AA");list3.add("BB");list3.add("CC");list = list3;//添加:对于List<?>就不能向其内部添加数据。//除了添加null之外。 因为什么类型的对象对可以赋值为nulllist.add(null);//读取: 允许读取数据,读取的数据类型为Object。Object o = list.get(0);System.out.println(o);}
在上述代码块中,list3的类型为List,并向其中添加了三个字符串元素,然后将list3赋值给list,这样的话list和list3就指向同一片空间。那么这个时候就不能向List<?>内部添加数据,因为添加的数据类型可能是非String的。 唯一的例外的是null,它是所有类型的成员;而对于读取元素则无限制,因为list包含的元素总是一个Object。
测试结果如下:

5.2 有限制的通配符的使用
通配符指定上限:
上限 extends:使用时指定的类型必须是继承某个类,或者实现某个接口,即<=。
通配符指定下限:
下限super:使用时指定的类型不能小于操作的类,即>= 。
举例如下:

下面给处测试验证:
首先我们声明一个Person类,并声明一个继承了Person类的Student类,把他们用作泛型的类型。给出如下的测试程序:
@Test
public void test4(){List<? extends Person> list1 = null; //表示list1中的对象为 <=Person类型的List<? super Person> list2 = null; //表示list2中的对象为 >=Person类型的List<Student> list3 = new ArrayList<>();List<Person> list4 = new ArrayList<>();List<Object> list5 = new ArrayList<>();list1 = list3;list1 = list4;//list5已经大于了Person了,所以会报错// list1 = list5;// list2 = list3; //list3为小于Person的类型了,所以会报错list2 = list4;list2 = list5;
}
显然,三者之间的关系为:Object是Person的父类,Person是Student的父类。所以根据<? extends Person>的规则,List 类型是不能传给List<? extends Person>的。同理,list3也不能赋给list2。
错误信息如下:


读取数据测试:
@Test
public void test4(){List<? extends Person> list1 = null; //表示list1中的对象为 <=Person类型的List<? super Person> list2 = null; //表示list2中的对象为 >=Person类型的List<Student> list3 = new ArrayList<>();List<Person> list4 = new ArrayList<>();List<Object> list5 = new ArrayList<>();//读取数据list1 = list3;Person p = list1.get(0);//Student s = list1.get(0); //编译不通过,需要用Person类型接收,找到的是Studentlist2 = list4;Object obj = list2.get(0);//Person ob = list2.get(0); //编译不通过,list2为大于等于Person的,所以只能用Object对象来接收
}
在接收数据时,为了保证不出现问题,需要用最大的类型去接收。因为在多态中,子类可以赋给父类,但父类不能赋为子类。
写入数据测试:
@Test
public void test4(){
List<? extends Person> list1 = null; //表示list1中的对象为 <=Person类型的
List<? super Person> list2 = null; //表示list2中的对象为 >=Person类型的List<Student> list3 = new ArrayList<>();
List<Person> list4 = new ArrayList<>();
List<Object> list5 = new ArrayList<>();//写入数据:
//编译不通过
//list1.add(new Student()); //虽然Student类型是小于Person的,但是需要添加的类型可能比Student还小(因为父类是不能赋给子类的)//编译通过
list2.add(new Person());
list2.add(new Student()); //此处不报错,是多态的体现}
向list1中添加Student类的对象时会出错,这是因为虽然Student类型是小于Person的,但是需要添加的类型可能比Student还小,那么像这样传参就会出现父类传给子类的现象。向list2中添加Person对象和Student对象都是可以的,这是因为在list2的规定下Person类型确实是最小的,而且Person都可以添加,子类一定也是可以的。这其实都是多态的应用。
相关文章:
Java高级编程—泛型
文章目录 1.为什么要有泛型 (Generic)1.1 泛型的概念1.2 使用泛型后的好处 2.在集合中使用泛型3.自定义泛型结构3.1 自定义泛型类、泛型接口3.2 自定义泛型方法 4.泛型在继承上的体现5.通配符的使用5.1 基本使用5.2 有限制的通配符的使用 1.为什么要有泛型 (Generic) Java中的…...
Exam in MAC [容斥]
题意 思路 正难则反 反过来需要考虑的是: (1) 所有满条件一的(x,y)有多少对: x 0 时,有c1对 x 1 时,有c对 ...... x c 时,有1对 以此类推 一共有 (c2)(c1)/2 对 (2) 符合 x y ∈ S的有多少对:…...
Java 学习和实践笔记(36):接口(interface)
面向对象的精髓,最能体现这一点的就是接口! 为什么我们讨论设计模式都只针对具备了抽象能力的语言(比如C、Java、C#等),就是因为设计模式所研究的,实际上就是如何合理的去抽象。 接口就是一组规范,所有实…...
Elastic Stack--10--QueryBuilders UpdateQuery
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 QueryBuildersESUtil QueryBuilders package com.elasticsearch; import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.search.Sea…...
腾讯云服务器CVM_云主机_云计算服务器_弹性云服务器
腾讯云服务器CVM提供安全可靠的弹性计算服务,腾讯云明星级云服务器,弹性计算实时扩展或缩减计算资源,支持包年包月、按量计费和竞价实例计费模式,CVM提供多种CPU、内存、硬盘和带宽可以灵活调整的实例规格,提供9个9的数…...
Java八股文(Spring Boot)
Java八股文のSpring Boot Spring Boot Spring Boot 什么是Spring Boot? Spring Boot是一个用于开发和构建微服务应用程序的框架,它简化了Spring应用的配置和部署。 Spring Boot的核心特性是什么? Spring Boot的核心特性包括自动配置、起步依…...
ts文件怎么无损转换mp4?这样设置转换模式~
TS格式(Transport Stream)的起源可追溯到数字电视广播领域。设计初衷是解决视频、音频等多媒体数据在传输和存储中的问题。采用一系列标准技术,TS格式让视频信号能够以流的形式传输,因此在数字电视、广播等领域得到广泛应用。 MP4…...
如何在Windows 10上打开和关闭平板模式?这里提供详细步骤
前言 默认情况下,当你将可翻转PC重新配置为平板模式时,Windows 10会自动切换到平板模式。如果你希望手动打开或关闭平板模式,有几种方法可以实现。 自动平板模式在Windows 10上如何工作 如果你使用的是二合一可翻转笔记本电脑࿰…...
介绍kafka核心原理及底层刷盘机制,集群分片机制,消息丢失和重复消费有对应的线上解决方案
Kafka是一个高性能、分布式、持久化的消息系统,它的核心原理包括发布/订阅模型、分布式日志存储和高吞吐量的数据流处理。 发布/订阅模型:Kafka采用发布/订阅模型,消息的生产者将消息发送到一个或多个主题(Topic)&…...
基于Python的中医药知识问答系统设计与实现
[简介] 这篇文章主要介绍了基于Python的中医药知识问答系统的设计与实现。该系统利用Python编程语言,结合中医药领域的知识和技术,实现了一个功能强大的问答系统。文章首先介绍了中医药知识的特点和传统问答系统的局限性,然后提出了设计思路…...
QT 如何防止 QTextEdit 自动滚动到最下方
在往QTextEdit里面append字符串时,如果超出其高度,默认会自动滚动到QTextEdit最下方。但是有些场景可能想从文本最开始的地方展示,那么就需要禁止自动滚动。 我们可以在append之后,添加如下代码: //设置编辑框的光标位…...
【C/C++ 学习笔记】指针
【C/C 学习笔记】指针 视频地址: Bilibili 概念 可以通过指针间接访问内存用于保存地址 使用 通过 & 可以获取数据的指针 通过 * 可以取得指针的数据 指针的数据类型就是 数据类型 * int number 10;int *p &number;// 10 cout << "number: " …...
【Node.js从基础到高级运用】十二、身份验证与授权:JWT
身份验证与授权是现代Web应用中不可或缺的部分。了解如何在Node.js应用中实施这些机制,将使你能够构建更安全、更可靠的应用程序。本文将引导你通过使用JWT实现用户注册、登录和权限控制的过程。 JWT(Json Web Token) JWT是一种用于双方之间…...
蓝桥杯刷题|01入门真题
[蓝桥杯 2020 省 AB1] 解码 题目描述 小明有一串很长的英文字母,可能包含大写和小写。 在这串字母中,有很多连续的是重复的。小明想了一个办法将这串字母表达得更短:将连续的几个相同字母写成字母 出现次数的形式。 例如,连续…...
Python Django相关解答
问题:什么是django? Django是一个开源的高级web框架,皆在快速开发安全可维护的网站。他鼓励快速开发,并遵循“don’t repeat yourself”DRY原则 Django的MTV架构是什么 Django遵循MTV(模型-模板-试图)架构模式。模型(…...
在Linux/Ubuntu/Debian中使用7z压缩和解压文件
要在 Ubuntu 上使用 7-Zip 创建 7z 存档文件,你可以使用“7z”命令行工具。 操作方法如下: 安装 p7zip: 如果你尚未在 Ubuntu 系统上安装 p7zip(7-Zip 的命令行版本),你可以使用以下命令安装它:…...
设计一些策略和技术来防止恶意爬虫
当涉及到反爬虫时,我们需要设计一些策略和技术来防止恶意爬虫访问我们的网站。以下是一个简单的反爬虫框架示例,供您参考: import requests from bs4 import BeautifulSoup import timeclass AntiScrapingFramework:def __init__(self, targ…...
elasticsearch常见问题:xpack.security.transport.ssl、unknown setting [node.master]
文章目录 引言I 安装elasticsearch1.1 安装Master Node1.2 安装Slave nodeII elasticsearch常见问题2.1 invalid configuration for xpack.security.transport.ssl2.2 server ssl configuration requires a key and certificate2.3 unknown setting [node.master]III Kibana启动…...
LLM(大语言模型)——Springboot集成文心一言、讯飞星火、通义千问、智谱清言
目录 引言 代码完整地址 入参 出参 Controller Service Service实现类 模型Service 入参转换类 文心一言实现类 讯飞星火实现类 通义千问实现类 智谱清言实现类 引言 本文将介绍如何使用Java语言,结合Spring Boot框架,集成国内热门大模型API&am…...
什么是堆?什么是栈?
在计算机科学中,"堆(heap)"和"栈(stack)"是两种用于存储数据的数据结构,它们在内存管理中扮演着不同的角色。 堆(Heap): 动态分配内存:…...
盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...
Java 加密常用的各种算法及其选择
在数字化时代,数据安全至关重要,Java 作为广泛应用的编程语言,提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景,有助于开发者在不同的业务需求中做出正确的选择。 一、对称加密算法…...
(转)什么是DockerCompose?它有什么作用?
一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器。 Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
USB Over IP专用硬件的5个特点
USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中,从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备(如专用硬件设备),从而消除了直接物理连接的需要。USB over IP的…...
Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?
Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...
Spring Security 认证流程——补充
一、认证流程概述 Spring Security 的认证流程基于 过滤器链(Filter Chain),核心组件包括 UsernamePasswordAuthenticationFilter、AuthenticationManager、UserDetailsService 等。整个流程可分为以下步骤: 用户提交登录请求拦…...
Vue3中的computer和watch
computed的写法 在页面中 <div>{{ calcNumber }}</div>script中 写法1 常用 import { computed, ref } from vue; let price ref(100);const priceAdd () > { //函数方法 price 1price.value ; }//计算属性 let calcNumber computed(() > {return ${p…...
鸿蒙HarmonyOS 5军旗小游戏实现指南
1. 项目概述 本军旗小游戏基于鸿蒙HarmonyOS 5开发,采用DevEco Studio实现,包含完整的游戏逻辑和UI界面。 2. 项目结构 /src/main/java/com/example/militarychess/├── MainAbilitySlice.java // 主界面├── GameView.java // 游戏核…...
WEB3全栈开发——面试专业技能点P4数据库
一、mysql2 原生驱动及其连接机制 概念介绍 mysql2 是 Node.js 环境中广泛使用的 MySQL 客户端库,基于 mysql 库改进而来,具有更好的性能、Promise 支持、流式查询、二进制数据处理能力等。 主要特点: 支持 Promise / async-await…...
