2

この質問はしばらくの間私を悩ませてきました、そして私は良い答えを見つけられませんでした(「それがまさにそれである」以外)。

私が話していることを示すために、いくつかのバックグラウンドコードを与えましょう。

class Note {
    private final String name = "Note";

    public Note() {
        System.out.println(name);
    }
    // ...
}

class Todo extends Note {
    private final String name = "Todo";

    public Todo() {
        System.out.println(name);
    }
    // ...
}

// ...
Note note = new Todo(); // case 1
Todo todo = new Todo(); // case 2

では、どうしてケース1とケース2の両方が印刷されるのでしょうか。

Note
Todo

(コンストラクター)は(少なくとも目に見えて)Todo()呼び出しないので、これは意味がありません。super()サブクラスが親のデフォルトコンストラクターを呼び出さなければならないのはなぜですか?コンストラクターを実装するためにサブクラスを必要としないのはなぜですか?

これに関連するいくつかの質問を読みましたが、理由は誰も答えていません。

編集:
私の例はちょっと貧弱だったと思いますが、実際にはJava 7認定の質問から派生したものです。回答の集合から、理由がわかりました。より良い例を提供しましょう:

public Note {
    private String description;

    public Note() {
        description = "I'm a Note";
    }

    public Note( String description ) {
        this.description = description;
    }

    // getters/setters/etc.
}

public Todo extends Note {
    // field vars..

    public Todo() {
        // empty constructor
    }

    // getters/setters/etc..
}

Todoが作成されたときsuper()に、カバーの後ろに挿入されていない場合、のNoteアスペクトは初期化されないため、これはより理にかなってTodoいます。その場合、サブクラスを持つことは無意味です。皆さんありがとう!

4

8 に答える 8

7

サブクラスのコンストラクターは、何らかのコンストラクターを呼び出す必要があります。どちらを使用するかを指定していない場合、デフォルトのコンストラクターが使用されます。

別の方法は、スーパークラスの変数を完全に初期化せずに、サブクラスやそのメソッドからアクセスできるようにすることです。これは非常に悪いことです。

ただし、たとえばコンパイルに失敗するのではなく、デフォルトのスーパークラスコンストラクターをサイレントに呼び出すという決定には議論の余地がありますが、そもそも「デフォルトコンストラクター」の存在に関係しているのではないかと思います。

参考までに、あなたの質問は、継承について混乱している可能性があることも示唆しています。とフィールドは完全に分離されNote.nameています。サブクラスのフィールドをオーバーライドすることはできません。メソッドのみです。Todo.name

于 2012-12-19T22:03:59.803 に答える
3

質問は 2 つの部分に分けることができます。

  1. スーパークラスのコンストラクターを呼び出す必要があるのはなぜですか? これは簡単です: コンストラクターはオブジェクトの状態を設定する責任があり、サブクラス コード (つまりフィールド) からは見えない状態がスーパークラスに存在する可能性があるためprivate、これはスーパークラスのコンストラクターを呼び出すことによってのみ処理できます。 .
  2. super()明示的に呼び出す必要がないのはなぜですか?これは、コードをよりシンプルに見せるために Java で行われたかなり恣意的な設計上の決定です。これは a の概念 (つまり、明示的なコンストラクターが定義されていないクラスに存在する暗黙の引数なしコンストラクター) とうまく結びついていdefault constructorますが、あなたの例でわかるように、no-スーパークラスで明示的に定義された arg コンストラクター。
于 2012-12-19T22:04:50.747 に答える
1

あなたの例では、親のコンストラクターはオブジェクトに対して何もしません。

通常、コンストラクターは、フィールドを設定することによってオブジェクトの構築を行います。これらのフィールドはそのクラスのコンストラクターに認識されており、別のクラスでは設定またはアクセスできない可能性があり、すべてのサブクラス (既に親クラスにある) ですべてのコードを複製したくないでしょう。親フィールドが正しく設定されています。

したがって、各クラスが認識しているフィールドを初期化し、正しく動作するためにサブクラスの動作にあまり依存しないことは理にかなっています。これにより、サブクラスを変更せずに 1 つのクラスを変更できます。たとえば、フィールドの追加または変更。

于 2012-12-19T22:41:55.683 に答える
1

スーパークラス コンストラクターを明示的に呼び出す必要はありません。また、サブクラスのコンストラクターで super() または super(arguments) を呼び出す必要はありません。これを指定しない場合、コンパイラは引数のないスーパークラス コンストラクターへの呼び出しを自動的に追加します。

スーパークラスに引数なしのコンストラクターがない場合は、各サブクラスのコンストラクターで明示的に super(arguments) を呼び出す必要があります。

于 2012-12-19T22:04:59.347 に答える
1

両方のケースが Note と Todo を出力する理由は、演算子 new always を使用して class のインスタンスを作成するためですTodo。あなたが書いた場合

Note note = new Note();
Note todo = new Todo(); 

次に、結果は次のようになります。

Note
Note
Todo

その動作の原因はポリモーフィズムです。

コンストラクターが自分自身を作成するためにスーパー コンストラクターを呼び出さなければならない理由は、簡単に想像できます。そのスーパークラスの要素を使用するため、そのクラスを最初に作成する必要があるため、それを継承するクラスはそれを操作できます。

于 2012-12-19T22:07:48.320 に答える
0

その通りです!:)

オブジェクト指向プログラミングのパラダイムでコードを書く主な理由は、既存のコードを再利用することなので、私にはすべてが理にかなっています。

再利用できる方法はたくさんありますが、そのうちの 1 つはクラスを継承することです (つまり、サブクラスを作成します)。

クラスを継承すると、そのクラスの作成方法も継承されます。

私の意見では、そのような動作が存在しない場合、Java ははるかに混乱する言語になるでしょう。

于 2012-12-19T23:15:10.123 に答える
0

実際、そうです。super()呼び出しは、記述しなくても自動的に追加されます。Todo のコンストラクターの最初の命令です。

これを自分でテストするには、パラメーターを指定して新しい Note コンストラクターを作成し、空のコンストラクターを削除します。今何が起こるか見てください:)

なぜこれが起こるのですか?簡単です。これが実装方法だからです。

于 2012-12-19T22:06:22.477 に答える
0

ドキュメントはそれをすべて言います:

コンストラクターがスーパークラス コンストラクターを明示的に呼び出さない場合、Java コンパイラーはスーパークラスの引数なしコンストラクターへの呼び出しを自動的に挿入します。スーパー クラスに引数のないコンストラクタがない場合は、コンパイル エラーが発生します。Object にはそのようなコンストラクターがあるため、Object が唯一のスーパークラスであれば問題はありません。

于 2012-12-19T22:07:43.187 に答える