Java 杂谈Thinking in Java面试

JAVA之假克隆、浅克隆、深克隆

2018-07-19  本文已影响3人  代码墨白

 一.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();

       }

学习群64弍46衣3凌9,资料群69似64陆0吧3

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 + "\n");

        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关键字将其排除在复制过程中。

上一篇下一篇

猜你喜欢

热点阅读