Java 6与Java 7之间的自动拆箱差异
我已经注意到在Java SE 6和Java SE 7之间的自动拆箱行为有所不同。我想知道为什么,因为在这两个版本之间我找不到任何有关此行为更改的文档。
这是一个简单的例子:
Object[] objs = new Object[2]; objs[0] = new Integer(5); int myInt = (int)objs[0];
这个编译良好的javac从Java SE 7.但是,如果我给编译器“-source 1.6”参数,我在最后一行得到一个错误:
inconvertible types found : java.lang.Object required: int
我尝试下载Java SE 6以使用本机版本6编译器进行编译(不带任何-source选项)。 它同意并给出与上述相同的错误。
那么给了什么? 从一些更多的实验看来,Java 6中的拆箱似乎只能清除(在编译时)是盒装types的值。 例如,这两个版本的作品:
Integer[] objs = new Integer[2]; objs[0] = new Integer(5); int myInt = (int)objs[0];
所以看起来,在Java 6和7之间,拆箱function得到了增强,因此它可以一次性投射和取消投放对象types,而不知道(在编译时)该值是否是适当的盒装types。 但是,阅读Java语言规范或Java 7发布时撰写的博客post,我看不出有什么变化,所以我想知道这个变化是什么,这个“特性”叫做什么?
只是一个好奇心:由于改变,有可能触发“错误的”拆箱:
Object[] objs = new Float[2]; objs[0] = new Float(5); int myInt = (int)objs[0];
这编译好,但在运行时给出一个ClassCastException。
有没有这方面的参考?
它看起来像第5.5 节中的语言,与Java 5/6 JLS中的同一部分相比,Java 7 JLS的“铸造转换”已更新,可能会澄清允许的转换。
Java 7 JLS说
通过拆箱转换,引用types的expression式可经历转换到基本types而没有错误。
Java 5/6:
一个引用types的值可以通过拆箱转换(第5.1.8节)转换为基本types。
Java 7 JLS还包含从引用types到基元的允许转换(此表不包含在Java 5/6 JLS中)的表(表5.1)。 这明确地列出了从Object到primitives的强制转换,并将其作为缩小的参考转换进行拆箱。
原因在这封电子邮件中解释:
底线:如果规格。 允许(Object)(int)它也必须允许(int)(Object)。
你是对的; 更简单地说:
Object o = new Integer(1234); int x = (int) o;
这在Java 7中起作用,但在Java 6及更低版本中出现编译错误。 奇怪的是,这个function没有明显的logging; 例如, 这里没有提到。 这是一个新function或错误修复(或一个新的错误?),是有争议的,看到一些相关的信息和讨论 。 这个共识似乎指向了原始规范中的一个模棱两可的问题,这导致了在Java 5/6上稍微不正确/不一致的实现,该实现在7中得到了修正,因为这对实现JSR 292(dynamictypes化语言)至关重要。
Java自动装箱现在有更多的陷阱和惊喜。 例如
Object obj = new Integer(1234); long x = (long)obj;
将在运行时编译,但会失败(带有ClassCastException
)。 相反,这将工作:
long x = (long)(int)obj;