scala反射

这篇博客主要探讨了Scala的反射机制,包括运行时和编译时的反射环境与镜像(Mirror)的区别。通过理解Scala的Universes和Mirrors,可以实现对类的方法和属性的动态操作。文中详细介绍了获取Environment、universe以及使用Mirrors进行反射操作的步骤,强调了反射过程中符号(Symbol)的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.

其实scala的非FP部分,看官方DOC是一个非常好的一个选择,FP部分推荐还是看HASHELL,毕竟我看过的书籍中,FP部分基本是HASHELL的"翻译",HASHELL是个非常好的语言,甚至其作者是推荐作为大学的课本,你不必会用HASHELL编写程序,这个是很少见的,但是要有HASHELL语言的思考逻辑去学习一门FP语言,记得我接触HASHELL是大二的时候了,它对我的影响却是很大.

 

2.

scala的反射,scala的反射分为两个范畴运行时和编译时

这两者之间的区别在于Environment,而Environment又是由universe决定的.反射的另一个重要的部分就是一个实体集合,而这个实体集合被称为mirror,有了这个实体集合我们就可以实现对需要反射的类进行对应的操作,如属性的获取,属性值得设置,以及对反射类方法的调用(其实就是成员函数的入口地址)!

讲了这么多都觉得很饶了,说的直白一些就是要获取可以操作类方法或者属性的mirror,而mirror又是Environment得来的,而Environment又是Universes得来的,而Universes根据运行时和编译时又可以分为两个领域的

 

3.

Universes

 

根据反射的要求不同可分为

scala.reflect.runtime.universe for runtime reflection

scala.reflect.macros.Universe for compile-time reflection

4.

Mirrors

这个很重要,所以我还要再唠叨几句,Mirrors可以对"符号"(这里涉及到编译原理的知识,不讲解),进行不同的操作所以通常分为

“Classloader”  mirrors
“Invoker”      mirrors

 

"Classloader" mirrors 负责把对应的name转译称"符号",这些符号所对一的name实实的存在的,待会用例子就好理解了

"Invoker”           mirrors 则是负责实现反射中的调用

 

5.运行时反射的实例

 

 

第一步:  获取Environment和universe

 

scala> val ru = scala.reflect.runtime.universe
ru: scala.reflect.api.JavaUniverse = scala.reflect.runtime.JavaUniverse@60cf3a


第二步: 获取对应的Mirrors,这里是运行时的

 

scala> val m = ru.runtimeMirror(getClass.getClassLoader)
m: ru.Mirror = JavaMirror with scala.tools.nsc.interpreter.IMain$TranslatingClas
sLoader@150b551 of type class scala.tools.nsc.interpreter.IMain$TranslatingClass
Loader with classpath [(memory)] and parent being scala.reflect.internal.util.Sc
alaClassLoader$URLClassLoader@ac5762 of type class scala.reflect.internal.util.S
calaClassLoader$URLClassLoader with classpath [file:/D:/ProgramFiles/Java/jdk1.8
.0_31/jre/lib/resources.jar,file:/D:/ProgramFiles/Java/jdk1.8.0_31/jre/lib/rt.ja
r,file:/D:/ProgramFiles/Java/jdk1.8.0_31/jre/lib/jsse.jar,file:/D:/ProgramFiles/
Java/jdk1.8.0_31/jre/lib/jce.jar,file:/D:/ProgramFiles/Java/jdk1.8.0_31/jre/lib/
charsets.jar,file:/D:/ProgramFiles/Java/jdk1.8.0_31/jre/lib/jfr.jar,file:/D:/Pro
gramFiles/Java/jdk1.8.0_31/jre/lib/ext/access-bridge.jar,file:/D:/ProgramFile...


第三步: 用Mirrors去reflect对应的类,返回一个Mirrors的实例,而该Mirrors装载着对应类的信息

scala> class C { def x = 2 }
defined class C
warning: previously defined object C is not a companion to class C.
Companions must be defined together; you may wish to use :paste mode for this.

scala> val im = m.reflect(new C)
im: ru.InstanceMirror = instance mirror for C@b55a0e

scala>


此时我们把一个类的信息"加载"完毕了,接下来我们来"反射"里面的信息,不过在反射之前我们要构建对应的符号(这个是我们上面介绍的,不懂没关系,会用就行)

 

第四步:符号

这里我们创建class C中变量x的符号

scala> val methodX = ru.typeOf[C].declaration(ru.TermName("x")).asMethod
warning: there was one deprecation warning; re-run with -deprecation for details

methodX: ru.MethodSymbol = method x


有了符号,我们就可以根据这个符号来向Mirrors"索求"我们的需要的东西了(这个就是反射了)

 

第五步:反射

scala> val mm = im.reflectMethod(methodX)
mm: ru.MethodMirror = method mirror for def x: scala.Int (bound to C@b55a0e)

 

 

第六步:已经反射到方法了,接下来...

 

scala> mm
res7: ru.MethodMirror = method mirror for def x: scala.Int (bound to C@b55a0e)

scala> mm()
res8: Any = 2

 

其实映射后我们并不是直接拿到该属性或者方法的,这是一个绑定,记住!

 

其他:

反射属性:

scala> class C { val x = 2; var y = 3 }
defined class C
warning: previously defined object C is not a companion to class C.
Companions must be defined together; you may wish to use :paste mode for this.

scala> class D { val x = 2; var y = 3 }
defined class D

scala> val m = ru.runtimeMirror(getClass.getClassLoader)
m: ru.Mirror = JavaMirror with scala.tools.nsc.interpreter.IMain$TranslatingClas
sLoader@150b551 of type class scala.tools.nsc.interpreter.IMain$TranslatingClass
Loader with classpath [(memory)] and parent being scala.reflect.internal.util.Sc
alaClassLoader$URLClassLoader@ac5762 of type class scala.reflect.internal.util.S
calaClassLoader$URLClassLoader with classpath [file:/D:/ProgramFiles/Java/jdk1.8
.0_31/jre/lib/resources.jar,file:/D:/ProgramFiles/Java/jdk1.8.0_31/jre/lib/rt.ja
r,file:/D:/ProgramFiles/Java/jdk1.8.0_31/jre/lib/jsse.jar,file:/D:/ProgramFiles/
Java/jdk1.8.0_31/jre/lib/jce.jar,file:/D:/ProgramFiles/Java/jdk1.8.0_31/jre/lib/
charsets.jar,file:/D:/ProgramFiles/Java/jdk1.8.0_31/jre/lib/jfr.jar,file:/D:/Pro
gramFiles/Java/jdk1.8.0_31/jre/lib/ext/access-bridge.jar,file:/D:/ProgramFile...

scala> val im = m.reflect(new D)
im: ru.InstanceMirror = instance mirror for D@119430f

scala> val fieldX = ru.typeOf[D].declaration(ru.TermName("x")).asTerm.accessed.a
sTerm
warning: there was one deprecation warning; re-run with -deprecation for details

fieldX: ru.TermSymbol = value x

scala> val fmX = im.reflectField(fieldX)
fmX: ru.FieldMirror = field mirror for private[this] val x: scala.Int (bound to
D@119430f)

scala> fmX.get
res9: Any = 2

scala> fmX.set(5)

scala> fmX.get
res11: Any = 5


 

这个是粗率的讲解scala反射,详细的

http://docs.scala-lang.org/overviews/reflection/environment-universes-mirrors.html


 

 

 

 

 

 

 


 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值