运行时类型信息使得你可以在程序运行时发现和使用类型信息。
主要有两种方式:一种是"传统的"RTTI, 它假定我们在编译时已经知道了所有的类型;另一种是"反射"机制,它允许我们在运行时发现和使用类的信息。
Class对象
类是程序的一部分,每个类都有一个Class对象。换言之,每当编写并且编译一个新类,就会产生一个Class对象(更恰当的说,是被保存在一个同名的.class文件中)。为了生成这个类的对象,运行这个程序的Java虚拟机(JVM)将使用被称为"类加载器"的子系统。
所有的类都是在对其第一次使用时,动态加载到JVM中。当程序创建第一个对类的静态成员引用时,就会加载这个类。这个证明构造器也是类的静态方法,即使在构造器之前并没有使用static关键字。因此,使用new操作符创建类的新对象也会被当做对类的静态成员的引用。
Java程序在它开始运行之前并非被完全加载,其各个部分是在必需时才加载的。
类加载器首先检查这个类的Class对象是否已经加载。如果尚未加载,默认的类加载器就会根据类名查找.class文件。在这个类的字节码被加载时,它们会接受验证,以确保其没有被破坏,并且不包含不良Java代码
一旦某个类的Class对象被载入内存,它就被用来创建这个类的所有对象。
获取Class对象的方法:Class.forName("className"),object.getClass(),class.class;
类字面常量
如:Toy.class
类字面常量不仅简单,而且更安全,因为它在编译时就会受到检查(因此不需要置于try语句块中)。并且它根除了对forName()方法的调用,所以也更高效。
类字面常量不仅可以应用于普通的类,也可以应用于接口,数组以及基本数据类型。
当使用".class"来创建对Class对象的引用时,不会自动地初始化该Class对象。为了使用类而做的准备工作实际包含三个步骤:
1.加载,这个由类加载器执行的。该步骤将查找字节码(通常在classpath所指定的路径中查找,但这并非是必需的),并从这些字节码中创建一个Class对象。
2.链接,在链接阶段将验证类中的字节码,为静态域分配存储空间,并且如果必需的话,将解析这个类创建的对其它类的所有引用。
3.初始化,如果该类具有超类,则对其初始化,执行静态初始化器和静态初始化块。
初始化被延迟到了对静态方法(构造器隐式地是静态的)或者非常数静态域进行首次引用时才执行。
如果一个static final常量是"编译期常量",那么这个值不需要对类进行初始化就可以被读取。
如果一个static域不是final的,那么在对它访问时,总是要求在它被读取之前,要先进行链接(为这个域分配存储空间)和初始化(初始化该存储空间)
接口与类型信息
interface关键字的一种重要目标就是允许程序员隔离构件,进而降低耦合性。如果你编写接口,那么就可以实现这一目标,但是通过类型信息,这种耦合性还是会传播出去——接口并非是对解耦的一种无懈可击的保障。
动态代理
使用反射可以查看类的任何东西。