1. 為什么要使用泛型
2. 泛型在Java中如何生效
3. 泛型類型
1) 泛型類或接口
一個類使用了一個或者多個類型的變量,則這個類是個泛型類。這些類型的變量稱為類型參數(shù)。用一個例子來理解:
class DemoClass<T> {
//T stands for "Type"
private T t;
public void set(T t) { this.t = t; }
public T get() { return t; }
}
使用泛型類之后,一方面支持這個類有多種類型參數(shù),另一方面避免發(fā)生編譯錯誤。比如:
DemoClass<String> instance = new DemoClass<String>();
instance.set("lokesh"); //Correct usage
instance.set(1); //This will raise compile time error
同理接口中使用類似,例如:
//Generic interface definition
interface DemoInterface<T1, T2>
{
T2 doSomeOperation(T1 t);
T1 doReverseOperation(T2 t);
}
//A class implementing generic interface
class DemoClass implements DemoInterface<String, Integer>
{
public Integer doSomeOperation(String t)
{
//some code
}
public String doReverseOperation(Integer t)
{
//some code
}
}
2) 泛型方法/構(gòu)造函數(shù)
泛型方法/構(gòu)造函數(shù)與泛型類很類似,但泛型方法的類型信息的范圍僅限于方法內(nèi)部,并且其引入了自身的類型參數(shù)。
4. 泛型數(shù)組
在java中,在運(yùn)行時將任何不兼容的類型推送到數(shù)組中都引發(fā)異常,這意味著數(shù)組在運(yùn)行時保留其類型信息,而泛型在運(yùn)行時會擦除或刪除任何類型的信息。所以在java中不允許實例化泛型數(shù)組。
// causes compiler error; Cannot create a generic array of T
public T[] array = new T[5];
數(shù)組不支持泛型的另一個原因是數(shù)組是協(xié)變的,這意味著超類型引用的數(shù)組是子類型引用數(shù)組的父類型。也就是說,Object[]是String[]的超類型,可以通過Object[]類型的引用變量訪問字符串?dāng)?shù)組。
Object[] objArr = new String[10]; // fine
objArr[0] = new String();
5. 帶通配符的泛型
為什么要使用通配符?
通配符用于提示使用者,java泛型所實施的規(guī)則,即在使用通配符的任何特定場景中,哪些類型是有效的。
泛型中 ? 代表通配符,表示一個未知的類型。通配符的參數(shù)化類型是泛型類型的一個實例,表示該泛型類型中至少有一個參數(shù)是通配符。通配符可以用于多種情況,比如作為參數(shù)、字段、局部變量的類型,或者作為返回類型。但通配符不能作為泛型方法調(diào)用、泛型類實例創(chuàng)建、超類的類型參數(shù)。
泛型用于不同位置的含義也不同:
Collection 表示該集合接口的所有實例化都與類型參數(shù)無關(guān);
List<? extends Number> 表示元素類型是Number子類型的所有列表類型;
Comparator<? super T> 表示類型參數(shù)是T的超類的所有Comparator接口的實例化
以下是正確的通配符使用:
Collection<?> coll = new ArrayList<String>();
List<? extends Number> list = new ArrayList<Long>();
Pair<String,?> pair = new Pair<String,Integer>();
以下是錯誤的通配符使用:
List<? extends Number> list = new ArrayList<String>(); //String is not subclass of Number; so error
Comparator<? super String> cmp = new RuleBasedCollator(new Integer(100)); //Integer is not superclass of String
通配符在泛型中可以是有界的也可以是無界的。
1) 無界通配符
所有的參數(shù)類型都是無界的通配符類型表示對其類型變量沒有任何限制。比如:
ArrayList<?> list = new ArrayList<Long>();
ArrayList<?> list = new ArrayList<String>();
ArrayList<?> list = new ArrayList<Employee>();
2) 有界通配符
有界通配符對參數(shù)的類型做了一些限制,通常使用extends、super限制參數(shù)的范圍。
上界通配符
說太多不好理解,直接上代碼
public class GenericsExample<T>
{
public static void main(String[] args)
{
//List of Integers
List<Integer> ints = Arrays.asList(1,2,3,4,5);
System.out.println(sum(ints));
//List of Doubles
List<Double> doubles = Arrays.asList(1.5d,2d,3d);
System.out.println(sum(doubles));
List<String> strings = Arrays.asList("1","2");
//This will give compilation error as :: The method sum(List<? extends Number>) in the
//type GenericsExample<T> is not applicable for the arguments (List<String>)
System.out.println(sum(strings));
}
//Method will accept
private static Number sum (List<? extends Number> numbers){
double s = 0.0;
for (Number n : numbers)
s += n.doubleValue();
return s;
}
}
下界通配符
package test.core;
import java.util.ArrayList;
import java.util.List;
public class GenericsExample<T>
{
public static void main(String[] args)
{
//List of grand children
List<GrandChildClass> grandChildren = new ArrayList<GrandChildClass>();
grandChildren.add(new GrandChildClass());
addGrandChildren(grandChildren);
//List of grand childs
List<ChildClass> childs = new ArrayList<ChildClass>();
childs.add(new GrandChildClass());
addGrandChildren(childs);
//List of grand supers
List<SuperClass> supers = new ArrayList<SuperClass>();
supers.add(new GrandChildClass());
addGrandChildren(supers);
}
public static void addGrandChildren(List<? super GrandChildClass> grandChildren)
{
grandChildren.add(new GrandChildClass());
System.out.println(grandChildren);
}
}
class SuperClass{
}
class ChildClass extends SuperClass{
}
class GrandChildClass extends ChildClass{
}
6. 哪些情況不允許使用泛型
1) 靜態(tài)字段不能用泛型
public class GenericsExample<T>
{
private static T member; //This is not allowed
}
2) 不能創(chuàng)建T的實例
public class GenericsExample<T>
{
public GenericsExample(){
new T();
}
}
3) 泛型表達(dá)式不接受基本類型
final List<int> ids = new ArrayList<>(); //Not allowed
final List<Integer> ids = new ArrayList<>(); //Allowed
4) 泛型類不能繼承java.lang.Throwable
public class GenericException<T> extends Exception {}
參考文獻(xiàn)
https://howtodoinjava.com/java/generics/complete-java-generics-tutorial/