JDK 7中的泛型和三元运算符的编译错误 [英] Compilation error with generics and ternary operator in JDK 7

查看:206
本文介绍了JDK 7中的泛型和三元运算符的编译错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在编写一些Java代码时碰到了一个编译失败的问题,我将其解析为以下测试用例:

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

公共类TernaryFailure {
public static List< String> thisWorks(){
返回Collections.emptyList();
}

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




$ b $ p
$ b

上面的代码无法用<$ c $进行编译


  $ javac TernaryFailure 使用JDK 1.7.0_45:javac  .java 
TernaryFailure.java:10:错误:不兼容的类型
返回true? Collections.emptyList():Collections.emptyList();
^
要求:列表< String>找到
:List< Object>
1错误


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



这是Java 7实现中的一个错误吗?或者是否对Java 8中的Java语言规范进行了改进,以便开始允许这样做 - 如果是这样,那么改变了什么?

解决方案

< JLS SE 8在( §15.2):


当某些表达式出现在特定的上下文中时,它们被视为多表达式。以下表达式可能是多表达式: >

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

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

    li>
  • 方法引用表达式(第15.13节)

  • 条件表达式(第15.25节)

  • >
  • Lambda表达式(§15.27)



  • <因此,从规范的这一部分可以看出,条件表达式即三元运算符可以被看作是多表达式。但并非所有条件表达式都可以被视为多表达式,只能根据(第15.25节)。可以将参考条件表达式视为多表达式的条件在(§15.25.3)


    参考条件表达式是一个poly表达式(如果它出现在赋值语境或调用语境中)(§5.2。§5.3)。



    当多参考条件表达式出现在特定种类的目标类型为T的上下文中时,它的第二个和第三个操作数表达式类似地出现在与目标类型T相同类型的上下文中。

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


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


    当一个带有Expression的return语句出现在一个方法声明中时,Expression必须是可分配的(§5.2)给该方法的声明返回类型,否则会发生编译时错误。


    所以在一天结束时,这意味着什么?这意味着当条件表达式是多表达式时,目标类型被下推到每个操作数。通过这种方式,编译器可以将条件的每个部分都归于目标。在你的情况下,目标是 List< String> 。如果我们检查emptyList()方法的定义,我们有:

      @SuppressWarnings(unchecked)
    public静态最终< T>列表与LT; T> emptyList(){
    return(List< T>)EMPTY_LIST;





    $ b

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


    I ran into a compilation failure while writing some Java code, which I distilled down to the following test case:

    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();
        }
    }
    

    The code above fails to compile with javac with JDK 1.7.0_45:

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

    However, it compiles without any error with JDK 1.8.0_05.

    Is that a bug in the Java 7 implementation? Or was there an enhancement to the Java Language Specification in Java 8 to start allowing this — and if so, what was the change?

    解决方案

    The JLS SE 8 says at (§15.2):

    When some expressions appear in certain contexts, they are considered poly expressions. The following forms of expressions may be poly expressions:

    • Parenthesized expressions (§15.8.5)

    • Class instance creation expressions (§15.9)

    • Method invocation expressions (§15.12)

    • Method reference expressions (§15.13)

    • Conditional expressions (§15.25)

    • Lambda expressions (§15.27)

    So from this part of the spec is clear that conditional expressions, the ternary operator, can be considered poly expressions. But not all conditional expressions can be considered poly expressions, only reference conditional expressions according to (§15.25). The conditions under which a reference conditional expression can be considered a poly expression are clarified at (§15.25.3):

    A reference conditional expression is a poly expression if it appears in an assignment context or an invocation context (§5.2. §5.3). Otherwise, it is a standalone expression.

    Where a poly reference conditional expression appears in a context of a particular kind with target type T, its second and third operand expressions similarly appear in a context of the same kind with target type T.

    The type of a poly reference conditional expression is the same as its target type.

    Check that in your example the conditional expression appears in an assignment context because according to (§14.17):

    When a return statement with an Expression appears in a method declaration, the Expression must be assignable (§5.2) to the declared return type of the method, or a compile-time error occurs.

    So at the end of the day, what all this means? This implied that when conditional expressions are poly expressions, the target type is "pushed down" to each operand. This way the compiler can attribute each part of the condition, against the target. In your case the target is List<String>. If we check the definition of the emptyList() method we have:

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

    So with the target List<String>, the compiler can infer that T == String and the code is accepted.

    这篇关于JDK 7中的泛型和三元运算符的编译错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆