Scala Reflect (反射)

xiaoxiao2021-02-28  72

Reflect (反射)

Scala 2.10之后提供了自身的反射相关API。

Java标准库中的反射API不支持Scala的专属特性。 Scala自身提供的反射API能完整地支持所有Scala语言特性。

到目前版本(Scala 2.12)为止,反射相关功能依然是Expermental(实验性)的,相关API在后续版本中可能会有较大改动。

反射机制相关类型

反射API相关的类型定义在包路径scala.reflect.runtime.universe中。

Type

包含类型内的成员信息(定义的字段fields、方法methods、类型别名type aliases等)、类型继承关系、基类信息等。

Type类型类似于Java反射机制中的Class类型,获取Type实例是整个反射流程的起始步骤。 通过typeOf[T]方法可以获取指定类型的Type实例。

Type类型可用于筛选出需要反射的成员的符号信息:

Type.decls 获取用户定义的成员的SymbolType.members 获取类内所有成员的SymbolType.decl()/member() 获取指定TermName的成员Symbol

Type类型可用于比较:

通过操作符=:=比较是否相等通过操作符<:<比较是否子类

Symbol

包含实例或成员的完整信息。

Symbol建立了名称与所指向的类型的绑定(establish bindings between a name and the entity it refers to)。 Symbol包含了类型(class/trait/object等)或成员(val/var/def等)的所有可用信息(contain all available information about the declaration of an entity or a member)。

根据包含信息的类别差异,Symbol类型存在以下子类:

TypeSymbol

TypeSymbol表示类型、类、特质的定义,以及类型参数(TypeSymbol represents type, class, and trait declarations, as well as type parameters)。

存在以下子类:

ClassSymbol

提供对包含在类、特质中所有信息的访问(Provides access to all information contained in a class or trait declaration)。

构建TypeSymbol:

Type.typeSymbol 通过Type实例获取类型对应的TypeSymbolsymbolOf[T] 直接通过泛型参数构建TypeSymbol

TermSymbol

TermSymbol表示字段、方法、单例的定义,以及包、参数(The type of term symbols representing val, var, def, and object declarations as well as packages and value parameters)。

存在以下子类:

MethodSymbol

表示方法定义(method symbols representing def declarations)。 支持查询方法是否为(主)构造器,或方法是否支持可变参数等(It supports queries like checking whether a method is a (primary) constructor, or whether a method supports variable-length argument lists)。

ModuleSymbol

表示单例定义(module symbols representing object declarations)。

Mirror

所有反射提供的信息需要通过Mirror来获取(All information provided by reflection is made accessible through mirrors)。

使用runtimeMirror()方法以ClassLoader为参数构建Mirror实例。

通过Mirror.reflect()获取InstanceMirror,用于反射访问/修改字段,调用方法。 通过Mirror.reflectClass()获取ClassMirror,可获取类型构造方法反射构建实例。 通过Mirror.reflectModule()获取ModuleMirror,可获取单例对象实例。

如下所示:

import scala.reflect.runtime.universe._ object Main extends App { class TestReflect(init: Int) { val field = init def showField = { println("Call method 'showField'") 2333 } } val run = runtimeMirror(getClass.getClassLoader) // 反射获取构造器MethodSymbol,构造器名称为 <init> val constructor = typeOf[TestReflect].decl(TermName("<init>")).asMethod val instance = run //通过构造器的MethodSymbol反射构建实例 .reflectClass(symbolOf[TestReflect].asClass) .reflectConstructor(constructor).apply(2333) // 遍历筛选特定成员 typeOf[TestReflect].decls foreach { case term: TermSymbol if term.name == TermName("field") => println(s"Field name: ${term.name}, value: ${run.reflect(instance).reflectField(term).get}") case method: MethodSymbol if method.name == TermName("showField") => println(s"Method name: ${method.name}, value: ${run.reflect(instance).reflectMethod(method).apply()}") case _ => } }

输出结果:

Field name: field, value: 2333 Call method 'showField' Method name: showField, value: 2333

注意事项:

Symbol类型的成员方法name返回类型为NameType。 NameType不要直接与文本比较,应使用toString方法转换为文本进行比较。 或者将NameType与TermName类型进行比较。类内方法的MethodSymbol对应的TermName与方法名称相同,一个方法的多个重载TermName相同。对于无重载的方法,使用Type.decl()/member()根据名称查找到的Symbol可直接使用Symbol.asSymbol方法转化为MethodSymbol。对于拥有重载的方法,使用Type.decl()/member()方法根据名称查找获取到的是包含重载信息的TermSymbol,使用Symbol.alternatives方法可获取包含所有同名重载方法的List[Symbol]。
转载请注明原文地址: https://www.6miu.com/read-30923.html

最新回复(0)