jes*_*slg 5 reflection scala scala-2.10
我正在玩反思,以实现对特质的深入分析.我想得到的一件事是设置成员字段的初始值.例如,在特征中:
trait A {
val x: Int = 3
val y: String = "y"
}
Run Code Online (Sandbox Code Playgroud)
知道3和"y"会很高兴.我没有在API中找到与此任务相关的任何内容,并且由于以下输出(由scalac -Xprint生成):
abstract trait A extends Object {
<accessor> def com$hablapps$A$_setter_$x_=(x$1: Int): Unit;
<accessor> def com$hablapps$A$_setter_$y_=(x$1: String): Unit;
<stable> <accessor> def x(): Int;
<stable> <accessor> def y(): String
};
abstract trait A$class extends {
def /*A$class*/$init$($this: com.hablapps.A): Unit = {
$this.com$hablapps$A$_setter_$x_=(3);
$this.com$hablapps$A$_setter_$y_=("y");
()
}
}
Run Code Online (Sandbox Code Playgroud)
我担心访问它们会很困难,因为它们保存在$ init $方法的主体中.是否有任何(简单)方法可以通过反射获得这些值?
您必须反汇编字节码:
trait A { val x: Int = 3 }
public abstract class A$class extends java.lang.Object{
public static void $init$(A);
Code:
0: aload_0
1: iconst_3
2: invokeinterface #12, 2; //InterfaceMethod A.A$_setter_$x_$eq:(I)V
7: return
Run Code Online (Sandbox Code Playgroud)
请参见第 1 行——该值存在的唯一位置是 init 方法的字节码中!
你无法以任何其他方式做到这一点,因为如果你有
trait A { val x: Int = 3 }
trait B extends A { override val x = 7 }
class C extends B {}
Run Code Online (Sandbox Code Playgroud)
您会发现C扩展A$_setter_$x_$eq根本不执行任何操作 - 使A$class.$init$调用成为无操作并使值无法检索。
证明:
public class C extends java.lang.Object implements B,scala.ScalaObject{
public void A$_setter_$x_$eq(int);
Code:
0: return
public void B$_setter_$x_$eq(int);
Code:
0: aload_0
1: iload_1
2: putfield #11; //Field x:I
5: return
Run Code Online (Sandbox Code Playgroud)