Java 对方法返回值的拆箱

Z.S*_*.SP 3 java unboxing

给出以下方法:

Long getLong() {
    ...
}
Run Code Online (Sandbox Code Playgroud)

如果我调用它并将返回值分配给这样的变量:

long abc = getLong();
Run Code Online (Sandbox Code Playgroud)

Long生成一个对象然后转换为 long 还是 Java 足够聪明以避免生成中间Long对象?或者它实际上可能取决于getLong()?

我问这个的原因是包装对象的大小通常比相应的原始类型大小大得多。如果我必须多次调用此方法,并且每次都需要为Long对象分配内存,则程序最终将消耗比实际需要更多的内存,从而触发更多的 GC 周期。

此外,我如何验证执行时发生的确切步骤long abc = getLong()(基本上也在寻找有关如何获得上述问题的答案的指导)?

Edw*_*rzo 5

也许测试您的问题的最简单方法是编写一个小示例,然后运行 ​​Java 反汇编程序。

假设我们有这个类:

public class Unboxing {

    public static void main(String[] args) {
        long l = getLong();
    }

    public static Long getLong() {
        return 10L;
    }

}
Run Code Online (Sandbox Code Playgroud)

然后我们可以编译它 ( javac Unboxing.java),一旦编译,我们就可以反汇编它 ( javap -c -s Unboxing) 以查看它的字节码并了解 JVM 在幕后做了什么。

public class Unboxing {
  public Unboxing();
    descriptor: ()V
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    Code:
       0: invokestatic  #7                  // Method getLong:()Ljava/lang/Long;
       3: invokevirtual #13                 // Method java/lang/Long.longValue:()J
       6: lstore_1
       7: return

  public static java.lang.Long getLong();
    descriptor: ()Ljava/lang/Long;
    Code:
       0: ldc2_w        #19                 // long 10l
       3: invokestatic  #21                 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
       6: areturn
}
Run Code Online (Sandbox Code Playgroud)

可以在代码中看到它获取了一个Long对象,然后longValue在上面调用了它的方法:

0: invokestatic  #7                  // Method getLong:()Ljava/lang/Long;
3: invokevirtual #13                 // Method java/lang/Long.longValue:()J
Run Code Online (Sandbox Code Playgroud)

之后,它将其存储到变量l( lstore_1) 中。

所以,这可能回答了你的问题。