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());
}
}