黑猴子的家:Scala 运行时反射

scala编译器会将scala代码编译成JVM字节码,编译过程中会擦除scala特有的一些类型信息,在scala-2.10以前,只能在scala中利用java的反射机制,但是通过java反射机制得到的只是擦除后的类型信息,并不包括scala的一些特定类型信息。从scala-2.10起,scala实现了自己的反射机制,我们可以通过scala的反射机制得到scala的类型信息。
给定类型或者对象实例

通过scala运行时反射,可以做到
1)获取运行时,类型信息;
2)通过类型信息,实例化新对象;
3)访问或调用对象的方法和属性等。

我们可以通过反射,去实例化一个对象,当然java也可以,可以通过反射实例化的对象,调用这个类的方法,私有的方法也可以被调用出来,所以说,反说是不安全的,但其实,反射是最安全的,这个话呐,我们要去辩论的去理解,反射最安全的原因是,反射是动态的,
控制会很灵活,只要你的思维缜密,它是很安全的,它不安全的原因是,你调用某个方法的时候,这个方法依赖的另外一个对象,它没有实例化完成,你调用的时候,不就崩溃了,那就不行了,所以说,反射动态调用的时候,有一定的动态依赖性,依赖性考虑不好的话,就会出错了

1、获取运行时类型信息

scala运行时类型信息是保存在TypeTag对象中,编译器在编译过程中将类型信息保存到TypeTag中,并将其携带到运行期。我们可以通过typeTag方法获取TypeTag类型信息。

object Nc2 {
  def main(args: Array[String]): Unit = {
    import scala.reflect.runtime.universe._
    //得到了包装Type对象的TypeTag对象
    val typeTagList = typeTag[List[Int]]
    println(typeTagList)
    //或者使用typeOf,直接得到了Type对象
    println(typeOf[List[Int]])
  }
}

尖叫提示:Type对象是没有被类型擦除的

我们可以通过typeTag得到里面的type,再通过type得到,里面封装的各种内容:

object N3 {
  def main(args: Array[String]): Unit = {
    import scala.reflect.runtime.universe._
    val typeTagList = typeTag[List[Int]]
    println(typeTagList)
    println(typeTagList.tpe)
    // decls  声明
    println(typeTagList.tpe.decls.take(10))
  }
}

2、运行时类型实例化

我们已经知道通过Type对象可以获取未擦除的详尽的类型信息,下面我们通过Type对象中的信息找到构造方法并实例化类型的一个对象

class Person(name:String, age: Int) {

  def myPrint() = {
    println(name + "," + age)
  }

}

object PersonMain {
  
  def main(args: Array[String]): Unit = {

    //得到JavaUniverse用于反射
    val ru = scala.reflect.runtime.universe
    
    //得到构造器Method
    val constructor = ru.typeOf[Person].decl(ru.termNames.CONSTRUCTOR).asMethod
    
    //得到一个JavaMirror,一会用于反射Person.class
    // JavaMirror是用来描述类信息的,但Mirror不是这个类
    val mirror = ru.runtimeMirror(getClass.getClassLoader)
    
    //得到Person类的Type对象后,得到type的特征值并转为ClassSymbol对象
    val classPerson = ru.typeOf[Person].typeSymbol.asClass
    
    //得到classMirror对象
    val classMirror = mirror.reflectClass(classPerson)

    //得到MethodMirror
    val methodMirror = classMirror.reflectConstructor(constructor)

    //实例化该对象
    val p = methodMirror("Mike", 1)

    println(p)
    
  }
}

3、运行时类成员的访问

class Person2(name: String, age: Int) {
  def myPrint() = {
    println(name + "," + age)
  }
}

object Fs3 {
  def main(args: Array[String]): Unit = {

    //获取Environment和universe
    val ru = scala.reflect.runtime.universe
    //获取对应的Mirrors,这里是运行时的
    val mirror = ru.runtimeMirror(getClass.getClassLoader)
    //得到Person类的Type对象后,得到type的特征值并转为ClassSymbol对象
    val classPerson = ru.typeOf[Person2].typeSymbol.asClass
    //用Mirrors去reflect对应的类,返回一个Mirrors的实例,而该Mirrors装载着对应类的信息
    val classMirror = mirror.reflectClass(classPerson)
    //得到构造器Method
    val constructor = ru.typeOf[Person2].decl(ru.termNames.CONSTRUCTOR).asMethod
    //得到MethodMirror
    val methodMirror = classMirror.reflectConstructor(constructor)
    //实例化该对象
    val p = methodMirror("Mike", 1)
    println(p)


    //反射方法并调用
    val instanceMirror = mirror.reflect(p)
    //得到Method的Mirror
    val myPrintMethod = ru.typeOf[Person2].decl(ru.TermName("myPrint")).asMethod
    //通过Method的Mirror索取方法
    val myPrint = instanceMirror.reflectMethod(myPrintMethod)
    //运行myPrint方法
    myPrint()


    //得到属性Field的Mirror
    val nameField = ru.typeOf[Person2].decl(ru.TermName("name")).asTerm
    val name = instanceMirror.reflectField(nameField)
    println(name.get)

  }
}

学习spark的时候,基本用不到,但是我们要学习一下,会Java的反射,不会Scala 的反射,挺唐突的,这样一来,Java能实现的,Scala基本都能实现了

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,001评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,210评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,874评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,001评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,022评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,005评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,929评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,742评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,193评论 1 309
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,427评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,583评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,305评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,911评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,564评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,731评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,581评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,478评论 2 352

推荐阅读更多精彩内容