使用Java反射在Scala特征中获取私有字段

时间:2017-10-31 14:57:11

标签: scala reflection

我正在尝试在测试中使用私有特征字段。非常简单的例子:

//Works fine with class A, but not trait A
trait A {  
  private val foo = "Some string"
}

class Test extends A {
  val field = classOf[A].getDeclaredField("foo")
  field.setAccessible(true)
  val str = field.get(this).asInstanceOf[String]
}

我得到了:

  

java.lang.NoSuchFieldException:foo at java.lang.Class.getDeclaredField

直播示例here

如何获取此代码段可执行文件?

2 个答案:

答案 0 :(得分:4)

A是一个特征,Scala转换为JVM接口。接口不能有字段,所以没有这样的字段。只有将接口实际混合到一个类中时,才会添加基础字段。

因此,您需要做的第一件事就是将classOf[A]更改为classOf[Test]

第二件事是将getDeclaredField("foo")更改为.getDeclaredField("A$$foo")

答案 1 :(得分:2)

编辑特别感谢@Seth Tisue(投票并接受他)

class Test extends A {
  val field:Field = this.getClass.getDeclaredField("A$$foo")

  field.setAccessible(true)

  println(field.get(this).asInstanceOf[String])

}

" A $$ FOO"获取超类型属性的正确方法是这个,并使用this.getClass。  我以前不知道它,但是通过这种修正,你的代码将会很好用!

第一个想法:

trait A {
  private val foo = "Some string"
}


class Test extends A {
  val fields: Seq[Field] = this.getClass.getDeclaredFields.toList

  val field = fields.filter(x => {
    println(x.getName)
    x.getName.contains("foo")
  }).head

  field.setAccessible(true)

  println(field.get(this).asInstanceOf[String])

}

正如您所看到的,当您打印" foo"的名称时变量,不是真的" foo",它是别的东西:

A$A295$A$A295$A$$foo

在我的情况下,这就是你(和我)收到错误的原因

java.lang.NoSuchFieldException: foo at java.lang.Class.getDeclaredField

所以,我现在的想法,我希望有人带来更好的想法,看看是否" foo"在变量名称内" A $ A295 $ A $ A295 $ A $$ foo"所以你可以告诉那个你要找的变量。