// Do runtime reflection on classes loaded by current ClassLoader
val currentMirror: universe.Mirror = scala.reflect.runtime.currentMirror
// Use symbols to navigate to pick out the methods and fields we want to invoke
// Notice explicit symbol casting with the `.as*` methods.
val classSymbol: universe.ClassSymbol = currentMirror.staticClass("com.example.Foo")
val constructorSymbol: universe.MethodSymbol = classSymbol.primaryConstructor.asMethod
val fooSymbol: Option[universe.TermSymbol] = classSymbol.toType.members.find(_.name.toString == "foo").map(_.asTerm)
// Get mirrors for performing constructor and field invocations
val classMirror: universe.ClassMirror = currentMirror.reflectClass(classSymbol)
val fooInstance: Foo = classMirror.reflectConstructor(constructorSymbol).apply().asInstanceOf[Foo]
val instanceMirror: universe.InstanceMirror = currentMirror.reflect(fooInstance)
// Do the actual invocation
val fooValue: String = instanceMirror.reflectField(fooSymbol.get).get.asInstanceOf[String]
println(fooValue) // Prints the value of the val "foo" of the object "fooInstance"
1条答案
按热度按时间9o685dep1#
在使用Scala反射API时,您会遇到比使用Java反射API时更多的类型。举一个例子,如果你从一个包含一个类的完全限定类名的
String
开始,你可能会遇到以下类型:scala.reflect.runtime
包,对于编译时反射,它对应于scala.reflect.macros
包。本文的回答集中在前者。像Java一样,您通常通过选择要反射的ClassLoader类来启动任何反射。Scala提供了一个使用当前类的
ClassLoader
的快捷方式:scala.reflect.runtime.currentMirror
,这会给你一个Mirror
(稍后会有更多关于镜像的内容)。许多JVM应用程序只使用一个类加载器,因此这是Scala反射API的一个公共入口点。因为你是从runtime
导入的,所以你现在就在那个宇宙中。词法作用域是您在执行反射的地方可以“看到”的所有内容,不包括隐式作用域(有关不同作用域的处理,请参阅this SO)。一个类的成员如何随词法作用域而变化?假设一个抽象类只有一个
def foo: String
。名称foo
可能在一个上下文中绑定到def
(如果您查询它,则会给您一个MethodSymbol
),或者它可以在另一个上下文中绑定到val
(给您一个TermSymbol
)。当使用Symbols时,通常需要明确说明您期望的符号类型,您可以通过.asTerm
,.asMethod
,.asClass
等方法来实现这一点。继续我们开始的
String
示例。使用Mirror
派生一个描述类的ClassSymbol
:currentMirror.staticClass(myString)
.Type
s通常用于两件事:查询有什么var、val和def,以及查询类型关系(例如,此类型是否为该类型的子类)。获取Type
的方法有两种。通过TypeSymbol
(ClassSymbol
是TypeSymbol
)或通过TypeTag
。继续这个例子,你可以对你得到的符号调用
.toType
方法来得到Type
。Type
询问.members
或.decl
时-这是给你的术语(var和vals)和方法-你得到一个当前词法作用域中成员的Symbol
列表。这个列表保存在MemberScope
类型中,它只是一个美化的List[Symbol]
。在上面的抽象类示例中,根据当前作用域,该列表将包含名称为
foo
的TermSymbol
或MethodSymbol
。TermName
和TypeName
。它只是一个String
的 Package 器。您可以使用类型来确定任何Name
的名称。Symbol
开始,然后使用该符号为您想要交互的方法、构造函数或字段派生符号。当您拥有所需的符号时,您可以使用currentMirror
为这些符号创建镜像。镜像允许您调用构造函数(ClassMirror
)、访问字段(FieldMirror
)或调用方法(MethodMirror
)。您不能使用镜像来查询有关被反射事物的元数据。因此,将一个反映上面描述的示例放在一起,这就是你如何搜索字段,调用构造函数并读取
val
,给定一个具有完全限定类名的String
: