注意:可以发现,是一个直角三角形。
某些时候,我们可能会有这样的需求:我们有一个包含一些有效值的A对象,此时,我们需要一个和A完全相同的对象B,并且我们对B对象的操作不会影响到A对象,也就是说,A和B是独立的对象,但是B的初始值是由A对象给的。只是使用赋值的语句无法满足这样的需求,但实现clone()方法是其中最简单、最高效的方法。
new操作符的本意是分配内存。程序执行到new操作符时,首先会查看new操作符后面的类型,因为知道了类型,才能知道要分配多大的内存空间。分配完内存后,再调用构造函数,填充对象的各个域,这一步叫做对象的初始化。构造函数返回后,一个对象就创建完毕了。
clone的第一步和new一样,都是分配内存空间,分配的内存空间和被clone的对象一样,然后再使用原对象的各个域,填充新对象的域,而后返回新对象。
首先来看一下使用=进行赋值
public static void main(String[] args) { Student s=new Student(); Student s1=s; System.out.println(s1); System.out.println(s); }执行结果:
com.hzp.test.Student@1b6d3586 com.hzp.test.Student@1b6d3586
可以发现,是同一个对象,如果使用s1对对象进行操作的话,必将引起变化。
接着来看下clone的使用
public static void main(String[] args) throws CloneNotSupportedException { Student s=new Student(); s.setAge(23); s.setName("张三"); Student s1= (Student) s.clone(); System.out.println(s); System.out.println(s1); System.out.println(s1.getAge()); System.out.println(s1.getName()); }执行结果:
com.hzp.test.Student@1b6d3586 com.hzp.test.Student@4554617c 23 张三
可以看出,不是同一个对象了,并且原对象的域已经被填充到新对象的域了。
我们知道,在clone对象的时候,会将原对象的各个域填充到新对象,对于基本数据类型的属性不用说,那么对于引用类型的属性是如何拷贝呢?有两种方式,第一种,将原对象的引用值拷贝给新对象,这是浅拷贝,第二种,根据原对象的属性值创建一个新的对象并赋给新对象的属性,这是深拷贝。
我们来看下clone是深拷贝还是浅拷贝
public static void main(String[] args) throws CloneNotSupportedException { Student s=new Student(); s.setAge(23); s.setName("张三"); Student s1= (Student) s.clone(); System.out.println(s.getName()==s1.getName()); }执行结果:
true
可以看出,是同一个对象,也就是说,clone是浅拷贝的
那么,我们如何才能在clone的时候实现深拷贝呢?首先,我们对象的属性所在类必须实现Cloneable接口,并且需要重写clone方法;其次,我们的对象所在类的clone方法内必须调用引用类型属性的clone方法
public class Panda implements Cloneable{ @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } public class Student implements Cloneable{ private String name; private int age; private Panda panda; public Panda getPanda() { return panda; } public void setPanda(Panda panda) { this.panda = panda; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override protected Object clone() throws CloneNotSupportedException { Student student=(Student) super.clone(); student.panda=(Panda) panda.clone(); return student; } } public static void main(String[] args) throws CloneNotSupportedException { Student s=new Student(); s.setPanda(new Panda()); Student s1= (Student) s.clone(); System.out.println(s.getPanda()==s1.getPanda()); }执行结果:
false
可以看出,并不是同一个Panda对象了。