- 论坛徽章:
- 0
|
先看一个浅克隆:
Employee original=new Employee("John Public",50000);
Employee copy=original.clone();
copy.raiseSalary(10);
不过事情没这么简单,clone是Object类的一个proteced方法,也就是说,在用户编写的代码中不能直接调用它,只有Employee类才能够克隆Employee对象.
这种限制不无道理.让我们查看下Object类实现的clone方法.由于这个类对具体的类对象一无所知.所以只能将各个域进行对应的拷贝.如果对象中的所有的数据域属于数值或基本类型.这样拷贝域没有任何问题.但是如果在对象中包含了子对象的引用.那么拷贝的结果会使得两个域引用同一个子对象,因此原始对象与克隆对象共享这部分信息.
重定义clone:
即使clone的默认实现(浅拷贝)能够满足需求,也应该实现Cloneable接口,将clone重定义为public,并调用super.clone().下面是一个例子:
class Employee implements Cloneable
{
//raise visibility level to public ,change return type
public Employee clone() throws CloneNotSupportedException
{
return super.clone();
}
]
刚才的clone方法并没有在Object.clone提供的浅拷贝基础上增加任何新功能,而只是将这个方法声明为public .为了实现深拷贝,必须克隆所有可变的实例域.
下面是一个建立深拷贝clone方法的一个例子:
class Employee implements Cloneable
{
.......
public Object clone() throws CloneNotSupportedException
{
//call Object.clone()
Employee cloned=(Employee) super.clone();
//clone mutable fields
cloned.hireDay=(Date)hireDay.clone()
return cloned;
}
}
只要在clone中没有实现Cloneable接口的对象,Object类的clone方法会抛出一个CloneNotSupportException异常.当然,Employee和Date类都实现了Cloneable接口,因此不会抛出异常.但是编译器并不知道这些情况,因此需要声明异常:
public Employee clone() throws CloneNotSupportedException
import java.util.*;
public class CloneTest
{
public static void main(String[] args)
{
try
{
Employee original = new Employee("John Q. Public", 50000);
original.setHireDay(2000, 1, 1);
Employee copy = original.clone();
copy.raiseSalary(10);
copy.setHireDay(2002, 12, 31);
System.out.println("original=" + original);
System.out.println("copy=" + copy);
}
catch (CloneNotSupportedException e)
{
e.printStackTrace();
}
}
}
class Employee implements Cloneable
{
public Employee(String n, double s)
{
name = n;
salary = s;
}
public Employee clone() throws CloneNotSupportedException
{
// call Object.clone()
Employee cloned = (Employee)super.clone();
// clone mutable fields
cloned.hireDay = (Date)hireDay.clone();
return cloned;
}
/**
Set the hire day to a given date
@param year the year of the hire day
@param month the month of the hire day
@param day the day of the hire day
*/
public void setHireDay(int year, int month, int day)
{
hireDay = new GregorianCalendar(year, month - 1, day).getTime();
}
public void raiseSalary(double byPercent)
{
double raise = salary * byPercent / 100;
salary += raise;
}
public String toString()
{
return "Employee[name=" + name
+ ",salary=" + salary
+ ",hireDay=" + hireDay
+ "]";
}
private String name;
private double salary;
private Date hireDay;
}
注意 对于实现子类的克隆.比如,一旦为Employee类定义了clone方法,任何人都可以利用它克隆Manager对象.Employee的克隆方法能够完成这项这项重任吗? 这将取决于Manager类中包含那些域.在前面看的些程序中,由于bonus域属于基本类型.所以不会出现任何问题.但是,在Manager类中有可能存在一些需要深拷贝的域,或者包含一些没有实现Cloneable接口的域.没有人能够保证子类实现的clone一定正确.鉴于这个原因.应该将Object类中的clone方法声明为protected.但是,如果想让用户调用clone方法,就不能这样做.
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/31513/showart_276785.html |
|