Javaクラスとオブジェクトの初期化順序

4346 ワード

Javaクラスとオブジェクトは、初期化時に主に次の順序で行われます.
親静的変数と静的ブロック(両方の初期化順序は定義された順序)-->子静的変数と静的ブロック-->親一般メンバーとブロック-->親構造関数-->子一般メンバーとブロック-->子構造関数
個人的な理解:親静的変数静的ブロックと子静的変数静的ブロックの初期化はクラスの初期化と呼ぶべきであり、他の4つのステップはクラス関連オブジェクトの初期化と呼ぶべきである.後4ステップはオブジェクトと密接に関連しているため,オブジェクトのアクセスがなければ後4ステップは現れないことが後述の例で分かる.オブジェクトの初期化ステップがなく、クラスの初期化のみが励起される場合があります.
基本コード:
本明細書の例はいずれも以下のコードに基づいており,各例はやや変更されている.
public class Sample {
	Sample(String s) {
		System.out.println(s);
	}

	Sample() {
		System.out.println("Sample         ");
	}
}
public class Parent {
	static int x = 1;
	
	static Sample sam_pa = new Sample("      sam_pa   ");
	Sample sam1_pa=new Sample("  sam1_pa     ");
	static {
		System.out.println("  static 2   ");
	}
	
	Parent() {
		System.out.println("          ");
	}
	Parent(String s) {
		System.out.println("           ");
	}
	
	static {
		System.out.println("  static 1   ");
	}
	
	{
		System.out.println("   1  ");
	}
	
	Sample sam2_pa=new Sample("  sam2_pa     ");
	
	{
		System.out.println("   2  ");
	}
}
public class Child extends Parent{
	static final int y = 2;
	
	static {
		System.out.println("  static 1   ");
	}
	Sample sam1_ch=new Sample("  sam1_ch     ");
	static Sample sam_ch = new Sample("      sam_ch   ");
	
	Child() {
		System.out.println("          ");
	}
	
	static {
		System.out.println("  static 2   ");
	}
	Sample sam2_ch=new Sample("  sam2_ch     ");
}
public class StartClass {
	public static void main(String[] args){
		new Child();
	}
}

試行1:
StartClassのmain関数をエントリとしてプログラムを起動します.印刷結果を表示します:親静的メンバーsam_pa親staticブロック2を初期化親staticブロック1を実行
サブクラスstaticブロック1は、サブクラス静的メンバーsam_を実行するch初期化サブクラスstaticブロック2実行
親sam 1_paメンバー初期化親ブロック1親sam 2_を実行paメンバー初期化親ブロック2親デフォルトコンストラクタ呼び出しを実行
サブクラスsam 1_chメンバー初期化サブクラスsam 2_chメンバー初期化サブクラスデフォルト構築関数呼び出し
結果は、上述した初期化順序に完全に合致した.試行2:
Childクラスを次のように変更します.
public class Child extends Parent{
	static final int y = 2;
	
	static {
		System.out.println("  static 1   ");
	}
	Sample sam1_ch=new Sample("  sam1_ch     ");
	static Sample sam_ch = new Sample("      sam_ch   ");
	
	Child() {
		//super("string");
		System.out.println("          ");
	}
	
	static {
		System.out.println("  static 2   ");
	}
	Sample sam2_ch=new Sample("  sam2_ch     ");
	
	public static void main(String[] args){
		System.out.println("  main  ---    ");
		new Child();
	}
}

main関数が追加されました.Childのmain関数からプログラムを起動します.印刷結果を表示します.
親静的メンバーsam_pa親staticブロック2を初期化親staticブロック1を実行
サブクラスstaticブロック1は、サブクラス静的メンバーsam_を実行するch初期化サブクラスstaticブロック2実行
サブクラスmainメソッド---プログラムエントリ
親sam 1_paメンバー初期化親ブロック1親sam 2_を実行paメンバー初期化親ブロック2親デフォルトコンストラクタ呼び出しを実行
サブクラスsam 1_chメンバー初期化サブクラスsam 2_chメンバー初期化サブクラスデフォルト構築関数呼び出し
奇妙なことが起こり、main関数の最初の文がどのように真ん中に現れたのか、かなり気まずい位置にありました.の実はこれは正しいです.main関数を呼び出すと、JVM仮想マシンは、このmain関数がChildクラスのstaticメンバーであることを発見し、Childクラスの初期化プロセスを励起し、Childクラスを初期化するには、まずParentクラスを初期化するため、印刷結果の最初の6行が現れ、main関数に入り、7行目が印刷される.New Child()励起オブジェクトの初期化プロセスには,後のすべての行がある.
試行3:
StarClassのmain関数を次のように変更します.
public class StartClass {
	public static void main(String[] args){
		System.out.println(Child.x);
		System.out.println(Child.y);
	}
}

印刷結果:
親静的メンバーsam_pa親staticブロック2を初期化親staticブロック1を実行1 2を実行
そうだxのアクセスは、xが親のstatic変数であるため、実際に親のクラス初期化プロセスを励起します.そうだyのアクセスは、Childのため、初期化プロセスを励起しません.yは定数です.試行4:
Childのデフォルトのコンストラクション関数を次のように変更します.
Child() {
		super("string");
		System.out.println("          ");
	}

印刷結果:
親静的メンバーsam_pa親staticブロック2を初期化親staticブロック1を実行
サブクラスstaticブロック1は、サブクラス静的メンバーsam_を実行するch初期化サブクラスstaticブロック2実行
サブクラスmainメソッド---プログラムエントリ
親sam 1_paメンバー初期化親ブロック1親sam 2_を実行paメンバー初期化親ブロック2親文字列構築関数呼び出しを実行
サブクラスsam 1_chメンバー初期化サブクラスsam 2_chメンバー初期化サブクラスデフォルト構築関数呼び出し
コンストラクション関数で親指定コンストラクション関数を呼び出すと、親のデフォルトコンストラクション関数は実行されません.
以上が実践によって証明されたjava初期化順序であるが、実際には初期化順序の内容はこれだけではない.例えばinterfaceとその関連メンバーが初期化過程全体の位置がどこにあるか、ここではまだ触れていない.では、実際に問題に遭遇したときに実践して証明しましょう.