无法使用getDeclaredFields()来检索Scala类的字段

我正在尝试使用Scala的Java库(JOhm)并注意到当lib尝试使用类似于model.getClass().getDeclaredFields()东西读取我的Scala类的字段时,它会失败。

然后我决定尝试使用Scala解释器中的简单示例:

 scala> import java.lang.reflect.Field; import java.lang.reflect.Field scala> class myClass(attribute1: String, attribute2: String, attribute3: String) defined class myClass scala> val myInstance = new myClass("value1", "value2", "value3") myInstance: myClass = myClass@7055c39a scala> myInstance.getClass().getDeclaredFields() res0: Array[java.lang.reflect.Field] = Array() 

实际上,我们根本没有任何领域。

现在,如果我尝试这样做:

 scala> class myClass2(attribute1: String, attribute2: String, attribute3: String) { override def toString = this.attribute1 } defined class myClass2 scala> val myInstance2 = new myClass2("value1", "value2", "value3") myInstance2: myClass2 = value1 scala> myInstance2.getClass().getDeclaredFields() res1: Array[java.lang.reflect.Field] = Array(private final java.lang.String myClass2.attribute1) 

因此,如果使用其中一个类’方法中的一个字段,则可以通过getDeclaredFields()找到它。 我在这里想念的是什么?

您缺少的是构造函数参数不会自动提升为字段

相反,它们只有在使用时才会被提升。 你使用了attribute1所以它变成了一个字段; 你没有使用其他人,所以他们没有。

如果将它们声明为valvar ,或者类是一个case类,它们也将被提升为字段(因为它们实际上会生成访问器方法,因此被使用)。

如果将字段标记为valvar ,则getDeclaredFields将找到它们,例如,

 class myClass(val attribute1: String) 

getFields的JavaDoc表示它返回“所有可访问的公共字段”,因此除非明确公开字段(默认情况下,构造函数参数是私有值),否则不会列出字段。 但是, getDeclaredFields的JavaDoc没有提到这样的限制,但字段的可见性显然也在这里产生影响。

编辑以回应@Clément:

 import java.lang.reflect.Field class Foo(val a1: String, private val a2: String, a3: String, a4: String) { val f = 10 def foo(s: String) = a4 + s } val foo = new Foo("v1", "v2", "v3", "v4") foo.getClass().getDeclaredFields().foreach(println) /* {a1, a2, a4, f} */ foo.getClass().getFields().foreach(println) /* {} */ 

我的猜测是,这是因为Scala编译器不为所有构造函数参数生成字段。 如果向类定义中添加varval ,则会生成以下字段:

 scala> class myClass3(val attribute1:String, attribute2:String, attribute3:String) defined class myClass3 scala> val myInstance3 = new myClass3("value1", "value2", "value3") myInstance: myClass3 = myClass3@fd9178 scala> myInstance3.getClass().getDecalaredFields() res1: Array[java.lang.reflect.Field] = Array(private field java.lang.String myClass3.attribute1) 

请注意,对于最后两个构造函数参数,不会生成任何字段。 那是因为它们仅仅是构造函数参数而且什么都不做。 我认为它覆盖toString函数时它的工作原理实际上只是因为编译器生成了一个隐藏字段,该字段在toString方法中访问参数时使用。 我不认为这应该依赖。 最好明确说明哪些构造函数参数是您的字段。