文章目录
为什么需要泛型Generic
假设一个需求
创建一个类,来打印Integer变量
普通方式完成需求
-
新建一个
IntegerPrinter
类public class IntegerPrinter { Integer content; public IntegerPrinter(Integer content) { this.content = content; } public void print(){ System.out.println(content); } }
-
main中测试
IntegerPrinter printer = new IntegerPrinter(114514); printer.print();
输出
114514
问题
此时,如果又有一个打印字符串变量的需求,就需要重写建一个StringPrinter
,新增加其他类型有需要创建其他类型的Printer。
这样代码会有很多重复性,所以引入Generics泛型的概念:
只要创建一个类,就能处理所有类型
泛型标记符
- E - Element (在集合中使用,因为集合中存放的是元素)
- T - Type(Java 类)
- K - Key(键)
- V - Value(值)
- N - Number(数值类型)
- ? - 表示不确定的 java 类型
Generic 参数类型约束
在尖括号(Angle Brackets)加泛型标记符:<泛型标记符>
用Generic方式完成上述需求
-
新建一个Printer处理所有类型的变量
public class Printer<T> { T content; public Printer(T content) { this.content = content; } public void print(){ System.out.println(content); } }
-
main中测试
Printer<Integer> integerPrinter = new Printer<>(114514); Printer<String> stringPrinter = new Printer<>("Hi printer!"); integerPrinter.print(); stringPrinter.print();
输出
114514 Hi printer!
多个参数
public class Printer<T, K> {
T content1;
K content2;
public Printer(T content1, K content2) {
this.content1 = content1;
this.content2 = content2;
}
public void print(){
System.out.println(content1+content2);
}
}
Bounded Generic
- 可以通过
<T extends 父类>
来约束,规定T
必须是该父类的子类 - 可以通过
<T extends 接口>
来约束,规定T
必须是该接口的实现类 - 可以通过
<T extends 父类 & 接口>
来约束,规定T
必须是该父类的子类,并且是该接口的实现类(class必须在Interface前面)
Collection : Java中Generic类型约束的常见应用
List<Object> list = new ArrayList<>();
list.add("hello world");
list.add(1234);
System.out.println(list); // 不建议这么做,会有类型安全问题
输出
[hello world, 1234]
类型安全 Type-Safe
泛型在编译阶段进行类型检查,而不是运行时,有时候编译时不会出错,但运行时会,比如
List<Object> list = new ArrayList<>();
list.add("hello world");
list.add(1234);
String item = (String) list.get(1);
System.out.println(item);
上述代码在IDE并不会报错,但运行时会出错
Generic Method 泛型函数
泛型在函数上的应用,在返回类型之前加一个<T>
这样会报错:Cannot resolve symbol 'T'
// private static void print(T content){
// System.out.println(content);
// }
private static <T> void print(T content){
System.out.println(content);
}
也可以通过Bounded Generic约束
Wildcard 通配符
为什么需要通配符
-
比如打印一个
List<Integer>
public static void main(String[] args) { List<Integer> list = new ArrayList<>(); list.add(123); list.add(456); print(list); } private static void print(List<Integer> content){ System.out.println(content); }
输出:
[123, 456]
-
再打印一个
List<String>
呢?public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("123"); list.add("456"); print(list); } private static void print(List<String> content){ System.out.println(content); }
输出:
[123, 456]
-
这样很麻烦,统一成Object?
public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("123"); list.add("456"); print(list); } private static void print(List<Object> content){ System.out.println(content); }
这时候IDE会报错,因为虽然String是Object子类,但是List不是List的子类
所以就需要通配符?
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("123");
list.add("456");
print(list);
}
private static void print(List<?> content){
System.out.println(content);
}
Upper Bounded Wildcard 上界通配符
<? extends 父类>
:继承该父类的对象
public static void main(String[] args) {
List<Car> list = new ArrayList<>();
list.add(new Car()); // Car是Vehicle子类
print(list);
}
private static void print(List<? extends Vehicle> content){
System.out.println(content);
}
Lower Bounded Wildcard 下界通配符
<? super 子类>
:该子类的父类或该子类本身
public static void main(String[] args) {
List<Car> list = new ArrayList<>();
list.add(new Vehicle()); // Vehicle是Car的父类
print(list);
}
private static void print(List<? super Car> content){
System.out.println(content);
}
Reference
https://www.bilibili.com/video/BV1H94y1a7bJ/?share_source=copy_web&vd_source=e40b707ba9b46ace5a15c44fb5fa3388