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