JavaのClassオブジェクト

3804 ワード

一、RTTI
        ランタイムタイプ情報(RTTI)を使用すると、プログラムの実行時にタイプ情報を発見して使用することができます.
二、Classオブジェクト
        ランタイムタイプ情報(RTTI)はクラスに関する情報を含むクラスオブジェクトと呼ばれる特殊なオブジェクトによって作成される.実際、Classオブジェクトはクラスのすべての一般オブジェクトを作成するために使用されます.JavaはClassオブジェクトを使用してRTTIを実行します.
        各クラスにはClassオブジェクトがあり、新しいクラスをコンパイルすると、Classオブジェクトは同じ名前の.classファイルに保存されます.Java仮想マシンはクラスローダを使用してClassオブジェクトをロードします.
        すべてのクラスは、最初の使用時にJVMに動的にロードされます.プログラムがクラスの静的メンバーへの最初の参照を作成すると、このクラスがロードされるので、コンストラクタもクラスの静的メソッドであることを証明します.したがってnewオペレータを使用してクラスを作成する新しいオブジェクトも、クラスの静的メンバーへの参照として使用されます.したがって,Javaプログラムが実行されるまで完全にロードされるわけではなく,その各部は必要に応じてロードされる.
        1、Classオブジェクトを取得するには3つの方法があります.
                ①ランタイムクラス自体を呼び出す字面定数 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、クラスを使用するには3つのステップの準備が必要です.
            ①クラス・ローダによって実行されるロードです.このステップでは、バイト・コードが検索され、これらのバイト・コードからClassオブジェクトが作成されます.
            ②リンクは、リンクフェーズでクラス内のバイトコードを検証し、静的ドメインに記憶領域を割り当て、必要であれば、このクラスが作成した他のクラスへのすべての参照を解析します.
            ③イニシャル化し、クラスにスーパークラスがある場合はイニシャル化し、スタティックイニシャルおよびスタティックイニシャルブロックを実行する.初期化は、静的メソッド(コンストラクタも静的)または非常数の静的ドメインを最初に参照するときに遅延します.
          検証コードの4つのクラス 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.forNameではすぐに初期化されます.