自动装箱调用valueOf()?

我试图确定下列陈述是否保证是正确的:

((Boolean)true) == Boolean.TRUE ((Boolean)true) == Boolean.valueOf(true) ((Integer)1) == Integer.valueOf(1) 

我一直认为自动装箱就相当于在相应的types上调用valueOf() 。 我在这个话题上看到的每一个讨论似乎都支持我的假设。 但是我能在JLS中find以下内容( §5.1.7 ):

如果值为p的盒子是一个介于-128127之间(§3.10.1)的inttypes的整数文字,或者是布尔文字truefalse (§3.10.3),或者在'\u0000'和(§3.10.4),然后让ab成为p的任意两个装箱转换的结果。 总是这样, a == b

这描述了 valueOf()相似的行为。 但是似乎没有任何保证valueOf()被实际调用,这意味着在理论上可以有一个实现为自动复制值保留一个单独的专用caching。 在这种情况下,caching自动复制值和常规caching盒装值之间可能不存在标识相等性。

Oracle的自动装箱教程指出事实上, li.add(i)被编译为li.add(Integer.valueOf(i)) ,其中i是一个int 。 但是我不知道教程是否应该被认为是一个权威的来源。


*这是一个比valueOf()略弱的保证,因为它只涉及字面值。

我首先想到你的问题是编译器为自动装箱生成什么代码?

不过,在您对@ElliottFrisch发表评论后,我意识到这是不同的:

我知道编译器的行为方式。 我试图弄清楚这种行为是否有保证。

对于其他读者来说,假设“performance那样”意味着使用valueOf

请记住,Java有多个编译器。 为了“合法”,他们必须遵循JLS中给出的合同。 因此,只要这里的所有规则都得到尊重,就不能保证内部如何实行自动装箱。

但我没有看到任何不使用valueOf理由,特别是它使用caching的值,并且是Joseph D. Darcy 本文的推荐方式。

在语言规范提到它之前,不能保证自动装箱就等同于调用静态的valueOf方法。 这是一个实现方面,不是拳击转换规范的一部分。 一个实现在理论上可以自由使用另一种机制,只要符合你从JLS提到的规则。

在实践中,有许多Sun JDK错误报告(例如JDK-4990346和JDK-6628737 ),这些报告明确暗示,当在Java 5中引入自动装箱时,其意图是使编译器依赖于JDO-6628737中所述的valueOf

在JDK 5中引入了静态工厂方法Integer.valueOf(int),Long.valueOf(long)等,以实现自动装箱规范所要求的caching行为。

但是,这只是为了javac,不一定是所有的编译器。

Autoboxing绝对在OpenJDK中使用valueOf() …实现的。 如果这是您的实施,请继续阅读…如果没有,请跳到下面。

 ((Boolean)true) == Boolean.TRUE ((Boolean)true) == Boolean.valueOf(true) 

Java文档指出, Boolean.valueOf()总是返回Boolean.TRUEBoolean.FALSE ,因此在这些情况下您的引用比较将会成功。

 ((Integer)1) == Integer.valueOf(1) 

对于这个特殊的例子,在默认设置的OpenJDK实现下,它可能会起作用,因为你select了一个在启动时caching的值(尽pipe这可以作为命令行参数被覆盖)。 如果频繁使用足够的caching,它也可能适用于较大的值。 除非你在“整数”caching的“安全”假设下工作,否则不要期望参考比较是平等的。

LongShortCharacterByte顺带实现了这个caching,但与Integer不同,它不可调整。 如果您比较autobox / valueOf()引用, Byte将始终工作,因为显然,您不能超出范围。 FloatDouble将不会令人惊讶的总是创造一个新的实例。


现在,纯粹通用的术语? 请参阅JLS的这一部分 – 在-128到127范围内,您必须给予boolean和任何intchar等同的引用。 没有别的保证

Oracle的自动装箱教程指出事实上,li.add(i)被编译为li.add(Integer.valueOf(i)),其中i是一个int。 但是我不知道教程是否应该被认为是一个权威的来源。

我正在运行Oracle Java 1.7.0_72它看起来像使用valueOf。 下面是一些代码和它的字节码。 字节码显示它正在使用valueOf。

 public class AutoBoxing { /** * @param args the command line arguments */ public static void main(String[] args) { Integer x = 5; int i = x; System.out.println(x.toString()); } } Compiled from "AutoBoxing.java" public class testing.AutoBoxing { public testing.AutoBoxing(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: iconst_5 1: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 4: astore_1 5: aload_1 6: invokevirtual #3 // Method java/lang/Integer.intValue:()I 9: istore_2 10: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream; 13: aload_1 14: invokevirtual #5 // Method java/lang/Integer.toString:()Ljava/lang/String; 17: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 20: return 

但是我不知道Open JDK使用什么。 会试试看。