在Java 7中是否允许从Number转换为double?(自动装箱)

Axe*_*xel 12 java eclipse unboxing

一位同事检查了这段代码:

    Number n = ...;
    double nr = n == null ? 0.0 : (double) n;
Run Code Online (Sandbox Code Playgroud)

然后另一位同事抱怨说这没有编译,这就是我所期待的.然而,事实证明我已经从SVN中提取了这些代码并且一切正常.我们都在eclipse中将Java版本设置为1.7,结果证明代码在eclipse 4.4.2(Luna)下编译得很好但在4.2.2下失败了.

我通过替换演员来解决问题n.doubleValue().

现在的实际问题是:为什么这首先被接受了?它当然应该工作的铸造时Double的代替double,但我认为,从直接投Numberdouble被判无效.那么,这是eclipse 4.2.2中的一个错误,在此期间修复了,或者eclipse 4.4.2是否默默接受不应该编译的代码(恕我直言,这将是一个错误)?

Raf*_*ter 6

对于Java 7,为了允许使用MethodHandles ,必须在原始类型方面略微改变转换系统.在调用方法句柄时,javac编译器会生成一个所谓的多态签名,该签名派生自方法句柄的方法签名.这些多态签名是通过使用强制转换提示出参数的类型来创建的.例如,当使用签名绑定方法时double, long -> int,需要进行以下转换:

Number foo = 42d, bar = 43L;
int ignored = (int) methodHandle.invoke((double) object, (long) bar);
Run Code Online (Sandbox Code Playgroud)

然而,源代码签名MethodHandle::invoke被定义为Object[] -> Object,在不直接将值转换为基元类型的情况下,不能生成多态签名.

显然,为了实现这一点,必须更改Java编译器以允许此类铸件以前不合法.虽然理论上可以将这种铸件的使用限制为带注释的方法@PolymorhicSignature,但这会导致一个奇怪的例外,为什么现在通常可以在javac中生成不创建多态签名时生成适当的字节代码的原因. .然而,原始类型仍然代表他们自己的运行时类型,而在另一个答案中指出了这种类型的铸件的生成字节代码.MethodHandle

Object foo = 42;
int.class.cast(foo);
Run Code Online (Sandbox Code Playgroud)

会导致运行时异常.

但是,我同意这些评论,这在JLS中未必适当地进行讨论,但我发现了一个提到这个规范差距的线索.有人提到,一旦lambda表达式到位,应该相应地更新规范,但JLS for Java 8似乎没有提到这样的castings或者@PolymorphicSignature其中之一.同时,它指出禁止明确允许的[a] ny转换.

可以说,JLS目前落后于javac实现,Eclipse编译器肯定没有正确地选择它.您可以将此与一般类型推断的一些角落情况进行比较,其中几个IDE编译器的行为与javac的行为不同,直到今天.