1. Scala 的 反射

关于 Scala 反射的具体内容,可以参考官方文档:https://docs.scala-lang.org/overviews/reflection/overview.html

这篇文章写一点自己的理解:

  • 由于 Scala 编译出来的内容是与 Java 相同的字节码文件,所以可以使用 Java 反射的相关方法来实现 Scala 代码的反射。
  • Scala 自己写了一套基于 Scala 的反射,具体的实现在 scala.reflect 这个 package 下面。
  • 这篇文章主要介绍,反射 Scala 中的 class 和 object 类的方法。

先看基础代码:

package com.personal

object ProvisioningApp {
val strInObj = "123"
def sayHello(): Unit = println("say hello")
def sayHello2(from: String, to: String): Unit = println(from + " say hello, " + to)
} class ProvisioningApp {
val strInClazz = "234"
def sayGoodbye(): Unit = println("say goodbye")
}

2. Java Style

2.1 使用 Java 的方式反射 Scala class

和反射 Java 的 class 步骤完全一致,所以不赘述,直接贴代码:

  test("Should reflect Scala class in Java style") {
val app = new ProvisioningApp
val field = classOf[ProvisioningApp].getDeclaredField("strInClazz")
field.setAccessible(true)
field.set(app, "789")
app.strInClazz shouldBe "789" val method = classOf[ProvisioningApp].getDeclaredMethod("sayGoodbye")
method.setAccessible(true)
method.invoke(app)
}

2.2 使用 Java 的方式反射 Scala object 

Scala 中的 object,称之为 “伴生类”,想要反射获取它的类或者方法,首先要知道它编译之后是个什么东西:

通过 jd-gui,我们知道了 Scala object 的具体实现:

  • 编译之后的类名是 "类名+$" 形式
  • 属性的名字,有时会和在代码中定义的不同(在这个例子里面没有显现,具体原因我还不知道,比如这个 "strInObj", 有时候这个类名会变成 “$com.$personal.$$strInObj” 这样)
  • 可以发现,这是一个使用静态代码块模式的单例,详见 https://www.cnblogs.com/jing-an-feng-shao/p/7501617.html
  • 因此,暂时没有找到使用 Java 方式反射 Scala object 的方法

3. Scala style

3.1 使用 Scala 方式反射 Scala class

步骤如下:

  1. 通过 universe 和 classLoader 找到 JavaMirror
  2. 通过 JavaMirror 和 实例化对象 获取 InstanceMirror
  3. 通过 universe 获取目标类的 TypeTag
  4. 通过 TypeTag 获取目标类的 TermSymbol or MethodSymbol
  5. 获取 FieldMirror or MethodMirror
  6. 反射执行
  test("Should reflect Scala class in Scala type") {
import scala.reflect.runtime.universe val app = new ProvisioningApp()
// JavaMirror
val classMirror = universe.runtimeMirror(getClass.getClassLoader)
// InstanceMirror
val instanceMirror = classMirror.reflect(app)
// TypeTag
val typeTag = universe.typeOf[ProvisioningApp] // TermSymbol
val strInClazzSymbol = typeTag.decl(universe.TermName("strInClazz")).asTerm
val fieldMirror = instanceMirror.reflectField(strInClazzSymbol)
fieldMirror.set("789")
app.strInClazz shouldBe "789" // MethodSymbol
val sayGoodbyeSymbol = typeTag.decl(universe.TermName("sayGoodbye")).asMethod
// MethodMirror and invoke action
val result = instanceMirror.reflectMethod(sayGoodbyeSymbol)() // No input parameters here
result shouldBe "Goodbye"
}

3.2 使用 Scala 方式反射 Scala object

与 Scala class 不同,反射 Scala object 核心是通过 staticModule 获取 ModuleMirror:

  test("Should reflect Scala object in Scala style") {
import scala.reflect.runtime.universe // JavaMirror
val classMirror = universe.runtimeMirror(getClass.getClassLoader)
// The ModuleSymbol for object
val staticMirror = classMirror.staticModule("com.personal.ProvisioningApp")
// ModuleMirror can be used to create instances of the class
val moduleMirror = classMirror.reflectModule(staticMirror)
// ObjectMirror can be used to reflect the members of the object
val objectMirror = classMirror.reflect(moduleMirror.instance)
// TermSymbol represents val, var, def and object declarations
val strInObjSymbol = moduleMirror.symbol.typeSignature.member(universe.TermName("strInObj")).asTerm
// FieldMirror can be used to get and set the value of the field
val fieldMirror = objectMirror.reflectField(strInObjSymbol)
fieldMirror.set("789")
ProvisioningApp.strInObj shouldBe "789" val sayHelloSymbol = moduleMirror.symbol.typeSignature.member(universe.TermName("sayHello")).asMethod
val sayHelloSymbol2 = moduleMirror.symbol.typeSignature.member(universe.TermName("sayHello2")).asMethod
// MethodMirror and invoke action
objectMirror.reflectMethod(sayHelloSymbol)()
objectMirror.reflectMethod(sayHelloSymbol2)("Sai", "Gerrard") // Pass the input parameters one by one
}

Scala进阶(1)—— 反射 object 和 class的更多相关文章

  1. Scala进阶之路-反射(reflect)技术详解

    Scala进阶之路-反射(reflect)技术详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. Scala中的反射技术和Java反射用法类似,我这里就不一一介绍反射是啥了,如果对 ...

  2. Scala进阶之路-Scala中的高级类型

    Scala进阶之路-Scala中的高级类型 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.类型(Type)与类(Class)的区别 在Java里,一直到jdk1.5之前,我们说 ...

  3. [.net 面向对象程序设计进阶] (21) 反射(Reflection)(下)设计模式中利用反射解耦

    [.net 面向对象程序设计进阶] (21) 反射(Reflection)(下)设计模式中利用反射解耦 本节导读:上篇文章简单介绍了.NET面向对象中一个重要的技术反射的基本应用,它可以让我们动态的调 ...

  4. Scala进阶之路-Scala中的枚举用法案例展示

    Scala进阶之路-Scala中的枚举用法案例展示 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. Scala中的枚举值和Java中的枚举值有点差别,不过使用起来也都差大同小异,我这 ...

  5. Scala进阶之路-Scala中的Ordered--Ordering

    Scala进阶之路-Scala中的Ordered--Ordering 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任.   说道对象的比较,在Java中大家最熟悉不过的就是实现类本身实 ...

  6. Scala进阶之路-正则表达式案例

    Scala进阶之路-正则表达式案例 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 废话不多说,正则大家都很清楚,那在Scala如何使用正则了?我们直接上个案例,如下: /* @au ...

  7. Scala进阶之路-进程控制之执行shell脚本

    Scala进阶之路-进程控制之执行shell脚本 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 废话不多说,我这里直接放一个案例. /* @author :yinzhengjie ...

  8. Scala进阶之路-Spark底层通信小案例

    Scala进阶之路-Spark底层通信小案例 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Spark Master和worker通信过程简介 1>.Worker会向ma ...

  9. Scala进阶之路-Scala高级语法之隐式(implicit)详解

    Scala进阶之路-Scala高级语法之隐式(implicit)详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 我们调用别人的框架,发现少了一些方法,需要添加,但是让别人为你一 ...

随机推荐

  1. 鸿蒙的js开发部模式16:鸿蒙布局Grid网格布局的应用一

    鸿蒙入门指南,小白速来!从萌新到高手,怎样快速掌握鸿蒙开发?[课程入口]目录:1.Grid简介2.使用Grid布局实现的效果3.grid-row-gap和grid-colunm-gap属性4.< ...

  2. 自己的Scrapy框架学习之路

    开始自己的Scrapy 框架学习之路. 一.Scrapy安装介绍 参考网上资料,先进行安装 使用pip来安装Scrapy 在开始菜单打开cmd命令行窗口执行如下命令即可 pip install Scr ...

  3. JDBC 用PreparedStatement语句动态操作SQL语句

    https://blog.csdn.net/u014453898/article/details/79038187 1.Statement 和 PreparedStatement: Statement ...

  4. Guava-RateLimiter实现令牌桶控制接口限流方案

    一.前言 对于一个应用系统来说,我们有时会遇到极限并发的情况,即有一个TPS/QPS阀值,如果超了阀值可能会导致服务器崩溃宕机,因此我们最好进行过载保护,防止大量请求涌入击垮系统.对服务接口进行限流可 ...

  5. Git:分支管理

    代码中至少有一个分支,就是主分支master,默认都是在主分支上开发. 多分支 分支名: 版本库中必须唯一 不能以 - 开头 可以试用/,但不能以/结尾,被/分隔的名称不能以.开头 不能有连个连续的 ...

  6. 001 说说Python中的深拷贝和浅拷贝

    在Python编程中忽略深拷贝和浅拷贝可能会造成未知的风险. 比如我们打算保存一份原始对象的副本作为上一状态的记录,此后修改原始对象数据时,若是副本对象的数据也发生改变,那么这就是一个严重的错误. 注 ...

  7. 10. vue之webpack打包详解

    一.什么是webpack webpack官网给出的定义是 本质上,webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler).当 webpack 处理应 ...

  8. js 前端MD5加密

    1.引入 <script src="https://cdn.bootcss.com/blueimp-md5/2.10.0/js/md5.js"></script& ...

  9. 【免费开源】基于Vue和Quasar的crudapi前端SPA项目实战—环境搭建 (一)

    背景介绍和环境搭建 背景 crudapi增删改查接口系统的后台Java API服务已经全部可用,需要一套后台管理UI,主要用户为开发人员或者对计算机有一定了解的工作人员,通过UI配置元数据和处理业务数 ...

  10. Hi3559AV100 NNIE开发(2)-RFCN(.wk)LoadModel及NNIE Init函数运行过程分析

    之后随笔将更多笔墨着重于NNIE开发系列,下文是关于Hi3559AV100 NNIE开发(2)-RFCN(.wk)LoadModel及NNIE Init函数运行过程分析,通过对LoadModel函数及 ...