先看個例子,有一個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....