(11):谨慎的覆盖clone

来源:互联网 发布:百度贴吧网络连接失败 编辑:程序博客网 时间:2024/05/01 23:05

当我们想要克隆一个对象时,也就是说我们想要两个一模一样的对象,但想要这两个对象各自开辟空间的时候,我们通常要实现cloneable接口。但是接口没给我们提供clone的实现,但Object类却给我们提供了一个受保护的clone实现。

一般来讲我们直接在子类重写的clone方法调用super,clone()可以得到我们想要的结果。

import java.util.Date;public class User implements Cloneable {private String username;private String password;private Date birthdate;public User(String username, String password, Date birthdate) {this.username = username;this.password = password;this.birthdate = birthdate;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}@Overridepublic int hashCode() {// 省略equals的实现(可用eclipse自动生成)}@Overridepublic boolean equals(Object obj) {// 省略equals的实现(可用eclipse自动生成)}// 省略一大堆get/set方法}
import java.util.Date;import org.junit.Test;public class TestCase {@Testpublic void testUserClone() throws CloneNotSupportedException {User u1 = new User("Kent", "123456", new Date());User u2 = u1;User u3 = (User) u1.clone();System.out.println(u1 == u2);// trueSystem.out.println(u1.equals(u2));// trueSystem.out.println(u1 == u3);// falseSystem.out.println(u1.equals(u3));// true}}

如上诉例子所示,我们得到了我们预期的结果,但也有时结果会和预期相去甚远。

public class Administrator implements Cloneable {private User user;private Boolean editable;public Administrator(User user, Boolean editable) {this.user = user;this.editable = editable;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}@Overridepublic int hashCode() {// 老规矩}@Overridepublic boolean equals(Object obj) {// 老规矩}// 老规矩}
import java.util.Date;import org.junit.Test;public class TestCase {@Testpublic void testAdministratorClone() throws CloneNotSupportedException {Administrator a1 = new Administrator(new User("Kent", "123456", new Date()), true);Administrator a2 = a1;Administrator a3 = (Administrator) a1.clone();System.out.println(a1 == a2);// trueSystem.out.println(a1.equals(a2));// trueSystem.out.println(a1 == a3);// falseSystem.out.println(a1.equals(a3));// trueSystem.out.println(a1.getUser() == a3.getUser());//true ! It's not our expected!!!!!System.out.println(a1.getUser().equals(a3.getUser()));//true}}
这里我们就可以引入两个专业的术语:浅克隆(shallow clone)和深克隆(deep clone)。
所谓的浅克隆,顾名思义就是很表面的很表层的克隆,如果我们要克隆Administrator对象,只克隆他自身以及他包含的所有对象的引用地址。
而深克隆,就是非浅克隆。克隆除自身以外所有的对象,包括自身所包含的所有对象实例。至于深克隆的层次,由具体的需求决定,也有“N层克隆”一说。
但是,所有的基本(primitive)类型数据,无论是浅克隆还是深克隆,都会进行原值克隆。毕竟他们都不是对象,不是存储在堆中。注意:基本数据类型并不包括他们对应的包装类。
如果我们想让对象进行深度克隆,我们可以这样修改Administrator类。

@Overrideprotected Object clone() throws CloneNotSupportedException {Administrator admin = (Administrator) super.clone();admin.user = (User) admin.user.clone();return admin;}
简而言之,所有实现了Cloneable接口的类都应该有一个公有的类覆盖clone。此方法先调用super. clone,然后修正需要修正的域。cloneable有很多问题,我们可以使用拷贝构造器或者拷贝工厂去代替它。
public Yum(Yum yum);public static Yum newInstance(Yum yum)
这两个做法都比实现Cloneable接口具有更多优势。事实上许多专家级的程序员重来不去覆盖clone()方法也重来不去调用它。





0 0
原创粉丝点击