@Beeder
2017-07-06T15:21:32.000000Z
字数 2125
阅读 509
java
1.java中的克隆对应设计模式中的prototype pattern。
2.如果一个对象想要被克隆,需要实现java.lang.Cloneable接口,这个接口和java.io.Serializable接口相似,都是不包含任何方法的接口,用来进行标志。
3.实现Cloneable接口后,需要覆盖Object类中的clone方法,是Object中的一个native方法,需要注意的是Object本身并没有实现Cloneable接口,所以不能对Object对象进行clone。
4.克隆分为shallow copy和deep copy
1、浅复制(浅克隆)
概念:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。
方法:类implements Cloneable,然后重写clone()方法,在clone()方法中调用super.clone()即可,没有其他操作了
2、深复制(深克隆)
概念:被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍
方法:
(1)类implements Cloneable,然后重写clone()方法,在clone()方法中调用super.clone(),然后还要对引用型变量所指的对象进行克隆。
(2)序列化:将该对象写出到对象输出流,那么用对象输入流读回的对象就是原对象的一个深度克隆
5.java文档上推荐的克隆的实现标准
The general intent is that, for any object x, the expression:
x.clone() != x
will be true, and that the expression:
x.clone().getClass() == x.getClass()
will be true, but these are not absolute requirements. While it is typically the case that:
x.clone().equals(x)
will be true, this is not an absolute requirement.
1) 克隆新生成了一个对象,所以引用不同。
2) 克隆的对象与原来的对象是相同的类型,所以getClass应该相同。
3) 按照java的规范,在调用一个对象的equals方法前,这个对象应该已经重写了equals方法,这样比较的不仅仅是引用,所以这里指的是两个对象的信息是否相同,克隆出来的对象信息当然相同,所以这里应该为true。
6.记一下今天写的测试代码
重写Dog类的equals方法,仿照String类写的
@Override
public boolean equals(Object obj) {
if(this == obj){
return true;
}
if(obj instanceof Dog){
Dog anotherDog = (Dog)obj;
if(this.getName() == anotherDog.getName()){
return true;
}
}
return false;
}
重写Dog类的clone方法
@Override
public Dog clone() {
Dog dog = null;
try {
dog = (Dog) super.clone();
dog.setClothes(getClothes().clone());//深克隆时把复制的对象所引用的对象也要clone
} catch (CloneNotSupportedException exception) {
exception.printStackTrace();
}
return dog;
}
PS:要想知道clone真正的用武之地还得在实际中。
又看了一眼Integer的toString方法,Dog的equals方法还可以优化,改为
@Override
public boolean equals(Object obj) {
if(this == obj){
return true;
}
if(obj instanceof Dog){
return name == ((Dog)obj).getName();
}
return false;
}
三行和一行是等价的......
写完了又发现这篇文章有2个严重的错误,弄巧成拙最后测试结果对了,不在文章上直接改,为了能牢记错误~。
1.String name是引用,所以在浅克隆的时候name仅仅是复制的引用。
2.在equals方法中,比较两个String是用的==比较的,好久没有这种错误了。
正好name复制的是引用,所以 == 还是返回的true。
改正:
@Override
public boolean equals(Object obj) {
if(this == obj){
return true;
}
if(obj instanceof Dog){
return name.equals(((Dog)obj).getName());
}
return false;
}
以后记住在浅拷贝的时候String引用还是指向原来的内存空间。