スポンサーリンク
目次
ディープコピーの実装方法
[方法1] Cloneableを使ってディープコピー(clone)する
Javaで提供されているCloneableインタフェースを実装することで、ディープコピーできます。
1. Cloneableをimplementsし、cloneメソッドを実装する
Cloneableを使ってディープコピーを実装する場合は、コピー対象となるオブジェクトがCloneableをimplementsする必要があります。
そしてcloneメソッドをOverrideしclone処理を書きます。
具体的なサンプルは以下の通りです。
cloneメソッド内では、Schoolクラスのcloneの作成、そしてリストで保持しているStudentクラスのcloneを作成しています。
package entity;
import java.util.ArrayList;
import java.util.List;
/**
* 学校クラス
*/
public class School implements Cloneable {
/**
* 学校名
*/
private String schoolName;
/**
* 生徒リスト
*/
private List<Student> studentList;
/**
* ディープコピー
*/
@Override
public School clone() {
School school = null;
try {
school = (School) super.clone();
// 生徒リストをコピー
school.studentList = new ArrayList<Student>();
if (this.studentList != null) {
for (Student sudent : this.studentList) {
school.studentList.add(sudent.clone());
}
}
}catch (Exception e){
school = null;
}
return school;
}
public String getSchoolName() {
return schoolName;
}
public void setSchoolName(String schoolName) {
this.schoolName = schoolName;
}
public List<Student> getStudentList() {
return studentList;
}
public void setStudentList(List<Student> studentList) {
this.studentList = studentList;
}
}
package entity;
/**
* 生徒クラス
*/
public class Student implements Cloneable {
/**
* 名前
*/
private String name;
/**
* ディープコピー
*/
@Override
public Student clone() {
Student student = null;
try {
student = (Student) super.clone();
}catch (Exception e){
student = null;
}
return student;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
2. cloneでディープコピーする
Cloneableをimplementsしているオブジェクトさえ作れれば、後はclone()を呼び出すことでディープコピーできます。
School school = new School();
// ディープーコピー
School copySchool = school.clone();
スポンサーリンク
[方法2] SerializationUtilsライブラリで、ディープコピー(clone)する
apache.commons.lang.SerializationUtilsクラスが提供しているcloneメソッドでディープコピーできます。
SerializationUtilsクラスは、Apache Commons Lang(commons-lang×.jar ※×はバージョン)のライブラリを使うことで利用可能です。
1. Serializableをimplementsする
SerializationUtilsクラスで「ディープコピー」するためには、コピー対象のオブジェクトがSerializableをimplementsしていなければコピーできません。
そのため、コピー対象のオブジェクトはSerializableをimplementsします。
具体的なサンプルは以下の通りです。
package entity;
import java.io.Serializable;
import java.util.List;
/**
* 学校クラス
*/
public class School2 implements Serializable {
/**
* 学校名
*/
private String schoolName;
/**
* 生徒リスト
*/
private List<Student2> studentList;
public String getSchoolName() {
return schoolName;
}
public void setSchoolName(String schoolName) {
this.schoolName = schoolName;
}
public List<Student2> getStudentList() {
return studentList;
}
public void setStudentList(List<Student2> studentList) {
this.studentList = studentList;
}
}
package entity;
import java.io.Serializable;
/**
* 生徒クラス
*/
public class Student2 implements Serializable {
/**
* 名前
*/
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
2. cloneでディープコピーする
コピー対象のオブジェクトがSerializableをimplementsしていれば、後はclone()を呼び出すことでディープコピーできます。
School2 school = new School2();
// ディープーコピー
School2 copySchool = SerializationUtils.clone(school);
スポンサーリンク
[方法3] コンストラクタ等で詰め替える
コンストラクタ等を利用して各項目を詰め替えることで「ディープコピー」できます。項目が多いと大変 または メンテナンス性が悪いなどのデメリットはありますが、シンプルな方法です。
1. コンストラクタで詰め替える処理を実装する
コンストラクタで詰め替える処理を実装します。
具体的なサンプルは以下の通りです。
package entity;
import java.util.ArrayList;
import java.util.List;
/**
* 学校クラス
*/
public class School3 {
/**
* コンストラクタ
*/
public School3() {}
/**
* コピー用コンストラクタ
* @param schoolName 学校名
* @param studentList 生徒リスト
*/
public School3(School3 school) {
this.schoolName = school.getSchoolName();
if (school.getStudentList() != null) {
this.studentList = new ArrayList<Student3>();
for(Student3 student : school.getStudentList()) {
this.studentList.add(new Student3(student));
}
}
}
/**
* 学校名
*/
private String schoolName;
/**
* 生徒リスト
*/
private List<Student3> studentList;
public String getSchoolName() {
return schoolName;
}
public void setSchoolName(String schoolName) {
this.schoolName = schoolName;
}
public List<Student3> getStudentList() {
return studentList;
}
public void setStudentList(List<Student3> studentList) {
this.studentList = studentList;
}
}
package entity;
/**
* 生徒クラス
*/
public class Student3 {
/**
* コンストラクタ
*/
public Student3() {}
/**
* コピー用コンストラクタ
* @param name 名前
*/
public Student3(Student3 student) {
this.name = student.getName();
}
/**
* 名前
*/
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
2. インスタンス生成時にディープコピーする
コピー用のコンストラクタを用意したら、後はインスタンス生成時に引数としてコピー元オブジェクトを渡すだけで「ディープコピー」できます。
School3 school = new School3();
// ディープーコピー
School3 copySchool = new School3(school);
スポンサーリンク
[方法4] ディープコピーの処理を自作する
最後は「ディープコピー」の処理を自作する方法です。
1. ディープコピー用の関数を作る
ディープコピー用の関数を作成します。
具体的なサンプルは以下の通りです。
※以下の関数では、コピー対象のオブジェクトはSerializableをimplementsしている必要があります。
/**
* ディープコピー
* @param obj コピー元オブジェクト
* @return コピー先オブジェクト
* @throws IOException
* @throws ClassNotFoundException
*/
public static Object deepcopy(Object obj) throws IOException, ClassNotFoundException {
Object copy = null;
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);) {
// 符号化されたオブジェクトのデータを保持する配列を取得
oos.writeObject(obj);
byte[] buff = baos.toByteArray();
// バイト配列から、オブジェクトを複合化
try (ByteArrayInputStream bais = new ByteArrayInputStream(buff);
ObjectInputStream os = new ObjectInputStream(bais);) {
copy = os.readObject();
}
}
return copy;
}
2. 関数を呼び出しディープコピーする
自作で作成した関数を呼び出し「ディープコピー」を行います。
School2 school = new School2();
// ディープーコピー
School2 copySchool = (School2) deepcopy(school);