http://tomsui.blog.hexun.com/4308236_d.html
方法(一) 引用拷贝
Employee original = new Employee ("tomsui",4000);
Employee copy = original ;
original 与copy仅仅是同一对象的不同引用。
方法(二) 浅克隆
直接利用Object的clone()方法:
protected Objectclone() throws CloneNotSupportedException
Employee copy = (Employee)original.clone();
注意两点:
1) Object的clone() 是protected. 只能在包内或子类调用.
2) 如果浅克隆的对象中存在对象形式的成员变量:
public class Employee
{
String name;
int salary;
Date birthday;
}
那么:
Employee copy = (Employee) original.clone();
只是拷贝了original对象中的基本类型和不变量.可变的对象成员变量拷贝得到的仍然是引用.
不变量应该包括(可以参见<java多线程设计模式>Immutable模式中界定的情况):
a. String类对象
b. 被final定义,子对象在生存周期中仅保存一些常量
方法(三) 深克隆
例子:
class Employee implements Cloneable
{
private String name;
private double salary;
private Date birthday;
// setter 与 getter
public Object clone()
{
try
{
Employee cloned = (Employee ) super.clone();
cloned.birthday = (Date) birthday.clone();
}catch(CloneNotSupportedException e) {
return null;
}
}
}
说明:
1)Employee 必须实现 Cloneable接口 (标志接口)
标志接口:完全的空接口。这里的作用是告诉JVM,类的设计者理解了cloneable()方法,可以通过isInstanceOf进行运行时检查。
2)覆写的clone()方法必须定义为public (原是protected)
3)clone()方法体必须在try-catch {}中,捕获处理CloneNotSupportedException 。(防止类没有实现Cloneable接口,正确实现了深克隆的话,这个异常肯定不会抛出)
ps. JDK中,StringBuffer没有覆写clone()方法,虽然它确实继承了Object的clone(),但在实际应用中, 因为StringBuffer绝不会有子类,而且是在JDK外使用StringBuffer,所以被protected界定的clone()方法是完全不可见的!
方法(四)使用序列化进行克隆
这种方法涉及IO操作,所以相对来讲要比方法(三)慢.
import java.io.*;
import java.util.*;
public class SerialCloneTest
{
public static void main(String[] args)
{
Employee harry = new Employee("Harry Hacker", 35000,
1989, 10, 1);
// clone harry
Employee harry2 = (Employee)harry.clone();
// mutate harry
harry.raiseSalary(10);
// now harry and the clone are different
System.out.println(harry);
System.out.println(harry2);
}
}
/**
A class whose clone method uses serialization.
*/
class SerialCloneable implements Cloneable, Serializable
{
public Object clone()
{
try
{
// save the object to a byte array
ByteArrayOutputStream bout = new
ByteArrayOutputStream();
ObjectOutputStream out
= new ObjectOutputStream(bout);
out.writeObject(this);
out.close();
// read a clone of the object from the byte array
ByteArrayInputStream bin = new
ByteArrayInputStream(bout.toByteArray());
ObjectInputStream in = new ObjectInputStream(bin);
Object ret = in.readObject();
in.close();
return ret;
}
catch (Exception e)
{
return null;
}
}
}
/**
The familiar Employee class, redefined to extend the
SerialCloneable class.
*/
class Employee extends SerialCloneable
{
public Employee(String n, double s,
int year, int month, int day)
{
name = n;
salary = s;
GregorianCalendar calendar
= new GregorianCalendar(year, month - 1, day);
// GregorianCalendar uses 0 for January
hireDay = calendar.getTime();
}
public String getName()
{
return name;
}
public double getSalary()
{
return salary;
}
public Date getHireDay()
{
return hireDay;
}
public void raiseSalary(double byPercent)
{
double raise = salary * byPercent / 100;
salary += raise;
}
public String toString()
{
return getClass().getName()
+ "[name=" + name
+ ",salary=" + salary
+ ",hireDay=" + hireDay
+ "]";
}
private String name;
private double salary;
private Date hireDay;
}
方法(五) 其他方法
可以通过java的反射机制定义一个类似于对象序列化的万能克隆。改进后再贴上来。