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