【问题标题】:Compilation error with generics and ternary operator in JDK 7JDK 7 中泛型和三元运算符的编译错误
【发布时间】:2014-06-16 09:36:44
【问题描述】:

我在编写一些 Java 代码时遇到了编译失败,我将其提炼为以下测试用例:

import java.util.Collections;
import java.util.List;

public class TernaryFailure {
    public static List<String> thisWorks() {
        return Collections.emptyList();
    }

    public static List<String> thisFailsToCompile() {
        return true ? Collections.emptyList() : Collections.emptyList();
    }
}

上面的代码使用 JDK 1.7.0_45 编译 javac 失败:

$ javac TernaryFailure.java
TernaryFailure.java:10: error: incompatible types
        return true ? Collections.emptyList() : Collections.emptyList();
                    ^
  required: List<String>
  found:    List<Object>
1 error

但是,它使用 JDK 1.8.0_05 编译时没有任何错误。

这是 Java 7 实现中的错误吗?或者是否对 Java 8 中的 Java 语言规范进行了增强以开始允许这样做——如果是,有什么变化?

【问题讨论】:

标签: java generics java-7 java-8 ternary-operator


【解决方案1】:

JLS SE 8 在 (§15.2) 上说:

当某些表达式出现在某些上下文中时,它们被认为是多边形表达式。以下形式的表达式可能是poly表达式:

  • 带括号的表达式 (§15.8.5)

  • 类实例创建表达式(§15.9)

  • 方法调用表达式(§15.12)

  • 方法引用表达式(§15.13)

  • 条件表达式(§15.25)

  • Lambda 表达式 (§15.27)

因此,从规范的这一部分可以清楚地看出,条件表达式(三元运算符)可以被视为多义表达式。但并不是所有的条件表达式都可以认为是poly表达式,只能根据(§15.25)引用条件表达式。 (§15.25.3) 阐明了可以将参考条件表达式视为 poly 表达式的条件:

如果引用条件表达式出现在赋值上下文或调用上下文中(第 5.2 节、第 5.3 节),则它是一个多边形表达式。否则,它是一个独立的表达式。

如果多引用条件表达式出现在目标类型为 T 的特定类型的上下文中,它的第二个和第三个操作数表达式同样出现在目标类型为 T 的相同类型的上下文中。

多引用条件表达式的类型与其目标类型相同。

检查您的示例中的条件表达式是否出现在赋值上下文中,因为根据(§14.17)

当带有表达式的返回语句出现在方法声明中时,表达式必须可分配(第 5.2 节)到方法声明的返回类型,否则会发生编译时错误。

所以说到底,这一切意味着什么?这意味着当条件表达式是 poly 表达式时,目标类型被“下推”到每个操作数。这样,编译器可以根据目标将条件的每个部分归因。在您的情况下,目标是List&lt;String&gt;。如果我们检查 emptyList() 方法的定义:

@SuppressWarnings("unchecked")
public static final <T> List<T> emptyList() {
    return (List<T>) EMPTY_LIST;
}

因此对于目标List&lt;String&gt;,编译器可以推断出 T == String 并且代码被接受。

【讨论】:

    猜你喜欢
    • 2017-05-12
    • 1970-01-01
    • 2015-09-21
    • 2012-12-18
    • 1970-01-01
    • 2015-07-28
    • 1970-01-01
    • 1970-01-01
    • 2017-09-25
    相关资源
    最近更新 更多