java clone,要想本类可以被clone,则必须实现Cloneable接口,否则会java.lang.CloneNotSupportedException。
super.clone()调用的是object的clone()。是属于浅克隆,如果属性中有对象类型的,克隆对象将会受原型对象影响,这是我们都不愿看到的事情,我们希望克隆对象像是new出来的对象一样独立。
package com.wangbiao.second;
public class TestClone {
public static void test_first(){
Person father=new Person("张三");
Person son_one=new Person("大儿子");
son_one.setFather(father);
Person son_two=(Person) son_one.clone();
son_two.setName("小儿子");
System.out.println(son_one.getName()+"的父亲是"+son_one.getFather().getName());
System.out.println(son_two.getName()+"的父亲是"+son_two.getFather().getName());
}
public static void test_second(){
Person father=new Person("张三");
Person son_one=new Person("大儿子");
son_one.setFather(father);
Person son_two=(Person) son_one.clone();
System.out.println(son_one==son_two);//false说明,是在内存中新开辟了空间,克隆对象和原型对象不是指向同一内存地址。
son_two.setName("小儿子");
System.out.println(son_one.getFather()==son_two.getFather());//true,说明克隆对象和原型对象中的Father属性指向同一个内存地址.
//现在大儿子要认一个干爹
//
son_one.getFather().setName("李四");
System.out.println(son_one.getName()+"的父亲是"+son_one.getFather().getName());
System.out.println(son_two.getName()+"的父亲是"+son_two.getFather().getName());
}
public static void main(String[] args) {
//test_first();
test_second();
}
}
//实现了Cloneable代表该类具有被拷贝的能力。
class Person implements Cloneable {
public Person() {
}
public Person(String name) {
this.name=name;
}
private String name;
private Person father;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person getFather() {
return father;
}
public void setFather(Person father) {
this.father = father;
}
@Override
protected Object clone(){
Person p=null;
//浅拷贝
try {
p=(Person) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
//深拷贝
// try {
// p=(Person) super.clone();
// p.setFather(new Person(p.getFather().getName()));
// } catch (CloneNotSupportedException e) {
// e.printStackTrace();
// }
return p;
}
}
运行的结果是:
false
true
大儿子的父亲是李四
小儿子的父亲是李四
原理就是如果类中有对象类型的属性,在克隆之后,克隆对象和原型对象中的对象类型属性将指向同一个内存空间,只有通过深克隆,才可以避免克隆对象受原型对象的影响。
还有一种方法进行深克隆,基本原理就是将被克隆的对象读入内存中,然后再读出赋给克隆对象。
package com.wangbiao.second;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class Test_Clone {
public static <T extends Serializable>T clone(T object) throws Exception{
T cloneObject=null;
//将对象写入字节流
ByteArrayOutputStream byteOut=new ByteArrayOutputStream();
ObjectOutputStream objectOut=new ObjectOutputStream(byteOut);
objectOut.writeObject(object);
objectOut.close();
//从字节流中读出对象
ByteArrayInputStream byteIn=new ByteArrayInputStream(byteOut.toByteArray());
ObjectInputStream objectIn=new ObjectInputStream(byteIn);
cloneObject=(T) objectIn.readObject();
byteIn.close();
return cloneObject;
}
public static void main(String[] args) throws Exception {
Person per=new Person("大儿子");
per.setFather(new Person("张三"));
Person clone_per=clone(per);
clone_per.setName("小儿子");
per.getFather().setName("李四");
System.out.println(per.getName()+"---"+per.getFather().getName());
System.out.println(clone_per.getName()+"---"+clone_per.getFather().getName());
// 大儿子---李四
// 小儿子---张三
}
}
class Person implements Serializable{
public Person() {
}
public Person(String name) {
this.name=name;
}
private String name;
private Person father;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person getFather() {
return father;
}
public void setFather(Person father) {
this.father = father;
}
}