8

私は最近 Java を読んでいて、何か (イディオム?) に新しいものに出くわしました: プログラムでは、複数のコンストラクターを持つクラスには、常に空のコンストラクターも含まれます。例えば:

public class Genotype {
  private boolean bits[];
  private int rating;
  private int length;
  private Random random;

  public Genotype() {              //  <= THIS is the bandit, this one right here
    random = new Random();
  }

  /* creates a Random genetoype */
  public Genotype(int length, Random r) {
    random = r;
    this.length = length;
    bits = new boolean[length];

    for(int i=0;i<length;i++) {
        bits[i] =random.nextBoolean();
    }
  }

  /* copy constructor */
  public Genotype(Genotype g,Random r) {
    random = r;
    bits = new boolean[g.length];
    rating = g.rating;
    length = g.length;

    for(int i=0;i<length;i++) {
        bits[i] = g.bits[i];
    }

  }
}

最初のコンストラクターは「実際の」コンストラクターではないようです。どの場合でも、他のコンストラクターのいずれかが使用されるようです。では、なぜそのコンストラクターがまったく定義されているのでしょうか。

4

10 に答える 10

10

あなたが読んでいたコードが高品質であったかどうかはわかりません (私は過去にいくつかのバイオインフォマティクス コードをレビューしましたが、残念ながらプロの開発者によって書かれたものではないことがよくあります)。たとえば、その 3 番目のコンストラクターはコピー コンストラクターではなく、通常、このコードには問題があるため、「読みすぎ」ません。

最初のコンストラクターはデフォルトのコンストラクターです。最低限のものだけを初期化し、残りはユーザーが getter と setter で設定できるようにします。他のコンストラクターは、多くの場合、より少ない呼び出しでオブジェクトを作成するのに役立つ「便利なコンストラクター」です。ただし、これは多くの場合、コンストラクター間の不一致につながる可能性があります。実際、セッターへの後続の呼び出しを伴うデフォルトのコンストラクターが望ましいことを示す最近の調査があります。

デフォルトのコンストラクターが重要な場合もあります。たとえば、digester (XML から直接オブジェクトを作成するために使用される) などの特定のフレームワークは、既定のコンストラクターを使用します。一般に、JavaBeans はデフォルトのコンストラクターなどを使用します。

また、一部のクラスは他のクラスから継承されます。親オブジェクトの初期化が「十分」である場合、デフォルトのコンストラクターが表示される場合があります。

この特定のケースでは、そのコンストラクターが定義されていない場合、すべての詳細を事前に知っておく必要があります。それは常に好ましいとは限りません。

最後に、一部の IDE は自動的にデフォルトのコンストラクターを生成します。クラスを作成した人がそれを削除することを恐れている可能性があります。

于 2008-12-31T08:19:33.580 に答える
5

オブジェクトはシリアライズ可能ですか?

シリアル化できないクラスのサブタイプをシリアル化できるようにするために、サブタイプは、スーパータイプの public フィールド、protected フィールド、および (アクセス可能な場合) package フィールドの状態を保存および復元する責任を負う場合があります。サブタイプは、それが拡張するクラスに、クラスの状態を初期化するためのアクセス可能な引数なしのコンストラクターがある場合にのみ、この責任を負うことができます。そうでない場合、Serializable クラスを宣言するとエラーになります。エラーは実行時に検出されます。

逆シリアル化中に、シリアル化できないクラスのフィールドは、クラスのパブリックまたは保護された引数なしのコンストラクターを使用して初期化されます。引数なしのコンストラクターは、シリアル化可能なサブクラスにアクセスできる必要があります。シリアライズ可能なサブクラスのフィールドはストリームから復元されます

于 2008-12-31T08:39:26.660 に答える
3

はい、「空の」コンストラクターが常に存在するとは限らないことに同意します(私の経験では、初心者はこの間違いを犯すことがよくあります)が、空のコンストラクターで十分な場合もあります。ただし、空白のコンストラクターが、構築後にすべてのメンバーが適切にインスタンス化されるという不変条件に違反する場合は、空白のコンストラクターを使用しないでください。コンストラクターが複雑な場合は、構成をいくつかのプロテクト/プライベート メソッドに分割することをお勧めします。次に、必要に応じて、静的メソッドまたは別のFactoryクラスを使用して、保護されたメソッドを呼び出して構築します。

上に書いたのは理想的なシナリオです。ただし、Spring のようなフレームワークでは、コンストラクター ロジックがコードから削除され、いくつかの xml 構成ファイルに含まれます。ゲッター関数とセッター関数を使用することもできますが、ここで説明されているように、おそらくインターフェイスから回避される可能性があります。

于 2008-12-31T08:20:27.010 に答える
2

デフォルトのコンストラクターは必須ではありません。

クラスでコンストラクターが定義されていない場合、デフォルト (空の) コンストラクターが自動的に作成されます。パラメーター化されたコンストラクターを提供した場合、デフォルトのコンストラクターは自動的に作成されないため、自分で作成することをお勧めします。実行時に依存性注入と動的プロキシ作成を使用するフレームワークには、通常、既定のコンストラクターが必要です。したがって、作成するクラスのユースケースに依存します。

于 2008-12-31T08:29:15.357 に答える
0

デフォルトのコンストラクターは、機能ビューには適していません。オブジェクトがメソッドに対してグローバルな可視性を持っている場合、デフォルトのコンストラクターが使用されます。たとえば、コード化できる try/catch でオブジェクトの実際の状態をログに記録したい場合

MyObejct myObject=null
try{...
}catch(Exception e){
    log.error(myObject);//maybe print null. information?
}

それとも好きですか

MyObejct myObject=new Object();
try{...
}catch(Exception e){
log.error(myObject);//sure print  myobject.toString, never null. More information
}

?

別の方法として、EMPTY オブジェクトの作成には多くのロジックはありませんが、NULL オブジェクトのインスタンス化は私の意見では有害です。この投稿を読むことができます

于 2008-12-31T10:47:37.447 に答える
0

それはコピーコンストラクターではありません。基本的に、フレームワークを操作するときは、空のコンストラクターが必要です。もちろん、パブリックまたはプライベートの空のコンストラクターが常に存在する必要がありますが、少なくとも、クラスがインスタンス化されている (またはインスタンス化されていない) 方法を制御できます。

于 2008-12-31T10:55:35.903 に答える
0

デフォルトの空の (空白の) コンストラクターを使用すると、final フィールドを使用できなくなります。これは、しばしば必要とされない多くの可変性につながります。

ビルダー パターンを使用すると、これら 2 つのスタイルを混在させて、より柔軟な初期化を可能にすると同時に、多引数のコンストラクターをファクトリの背後に隠すことで不変性を維持できます。

于 2009-06-23T16:30:04.400 に答える
0

一部の POJO クラスまたは単純なクラスでは、デフォルト コンストラクターは、それらを使用するクラスで単体テストを実行する場合に役立ちます。それらをモックする必要はありません。デフォルトのコンストラクターでオブジェクトを新規作成し、値セットをテストしてそれらから取得するか、引数として渡すことができます。

于 2016-10-07T01:26:40.493 に答える
0

私は通常、オブジェクトを完全に初期化する 1 つのコンストラクターを作成します。他にある場合、それらはすべて適切なデフォルトで this(...) を呼び出します。

オブジェクトは、作成時に 100% 初期化され、使用できる状態になっている必要があります。

Hibernate などの一部のフレームワークは、引数なしのコンストラクターを必要とします。それらがベストプラクティスと衝突する方法は、時々私を不安にさせます。

于 2008-12-31T13:51:10.557 に答える