黑猴子的家: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基本都能实现了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值