美文网首页spark||flink||scala
黑猴子的家:Scala 运行时反射

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

作者: 黑猴子的家 | 来源:发表于2019-06-07 21:20 被阅读0次

    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基本都能实现了

    相关文章

      网友评论

        本文标题:黑猴子的家:Scala 运行时反射

        本文链接:https://www.haomeiwen.com/subject/aeocxctx.html