ここに興味深いJava質問があります。
次の簡単なJavaプログラムには、メソッドによって静的に初期化された静的フィールドが含まれています。実際には、初期化値を計算するメソッドにNullPointExceptionを発生させます。そのような静的フィールドにアクセスすると、NoClassDefFoundErrorがVM扱うクラスは完全ではないようです。
しかし、私がクラスにアクセスするとき、それはまだ利用可能です。
誰かが理由を知っていますか?
class TestClass {
public static TestClass instance = init();
public static TestClass init() {
String a = null;
a.charAt(0); //force a null point exception;
return new TestClass();
}
}
class MainClass {
static public void main(String[] args) {
accessStatic(); // a ExceptionInInitializerError raised cause by NullPointer
accessStatic(); //now a NoClassDefFoundError occurs;
// But the class of TestClass is still available; why?
System.out.println("TestClass.class=" + TestClass.class);
}
static void accessStatic() {
TestClass a;
try {
a = TestClass.instance;
} catch(Throwable e) {
e.printStackTrace();
}
}
}
このような質問への答えは通常、仕様のどこかに埋め込まれています... (§12.4.2)
クラスが初期化されるとどうなるか:
手順1〜4は、この質問とは多少関係ありません。ここでのステップ5は、例外をトリガーするものです。
5
。 Classオブジェクトが誤った状態にある場合、初期化はできません。 Classオブジェクトのロックを解除し、NoClassDefFoundErrorをスローします。
6-8は初期化を続行し、8は初期化子を実行し、通常はステップ9で発生します。
9
。イニシャライザの実行が正常に完了したら、このClassオブジェクトをロックし、完全に初期化したラベルを付け、待機中のすべてのスレッドに通知し、ロックを解放して、この手順を正常に完了します。
しかし、イニシャライザでエラーが発生しました。
10
。 それ以外の場合、イニシャライザはいくつかの例外Eをスローすることによって突然完了している必要があります。EのクラスがErrorまたはそのサブクラスの1つでない場合、Eを引数として、クラスExceptionInInitializerErrorの新しいインスタンスを作成します。次の手順で、このオブジェクトをEの代わりに使用します。ただし、OutOfMemoryErrorが発生したためにExceptionInInitializerErrorの新しいインスタンスを作成できない場合は、代わりに次の手順でEの代わりにOutOfMemoryErrorオブジェクトを使用します。
はい、ヌルポインター例外のExceptionInInitializerError
b/cが表示されます。
11
。 Classオブジェクトをロックし、誤ったラベルを付けます。待機中のすべてのスレッドに通知し、ロックを解除して、理由Eまたはその置換で決定されたように、この手順を突然完了します。前のステップ。 (いくつかの初期の実装の欠陥のため、ここで説明されているようにExceptionInInitializerErrorを引き起こすのではなく、クラスの初期化中の例外が無視されました。)
そして、クラスにエラーのマークが付けられたため、2回目に手順5で例外が発生します。
意外なのは、
TestClass.class
inMainClass
は実際には物理的なClass
オブジェクトへの参照を保持しています。
おそらくTestClass
がまだ存在しているため、エラーとしてマークされています。すでにロードされ、検証されています。
はい、それが通常NoClassDefFoundError
が発生する理由です。 evillyという名前です。それだけです。 「class init failed exception」などの名前が付けられているはずです。
Javaこのエラーが発生したプログラマは、クラスが見つからない理由を理解しようとして何百年も無駄に費やしました。
この例外が発生した場合は、ログを上方に確認し、クラスの初期化に失敗した根本的な原因を見つけてください。
このような静的フィールドにアクセスすると、NoClassDefFoundErrorが発生します。 VMクラスの扱いは完全ではないようです。
それは正しいです ...
しかし、私がクラスにアクセスするとき、それはまだ利用可能です
はい。
次の理由により、クラスローダーは壊れたクラスを削除しようとしませんでした。
この不整合が目に見える状態になるには、アプリケーションがClassDefNotFoundError
(またはスーパークラス)をキャッチし、そこからの回復を試みる必要があります。 Error
例外は通常回復できないということは、十分に文書化された事実です。つまり、回復しようとすると、JVMが一貫性のない状態になる可能性があります。これがここで起こったことです...ロード/初期化されていたクラスに関して。
制限されています
8.3.2.2of http://psc.informatik.uni-jena.de/languages/Java/javaspec-3.pdf