泛型
泛型:是一種把類型明確的工作推遲到創(chuàng)建對象或者調(diào)用方法的時候才去明確的特殊的類型。把類型當作參數(shù)傳遞多矮。
格式:<數(shù)據(jù)類型> 此處的數(shù)據(jù)類型只能是引用類型, 如<E>, 丟進去的類型必須是E的對象或其子類的對象迷郑。
好處:
A:把運行時期的問題提前到了編譯期間
B:避免了強制類型轉(zhuǎn)換
C:優(yōu)化了程序設(shè)計,解決了黃色警告線
泛型方法
such as, ResponseEntity類帶有一個E類型形參
public class ResponseEntity<E> {
private String msg;
private String code;
private E data;
public ResponseEntity(String code, String msg, E data) {
this.code = code;
this.msg = msg;
this.data = data;
}
/*
方法靜態(tài)時,不能訪問類定義上的泛型
*/
public static <E> ResponseEntity<E> success(String code, String msg, E data) {
// 傳入什么類型默穴,E就是什么類型
return new ResponseEntity<E>(code, msg, data);
}
}
現(xiàn)在假設(shè)有一個
Apple a = new Apple();
// 調(diào)用success()方法,
ResponseEntity.success("200", "ok", a);
//這樣success()方法的返回值類型 ResponseEntity<E>中的E代表Apple類型褪秀。
再比如:
public static <T> void fromArrayToCollection(T[] a, Collection<T> c) {
for (T o : a) {
c.add(o);
}
}
這是一個泛型方法蓄诽,該泛型方法定義一個T類型形參,這樣方法就能接受任意類型的參數(shù)了媒吗。
Integer[] ia = new Integer[100];
Collection<Number> cn = new ArrayList<>();
// T代表Number類型
// 只比較泛型形參: Collection<T> cn
fromArrayToCollection(ia, cn);
cn是Collection<Number>類型仑氛,與此方法的方法簽名進行比較——只比較泛型參數(shù),故該T類型形參代表了Number類型。
public static <T> void test(Collection<? extends T> from, Collection<T> to) {
for (T ele : from) {
to.add(ele);
}
}
//String Object
List<Object> ao = new ArrayList<>();
List<String> as = new ArrayList<>();
// T代表Object類型锯岖, as中的String是Object的子類類型
test(as, ao);
泛型方法和類型通配符(?)
大多時候介袜,可以使用泛型方法來代替類型通配符。如Java的Collection接口中的兩個方法:
// 泛型通配符
public interface Collection<E> {
boolean containsAll(Collection<?> c);
boolean addAll(Collection<? extends E> c);
}
//采用泛型方法的形式
public interface Collection<E> {
<T> boolean containsAll(Collection<T> c);
<T extends E> boolean addAll(Collection<T> c);
}
上面兩個方法中類型形參T只使用了一次出吹,類型形參T產(chǎn)生的唯一效果是可以在不同的調(diào)用點傳入不同的實際類型遇伞。對于這種情況,應(yīng)該使用通配符:通配符就是被設(shè)計用來支持靈活的子類化的捶牢。
泛型方法允許類型形參被用來表示方法的一個或多個參數(shù)之間的類型依賴關(guān)系鸠珠,或者方法返回值與參數(shù)之間的類型依賴關(guān)系。如果沒有這種依賴關(guān)系秋麸,就不應(yīng)該使用泛型方法渐排。
再來看一個栗子, Collections.copy()方法:
public class Collections {
public static <T> void copy(List<T> dest, List<? extends T> src){...}
}
/*
src中 ? 代表的類型須是dest中 T 的子類或它本身
dest于src的類型存在明顯的依賴關(guān)系
但JDK定義src時使用的是類型通配符,而不是泛型方法
Reason: 該方法無須向src集合中添加元素灸蟆,也無須修改src集合里的元素驯耻,使用類型通配符,無須使用泛型方法
*/
如果改成泛型方法炒考,不使用類型通配符:
class Collections {
public static <T, S extends T> void copy(List<T> dest,
List<S> src) {...}
}
/*
這里的類型形參S, 它使用了一次, 其他參數(shù)的類型可缚、方法返回值的類型都不依賴于它,
那類型形參S就沒有存在的必要票腰,即可以用通配符來代替S城看。so Java 設(shè)計該方法時采用了通配符,而不是泛型方法杏慰。
*/
類型通配符既可以在方法簽名中定義形參的類型测柠,也可以用于定義變量的類型;但泛型方法中的類型形參必須在對應(yīng)方法中顯式聲明缘滥。