Java中clone()方法的作用

    xiaoxiao2022-07-08  242

    Java在处理基本数据类型(例如int、char、double等)时,都是采用值传递(传递的是输入参数的副本)的方式执行,除此之外的其它类型(对象啊,String类型等)都是按引用传递(传递的是对象的一个引用)的方式执行。对象除了在函数调用时是引用传递,在使用“=”也是采用引用传递。

    class Obj { private int i = 0; public int getI() { return i; } public void setI(int i) { this.i = i; } public void changeI() { this.i = 1; } } public class LianXi { public static void main(String[] args) { Obj a = new Obj(); Obj b = a; b.changeI(); System.out.println("a:"+a.getI()); System.out.println("b:"+b.getI()); } }

    运行结果:

    a:1 b:1

    在实际编程中,经常需要从某个已知对象A创建出另一个与A具有相同状态的对象B,并且对B的修改不会影响到A的状态,但从上面的实例中,我们会发现仅仅通过简单的赋值操作显然是无法达到这个目的的(b对象对i的修改影响到了a对象中的i),所以Java提供了一个简单有效的clone()方法来满足这个需求。

    Java中所有的类都默认继承自Object类,而Object类中提供了一个clone()方法,这个方法的作用是返回一个Object对象的复制,这个复制方法返回的是一个新的对象而不是一个引用。以下是使用clone()方法的步骤:

    1.实现clone的类首先需要继承Cloneable接口(Cloneable接口实质是一个标识接口,没有任何的接口方法)。2.在类中重写Object类中的clone()方法3.在clone()方法中调用super.clone()。无论clone类继承结构是什么,super.clone()会直接或间接java.lang.Object类中的clone()方法。4.把浅复制的引用指向原型对象新的克隆体。

    上面的例子引入clone()方法后代码:

    class Obj implements Cloneable { private int i = 0; public int getI() { return i; } public void setI(int i) { this.i = i; } public void changeI() { this.i = 1; } public Object clone() { //重写clone()方法 Object o = null; try { o = (Obj)super.clone(); }catch(CloneNotSupportedException e) { e.printStackTrace(); } return o; } } public class LianXi { public static void main(String[] args) { Obj a = new Obj(); Obj b = (Obj)a.clone(); b.changeI(); System.out.println("a:"+a.getI()); System.out.println("b:"+b.getI()); } }

    在开发人员自定义复制构造函数时,会存在浅复制和深复制之分,Java在重载clone()方法时也存在同样的问题,当类中只有一些基本数据类型时,采用上述的方法就可以了,但是当类中包含了一些对象时,就需要用到深复制了(没错,上面那个就是浅复制),实现方法是在对对象调用clone()方法完成复制后,接着对对象中的非基本数据类型的属性也调用clone()方法完成深复制(非基本数据类型本身也要实现Cloneable接口重写clone()方法你才能完成深复制),实例如下:

    class Obj implements Cloneable { private Date birth = new Date(); //对象 public Date getBirth() { return birth; } public void setBirth(Date birth) { this.birth = birth; } public void changeDate() { this.birth.setMonth(4); } public Object clone() { Obj o = null; try { o = (Obj)super.clone(); //先执行浅复制 }catch(CloneNotSupportedException e) { e.printStackTrace(); } o.birth = (Date)this.getBirth().clone(); //深复制,没有这一步的话,两个对 //象的运行结果都是4月,原因是后面的深复制和浅复制的区别 return o; } } public class LianXi { public static void main(String[] args) { Obj a = new Obj(); Obj b = (Obj)a.clone(); b.changeDate(); System.out.println("a:"+a.getBirth()); System.out.println("b:"+b.getBirth()); } }

    运行结果:

    a:Tue Sep 25 13:14:44 CST 2018 b:Fri May 25 13:14:44 CST 2018

    深复制和浅复制的区别:

    浅复制:被复制对象的所有变量都含有与原来对象相同的值,而所有对其他对象的引用任然指向原来的对象,换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象深复制:被复制对象的所有变量都含有与原来对象相同的值,除去那些引用其他对象的变量,那些引用其他对象的变量将指向被复制的新对象,而不知原来那些被引用的对象,换言之,深复制把浅复制的对象所引用的对象都复制了一遍!

    对于自定义的类的对象实例做引用其他对象的变量:

    class Money implements Cloneable{ double money = 10.0; @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } class Person implements Cloneable{ private String name; Money m; public Person(String name) { this.name = name; this.m = new Money(); } //重写Object的克隆方法 @Override protected Object clone() throws CloneNotSupportedException { Person person = (Person)super.clone(); //克隆Person对象 person.m = (Money)this.m.clone(); //克隆在Person对象中引用指向的对象 return person; } } public class TestDemo20 { public static void main(String[] args) throws CloneNotSupportedException { Person person1 = new Person("caocao"); Person person2 = (Person)person1.clone(); System.out.println(person1.m.money); System.out.println(person2.m.money); person2.m.money = 1000.0; System.out.println(person1.m.money); System.out.println(person2.m.money); }

     

    最新回复(0)