Kotlin/Java中的反射详解

什么是反射

反射是一种计算机处理方式。有程序可以访问、检测和修改它本身状态或行为的这种能力。能提供封装程序集、类型的对象。
对于Java这种OOP语言来讲,运行状态中,我们可以根据“类的部分信息”来还原“类的全部信息”,这就是Java中的反射。

Java虚拟机的体系结构

Java虚拟机屏蔽了与具体操作系统平台相关的信息,使得Java程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。通俗地说Java虚拟机就是处理Java程序(确切地说是Java字节码)的虚拟机。
作为虚拟机,JVM的结构和常见的操作系统一致,有着自己的堆、栈、方法区、PC计数器和指令系统。它的结构如下图所示:
这里我们暂时不去谈类加载子系统与执行引擎,只谈一下Java运行时的数据区,它由五个部分组成:


image.png

(1)程序计数器(线程私有)
程序计数器是当前线程所执行的字节码的行号指示器,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,
分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。
在任何一个确定的时刻,一个处理器(对于多核处理器来说是一个内核)只会执行一条线程中的指令。
因此,为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的线程计数器,各条线程之间的计数器互不影响,独立存储。
(2)虚拟机栈(线程私有)
在Java(或者其他JVM的语言)每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。
每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
Java虚拟机栈存放局部变量表,如编译期可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用(reference类型,它不等同于对象本身,根据不同的虚拟机实现,它可能是一个指向对象起始地址的引用指针,也可能指向一个代表对象的句柄或者与此对象相关的位置)和returnAddress类型(指向了一条字节码指令的地址)。
这也导致在Java中匿名内部类来自外部闭包环境的自由变量必须是final的(Java编译器是capture-by-value模式),不过在Kotlin中则没有此限制,它通过自动包装实现了capture-by-reference(所以它没有基本类型)。
(3)本地方法栈(线程私有)
与虚拟机栈的作用相似,其区别为虚拟机栈执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机所使用的Native方法。
(4)堆(线程共享)
是Java虚拟机所管理的内存中最大的一块。Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域唯一的目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。
Java堆是垃圾收集器管理的主要区域,因此很多时候也被称为“GC堆”(Garbage Collected Heap)。由于现在收集器基本都是采用的分代收集算法,所以Java堆中还可以细分为:新生代和老年代。
(5)方法区(线程共享)
方法区用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
具体来讲,对于我们在Java程序中使用的每一个类,它都会在方法区生成一个对应的class文件,这个文件记录的信息有:
(如果你想了解更多的信息,可以参考http://blog.csdn.net/luanlouis/article/details/39892027),这里只简单的说明一下。
1.类信息
2.字段信息
3.方法信息
4.常量池
5.类变量(静态static字段,或者companion object)
6.classLoader的引用
7.class对象的引用
8.方法表
正由于在JVM的方法区中实时记录了这些信息,我们才可以在运行时获取类的全部信息,其关键在于获取其对应的Class对象。

获取Class对象

在Java中,获取Class对象有以下几种方法:
1: Class.forName("类名字符串") (注意:类名字符串必须是全称,包名+类名)
2: 类名.class
3: 实例对象.getClass()

    public void getClassTest()
    {
       try{
           Class baseInfo = Class.forName("com.suiseiseki.www.BaseInfo");
           Class object = Object.class;
           Class date = (new Date()).getClass();
           Class testclass = this.getClass();
       }
       catch (Exception e)
       {
           e.printStackTrace();
       }
    }

还原类的信息

获取类的构造器

Java提供以下Api用于获取类的构造方法:

// 获取“参数是parameterTypes”的public的构造函数
public Constructor    getConstructor(Class[] parameterTypes)
// 获取全部的public的构造函数
public Constructor[]    getConstructors()
// 获取“参数是parameterTypes”的,并且是类自身声明的构造函数,包含public、protected和private方法。
public Constructor    getDeclaredConstructor(Class[] parameterTypes)
// 获取类自身声明的全部的构造函数,包含public、protected和private方法。
public Constructor[]    getDeclaredConstructors()
// 如果这个类是“其它类的构造函数中的内部类”,调用getEnclosingConstructor()就是这个类所在的构造函数;若不存在,返回null。
public Constructor    getEnclosingConstructor()

例如:

public class Test1 {

    
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值