JAVA面接問題解決シリーズ(類の初期化順)

7753 ワード

URL:http://zangweiren.iteye.com
面接に行くとき、よくこのような問題に遭遇します.2つのクラスのコードをあげます.それらの間には継承の関係があります.各クラスにはコンストラクタの方法と変数しかありません.コンストラクタには変数値を演算するコードがあるかもしれません.また、変数値をコンソールに出力するコードもあります.そして出力の結果を判断しましょう.これは実際には,継承の場合のクラスの初期化順序に対する我々の理解を調べる.静的変数、静的初期化ブロック、変数、初期化ブロック、コンストラクタの初期化順序は、(静的変数、静的初期化ブロック)>(変数、初期化ブロック)>コンストラクタの順であることが知られている.この点は、次のテストコードで検証することもできます.
  • public   class  InitialOrderTest {  
  •   
  •     // せいてきへんすう  
  •     public   static  String staticField =  静的変数  
  •     // 変数#ヘンスウ#  
  •     public  String field =  変数  
  •   
  •     // スタティツクイニシャルブロック  
  •     static  {  
  •         System.out.println(staticField);  
  •         System.out.println(「静的初期化ブロック」);  
  •     }  
  •   
  •     // イニシャルブロック  
  •     {  
  •         System.out.println(field);  
  •         System.out.println(「初期化ブロック」);  
  •     }  
  •   
  •     // コンストラクタ  
  •     public  InitialOrderTest() {  
  •         System.out.println(「コンストラクタ」);  
  •     }  
  •   
  •     public   static   void  main(String[] args) {  
  •         new  InitialOrderTest();  
  •     }  
  • }  
  • public class InitialOrderTest {
    
    	//     
    	public static String staticField = "    ";
    	//   
    	public String field = "  ";
    
    	//       
    	static {
    		System.out.println(staticField);
    		System.out.println("      ");
    	}
    
    	//     
    	{
    		System.out.println(field);
    		System.out.println("    ");
    	}
    
    	//    
    	public InitialOrderTest() {
    		System.out.println("   ");
    	}
    
    	public static void main(String[] args) {
    		new InitialOrderTest();
    	}
    }
    

    上記のコードを実行すると、次のような出力結果が得られます.
  • 静的変数
  • 静的初期化ブロック
  • 変数
  • 初期化ブロック
  • コンストラクタ
  • これは、上記の説明と完全に一致しています.では、継承の場合はどうなりますか.最終的な結果は、テストコードで取得されます.
  • class  Parent {  
  •     // せいてきへんすう  
  •     public   static  String p_StaticField =  親--静的変数  
  •     // 変数#ヘンスウ#  
  •     public  String p_Field =  親--変数  
  •   
  •     // スタティツクイニシャルブロック  
  •     static  {  
  •         System.out.println(p_StaticField);  
  •         System.out.println(「親--静的初期化ブロック」)  
  •     }  
  •   
  •     // イニシャルブロック  
  •     {  
  •         System.out.println(p_Field);  
  •         System.out.println(「親--初期化ブロック」);  
  •     }  
  •   
  •     // コンストラクタ  
  •     public  Parent() {  
  •         System.out.println(「親--コンストラクタ」);  
  •     }  
  • }  
  •   
  • public   class  SubClass  extends  Parent {  
  •     // せいてきへんすう  
  •     public   static  String s_StaticField =  「サブクラス--静的変数」  
  •     // 変数#ヘンスウ#  
  •     public  String s_Field =  「サブクラス--変数」  
  •     // スタティツクイニシャルブロック  
  •     static  {  
  •         System.out.println(s_StaticField);  
  •         System.out.println(「サブクラス--静的初期化ブロック」);  
  •     }  
  •     // イニシャルブロック  
  •     {  
  •         System.out.println(s_Field);  
  •         System.out.println(「サブクラス--初期化ブロック」);  
  •     }  
  •   
  •     // コンストラクタ  
  •     public  SubClass() {  
  •         System.out.println(「サブクラス--コンストラクタ」);  
  •     }  
  •   
  •     // プログラムエントリ  
  •     public   static   void  main(String[] args) {  
  •         new  SubClass();  
  •     }  
  • }  
  • class Parent {
    	//     
    	public static String p_StaticField = "  --    ";
    	//   
    	public String p_Field = "  --  ";
    
    	//       
    	static {
    		System.out.println(p_StaticField);
    		System.out.println("  --      ");
    	}
    
    	//     
    	{
    		System.out.println(p_Field);
    		System.out.println("  --    ");
    	}
    
    	//    
    	public Parent() {
    		System.out.println("  --   ");
    	}
    }
    
    public class SubClass extends Parent {
    	//     
    	public static String s_StaticField = "  --    ";
    	//   
    	public String s_Field = "  --  ";
    	//       
    	static {
    		System.out.println(s_StaticField);
    		System.out.println("  --      ");
    	}
    	//     
    	{
    		System.out.println(s_Field);
    		System.out.println("  --    ");
    	}
    
    	//    
    	public SubClass() {
    		System.out.println("  --   ");
    	}
    
    	//     
    	public static void main(String[] args) {
    		new SubClass();
    	}
    }
    

    上のコードを実行すると、すぐに目の前に表示されます.
  • 親--静的変数
  • 親--静的初期化ブロック
  • サブクラス--静的変数
  • サブクラス--静的初期化ブロック
  • 親--変数
  • 親--初期化ブロック
  • 親--コンストラクタ
  • サブクラス--変数
  • サブクラス--初期化ブロック
  • サブクラス--コンストラクタ
  • ここで、結果は自明である.親が完全に初期化されてから子クラスの初期化を行うわけではないことに気づくかもしれないが、実際には子クラスの静的変数と静的初期化ブロックの初期化は、親クラスの変数、初期化ブロック、コンストラクタの初期化前に完了する.静的変数と静的初期化ブロックの間で、変数と初期化ブロックの前後順はどうでしょうか.静的変数は常に静的初期化ブロックより先に、変数は常に初期化ブロックより先に初期化されているのではないでしょうか.実際には、クラスに現れる前後順に依存します.静的変数と静的初期化ブロックを例に説明します.同様に、クラスを書いてテストします.
  • public   class  TestOrder {  
  •     // せいてきへんすう  
  •     public   static  TestA a =  new  TestA();  
  •       
  •     // スタティツクイニシャルブロック  
  •     static  {  
  •         System.out.println(「静的初期化ブロック」);  
  •     }  
  •       
  •     // せいてきへんすう  
  •     public   static  TestB b =  new  TestB();  
  •   
  •     public   static   void  main(String[] args) {  
  •         new  TestOrder();  
  •     }  
  • }  
  •   
  • class  TestA {  
  •     public  TestA() {  
  •         System.out.println("Test--A");  
  •     }  
  • }  
  •   
  • class  TestB {  
  •     public  TestB() {  
  •         System.out.println("Test--B");  
  •     }  
  • }  
  • public class TestOrder {
    	//     
    	public static TestA a = new TestA();
    	
    	//       
    	static {
    		System.out.println("      ");
    	}
    	
    	//     
    	public static TestB b = new TestB();
    
    	public static void main(String[] args) {
    		new TestOrder();
    	}
    }
    
    class TestA {
    	public TestA() {
    		System.out.println("Test--A");
    	}
    }
    
    class TestB {
    	public TestB() {
    		System.out.println("Test--B");
    	}
    }
    

    上記のコードを実行すると、次の結果が得られます.
  • Test--A
  • 静的初期化ブロック
  • Test--B

  • 変数a、変数b、および静的初期化ブロックの前後位置を任意に変更すると、出力結果がクラスに現れる前後の順序に従って変化することがわかります.これは、静的変数と静的初期化ブロックがクラスで定義された順序に従って初期化されていることを示しています.同様に、変数と初期化ブロックもこの法則に従っています.継承の場合、クラスが理解されますの初期化順になってから、最終出力結果をどう判断するかが解決します.