2

私はこの問題に遭遇しました。一言で言えば、同じクラスの2つのオブジェクトをインスタンス化します。一方のオブジェクトでメソッドを実行すると、もう一方のオブジェクトも、2番目のオブジェクトでメソッドを明示的に呼び出したかのように影響を受けます。誰かが私にこれを手に入れてくれないかと思っていました。

仮に、クラスがありPortfolioます...

public class Portfolio implements Cloneable {

public ArrayList<Instrument> portfolio;
private String name;
private String description;

public Portfolio() {
    portfolio = new ArrayList<Instrument>();
}

public Portfolio(Portfolio copyFrom) {
    //attempt to copy the object by value
    this.portfolio = (ArrayList<Instrument>) copyFrom.portfolio.clone();
    this.name = copyFrom.name;
    this.description = copyFrom.description;
}

public void applyStress(Stress stress) {
    this.portfolio.set(0,this.portfolio.get(0)+1;
}

1番目のコンストラクターは、オブジェクトなどをインスタンス化するために使用されます。2番目のコンストラクターは、オブジェクトを値でコピーするために使用されます。

メソッドapplyStressは、合計計算を実行するために使用されます。この例では、メソッドを簡略化して、オブジェクト内にあるものに+1を追加するだけです。

したがって、オブジェクトを次のようにインスタンス化します

Portfolio p = new Portfolio();

portfolioそれから私はフィールド、いくつかの楽器に割り当てます。

p.portfolio = someInstrumentList;

次に、値で次のようにコピーしportfolio pますpCopy

Portfolio pCopy = new Portfolio(p);

したがって、現時点では、同じオブジェクトが2つあります。もう1つは、値によるコピーオブジェクトです。のフィールドの値を変更しても、のpCopy同じフィールドには影響しませんp

ここで、でメソッドを実行するapplyStressp、の機器リストの値pCopyも変更されます。

言い換えれば、もしp.portfolio.get(0) == 1、その後、私はそれがであるとp.applyStress見ることを期待しますp.portfolio.get(0)2pCopy.portfolio.get(0)1

しかし、代わりに私が見ているのp.portfolio.get(0)2pCopy.portfolio.get(0)2

なぜこれが起こるのかわかりません。静的修飾子がないため、static修飾子の問題ではありません。誰かアイデアはありますか?

4

2 に答える 2

3

ArrayList 参照に適用されるcloneメソッドは、深いコピーではなく、浅いコピーを実行します。これは、元のコレクションにあるものはすべて、複製されたコレクションによって共有されることを意味します。

つまり、すべてのインストゥルメントのクローンを作成するか、すべてのインストゥルメントにコピーコンストラクターを提供する必要があります。

this.portfolio = new ArrayList<Instrument>();
for(Instrument toBeCopiedInstrument : copyFrom.portfolio){
   this.portfolio.add(new Instrument(toBeCopiedInstrument ));
}
于 2012-05-30T00:18:02.883 に答える
1

デフォルト.clone()では、 a と呼ばれるものを実行します。これは、 a に保持されているオブジェクトにshallow copya をコピーするだけで、オブジェクト自体を新しいインスタンスに実際にコピーするわけではありません。referenceListcloned

あなたがする必要があるのは、リストに保持されている各アイテムのカスタムdeep copyを実装することです。Listしかしdeep clone、Java での壊れた概念と実装です。

ほとんどのcopy constructor場合、参照もコピーすることになり、コンストラクターに注入するすべてのオブジェクトは、同じコピー コンストラクターのセマンティクスに従う必要があるため、Java でもあまり良いパターンではありません。C++ とは異なり、これは手作業で、退屈で、メンテナンスが不可能で、エラーが発生しやすいプロセスです。

.clone()そしてimplements Cloneable、Java で正しい概念を得るには最も複雑なものの 1 つです。適切に設計されたアプリケーションではほとんど必要ありません。つまり、使用し.clone()ている場合は、おそらく間違っています。オブジェクトのビットごとのコピーを作成することがストレージ以外の設計の一部である場合は、設計を再検討することをお勧めします。

Josh Bloch によるデザイン

オブジェクトの clone メソッドは非常にトリッキーです。これはフィールド コピーに基づいており、「言語外」です。コンストラクターを呼び出さずにオブジェクトを作成します。コンストラクターによって確立された不変条件が保持されるという保証はありません。Sun の内外で長年にわたって多くのバグがありました。これは、オブジェクトのクローンを作成するまでチェーンの中で super.clone を繰り返し呼び出すと、オブジェクトの浅いコピーが作成されるという事実に起因しています。クローンは通常、クローンされるオブジェクトと状態を共有します。その状態が変更可能な場合、2 つの独立したオブジェクトはありません。一方を変更すると、他方も変更されます。そして突然、ランダムな動作になります。

不変

より良いパターンは、すべてを不変にすることです。そうすれば、個別のインスタンスは必要ありません。変更が必要になるまでインスタンスを共有できます。変更が必要になると、新しいデータを含む新しいインスタンスが作成され、副作用なしで共有できます。

于 2012-05-30T02:01:47.943 に答える