Java的Class对象

一、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 这种方式就会立刻进行初始化。

猜你喜欢

转载自blog.csdn.net/chinabate/article/details/79860132