web-dev-qa-db-ja.com

明示的なコンストラクターを定義すると、デフォルトのコンストラクターが生成されないのはなぜですか?

_class Employee{

    String name;
    int id;

   //No explicit constructors
}
_

これで、次のステートメントを呼び出すことができます。

_Employee e1 = new Employee();
_

上記のコードを使用すると、コンパイラーはコンストラクターEmployee()の定義を提供します。

次のように単一の明示的なコンストラクタを定義すると、

_ class Employee{

    String name;
    int id;

    Employee(String aName){
        this.name=aName;
    }
}
_

さて、次のステートメントを呼び出せないのはなぜですか。

_Employee e2 = new Employee();
_

コンパイラはEmployee()の定義を提供する方法を知っていますが。

さて、明示的なコンストラクタEmployee(String aName)を定義したからといって、なぜデフォルトのコンストラクタを使用できないのですか?

また、コンパイラーが明示的なコンストラクターを定義した後でもデフォルトのコンストラクターの使用を許可した場合は、デフォルトのコンストラクターのコードを再利用するのに役立ちます。

9
Harish_N

まず、デフォルトのコンストラクターは生成されません。引数なしのコンストラクターが明示的に記述されていない場合、コンパイラーによって提供されます。

クラスの引数なしのコンストラクターを明示的に記述しない場合、パラメーターコンストラクターなしでオブジェクトが構築されている限り、コンパイラーは文句を言わない(コンパイラーは、デフォルトのコンストラクターがオブジェクトを作成できるため、引数なしのコンストラクターを呼び出すことができるため) )。

ただし、引数のないコンストラクターを定義すると、コンパイル時に、コンパイラーはコンストラクターの呼び出しとクラス内のその定義をチェックします。これは、クラスの他のメソッドを認証するのと同じです。

したがって、パラメーター化されたコンストラクターを定義した後で引数なしのコンストラクターを呼び出すと、クラスで明示的に定義された引数なしのコンストラクターが見つからないため、エラーが発生します。また、データが含まれていないオブジェクトの作成をブロックする場合は、これが1つの良い方法であるため、これは論理的に正しいです。

たとえば、従業員オブジェクトに従業員IDが関連付けられている必要があるとします。これを実現するには、単一引数コンストラクターを定義し、引数なしコンストラクターは定義しないでください。

6
Tyson

引数を持つコンストラクターは、セッターを使用するための単なる便利な方法ではありません。特定のデータが存在しなくてもオブジェクトがnever、everになるようにコンストラクターを記述します。

そのような要件がない場合は、問題ありません。ただし、そのようなコンストラクターがある場合は、そのようなコンストラクターを作成したという事実が示すように、デフォルトのコンストラクターを生成するのは無責任です。これにより、クライアントは「データなしのオブジェクトなし」ルールを回避できます。二重にそうなのは、自動生成されたデフォルトコンストラクターがinvisibleであり、カジュアルなコードリーダーからは見えないためです。いいえ、引数のコンストラクタをデフォルトコンストラクタにしたい場合は、デフォルトコンストラクタを自分で作成する必要があります。とにかく、それは空のブロックを書くのに多くの努力があるようではありません。

38
Kilian Foth

他に何もないときにパラメーターなしのコンストラクターを生成するJavaは、礼儀正しいウェイターがあなたのコートをあなたに代わってくれるようなものです。

Javaは、別のバージョンを定義した後もパラメーターなしのコンストラクターを生成しますが、コートをどうするかについて独自の計画を持っていることを明確に示した後、同じウェイターがコートを外すのと同じです。

クラス(不変にしたい)がある場合:

_class Person
{
    final String firstName;
    final String lastName;
_

そして、コンストラクターを追加します。

_    Person(String firstName, String lastName) 
    {
        this.firstName = firstName;
        this.lastName = lastName;
    }
}
_

そしてJavaはデフォルトでパラメータのないコンストラクタを提供することでした。この場合、firstNameおよびlastNameフィールドがfinalとして宣言されているため、このコードはコンパイルできません。 Person p = new Person()を呼び出した後は設定されません。

あなたは私に別の実装を提供することを強いています:

_private Person() 
{
    this.firstName = null; // or "", or whatever
    this.lastName = null;
}
_

そして、私はそれを望んでいない-それは役に立たないので、それに頭蓋骨とクロスボーンを置く傾向があると感じるかもしれません:

_@Deprecated
private Person() 
{
    // don't use this constructor! i don't want it to ever be called!
    throw new RuntimeException("Illegal constructor called");
}
_

しかし、他の開発者がメソッドを作成することを禁止することはできません(Personクラス内にあるため、コンストラクターをプライベートとしてマークしても役に立たなかった)。

_public static Person createPerson()
{
    return new Person(); // this will blow in our face
}
_

Java(およびJavaだけでなく))が機能するように動作するという事実のおかげで、この大騒ぎはすべて可能であり、回避されています。

メソッドsetCoordinates(int x, int y)を定義する場合、コンパイラーがパラメーターなしバージョンのsetCoordinates()を自動的に受け入れることは期待できません。それは何もしません。

これは、パラメーターのないコンストラクターを期待することとどのように異なりますか?まあ、明らかに、コンストラクターは常に少なくとも1つのことを行います-それはオブジェクトを作成します(または試して死ぬ)。

しかし、私はオブジェクトをどのようにインスタンス化するか制御下になりたいです。何をしてもパラメーターなしのコンストラクターを使用するように強制すると、このコントロールが不要になります。

8
Konrad Morawski

この言語では、デフォルトコンストラクターが優先されます。カスタムコンストラクターを作成した場合、引数のないコンストラクターにも特別な注意が必要になる可能性があると想定されます。大きな理由ではありませんが、恐ろしいことでもありません。

Cruftがその言語に山積みになる2番目の理由IDは、既存の慣行との対称性を考慮せず、それを読みやすくすることにほとんど関心がありません。 Stoustroupのオリジナルの "C with Classes"はハックアップされたCプリプロセッサでしたが、おそらくラボから出てはいけません。そのように世界は面白いです。

3
msw

パラメーターを使用してコンストラクターを定義する場合は、そうすることには正当な理由があるはずです。おそらく、このパラメーターはクラスにとって非常に重要なので、それがないとオブジェクトの状態は無効になります。 Javaは、すでに引数を定義していない場合、引数なしのコンストラクタを作成しません。

引数なしのコンストラクタがあると便利だと判断した場合でも、それを定義できます。

Employee(){
  // good practice to call existing constructor with your favorite value
  this("");
}
3
MaxZoom