【问题标题】:What code does the compiler generate for autoboxing?编译器为自动装箱生成什么代码?
【发布时间】:2009-01-03 05:32:02
【问题描述】:

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

  • 包装器上的 valueOf() 方法
  • 包装器的构造函数
  • 其他魔法?

【问题讨论】:

    标签: java autoboxing


    【解决方案1】:

    您可以使用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
    
    }
    

    因此,如您所见,自动装箱会调用静态方法Integer.valueOf(),而自动拆箱会在给定的Integer 对象上调用intValue()。真的没有别的了 - 它只是语法糖。

    【讨论】:

    • 有趣的是,它调用 valueOf(int) 而不是 new Integer(int) 来将 int 转换为 Integer。 valueOf 对前 1000 个左右的整数进行对象缓存。
    • @Craig:准确地说,-128 到 127 必须被缓存,其他值可能被实现缓存。
    • 另外值得注意的是,编译器没有使用 Integer.valueOf - 语言规范只要求 a.intValue() == 3。docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.7
    • @PaŭloEbermann 更准确地说,你不能重新定义缓存的下限(除了一些肮脏的黑客):stackoverflow.com/questions/29633158/…
    【解决方案2】:

    我想出了一个单元测试,证明调用 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);
        }
    }
    

    【讨论】:

      【解决方案3】:

      如果您查找Integer#valueOf(int) 的 API 文档,您会发现它是在 JDK 1.5 中添加的。所有包装器类型(还没有)都添加了类似的方法来支持自动装箱。如 JLS 中所述,对于某些类型有额外的要求:

      如果被装箱的值 ptruefalsebytechar,范围在 \u0000\u007fintshort 介于-128127 之间的数字,则令r1r2p 的任意两次装箱转换的结果. r1 == r2 总是如此。 §5.1.7

      有趣的是,longs 不受相同要求的约束,尽管在 Sun 的实现中缓存了 -128..127 范围内的 Long 值,就像其他整数类型一样。

      我还刚刚发现,在我的 The Java Programming Language 副本中,它说 char 值从 \u0000\u00ff 被缓存,但当然每个规范的上限是 \u007f(和 Sun JDK在这种情况下符合规范)。

      【讨论】:

        【解决方案4】:

        我建议使用jad 之类的内容并大量反编译代码。你可以学到很多关于 java 实际在做什么。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-07-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-11-17
          • 2014-10-03
          相关资源
          最近更新 更多