web-dev-qa-db-ja.com

.classがクラスの静的ブロックを呼び出さないのはなぜですか?

これは私が持っているコードです:

public class StupidClass {
    static {
        System.out.println("Stupid class loaded!");
    }
}

そして、私が実行するテストを個別に実行します

import org.junit.Test;

public class StupidTest {
    @Test
    public void foo() throws ClassNotFoundException {
        final Class<?> stupidClass = Class.forName("StupidClass");
        System.out.println(stupidClass.getSimpleName());
    }

    @Test
    public void bar() throws ClassNotFoundException {
        final Class<StupidClass> stupidClassClass = StupidClass.class;
        System.out.println(stupidClassClass.getSimpleName());
    }
}

テストfooを実行すると、次のようになります。

Stupid class loaded!
StupidClass

しかし、テストbarを実行すると、次のように表示されます。

StupidClass

this ページからの引用。

クラスオブジェクトは、クラスがロードされるときにJava Virtual Machineによって、およびクラスローダーのdefineClassメソッドを呼び出すことによって、自動的に構築されます。

だから私の理解は、テストバーで、愚かなクラスがロードされていることです、そうでなければ私は私が推測するnullを見たでしょうか?クラス自体が読み込まれるため、Classオブジェクトが作成されます。

そして this ページから引用します

静的初期化ブロックは、JVM(クラスローダー-具体的には)がStaticClassをロードするときに実行されます(これは、コードで初めて参照されるときに発生します)。

そのため、「愚かなクラスがロードされました!」テストバーのテキストも同様ですが、私はそうではありません。

Javaで考える からも引用

Candy、Gum、およびCookieの各クラスには、クラスが初めてロードされるときに実行される静的句があります。

あまり正確ではないようです。

何が欠けていますか?

68
Koray Tugay

静的初期化ブロックは、JVM(クラスローダー-具体的には)がStaticClassをロードするときに実行されます(これは、コードで初めて参照されるときに発生します)。

上記の引用は明らかに間違っていますが、それは非常に広範囲にわたる誤解の一例にすぎません。

  1. クラスは、ロード時に初期化されませんが、静的クラスmemberが最初に参照されます。これは 指定 によって正確に管理されます。

  2. クラスのロードは、クラスが最初に参照されるときは発生しませんが、実装に依存するポイントで発生します。

  3. クラスをロードする必要がある最後の瞬間は、クラスが参照されるときです。これは、クラスの参照と同じではありません =)メンバー

Class.forNameはデフォルトでクラスを初期化しますが、boolean initializeを受け取り、falseを提供するオーバーロードを呼び出すこともできます。初期化せずにクラスをロードします。

59
Marko Topolnik

クラスのロードと初期化は2つの異なるものです。クラスはロードできますが、本当に必要になるまで初期化できません。静的イニシャライザは、クラスが初期化されているときにのみ実行されます<>ロードされない、「初期化された」

最初のケースでは、class.forName()を使用するときにクラスをロードして初期化しているため、静的初期化子が実行され、出力として"Stupid class loaded!"が表示されます。 2番目のケースでは、クラスの参照を割り当てるだけですクラスが読み込まれます(Java -verbose:classを使用して、読み込まれているクラスを確認します)。実際に初期化しているわけではありません(正確には、イニシャライザを強制的に実行するようなことは何もしていません)。したがって、出力がStupid class loaded!として表示されません。newInstance()クラスでは、クラスの初期化を強制する必要があり、Stupid class loaded!が表示されます。

私のコード:

public class CheckPalindrome {

    public static void main(String[] args) {
        Class<Test> t = Test.class;
    }

}
// class being loaded
class Test {
    static {
        System.out.println("aaa");
    }
}

ロードされるクラス

...
[Loaded Test from file:/Workspaces/SampleTest/Java8/bin/]
...

^-これは、クラスがロードされているが初期化されていないことを示しています。

22
TheLostMind