下列类定义了两种方法,它们在直观上都具有相同的功能。每个函数都有两个类型List<? super Integer>
和一个布尔值的列表来调用,该值指定应将这些列表中的哪个分配给局部变量。
import java.util.List;
class Example {
void chooseList1(boolean choice, List<? super Integer> list1, List<? super Integer> list2) {
List<? super Integer> list;
if (choice)
list = list1;
else
list = list2;
}
void chooseList2(boolean choice, List<? super Integer> list1, List<? super Integer> list2) {
List<? super Integer> list = choice ? list1 : list2;
}
}
根据javac 1.7.0_45
,chooseList1
有效而chooseList2
无效。它抱怨:
java: incompatible types
required: java.util.List<? super java.lang.Integer>
found: java.util.List<capture#1 of ? extends java.lang.Object>
我知道查找包含三元运算符(… ? … : …
)的表达式类型的规则非常复杂,但是据我了解,它选择了最具体的类型,第二个和第三个参数都可以转换为该类型,而无需显式投。在这里,应该是,List<? super Integer> list1
但不是。
我想解释一下为什么不是这种情况,最好参考 Java语言规范, 并给出直观的解释,说明如果不能避免,可能会出错。
此答案适用于Java 7。
Java语言规范规定了有关条件运算符()的以下内容? :
否则,第二和第三操作数分别为S1和S2类型。令T1为对S1进行装箱转换所产生的类型,而T2为对S2进行装箱转换所产生的类型。
条件表达式的类型是将捕获转换(§5.1.10)应用于lub(T1,T2)(§15.12.2.7)的结果。
在表达中
List<? super Integer> list = choice ? list1 : list2;
T1
是List<capture#1? super Integer>
并且T2
是List<capture#2? super Integer>
。两者都有下限。
本文详细介绍了如何计算lub(T1, T2)
(或join function
)。让我们从那里举个例子
<T> T pick(T a, T b) {
return null;
}
<C, A extends C, B extends C> C test(A a, B b) {
return pick(a, b); // inferred type: Object
}
void tryIt(List<? super Integer> list1, List<? super Integer> list2) {
test(list1, list2);
}
如果使用IDE并将鼠标悬停在test(list1, list2)
,您会注意到返回类型为
List<? extends Object>
这是Java的类型推断可以做的最好的事情。如果list1
为a List<Object>
和list2
为a
List<Number>
,则唯一可接受的返回类型为List<? extends Object>
。因为必须解决这种情况,所以该方法必须始终返回该类型。
同样在
List<? super Integer> list = choice ? list1 : list2;
该lub(T1, T2)
又是List<? extends Object>
和它的捕获转换List<capture#XX of ? extends Object>
。
最后,List<capture#XX of ? extends Object>
不能将类型的引用分配给类型的变量,List<? super Integer>
因此编译器不允许这样做。
null 编译,我真的不明白为什么。基本上与第1行相同的问题。是的超类,如何将超类的成员放入此中? 编译。与第1行相同的问题。
根据Joshua Bloch的“有效Java”一书,关于如何/何时在泛型中使用有界通配符有一个规则。这个规则就是PECS(productor-extends,Comsumer-Super)。当我研究以下示例时: 根据PECS规则,上述声明是错误的。但是我希望有一个的,并向这个传递一个。为什么不做呢? 为什么要始终使用关键字?为什么使用是错误的? 当然,这也代表了Comsumer的观点。为什么消费者
我正在与Java8通配符泛型作斗争。 假设一个名为的泛型类(来自Core Java book) 是因为Java8编译器转换吗?超级经理反对,因此任何事情都是允许的?
在了解Java泛型的过程中,我遇到了以下问题: 假设我有下面的方法来添加列表的元素,只限于包含数字的列表。 但是这段代码和这段代码有什么不同: 它们都按预期编译和执行。这两者之间有什么区别?除了语法之外?什么时候我更喜欢使用通配符而不是前者? 是的,使用通配符方法,我不能在列表中添加除null之外的新元素,否则它将无法编译。除此之外呢?
问题内容: 我知道Java的泛型类型有各种各样的违反直觉的属性。特别是我不理解的一个,希望有人可以向我解释。为类或接口指定类型参数时,可以对其进行绑定,以使其必须使用来实现多个接口。但是,如果要实例化实际对象,则此方法不再起作用。很好,但是无法编译。考虑以下完整代码段: 似乎应该明确定义的语义-我想通过允许两种类型(而不只是一种类型)的交集,不会损失类型安全性。我敢肯定有一个解释。有谁知道它是什么
在试图理解java泛型类型和通配符“?”的用法时,我尝试了以下方法: 我得到以下编译错误(使用Oracle JDeveloper作为IDE): 为什么上面的代码不能编译,而赋值却可以呢?另外,如果我想调用,什么是可接受的参数值?