“嗨!我要繼續艾莉的泛型課程。準備好聽了嗎?”

“是的。”

“那我們開始吧。”

“首先你需要知道的是,一個類的方法也可以有自己的類型參數。”

“我知道。”

“不,我特指自己的類型參數:

例子
class Calculator
{
  T add(T a, T b); // Add
  T sub(T a, T b); // Subtract
  T mul(T a, T b); // Multiply
  T div(T a, T b); // Divide
}

“這些類型參數專門與方法有關。該類沒有參數。您甚至可以將這些方法聲明為靜態的,並在沒有對象的情況下調用它們。”

“我明白了。方法中的類型參數的意義與類相同?”

“是的。但是有一些新東西。”

“正如你已經知道的,你可以在類型聲明中使用通配符。那麼想像一下以下情況:”

示例 1
public void doSomething(List<? extends MyClass> list)
{
 for(MyClass object : list)
 {
  System.out.println(object.getState()); // Everything works well here.
 }
}

“但是如果我們想向集合中添加一個新項目怎麼辦:”

示例 2
public void doSomething(List<? extends MyClass> list)
{
 list.add(new MyClass()); // Error!
}

“問題是,在一般情況下,doSomething 方法可能會傳遞一個列表,其元素不是 MyClass 對象,而是 MyClass 的任何子類的對象。但是你不能將 MyClass 對象添加到這樣的列表中!”

“啊。那麼,那有什麼辦法呢?”

“沒什麼。在這種情況下,你什麼也做不了。但這給了 Java 的創造者一些思考。他們想出了一個新的關鍵字:super。”

“語法看起來幾乎一樣:”

List<? super MyClass> list

但是 extends 和 super 之間有一個重要的區別。

“«? extends T» 意味著該類必須是 T 的後代。”

“«?super T» 意味著該類必須是 T 的祖先。”

“我的天啊。那這東西用在什麼地方?”

“«? super T» 在方法涉及添加到 T 對象的集合時使用。在這種情況下,它可以是 T 對象的集合或 T 的任何祖先。”

“啊。可以將 AT 對象分配給類型為 T 的任何祖先的引用變量”

“老實說,這種方式用得併不多,而且還有一個缺點,比如:”

例子
public void doSomething(List<? super MyClass> list)
{
 for(MyClass object : list) // Error!
 {
  System.out.println(object.getState());
 }
}
public void doSomething(List<? super MyClass> list)
{
 list.add(new MyClass()); // Everything works well here.
}

“現在第一個例子行不通了。”

“因為 list 甚至可以是 List<Object>(Object 是 MyClass 的最頂層超類),我們實質上是在編寫以下無效代碼:”

示例 1
List<Object> list; 

for(MyClass object : list) // Error!
{ 
 System.out.println(object.getState()); 
}

“我明白了。謝謝你有趣的課。”

“不客氣。”