Java unboxing on method return value

Given following method:

Long getLong() {
    ...
}

If I call it and assign the return value to a variable like this:

long abc = getLong();

Will a Long object get generated and then converted to long or Java is smart enough to avoid generating the intermediate Long object? Or it might actually depends on the implementation of getLong()?

The reason I am asking this is that the wrapper object size is usually much bigger than the corresponding primitive type size. If I have to call this method a lot of times and each time memory needs to be allocated to the Long object, the program will end up consuming a lot more memory than it actually needs, which triggers more GC cycles.

Also, how can I verify the exactly steps happening when executing long abc = getLong() (basically also looking for guidance on how can I get answers myself for the questions above)?

Answer

Perhaps the simplest way to test your question is by writing a small example and then run the Java disassembler.

Let’s say we had this class:

public class Unboxing {

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

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

}

Then we can compile it (javac Unboxing.java) and once compiled we can disassemble it (javap -c -s Unboxing) to see its bytecodes and learn what the JVM is doing under the hood.

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
}

You can see in the code that it gets an Long object, and then call its longValue method on it:

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

After that it stores it into the variable l (lstore_1).

So, that probably answers your question.

Leave a Reply

Your email address will not be published. Required fields are marked *