2012-08-26 208 views
5

我有一個相當簡單的問題。通過搜索我找不到答案。泛型類型的參數化方法

這兩個代碼片段有區別嗎?有什麼區別?

片段1:

public class BinaryTree<T extends Comparable<? super T>> { 
    ... 
    public <E extends T> void add(E value) { 
     ... 
    } 

    public <E extends T> void add(E value, Node node) { 
     ... 
    } 
    ... 
} 

Fragment2:

public class BinaryTree<T extends Comparable<? super T>> { 
    ... 
    public void add(T value) { 
     ... 
    } 

    public void add(T value, Node node) { 
     ... 
    } 
    ... 
} 

片段1指定明確的是,參數值必須是類型T類型T的亞型。

Fragment2指定,該參數值必須類型T的。但從我的知識和經驗來看,我認爲我也可以在這裏提供T的子類型。和fragment1一樣。

我看了這兩個片段的反彙編字節代碼。的確是有區別的:

< public <E extends T> void add(E); 
--- 
> public void add(T); 

這只是反映了源代碼

我只是不明白的意思。而且我也找不到示例應用程序,它顯示了差異。

感謝您的意見。

+0

這些碎片來自哪裏?這是作業/課程作業嗎? – Bobulous

+0

這些碎片形成一本書。作者聲稱通過從fragment2移動到fragment1來改進該類。我無法重建他的解釋。 – Bridy

回答

4

在這種情況下,沒有區別。讓我們例如BinaryTree<Number>並嘗試添加Integer

BinaryTree<Number> numTree = new BinaryTree<>(); 
Integer i = 1; 
numTree.add(i); 

隨着片段1,E可以評估到Integer,但是這是在這種情況下是多餘的。 Integer是一個Number,你也可以同樣指定NumberE

numTree.<Number>add(i); 

出於這個原因,第二個片段是沒有不同於第一,並沒有報關不必要的類型參數不易混淆。


有些情況下,一個額外的類型參數會有用。想象一下,由於某種原因,你想返回值傳遞:

public <E extends T> E add(E value) { 
    ... 
    return value; 
} 

public <E extends T> E add(E value, Node node) { 
    ... 
    return value; 
} 

現在,這將是主叫有用:

Integer i2 = numTree.add(i); 

隨着第二片斷是不可能的,而numTree.add可能即使您通過Integer也只返回Number

1

不,沒有差異的add()方法的兩個變化之間。Java的方法參數已經在可接受的類型上建立了一個上限,這與使用類型變量<E extends T>extends形式完成的約束相同。

您的類型變量不會添加任何新信息,也不會添加任何其他約束。通過類型爲T的參數或延伸爲T的任何類型的參數已經合法。你的類型變量<E extends T>確實提供了一種方法來再次引用實際的參數類型—說,如果你想確保第二個方法參數與第一個—類型相同,但在你的情況下,你沒有做出使用E