スライドショー

【Java入門】配列のコピー(clone、arraycopy、ShallowとDeep)

こんにちは!フリーランスのオータケです。

Java言語では配列をコピーする方法が幾つかあります。

コードの長さを気にせず書く方法としては配列を2つ用意してfor文を使いコピー元の配列からコピー先の配列に代入していく方法がありますが、

もっと簡潔に書く方法をわかりやすくご紹介したいと思います!

この記事では、配列をコピーする方法について

・clone、arraycopyを使った配列のコピー

という基本的な内容から

・ArrayListのシャローコピーとディープコピー

など具体的な内容についても解説していきます。

今回は配列をコピーする方法について、使い方をわかりやすく解説します!

clone、arraycopyを使った配列のコピー

配列をコピーする方法をご紹介します!

幾つか方法があるのでご自身の状況にあった使い方を選んで下さい。

cloneでのコピー(DeepCopy)

とてもシンプルな方法をご紹介します。

cloneメソッドを使って、次のように書けば配列のコピーができます。

データ型名[] コピー元の配列名 = new データ型[要素数];
データ型名[] コピー先の配列名 = コピー元の配列名.close();

では実際にコピー元の配列の値がコピー先の配列にコピーされているのか見てみたいと思います。

次の例をご覧ください。

import java.util.Arrays;

public class Main {
 
    public static void main(String[] args) {
        int[] foo = new int[10]; // 元の配列
         
        for(int i = 0; i < foo.length; i++) {
            foo[i] = i + 1;
        }
         
        int[] bar = foo.clone();
        
        System.out.println(Arrays.toString(foo));
        System.out.println(Arrays.toString(bar));
    }

}

実行結果:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

このサンプルコードでは、配列fooに1~10の数値を代入し、配列barにコピーした後にbarの中身を表示しています。

しっかりコピーされていますね!

arraycopyでのコピー

もう一つのコピー方法を見てみましょう。

arraycopyを使って以下のように記述します。

System.arraycopy(コピー元配列, コピー元配列のコピー開始位置, コピー先配列, コピー先配列の開始位置, コピーの個数)

なおarraycopyを使う場合、コピー先の値がコピー元の値で上書きされますので注意が必要です。

サンプルコードで確認しましょう。

import java.util.Arrays;

public class Main {
 
    public static void main(String[] args) {
        int[] foo = new int[10]; // 元の配列
        int[] bar = new int[10]; // コピー先の配列
         
        for(int i = 0; i < foo.length; i++) {
            foo[i] = i + 1;
        }
        
        System.arraycopy(foo, 0, bar, 0, 10);
        
        System.out.println(Arrays.toString(foo));
        System.out.println(Arrays.toString(bar));
    }

}

実行結果:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

ArrayListのシャローコピーとディープコピー

今度はArrayListを用いたコピー方法を見てみましょう。

ArrayListのコピーにはシャローコピー(ShallowCopy)とディープコピー(DeepCopy)があります。

それぞれの言葉の意味としては

  • Shallow(浅い)
  • Deep(深い)

になり、配列の各要素にある中身を厳密にコピーするかどうかを意味します。

シャローコピーの場合は参照のみコピーを行います。

ディープコピーの場合は別の参照先に構造と値をコピーします。

それぞれのコピー方法は用途によって使い分ける必要があり、このあたりをよく理解しないで使ってしまうと思わぬ不具合を生み出す可能性もあります。

この2つの違いをサンプルコードで確認していきましょう。

シャローコピー(ShallowCopy)

シャローコピーは以下のように定義時に代入する形で記述します。

ArrayList<Object名> コピー元の配列名 = new ArrayList<>();
ArrayList<Object名> コピー先の配列名 = コピー元の配列名;

サンプルコードで確認しましょう。

import java.util.ArrayList;

public class Main {
 
    public static void main(String[] args) {
        // コピー元のArrayList
        ArrayList<String> src_list = new ArrayList<>();
 
        for(int i = 0; i < 10; i++) {
            src_list.add("AAA");
        }
        
        // コピー先のArrayListオブジェクトに代入してコピー(ShallowCopy)
        ArrayList<String> dst_list = src_list;
        
        // コピー先を変更
        for(int i = 0; i < dst_list.size(); i++) {
            dst_list.set(i, "BBB");
        }
         
        // コピー元とコピー先を出力表示
        System.out.println(src_list);
        System.out.println(dst_list);
    }

}

実行結果:

[BBB, BBB, BBB, BBB, BBB, BBB, BBB, BBB, BBB, BBB]
[BBB, BBB, BBB, BBB, BBB, BBB, BBB, BBB, BBB, BBB] 

このサンプルコードでは、src_listとdst_listの両方の値がBBBと書き換わってしまっています。

意図せず書き換えてしまって不具合を生む可能性もありますので注意しましょう。

ディープコピー(DeepCopy)

ディープコピーの場合はnew句を使いインスタンスを生成し、その引数にコピー元の配列を渡して記述します。

ArrayList<Object名> コピー元の配列名 = new ArrayList<>();
ArrayList<Object名> コピー先の配列名 = new ArrayList<>(コピー元の配列名);

サンプルコードで確認しましょう。

import java.util.ArrayList;

public class Main {
 
    public static void main(String[] args) {
        // コピー元のArrayList
        ArrayList<String> src_list = new ArrayList<>();
 
        for(int i = 0; i < 10; i++) {
            src_list.add("AAA");
        }
        
        // ArrayListのインスタンス生成時にコピー元を引数で渡してコピー(DeepCopy)
        ArrayList<String> dst_list = new ArrayList<>(src_list);
        
        // コピー先を変更
        for(int i = 0; i < dst_list.size(); i++) {
            dst_list.set(i, "BBB");
        }
         
        // コピー元とコピー先を出力表示
        System.out.println(src_list);
        System.out.println(dst_list);
    }

}

実行結果:

[AAA, AAA, AAA, AAA, AAA, AAA, AAA, AAA, AAA, AAA]
[BBB, BBB, BBB, BBB, BBB, BBB, BBB, BBB, BBB, BBB] 

このサンプルコードでは、ArrayListのインスタンス生成時にコピー元を引数で渡してディープコピーを行っています。

ディープコピーでは配列の構造だけでなく中に入っている文字列自体もコピーされるため、dst_listの文字列を変更してもsrc_listには影響がなく別物として扱われていることがわかります。

配列の宣言、初期化、値の追加など知りたい!

配列の宣言、初期化、値の追加、要素数の取得、値のソートや結合についてなど、詳しく知りたい方はこちらもご覧ください!

【Java入門】配列の使い方総まとめ(宣言、初期化、追加、要素数)
更新日 : 2019年7月29日

まとめ

いかがでしたか?

配列コピーの方法からArrayListを用いたコピーの方法を見てきました。

それぞれ使い方がやや違ったり、シャローコピーやディープコピーの考え方で少し混乱してしまうかもしれません。

この記事で記載したサンプルプログラムを元に、いろいろ試してみるのもいいかと思います!

LINEで送る
Pocket

ITエンジニアへ転職したい方におすすめ

自分を評価してくれる企業に転職して年収を上げたい! 自分のスキルにあった独自案件を知りたい!
エンジニアは今もっとも注目されている職業の1つ。エンジニアになって年収を増やしたい方や、あなたのスキルに見合った企業へ転職したいエンジニアの方も多いですよね。

しかし、大手の転職媒体は扱う求人数が多くても、誰もが登録しているので競争率もかなり高くなっています。そのため、あなたの条件に見合った企業を見つけても転職するためには、相応の努力とスキルが必要となります。

こういった媒体では、未経験からエンジニアを目指す方やエンジニア歴2〜3年で転職を考えている方にとって、最適な転職環境とはいえません。

そこでオススメしたいのが、未経験者や若手エンジニア向けの独自案件を多く掲載している「侍ワークス」です。

侍ワークスは、独自案件を多く掲載しているだけでなく、

・応募から就業まで一貫したサポート

・就業後もアフターフォロー

といった経験の浅い方や初めてエンジニアを目指す方にも安心のフォロー体制が整っています。もちろん登録は完全無料!しかも案件を見るだけなら登録も不要です。

まずは、お気軽にどんな求人があるか見てみてください。あなたにピッタリの企業がきっと見つかりますよ! 侍ワークスの求人情報を見る

書いた人

オータケ

オータケ

30歳、フリーランスプログラマ。中学の頃よりプログラミングに興味を持ちゲーム開発やWebサイト構築などを経験
新しいフレームワークやライブラリに興味があり革新的な機能が含まれていると泣いて喜ぶ。