反射reflection是程序对自身的检查、验证甚至代码修改功能。反射可以通过它的Reify功能来实时自动构建生成静态的Scala实例如:类(class)、方法(method)、表达式(expression)等。或者动态跟踪当前程序运算事件如:方法运算(method invocation)、字段引用(field access)等。反射又分编译时段与运算时段反射即:compile-time-reflection及runtime-reflection。我们使用compile-time-reflection在编译程序时指导编译器修改编译中代码或者产生新的代码,用runtime-reflection来进行实例的类型匹配、验证等。在v2.10之前,Scala没有自备的Reflection工具库,只能用Java Reflection库提供的部分功能来动态检验类型(class)或对象(object)及使用它们的字段(member access)。但java-reflection无法提供对某些scala项目的支持如:function、trait以及特殊类型如:existential、high-kinder、path-dependent、abstract types。特别是java-reflection无法获取泛类型在runtime过程中的信息,这个一直是一个诟病。直到scala2.10增加了新的reflection库才从根本上解决了针对scala特性的反射(refective)功能问题。scala-reflection同样提供了compile-time-reflection和runtime-reflection。其中compile-time-reflection是通过独立的macro库实现的。在这篇讨论里我们主要介绍runtime-reflection功能。
scala runtime-reflection有以下几项主要功能:
1、动态检验对象类型,包括泛类型
2、实时构建类型实例
3、实时调用类型的运算方法
反射功能可以在两种环境下体现:compile-time及runtime,是通过反射库的universe命名空间分辨的,即:
runtime-reflection : scala.reflect.runtime.universe
compile-time-reflection: scala.reflect.macros.universe
我们必须import相应的命名空间来获取compile-time或runtime反射功能。
各种具体的runtime反射功能是通过Mirror来获取的,以runtimeMirror(...)为入口。下面是各种Mirror的获取和使用方法示范:
1 val ru = scala.reflect.runtime.universe 2 //runtime reflection入口
3 val m = ru.runtimeMirror(getClass.getClassLoader) //m: ru.Mirror = JavaMirror with java.net.URLClassLoader... 4 //sample class
5 class Person(name: String, age: Int) { 6 var hight: Double = 0.0
7 def getName = name 8 } 9 val john = new Person("John", 23) { 10 hight = 1.7
11 } 12 //instance mirror
13 val im = m.reflect(john) 14 //im: ru.InstanceMirror = instance mirror for... 15 //query method on instance
16 val mgetName = ru.typeOf[Person].decl(ru.TermName("getName")).asMethod 17 //mgetName: ru.MethodSymbol = method getName 18 //get method
19 val invoke_getName = im.reflectMethod(mgetName) //invoke_getName: ru.MethodMirror = ...
20 invoke_getName() 21 //res0: Any = John 22 //query field on instance
23 val fldHight = ru.typeOf[Person].decl(ru.TermName("hight")).asTerm 24 //fldHight: ru.TermSymbol = variable hight 25 //get field
26 val fmHight = im.reflectField(fldHight) //fmHight: ru.FieldMirror = ...
27 fmHight.get //res1: Any = 1.7
28 fmHight.set(1.6) 29 fmHight.get
30 //res3: Any = 1.6
31 val clsP = ru.typeOf[Person].typeSymbol.asClass 32 //get class mirror
33 val cm = m.reflectClass(clsP) 34 //get constructor symbol
35 val ctorP = ru.typeOf[Person].decl(ru.nme.CONSTRUCTOR).asMethod 36 //get contructor mirror
37 val ctorm = cm.reflectConstructor(ctorP) 38 val mary = ctorm("mary", 20).asInstanceOf[Person] 39 println(mary.getName) // mary
40 object OB { 41 def x = 3
42 } 43 //get object symbol
44 val objOB = ru.typeOf[OB.type].termSymbol.asModule 45 //get module mirror
46 val mOB = m.reflectModule(objOB) 47 //get object instance
48 val instOB = mOB.instance.asInstanceOf[OB.type] 49 println(instOB.x) // 3
上面例子里的typeOf[T]和typeTag[T].tpe及implicitly[TypeTag[T]].tpe是通用的,看下面的示范:
1 val clsP = ru.typeTag[Person].tpe.typeSymbol.asClass //ru.typeOf[Person].typeSymbol.asClass
2 val clsP1 = implicitly[ru.TypeTag[Person]].tpe.typeSymbol.asClass //clsP1: ru.ClassSymbol = class Person
3 val clsP2 = ru.typeTag[Person].tpe.t