泛型
泛型:是一種把類型明確的工作推遲到創建對象或者調用方法的時候才去明確的特殊的類型。把類型當作參數傳遞。
格式:<數據類型> 此處的數據類型只能是引用類型, 如<E>, 丟進去的類型必須是E的對象或其子類的對象。
好處:
A:把運行時期的問題提前到了編譯期間
B:避免了強制類型轉換
C:優化了程序設計,解決了黃色警告線
泛型方法
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;
}
/*
方法靜態時,不能訪問類定義上的泛型
*/
public static <E> ResponseEntity<E> success(String code, String msg, E data) {
// 傳入什么類型,E就是什么類型
return new ResponseEntity<E>(code, msg, data);
}
}
現在假設有一個
Apple a = new Apple();
// 調用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類型形參,這樣方法就能接受任意類型的參數了。
Integer[] ia = new Integer[100];
Collection<Number> cn = new ArrayList<>();
// T代表Number類型
// 只比較泛型形參: Collection<T> cn
fromArrayToCollection(ia, cn);
cn是Collection<Number>類型,與此方法的方法簽名進行比較——只比較泛型參數,故該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產生的唯一效果是可以在不同的調用點傳入不同的實際類型。對于這種情況,應該使用通配符:通配符就是被設計用來支持靈活的子類化的。
泛型方法允許類型形參被用來表示方法的一個或多個參數之間的類型依賴關系,或者方法返回值與參數之間的類型依賴關系。如果沒有這種依賴關系,就不應該使用泛型方法。
再來看一個栗子, Collections.copy()方法:
public class Collections {
public static <T> void copy(List<T> dest, List<? extends T> src){...}
}
/*
src中 ? 代表的類型須是dest中 T 的子類或它本身
dest于src的類型存在明顯的依賴關系
但JDK定義src時使用的是類型通配符,而不是泛型方法
Reason: 該方法無須向src集合中添加元素,也無須修改src集合里的元素,使用類型通配符,無須使用泛型方法
*/
如果改成泛型方法,不使用類型通配符:
class Collections {
public static <T, S extends T> void copy(List<T> dest,
List<S> src) {...}
}
/*
這里的類型形參S, 它使用了一次, 其他參數的類型、方法返回值的類型都不依賴于它,
那類型形參S就沒有存在的必要,即可以用通配符來代替S。so Java 設計該方法時采用了通配符,而不是泛型方法。
*/
類型通配符既可以在方法簽名中定義形參的類型,也可以用于定義變量的類型;但泛型方法中的類型形參必須在對應方法中顯式聲明。