一、RTTI
运行时类型信息(RTTI)使得你可以在程序运行时发现和使用类型信息。
二、Class对象
运行时类型信息(RTTI)是由被称为Class对象的特殊对象完成的,它包涵了与类有关的信息。实际上,Class对象就是用来创建类的所有的“常规”对象的。Java使用Class对象来执行其RTTI。
每个类都有一个Class对象,当我们编译一个新类时,Class对象就被保存在了一个同名的.class文件中了。Java虚拟机使用“类加载器”来加载Class对象。
所有的类都是在对其第一次使用时,动态加载到JVM中的。当程序创建第一个对类的静态成员的引用时,就会加载这个类,所以证明构造器也是类的静态方法。因此使用new操作符创建类的新对象也会被当做对类的静态成员的引用。因此Java程序运行之前并非被完全加载,其各部分都是在必需时才加载的。
1、获取Class对象的有三种方式:
①调用运行时类本身的字面常量 Demo.class
②通过运行时类对象的getClass方法获取
③通过Class的静态方法forName()获取
public class ClassTest {
/**
* @param args
* @throws ClassNotFoundException
*/
public static void main(String[] args) throws ClassNotFoundException {
Demo demo = new Demo();
//1、调用运行时类本身的.class属性
Class cls = Demo.class;
print(cls);
//2、通过运行时类对象的getClass方法获取
Class cls2 = demo.getClass();
print(cls2);
//3、通过Class的静态方法forName()获取
Class cls3 = Class.forName("com.java.Demo");
print(cls3);
}
public static void print(Class cls) {
System.out.println("-----" + cls.getSimpleName());
}
}
class Demo{
}
2、为了使用类需要三个步骤的准备工作:
①加载,这是由类加载器执行的,该步骤将查找字节码,并从这些字节码中创建一个Class对象。
②链接,在链接阶段将验证类中的字节码,为静态域分配存储空间,并且如果必需的话,将解析这个类创建的对其他类的所有引用。
③初始化,如果该类具有超类,则对其初始化,执行静态初始化器和和静态初始化块。初始化延迟到了对静态方法(构造器也是静态的)或者非常数静态域进行首次引用时才执行。
验证代码 四个类 ClassInitialization、Initable、Initable1、Initable2
public class ClassInitialization {
/**
* @param args
*/
public static Random rand = new Random(47);
public static void main(String[] args) throws ClassNotFoundException {
Class inti = Initable.class;
System.out.println("==========分割线1======");
System.out.println("=======staticFianl="+Initable.staticFinal);
System.out.println("==========小分割线1======");
System.out.println("=======staticFianl="+Initable.staticFinal2);
System.out.println("==========分割线2======");
System.out.println("=======staticFian3="+Initable1.staticFinal3);
System.out.println("==========分割线3======");
Class inti2 = Class.forName("com.java.Initable2");
System.out.println("==========小分割线3======");
System.out.println("=======staticFian4="+Initable2.staticFinal4);
}
}
class Initable {
public static final int staticFinal = 47;//编译时期的常量
public static final int staticFinal2 =
ClassInitialization.rand.nextInt(500);//运行时期的常量
static {
System.out.println("Initialization -- Initable");
}
}
class Initable1 {
public static int staticFinal3 = 47;
static {
System.out.println("Initialization -- Initable1");
}
}
class Initable2 {
public static int staticFinal4 = 47;
static {
System.out.println("Initialization -- Initable2");
}
}
运行结果:
==========分割线1======
=======staticFianl=47
==========小分割线1======
Initialization -- Initable
=======staticFianl=258
==========分割线2======
Initialization -- Initable1
=======staticFian3=47
==========分割线3======
Initialization -- Initable2
==========小分割线3======
=======staticFian4=47
分析:
当时用“.class”来创建对Class对象的引用时,不会自动的初始化该Class对象,所以不会输出静态代码块的内容,而Initable类的staticFinal 字段是编译期常量,输出也不会初始化该Class对象。但是通过Class.forName 这种方式就会立刻进行初始化。