Arrays.copyOf の「役割」をざっくりつかむ
java.util.Arrays.copyOf は、
「今ある配列をもとに、“新しい配列”を作るためのコピー専用メソッド」
です。
ポイントは次の二つです。
ひとつめは、「元の配列とは別物の配列インスタンス」を作ること。
ふたつめは、「新しい配列の長さを第二引数で自由に決められる」ことです。
つまり、「中身は似ているけど、長さは変えたい」「元の配列はそのまま残したい」ときに、とてもよく使います。
一番基本の使い方:同じ長さで丸ごとコピー
まったく同じ内容の別配列を作る
まずは、元の配列と同じ長さでコピーする一番シンプルな例から見てみましょう。
import java.util.Arrays;
public class CopyOfBasic {
public static void main(String[] args) {
int[] original = {1, 2, 3};
int[] copy = Arrays.copyOf(original, original.length);
System.out.println("original: " + Arrays.toString(original));
System.out.println("copy : " + Arrays.toString(copy));
}
}
Java実行結果のイメージはこうなります。
original: [1, 2, 3]
copy : [1, 2, 3]
Java中身は同じですが、original と copy は別の配列インスタンスです。
片方を書き換えても、もう片方は変わりません。
copy[0] = 100;
System.out.println(Arrays.toString(original)); // [1, 2, 3]
System.out.println(Arrays.toString(copy)); // [100, 2, 3]
Javaこの「元とは別の配列を作れる」というのが、copyOf の一番大事な役割です。
長さを変えながらコピーするのが本領発揮
配列を“伸ばしながら”コピーする(拡張)
第二引数には「新しい配列の長さ」を渡します。
元の配列よりも長い値を指定すると、足りない部分は「型の初期値」で埋められます。
int[] original = {1, 2, 3};
int[] bigger = Arrays.copyOf(original, 5);
System.out.println(Arrays.toString(bigger)); // [1, 2, 3, 0, 0]
Javaint 型の初期値は 0 なので、後ろ二つが 0 で埋まっています。
String[] の場合は、足りない要素は null になります。
String[] names = {"Alice", "Bob"};
String[] bigger = Arrays.copyOf(names, 4);
System.out.println(Arrays.toString(bigger)); // [Alice, Bob, null, null]
Java配列そのものはサイズ変更できないので、「サイズを変えたい」ときはいったん copyOf で大きめの新しい配列を作る、という発想になります。
実務ではサイズ可変の ArrayList を使うことが多いですが、「配列って本当はサイズ変わらないんだよ」という実態を理解するうえで、このパターンはとても役立ちます。
配列を“短くしながら”コピーする(切り捨て)
逆に、新しい長さを小さくすれば、後ろの要素が切り捨てられます。
int[] original = {10, 20, 30, 40, 50};
int[] first3 = Arrays.copyOf(original, 3);
System.out.println(Arrays.toString(first3)); // [10, 20, 30]
Java「先頭から n 件だけ欲しい」「上位 10 件だけにしたい」
といった場面で、ループでコピーするより copyOf のほうが意図が読み取りやすくなります。
コードを読む人にとっても、「ああ、先頭だけ取り出してるんだな」とすぐ分かります。
Arrays.copyOf と System.arraycopy の関係
copyOf は「よくあるパターン専用の便利ラッパー」
配列コピーには、もう一つ System.arraycopy という低レベル API があります。
System.arraycopy(src, srcPos, dest, destPos, length);
Javaこれは「どの配列の、どの位置から、どの配列の、どの位置へ、何個コピーするか」を細かく指定できる反面、
書き間違えやすく、コードも読みにくくなりがちです。
Arrays.copyOf は、その中でも一番よくある
「元配列の先頭から、新しい配列に丸ごとコピーしたい」
「ついでに新しい配列の長さも決めたい」
というパターンだけを、シンプルに書けるようにしたメソッドです。
初心者のうちは、次のように考えておけば十分です。
配列をそのまま新しくしたいとか、長さを変えて新しい配列を作りたい → Arrays.copyOf
元配列の一部だけ、細かい位置を指定して別配列にコピーしたい → System.arraycopy
まずは copyOf に慣れてから、必要になったら arraycopy を知るくらいでいいです。
ソートや加工をするときの「安全コピー」としての使い道
元の配列を壊さずにソートしたいとき
Arrays.sort は「元の配列をその場で並べ替える」メソッドです。
元の順番も残しておきたいとき、copyOf が出番になります。
import java.util.Arrays;
public class SortWithCopy {
public static void main(String[] args) {
int[] original = {5, 2, 9, 1, 3};
int[] sorted = Arrays.copyOf(original, original.length);
Arrays.sort(sorted);
System.out.println("original: " + Arrays.toString(original)); // [5, 2, 9, 1, 3]
System.out.println("sorted : " + Arrays.toString(sorted)); // [1, 2, 3, 5, 9]
}
}
Javaこのようにすると、「元の順番」と「ソート後の順番」を並べて使えます。
実務だと、
画面にはソートした一覧を出したい
裏では元データの順番(入力順・優先度順など)も覚えておきたい
という状況はよくあります。
そういうときに、「まず copyOf でソート専用の配列を作る」というのが定番パターンです。
参照型配列では「シャローコピー」であることに注意
配列そのものは別物、中身のオブジェクトは同じ
int[] のようなプリミティブ配列の場合、copyOf は中身の数値もそのままコピーされます。
一方、String[] や自作クラスの配列など、「オブジェクトの配列」の場合は少し注意が必要です。
class Person {
String name;
Person(String name) { this.name = name; }
}
Person[] original = {
new Person("Alice"),
new Person("Bob")
};
Person[] copy = Arrays.copyOf(original, original.length);
// 配列自体は別インスタンス
System.out.println(original == copy); // false
// しかし、中身の参照は同じ
System.out.println(original[0] == copy[0]); // true
JavacopyOf がコピーしているのは「配列(入れ物)」だけです。
その中に入っているオブジェクトは同じものを指しています。
このようなコピーを「シャローコピー(浅いコピー)」と呼びます。
多くの場面ではこれで問題ありませんが、
片方の配列の要素オブジェクトの中身を書き換えたら、もう片方から見ても変わる
ということは意識しておく必要があります。
「オブジェクトも丸ごと別インスタンスにしたい」場合は、
自分で for 文を書いて、一つずつ new し直すような「ディープコピー」が必要になります。
初心者の段階では、とりあえず
copyOf は「配列という箱」をコピーする。中のオブジェクトは同じものを指す
このイメージを持っておけば十分です。
まとめ:Arrays.copyOf を自分の中でどう位置づけるか
Arrays.copyOf を一言で言い直すと、
「元の配列から、新しい配列(長さも自由に)を作るための、シンプルで安全なコピー用メソッド」
です。
特に意識してほしいのは次のあたりです。
- 元配列とは別インスタンスなので、片方をいじってももう片方には影響しない
- 第二引数で新しい配列の長さを指定できるので、配列を“伸ばしながら” or “切り詰めながら”コピーできる
- ソートなどで元配列を壊したくないときは、まず copyOf で作ったコピーに対して操作する
- オブジェクト配列では「箱だけコピー、中身は同じオブジェクト」というシャローコピーになる
