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) {
      ...
   }
   ...
}

片段2:

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

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

Fragment1 明确指定参数必须是T类型或T类型的子类型。

Fragment2 指定参数必须是T类型。但是根据我的知识和经验,我认为我也可以在这里提供T的子类型。与fragment1相同。

我查看了这两个片段的反汇编字节码。确实有区别:

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

那只是反映了源代码...

我只是不明白意思。而且我也找不到显示差异的示例应用程序。

感谢您的评论。

4

2 回答 2

4

在这种情况下没有区别。让我们以 a 为例BinaryTree<Number>并尝试添加一个Integer

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

对于片段 1,E可能评估为Integer,但在这种情况下这是多余的。Integer 是 a Number,您也可以指定Numberfor E

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.adda 也只能返回 a 。NumberInteger

于 2012-08-26T14:53:08.977 回答
1

不,该方法的两种变体之间没有区别add()。Java 的方法参数已经在接受的类型上建立了一个上限extends,这与使用类型变量的形式完成的约束相同<E extends T>

您的类型变量不会添加任何新信息,也不会添加任何额外的约束。T 传递类型或任何扩展T类型的参数已经是合法的。您的类型变量<E extends T>确实提供了一种再次引用实际参数类型的方法 - 例如,如果您想确保第二个方法参数与第一个方法参数的类型相同 - 但在您的情况下,您没有使用的E

于 2012-08-26T14:56:20.720 回答