在实际饿使用中,克隆对象的情况比较少,大部分情况需要的是属性的赋值,大部分情况使用的BeanUtils
PART ONE:概念
- 深度克隆: 两个对象是完全独立的两个对象。
- 浅克隆: 对于基本数据类型和String类型的数据,直接赋值一份给新的对象,但是对于其他类型的属性,仅仅是复制一份引用给新的对象,所以原始兑现和新的对象中的非基本数据类型的属性指向的是同一个对象。
两个对象在有非基本数据类型和String类型之外的类型的属性时,是无法完全独立的。
PART TWO:实现
无论是深克隆还是浅克隆首先都要是实现接口Cloneable, 重写Object中的方法 clone。Cloneable 接口中没有任何的方法,只是为了标识这个类会进行克隆,不然载调用clone 方法的时候会抛出CloneNotSupertedException
package package_three;
public class test_clone implements Cloneable {
private int id;
private String massage;
private double length;
public test_clone(int id, String massage, double length) {
this.id = id;
this.massage = massage;
this.length = length;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getMassage() {
return massage;
}
public void setMassage(String massage) {
this.massage = massage;
}
public double getLength() {
return length;
}
public void setLength(double length) {
this.length = length;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
//测试
public static void main(String[] args) throws CloneNotSupportedException {
test_clone A = new test_clone(1,"good",2.3);
test_clone B = (test_clone) A.clone();
B.setMassage("like");
System.out.println(A==B);
System.out.println(A.getMassage()==B.getMassage());
}
//输出
false
false
表明了A,B是两个完全独立的对象,实现了深度克隆。但是注意一点,clone() 只支持基本数据类型和String类型的复制,如果是其他类型的字段(ArrayList ,Map等)会直接复制地址
public class test_clone implements Cloneable {
private int id;
private String massage;
private double length;
private ArrayList arr ;
//...
}
//测试
public static void main(String[] args) throws CloneNotSupportedException {
test_clone A = new test_clone(1,"good",2.3);
test_clone B = (test_clone) A.clone();
B.setMassage("like");
System.out.println(A==B);
System.out.println(A.getMassage()==B.getMassage());
System.out.println(A.getArr()==B.getArr());
}
//输出
false
false
true
从上可以看出,A,B两个对象并未完全独立,A,B虽然是堆上的两个不同的对象,但是他们的arr 字段引用的是同一个ArrayList 对象。
对上面的代码进行改造实现,实现Serializable 接口,使用流操作实现深克隆
核心代码
//public class test_clone implements Cloneable ,Serializable
@Override
public Object clone() throws CloneNotSupportedException {
ByteArrayOutputStream bos=null;
ObjectOutputStream oos=null;
ObjectInputStream ois=null;
try {
bos=new ByteArrayOutputStream();//内存中的字节数组缓冲区
oos=new ObjectOutputStream(bos);
oos.writeObject(this);
ois=new ObjectInputStream( new ByteArrayInputStream(bos.toByteArray()));
A a1= (A) ois.readObject();
return a1;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
//下面的部分为关闭流主要是上面的部分
if (oos!=null) {
try {
oos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (ois!=null) {
try {
ois.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (oos!=null) {
try {
oos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return null;
}
//测试
public static void main(String[] args) throws CloneNotSupportedException {
test_clone A = new test_clone(1,"good",2.3);
test_clone B = (test_clone) A.clone();
B.setMassage("like");
System.out.println(A==B);
System.out.println(A.getMassage()==B.getMassage());
System.out.println(A.getArr()==B.getArr());
}
//输出
false
false
false
可以看出A,B完全是独立的两个对象。
clone() 和序列化实现实现深克隆的选择,如果属性比较多,或者包含除String之外的非基本数据类型要实现深度克隆就选择,序列化克隆,如果只有基本数据类型,字段又比较少,那么可以选择clone 。
PART THREE:第三方工具实现克隆
第三方的工具,BeanUtlils 实现浅克隆 BeanUtils.copyProperties(B,A),针对的是javaBean对象(这样的放法也存在浅拷贝的情况);
使用反射和内省的方式完成拷贝:反射完成对象的创建,get/set 方法完成数据的复制。
实现深度 克隆最可靠的方式就是:使用序列化方式