我希望通过反射从类实例中获取所有字段。一切都适用于普通类(仅限过滤器):
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
上面的示例描述了为什么在匿名类的情况下此代码不起作用。所以,现在我正在寻找一些方法,如何从普通和匿名课程中获取所有公共字段。
答案 0 :(得分:1)
根据我的理解,您可以通过method b
和value 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方法,因为它们是不可变的。)