深入理解Java反射机制

反射机制定义

         在Java程序的运行过程中,对于任意的类,都能知道类的所有属性与方法,也能调用其实例化对象的任何方法与属性,这种在程序运行过程中检查周围环境,并可以依次进行进一步改变环境的能力,就是反射。翻译一下:反射可以在程序运行时根据类名获得类的详细信息。

RTTI原理

Java在运行时识别对象和类的类型信息的主要方式有两种:一种是反射,另一种则是RTTI,我们首先了解一下RTTIDE工作方式及其原理。

RTTI即为Run-time Type Identification,负责在运行时维护类的相关信息,通过运行时类型信息程序能够使用基类的指针或引用来检查这些指针或引用所指的对象的实际派生类型(节选自百度百科),多态则是基于这种能力而实现的。RTTI主要通过Class类实现,这里说的Class类是指class of classes(类的类),有人总结过:如果说类是对象的抽象和集合的话,那么Class类就是对类的抽象与集合,即其他类都是Class类的对象,当我们调用getClass()方法时,就能够得到对应Class对象的引用。

接下来我们通过一段代码来认识下RTTI:

/**
 * @author jhz
 * @date 18-8-15 下午8:50
 */
public class RTTITest {
    public static void main(String[] args) {
        Animal oneAnimal = new Animal();
        System.out.println(oneAnimal.getClass().getName());
        Animal oneDog = new Dog();
        System.out.println(oneDog.getClass().getName());
        Dog anotherDog = new Dog();
        Animal littleDog = anotherDog.propagate();
        System.out.println(littleDog.getClass().getName());
    }

}
class Animal{
    private int age;
    public int grow(){
        this.age++;
        return this.age;
    }
}

class Dog extends Animal{
    public Animal propagate(){
        System.out.println("propagating:");
        return new Animal();
    }
}

可以看到,new出来的是animal,得到的就是animal;new出来的是dog,得到的就是dog,正应了那句“龙生龙,凤生凤”,不管进行怎么的类型转换,对象本身对应的Class对象(类)也不会发生改变,正是由于这样的机制才能保证多态不会迷失在复杂的类型转换之中。除了getClass()方法,常用的还有forName()方法,即通过类名去获得Class对象。当我们创建某个类对象时(这里的类对象需要区别与Class类对象),Java首先会去内存中检查是否存在该Class类对象,比如我们创建一个dog对象,首先就会去检查是否存在Dog对象,如果内存中不存在,会继续搜索.class文件,在其中搜索Dog类的定义并加载该Class对象,该对象加载成功后,其余的Human对象都参照该Class对象进行创建和相关操作。注:该加载过程都是在第一次使用该类时动态加载到JVM的(因此类中的静态块是在类加载时才完成初始化的)。该过程如下:

  • 加载:由类加载器完成,找到对应的字节码,创建一个Class对象
  • 链接:验证类中的字节码,为静态域分配空间
  • 初始化:如果该类有超类,则对其初始化,执行静态初始化器和静态初始化块

特点:RTTI可以在运行时告诉我们某个对象的类型信息,但是有一个前提:这个类型必须是在编译时就已知的了,否则我们就需要反射机制的支持了。

 

反射原理

在Java中,可以支持Class<?> c = Class.forName(Stringarg[0])这样的获取Class对象的方式,这里的参数定义在Field类的成员变量中,同时reflect库中的Method类也支持Method[] methods = c.get Methods()这种从不确定的类中获取方法的方式,在编译时,编译器并不知道forName()方法的参数Stringarg[0]到底是什么,因此也不知道该去打开哪个.class文件,这时JVM是如何应该作何抉择呢?可以看到reflect类库中Field、Method以及Constructor类源码中的成员变量:

它们定义了一系列变量来存储未知类的类型信息,表示未知类里的成员,在JVM启动时创建,用于存储未知对象的类型信息。这样就能等到运行时再去确定类的细节信息,比如使用get、set方法修改类中与Field成员变量相关的类的信息,用invoke方法调用与Method对象关联的方法,这样便能在运行时获得信息之后,再去了解一个类。因此,在使用反射了解一个未知对象时,JVM只是简单的检查它属于哪一个类,因此,这个类必须是可获取的,要么在本地,要么在网络上可以获取(dubbo就是在网络上获取服务方的类对象)。因此反射与RTTI的本质区别其实在于:

  • RTTI,编译器在编译时打开和检查.class文件
  • 反射,运行时打开和检查.class文件
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值