次の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;
}
}
コードはコンパイルされず、コンパイラは上記で強調した行について文句を言います。なぜこのエラーが発生し、最善の回避策は何ですか?
コードが最初にコンパイルされない理由は、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が最初にクラスをロードするときに作成されます。クラスを使用してインスタンスを作成するときにクラスは既にロードされているため、静的変数はすぐに使用でき、コンストラクターを含むクラスで使用できます。
参照:
defaultValue
がTest
の構築中のインスタンス(まだ作成されていない)のメンバーであるためです
static
があれば、クラスローダーによってクラスがロードされたときにロードされました
ルール:すべてのコンストラクターは、自分自身を実行する前にスーパークラスのコンストラクターを実行する必要があります。
したがって、すべてのコンストラクターの最初の行はsuper()またはthis()であり、defaultValueをこのクラスコンストラクターに送信します。このコンストラクターはまだ存在していないため、コンパイル時エラーが発生します。
DefaultValueを静的として作成できます。クラスがメモリにロードされると静的変数が作成されるため、this(defaultValue)行でdefaultValueを使用できます。
まだ存在しないである変数を参照している場合静的であるため、存在しますコンストラクター自体の前でも
しかし、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;
}
}
オブジェクトが構築されるまで、変数のデフォルト値は設定されません。したがって、構築時にデフォルト値を設定する場合は、static
にするか、明示的に設定してください。
コンストラクタはオブジェクトの作成時に呼び出されるため、変数への参照はコンパイラによって認識されません。コンパイラはオブジェクトがまだ作成されていないため、インスタンス変数に関する知識がありません。
オブジェクトの作成中、フィールド初期化命令はコンストラクターの前に実行されるため、実際にはこれは正解ではありません。オブジェクト作成プロセスをデバッグして、自分で確認できます。私自身もこの問題について混乱しています。例えば、少し変更すると最初のコンストラクタは次のようになります。
public Test(int i) {
this(i, 0);
}
public Test (int a, int k) {
}
これは機能します。したがって、最初の/ nullコンストラクターが別のコンストラクターを呼び出すと、明示的にsuper()を呼び出しても、奇妙な理由で機能しません。前。
最も関連する説明は、JVMがメモリ内で宣言をロードするが、完全に実行される前にNO CONSTRUCTOR IS INSTANCE VARIABLE/FIELD)に到達できないことということです。