【完全理解】Javaのシャローコピーとディープコピー|仕組みと実装方法を徹底解説

Java

1. はじめに

Java を勉強していると必ず出てくるキーワードの一つが 「コピー」 です。
コピーといっても、単に代入することと、新しいオブジェクトを生成して同じ内容を持たせることはまったく意味が違います。

さらにコピーには シャローコピー(浅いコピー)ディープコピー(深いコピー) があり、この違いを正しく理解していないと、バグや予期しない挙動の原因になります。

本記事では以下を徹底的に解説します。

  • Java におけるコピーの基本
  • シャローコピーとディープコピーの違い
  • 実際のコード例で挙動を確認
  • よくある罠と注意点
  • 実務に役立つ設計パターンとベストプラクティス

「コピー」という一見シンプルなテーマですが、ここを理解しているかどうかで、コードの安全性と拡張性に大きな差が出ます。

Java を学んでいる方はまず 絶対にJavaプログラマーになりたい人へ。 を読み、さらに転職やソースレビューを受けたい方は サイゼントアカデミー を利用すると良いでしょう。


2. コピーの基本

Javaの変数は参照である

Java のオブジェクト型変数は 参照(reference) を保持しています。
たとえば以下のコードを見てみましょう。

ここで p1p2同じオブジェクト を指しているため、p2 を変更すると p1 にも影響します。

コピーとは、このような「参照共有」ではなく、別のオブジェクトを新しく作ること を指します。


3. シャローコピー(浅いコピー)とは

定義

シャローコピーは、オブジェクトを複製するが、その中の参照フィールドは「参照をコピーするだけ」で、中身のオブジェクト自体は複製しない方法です。

特徴

  • プリミティブ型フィールドは値をコピーする
  • 参照型フィールドは同じオブジェクトを共有する
  • コピー元とコピー先が一部のデータを共有してしまう

コード例

この例では、p1p2 は別インスタンスですが、内部の Address は同じ参照を共有しているため、片方を変更するともう片方にも影響します。


4. ディープコピー(深いコピー)とは

定義

ディープコピーは、オブジェクトをコピーするだけでなく、内部にある参照型フィールドも再帰的にコピーして新しいオブジェクトを生成する方法です。

特徴

  • コピー元とコピー先は完全に独立する
  • 片方を変更してももう片方に影響しない
  • 実装の手間は増える

コード例

この場合、p1p2 は完全に独立しています。


5. シャローコピー vs ディープコピー比較表

項目シャローコピーディープコピー
プリミティブ型値をコピー値をコピー
参照型参照を共有新しいオブジェクトを生成
独立性部分的に共有完全に独立
実装コスト低い高い
パフォーマンス高速遅い
利用シーン不変オブジェクトを含む場合変更が独立であるべき場合

6. よくある罠と注意点

  1. Cloneable と clone() の制約
    • Cloneable を実装しないと clone() は例外を投げる
    • デフォルトではシャローコピー
  2. immutable オブジェクトは安全
    • StringInteger は共有しても問題なし
  3. 循環参照の問題
    • A が B を持ち、B が A を持つような構造をディープコピーすると無限ループに注意
  4. シリアライズを使ったコピー
    • シリアライズ&デシリアライズでディープコピー可能
    • ただしパフォーマンスと制約に注意

7. 実践例:リストを持つクラスのコピー

実行して挙動を比較すると、シャローコピーではページリストが共有され、ディープコピーでは独立します。


8. ベストプラクティスと設計パターン

  • コピーコンストラクタを用意
  • deepClone() メソッドを別に作る
  • 不変クラス設計でコピー自体を不要にする
  • Apache Commons Lang などのライブラリを活用
  • コピー仕様をコメントや設計書に明記する

9. まとめ

  • シャローコピー:参照を共有するコピー(速いが危険)
  • ディープコピー:完全に独立するコピー(安全だが重い)
  • 使い分けは状況次第。immutable が多い場合はシャローで十分、mutable が多い場合はディープコピーを検討。

まずは 絶対にJavaプログラマーになりたい人へ。 を読み、さらに実務スキルや転職を目指すなら サイゼントアカデミー を活用してください。

コメント

タイトルとURLをコピーしました