JAvaクラスのロードタイミングとオブジェクトnewの順序に関する問題のまとめ

3674 ワード

一、どのような場合にクラスを初期化しなければなりませんか?
1.new,getstatic,putstatic,invokestaticの4バイト命令に遭遇した場合、クラスが初期化されていない場合は、その初期化をトリガーする必要があります.この4つのバイト命令の一般的なシーン:newインスタンス化オブジェクトを使用して、dinal修飾された場合、コンパイラが結果を定数プールに入れた静的フィールドを除く静的フィールドを読み取りまたは設定し、クラスの静的メソッドを呼び出します.シーンは基本的に上のバイト命令に対応します.
2.javaを使用する.lang.reflectパケットのメソッドがクラスを反射呼び出した場合、このクラスが初期化されていなければ初期化
3.クラスを初期化するとき、その親が初期化されていないことに気づいたら、まずその親を初期化し、親の初期化は同じです.
4.仮想マシンが起動すると、ユーザーは実行するメインクラス(main関数を含むクラス)を指定して初期化する必要があります.
5.jdk 1を用いる場合.7の動的言語がサポートされている場合java.lang.invoke.MethodHandleインスタンスの最終結果のEREF_getstatic, EREF_putstatic, EREF_invokestaticのメソッドハンドルで、対応するクラスが初期化されていない場合は初期化します.
この2でクラスの初期化シーンがトリガーされ、1つのクラスへのアクティブな参照となります.それ以外は、すべての参照クラスのメソッドがクラスの初期化をトリガーしません.
 
いくつかの受動引用例:
1.親の静的フィールドを参照し、子の初期化は行われません.
public class ClassA {
    public static String a="sa";
    static {
        System.out.println("sA");
    }
}

public class ClassB extends ClassA {
    public static String b="sb";
    static {
        System.out.println("sB");
    }
}
//   
public class TestAB {
    public static void main(String[] args){
        System.out.println(ClassB.a);
    }
}

最終出力結果は、サブクラスオブジェクトが初期化されていないことがわかります.
sA sa
2.static変数修飾final定数を参照すると、コンパイルされたアキュムレータに定数が既に定数プールに追加されているため、サブクラスと親クラスの初期化はトリガーされません.
コードを参照:
public class ClassA {
    public static String a="sa";
    static {
        System.out.println("sA");
    }
}

public class ClassB extends ClassA {
    public static String final b="sb";
    static {
        System.out.println("sB");
    }
}
//   
public class TestAB {
    public static void main(String[] args){
        System.out.println(ClassB.b);
    }
}

出力結果:sb
4.しかしfinalに修飾された定数はすべてこのような結果ではないでしょうか.答えはもちろんNo!、この定数はコンパイル期間定数でなければなりませんが、次の例がありますか?
public class ClassA {
    public static String a="sa";
    static {
        System.out.println("sA");
    }
}

public class ClassB extends ClassA {
    public static String final b= new String("sb");
    static {
        System.out.println("sB");
    }
}
//   
public class TestAB {
    public static void main(String[] args){
        System.out.println(ClassB.b);
    }
}

出力結果:
sA
sB
sb
このように、まずClassBを初期化したとき、親が初期化されていないことに気づき、まず父を初期化し、息子を再初期化しました.
3.配列定義でクラスを参照し、クラスの初期化はトリガーされません
public class ClassA {
    public static String a="sa";
    static {
        System.out.println("sA");
    }
}

public class ClassB extends ClassA {
    public static String b="sb";
    static {
        System.out.println("sB");
    }
}
//   
public class TestAB {
    public static void main(String[] args){
        // System.out.println(ClassB.b);
        ClassB[] classBS = new ClassB[100];
    }
}

出力結果が空で、ClassAを設定してもClassBは初期化されていないと思います!
 
次に、いくつかの関連する問題を見ます.
タイトル1:
public class Main {

    public static void main(String[] args) {
        System.out.println("A");
        new Main();
        new Main();
    }

    public Main() {
        System.out.println("B");
    }

    {
        System.out.println("C");
    }

    static {
        System.out.println("D");
    }
}

以上のプログラム出力の結果、正しいのは?
答え:
DACBCB
解析:
  • mainが存在するクラスが最初に初期化して静的ブロックコードを実行する:D
  • main関数出力:A
  • は、Mainクラスが初期化されているため、Mainクラスをインスタンス化する.静的コードブロックは、クラスの初期化時に1回実行されることを目的としています.同時に構築コードブロックは構築関数より優先的に実行される:CB
  • 同上出力:CB
  •  
    参考文献:
    周志明Java仮想マシン[M].機械工業出版社、2013.