Java | Java 標準ライブラリ:Arrays.copyOf

Java Java
スポンサーリンク

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

中身は同じですが、originalcopy は別の配列インスタンスです。
片方を書き換えても、もう片方は変わりません。

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]
Java

int 型の初期値は 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
Java

copyOf がコピーしているのは「配列(入れ物)」だけです。
その中に入っているオブジェクトは同じものを指しています。

このようなコピーを「シャローコピー(浅いコピー)」と呼びます。

多くの場面ではこれで問題ありませんが、

片方の配列の要素オブジェクトの中身を書き換えたら、もう片方から見ても変わる
ということは意識しておく必要があります。

「オブジェクトも丸ごと別インスタンスにしたい」場合は、
自分で for 文を書いて、一つずつ new し直すような「ディープコピー」が必要になります。

初心者の段階では、とりあえず

copyOf は「配列という箱」をコピーする。中のオブジェクトは同じものを指す

このイメージを持っておけば十分です。


まとめ:Arrays.copyOf を自分の中でどう位置づけるか

Arrays.copyOf を一言で言い直すと、

「元の配列から、新しい配列(長さも自由に)を作るための、シンプルで安全なコピー用メソッド」

です。

特に意識してほしいのは次のあたりです。

  • 元配列とは別インスタンスなので、片方をいじってももう片方には影響しない
  • 第二引数で新しい配列の長さを指定できるので、配列を“伸ばしながら” or “切り詰めながら”コピーできる
  • ソートなどで元配列を壊したくないときは、まず copyOf で作ったコピーに対して操作する
  • オブジェクト配列では「箱だけコピー、中身は同じオブジェクト」というシャローコピーになる

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