从Scala中的匿名类获取所有字段

时间:2016-03-04 16:24:20

标签: scala reflection anonymous-class

我希望通过反射从类实例中获取所有字段。一切都适用于普通类(仅限过滤器):

scala> import scala.reflect.runtime.universe._
scala> import scala.reflect.runtime.currentMirror
scala> class A {val a = 1}
scala> currentMirror.classSymbol((newA).getClass).toType.members.filter(_.name.toString == "a")
res12: Iterable[reflect.runtime.universe.Symbol] = SynchronizedOps(value a)

但是在匿名课程的情况下,我有不同的情况:

scala> trait B {val b = 2}
scala> currentMirror.classSymbol((new B {}).getClass).toType.members.filter(_.name.toString == "b")
res13: Iterable[reflect.runtime.universe.Symbol] = SynchronizedOps(method b, value b)

此值不公开,但方法是公开的。有人可以解释一下,这里发生了什么?为什么在匿名课程中我没有简单的公开value b?是否有统一成员处理的解决方法?

修改

实际上,我的原始任务是从任何实例获取所有公共字段。在普通类的情况下,我使用此代码:

val reflectedInstance = currentMirror.reflect(instance)
for {
  member ← reflectedInstance.symbol.toType.members
  if member.isPublic && (!member.isMethod || member.asMethod.isGetter)
} yield //do something

上面的示例描述了为什么在匿名类的情况下此代码不起作用。所以,现在我正在寻找一些方法,如何从普通和匿名课程中获取所有公共字段。

2 个答案:

答案 0 :(得分:1)

根据我的理解,您可以通过method bvalue b获取特征而不是单value b来抱怨。

您正在观察的

method b实际上是由scalac生成的b的抽象setter方法。 如果在类本身内部定义了val,则不会生成它,但只有在特性中定义了val时才会生成。

为什么他们需要val b的setter,它实际上是final(不可变的)? 以下示例显示了它的工作原理。 为一个特征生成的接口和抽象类。 使用此setter设置默认值但在接口中同时具有抽象b的抽象类允许我们在其他类中覆盖它。

  class B1 {val b = 2}
  trait B2 {val b = 2}
  class B22 extends B2


// decompile...

public class B1
{
  private final int b = 2;

  public int b() { 
  return this.b;
  }
}



public abstract interface B2
{
  public abstract void com$db$itrac$summit$service$B2$_setter_$b_$eq(int paramInt);

  public abstract int b();
}

public abstract class B2$class
{
  public static void $init$(B2 $this)
  {
    $this.com$db$itrac$summit$service$B2$_setter_$b_$eq(2);
  }
}

答案 1 :(得分:0)

首先,如果需要,可以使用_.ismethod过滤掉方法

来自the scala docs:“traits用于通过指定受支持方法的签名来定义对象类型”

This回答澄清说“特征只能访问受隐式getter和setter保护的公共字段”。 (我相信这称为统一访问)

这意味着当你声明匿名类时,有一个val的隐式get方法(注意'val'没有setter方法,因为它们是不可变的。)