類型參數
泛型有三種實現方式,分別是泛型接口、泛型類、泛型方法,下面通過泛型方法來介紹什么是類型參數。
泛型方法聲明方式:訪問修飾符 <T,K,S...> 返回類型 方法名(方法參數){方法體}
一、訪問修飾符與返回類型中間有個<T,K,S...>,T、K、S等屬於類型參數,可以隨便定義。
二、返回類型和方法參數可以是或者包含類型參數T、K、S等。
三、可以限定類型參數必須實現某些接口或者繼承某個類,多個限定的類、接口中間用&分隔,類必須放在限定列表中所有接口的前面。
四、
泛型方法可以定義在普通類中。
示例:
import java.io.Serializable;
public class Demo {
public static void main(String[] args) {
B b = new B();
C c = new C();
System.out.println(D.d(b, c));
}
}
class A {
@Override
public String toString() {
return "A{}";
}
}
class B extends A implements Serializable, Cloneable {
@Override
public String toString() {
return "B{}";
}
}
class C extends A {
@Override
public String toString() {
return "C{}";
}
}
class D {
public static <T extends A & Serializable & Cloneable, K> K d(T t, K k) {
System.out.println(t);
return k;
}
}
輸出:
B{}
C{}
通配符類型
通配符類型可以理解為一種泛型調用時傳遞的一種特殊數據類型,表示允許類型參數在某個范圍內變化。通配符類型有三種,分別是?、? extends、? super。它有什么用?創建如下三個類:
public class ParentClass{}
public class SonClass extends ParentClass{}
public class Operate<T> {
private T item;
public Operate(T item) {
this.item = item;
}
public T get() {
return item;
}
public void set(T item) {
this.item = item;
}
}
? extends X
子類型限定,表示泛型的類型參數不是固定的,而是X及其子類型。
如果存在Operate<ParentClass> operate1 = new Operate<SonClass>(new SonClass()),那么這行代碼會報錯,編譯器提示類型不兼容,因為左邊不是右邊的基類。此時如果有這樣一個方法:
public static void method(Operate<ParentClass> operate) {},
就無法將 new Operate<SonClass>(new SonClass()) 傳遞給這個方法。解決辦法就是使用子類型限定定義方法參數:
public static void method(Operate<? extends ParentClass> operate) {},
就可以將 new Operate<SonClass>(new SonClass()) 傳遞給這個方法。
子類型限定的副作用是不能傳遞null以外的類型。
Operate<? extends ParentClass>的方法可以想象成下面這個樣子(實際上不能這樣寫代碼):
public ? extends ParentClass get() {
return item;
}
public void set(? extends ParentClass item) {
this.item = item;
}
此時get方法可以正常調用,因為返回的item肯定是ParentClass或者它的子類型。但是set方法就不能傳遞null以外的類型了,因為編譯器只知道需要ParentClass或者它的子類型,但是不知道具體是哪個類,所以只能調用set(null)。如下:
public static void method(Operate<? extends ParentClass> operate) {
operate.get();
operate.set(null);
operate.set(new ParentClass());//報錯
operate.set(new SonClass());//報錯
}
? super X
超類型限定,表示泛型的類型參數不是固定的,而是X及其父類型。
Operate<? super SonClass>的方法可以想象成下面這個樣子(實際上不能這樣寫代碼):
public ? super SonClass get() {
return item;
}
public void set(? super SonClass item) {
this.item = item;
}
一、類型參數限定為X及其父類型,直至Object類,因為不知道具體是哪個父類型,因此方法返回的類型只能賦給Object。
二、只能傳遞null、X及其子類型,因為X及其子類型都是向上轉型成X及其父類型。
Operate<? super SonClass> operate3 = new Operate<ParentClass>(new ParentClass())是成立的,所以可以將new Operate<ParentClass>(new ParentClass())傳遞給以下方法。
public static void method(Operate<? super SonClass> operate) {
SonClass sonClass = operate.get();//報錯
ParentClass parentClass = operate.get();//報錯
Object object = operate.get();
operate.set(new ParentClass());//報錯
operate.set(null);
operate.set(new SonClass());
}
?
無類型限定,泛型的類型參數沒有限定。
一、只能傳遞null類型。
二、方法返回的類型只能賦給Object。
new Operate<SonClass>(new SonClass())、new Operate<ParentClass>(new ParentClass())、new Operate<Object>(new Object())、new Operate<String>(new String())等都可以傳遞給以下方法。
public static void method(Operate<?> operate) {
SonClass sonClass = operate.get();//報錯
ParentClass parentClass = operate.get();//報錯
operate.set(new ParentClass());//報錯
Object object = operate.get();
operate.set(null);
operate.set(new SonClass());//報錯
}
有什么作用呢?對於一些不需要實際類型的方法,就顯得比泛型方法可讀性強,如下。
public static void method(Operate<?> operate) {
System.out.println(operate.get() == null);
}
public static <T> void method(Operate<T> operate) {
System.out.println(operate.get() == null);
}