2

次のコードがヒープ (OutOfMemoryError など) に相当するスタック オーバーフローを引き起こさない理由がわかりません。静的初期化は、このようなものに対するガードを提供し、代わりに NullPointerException をスローしますか?

編集:私は理解されたとは思わない: public static void main(String[] args)から静的メソッドを呼び出しますStaticClass。このメソッドdoSmth()を呼び出す前に、StaticClass最初にロードする必要があります。クラスがロードされると、すべての静的コードが実行されます。StaticClassクラスでは、は a の値に属性付けされobjClassた静的フィールドであるため、(をスローする)new ObjClass()べきではありません。これを行うには をロードする必要があり、これは がロードされているときにすでに発生しているため、明らかにインスタンス化できません(したがって、無限再帰との類推、またはおそらくデッドロックの類推)。問題は、JVM が、ある種の繰り返し呼び出しのために初期化できなかったと言うのではなく、null であると言うことです。nullNullPointerExceptionnew ObjClass()StaticClassStaticClassobjClassnew ObjClass()

通常、呼び出し元が原因で NullPointerException がスローされます。ただし、この場合、呼び出し先のみを変更できます (ObjClassコンストラクターで、最後にコメントのある行を削除します) NullPointerException

package pack;

public class ObjClass
{
    public ObjClass() {
        StaticClass.doSmth();//if removed, no NullPointerException
    }

    public String getSomething() {
        return "get";
    }

    public static void main(String[] args) {
        StaticClass.loadStaticClass();
    }
}

class StaticClass {
    private static ObjClass objClass = new ObjClass();

    static void loadStaticClass() {
    }

    static void doSmth()             {
        System.out.println(objClass.getSomething());
    }
}

与える:

Exception in thread "main" java.lang.ExceptionInInitializerError
    at pack.ObjClass.main(ObjClass.java:28)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Caused by: java.lang.NullPointerException
    at pack.ObjClass$StaticClass.doSmth(ObjClass.java:39)
    at pack.ObjClass.<init>(ObjClass.java:20)
    at pack.ObjClass$StaticClass.<clinit>(ObjClass.java:34)
    ... 6 more
4

3 に答える 3

4

あなたがどれほど決心していても、この問題には複雑な答えがなければなりません。それは非常に簡単です。値を逆参照したため、NullPointerExceptionが発生しnullます。これ以上何もない。

public class Main {
    public static void main(String... args) {
        new A();
    }

    static class A {
        static {
            System.out.println("Start of class A initialisation, A.b is " + A.b);
        }

        static final B b = new B();

        static void method(String from) {
            System.out.println("Called a method in A from " + from + ", A.b is " + A.b);
            B.method();
        }

        static {
            System.out.println("End of class A initialisation, A.b is " + A.b);
        }
    }

    static class B {
        static {
            System.out.println("Start of class B initialisation, A.b is " + A.b);

            A.method("B static block");

            System.out.println("End of class B initialisation, A.b is " + A.b);
        }

        B() {
            A.method("B() constructor");
            System.out.println("Only after this should A.b be set.");
        }

        static void method() {
            System.out.println("Called a method in B, A.b is " + A.b);
        }
    }
}

プリント

Start of class A initialisation, A.b is null
Start of class B initialisation, A.b is null
Called a method in A from B static block, A.b is null
Called a method in B, A.b is null
End of class B initialisation, A.b is null
Called a method in A from B() constructor, A.b is null
Called a method in B, A.b is null
Only after this should A.b be set.
End of class A initialisation, A.b is Main$B@33b7b32c

ご覧のとおり、あるクラスは初期化が完了する前に別のクラスを呼び出すことができ、初期化される前の参照を調べることができnullますfinal


objClassまだ設定されていないため、NullPointerExceptionがスローされます。

コンストラクターから戻るまで設定されませんが、コンストラクター内にいるため、デフォルト値は。になりnullます。

ところで、これはhttp://en.wiktionary.org/wiki/infinite_recursionのようなものではありません

次のコードがヒープ(OutOfMemoryErrorなど)と同等のスタックオーバーフローを引き起こしていない理由がわかりません

これらはすべて、特定の意味を持つさまざまなエラーです。参照が初期化されずに使用された場合にスローされるエラーは、NullPointerExceptionです。

静的初期化はこのようなものに対するガードを提供し、代わりにNullPointerExceptionをスローしますか?

これが発生するために、フィールドは静的である必要はありません。初期化される前に非静的フィールドにアクセスした場合も、同じことが起こります。

StaticClassがロードされるときにobjClassをインスタンス化する必要がありますか?

ロードされていません。実際、完了する前に例外をスローするため、ロードされることはありません。この後、このクラスを使用しようとすると、クラスのロードに失敗したため、NoClassDefErrorが発生します。

于 2012-12-18T15:23:57.157 に答える
4

を呼び出すコンストラクターを呼び出すStaticClassインスタンス化を参照します。これは referenceを使用しますが、参照するには完全に構築された が必要なため、まだ割り当てられていませんobjClassObjClassdoSmth()objClassobjClass

簡単に言えば、

this.x = doMethod();

参照が結果に割り当てられるdoMethod()前に完了する必要があります。x

あなたは何をしようとしているのですか ?それともこれはある種の運動ですか?

于 2012-12-18T15:24:26.860 に答える
1
  private static ObjClass objClass = new ObjClass();

クラスローディングjvmがのインスタンスを作成しようとしている間ObjClass、参照は呼び出された時間コンストラクターによってobjClassポイントされます(インスタンスの作成はまだ行われていません)。\nullObjClass

あなたは電話をかけようとしています、あなたは原因となっている参照をobjClass.getSomething()呼び出しgetSomething()ています。nullNullPointerException

于 2012-12-18T15:23:25.673 に答える