反射详解"/>
scala反射详解
概述
Scala 的反射分为两个范畴:
运行时反射:通常意义上的反射
编译时反射:宏,或者元编程
这两者之间的区别在于Environment, 而Environment又是由universe决定的. 反射的另一个重要的部分就是一个实体集合,而这个实体集合被称为mirror,有了这个实体集合我们就可以实现对需要反射的类进行对应的操作,如属性的获取,属性值得设置,以及对反射类方法的调用(其实就是成员函数的入口地址, 但请注意, 这只是个地址)!
可能有点绕, 说的直白点就是要操作类方法或者属性就需要获得指定的mirror,而mirror又是从Environment中得来的,而Environment又是Universes中引入的,而Universes根据运行时和编译时又可以分为两个领域的.
Universes
Universes有两类,运行时和编译时。提供了反射时要用的主要概念。such as Types, Trees, and Annotations。
- scala.reflect.runtime.universe for runtime reflection
- scala.reflect.macros.Universe for compile-time reflection.
Environment
Environment就是运行时和编译时两种环境
Mirrors
镜像层级:
- ClassLoaderMirror
- ClassMirror ( => 类)
-
- MethodMirror ( 只有构造函数)
-
- InstanceMirror ( => 实例)
-
- MethodMirror(方法)
-
- FieldMirror(属性)
-
- ModuleMirror ( => Object)
-
- instance: Any (单例类)
-
镜像使用
Mirrors 提供了反射时要操作的实体(内存中的实体)。
mirror分两大类:
“Classloader” mirrors : 通过staticClass/staticModule/staticPackage方法把变量转为符号。
“Invoker” mirrors : 用于产生方法调用。是由 classloader mirror创建。包括:InstanceMirror,
MethodMirror,FieldMirror,ClassMirror 和 ModuleMirror。
Classloader入口
- 镜像的入口通过runtimeMirror()获得。runtimeMirror 的返回值就是一个 classloader mirror。它是一个ReflectiveMirror。可以通过名字加载符号。
scala> import scala.reflect.runtime.universe._
import scala.reflect.runtime.universe._scala> val mirror = runtimeMirror(getClass.getClassLoader)
val mirror: reflect.runtime.universe.Mirror = JavaMirror with scala.tools.nsc.interpreter.IMain$TranslatingClassLoader@fb9c7aa of type class scala.tools.nsc.interpreter.IMain$TranslatingClassLoader with classpath [(memory)] and parent being scala.reflect.internal.util.ScalaClassLoader$URLClassLoader@a5d23c9 of type class scala.reflect.internal.util.ScalaClassLoader$URLClassLoader with classpath [file:/Library/Java/JavaVirtualMachines/jdk1.8.0_77.jdk/Contents/Home/jre/lib/resources.jar,file:/Library/Java/JavaVirtualMachines/jdk1.8.0_77.jdk/Contents/Home/jre/lib/rt.jar,file:/Library/Java/JavaVirtualMachines/jdk1.8.0_77.jdk/Contents/Home/jre/lib/jsse.jar,file:/Library/Java/JavaVirtualMachines/jdk1.8.0_77.jdk/Contents/Home/jre/lib/jce.jar,file:/Library/Java/JavaVir...
生成 invoker类型
通过镜像入口mirror (ReflectiveMirror) 来生成 invoker类型的实例。如 InstanceMirror
case class Fruits(id: Int, name: String) {def func(): Unit = {println("func")}}scala> val fruits = Fruits(2, "banana")
val fruits: Fruits = Fruits(2,banana)scala> val instanceMirror = mirror.reflect(fruits)
val instanceMirror: reflect.runtime.universe.InstanceMirror = instance mirror for Fruits(2,banana)
通过反射获取实例的方法和属性
属性和方法的反射要先获得符号,再反射。属性和方法都可以看成是符号(symbol) 通过下面的方法获取:
获取属性符号:
scala> val field = typeOf[Fruits].decl(TermName("name")).asTerm
val field: reflect.runtime.universe.TermSymbol = value namescala> val fieldMirror = instanceMirror.reflectField(field)
val fieldMirror: reflect.runtime.universe.FieldMirror = field mirror for private[this] val name: String (bound to Fruits(2,banana))scala> fieldMirror.get
val res3: Any = bananascala> fieldMirror.set("apple")scala> fieldMirror.get
val res6: Any = apple
获取方法符号:
// 方法符号
scala> val method = typeOf[Fruits].decl(TermName("func")).asMethod
val method: reflect.runtime.universe.MethodSymbol = method func// 方法镜像
scala> val methodMirror = instanceMirror.reflectMethod(method)
val methodMirror: reflect.runtime.universe.MethodMirror = method mirror for def func(): Unit (bound to Fruits(2,apple))// 调用方法
scala> methodMirror()
func
val res7: Any = ()
通过反射获取构造函数
获取构造函数(通过ClassMirror),内部类的构造函数通过InstanceMirror获得:
scala> val clazz = typeOf[Fruits].typeSymbol.asClass
clazz: reflect.runtime.universe.ClassSymbol = class Fruitsscala> val classMirror = mirror.reflectClass(clazz)classMirror: reflect.runtime.universe.ClassMirror = class mirror for Fruits (bound to null)scala> val constructMethod = typeOf[Fruits].decl(termNames.CONSTRUCTOR).asMethodconstructMethod: reflect.runtime.universe.MethodSymbol = constructor Fruitsscala> val methodMirror = classMirror.reflectConstructor(constructMethod)methodMirror: reflect.runtime.universe.MethodMirror = constructor mirror for def <init>(id: Int,name: String): Fruits (bound to null)scala> methodMirror(2, "banana")
res2: Any = Fruits(2,banana)
通过反射获取单例对象
ModuleMirror可以用来访问object,内部object通过InstanceMirror获得:
import scala.reflect.runtime.universe._
val mirror = runtimeMirror(getClass.getClassLoader)object C { def x = 2 }scala> val module = typeOf[C.type].termSymbol.asModulemodule: reflect.runtime.universe.ModuleSymbol = object Cscala> val moduleMirror = mirror.reflectModule(module)moduleMirror: reflect.runtime.universe.ModuleMirror = module mirror for C (bound to null)scala> val instance = moduleMirror.instance // 生成anyinstance: Any = C$@5cb3bd9bscala> println(instance.asInstanceOf[C.type].x) // 2
2
更多推荐
scala反射详解
发布评论