我正在尝试确定以下陈述是否可以保证为真:
((Boolean)true) == Boolean.TRUE
((Boolean)true) == Boolean.valueOf(true)
((Integer)1) == Integer.valueOf(1)
我一直认为自动装箱相当于在相应类型上调用valueOf()
。我在discussion上看到的topic似乎support我的假设。但我在JLS中找到的只有以下内容(§5.1.7):
如果装箱的值
的情况p
是int
和-128
之间的127
类型的整数文字(§3.10.1),或布尔文字{{ 1}}或true
(§3.10.3),或false
和'\u0000'
之间的字符文字(§3.10.4),然后让'\u007f'
和{{ 1}}是a
任意两次拳击转换的结果。始终是b
。
这描述了行为与<{1}}相似的 *。但似乎没有任何保证p
实际被调用,这意味着理论上可以有一个实现为自动装箱值保留一个单独的专用缓存。在这种情况下,缓存的自动装箱值和常规缓存的装箱值之间可能没有相同的身份。
Oracle's autoboxing tutorial明确说明a == b
已编译为valueOf()
,其中valueOf()
为li.add(i)
。但我不知道该教程是否应被视为权威来源。
*它比li.add(Integer.valueOf(i))
稍微弱一些,因为它只引用文字值。
答案 0 :(得分:29)
我首先提出你的问题是What code does the compiler generate for autoboxing?
的欺骗然而,在您对@ElliottFrisch发表评论后,我发现它有所不同:
我知道编译器的行为方式。我想知道是否 这种行为是有保障的。
对于其他读者,假设“表现那样”意味着使用valueOf
。
请记住,Java有多个编译器。为了“合法”,他们必须遵守JLS中给出的合同。因此,只要遵守此处的所有规则,就无法保证内部如何实现自动装箱。
但我认为没有任何理由不使用valueOf
,特别是它使用缓存的值,并且是Joseph D. Darcy根据this article建议的方式。
答案 1 :(得分:18)
在语言规范提到之前,无法保证自动装箱等同于对静态valueOf
方法的调用。它是实现方面,不是装箱转换规范的一部分。理论上,只要符合您在JLS中提到的规则,实现就可以自由使用其他机制。
在实践中,有很多Sun JDK错误报告(例如JDK-4990346和JDK-6628737)明确暗示在Java 5中引入自动装箱时,目的是让编译器依赖{{ 1}}如JDK-6628737中所述:
JDK 5中为javac引入了静态工厂方法Integer.valueOf(int),Long.valueOf(long)等,以实现自动装箱规范所需的缓存行为。
但这只适用于javac,不一定都是编译器。
答案 2 :(得分:4)
Autoboxing 绝对是在OpenJDK中使用valueOf()
...实现的。如果这是您的实施,请继续阅读......如果没有,请跳至下方。
((Boolean)true) == Boolean.TRUE
((Boolean)true) == Boolean.valueOf(true)
Java文档指出Boolean.valueOf()
始终返回Boolean.TRUE
或Boolean.FALSE
,因此在这些情况下您的参考比较将会成功。
((Integer)1) == Integer.valueOf(1)
对于这个特定的例子,在具有默认设置的OpenJDK实现下,由于您选择了一个值&lt; ,可能工作。 128在启动时缓存(虽然这可以作为命令行arg重写)。 可能也适用于较大的值,如果它经常被足够用于缓存。除非你在&#34; safe&#34;关于整数缓存的假设,不要期望参考比较是相等的。
Long
,Short
,Character
和Byte
也偶然实现了此缓存,但与Integer
不同,它不可调。如果您正在比较自动装箱/ Byte
参考,valueOf()
将始终有效,因为很明显,您无法超出范围。不出所料,Float
和Double
总会创建一个新实例。
现在,用纯粹的通用术语? See this section of the JLS - 必须在-128到127范围内为boolean
和任何int
或char
提供相同的参考。其他任何事情都有无保证。
答案 3 :(得分:-1)
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使用的是什么。会尝试一下。