如何识别反编译Scala代码中的装箱/拆箱?

如何识别反编译Scala代码中的装箱/拆箱?,scala,boxing,unboxing,Scala,Boxing,Unboxing,在被接受的最佳回答中,有一个明确的解释为什么拳击会发生 但是,如果我反编译代码(使用java反编译器),我看不到scala.runtime.BoxesRunTime的用法。此外,如果我分析代码(使用JProfiler),我就看不到BoxesRunTime的任何实例 那么,我如何才能真正看到装箱/拆箱的证明呢?在这段代码中: class Foo[T] { def bar(i: T) = i } object Main { def main(args: Array[String]) {

在被接受的最佳回答中,有一个明确的解释为什么拳击会发生

但是,如果我反编译代码(使用java反编译器),我看不到scala.runtime.BoxesRunTime的用法。此外,如果我分析代码(使用JProfiler),我就看不到BoxesRunTime的任何实例

那么,我如何才能真正看到装箱/拆箱的证明呢?

在这段代码中:

class Foo[T] {
  def bar(i: T) = i
}


object Main {
  def main(args: Array[String]) {
    val f = new Foo[Int]
    f.bar(5)
  }
}
调用
bar
应首先将整数框起来。使用Scala 2.8.1编译并使用:

javap -c -l -private -verbose -classpath <dir> Main$
在调用
之前,您可以看到对
框运行时间的调用

BoxesRunTime
是一个包含基本类型的装箱方法的对象,因此总共应该只有一个实例。这里的技巧是库中的这个特定文件是用Java编写的,转换是静态方法。由于这个原因,在运行时没有它的任何实例,尽管在Scala代码中使用它感觉像是一个对象

您可能应该在JProfile中查找装箱原语(例如java.lang.Integer),尽管我不确定JVM是如何工作的,以及它是否可能在运行时重写代码并对其进行优化以避免装箱。据我所知,它不应该应用专门化(但我相信CLR可以)。有和没有装箱情况的一些微基准是另一种了解运行时发生了什么的方法

编辑:


以上假设类型参数没有使用
@specialized
注释进行注释。在这种情况下,可以避免装箱/拆箱。标准库中的某些类是专用的。请参阅。

给定以下Test.scala程序:

object Test {
  def main(args:Array[String]) {
    val list = List(1,5,15)
    val res = list.map(e => e*2).filter(e => e>10)
  }
}
如果我使用
scalac-Xprint:jvm Test.scala
进行编译,我会收到一段代码,表明发生了专门化(很抱歉出现了广泛的粘贴):

包{
最后一个类测试使用ScalaObject扩展了java.lang.Object{
def main(args:Array[java.lang.String]):单位={
val list:list=immutable.this.list.apply(scala.this.Predef.wrapIntArray(数组[Int]{1,5,15}));
val res:List=List.map({
(新测试$$anonfun$1():函数1)
},不可变。this.List.canBuildFrom())。$asInstanceOf[scala.collection.TraversableLike]().filter({
(新测试$$anonfun$2():函数1)
}).$asInstanceOf[列表]();
()
};
def this():对象测试={
Test.super.this();
()
}
};
@SerialVersionUID(0)@serializable最终类测试$$anonfun$1扩展了scala.runtime.AbstractFunction1$mcII$sp{
最终def应用(e:Int):Int=Test$$anonfun$1。此.apply$mcII$sp(e);
def apply$mcII$sp(v1:Int):Int=v1.*(2);
final def apply(v1:java.lang.Object):java.lang.Object=scala.Int.box(Test$$anonfun$1.this.apply(scala.Int.unbox(v1));
def this():Test$$anonfun$1={
Test$$anonfun$1.super.this();
()
}
};
@SerialVersionUID(0)@serializable最终类测试$$anonfun$2扩展了scala.runtime.AbstractFunction1$mcZI$sp{
最终定义应用(e:Int):布尔值=测试$$anonfun$2。此.apply$mcZI$sp(e);
def apply$mcZI$sp(v1:Int):布尔值=v1.>(10);
final def apply(v1:java.lang.Object):java.lang.Object=scala.Boolean.box(Test$$anonfun$2.this.apply(scala.Int.unbox(v1));
def this():Test$$anonfun$2={
Test$$anonfun$2.super.this();
()
}
}
}

这可能是您没有看到字节码中装箱的任何证据的原因…

函数匿名类
Test$$anonfun$#
发生专门化,因为函数是专门化的。但是,这些函数匿名类在
map
filter
方法中使用,这些方法不是专门化的,并调用它们的默认泛型
apply
,这需要一个对象-装箱应该发生在那里。如果您反编译
TraversableLike
的代码,并搜索
map
filter
,则它们应该调用
BoxesRunTime
object Test {
  def main(args:Array[String]) {
    val list = List(1,5,15)
    val res = list.map(e => e*2).filter(e => e>10)
  }
}
package <empty> {
  final class Test extends java.lang.Object with ScalaObject {
    def main(args: Array[java.lang.String]): Unit = {
      val list: List = immutable.this.List.apply(scala.this.Predef.wrapIntArray(Array[Int]{1, 5, 15}));
      val res: List = list.map({
        (new Test$$anonfun$1(): Function1)
      }, immutable.this.List.canBuildFrom()).$asInstanceOf[scala.collection.TraversableLike]().filter({
        (new Test$$anonfun$2(): Function1)
      }).$asInstanceOf[List]();
      ()
    };
    def this(): object Test = {
      Test.super.this();
      ()
    }
  };
  @SerialVersionUID(0) @serializable final <synthetic> class Test$$anonfun$1 extends scala.runtime.AbstractFunction1$mcII$sp {
    final def apply(e: Int): Int = Test$$anonfun$1.this.apply$mcII$sp(e);
    <specialized> def apply$mcII$sp(v1: Int): Int = v1.*(2);
    final <bridge> def apply(v1: java.lang.Object): java.lang.Object = scala.Int.box(Test$$anonfun$1.this.apply(scala.Int.unbox(v1)));
    def this(): Test$$anonfun$1 = {
      Test$$anonfun$1.super.this();
      ()
    }
  };
  @SerialVersionUID(0) @serializable final <synthetic> class Test$$anonfun$2 extends scala.runtime.AbstractFunction1$mcZI$sp {
    final def apply(e: Int): Boolean = Test$$anonfun$2.this.apply$mcZI$sp(e);
    <specialized> def apply$mcZI$sp(v1: Int): Boolean = v1.>(10);
    final <bridge> def apply(v1: java.lang.Object): java.lang.Object = scala.Boolean.box(Test$$anonfun$2.this.apply(scala.Int.unbox(v1)));
    def this(): Test$$anonfun$2 = {
      Test$$anonfun$2.super.this();
      ()
    }
  }
}