当前位置: 首页 > 面试题库 >

为什么三元运算符不喜欢带有有界通配符的泛型类型?

韦业
2023-03-14
问题内容

下列类定义了两种方法,它们在直观上都具有相同的功能。每个函数都有两个类型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_45chooseList1有效而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;

T1List<capture#1? super Integer>并且T2List<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): 为什么上面的代码不能编译,而赋值却可以呢?另外,如果我想调用,什么是可接受的参数值?