案例1:
class Gen3<T extends Number> {
T val;
<T extends String> Gen3(String ob){
}
}
这里编译器没有给出任何错误,但它应该给出正确的答案?因为这是T的两个相互矛盾的界限。请帮助我理解这一点。
案例2:
class Gen3<T extends Number> {
T val;
<T extends String> Gen3(String ob) {
}
}
假设我写下以测试上面的类
Gen<Integer> a = new Gen<>("r");
现在自动类型推断如何在这里起作用?
请帮助理解这一点。
答案 0 :(得分:5)
T
没有两个矛盾的界限。有两个类型变量碰巧具有相同的名称。在构造函数中,类型参数T
隐藏了类级别的类型参数。
请注意,问题不在于不同的类型范围。如果您实际尝试使用type参数执行某些操作,例如:
class Gen3<T extends Number> {
T val;
<T extends Number> Gen3(T ob) {
val = ob;
}
}
即使两个T
具有相同的类型绑定,也不会通过编译,因为ob
的类型参数与val
的类型参数不同。
答案 1 :(得分:2)
“因为这是T”的两个相互矛盾的界限 - 没有。只有两个单独的T
定义彼此无关。构造函数上的T
隐藏了类的T
,与本地变量和同名字段相同。 “正确”的IDE会告诉您内部T
隐藏了外部T
并且未使用。
答案 2 :(得分:1)
这个&#34;用例&#34;泛型在多个方面都没有意义。使用<T extends String>
子句,您将引入一个您不会使用的类型变量,并且不会让编译器有机会在给定的调用情况下用具体类型替换它。
您的定义等同于以下内容(我只是将两个不同的类型变量重命名为不同的名称,使讨论更容易):
class Gen3<T extends Number> {
T val;
<U extends String> Gen3(String ob) {
}
}
<U extends String>
子句告诉编译器:&#34;以下构造函数将使用类型参数U
,我只允许U
为String
或者String
&#34;的子类。正如其他人已经说过的那样,字符串是最终的,因此U
只能是String
,所以它不是真正的变量类型,并且声明一个无法变化的变量类型并不是#&# 39;有意义。我将继续修改版本:
class Gen3<T extends Number> {
T val;
<U extends Collection> Gen3(String ob) {
}
}
如果你做Gen<Integer> a=new Gen<Integer>("r");
,编译器应该如何找出用{1}}替换的具体类? U
部分适用于<Integer>
变量,因此对T
没有帮助。由于您没有在任何参数中引用U
,因此编译器没有提示。
泛型的概念是一个类有一些元素,你想允许不同的类型,并允许编译器标记滥用,例如将U
添加到Integer
:
List<String>
此处,编译器可以将通用List<String> myList = new ArrayList<String>();
myList.add(new Integer(12345));
类型参数List<E>
与E
(来自String
声明)进行匹配。在此上下文中,gegeric List<String>
方法声明变为List.add(E e)
,并且与add(String e)
的使用不匹配,这不是new Integer(12345)
,允许编译器标记错误。
<强>要点:强>
仅当您为编译器提供从调用参数中推导出它的机会时才引入类型参数。