7

オブジェクトのインスタンス化の代わりにクローンを使用しているように見える古い Java コード ベース (jvm 1.4) を維持しています。パフォーマンスの最適化として推測しています。これは不自然な例です:

public class Foo {
  private SomeObject obj; // SomeObject implements Cloneable
  public Foo() {
    obj = new SomeObject();
    obj.setField1("abc"); // these fields will have the same value every time
    obj.setField2("def");
  }
  public void doStuff() {
    SomeObject newObj = obj.clone(); // clone it instead of using a factory method
    // do stuff with newObj
  }
}

時期尚早の最適化に関する通常の警告にもかかわらず、これは実際にある時点で推奨されるイディオムでしたか?

4

5 に答える 5

4

おそらく彼らはコピーが欲しかったのでしょう。おそらく、彼らはそれを別の関数に渡したいと思っており、その関数がそれを変更しないかどうか確信が持てません。これは、メソッド doStuff() が呼び出された Foo オブジェクトの状態に関して const であることを確認する方法です。

于 2009-03-19T17:10:09.307 に答える
3

コピー コンストラクターまたはファクトリ メソッドの代わりに呼び出す理由の 1 つclone()は、他のオプションを使用できない可能性があるためです。

浅いオブジェクト コピーを実行するための実装clone()(ディープ コピーはより複雑です) は、同じ操作を実行するためのコピー コンストラクターまたはファクトリ メソッドの実装に比べて簡単です。を実装するclone()には、クラスは単純にインターフェイスを実装し、通常はを呼び出すものでCloneableメソッドをオーバーライドする必要があります。 元のオブジェクトのすべてのプロパティを複製の対応するプロパティにコピーし、浅いコピーを作成します。clone()super.clone()Object.clone()Object.clone()

実装clone()は簡単ですが、それでも実装を忘れがちCloneableです。したがって、 を使用してオブジェクトを複製する潜在的なリスクはclone()、そのオブジェクトのクラスが実装Cloneableを怠り、直接的または間接的にclone()呼び出すと、 がスローされることです。Object.clone()CloneNotSupportedException

このコード例と、インターフェースの設計が不十分であるという以前の議論を参照してください。Cloneable

于 2009-11-11T19:03:20.520 に答える
2

コピー コンストラクターの主な問題の 1 つは、コンパイル時にオブジェクトの型を認識しなければならないことです。継承可能なクラスがコピー コンストラクターをサポートし、コンストラクターに派生クラス オブジェクトが渡された場合、コンストラクターは、基本クラスのプロパティが渡されたオブジェクトのプロパティと通常一致する基本クラス オブジェクトを生成しますが、新しいオブジェクトは作成されません。渡されたオブジェクトに存在し、基本クラスには存在しなかった機能はサポートされません。

この問題は、コピー コンストラクターを「保護」し、そのクラス独自のコピー コンストラクターを呼び出すオーバーライド可能なファクトリ コピー メソッドをすべての派生クラスに配置することで、ある程度解決することができます。ただし、新しいフィールドを追加するかどうかにかかわらず、すべての派生クラスにはコピー コンストラクターとコピー メソッドのオーバーライドが必要です。ケース クラスが「クローン」を使用する場合、この余分なコードを削除できます。

于 2011-03-09T18:21:32.390 に答える
1

コンストラクターで実行される作業の量によっては、パフォーマンスの最適化になる場合があります。

セマンティクスが異なるため、使用される可能性が高くなります。クローン作成は、通常はそのようにならない言語で「プロトタイプ セマンティクス」(javascript、self など) を実装する方法を提供します。

于 2009-03-19T17:10:46.013 に答える
0

SomeObject コンストラクターが、データベースから何かを取得したり、何かを解析したり、ファイルから何かを読み取ったりするなど、コストのかかる作業を行う場合、クローンはその作業を避けるのが理にかなっています。

コンストラクターが何もしない場合、クローンを使用する必要はありません。

編集:クローンがコンストラクターと同じ作業を行う必要がないことを示すコードを追加しました:

class Main
    implements Cloneable
{
    private final double pi;

    public Main()
    {
        System.out.println("in Main");
        // compute pi to 1,000,000,000 decimal palaces
        pi = 3.14f;
    }

    public Object clone()
    {
        try
        {
            return (super.clone());
        }
        catch(final CloneNotSupportedException ex)
        {
            throw new Error(); // would not throw this in real code
        }
    }


    public String toString()
    {
        return (Double.toString(pi));
    }

    public static void main(String[] args)
    {
        final Main a;
        final Main b;

        a = new Main();
        b = (Main)a.clone();

        System.out.println("a = " + a);
        System.out.println("b = " + b);
    }
}

Main コンストラクターは 1 回呼び出され、計算 pi は 1 回実行されます。

于 2009-03-19T17:27:58.763 に答える