ProgrammingJava開発者

Javaにおけるシャローコピーとディープコピーの違いを説明してください。それらはどのように実装され、どのような場合に使用する必要がありますか?

Hintsage AIアシスタントで面接を突破

答え

シャローコピーは新しいオブジェクトを作成しますが、ネストされたオブジェクトの参照をコピーするだけで、それ自体をコピーしません。ディープコピーは新しいオブジェクトを作成し、元のオブジェクトにネストされたすべてのオブジェクトを再帰的にコピーします。そのため、コピーと元のオブジェクトの間には共通の参照がありません。

使用するタイミング:

  • シャローコピーは、オブジェクトの構造に変更可能なネストされたオブジェクトが含まれていない場合、またはネストされたオブジェクトを変更する必要がない場合に十分です。
  • ディープコピーは、ネストされたオブジェクトの変更可能性が重要であり、コピーに対する変更が元のオブジェクトに反映されるべきでない場合に必要です。

実装例:

// ネストされたオブジェクトを持つクラスの例 class Address { String city; Address(String city) { this.city = city; } } class Person implements Cloneable { String name; Address address; Person(String name, Address address) { this.name = name; this.address = address; } // シャローコピー public Person clone() throws CloneNotSupportedException { return (Person) super.clone(); } // ディープコピー public Person deepClone() { return new Person(this.name, new Address(this.address.city)); } }

ひっかけ質問

clone()メソッドを使用してディープコピーを実装できますか?

答え: いいえ、標準のObject.clone()メソッドは「シャローコピー」しか実装していません。ディープコピーを取得するには、すべてのネストされたフィールドを手動でクローンするか、外部ライブラリ(例えばApache Commons Lang)を使用する必要があります。

例:

@Override public Person clone() throws CloneNotSupportedException { Person cloned = (Person) super.clone(); cloned.address = new Address(this.address.city); // 手動でディープコピー return cloned; }

逸話

大規模なCRMプロジェクトで、super.clone()を通じてオブジェクトのコピーを実装した後、開発者はコピーが完全に独立していると期待していましたが、コピーしたユーザーの住所を変更すると、元の住所も変更されてしまいました。バグはリリース後に発覚し、顧客データベースに混乱を引き起こしました。


逸話

シリアル化/デシリアル化のためにディープコピーの標準メカニズムSerializableを選択しましたが、ネストされたオブジェクトのフィールドの一つをSerializableとして宣言するのを忘れたため、実行中にエラー(NotSerializableException)が発生し、バックアップ時にデータの損失が生じました。


逸話

あるマイクロサービスで、DTOをコピーするためにBeanUtils.copyPropertiesライブラリを使用していましたが、このメカニズムがシャローコピーしか実装していないことに気づきませんでした。その後のリファクタリングで、ネストされたコレクションの変更がデータベースから取得した元のデータに影響を与え、多くの不明瞭なバグが発生しました。