问题

最近我正在阅读Spring Framework的源代码。我无法理解的东西在这里:

public Member getMember() {
    // NOTE: no ternary expression to retain JDK <8 compatibility even when using
    // the JDK 8 compiler (potentially selecting java.lang.reflect.Executable
    // as common type, with that new base class not available on older JDKs)
    if (this.method != null) {
        return this.method;
    }
    else {
        return this.constructor;
    }
}

此方法是classorg.springframework.core.MethodParameter的成员。代码很容易理解,而评论很难。

注意:即使使用JDK 8编译器,也没有三元表达式来保持JDK <8的兼容性(可能选择java.lang.reflect.Executable作为通用类型,旧的JDK上没有新的基类)

在这种情况下使用三元表达式和使用if...else...construct有什么区别?


#1 热门回答(102 赞)

当你考虑操作数的类型时,问题变得更加明显:

this.method != null ? this.method : this.constructor

具有两种操作数的最特殊的共同类型,即this.methodthis.constructor共有的最特殊类型。

在Java 7中,这是java.lang.reflect.Member,但Java 8类库引入了一个比genericMember更专业的新类型java.lang.reflect.Executable。因此,对于Java 8类库,三元表达式的结果类型为Executable,而不是Member

在编译三元运算符时,Java 8编译器的某些(预发布)版本似乎已生成对Executableinside生成的代码的显式引用。这将触发类加载,因此在运行类库<JDK 8时依次运行时运行时间为ClassNotFoundException,因为JDK≥8,因此存在Executable

正如Tagir Valeev在this answer中所指出的,这实际上是JDK 8预发布版本中的一个错误,并且已经修复,因此现在已经过时了.if-else工作方式和解释性注释都已过时。

**附加说明:**可能会得出结论,这个编译器错误出现在Java 8之前。但是,OpenJDK 7为三元生成的字节代码与OpenJDK 8生成的字节代码相同。实际上,类型为表达式在运行时完全没有提及,代码实际上只是测试,分支,加载,返回而不进行任何额外的检查。所以请放心,这不再是问题(在Java 8的开发过程中确实是一个临时问题)。


#2 热门回答(30 赞)

这是在2013年5月3日quite old commit推出的,差不多在官方JDK-8发布前一年。编译器在那些时候处于大量开发阶段,因此可能会出现这种兼容性问题。我想,Spring团队刚刚测试了JDK-8版本并尝试修复问题,即使它们实际上是编译器问题。通过JDK-8官方发布,这变得无关紧要。现在,此代码中的三元运算符正常工作(没有引用已编译的.class文件中的Executableclass)。

目前在JDK-9中出现了类似的东西:JDK-8中可以很好地编译的一些代码在JDK-9 javac中失败了。我想,大多数此类问题将在发布之前修复。


#3 热门回答(7 赞)

主要的不同之处在于anif``else阻止是三元数据(在Java中更常被称为条件运算符)是一种表达式。

在某些控制路径上,Astatement可以像return那样对调用者执行操作。 Anexpression可用于作业:
int n = condition ? 3 : 2;
因此条件之后的三元中的两个表达式需要可强制到同一类型。这可能会导致Java中出现一些奇怪的效果,尤其是自动装箱和自动引用 - 这就是你发布的代码中的注释所指的内容。在你的情况下,表达式的强制将是ajava.lang.reflect.Executabletype(因为它是最特殊的类型)并且在旧版本的Java中不存在。

从风格上讲,如果代码类似于语句,则应使用aif``else块;如果类似于表达式,则应使用三元数。

当然,如果使用lambda函数,可以使aif``else块的行为类似于表达式。


原文链接