AJ(あじ)ブログ

IT系の記事中心になります。

【Java】初心者向け クラス(Object)の複製(コピー)について


Javaのコピーについておさらいのため、作成してみました。

POINTとしてはimmutableでないものを代入(=)で複製(コピー)を行うと参照が同じとなってしまうということです。
なので、Cloneメソッドを使用するようにしましょうということです。(独自に作成したクラスの場合はCloneメソッドを作成する)


今回はコピーに関するコードを作成して”paiza.io”で試してみました。
※コメントがあればちゃんと解説します。

▼コード

import java.util.*;
import java.util.Arrays;
import java.util.List;

public class Main {
    public static void main(String[] args) throws Exception {
        // Your code here!
        SampleClass sample = new SampleClass();
        sample.Start();
    }
}

class SampleClass {
    private String SEPARATE = "---------------------";
    private String LOG_STRING = "▼▼ 結果 ▼▼";
    public void Start(){
        // 飲み物クラスの初期化
        System.out.println(SEPARATE);
        Drink carbonatedWater = new Drink("carbonated water","炭酸水","水");
        System.out.println(carbonatedWater);

        // Drink 代入
        System.out.println(SEPARATE);
        System.out.println("NGパターン1");
        System.out.println("飲み物 carbonatedWater をコピーして lightlyCarbonated を作成(代入)");
        System.out.println("=で代入しただけでは同じObjectを参照しているため、carbonatedWater の値も変わってしまう。");
        Drink lightlyCarbonated = carbonatedWater;
        lightlyCarbonated.name = "lightly carbonated";
        lightlyCarbonated.detail = "炭酸水(微炭酸)";

        System.out.println(LOG_STRING);
        System.out.println(carbonatedWater);
        System.out.println(lightlyCarbonated);

        // Drink new
        System.out.println(SEPARATE);
        System.out.println("NGパターン2");
        System.out.println("飲み物 Drinkをnewして carbonatedWater の値を設定して soda を作成(クラスだけnew)");
        System.out.println("OK : newでDrinkを作成したので、IDは別物になっている。また、Stringはイミュータブルなので同じく別物になっている。");
        System.out.println("NG : ingredient(ArrayList<String>)は同じObjectとなってしまうため、carbonatedWater の値も変わってしまう。");

        Drink soda = new Drink(carbonatedWater);
        soda.name = "soda";
        soda.detail = "ソーダ";
        soda.ingredient.add("砂糖");

        System.out.println(LOG_STRING);
        System.out.println(carbonatedWater);
        System.out.println(lightlyCarbonated);
        System.out.println(soda);

        // Drink Clone
        System.out.println(SEPARATE);
        System.out.println("Drinkをcloneする Drinkクラスに Cloneableを継承して clon メソッドを作成して、Objectの複製時はCloneを使用するようにする。(Clone)");
        System.out.println("※Drink.clone内でingredient(ArrayList<String>)のcloneも行うようにしています。");
        System.out.println("Clone(複製)なのでIDは同じとなっている。");
        try {
            Drink appleSoda = soda.clone();
            appleSoda.name = "Apple Soda";
            appleSoda.detail = "りんごソーダ";
            appleSoda.ingredient.add("りんご");

            System.out.println(LOG_STRING);
            System.out.println(carbonatedWater);
            System.out.println(lightlyCarbonated);
            System.out.println(soda);
            System.out.println(appleSoda);
        }
        catch (CloneNotSupportedException e){
            e.printStackTrace();
        }
    }
}

class Drink implements Cloneable {
    UUID id = UUID.randomUUID();
    public String name;
    public String detail;
    public ArrayList<String> ingredient;

    Drink(String name,String detail,String... ingredient){
        this.name = name;
        this.detail = detail;
        this.ingredient = new ArrayList<>(Arrays.asList(ingredient));
    }

    Drink(Drink drink){
        this.name = drink.name;
        this.detail = drink.detail;
        this.ingredient = drink.ingredient;
    }

    public String toString(){
        return String.format("ID:%s,名前:%s,詳細:%s,成分:%s (ID:%s,名前:%s,詳細:%s,成分:%s)",
                id,
                name,
                detail,
                ingredient.toString(),
                System.identityHashCode(id),
                System.identityHashCode(name),
                System.identityHashCode(detail),
                System.identityHashCode(ingredient)
        );
    }

    @Override
    public Drink clone() throws CloneNotSupportedException{
        Drink clone = (Drink)super.clone();
        clone.ingredient = (ArrayList<String>) this.ingredient.clone();
        return clone;
    }
}

▼実行結果

---------------------
ID:31b43f8b-c595-4bce-9a12-d7562098a2b2,名前:carbonated water,詳細:炭酸水,成分:[水] (ID:930990596,名前:1921595561,詳細:565760380,成分:6566818)
---------------------
NGパターン1
飲み物 carbonatedWater をコピーして lightlyCarbonated を作成(代入)
=で代入しただけでは同じObjectを参照しているため、carbonatedWater の値も変わってしまう。
▼▼ 結果 ▼▼
ID:31b43f8b-c595-4bce-9a12-d7562098a2b2,名前:lightly carbonated,詳細:炭酸水(微炭酸),成分:[水] (ID:930990596,名前:787604730,詳細:812265671,成分:6566818)
ID:31b43f8b-c595-4bce-9a12-d7562098a2b2,名前:lightly carbonated,詳細:炭酸水(微炭酸),成分:[水] (ID:930990596,名前:787604730,詳細:812265671,成分:6566818)
---------------------
NGパターン2
飲み物 Drinkをnewして carbonatedWater の値を設定して soda を作成(クラスだけnew)
OK : newでDrinkを作成したので、IDは別物になっている。また、Stringはイミュータブルなので同じく別物になっている。
NG : ingredient(ArrayList<String>)は同じObjectとなってしまうため、carbonatedWater の値も変わってしまう。
▼▼ 結果 ▼▼
ID:31b43f8b-c595-4bce-9a12-d7562098a2b2,名前:lightly carbonated,詳細:炭酸水(微炭酸),成分:[水, 砂糖] (ID:930990596,名前:787604730,詳細:812265671,成分:6566818)
ID:31b43f8b-c595-4bce-9a12-d7562098a2b2,名前:lightly carbonated,詳細:炭酸水(微炭酸),成分:[水, 砂糖] (ID:930990596,名前:787604730,詳細:812265671,成分:6566818)
ID:ba2f7be6-2340-446c-8011-bfdfa8cd5887,名前:soda,詳細:ソーダ,成分:[水, 砂糖] (ID:193064360,名前:109961541,詳細:670700378,成分:6566818)
---------------------
Drinkをcloneする Drinkクラスに Cloneableを継承して clon メソッドを作成して、Objectの複製時はCloneを使用するようにする。(Clone)
※Drink.clone内でingredient(ArrayList<String>)のcloneも行うようにしています。
Clone(複製)なのでIDは同じとなっている。
▼▼ 結果 ▼▼
ID:31b43f8b-c595-4bce-9a12-d7562098a2b2,名前:lightly carbonated,詳細:炭酸水(微炭酸),成分:[水, 砂糖] (ID:930990596,名前:787604730,詳細:812265671,成分:6566818)
ID:31b43f8b-c595-4bce-9a12-d7562098a2b2,名前:lightly carbonated,詳細:炭酸水(微炭酸),成分:[水, 砂糖] (ID:930990596,名前:787604730,詳細:812265671,成分:6566818)
ID:ba2f7be6-2340-446c-8011-bfdfa8cd5887,名前:soda,詳細:ソーダ,成分:[水, 砂糖] (ID:193064360,名前:109961541,詳細:670700378,成分:6566818)
ID:ba2f7be6-2340-446c-8011-bfdfa8cd5887,名前:Apple Soda,詳細:りんごソーダ,成分:[水, 砂糖, りんご] (ID:193064360,名前:1190654826,詳細:1109371569,成分:728890494)

▼paiza.io
paiza.io

個人制作アプリリリース中「TimePost」
Download on the App Store
個人制作アプリリリース中「UrlReader」
Download on the App Store