web-dev-qa-db-ja.com

JavaにC ++のような初期化リストがないのはなぜですか?

C++では、コンストラクターが実行を開始する前に、初期化リストを使用してクラスのフィールドを初期化できます。例えば:

Foo::Foo(string s, double d, int n) : name(s), weight(d), age(n) {
    // Empty; already handled!
}

Javaに同様の機能がないのはなぜですか?Core Java:Volume 1によると:

C++は、この特別な構文を使用してフィールドコンストラクターを呼び出します。 Javaでは、オブジェクトにはサブオブジェクトがなく、他のオブジェクトへのポインタのみがあるため、その必要はありません。

ここに私の質問があります:

  1. 「オブジェクトにはサブオブジェクトがないため」とはどういう意味ですか?サブオブジェクトが何であるかわかりません(調べてみました)。それらは、スーパークラスを拡張するサブクラスのインスタンス化を意味しますか?

  2. JavaにC++のような初期化リストがない理由は、Javaですべてのフィールドがデフォルトですでに初期化されているためであり、 Javaはsuperキーワードを使用して、super(またはC++の用語ではbase)クラスのコンストラクターを呼び出します。これは正しいですか?

54
Jesse Good

C++では、Javaに存在しないか、Javaでは動作が異なるいくつかの言語機能があるため、初期化リストが必要です。

  1. const:C++では、constとマークされているフィールドを定義できます。このフィールドは、割り当てることができず、初期化リストで初期化する必要があります。 Javaにはfinalフィールドがありますが、コンストラクターの本体のfinalフィールドに割り当てることができます。C++では、コンストラクターのconstフィールドへの割り当ては無効です。

  2. 参照:C++では、参照(ポインターではなく)を初期化して、オブジェクトにバインドする必要があります。初期化子なしで参照を作成することは違法です。 C++では、これを指定する方法は初期化子リストを使用します。初期化せずにコンストラクターの本体で参照を参照すると、初期化されていない参照が使用されるためです。 Javaでは、オブジェクト参照はC++ポインターのように動作し、作成後に割り当てることができます。それ以外の場合、デフォルトはnullです。

  3. 直接サブオブジェクト。 C++では、オブジェクトにオブジェクトをフィールドとして直接含めることができますが、Javaオブジェクトでは、これらのオブジェクトへの参照のみを保持できます)つまり、C++では、stringをメンバーとして持つオブジェクトを宣言すると、その文字列の格納領域は、オブジェクト自体の領域に直接組み込まれますが、Java you他の場所に格納されている他のStringオブジェクトへの参照用のスペースを取得するだけです。したがって、C++では、これらのサブオブジェクトに初期値を与える方法を提供する必要があります。 、ただし、別のコンストラクタを使用する場合、またはデフォルトのコンストラクタが使用できない場合、イニシャライザリストはこれを回避する方法を提供します。Javaでは、参照がデフォルトでnullになるため、このことを心配する必要はありません。次に、実際に参照させたいオブジェクトを参照するように割り当てます。デフォルト以外のコンストラクターの場合、特別な構文は必要ありません。適切なコンストラクタを介して初期化された新しいオブジェクトへの参照を設定するだけです。

Javaがイニシャライザリストを必要とする場合があります(たとえば、スーパークラスコンストラクタを呼び出す、またはフィールドにデフォルト値を与える)場合、これは他の2つの言語機能を通じて処理されます:呼び出すsuperキーワードスーパークラスコンストラクター、およびJavaオブジェクトはフィールドが宣言された時点でフィールドにデフォルト値を与えることができるという事実。C++には複数の継承があるため、単一のsuperキーワードがあるだけで一義的になることはありません。単一の基本クラスを参照し、C++ 11以前はC++はクラスのデフォルトの初期化子をサポートしておらず、初期化子リストに依存する必要がありました。

お役に立てれば!

97
templatetypedef

C++

違いがあります

ClassType t(initialization arguments);

そして

ClassType * pt;

後者は初期化する必要はありません(NULLに設定)。前者はします。整数と考えてください。値なしでintを作成することはできません[〜#〜] but [〜#〜]値なしでintポインターを作成できます。

だからあなたが持っているとき:

class ClassType
{
    OtherClass value;
    OtherClass * reference;
};

次に宣言:

ClassType object;

OtherClassvalueのインスタンスを自動的に作成します。したがって、OtherClassに初期化がある場合は、ClassTypeコンストラクターで初期化する必要があります。ただし、referenceは単なるポインタ(メモリ内のアドレス)であり、初期化されていないままにすることができます。 OtherClassのインスタンスが必要な場合は、

object.reference = new OtherClass(initialization arguments);

Java

しかありません

class ClassType
{
    OtherClass reference;
}

これは、C++のポインターに相当します。この場合、次のことを行います。

ClassType object = new ClassType();

OtherClassのインスタンスは自動的には作成されません。したがって、必要がない限り、コンストラクターで何も初期化する必要はありません。 OtherClassのオブジェクトが必要な場合は、

object.reference = new OtherClass();
9
George

なぜなら、Javaは、型にゼロ値がないフィールドの初期化を許可する必要がないからです。

C++では

_class C {
  D d;
}
_

dのメンバー初期化子がない場合、D::D()が呼び出され、Dのゼロ型がない場合にフィールドを初期化できなくなります。これは、D::D()privateとして明示的に宣言されている場合に発生する可能性があります。

Javaでは、すべての参照型に対して既知の ゼロ値 が存在するため、nullがあるため、フィールドを常に初期化できます。

Javaはまた、すべてのfinalフィールドが最初に使用される前とコンストラクターが終了する前に初期化されるようにする一連の作業を行います。したがって、JavaにはC++のconstフィールド初期化要件のような要件がありますが、_this.fieldName = <expression>_コンストラクター本体でフィールドの初期化を意味します。

  • :ctorでスローされたモジュロ例外、基本クラスからのオーバーライドされたメソッド呼び出しなど.
1
Mike Samuel