107

我注意到 Java SE 6 和 Java SE 7 之间的自动拆箱行为存在差异。我想知道为什么会这样,因为我找不到这两个版本之间这种行为变化的任何文档。

这是一个简单的例子:

Object[] objs = new Object[2];
objs[0] = new Integer(5);
int myInt = (int)objs[0];

这与 Java SE 7 中的 javac 编译得很好。但是,如果我给编译器“-source 1.6”参数,我会在最后一行得到一个错误:

inconvertible types
found   : java.lang.Object
required: int

我尝试下载 Java SE 6 以使用本机版本 6 编译器进行编译(没有任何 -source 选项)。它同意并给出与上述相同的错误。

那么给了什么?从更多的实验来看,Java 6 中的拆箱似乎只能拆箱(在编译时)明显属于装箱类型的值。例如,这适用于两个版本:

Integer[] objs = new Integer[2];
objs[0] = new Integer(5);
int myInt = (int)objs[0];

因此,似乎在 Java 6 和 7 之间,取消装箱功能得到了增强,因此它可以一口气强制转换和取消装箱对象类型,而无需(在编译时)知道该值是否属于正确的装箱类型。但是,通过阅读 Java 7 发布时编写的 Java 语言规范或博客文章,我看不出这件事有什么变化,所以我想知道变化是什么,这个“特性”叫什么?

只是好奇:由于更改,可能会触发“错误”的拆箱:

Object[] objs = new Float[2];
objs[0] = new Float(5);
int myInt = (int)objs[0];

这编译得很好,但在运行时会给出 ClassCastException。

对此有任何参考吗?

4

2 回答 2

93

与 Java 5/6 JLS 中的同一部分相比,Java 7 JLS 的 5.5 Casting Conversion 部分中的语言似乎已更新,可能是为了阐明允许的转换。

Java 7 JLS 说

引用类型的表达式可以通过取消装箱转换无错误地转换为原始类型。

Java 5/6:

可以通过拆箱转换(第 5.1.8 节)将引用类型的值强制转换为原始类型。

Java 7 JLS 还包含一个表(表 5.1),其中包含从引用类型到原语的允许转换(该表不包含在 Java 5/6 JLS 中)。这明确列出了从 Object 到基元的转换,作为取消装箱的缩小引用转换。

原因在此电子邮件中解释:

底线:如果规格。允许 (Object)(int) 它也必须允许 (int)(Object)。

于 2013-04-20T13:32:19.763 回答
35

你说的对; 更简单地说:

Object o = new Integer(1234);
int x = (int) o;

这在 Java 7 中有效,但在 Java 6 及更低版本中会出现编译错误。奇怪的是,这个特性并没有被显着记录。例如,这里没有提到。如果它是新功能还是错误修复(或新错误?),这是值得商榷的,请参阅一些相关信息和讨论。共识似乎指向原始规范中的模棱两可,这导致 Java 5/6 上的实现稍微不正确/不一致,该实现在 7 中得到修复,因为它对于 JSR 292(动态类型语言)的实现至关重要。

Java 自动装箱现在有更多的陷阱和惊喜。例如

Object obj = new Integer(1234);
long x = (long)obj;

将编译,但ClassCastException在运行时失败(带有 )。相反,这将起作用:

long x = (long)(int)obj;

于 2013-04-20T12:41:28.197 回答