Boxing/unboxing costs and do boxed objects have copy on write?



From what I understand, Java has boxed (heap) and unboxed (stack) variables, and if I assign a boxed type to an unboxed type or vice-versa there is a(n) (un)boxing cost involved.

Is unboxing cheaper than allocating a new boxed object? And do boxed objects support COW if used readonly?

class MyClass {
   public String myString;
   public Long myLong;
   public MyClass(String s, Long l) {
      myString = s;
      myLong = l;
   }
}

MyClass cls = new MyClass("A string", 5L);
Long l2 = cls.myLong; // does l2 and cls.myLong share memory or is new memory allocated here?
if (l2 < 10) {
   l2 += 5; // now l2 must have its own memory
}

Answer

Wrapping types are not on the heap because they box a primitive type but because they are objects. Primitive types can live on the stack, as local variables, or on the heap, as member variables.

What happens in your example is:

  • Long l2 = cls.myLong; assigns the reference of the object behind class.myLong to l2, or in other words: l2 now references the same object as class.myLong.
  • l2 += 5; unboxes the object referenced by l2, adds 5 to the value, wraps the result in a new instance of Long and assigns the reference of that new instance to l2, or in other words: l2 now references a new object, which wraps the result.

Imagine this example code:

public class Test {
    public static void main(String[] args) {
        Long long1 = Long.valueOf(1);
        Long long2 = long1 + 1;
    }
}

Compile it (javac Test.java) and see the bytecode (javap -c Test):

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

  public static void main(java.lang.String[]);
    Code:
       0: lconst_1
       1: invokestatic  #2                  // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
       4: astore_1
       5: aload_1
       6: invokevirtual #3                  // Method java/lang/Long.longValue:()J
       9: lconst_1
      10: ladd
      11: invokestatic  #2                  // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
      14: astore_2
      15: return
}

You can see that the addition to long1 expands to a call of longValue, the “unboxing”, and valueOf, the “boxing”. Like in your example, a new instance is created.

Is unboxing cheaper than allocating a new boxed object?

As we have seen, unboxing is more or less equivalent to calling a method. Creating a new instance includes more steps, e.g. additionally allocating memory.

And do boxed objects support COW if used readonly?

These classes are immutable so copy-on-write is what they always do.



Source: stackoverflow