Java 编译器为自动装箱生成什么代码?

Java 编译器为自动装箱生成什么代码?,java,autoboxing,Java,Autoboxing,当Java编译器将原语自动装箱到包装器类时,它会在幕后生成什么代码?我想它叫: 包装器上的valueOf()方法 包装器的构造函数 还有别的魔法吗 您可以使用javap工具自己查看。编译以下代码: public class AutoboxingTest { public static void main(String []args) { Integer a = 3; int b = a; } } 要编译和反汇编: javac Autob

当Java编译器将原语自动装箱到包装器类时,它会在幕后生成什么代码?我想它叫:

  • 包装器上的valueOf()方法
  • 包装器的构造函数
  • 还有别的魔法吗

您可以使用
javap
工具自己查看。编译以下代码:

public class AutoboxingTest
{
    public static void main(String []args)
    {
        Integer a = 3;
        int b = a;
    }
}
要编译和反汇编:

javac AutoboxingTest.java
javap -c AutoboxingTest
输出为:

Compiled from "AutoboxingTest.java"
public class AutoboxingTest extends java.lang.Object{
public AutoboxingTest();
  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_3
   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:  return

}
从“AutoboxingTest.java”编译而来
公共类AutoboxingTest扩展了java.lang.Object{
公共自动装箱测试();
代码:
0:aload_0
1:invokespecial#1;//方法java/lang/Object。“:()V
4:返回
公共静态void main(java.lang.String[]);
代码:
0:iconst_3
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:返回
}

因此,正如您所看到的,自动装箱调用静态方法
Integer.valueOf()
,自动取消装箱调用给定
Integer
对象上的
intValue()
。真的,没有其他东西了——只是语法上的糖分。

我建议你经常使用类似的东西,并对代码进行反编译。您可以了解到java实际上在做什么。

我提出了一个单元测试,证明调用Integer.valueOf()而不是包装器的构造函数

import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame;

import org.junit.Test;

public class Boxing {
    @Test
    public void boxing() {
        assertSame(5, 5);
        assertNotSame(1000, 1000);
    }
}

如果您查找API文档,您将看到它是在JDK1.5中添加的。所有包装器类型(还没有)都添加了类似的方法来支持自动装箱。对于某些类型,如JLS中所述,还有一个附加要求:

如果要装箱的值p是
true
false
,在
\u0000
\u007f
范围内的
字节
字符
,或
int
-128
127
之间的
,则让r1和r2为p的任意两个装箱转换的结果。r1==r2总是这样


值得注意的是,
long
s不受相同要求的约束,尽管与其他整数类型一样,
-128..127
范围中的长值被缓存在Sun的实现中


我还发现,在我的副本中,它说从
\u0000
\u00ff
char
值是缓存的,但是当然每个规范的上限是
\u007f
(在本例中,Sun JDK符合规范)。

有趣的是,它调用了valueOf(int)而不是新的整数(int)将int转换为整数。valueOf对前1000个左右的整数进行对象缓存。@Craig:准确地说,必须缓存-128到127,其他值可以由实现缓存。另外值得注意的是,编译器不必使用Integer.valueOf-语言规范只要求a.intValue()==3@PaŭloEbermann更准确地说,你不能重新定义缓存的下限(除了一些肮脏的黑客):