Java 6 与 Java 7 之间自动拆箱的差异

2022-08-31 09:54:03

我注意到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语言规范或Java 7问世时写的博客文章,我看不到这件事的任何变化,所以我想知道这个变化是什么,这个“功能”叫什么?

只是一个好奇心:由于变化,有可能触发“错误”的拆箱:

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

这可以很好地编译,但在运行时给出一个ClassCastException。

对此有什么参考吗?


答案 1

看起来Java 7 JLS的5.5节中的语言Java 5/6 JLS中的同一节中的语言进行了更新,可能是为了澄清允许的转换。

Java 7 JLS 说

通过取消装箱转换,引用类型的表达式可以进行强制转换为基元类型而不会出错。

Java 5/6:

可以通过取消装箱转换 (§5.1.8) 将引用类型的值强制转换为基元类型。

Java 7 JLS 还包含一个表(表 5.1),其中包含从引用类型到基元的允许转换(此表不包括在 Java 5/6 JLS 中)。这会将“对象”到基元的强制转换显式列为通过取消装箱进行缩小引用转换的范围。

原因在以下电子邮件中进行了说明:

底线:如果规范允许(Object)(int),它还必须允许(int)(Object)。


答案 2

你是对的;更简单地说:

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;


推荐