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的成员SymbolType类型可用于比较:
通过操作符=:=比较是否相等通过操作符<:<比较是否子类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] 直接通过泛型参数构建TypeSymbolTermSymbol
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]。