zoukankan      html  css  js  c++  java
  • JAVA之路_假克隆、浅克隆、深克隆

    一.JAVA假克隆

    Java中,对于基本类型,可以用“=”进行克隆,而对于引用类型却不能简单的使用“=”进行克隆,这与JAVA的内存使用空间有关,JAVA在栈中保存基本类型和引用变量,在堆中保存对象。对于引用变量而言,使用“=”将修改引用,而不是复制堆中的对象,此时两个引用对象将指向同一个对象,因此如果对一个变量修改则会修改另一个对象。

    public class Employee {
        private String name;
        private int age;
    //省略get和set方法
    @Override
        public String toString() {
            return "姓名:" + name + ", 年龄:" + age;
        }
    }
      public class Test {
        public static void main(String[] args) {
            System.out.println("克隆之前:");
            Employee employee1 = new Employee();
            employee1.setName("芋头1");
            employee1.setAge(12);
            System.out.println("员工1的信息:");
            System.out.println(employee1);
            System.out.println("克隆之后:");
            Employee employee2 = employee1;
            employee2.setName("芋头2");
            employee2.setAge(114);
            System.out.println("员工2的信息:");
            System.out.println(employee2);
            System.out.println("员工1的信息:");
            System.out.println(employee1);
        }
    }

    输出:
    克隆之前:
    员工1的信息:
    姓名:芋头1, 年龄:12
    克隆之后:
    员工2的信息:
    姓名:芋头2, 年龄:114
    员工1的信息:
    姓名:芋头2, 年龄:114
    可以看出,employee1和employ2两个引用变量同时指向一个对象,当修改employee2的域时,employee11的域也被修改,因此是假克隆。
    二、浅克隆
    protect Object clone() 
    通常需要改写该方法并把访问权限限定为public,该方法对于类中的每个域,如果只包含基本类型和不可变的引用类型,如string,或者对象在其生命周期内不可变化,则可以用浅克隆来复制对象。

     public class Address {
        private String state;
        private String province;
        private String city;
    //省略get和set
     @Override
        public String toString() {
            StringBuilder sb = new StringBuilder();
            sb.append("国家:" + state + ", ");
            sb.append("省:" + province + ", ");
            sb.append("市:" + city);
            return sb.toString();
        }
    }
     
    public class Employee implements Cloneable {
        private String name;
        private int age;
        private Address address;
    //省略get和set
    @Override
        public String toString() {
            StringBuilder sb = new StringBuilder();
            sb.append("姓名:" + name + ", ");
            sb.append("年龄:" + age + "
    ");
            sb.append("地址:" + address);
            return sb.toString();
        }
        
        @Override
        public Employee clone() {
            Employee employee = null;
            try {
                employee = (Employee) super.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
            return employee;
        }
    }
     
    public class Test {
        public static void main(String[] args) {
            System.out.println("克隆之前:");
            Address address = new Address("中国", "吉林", "长春");
            Employee employee1 = new Employee("明日科技", 12, address);
            System.out.println("员工1的信息:");
            System.out.println(employee1);
            System.out.println("克隆之后:");
            Employee employee2 = employee1.clone();
            employee2.getAddress().setState("中国");
            employee2.getAddress().setProvince("四川");
            employee2.getAddress().setCity("成都");
            employee2.setName("西南交通大学");
            employee2.setAge(114);
            System.out.println("员工2的信息:");
            System.out.println(employee2);
            System.out.println("员工1的信息:");
            System.out.println(employee1);
        }
    }

    输出:

    克隆之前:
    员工1的信息:
    姓名:明日科技, 年龄:12
    地址:国家:中国, 省:吉林, 市:长春
    克隆之后:
    员工2的信息:
    姓名:西南交通大学, 年龄:114
    地址:国家:中国, 省:四川, 市:成都
    员工1的信息:
    姓名:明日科技, 年龄:12
    地址:国家:中国, 省:四川, 市:成都


    我们发现,employee类中又包含了Adress类adress的引用,我们知道,clone方法默认的是浅克隆,即不会克隆对象引用的对象,而只是简单地复制这个引用。所以在上例中,adress对象在内存中只有一个,employee1和employee2都指向它,任何一个对象对它的修改都会影响另一个对象。所以adress的值也被修改了。
    三,深克隆


    一种就是在引用类型中添加克隆方法。如对上面的浅克隆代码改成:

    在Adress类中增加

    protected Address clone() {
            Address address = null;
            try {
                address = (Address) super.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
            return address;
        }

    Employee中:

     
    public Employee clone() {
     
    Employee employee = null;
     
    try {
     
    employee = (Employee) super.clone();
     
    employee.address = address.clone();
     
    } catch (CloneNotSupportedException e) {
     
    e.printStackTrace();
     
    }

    输出:
    克隆之前:
    员工1的信息:
    姓名:明日科技, 年龄:12
    地址:国家:中国, 省:吉林, 市:长春
    克隆之后:
    员工2的信息:
    姓名:西南交通大学, 年龄:114
    地址:国家:中国, 省:四川, 市:成都
    员工1的信息:
    姓名:明日科技, 年龄:12
    地址:国家:中国, 省:吉林, 市:长春


    实现了深克隆


    一个方法自然是重写clone方法,添加如order.items=(LineItems)items.clone()的语句,也就是人为地添加对引用对象的复制。这个方法的缺点是如果引用对象有很多,或者说引用套引用很多重,那么太麻烦了。业界常用的方法是使用串行化然后反串行化的方法来实现深克隆。由于串行化后,对象写到流中,所有引用的对象都包含进来了,所以反串行化后,对等于生成了一个完全克隆的对象。
    这个方法的要求是对象(包括被引用对象)必须事先了Serializable接口,否则就要用transient关键字将其排除在复制过程中。

  • 相关阅读:
    结对第二次作业——某次疫情统计可视化的实现
    结对第一次—疫情统计可视化(原型设计)
    个人作业——软件工程实践总结&个人技术博客
    虚拟列表(VirtualList)在Taro3中的使用
    结对第二次作业—某次疫情统计可视化的实现
    结对第一次—疫情统计可视化(原型设计)
    软工实践寒假作业(2/2)
    软工实践寒假作业(1/2)
    个人作业——软件工程实践总结&个人技术博客
    Spring Boot
  • 原文地址:https://www.cnblogs.com/zcjyzh/p/9330659.html
Copyright © 2011-2022 走看看