18.7.19
1、Cloneable接口没有定义成员。
2、想要使用Object提供的clone()方法,必须实现Cloneable接口。
一个原因是Object类的clone()方法是protected修饰的,Object与自定义类不在同一个包里,因此无法调用clone()方法,会报错CloneNotSupporteddException。但是实现了Cloneable接口的自定义类,就可以调用Object提供的默认clone方法。(这里也不知道为何)
由于实现Cloneable接口的自定义类一般为实体类,而被调用是在其他包,因此使用时一般需要重写clone()方法,主要目的是赋予public修饰。
3、实现Cloneable接口的类和其所有超类都必需遵守一个复杂、不可实施、且没有文档说明的协议,由此得到一种语言之外的机制:无需调用构造器就可以创建对象。
原因如下:
Object类的clone方法是本地方法native,本地方法一般是C/C++写的。native方法的效率一般来说都是远高于java中的非native方法。这也解释了为什么要用Object中clone()方法而不是先new一个类,然后把原始对象中的信息赋到新对象中,虽然这也实现了clone功能。
例子:testDeepClone o = (testDeepClone) super.clone();
4、调用默认的clone属于浅拷贝,浅拷贝很危险,共用一个对象属性,一旦对象属性的内容改变或者引用改变,会影响所有的拷贝对象。因此一般都会写成深拷贝。
例子:里是另一个 例子。如果一个对象打开一个I/O流并被复制,两个对象将可操作相同的流。而且,如果其中一个对象关闭了流,而另一个对象仍试图对I/O流进行写操作的 话,将导致错误。
5、深拷贝:
public class testDeepClone implements Cloneable {
public int num = 0;
public String str = "default";
public A a;
public Object clone() throws CloneNotSupportedException {
testDeepClone o = (testDeepClone) super.clone();
o.str = new String(this.str);
o.a = (A) a.clone();
return o;
}
}
// 成员属性A必须为Cloneable的,否则无法Clone其组合的类
class A implements Cloneable {
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
6、利用Serializable来实现深拷贝
不用实现cloneable,实现Serializable
参考:https://blog.csdn.net/ab113/article/details/75013496
7、克隆一个对象并不会调用对象的构造方法。因为调用的Object的本地方法clone
8、符合JDK API的clone()方法三条规则
(1)x.clone() != x; 克隆对象与原对象不是同一个对象
(2)x.clone().getClass() == x.getClass(); 克隆的是同一类型的对象
(3)x.clone().equals(x) == true,如果x.equals()方法定义恰当的话
注意,上面的三条规则要求不是绝对的,一般来说前两条是必需的,第三个也应该尽量遵守。
9、还有一些第三方包可以克隆。
10、还有设计模式专门用来克隆。
参考:https://www.cnblogs.com/tonyluis/p/5778266.html
https://www.cnblogs.com/ldq2016/p/5231832.html
https://blog.csdn.net/ab113/article/details/75013496
https://www.cnblogs.com/haitaofeiyang/p/7708000.html
https://blog.csdn.net/yuhongye111/article/details/38148021
别人的总结还不错:
总结
1.Cloneable接口是一个失败的接口,它没有提供clone()方法,却影响了Object.clone()克隆的行为:如果类没有实现Cloneable接口,调用super.clone()方法会得到CloneNotSupportedException。
2.所有实现了Cloneable接口的类都应该提供一个公有的方法覆盖clone(),此公有方法首先调用super.clone(),然后修正域,此公有方法一般不应该声明抛出CloneNotSupportedException。
3.如果为了继承而设计的类不应该实现Cloneable接口,这样可以使子类具有实现或者不实现Cloneable接口的自由,就仿佛它们直接扩展了Object一样。父类没有实现Cloneable接口,也没有覆盖clone(),子类如果实现了Cloneable,在覆盖的clone()中调用super.clone()是可以得到正确对象的。
据说很多专家级程序猿从来都不使用clone()方法。
更好的方法
等等,为了实现clone()方法的功能,有必要这么复杂吗?很少有这种必要。为了实现对象拷贝的更好的方法是提供一个拷贝构造器或者拷贝工厂,它们接受这类的一个对象作为参数。
public Yum( Yum yum);//拷贝构造器
public static YumcopyInstance(Yum yum);//拷贝工厂
参考:https://blog.csdn.net/yuhongye111/article/details/38148021
网友评论