RTTI,英文全称Run-Time Type Identification,即运行时类型识别,我们常用的多态就是基于RTTI实现的。RTTI的功能主要有Class类实现。
在Java中,所有的类都是在对其第一次使用时,动态加载到JVM中的。当程序创建第一个对类的静态成员的引用是,就会加载这个类,所以构造器也是静态的,即使它并没有声明成static。
在程序运行时,类加载器会先检查这个类的Class对象是否已经加载。如果没有加载,默认的类加载器就会根据类名查找.class文件,将其加载进内存,然后用它来创建对象。
获取Class对象的方法:
Class.forName(包名.对象名)
类名.class
对象.getClass()
Class.forName(包名.对象名)
public class Demo1 {
public static void main(String[] args) throws Exception{
new A();
System.out.println("-----------------");
Class.forName("chapter14.B");
System.out.println("----------------");
new C();
}
}
class A{
static{
System.out.println("Loading A");
}
}
class B{
static{
System.out.println("Loading B");
}
}
class C{
static{
System.out.println("Loading C");
}
}
结果:
Loading A
-----------------
Loading B
----------------
Loading C
可以看出Class对象仅在需要的时候加载,当一个类的Class对象没有加载时,“Class.forName(包名.对象名)”会加载类。
类名.class
也叫使用类字面常量生成Class对象引用,需要特别注意的是,使用此方法来创建Class对象引用时,不会自动地初始化该Class对象,这与用Class.forName()来创建是不一样的。为了使用类而做的准备工作时间包含三个步骤:
1.加载,由类加载器执行,该步骤将查找字节码,并从这些字节码中创建Class对象。
2.链接,在链接阶段将验证类中的字节码,为静态域分配存储空间,并且如果必需的话,将解析这个类创建的对其他类的引用。
3.初始化,如果给类具有超类,则对其初始化,执行静态初始化器和静态构造代码块。
可以看到,初始化被延迟到了对静态方法或者非常数静态域进行首次引用时才执行。
public class Demo2 {
public static Random rand = new Random(47);
public static void main(String[] args) throws Exception {
Class t1 = Test1.class;
System.out.println("----------------");
System.out.println(Test1.staticFinal); // 对常数静态域的引用
System.out.println("-----------------");
System.out.println(Test1.staticFinal2); // 对非常数静态域的引用
System.out.println("----------------");
System.out.println(Test2.staticNoFinal);
System.out.println("----------------");
Class t3 = Class.forName("chapter14.Test3");
System.out.println("----------------");
System.out.println(Test3.staticNoFinal);
}
}
class Test1{
static final int staticFinal = 47;
static final int staticFinal2 = Demo2.rand.nextInt(1000);
static{
System.out.println("Initializing Test1");
}
}
class Test2{
static int staticNoFinal = 147;
static{
System.out.println("Initializing Test2");
}
}
class Test3{
static int staticNoFinal = 74;
static{
System.out.println("Initializing Test3");
}
}
输出:
----------------
47
-----------------
Initializing Test1
258
----------------
Initializing Test2
147
----------------
Initializing Test3
----------------
74