scala反射详解

编程入门 行业动态 更新时间:2024-10-27 22:26:48

scala<a href=https://www.elefans.com/category/jswz/34/1765951.html style=反射详解"/>

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入口
  1. 镜像的入口通过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反射详解

本文发布于:2023-07-03 16:27:13,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1008937.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:反射   详解   scala

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!