java克隆

java克隆分为浅克隆和深克隆,概念如下:

浅拷贝(浅克隆)
克隆出来的对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。

深拷贝(深克隆)
克隆出来的所有变量都含有与原来的对象相同的值,那些引用其他对象的变量将指向复制出来的新对象,而不再是原有的那些被引用的对象。换言之,深克隆把要克隆的对象所引用的对象都克隆了一遍。

测试:

​ 接下来我们新建两个实体类,一个为Person类,另一个为Father类,同时实现Clonable接口

Person.java

public class Person implements Cloneable { private String name; private int age; private Father father; public Person(String name,int age,Father father){ this.name = name; this.age = age; this.father = father; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Father getFather() { return father; } public void setFather(Father father) { this.father = father; } } 

Father.java

public class Father implements Cloneable { private String name; private int age; public Father(String name, int age){ this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } 

注:这里不能使用lombok注解

测试一:

为Person重写clone方法:

public Person(String name,int age,Father father){ this.name = name; this.age = age; this.father = father; } 

编写测试方法:

Father father = new Father("小明父亲",32); Person person = new Person("小明",12,father); Person personCloneable = person.clone(); personCloneable.setAge(1234); personCloneable.setName("小刚"); personCloneable.getFather().setName("小刚父亲"); System.out.println(person.getName()+":"+person.getAge()); System.out.println(personCloneable.getName()+":" + personCloneable.getAge()); System.out.println(person.getFather().getName()+":"+personCloneable.getFather().getName()); System.out.println(person.getFather() == personCloneable.getFather()); 

输出结果:

小明:12
小刚:1234
小刚父亲:小刚父亲 true 

从测试结果来看person对象的age和name属性成功被克隆,但father属性的引用未变化,因此这是一个浅克隆。

测试二

为Father类重写clone方法:

    @Override
    public Father clone() throws CloneNotSupportedException { Father father = null; father = (Father) super.clone(); return father; } 

为Person类重写clone方法:

    @Override
    public Person clone() throws CloneNotSupportedException { Person person = null; Father father = this.father.clone(); person = (Person) super.clone(); person.setFather(father); return person; } 

再次使用测试一中的测试方法,结果如下:

小明:12
小刚:1234
小明父亲:小刚父亲 false 

可以发现此时被克隆的对象的father对象引用和原对象中的father引用不相同,此时我们实现了深克隆。

扩展

如果要克隆的对象继承链比较长的话要实现深克隆,就必须逐层地实现Cloneable,这个过程是比较麻烦的,不过还有一种方法可以简便地实现深克隆。

serializable克隆

PersonSer.java

 private String name;
    private int age; private FatherSer father; public PersonSer serializableClone() throws IOException, ClassNotFoundException { PersonSer person; ByteArrayOutputStream bo = new ByteArrayOutputStream(); ObjectOutputStream oo = new ObjectOutputStream(bo); oo.writeObject(this); ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray()); ObjectInputStream oi = new ObjectInputStream(bi); person = (PersonSer) oi.readObject(); return person; } public PersonSer(String name,int age,FatherSer father){ this.name = name; this.age = age; this.father = father; } @Override public Person clone() throws CloneNotSupportedException { Person person = null; Father father = this.father.clone(); person = (Person) super.clone(); person.setFather(father); return person; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public FatherSer getFather() { return father; } public void setFather(FatherSer father) { this.father = father; } 

FatherSer.java

public class FatherSer implements Serializable { private String name; private int age; @Override public Father clone() throws CloneNotSupportedException { Father father = null; father = (Father) super.clone(); return father; } public FatherSer(String name, int age){ this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } 

测试类

public static void main(String[] args) throws IOException, ClassNotFoundException { FatherSer father = new FatherSer("小明父亲",32); PersonSer person = new PersonSer("小明",12,father); PersonSer personCloneable = person.serializableClone(); personCloneable.setAge(1234); personCloneable.setName("小刚"); personCloneable.getFather().setName("小刚父亲"); System.out.println(person.getName()+":"+person.getAge()); System.out.println(personCloneable.getName()+":" + personCloneable.getAge()); System.out.println(person.getFather().getName()+":"+personCloneable.getFather().getName()); System.out.println(person.getFather() == personCloneable.getFather()); } 

输出结果:

小明:12
小刚:1234
小明父亲:小刚父亲 false 

通过把对象写进ByteArrayOutputStream里,再把它读取出来。

注意这个过程中所有涉及的对象都必须实现Serializable接口,由于涉及IO操作,这种方式的效率会比前面的低。

猜你喜欢

转载自www.cnblogs.com/zhuyeshen/p/12120899.html