java之rtti(run-time Type identification)类对象

RTTI (run-time Type identification) :

为什么要使用rtti:rtti代表java类型信息,从面向对象的角度来说,每一个对象都是一个类,那么类型也是一个类:类型类,其保证不仅在编译期知道java对象的类型,并且可以在运行期 运用对象的类型信息,在jvm中方法区保存class信息,但是类型对象一般存放在堆中
jvm是如何实现的呢?jvm通过在方法区保存class信息,类型对象一般存放在堆中,具体使用时则是通过堆中的类对象来获取类型信息。
使用场景一:instanceof关键字:尽管对象使用了java多态中的向上转型,依然可以识别出其类型类。
使用场景二: java在运行时识别对象类型有两种情况:传统rtti和反射类是程序的一部分,每一个类都有一个class对象,java使用class对象来执行RTTI
类是程序的一部分,每一个类都有一个class对象,java使用class对象来执行RTTI

Class对象中的forName方法

@CallerSensitive
public static Class<?> forName(String className)
            throws ClassNotFoundException {
    Class<?> caller = Reflection.getCallerClass();
    return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}

通过源码可以看到Class的静态方法forName 返回一个Class对象,这个方法的副作用是,如果 参数className所指向的类还没有被jvm加载,就先加载该类,执行其中的static方法。
可以不用为了使用该Class引用而持有该类型的对象。
可以看到使用class的forName方法 执行了其中的static方法,而使用.class 获得类型类(类字面常量,下一节会讲),仅把类加载进jvm,而不执行其中的static语句
类中的static方法,在class对象第一次被加载进jvm时执行,而class对象只在需要时被加载,也就是需要访问类中的静态方法时,因此可以认为构造函数也是class的一个静态方法。
深入理解java虚拟机 中所述,虚拟机把class文件加载到内存,并进行校验,解析初始化,最后形成可以被虚拟机直接使用的java类型,这就是虚拟机的类加载机制,这些都是在运行期进行的,因此是java具有良好的动态扩展语言特性。
其中规定,遇到new、getstatic、putstatic或invokestatic这四个字节码指令时,如果类没有进行初始化,首先触发其初始化。

加载

加载包括三个步骤:
1. 获取字节流
2. 将字节流所代表的静态存储结构转化为方法区运行时数据结构
3. 内存中生成一个代表这个类的java.lang.Class对象,做为方法区这个类的各种数据的访问入口
* 加载完成后生成Class类的对象,并没有规定必须在堆中,也可以在方法区中,这个对象可以访问方法区中这些类型数据的外部接口,因此也造成多用于反射创建对象。
* 那么什么是方法区呢?
首先需要了解一下java虚拟机的运行时数据区
这里写代码片.cnblogs.com/blog/1182497/201706/1182497-20170616192739978-1176032049.png” alt=”” title=”” />
其中绿色的是每个线程独有的,程序计数器表示字节码的行号指示器
方法区和堆是线程之间共享的。其中的作用是存放对象实例,几乎所有的对象实例及数组都要在堆上分配。方法区存储被虚拟机加载的类信息、常量、静态变量等,运行时常量池也是方法区的一部分(Metaspace表示类型的类型,不在jvm内存中,而是在本地内存中)。

类字面常量

也就是上面说的通过 类名.class 获得类型的引用,使用这种方式不会自动的初始化该class对象。
为使用类而做的准备工作包含三个步骤:
1. 加载 加载class,并创建一个class对象
2. 链接 分配静态空间
3. 初始化 执行静态初始化代码,或静态代码块时初始化
如果一个static final 是编译器常量,那么不需要类初始化就可以读取,但是static修饰的不是一个编译器常量(比如不是final修饰的,或者是一个随机变量),那么必须强制进行类初始化。

使用泛型,使 类引用更具体(利用了编译期检查)

instanceof

使用场景:在向下转型前,如果没有其他的信息表明这是一个什么类,那么使用instanceof是必须的,防止castException异常

使用反射可以调用向上转型后子类中的方法

也给程序留下了后门

public class ConcreteRtti implements IRttiInterface {

    @Override
  public void say() {
        System.out.println ("this is IRttiInterface");
    }
    private void concreteSay(){
        System.out.println ("this is concreteSay");
    }
    public static void main(String[] args) throws Exception {
        IRttiInterface iRttiInterface = new ConcreteRtti ();
        iRttiInterface.say ();
        System.out.println (iRttiInterface.getClass ().getName ());
        ConcreteRtti iRttiInterface1 = (ConcreteRtti) iRttiInterface;
        iRttiInterface1.concreteSay (); //调用非接口中的方法
        Method concreteMethod = iRttiInterface.getClass ().getDeclaredMethod ("concreteSay");
        concreteMethod.invoke (iRttiInterface);//调用非接口中的方法
    }
}

反射reflect

java reflect包中 包含Construct Field Method等类
反射是在运行时打开和检查.class文件,而普通rtti实在编译器 检查和运行.class,简单的使用

public static void main(String[] args) throws Exception {
    Class<ReflectTest> reClass = ReflectTest.class;
    ReflectTest test = reClass.newInstance (); //使用newInstance 必须有一个无参构造器
  Constructor[] cons = reClass.getConstructors ();
    Method[] methods = reClass.getMethods ();
    Method method0 = null;
    method0 = reClass.getMethod ("say");
    assert method0 != null;
    method0.invoke (test);
}

使用反射技术包括 动态代理等
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值