反射環境(Environment)根據反射任務是在運行時仍是在編譯時而有所不一樣。在運行時或編譯時使用的環境之間的區別被封裝在一個所謂的universe中。 反射環境的另外一個重要方面是咱們能夠反射訪問的一組實體。 這組實體由所謂的mirror肯定。api
例如,經過運行時反射可訪問的實體可由 ClassloaderMirror
提供。此鏡像僅提供對由特定類加載器加載的實體(包,類型和成員)的訪問。安全
Mirror 不只肯定了可反射訪問的一組實體,他們還提供對這些實體進行反射的操做。例如,在運行時反射中,invoker mirror 可用於調用類的方法或構造函數。app
有兩種主要類型的 universe
——由於存在運行時和編譯時反射能力,因此使用了與各自任務相對應的universe
。有如下兩種:函數
scala.reflect.runtime.universe
用於運行時反射,或scala.reflect.macros.Universe
用於編譯時反射。universe 爲反射中使用的全部主要概念(如Type
,Tree
和 Annotation
)提供了一個接口。scala
經過反射提供的全部信息均可以經過mirror訪問。 根據要獲取的信息類型或要採起的反射行爲,必須使用不一樣的mirror 風格。 Classloader mirror 可用於獲取類型和成員的表示。從類加載器鏡像中,能夠得到更專用的invoker mirror(最經常使用的鏡像),這些鏡像實現反射調用,例如方法或構造函數調用和字段訪問。code
概要:orm
staticClass
/ staticModule
/ staticPackage
方法)。MethodMirror.apply
,FieldMirror.get
等)。 這些 invoker mirror 是最經常使用的鏡像類型。在運行時使用的 mirror 入口點是經過 ru.runtimeMirror(<classloader>)
,其中 ru
是scala.reflect.runtime.universe
。對象
scala.reflect.api.JavaMirrors#runtimeMirror
調用的結果是一個類加載器鏡像,類型爲scala.reflect.api.Mirrors#ReflectiveMirror
,它能夠按名稱加載符號。接口
類加載器鏡像能夠建立調用者鏡像(包括 scala.reflect.api.Mirrors#InstanceMirror
,scala.reflect.api.Mirrors#MethodMirror
,scala.reflect.api.Mirrors#FieldMirror
,scala.reflect.api.Mirrors#ClassMirror
和 scala.reflect.api.Mirrors#ModuleMirror
)。ssl
這兩種類型的鏡像如何交互的例子能夠在下面找到。
`ReflectiveMirror
用於按名稱加載符號,並做爲調用者鏡像的入口點。 入口點:val m = ru.runtimeMirror(<classloader>)
。 例:
scala> val ru = scala.reflect.runtime.universe ru: scala.reflect.api.JavaUniverse = ... scala> val m = ru.runtimeMirror(getClass.getClassLoader) m: scala.reflect.runtime.universe.Mirror = JavaMirror ...
InstanceMirror
用於爲方法和字段以及內部類和內部對象(模塊)建立調用者鏡像。 入口點:val im = m.reflect(<value>)
。例:
scala> class C { def x = 2 } defined class C scala> val im = m.reflect(new C) im: scala.reflect.runtime.universe.InstanceMirror = instance mirror for C@3442299e
MethodMirror
用於調用實例方法(Scala只有實例方法 - 對象方法是對象實例的實例方法,可經過ModuleMirror.instance
獲取)。入口點:val mm = im.reflectMethod(<method symbol>)
。 例:
scala> val methodX = ru.typeOf[C].decl(ru.TermName("x")).asMethod methodX: scala.reflect.runtime.universe.MethodSymbol = method x scala> val mm = im.reflectMethod(methodX) mm: scala.reflect.runtime.universe.MethodMirror = method mirror for C.x: scala.Int (bound to C@3442299e) scala> mm() res0: Any = 2
FieldMirror
用於獲取/設置實例字段(如方法,Scala只有實例字段,參見上文)。 入口點:val fm = im.reflectField(<field or accessor symbol>)
。 例:
scala> class C { val x = 2; var y = 3 } defined class C scala> val m = ru.runtimeMirror(getClass.getClassLoader) m: scala.reflect.runtime.universe.Mirror = JavaMirror ... scala> val im = m.reflect(new C) im: scala.reflect.runtime.universe.InstanceMirror = instance mirror for C@5f0c8ac1 scala> val fieldX = ru.typeOf[C].decl(ru.TermName("x")).asTerm.accessed.asTerm fieldX: scala.reflect.runtime.universe.TermSymbol = value x scala> val fmX = im.reflectField(fieldX) fmX: scala.reflect.runtime.universe.FieldMirror = field mirror for C.x (bound to C@5f0c8ac1) scala> fmX.get res0: Any = 2 scala> fmX.set(3) scala> val fieldY = ru.typeOf[C].decl(ru.TermName("y")).asTerm.accessed.asTerm fieldY: scala.reflect.runtime.universe.TermSymbol = variable y scala> val fmY = im.reflectField(fieldY) fmY: scala.reflect.runtime.universe.FieldMirror = field mirror for C.y (bound to C@5f0c8ac1) scala> fmY.get res1: Any = 3 scala> fmY.set(4) scala> fmY.get res2: Any = 4
ClassMirror
用於爲構造函數建立調用者鏡像。入口點:對於靜態類 val cm1 = m.reflectClass(<class symbol>)
,對於內部類 val mm2 = im.reflectClass(<class symbol>)
。 例:
scala> case class C(x: Int) defined class C scala> val m = ru.runtimeMirror(getClass.getClassLoader) m: scala.reflect.runtime.universe.Mirror = JavaMirror ... scala> val classC = ru.typeOf[C].typeSymbol.asClass classC: scala.reflect.runtime.universe.Symbol = class C scala> val cm = m.reflectClass(classC) cm: scala.reflect.runtime.universe.ClassMirror = class mirror for C (bound to null) scala> val ctorC = ru.typeOf[C].decl(ru.termNames.CONSTRUCTOR).asMethod ctorC: scala.reflect.runtime.universe.MethodSymbol = constructor C scala> val ctorm = cm.reflectConstructor(ctorC) ctorm: scala.reflect.runtime.universe.MethodMirror = constructor mirror for C.<init>(x: scala.Int): C (bound to null) scala> ctorm(2) res0: Any = C(2)
ModuleMirror
用於訪問單例對象的實例。入口點:對於靜態對象 val mm1 = m.reflectModule(<module symbol>)
,對於內部對象 val mm2 = im.reflectModule(<module symbol>)
。例:
scala> object C { def x = 2 } defined module C scala> val m = ru.runtimeMirror(getClass.getClassLoader) m: scala.reflect.runtime.universe.Mirror = JavaMirror ... scala> val objectC = ru.typeOf[C.type].termSymbol.asModule objectC: scala.reflect.runtime.universe.ModuleSymbol = object C scala> val mm = m.reflectModule(objectC) mm: scala.reflect.runtime.universe.ModuleMirror = module mirror for C (bound to null) scala> val obj = mm.instance obj: Any = C$@1005ec04
編譯時鏡像僅使用類加載器鏡像來按名稱加載符號。
類加載器鏡像的入口點是經過 scala.reflect.macros.Context#mirror
。使用類加載器鏡像的典型方法包括scala.reflect.api.Mirror#staticClass
,scala.reflect.api.Mirror#staticModule
和 scala.reflect.api.Mirror#staticPackage
。例如:
import scala.reflect.macros.Context case class Location(filename: String, line: Int, column: Int) object Macros { def currentLocation: Location = macro impl def impl(c: Context): c.Expr[Location] = { import c.universe._ val pos = c.macroApplication.pos val clsLocation = c.mirror.staticModule("Location") // get symbol of "Location" object c.Expr(Apply(Ident(clsLocation), List(Literal(Constant(pos.source.path)), Literal(Constant(pos.line)), Literal(Constant(pos.column))))) } }
值得注意的是:有幾種高級別的選擇能夠用來避免手動查找符號。例如,Of[Location.type].termSymbol
(或 typeOf[Location].typeSymbol
,若是咱們須要一個 ClassSymbol
),這是類型安全的,由於咱們沒必要使用字符串來查找符號。