我注意到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。
有关此的任何参考?
答案 0 :(得分:92)
与section 5.5 Casting Conversion of Java 7 JLS相比,the same section in the Java 5/6 JLS中的语言似乎已更新,可能是为了澄清允许的转化次数。
Java 7 JLS说
引用类型的表达式可以通过拆箱转换进行转换为基本类型而无错误。
Java 5/6:
引用类型的值可以通过拆箱转换(第5.1.8节)转换为基本类型。
Java 7 JLS还包含一个允许转换的表(表5.1)(此表不包含在Java 5/6 JLS中),从引用类型到基元。这显式地将从Object转换为基元的转换作为带有拆箱的缩小引用转换。
原因在this email中解释:
底线:如果规格。 allow(Object)(int)它也必须是allow(int)(Object)。
答案 1 :(得分:35)
Object o = new Integer(1234);
int x = (int) o;
这适用于Java 7,但在Java 6及更低版本中提供了编译错误。奇怪的是,这个特征没有突出的记录;例如,它没有提到here。如果它是一个新功能或错误修复(或一个新的错误?),这是有争议的,请参阅一些related info and discussion。共识似乎指向原始规范中的ambiguity,这导致Java 5/6上的稍微不正确/不一致的实现,其在7中被修复,因为它对于JSR 292的实现是至关重要的(动态类型)语言)。
Java autoboxing现在有更多的陷阱和惊喜。例如
Object obj = new Integer(1234);
long x = (long)obj;
将编译,但在运行时失败(使用ClassCastException
)。相反,这将起作用:
long x = (long)(int)obj;