我有一个相当简单的问题。我找不到答案。
这两个代码片段有区别吗?有什么区别?
片段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) {
...
}
...
}
Fragment1明确指定参数 value 必须是 T 类型或 T 类型的子类型。
Fragment2指定参数 value 必须是 T 类型。但是根据我的小知识和经验,我认为我还可以在这里提供 T 的子类型。和fragment1一样。
我查看了这两个片段的反汇编字节码。确实存在差异:
< public <E extends T> void add(E);
---
> public void add(T);
这只反映了源代码......
我只是没有意义。而且我也找不到示例应用程序,它显示了差异。
感谢您的评论。
答案 0 :(得分:4)
在这种情况下没有区别。我们以BinaryTree<Number>
为例,尝试添加Integer
:
BinaryTree<Number> numTree = new BinaryTree<>();
Integer i = 1;
numTree.add(i);
对于片段1,E
可以评估为Integer
,但在这种情况下这是多余的。 Integer
是 Number
,您也可以为Number
指定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.add
,Number
也只能返回Integer
。
答案 1 :(得分:1)
不,add()
方法的两种变体之间没有区别。 Java的方法参数已经在接受的类型上建立了上限,这是使用类型变量extends
的{{1}}形式完成的相同约束。
您的类型变量不会添加任何新信息,也不会添加任何其他约束。传递<E extends T>
类型的参数或任何扩展T
的类型已经合法。你的类型变量T
确实提供了一种再次引用实际参数类型的方法 - 比方说,如果你想要确保第二个方法参数与第一个类型相同 - 但在你的情况下,你“我没有使用<E extends T>
。