Java 自动装箱是否调用valueOf()?

Java 自动装箱是否调用valueOf()?,java,boxing,autoboxing,Java,Boxing,Autoboxing,我试图确定以下陈述是否保证属实: ((Boolean)true) == Boolean.TRUE ((Boolean)true) == Boolean.valueOf(true) ((Integer)1) == Integer.valueOf(1) 我一直认为自动装箱相当于对相应类型调用valueOf()。我在网上看到的每一件事似乎都符合我的假设。但我在JLS中只能找到以下内容(): 如果要装箱的值p是int类型介于-128和127之间的整数文字(§3.10.1),或布尔文字true或fals

我试图确定以下陈述是否保证属实:

((Boolean)true) == Boolean.TRUE
((Boolean)true) == Boolean.valueOf(true)
((Integer)1) == Integer.valueOf(1)
我一直认为自动装箱相当于对相应类型调用
valueOf()
。我在网上看到的每一件事似乎都符合我的假设。但我在JLS中只能找到以下内容():

如果要装箱的值
p
int
类型介于
-128
127
之间的整数文字(§3.10.1),或布尔文字
true
false
(§3.10.3),或介于
'\u0000'
'\u007f'
之间的字符文字(§3.10.4),然后让
a
b
p
的任意两个装箱转换的结果。通常情况下,
a==b

它描述的行为与
valueOf()
的行为相同或相似。但似乎无法保证实际调用了
valueOf()
,这意味着理论上可能有一个实现为自动装箱的值保留单独的专用缓存。在这种情况下,缓存的自动装箱值和常规缓存的装箱值之间可能不存在标识相等

事实上,声明
li.add(i)
被编译为
li.add(Integer.valueOf(i))
,其中
i
int
。但是我不知道这篇教程是否应该被认为是一个权威的来源



*它的保证比valueOf()稍弱一些,因为它只涉及文字值。

首先我认为你的问题是重复的

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

我知道编译器就是这样运行的。我想弄清楚 这种行为是有保证的

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

请记住,Java有多个编译器。为了“合法”,他们必须遵守合同中给出的合同。因此,只要遵守这里的所有规则,就无法保证自动装箱在内部是如何实现的

但是我不认为有任何理由不使用
valueOf
,特别是它使用缓存的值,这是Joseph D.Darcy推荐的方法

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

我正在运行Oracle Java 1.7.072,看起来它确实使用了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
公共类自动装箱{
/**
*@param指定命令行参数
*/
公共静态void main(字符串[]args){
整数x=5;
int i=x;
System.out.println(x.toString());
}
}
从“AutoBoxing.java”编译而来
公共类测试.自动装箱{
公开测试。自动装箱();
代码:
0:aload_0
1:invokespecial#1//方法java/lang/Object。“:()V
4:返回
公共静态void main(java.lang.String[]);
代码:
0:iconst_5
1:invokestatic#2//方法java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
4:astore_1
5:aload_1
6:invokevirtual#3//方法java/lang/Integer.intValue:()I
9:istore_2
10:getstatic#4//fieldjava/lang/System.out:Ljava/io/PrintStream;
13:aload_1
14:invokevirtual#5//方法java/lang/Integer.toString:()Ljava/lang/String;
17:invokevirtual#6//方法java/io/PrintStream.println:(Ljava/lang/String;)V
20:返回

但是我不知道OpenJDK使用了什么。我会尝试一下。

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

在实践中,有许多Sun JDK错误报告(例如和)清楚地表明,当Java 5中引入自动装箱时,其目的是让编译器依赖
valueOf
,如中所述:

JDK5forJavaC中引入了静态工厂方法Integer.valueOf(int)、Long.valueOf(Long)等,以实现自动装箱规范所要求的缓存行为


但这仅适用于javac,不一定适用于所有编译器。

自动装箱绝对是使用OpenJDK中的
valueOf()
实现的。如果这是您的实现,请继续阅读…如果不是,请跳到下面

((Boolean)true) == Boolean.TRUE
((Boolean)true) == Boolean.valueOf(true)
Java文档说明
Boolean.valueOf()
始终返回
Boolean.TRUE
Boolean.FALSE
,因此在这些情况下,您的引用比较将成功

((Integer)1) == Integer.valueOf(1)
对于这个特定的示例,在带有默认设置的OpenJDK实现下,它可能会工作,因为您选择了一个<128的值,该值在启动时被缓存(尽管这可以作为命令行参数重写)。如果它经常被使用到足以缓存,则它也可能适用于较大的值。除非您是在关于整数缓存的“安全”假设下工作,否则不要期望引用比较是相等的

Long
Short
Character
Byte
也顺便实现了这种缓存,但与
Integer
不同,它是不可调的。
Byte
在比较autobox/
valueOf()时总是有效的
引用,因为显然,您不能超出范围。
Float
Double
总是会创建一个