值类型的装箱问题

之前在ATA上讨论过的一个unit类型为何会被装箱的问题:http://www.atatech.org/qa/detail/11811?group_id=51
外网可能无法访问,转述一下。

先通过scala-user邮件列表的一个例子看看:

class Y(val i: Int) extends AnyVal

object X {
    def main(args: Array[String]) {
        val y = new Y(3) // ok
        println(y) // oops, should be y.i   
    }
}

通过 scalac -print A.scala 来看编译的输出

def main(args: Array[String]): Unit = {
    // 这里并没有用 new Y(3) ,没有在堆上分配对象
    val y: Int = 3;                                 
    // 这里做了装箱,因为println接受的参数类型是Any
    scala.this.Predef.println(new Y(y)) 
};

已经有人实现了一个sbt的插件,用来检查编译时box,给出警告信息的:https://github.com/retronym/boxer

分析一下为什么 Any类型的变量在被赋值一个Int值时会发生boxing,归根到底,是因为Any/AnyVal 类型被翻译为java时是使用的 Object 这个引用类型

scala -Xprint:jvm -e 'val a:Any=100'
...
final class Main$$anon$1 extends Object {
    private[this] val a: Object = _; //Any/AnyVal都被转为Object 
    <stable> <accessor> private def a(): Object = Main$$anon$1.this.a;
    def <init>(): anonymous class anon$1 = {
        Main$$anon$1.super.<init>();
        Main$$anon$1.this.a = scala.Int.box(100); //需要boxing
        ()
    }
}

而 Int,Float, Unit这些类型被翻译为java代码时,就是对应的java基本类型的int, float, void

scala -Xprint:jvm -e 'val b:Int=100'
...
final class Main$$anon$1 extends Object {
    private[this] val b: Int = _;   // 就是 java里的int类型,
    <stable> <accessor> private def b(): Int = Main$$anon$1.this.b;
    def <init>(): anonymous class anon$1 = {
        Main$$anon$1.super.<init>();
        Main$$anon$1.this.b = 100; //不需要boxing
        ()
    }
}

发表评论

电子邮件地址不会被公开。 必填项已用*标注