ここまで「コピーの基本」と「浅い/深いコピー」を理解したので、さらに一歩進んだ 応用編 を紹介します。実際のプログラムで遭遇する「コピーの落とし穴」や「便利な使い方」を題材にしますね。
コピーの基本の応用編
1. 配列の結合(マージ)
- 状況: 2つの配列をまとめて1つにしたい。
- 例:
int[] a = {1, 2, 3};
int[] b = {4, 5, 6};
int[] merged = new int[a.length + b.length];
System.arraycopy(a, 0, merged, 0, a.length);
System.arraycopy(b, 0, merged, a.length, b.length);
System.out.println(Arrays.toString(merged)); // [1, 2, 3, 4, 5, 6]
Java👉 コピーを使えば「配列の結合」が簡単にできる。
2. コピーしてバックアップを作る
- 状況: 元の配列を残しておきたいとき。
- 例:
int[] data = {10, 20, 30};
int[] backup = Arrays.copyOf(data, data.length);
data[0] = 999;
System.out.println(Arrays.toString(data)); // [999, 20, 30]
System.out.println(Arrays.toString(backup)); // [10, 20, 30]
Java👉 コピーを「スナップショット」として使うと、変更前の状態を保持できる。
3. 多次元配列のコピー
- 状況: 2次元配列をコピーしたいとき。
- 例:
int[][] matrix = {{1, 2}, {3, 4}};
int[][] copy = new int[matrix.length][];
for (int i = 0; i < matrix.length; i++) {
copy[i] = Arrays.copyOf(matrix[i], matrix[i].length);
}
copy[0][0] = 99;
System.out.println(Arrays.deepToString(matrix)); // [[1, 2], [3, 4]]
System.out.println(Arrays.deepToString(copy)); // [[99, 2], [3, 4]]
Java👉 外側だけコピーすると「内側の配列」が共有されてしまうので、ループで内側もコピーする必要がある。
浅い/深いコピーの応用編
1. 複合オブジェクトのコピー
- 状況:
Studentクラスがnameとscores(配列)を持つ場合。 - 浅いコピー:
scoresが共有される。 - 深いコピー:
scoresも新しくコピーする。
class Student {
String name;
int[] scores;
Student(String name, int[] scores) {
this.name = name;
this.scores = scores;
}
}
Student[] src = {
new Student("Alice", new int[]{90, 80}),
new Student("Bob", new int[]{70, 60})
};
// 深いコピー
Student[] deep = new Student[src.length];
for (int i = 0; i < src.length; i++) {
deep[i] = new Student(src[i].name, Arrays.copyOf(src[i].scores, src[i].scores.length));
}
deep[0].scores[0] = 100;
System.out.println(Arrays.toString(src[0].scores)); // [90, 80]
System.out.println(Arrays.toString(deep[0].scores)); // [100, 80]
Java👉 「浅いコピー」だと scores が共有されてしまう。「深いコピー」なら完全に独立。
2. コピーを使った Undo 機能
- 状況: ゲームやエディタで「元に戻す」機能を作りたい。
- 方法: 配列の状態をコピーして履歴として保存しておく。
int[] state = {1, 2, 3};
List<int[]> history = new ArrayList<>();
// 状態を保存
history.add(Arrays.copyOf(state, state.length));
state[0] = 99; // 変更
// Undo(履歴から復元)
state = Arrays.copyOf(history.get(0), state.length);
System.out.println(Arrays.toString(state)); // [1, 2, 3]
Java👉 コピーを「履歴」として使うことで、Undo機能が作れる。
✅ まとめ
- コピーの基本応用: 結合・バックアップ・多次元配列コピー
- 浅い/深いコピー応用: 複合オブジェクトの安全なコピー、Undo機能の実装
- ポイント: 「浅いコピーは参照を共有」「深いコピーは中身も新しく作る」
💡 提案: さらに実践的にするなら「ゲームのキャラクター配列」「図書館の本リスト」などを題材にしてコピーを使うと面白いです。
