Невозможно использовать getDeclaredFields() для извлечения полей класса Scala

Я пытаюсь использовать библиотеку Java (JOhm) с Scala и заметил, что это не удается, когда lib пытается прочитать поля моих классов Scala с чем-то вроде 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 (). Я что-то упускаю?

3 ответов


то, что вам не хватает, это параметры конструктора автоматически не повышаются до полей.

скорее, они продвигаются только в том случае, если они используются. Вы использовали attribute1 таким образом, он был превращен в поле; вы не использовали другие, поэтому они не были.

Если вы объявите их как val или var, или класс является классом case, они также будут повышены до полей (поскольку они фактически будут иметь сгенерированные методы доступа и, таким образом, используются).


если пометить поля как val или var, потом getDeclaredFields найдет их, е. g,

class myClass(val attribute1: String)

JavaDoc для getFields говорит, что он возвращает "все доступные общедоступные поля", поэтому имеет смысл, что поля не перечислены, если они не сделаны общедоступными явно (по умолчанию аргументы конструктора являются частными vals). Тем не менее, JavaDoc для getDeclaredFields не упоминает такое ограничение, но видимость полей, по-видимому, имеет здесь тоже эффект.


редактировать в ответ на @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 не генерирует поля для всех аргументов конструктора. Если вы добавите 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 метод. Я не думаю, что на это следует полагаться. Вам лучше явно указать, какие параметры конструктора являются вашими полями.