如何在反编译的Scala代码中识别装箱/拆箱?
在对
this question的公认的最佳回应中,有一个明确的解释为什么拳击发生.
但是,如果我反编译代码(使用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$ 看到为Main类的main方法生成的字节码产生: public void main(java.lang.String[]); ... 9: iconst_5 10: invokestatic #24; //Method scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer; 13: invokevirtual #28; //Method Foo.bar:(Ljava/lang/Object;)Ljava/lang/Object; 16: pop 17: return ... 在调用bar之前,您可以看到对BoxesRunTime的调用. BoxesRunTime是一个包含原始类型的装箱方法的对象,因此总共应该只有一个实例.这里的技巧是库中的这个特定文件是用Java编写的,转换是静态方法.出于这个原因,在运行时没有它的任何实例,尽管在Scala代码中使用它感觉就好像它是一个对象. 您可能应该使用JProfile查找盒装基元(例如java.lang.Integer),但我不确定JVM是如何工作的,以及它是否可以在运行时实际重写代码并优化它以避免装箱.据我所知,它不应该应用专业化(但我相信CLR确实如此).有和没有装箱情况的一些微基准测试是另一种弄清楚运行时会发生什么的方法. 编辑: 以上假设类型参数未使用@specialized注释进行注释.在这种情况下,可以避免装箱/拆箱.标准库中的某些类是专用的.见this sid. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |