一、使用
创建对象有两种方式:new 和 clone
当一个对象创建过程复杂,我们是否可以根据已有的对象直接来克隆一份,而不必关系创建的细节呢(原型模式)
1、Java Object根类默认提供了clone方法
protected native Object clone() throws CloneNotSupportedException;
一个本地方法,protected权限: 这样做是为避免我们创建每一个类都默认具有克隆能力。
2、实现Cloneable接口
我们要使用一个对象的clone方法,必须Cloneable接口,这个接口没有任何实现,跟 Serializable一样是一种标志性接口。
如果不实现Cloneable接口,会抛出CloneNotSupportedException异常。
重写clone方法,使用public修饰(否则外部调用不到),调用父类的clone方法,如下
public class CloneModel implements Cloneable { private String name; private int age; @Override public Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public String toString() { return "CloneModel{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
3、Object.clone() 与 构造方法
我们看一个例子 CloneModel 类
public class CloneModel implements Cloneable { private String name; private int age; public CloneModel(){ System.out.println("will new a instance"); } @Override public Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public String toString() { return "CloneModel{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
当我们调用此对象的clone方法时,构造方法并没有被调用,所以我说创建一个对象new和clone是两条路。
public static void main(String[] args) throws CloneNotSupportedException { CloneModel cloneModel = new CloneModel(); System.out.println(cloneModel.clone()); }
输出
CloneModel{name='null', age=0}
二、重写clone方法原则
- x.clone != x将会是true;
- x.clone().getClass()==x.getClass()将会是true(不是绝对的,但建议这么做)
- x.clone().equals(x)将会是true(不是绝对的,但建议这么做)
三、浅克隆和深克隆
1、默认clone方法时浅克隆
Object默认的clone方法实际是对域的简单拷贝,对于简单数据类型,是值的拷贝;
对于复杂类型的字段,则是指针地址的拷贝,clone后的对象和原对象指向的还是一个地址空间
所以说默认的clone方法时浅克隆。例子
class Model2{ int height; } public class CloneModel implements Cloneable{ private String name; private int age; private Model2 model2; public CloneModel() { this.model2 = new Model2(); } public Model2 getModel2() { return model2; } @Override public Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public String toString() { return "CloneModel{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
clone之后比较复杂对象是否相等
public static void main(String[] args) throws CloneNotSupportedException { CloneModel cloneModel1 = new CloneModel(); CloneModel cloneModel2 = (CloneModel)cloneModel1.clone(); System.out.println(cloneModel1.getModel2()==cloneModel2.getModel2()); }
输出
true