7

我正在尝试将 Java 库(Johm)与 Scala 一起使用,并注意到当 lib 尝试使用类似model.getClass().getDeclaredFields().

然后我决定尝试用 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() 找到。我在这里想念什么?

4

3 回答 3

8

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

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

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

于 2012-08-07T20:03:09.247 回答
1

如果您将字段标记为valvargetDeclaredFields则会找到它们,例如,

class myClass(val attribute1: String)

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


编辑以回应@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)
  /* {} */
于 2012-08-07T19:59:40.900 回答
0

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

于 2012-08-07T20:06:39.627 回答