1.拷贝
克隆又称为拷贝,大家都知道克隆羊多莉吧!在java中,例如有一个对象obj1,我想克隆出一个obj2,这个obj2和obj1有着一样的内容。
2..浅拷贝
Object类提供了protected关键字修饰的clone()方法,所有类都是Object类的子类,所以自定义类可以直接使用clone()方法拷贝一个初始状态和自己一样的对象。但是这样是存在局限性的。想想看Object类如何实现clone。它对于你自定义类的对象一无所知,所以只能逐个域的进行拷贝。如果对象中的所有数据域都是数值或者是其他基本类型,拷贝这些域没有任何问题。但是如果对象包含子对象的引用,拷贝域就会得到相同子对象的另一个引用,这样一来原对象和克隆对象仍然会共享一些信息。
浅拷贝会有什么影响吗?这要看具体情况。如果原对象和浅克隆对象共享的子对象是不可变的,那么这种共享就是安全的,如String就是这种情况。或者在对象的声明周期中,子对象一直包含不变的常量,没有更改器方法会改变它,也没有方法会生成它的引用,这种情况下同样是安全的。不过,通常子对象都是可变的。必须重新定义cloned方法来建立一个深拷贝,同时克隆所有子对象。
3.深拷贝
之前我们提到不可变的对象,例如String类的对象,它是被final修饰的类,LocalTime也是如此。再来看看可变的情况,Date的实例就是可变的对象,所以它作为子类时,它也需要被克隆。
对于每一个类在克隆时,需要确定:
1)默认的clone()方法是否满足需求;
2)是否可以在可变的子对象上调用clone()方法来修补默认的clone()方法
如果满足以上任意一项,类必须:
1)实现Cloneable接口
2)重新定义clone方法,并指定pulic访问修饰符
4.实例
import java.util.Date; class Student{ public String name; public Student(String name){ this.name = name; } } public class Test implements Cloneable{ public Student st; public Date date; //Date实现了clone方法 public Test(Date date) { this.date=date; } / * Test类重写clone方法 */ @Override protected Object clone() throws CloneNotSupportedException { Test cloned=(Test) super.clone(); cloned.date=(Date) date.clone(); return cloned; } public static void main(String[] args) throws CloneNotSupportedException{ Student s1 = new Student("Tom"); Test t1 = new Test(new Date()); t1.st = s1; Test t2 = (Test) t1.clone(); System.out.println("t1:\t"+t1); System.out.println("t2:\t"+t2); System.out.println("t1.st:\t"+ t1.st); System.out.println("s1:\t"+s1); System.out.println("t1.date:\t"+t1.date); System.out.println("t2.date:\t"+t2.date); System.out.println("================================"); System.out.println("t1 == t2\t"+(t1 == t2)); System.out.println("t1.equals(t2)\t"+(t1.equals(t2))); System.out.println("t1.st != t2.s\t"+(t1.st != t2.st)); System.out.println("t1.st.equals(t2.st)\t"+t1.st.equals(t2.st)); System.out.println("t1.st==t2.st\t"+(t1.st==t2.st)); System.out.println("t1.date.equals(t2.date)\t"+(t1.date.equals(t2.date))); System.out.println("t1.date==t2.date\t"+(t1.date==t2.date)); new String("nihao"); } }
讯享网
这是程序的输出情况

让我们来模拟一下这个过程:
首先创建了Student类的对象s1,然后创建了Test类的t1,这里使用了当前系统时间去初始化Test的date属性。随后让t1对象的st引用了刚刚创建的s1所引用的域。因为现在t1.st和t1引用了同一个对象了,所以t1.st==st和t1.equals(t2))都为true。随后Test类创建了另一个对象,这个对象是由t1调用了Test类重写后的clone方法创建的。让我们来看看这个重写的方法做了什么:
讯享网/ * Test类重写clone方法 */ @Override protected Object clone() throws CloneNotSupportedException { Test cloned=(Test) super.clone(); cloned.date=(Date) date.clone(); return cloned; }
它除了调用Object的clone方法之外,还对可变的对象data也进行了克隆。因为Data类也重写了clone方法,所以我们不用再考虑Data内部的子类是浅拷贝的情况了,它一定是一个深拷贝了。但是Test类不是还有一个属性st是自定义类Student吗?难道它不需要也像Data一样,由我们手动书写这个拷贝吗?别着急,这就是我为了对比写与不写的区别。
这是Test类的两个对象中的属性st(Student类)的对比情况。我们会发现,这两项的比较结果都是true。

这是Test类的两个对象中的属性date(Date类)的对比情况。我们会发现,使用euqals方法进行比较时,得到的结果是true,而使用全等号进行比较的时候,得到的结果却是false。

大家应该都知道,使用euqals方法进行比较相等就说明两个对象的值是相等的。而使用全等号==进行比较就说明这两个对象引用的是同一个对象!
由于我们在test重写的方法中没有对st属性也进行手动的克隆,所以这两个对象的st属性都是引用的同一个对象。而我们对Date进行了手动的克隆,这才是真正的会克隆一个date对象出来,而不仅仅只是引用了!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/51159.html