获取Scala / Java中的实例的公共字段(及其各自的值)

时间:2011-09-17 21:36:14

标签: scala reflection field

PHP introduces a method that allows you to pick out all public values of an instance. 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 );

我所需要的方法是获取一个Map或两个值的集合。

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

5 个答案:

答案 0 :(得分:21)

是时候睡觉了,所以我没时间找到完整的答案,但看看element.getClass.getFields(或getDeclaredFields私有字段的结果) - 你可以致电{{1}在getValue(element)个对象上获取它们的值。


现在醒来,仍然没有更好的答案,所以:

首先,请注意,在Java术语中,您的类没有公共字段主题,它具有私有字段主题和访问者方法subject()和subject_ $ eq(String)。

您可以如上所述迭代私有字段对象,从对中填充地图:

Field

现在,您可以在TestElement上定义此方法(将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 :_*) } 替换为o),或者通常更有用地定义转换,以便您可以在任何引用上调用getFields

this

那样

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

会给出你想要的结果。

答案 1 :(得分:3)

根据Philippe的回答,你可以为案例分类做到这一点。

更广泛地说,同样的技术适用于 Product的任何子类。除了案例类之外,元组是另一个明显的例子,但列表远不止于此。

在这里查看“已知的子类”:http://www.scala-lang.org/api/current/scala/Product.html

答案 2 :(得分:2)

对于案例类,你可以做一些比较接近的事情:

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出来。

答案 3 :(得分:1)

对于那些试图通过使@duncan的方法更强大来改善这一点的人来说,请注意:

您可以执行以下操作,而不是返回Map[String, Any],其中值的类型为Any,您可以执行以下操作:

def propertiesAsPairs() = {
    val fields = (this.getClass.getDeclaredFields())
    for ( field <- fields ) yield {
        field.setAccessible( true );
        ( field.getName, field.get( this ) );
    }
}

答案 4 :(得分:0)

Scala故意让valvardef共享一个公共接口,因此您可以使用后者替换前两个而不会破坏任何代码 - 甚至不需要重新编译。

所以,尽管可以做你想做的事情,但它会导致代码变得脆弱,这就是它不应该做的事情。