ScalaJava中的反射机制探索

    xiaoxiao2021-03-25  102

    最近看Spark源码,看到在Spark这种底层架构中用到很多Scala/Java的反射机制,在网上看了一些关于Scala/Java反射机制的原理和用处,总结如下。scala的多线程的实现依赖于JVM的,在反射机制中也是完全套用了Java的反射机制,所以本文讨论的实际上就是Java的反射机制。

    反射机制的用处:1、在已有一个类的对象,在运行之前并不能确定这个对象对应的Class的时候,需要在运行时动态的确定所需要的类的时候

         2、在给定的接口,当时无法得到接口内部的信息的时候,需要通过反射的方法来定义接口,这个在JDBC中使用的比较多。

         3、网上有很多说反射在黑客技术中使用的比较多,个人猜测是可以通过反射获得对象队形的class的内部所有的信息和类结构,field、constructor、method等。

    1、在应用层面

    在你编写好并且编译过后,会生成Class文件,这些Class文件在被JVM的ClassLoader加载之后都会有对应的java.lang.Class<T>这个类的实例。每个类的自有的方法属性(类的结构)会自然的包含在这个实例上,因此就可以获取到对应的方法属性,无论这写方法属性是否private.

    2、在jvm层面

    首先,Class文件是以8位字节为基础的二进制文件,这些二进制文件是按照严格的结构顺序保存的,里面的结构顺序为:

    版本号、常量池、访问标志、类索引、字段表集合等

          知道了Class文件的物理结构了,就可以随心所欲的获取关于这些类的所有信息了。

    从上面可以得知,在反射获取一个类的信息(Fields/Method/Constructor)之前,需要加载这个类的class文件,通过class文件中的物理结构来获取这个类的所有信息。

    假设有类

    class Secret(sec:String){ private val secrecy = sec def getSecrecy(){ return "Inner Secret" } }

    我们有了一个Secret类的对象:

    val s = new Secret("Top Secret")

    我们可以通过以下方法Secret的class对象:

    val clz = Class.forName("Secret") // 在forName内填写需要的类名称,如果是在同一个包中,但是不是同一个文件内则需要填写完整的包路径,比如com.test.Secret

    此时,Java虚拟机会加载Secret的class文件,然后在方法区创建Secret类实例,即Secret的class对象。

    然后我们使用getDeclaredFiled()来获取这个类的field

    val f = clz.getDeclaredField("secrecy")

    设置这个field的访问权限

    f.setAccessible(true)

    println(f.get(s)) //输出为Top Secret 通过这种方法就能够范围s对象的私有成员变量了

    以上是Field的反射方法,Constructor和Method的反射方法类似。

    至于Class.forName是如何实现通过类名获得对应的class的,这个在JVM中是native方法,使用的是cpp实现的。总之就是取实现是的字节码文件,然后blalabla....没有细看,有兴趣的同学可以探究下JVM中这方面的实现。

    贴上自己做实验用的代码:

    class Secret(sec: String = "defalut") { def this(seret: Secret) { this(seret.getSecrecy()) } private val secrecy = sec def getSecrecy() = { "Inner Secret" } } object testReflection { def main(args: Array[String]): Unit = { // val semaphore = new Semaphore(5) // (1 to 10).foreach { _ => // new Thread(new EtaThread(semaphore)).start() // } val first = new Secret() val cls = Class.forName("Secret") val constructor = cls.getConstructor(classOf[Secret]) val s = constructor.newInstance(first) val f = s.getClass.getDeclaredField("secrecy") f.setAccessible(true) println(f.get(s)) val m: Method = Class.forName("Secret").getDeclaredMethod("getSecrecy") m.setAccessible(true) println(m.invoke(s)) } }

    【参考文献】

    http://a.codekk.com/detail/Android/Mr.Simple/公共技术点之 Java 反射 Reflection

    https://www.zhihu.com/question/46883050

    转载请注明原文地址: https://ju.6miu.com/read-4088.html

    最新回复(0)