コンストラクタを使用してオブジェクト配列のディープコピーを作成したいのですが。
public class PositionList {
private Position[] data = new Position[0];
public PositionList(PositionList other, boolean deepCopy) {
if (deepCopy){
size=other.getSize();
data=new Position[other.data.length];
for (int i=0;i<data.length;i++){
data[i]=other.data[i];
}
しかし、私が上記の理由で何らかの理由で機能していません。私が実行した自動テストと、それらのテストに失敗しました。だから、ここにエラーがあります。
あなたが実装したのはshallowコピーです。 deepコピーを実装するには、変更する必要があります
data[i] = other.data[i];
other.data[i]
の__copyをdata[i]
に割り当てるものに。これを行う方法は、Position
クラスによって異なります。可能な選択肢は次のとおりです。
コピーコンストラクタ:
data[i] = new Position(other.data[i]);
ファクトリーメソッド:
data[i] = createPosition(other.data[i]);
クローン:
data[i] = (Position) other.data[i].clone();
ノート:
clone
アプローチは、Position
が明示的にサポートしている場合にのみ機能し、これは一般に劣ったソリューションと見なされます。さらに、clone
のネイティブ実装(つまり、Object.clone()
メソッド)は浅いコピーを行うことに注意する必要があります。実際、Javaにディープコピーを実装することの一般的な問題は複雑です。Position
クラスの場合、属性はすべてプリミティブ型(たとえば、intまたはしたがって、参照コピーがある場合は、コピーコンストラクター/ファクトリーメソッド/クローンメソッドを使用して、必要な種類のコピーを実行する必要があります。また、一般的なケース(サイクルを処理する必要がある場合)は難しく、各クラスに特別なメソッドを実装する必要があります。
オブジェクトの配列をコピーするには、他に潜在的な方法が1つあります。配列内のオブジェクトがserializableである場合、ObjectOutputStream
およびObjectInputStream
serializeを使用してオブジェクトをコピーし、配列を逆シリアル化できます。しかしながら:
transient
フィールドの値はコピーされません。シリアル化によるコピーは推奨されません。クローニングや他の方法をサポートする方が良いでしょう。
全体として、Javaではディープコピーを回避するのが最善です。
最後に、Position
クラスのコピーコンストラクターが機能することについての質問に答えるには、次のようになると思います。
public class Position {
private int x;
private int y;
...
public Position(Position other) {
this.x = other.x;
this.y = other.y;
}
...
}
@Turtleが言うように、魔法は関与していません。既存のインスタンスからコピーして状態を初期化するコンストラクターを(手動で)実装します。
あなたが言う時:
data[i]=other.data[i];
参照のリストをコピーしているだけです(これがオブジェクトの配列であると想定しています)。詳細コピーを作成する場合は、new
を使用して、配列内の各オブジェクトの新しいインスタンスを作成する必要があります。
言う代わりに:
data[i]=other.data[i]
Position
のコピーコンストラクター(つまり、別のPosition
を取り込んでその内部のプリミティブデータをコピーするPositionのコンストラクター)を作成し、data[i]=new Position(other.data[i]);
と言います。
基本的に「ディープコピー」コンストラクターPositionList
はコピーコンストラクターですが、コピーコンストラクターはディープコピーを示す傾向があるため、deepCopy
パラメーターは不要です。
これが私が使用する関数です:
function copy(arr) {
return arr
.map(x => Object
.keys(x)
.reduce((acc, y) => {
acc[y] = x[y]
return acc
}, {}))
}
単一レベルのオブジェクトを持つ配列でのみ機能します。