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


9
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)、なぜデフォルトのコンストラクタを使用できないのですか?

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


7
それはないだろうデフォルトもうコンストラクタ。常に存在するので、私は定数コンストラクターになります。
Reactgular

回答:


6

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

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

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

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

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


39

引数を持つコンストラクターは、セッターを使用するための便利な省略形ではありません。特定のデータが存在しないとオブジェクトが決して存在しないことを保証するために、コンストラクタを記述します。

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


4
よく言って、パラメーター付きのコンストラクターを作成すると、クラスインスタンスが機能するためにそれらの値が必要になるからです。いくつかの有用なデフォルトがある場合は、それらのデフォルトを提供しながら、他のコンストラクターを呼び出す引数なしのコンストラクターを作成します。
2014年

+1。さらに、フィールドがコンストラクターで初期化されることを保証できない場合は、不変のオブジェクトを持つことはできません。
Doval

2
@Doval:特定の状況で、どちらを使用するか。他のすべてと同様に、不変オブジェクトにはトレードオフがあります。特効薬はありません。
whatsisname 2014年

1
@whatsisname決して特効薬とは呼ばれていませんが、デフォルトの方が適しています。
Doval

この回答は、Konrad Morawskiによる優れた回答と併せて読むと非常に役立ちます。彼の回答は、基本的に同じ回答を説明するための素晴らしい実例です。
cellepo 2018年

8

他に何もないときにパラメーターなしのコンストラクターを生成する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つのことを行います-それはオブジェクトを作成します(または試して死ぬ)。

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


この回答は、Kilian Fothによる同じく良い回答と併せて読むと非常に役立ちます。私はウェイター/コートの説明/アナロジーの創造性が大好きです。
cellepo 2018年

3

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

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


3

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

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

Employee(){
  // good practice to call existing constructor with your favorite value
  this("");
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.