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入口
生成 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 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總結
- 上一篇: 节水小妙招
- 下一篇: 沈寅鑫银行内训实战专家