Java Generics

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/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容