2012-08-26 85 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