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

Java 无法使用getDeclaredFields()检索Scala类的字段,java,scala,reflection,Java,Scala,Reflection,我正在尝试将Java库(JOhm)与Scala一起使用,并注意到当库尝试使用类似于model.getClass().getDeclaredFields()的内容读取Scala类的字段时,它失败了 然后,我决定尝试在Scala解释器中的简单示例中执行同样的操作: scala> import java.lang.reflect.Field; import java.lang.reflect.Field scala> class myClass(attribute1: String, a

我正在尝试将Java库(JOhm)与Scala一起使用,并注意到当库尝试使用类似于
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()找到它。这里缺少什么?

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

class myClass(val attribute1: String)
JavaDoc for表示它返回“所有可访问的公共字段”,因此,除非字段显式公开(默认情况下,构造函数参数为私有VAL),否则不列出这些字段是有意义的。然而,JavaDoc for没有提到这样的限制,但是字段的可见性显然在这里也有影响


编辑以响应@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)
  /* {} */

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

相反,它们只有在被使用的情况下才会得到推广。您使用了
attribute1
,因此它变成了一个字段;你没有使用其他的,所以他们没有


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

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

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
方法中访问参数时使用该字段。我认为这是不应该依赖的。最好明确说明哪些构造函数参数是字段。

我很确定getDeclaredFields()也会返回私有字段。@Clément你说得对,我添加了一个示例来说明这种行为。