web-dev-qa-db-ja.com

コンストラクター内から同じクラスのコンストラクターへの複数の呼び出しが機能しないのはなぜですか?

次のスニペットをご覧ください:

public class Foo {
int digit;
String name;

Foo (int d, String n) {
    this(d);
    // cannot do following.
    //compile-time error: Constructor call must be first statement in a Constructor 
    //this(n);
}

Foo (int p) {
    digit = p;
}

Foo (String q) {
    name = q;
}

この制限の理由は何でしょうか?コンストラクターへの呼び出し(コンストラクター内またはメソッド内の両方)が最初のステートメントでなければならない理由を理解しています。オブジェクトを使用する前に、オブジェクトを適切に初期化する必要があります。私が取得できないのは、コンパイラーがコンストラクター内から同じクラスの複数のコンストラクターを呼び出すことを許可していないことです。初期化と不変量の両方に関して、この構造に問題はありません。

誰かが私がここで欠けているものにいくつかの光を当てることができれば素晴らしいでしょう...

ありがとう!

5
Chaitanya

コンストラクターは、「オブジェクトの作成時に呼び出されるメソッド」だけでなく、概念的にも異なります。

コンストラクターの目的は、オブジェクトの状態を最初に制限することです。新しく作成されたオブジェクトはすべてのフィールドでゼロになり(null/0/false)、プログラムでは無効な状態である可能性があります。たとえば、アプリケーションのCustomerオブジェクトは常にcustomerId> 0になるように制約する必要があります。次に、そのIDを取得してチェックするコンストラクターを定義します。

この観点では、2つのコンストラクターを呼び出す目的はありません。最初のコンストラクターを呼び出した後、オブジェクトは既に一貫した状態にあります。 2番目のコンストラクターは、目的の違反である初期化されたオブジェクトを受け取ります(0 =>初期化済み)。

この場合、初期化の一部を実行してそれらを呼び出すプライベートメソッドを導入するか、より一般的なパターン(より一般的なパターン)をより具体的なコンストラクターに呼び出します。

Foo (int d, String n) {
    digit = d;
    name = n;
}

Foo (int p) {
    this(p, null)
}

Foo (String q) {
    this(0, q)
}
8
Fixpoint

その理由は、Java言語仕様にそのように記載されているためです。おそらく、記述した内容を許可するように作成されているかもしれませんが、無料ではありません。順序を強制することで物事が簡単になります。継承とsuper()。コンストラクターの最初のステートメントにならない場合、サブクラスは、まだ作成されていないスーパークラスで何かを実行できます。ユビキタスな場合、どの時点でthisが存在しますかスーパークラスObjectはまだ構築されていないでしょうか?

任意のコンストラクター呼び出し順序を許可することはあまり役に立ちませんでしたが、言語仕様とコンパイラーを複雑にしました(おそらく、私はそう思います)。

4
Joonas Pulakka