Получение общедоступных полей (и их соответствующих значений) экземпляра в Scala/Java

PHP представляет метод, позволяющий выбрать все общедоступные значения экземпляра. Есть ли способ сделать это в Scala? То есть получить все значения всех общедоступных полей созданного класса (не объекта).

Предположим, у меня есть этот класс

class TestElement( datatype: Datatype, var subject: String, var day: Int, var time: Int )
  extends DataElement( datatype: Datatype ) {    
   def to( group: Group ) = group.add( this );
}

var element = new TestElement( datatype, "subject", 1, 1 );

Что мне нужно от рассматриваемого метода, так это получить карту или две коллекции значений.

var element.method                                       // the function I need
ret: ( ("subject", "subject"), ("day", 1), ("time", 1) ) // its output

person sdkfasldf    schedule 17.09.2011    source источник


Ответы (5)


Пора спать, поэтому у меня нет времени на полный ответ, но посмотрите на результаты element.getClass.getFields (или getDeclaredFields для приватных полей) — вы можете вызвать getValue(element) для Field объектов, чтобы получить их значения.


Пробудитесь сейчас, и все еще нет лучшего ответа, так что:

Во-первых, обратите внимание, что в терминах Java у вашего класса нет темы публичного поля, а есть тема частного поля и методы доступа subject() и subject_$eq(String).

Вы можете перебирать объекты частного поля, как описано выше, заполняя карту из пар:

def getFields(o: Any): Map[String, Any] = {
  val fieldsAsPairs = for (field <- o.getClass.getDeclaredFields) yield {
    field.setAccessible(true)
    (field.getName, field.get(o)) 
  }
  Map(fieldsAsPairs :_*)
}

Теперь вы можете либо определить этот метод в TestElement (заменив o на this), либо, в более общем смысле, с пользой определить преобразование, чтобы вы могли вызывать getFields для любой ссылки.

implicit def any2FieldValues[A](o: A) = new AnyRef {
  def fieldValues = getFields(o)
}

Так что

element.fieldValues 

даст желаемый результат.

person Duncan McGregor    schedule 17.09.2011
comment
Что делает синтаксис :_*? - person Ali; 01.02.2018

Согласно ответу Филиппа, вы можете сделать это для кейс-классов.

Однако в более широком смысле тот же метод работает для любого подкласса Product. Наряду с case-классами Tuples — еще один очевидный пример, но этот список гораздо шире.

Взгляните на «известные подклассы» здесь: http://www.scala-lang.org/api/current/scala/Product.html

person Kevin Wright    schedule 18.09.2011

Вы можете сделать что-то относительно близкое к этому для классов case:

case class SomeEntity(name : String, value : Int, misc : Boolean)
val s = SomeEntity("Tom", 42, false)
println(s.productIterator.map(_.toString).mkString(", ")) // "Tom, 42, false"

... как и следовало ожидать, productIterator перебирает элементы типа Any. Этот метод автоматически генерируется только для классов дел, и вы не получите имя поля. Для чего-то большего вам нужно будет использовать отражение, и для этого вы можете дождаться выхода версии 2.10.

person Philippe    schedule 17.09.2011

Просто примечание для тех, кто пытается улучшить это, сделав подход @duncan более сильным:

Вместо того, чтобы возвращать Map[String, Any], где значение вводится как Any, вы можете сделать следующее:

def propertiesAsPairs() = {
    val fields = (this.getClass.getDeclaredFields())
    for ( field <- fields ) yield {
        field.setAccessible( true );
        ( field.getName, field.get( this ) );
    }
}
person sdkfasldf    schedule 18.09.2011
comment
Каков возвращаемый тип этого? Мне кажется, что Array[Pair[String, Any]], который вам ничего не купил? - person Duncan McGregor; 19.09.2011

Scala намеренно делает так, чтобы val, var и def имели общий интерфейс, так что вы можете заменить первые два вторыми, не нарушая никакого кода — даже не требуя перекомпиляции.

Таким образом, хотя можно делать то, что вы хотите, это приведет к хрупкому коду, который делает то, чего не должен делать.

person Daniel C. Sobral    schedule 19.09.2011
comment
Думаю, я бы сказал, что для таких классов данных смысл заключается в простом перемещении значений в полях. - person Duncan McGregor; 19.09.2011