• 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操作,这种方式的效率会比前面的低。

  • 相关阅读:
    并发通信、生产者消费者模型
    进程和线程的标识,守护模式
    IO多路复用
    网络编程(三):非阻塞套接字
    网络编程(二):套接字Socket
    网络编程(一):基础知识
    python标准库:base64模块
    @classmethod 和 @staticmethod
    Python特性及解释目录(不间断更新)
    Keras 整理及部分源码分析目录(不间断更新)
  • 原文地址:https://www.cnblogs.com/zhuyeshen/p/12120899.html
Copyright © 2020-2023  润新知