泛型類
public class Container<K, V> {
private K key;
private V value;
public Container(K k, V v) {
key = k;
value = v;
}
public K getKey() {
return key;
}
public void setKey(K key) {
this.key = key;
}
public V getValue() {
return value;
}
public void setValue(V value) {
this.value = value;
}
}
在編譯期,是無法知道K和V具體是什么類型,只有在運行時才會真正根據類型來構造和分配內存。
泛型接口
在泛型接口中,生成器是一個很好的理解,看如下的生成器接口定義:
public interface Generator<T> {
public T next();
}
然后定義一個生成器類來實現這個接口:
public class FruitGenerator implements Generator<String> {
private String[] fruits = new String[]{"Apple", "Banana", "Pear"};
@Override
public String next() {
Random rand = new Random();
return fruits[rand.nextInt(3)];
}
}
泛型方法
一個基本的原則是:無論何時,只要你能做到,你就應該盡量使用泛型方法。也就是說,如果使用泛型方法可以取代將整個類泛化,那么應該有限采用泛型方法。下面來看一個簡單的泛型方法的定義
public class Main {
public static <T> void out(T t) {
System.out.println(t);
}
public static void main(String[] args) {
out("findingsea");
out(123);
out(11.11);
out(true);
}
}
可以看到方法的參數徹底泛化了,這個過程涉及到編譯器的類型推導和自動打包,也就說原來需要我們自己對類型進行的判斷和處理,現在編譯器幫我們做了。這樣在定義方法的時候不必考慮以后到底需要處理哪些類型的參數,大大增加了編程的靈活性。
再看一個泛型方法和可變參數的例子:
public class Main {
public static <T> void out(T... args) {
for (T t : args) {
System.out.println(t);
}
}
public static void main(String[] args) {
out("findingsea", 123, 11.11, true);
}
}
<T>是用來規范T的,例如<T extends Object>就規定了邊界,即規定了所有出現T的地方,T類型必須是Object的子類
泛型通配符
- ? 通配符類型
- <? extends T> 表示類型的上界,表示參數化類型的可能是T 或是 T的子類
- <? super T> 表示類型下界(Java Core中叫超類型限定),表示參數化類型是此類型的超類型(父類型),直至Object
extends 可用于的返回類型限定,不能用于參數類型限定。
super 可用于參數類型限定,不能用于返回類型限定。
帶有super超類型限定的通配符可以向泛型對易用寫入,帶有extends子類型限定的通配符可以向泛型對象讀取。