克隆函数的用法:
调用clone()方法的对象的类必须实现Cloneable接口。
在进行使用时,通常需要先自定义clone()方法,Object提供了一个默认的对象拷贝实现,在自定义时使用super.clone()来调用Object类的clone()方法。
该方法并非十全十美,它只是提供了一个浅拷贝的方法,即该方法并不会把对象中的所有属性全部真正的clone一份,有一部分clone出来的属性与原来属性保持独立变化,而有一部分则不会。具体的处理规则如下:
1.如果属性是基本数据类型
Java基本类型包括了浮点型(float、double);整型(byte、short、int、long);字符型(char);布尔型(boolean)。那么就直接拷贝其值。
2.如果属性是对象类型
则拷贝地址引用,也就是说新拷贝的属性对象与原属性对象指向了同一块内存区域,其实是同一对象。
3.如果属性是String对象类型
该对象比较特殊,clone的也是一个地址引用;但是如果一旦修改该字符串的值,clone出来的对象就会重新生成一个新对象,原有的字符串对象保持不变。从实际的结果这一点来看,可以认为String类型与基本类型是一致的。
浅拷贝代码:
class Color{
private String name; //包包的颜色名称
public Color(String name){
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name){
this.name = name;
}
}
//包包类
public class Package implements Cloneable{
private String name; //包包的名字
private Color color; //包包的颜色
public Package(String name,Color color){
this.name = name;
this.color = color;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
public Package clone(){
Package pkg = null;
try {
pkg = (Package)super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return pkg;
}
//输出包包的信息
public void print(){
System.out.println("Package "+getName()+" => Color is : "+getColor().getName());
}
//测试客户端
public static void main(String[] args) {
Package pkg1 = new Package("Dior",new Color("Red"));
pkg1.print();//打印Dior包的信息
//利用clone方法创建一个新对象,并更新新对象相关属性
Package pkg2 = pkg1.clone();
pkg2.setName("0007");
pkg2.getColor().setName("White");
pkg1.print();//再次打印Dior包的信息
pkg2.print();//打印0007包的信息
}
}
Package Dior => Color is : White
Package 0007 => Color is : White
深拷贝代码:
public Package clone(){
Package pkg = null;
try {
pkg = (Package)super.clone();
//新增:新生成一个对象,切断与原对象关联,实现深拷贝
pkg.setColor(new Color(pkg.getColor().getName()));
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return pkg;
}
注意:
clone方法和new方法是Java世界里生成对象的两种方法。但是,从性能上来看,一般用new方法生成对象的效率会比clone高。clone方法主要应用于构造函数比较复杂、成员属性比较繁多或者是用new方法创建对象比较耗时(可采用性能工具测试比较)的业务场景。
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
(来自程序员chatbook)