运行时类型信息使得我们可以在程序运行时发现和使用类型信息!
主要有两种方式:1、“传统”的RTTI,它假定我们在编译时已经知道所有的类型。
2、“反射”机制,它允许我们在运行时发现和使用类的信息。
Class对象:java使用Class对象来执行器RTTI。每一个类都有一个Class对象,通过类加载器生成。
类加载器步骤:1、检查这个类的Class对象是否已经加载,如果尚未加载,默认的类加载器就会根据类名查找.class文件。在这个类的字节码被加载时,它会接受验证,以确保它没被破坏或者含有不良的java代码。
2、一旦某个类的Class对象被载入内存,它就被用来创建这个类的所有对象。
所有的类都在对其第一次使用的时候动态加载到JVM中,当程序创建第一个对类的静态成员的引用的时候,就会加载这个类。这个证明构造器也是类的静态方法,所以new操作符创建类的新对象也被当做对类的静态成员的引用。java程序在开始运行之前并非完全被加载,其各个部分在必需时才会被加载(动态加载)。
Class.forName(String className):这个方法是Class类的一个static成员,是获得对象引用的一种方法(立即进行初始化)。只要你想在运行时使用类型信息,就必须获得对恰当的Class对象的引用。但是你已经拥有了感兴趣的类型对象,可以通过getClass()方法来获取Class引用,返回该对象的实际类型的Class引用。
Class.newInstance(): 实现“虚拟构造器”的一种途径,使用该方法创建的类,必须带有默认的构造器。
类字面常量:java提供的另一种获得Class对象引用。编译时就能受到检查(不需要置于try语句块中),根除了对forName()的调用,更加安全高效。
不仅可以应用于普通的类,也可以应用于接口、数组以及基本数据类型(基本数据类型还有个标准字段TYPE,是一个引用,指向对应的数据类型的Class对象)
使用类字面常量创建对Class对象的引用时,不会自动的初始化该Class对象。
为使用类而做的准备工作包括:1、加载。由类加载器完成,查找字节码,并从字节码中创建一个Class对象。
2、链接。验证类字节码,为静态域分配存储空间,如果必需的话,为解析这个类创建的对其他类的所有引用。
3、初始化。如果该类具有超类,则对其进行初始化,执行静态初始化器和静态初始化块。(对于static final值这种编译期常量,是不需要将类进行初始化就可以访问的;
对于一个static不是final的,那么对它进行访问时总是要求它被读取之前进行链接和初始化。)
向Class引用添加泛型语法的原因仅仅是为了提供编译期类型检查。?extends 限定为该类型或者该类型的子类。
Class.getSuperClass(): 获得该类的父类Class对象的引用,注意需要这样申明 Class<? super Son> father = son.getSuperClass(); 而Class<Father> 这样申明不被接受;并且 father.newInstance()
的返回值不是精确类型,而是Object。