web-dev-qa-db-ja.com

スーパータイプコンストラクターが呼び出される前に「X」を参照できません。xは最終変数です

次のJavaクラス宣言を検討してください。

public class Test {

    private final int defaultValue = 10;
    private int var;

    public Test() {
        this(defaultValue);    // <-- Compiler error: cannot reference defaultValue before supertype constructor has been called.
    }

    public Test(int i) {
        var = i;
    }
}

コードはコンパイルされず、コンパイラは上記で強調した行について文句を言います。なぜこのエラーが発生し、最善の回避策は何ですか?

67
Amr Bekhit

コードが最初にコンパイルされない理由は、defaultValueがクラスTestインスタンス変数であるためです。タイプTestのオブジェクトが作成されると、defaultValueの一意のインスタンスも作成され、その特定のオブジェクトにアタッチされます。このため、コンストラクターでもオブジェクトもまだ作成されていないため、コンストラクターでdefaultValueを参照することはできません。

解決策は、最終変数staticを作成することです。

public class Test {

    private static final int defaultValue = 10;
    private int var;

    public Test() {
        this(defaultValue);
    }

    public Test(int i) {
        var = i;
    }
}

変数staticを作成すると、そのクラスのインスタンスではなくクラス自体に関連付けられ、Testのすべてのインスタンス間で共有されます。静的変数は、JVMが最初にクラスをロードするときに作成されます。クラスを使用してインスタンスを作成するときにクラスは既にロードされているため、静的変数はすぐに使用でき、コンストラクターを含むクラスで使用できます。

参照:

90
Amr Bekhit

defaultValueTestの構築中のインスタンス(まだ作成されていない)のメンバーであるためです

staticがあれば、クラスローダーによってクラスがロードされたときにロードされました

8
Jigar Joshi

ルール:すべてのコンストラクターは、自分自身を実行する前にスーパークラスのコンストラクターを実行する必要があります。

したがって、すべてのコンストラクターの最初の行はsuper()またはthis()であり、defaultValueをこのクラスコンストラクターに送信します。このコンストラクターはまだ存在していないため、コンパイル時エラーが発生します。

DefaultValueを静的として作成できます。クラスがメモリにロードされると静的変数が作成されるため、this(defaultValue)行でdefaultValueを使用できます。

4
Himanshu Mohta

まだ存在しないである変数を参照している場合静的であるため、存在しますコンストラクター自体の前でも

しかし、defaultValueが静的になったため、別の問題に直面することになります。そのため、他のすべてのインスタンスは同じ値を共有する可能性がありますが、

public class Test {

    private final int defaultValue = 10; //this will be exists only after calling the contractor
    private final static int vakue2= 10; //this is exists before the contractor has been called
    private int var;

    public Test() {
       // this(defaultValue);    // this metod will not work as defaultValue doesn't exists yet
    this(value2); //this will work
    //this(10); will work
    }

    public Test(int i) {
        var = i;
    }
}
4
Sherif Eldeeb

オブジェクトが構築されるまで、変数のデフォルト値は設定されません。したがって、構築時にデフォルト値を設定する場合は、staticにするか、明示的に設定してください。

1
amicngh

コンストラクタはオブジェクトの作成時に呼び出されるため、変数への参照はコンパイラによって認識されません。コンパイラはオブジェクトがまだ作成されていないため、インスタンス変数に関する知識がありません。

0
Hardik Mehta

オブジェクトの作成中、フィールド初期化命令はコンストラクターの前に実行されるため、実際にはこれは正解ではありません。オブジェクト作成プロセスをデバッグして、自分で確認できます。私自身もこの問題について混乱しています。例えば、少し変更すると最初のコンストラクタは次のようになります。

public Test(int i) {
   this(i, 0);
}
public Test (int a, int k) {
}

これは機能します。したがって、最初の/ nullコンストラクターが別のコンストラクターを呼び出すと、明示的にsuper()を呼び出しても、奇妙な理由で機能しません。前。

最も関連する説明は、JVMがメモリ内で宣言をロードするが、完全に実行される前にNO CONSTRUCTOR IS INSTANCE VARIABLE/FIELD)に到達できないことということです。

0