corejava基礎知識(3)-泛型

Zouxxyy發表於2019-03-13

泛型

泛型類與方法的一般格式

泛型類:

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

  • 不能構造泛型陣列

  • 泛型類的靜態上下文中型別變數無效

也就是不能在靜態域或方法中引用型別變數。

  • 不能丟擲或捕獲泛型類的例項
  • 可以消除對受查異常的檢查

相關文章