泛型
泛型類與方法的一般格式
泛型類:
public class Pair<T>
{
private T first;
private T second;
public Pair() { first = null ; second = null; }
public Pair(T first, T second) { this.first = first; this.second = second; }
public T getFirst() { return first; }
public T getSecond() { return second; }
public void setFirst(T newValue) { first = newValue; }
public void setSecond(T newValue) { second = newValue; }
}
複製程式碼
泛型方法:
class ArrayAlg
{
public static <T> T getMiddle(T... a)
{
return a[a.length / 2];
}
}
複製程式碼
該方法是在普通類定義的泛型方法,呼叫時:
String middle = ArrayAlg.<String>getMiddle("]ohnM, "Q.n, "Public");
術語:
ArrayList<E>
– 泛型型別ArrayList
– 原始型別E
– 型別引數(變數)<>
– 讀作”typeof”ArrayList<Integer>
– 引數化的型別Integer
– 實際型別引數
型別變數的限定
我們可以對型別變數加以約束,畢竟我們很難適用每種泛型。可以通過對型別變數 T 設定限定(bound) 實現這一點,格式如下:
<T extends BoundingType>
BoundingType 可以是
- 類:T 是它的子型別(subtype)
- 介面: T 是實現了該介面的類
可以有多個介面,當然至多有一個類,用 “&” 分隔。
ps: 由於型別擦除機制,為了提高效率,應該將標籤(tagging) 介面 (即沒有方法的介面)放在邊界列表的末尾。
泛型轉化的內部
- 虛擬機器中沒有泛型, 只有普通的類和方法;所有的型別引數都用它們的限定型別替換。
- 編譯器在呼叫泛型方法時會自動插入強制型別轉換。
- 橋方法被合成來保持多型。
約束與侷限性
- 不能用基本型別例項化型別引數
即沒有Pair<double>
,只有Pair<Double>
。原因是型別擦出後,Object不能儲存double值,畢竟它不是物件
- 執行時型別查詢只適用於原始型別
所有的型別查詢只產生原始型別,例子:
Pair<String> stringPair = ...;
Pair<Employee> employeePair = ...;
if(stringPir.getClass() == employeePair.getClass()) // they are equal
複製程式碼
- 不能建立引數化型別的陣列
Pair<String>[] table
是錯的;
只能使用AllayList: ArrayList<Pair<String>> table
- Varargs警告
向引數個數可變的方法傳遞一個泛型型別的例項時,為了呼叫這個方法,Java 虛擬機器必須建立一個引數化型別的陣列,可是這違反了前一個規則。
我們可以用 @SafeVarargs 直接標註該方法,這樣就能正常執行。
- 不能例項化型別變數
例如:
public Pair() { first = new T(); second = new T(); } // Error
-
不能構造泛型陣列
-
泛型類的靜態上下文中型別變數無效
也就是不能在靜態域或方法中引用型別變數。
- 不能丟擲或捕獲泛型類的例項
- 可以消除對受查異常的檢查