Clone

C#

Shallow Clone

public class Person : ICloneable

{

public int Age { get; set; }

public Name Name { get; set; }

public object Clone()

{

return this.MemberwiseClone();

}

}

Deep Clone

public class Person : ICloneable

{

public int Age { get; set; }

public Name Name { get; set; }

public object Clone()

{

//方法1

return new Person

{

Age = this.Age,

Name = new Name(this.Name.FristName, this.Name.LastName)

};

//方法2

using(Stream stream = new MemoryStream())

{

IFormatter formatter = new BinaryFormatter();

formatter.Serialize(stream, this);

stream.Seek(0, SeekOrigin.Begin);

return formatter.Deserialize(stream) as Person;

}

}

}

★Copy Constructor and Copy factory(Java)

public class Person {

public Person(double firstName, String lastName) {

this.firstName = firstName;

this.lastName = lastName;

}

public Person(Person person) {

this(person.getFirstName(), person.getLastName());

}

public static Person newInstance(Person person) {

return new Person(person.getFirstName(), person.getLastName());

}

...

}

Java

Shallow Clone

class Employee implements Cloneable{

private String name = "";

private Date hireDay = null;

@Override

public Object clone(){

try{

Employee cloned = (Employee)super.clone();

}catch(CloneNotSupportedException){

return null;

}

return cloned;

}

}

Deep Clone

class Employee implements Cloneable{

private String name = "";

private Date hireDay = null;

@Override

public Object clone(){

try{

Employee cloned = (Employee)super.clone();

cloned.hireDay = (Date)hireDay.clone();

}catch(CloneNotSupportedException){

return null;

}

return cloned;

}

}

方法1(Cloneableを実現)

public class Person implements Cloneable {

private String name;

private Person father;

public Person(String name) {

this.name = name;

}

public Person(String name, Person parent) {

this.name = name;

this.father = parent;

}

// getter/setter

//★Shallow Clone

@Override

protected Object clone() throws CloneNotSupportedException {

return (Person)super.clone();

}

//★Deep Clone

@Override

protected Object clone() throws CloneNotSupportedException {

Person p = null;

p = (Person)super.clone();

p.setFather(new Person(p.getFather().getName()));

return p;

}

}

※欠点:それぞれのクラスに対し、Cloneableを書くのは面倒。

方法2(シリアル) 推薦

public final class CloneUtils {

@SuppressWarnings("unchecked")

public static <T extends Serializable> T Clone(T obj){

T clonedObj = null;

try{

ByteArrayOutputStream baos = new ByteArrayOutputStream();

ObjectOutputStream oos = new ObjectOutputStream(baos);

oos.writeObject(obj);

oos.close();

ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());

ObjectInputStream ois = new ObjectInputStream(bais);

clonedObj = (T)ois.readObject();

ois.close();

}catch(Exception e){

e.printStackTrace();

return null;

}

return clonedObj;

}

}

public class Person implements Serializable {

private static final long serialVersionUID = 1L;

private String name;

private Person father;

public Person(String name) {

this.name = name;

}

public Person(String name, Person parent) {

this.name = name;

this.father = parent;

}

// getter/setter

}

※ApacheのcommonsにSerializationUtilsが便利

★配列のClone

private int[] copy;

void saveCopy (int[] data){

this.copy = cloneArray(data);

}

//一次元配列の場合

static int[] cloneArray(int[] data) throws CloneNotSupportedException{

return(int[])data.clone();

}

//二次元配列の場合

static int[][] cloneArray2(int[][] data) throws CloneNotSupportedException{

int[][] copy = (int[][])data.clone();

for (int i = 0; i < data.length; ++i){

if (data[i] != null){

copy[i] = (int[])data[i].clone();

}

}

return copy;

}

★Cloneと参照

public class Example{

private Dimension d = new Dimension(0, 0);

private Integer i = new Integer(0);

public Example(){ }

public synchronized void setDimension(int height,int width)

throws IllegalArgumentException{

if (height < 0 || width < 0){

throw new IllegalArgumentException();

}

d.height = height;

d.width = width;

}

public synchronized Dimension getDimension(){

// return d; //参照 ×

return new Dimension(d.height, d.width); //Clone 〇

}

public synchronized void setInteger(int x) throws IllegalArgumentException{

if (x < 0){

throw new IllegalArgumentException();

}

i = new Integer (x);

}

public synchronized Integer getInteger(){

// return new Integer(i.intValue());

return i; //immutable 〇

}

//★配列の場合

static final public int TOTAL = 10;

private Dimension[] ds = new Dimension[TOTAL];

public synchronized void setDimensions(int index, int height, int width)

throws IllegalArgumentException{

if (height < 0 || width < 0){

throw new IllegalArgumentException();

}

if (ds[index] == null){

ds[index] = new Dimension();

ds[index].height = height;

ds[index].width = width;

}

}

public synchronized Dimension[] getDimensions()

throws CloneNotSupportedException{

// return (Dimension[])ds.clone(); //配列のCloneのみ ×

Dimension[] copy = (Dimension[])ds.clone();

for (int i = 0; i < copy.length; ++i){

if (ds[i] != null){

copy[i] = new Dimension (ds[i].height, ds[i].width);

}

}

return copy;

}

}

Example ex = new Example();

Dimension d = ex.getDimension();

d.height = -1;

d.width = -2;

Dimension d2 = ex.getDimension(); //参照の場合、外部から破壊される

System.out.println(d2.height);

System.out.println(d2.width);

※immutable:Boolean Byte Character Class Double Float Integer Long Short String

★必要のないクローンを不可にする

特定な場合にオブジェクトの内部情報がコピーされてしまうので

public class Sample() {

public final void clone() throws CloneNotSupportedException {

throw new CloneNotSupportedException(getClass().getName());

}

}