In these cases, the Scala value class will be “boxed”, right?

后端 未结 3 649
-上瘾入骨i
-上瘾入骨i 2021-01-02 13:51

If I have this value class:

class ActionId(val value: Int) extends AnyVal

Then, in all the examples below, an object will be allocated for

3条回答
  •  攒了一身酷
    2021-01-02 14:46

    In all three cases there will be no boxing at all.

    It's quite easy to check by your self:

    class ActionId(val value: Int) extends AnyVal
    object Foo {
      def someFunction(): ActionId = {
        new ActionId(123)
      }
    }
    

    Now lets run scalac, and we will have a bunch of class files (files with bytecode). The one that we need is Foo\$.

    » javap Foo\$ 
    Compiled from "Boxing.scala"
    public final class Foo$ extends java.lang.Object{
        public static final Foo$ MODULE$;
        public static {};
        public int someFunction();
    }
    

    As you can see, even if value class leaks from function generally it wouldn't be boxed.

    case class Post(id: ActionId, notion: String)
    
    object Foo2 {
      def someFunction(): Post = {
        Post(new ActionId(123), "So ActionID will be boxed?")
      } 
    }
    

    scalac => javap:

    » javap Post  
    Compiled from "Boxing.scala"
    public class Post extends java.lang.Object implements scala.Product,scala.Serializable{
        public static scala.Function1 tupled();
        public static scala.Function1 curried();
        public int id();
        public java.lang.String notion();
        public Post copy(int, java.lang.String);
        public int copy$default$1();
        public java.lang.String copy$default$2();
        public java.lang.String productPrefix();
        public int productArity();
        public java.lang.Object productElement(int);
        public scala.collection.Iterator productIterator();
        public boolean canEqual(java.lang.Object);
        public int hashCode();
        public java.lang.String toString();
        public boolean equals(java.lang.Object);
        public Post(int, java.lang.String);
    }
    

    As you can see id here represented as plain int (e.g. third method).

    Finally, will value class boxed if the object with a value class member is not returned (doesn't really escape the scope)?

    case class Post(id: ActionId, notion: String)
    
    object Foo3 {
      def anotherFunction(): Unit {
        val post = Post(new ActionId(123), "Will be boxed?")
      } 
    }
    

    If we look closely at bytecode of the method, here is what we will see:

    Code:
       Stack=4, Locals=2, Args_size=1
       0:   new #15; //class Post
       3:   dup
       4:   bipush  123
       6:   ldc #17; //String Will be boxed?
       8:   invokespecial   #20; //Method Post."":(ILjava/lang/String;)V
       11:  astore_1
       12:  return
      LocalVariableTable: 
       Start  Length  Slot  Name   Signature
       0      13      0    this       LFoo3$;
       12      0      1    post       LPost;
    

    There is no boxing of int in ActionId. If it would box you would see something like this one:

    Code:
       Stack=5, Locals=2, Args_size=1
       0:   new #15; //class Post
       3:   dup
       4:   new #17; //class ActionId
       7:   dup
       8:   bipush  123
       10:  invokespecial   #20; //Method ActionId."":(I)V
       13:  ldc #22; //String Will be boxed?
       15:  invokespecial   #25; //Method Post."":(LActionId;Ljava/lang/String;)V
       18:  astore_1
       19:  return
      LocalVariableTable: 
       Start  Length  Slot  Name   Signature
       0      20      0    this       LFoo3$;
       19      0      1    post       LPost;
    

    You see, the difference is bipush 123 versus

       4:   new #17; //class ActionId
       7:   dup
       8:   bipush  123
       10:  invokespecial   #20; //Method ActionId."":(I)V
    

提交回复
热议问题