先看个例子,有一个IntegerPrinter类,里面有一个printf方法打印一个integer类型的值。
public class Main {
public static void main(String[] args) {
IntegerPrinter integerPrinter = new IntegerPrinter(123);
integerPrinter.printf();
}
}
public class IntegerPrinter {
Integer a;
IntegerPrinter(Integer integer) {
this.a = integer;
}
void printf() {
System.out.println("打印的值是:" + this.a);
}
}
打印 integer类型的值是有了,现在想打印String类型的值,你会如何做呢,是创建一个打印String类型的类,还是和我一样使用泛型。
泛型
简单的说,泛型就是允许你编写可以操作各种类型数据的代码,而不需要提前指定具体的数据类型。
现在对IntegerPrinter类 进修改,
//main函数如下
Printer<Integer> integerPrinter = new Printer<Integer>(123);
integerPrinter.printf(); //打印的值是:123
Printer<String> stringPrinter = new Printer<String>("hello,world");
stringPrinter.printf(); //打印的值是:hello,world
public class Printer<T> {
T data;
Printer(T data) {
this.data = data;
}
void printf() {
System.out.println("打印的值是:" + this.data);
}
}
再类中,多个参数的实现
Printer<String, Integer> integerPrinter = new Printer<String, Integer>("hello,world", 123);
integerPrinter.printf();
//第一个参数打印的值是:hello,world
//第二个参数打印的值是:123
public class Printer<T, K> {
T data;
K data2;
Printer(T data, K data2) {
this.data = data;
this.data2 = data2;
}
void printf() {
System.out.println("第一个参数打印的值是:" + this.data);
System.out.println("第二个参数打印的值是:" + this.data2);
}
}
在方法中使用泛型
public static void main(String[] args) {
print("张三"); //数据是:张三
print(18); //数据是:18
print(true); //数据是:true
}
public static <T> void print(T data) {
System.out.println("数据是:" + data);
}
泛型上下边界(约束)
泛型上边界:指定泛型参数必须是某个类或接口的子类。
如:类型实参只准传父类或父类型的子类
public class Printer<T extends Zoon> {
T data;
Printer(T data) {
this.data = data;
}
void printf() {
System.out.println("类是:" + this.data.getClass());
}
}
public class Zoon {
String color;
}
public class Dog extends Zoon {
String name;
}
public class Cat extends Zoon {
String name;
}
public static void main(String[] args) {
Printer<Cat> catPrinter = new Printer<Cat>(new Cat());
Printer<Dog> dogPrinter = new Printer<Dog>(new Dog());
Printer<Zoon> zoonPrinter = new Printer<Zoon>(new Zoon());
catPrinter.printf(); //类是:class Cat
dogPrinter.printf(); //类是:class Dog
zoonPrinter.printf(); //类是:class Zoon
//如果强行使用会出现报错:Type parameter 'Flowers' is not within its bound; should extend 'Zoon'
Printer<Flowers> flowersPrinter = new Printer<Flowers>(new Zoon());
}
例: 类型必须是父类中的子类,且必须实现了其中的接口
public interface Life {
}
//使Cat类 实现Life 接口
public class Cat extends Zoon implements Life {
String name;
}
//使Dog类,不实现 Life 接口
public class Dog extends Zoon {
String name;
}
// 注:类必须写到接口前面,不然会报错
public class Printer<T extends Zoon & Life> {
T data;
Printer(T data) {
this.data = data;
}
void printf() {
System.out.println("类是:" + this.data.getClass());
}
}
public static void main(String[] args) {
Printer<Cat> catPrinter = new Printer<Cat>(new Cat());
catPrinter.printf(); //类是:class Cat
//下面会报错:Type parameter 'Dog' is not within its bound; should implement 'Life'
Printer<Dog> dogPrinter = new Printer<Dog>(new Dog());
}
在List 中使用
public static void main(String[] args) {
List<Integer> lists = new ArrayList<>();
lists.add(123);
lists.add(456);
print(lists); //[123, 456]
}
public static void print(List<Integer> lists) {
System.out.println(lists);
}
在上面中可以看到list类型是Integer,现在我想让类型是String,该如何实现呢,使用Object?,或者再写一个方法? 还是什么,
为什么不能使用Object:
因为String确实是Object 的子类,但是ListString 不是 List Object的子类。
重装写一个方法确实可以实现,但这样太麻烦了。
此时就引出了通配符,符号: ? 来表示,代表可以配置任何类型。
public static void main(String[] args) {
List<String> lists = new ArrayList<>();
lists.add("hello");
lists.add("world");
print(lists); //[hello, world]
List<Integer> lists2 = new ArrayList<>();
lists2.add(123);
lists2.add(456);
print(lists2); //[123, 456]
}
public static void print(List<?> lists) {
System.out.println(lists);
}
泛型下边界:指定泛型参数必须是某个类的父类。
例如:指定的类型是Cat类,
这个时候 我们就要使用到 super了,super 关键字允许泛型参数限制为某个类型的父类或者它本身,但不能是子类。
public static void main(String[] args) {
List<Zoon> lists = new ArrayList<>();
lists.add(new Zoon());
print(lists);
List<Cat> lists2 = new ArrayList<>();
lists2.add(new Cat());
print(lists2);
}
//参数的类型可以是Cat,也可以是Zoon, 不可以是Dog,因为Cat类没有继承Dog类,继承代码在上中有给出。
public static void print(List<? super Cat> lists) {
System.out.println(lists);
}
总结
1,使用泛型最主要的是提高代码的复用性。
2,当看到T, E, K, V这个符号的时候不用慌,他们都只是占位符,当然,这只是一种约定俗成的习惯,你也可以使用26个字母中的任何一个表示泛型。
参考
https://www.baeldung.com/java-generics
https://www.bilibili.com/video/BV1H94y1a7bJ/?spm_id_from=333....
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。