美文网首页
深拷贝与浅拷贝

深拷贝与浅拷贝

作者: 芥末味的冰淇淋 | 来源:发表于2020-03-31 01:38 被阅读0次

什么是克隆

克隆,顾名思义就是复制一个对象的的所有当前状态,并产生一个新的对象,该对象与被复制的对象具有相同的状态。

怎样实现克隆

如果一个类的实例想要实现克隆的功能,那么只需要该类实现Cloneable这个标记接口(标记接口是指没有任何方法,只有一个接口声明的接口,向JVM声明该类实现了某种功能),并覆写继承自Object的clone方法即可。

如何实现对象克隆

当一个类实现了Cloneable这个标记接口并覆写了继承自Object的clone方法时,并将限定修饰符修改为public,就可以实现对象克隆。在Object类中,clone方法为protected,为了保证可以在自己的业务逻辑处理中使用克隆方法,需要将方法的限定修饰符修改为public。在Object类中,该方法会抛出一个 CloneNotSupportedException异常,可以选择把这个异常抛出交给业务处理代码去处理,也可以在覆写的clone方法中去捕获。

示例代码如下
        public class Person implements Cloneable {

           @Override
           public Object clone() throws CloneNotSupportedException {
                return super.clone();
           }

       }

深克与浅克隆的问题怎么产生的

探究这个问题需要了解一个实现了Cloneable接口并覆写了clone方法的类是如何实现克隆的。如上示例代码所示,实现克隆就是调用Object类的克隆方法,即super.clone()。在Object类中,克隆方法是一个本地方法,它实现了对象克隆的所有操作。当你调用对象实例的clone()时,实际时通过Object的本地方法类来完成的。问题就是在这产生的。由于Object是所有Java类的超类,它并不了解子类的实现细节,只能去遍历子类的每个实例域,如果子类的实例域都是基本类型或是不可变类的话,克隆出的对象的实例域和原有对象实例域同时指向同一个对象(实际就是内存中的同一块地址),由于实例域都是基本类型或不可变类,那么克隆对象和原对象并不会产生问题,大家的状态都不会改变,所以并不会产生问题。但是实际开发中这情况是非常少见的,我们日常开发中类的实例域往往都是可变的,那么问题就来了,实例域是可变的,那么克隆出的对象和原对象的实例域指向同一个对象铁定出问题,一个对象的实例域的修改都会影响到另一个对象的状态,而我们往往希望克隆出的对象和原对象谁都不影响谁,大家 各走各路,这种情况就是我们常说的浅拷贝

       public class Salary {

         private  double  baseSalay;

         private  double  bonus;
        
         // 省略get set方法
       }

       public class Person implements Cloneable {

         private String height;

         private Salary salary;

         // 省略get set方法

         @Override
         public Object clone() throws CloneNotSupportedException {
         return super.clone();
        }
      }

如上代码,一个Person类有一个String类型的height属性和一个Salary类型的salary属性,且Person类覆写了超类的clone方法,我们来看一下下面两行代码

    Person  peter=new Person();  
    Person  harry=perter.clone();

原对象peter和克隆对象harry的实例域指向了一个String类型的height引用和一个Salary类型的salary引用,String类型是不可变的,这是ok的,克隆出来的有一样的身高无可厚非,但世界上没有相同的两片叶子,任何个体都有其特性,假设harry机遇更好一点,薪资更高,我们试着来为harry给更高的薪资,然后打印出peter和harry,你会神奇的发现peter的薪资竟然也提高了并且和harry一样,这是因为上面的代码只是实现了对象的浅拷贝造成的,那么我们如何让peter和harry互不影响,成为独立的两个个体呢?你需要考虑深拷贝了。
深拷贝是当一个类中存在可变的实例域时,该类的clone方法中也要相应的克隆该实例域并复制给克隆对象。下面来更改一下代码实现。

       public class Salary implements Cloneable{

         private  double  baseSalay;

         private  double  bonus;
        
         // 省略get set方法

        @Override
        protected Salary clone() throws CloneNotSupportedException {
          return (Salary)super.clone();
        }
       }

       public class Person implements Cloneable {

         private String height;

         private Salary salary;

         // 省略get set方法

        @Override
        public Person clone() throws CloneNotSupportedException {
           Person clone = (Person) super.clone();
           clone.salary = salary.clone();
           return clone;
        }
      }

Salary类实现了Cloneable接口并覆写了clone方法,在Person类的clone方法中调用salary的克隆方法并赋值给克隆出的对象的salary域,此时,perter和harry终于可以不用互相影响了,至此深拷贝就完成了。
考虑一下,如果Salary类不只是基本类型的实例域,该怎么做呢?我们应该在Salary类的clone方法继续调用该类的可变实例域的clone方法,如果想要实现深拷贝,我们一定要保证类中不存在可变的实例域对象,要不然只能递归的确保每一个实例域都实现了clone方法。

总结

关于深拷贝与浅拷贝的坑这里还并没有说完,比如我们应不应该让一个类覆写clone方法,是否可以以更好的类设计来避免clone,这些都需要日常中多总结,思考,学习。
路漫漫其修远兮,吾将上下而求索。。。

相关文章

  • JS中的深拷贝与浅拷贝

    知乎:js中的深拷贝和浅拷贝? 掘金: js 深拷贝 vs 浅拷贝 前言 首先深拷贝与浅拷贝只针对 Object,...

  • 认识js下的浅拷贝与深拷贝

    浅拷贝与深拷贝 首先深拷贝和浅拷贝只针对像 Object, Array 这样的复杂对象的。简单来说,浅拷贝只拷贝一...

  • iOS深拷贝(MutableCopy)与浅拷贝(Copy)的区别

    深拷贝和浅拷贝的概念 iOS中有深拷贝和浅拷贝的概念,那么何为深拷贝何为浅拷贝呢?浅拷贝:浅拷贝并不拷贝对象本身,...

  • Objective-C中的浅拷贝和深拷贝

    Objective-C中的浅拷贝和深拷贝IOS开发之深拷贝与浅拷贝(mutableCopy与Copy)详解iOS ...

  • 深拷贝和浅拷贝

    干货!深拷贝和浅拷贝的区别 深拷贝才是拷贝,浅拷贝就是Retain Copy与Retain的区别 Copy: 根据...

  • js浅拷贝、深拷贝

    前言 本文主要简单讲一下什么是浅拷贝、什么是深拷贝、深拷贝与浅拷贝的区别,以及怎么进行深拷贝和怎么进行浅拷贝。 一...

  • iOS 图文并茂的带你了解深拷贝与浅拷贝

    iOS 图文并茂的带你了解深拷贝与浅拷贝 iOS 图文并茂的带你了解深拷贝与浅拷贝

  • 深拷贝和浅拷贝

    1: iOS开发 深拷贝与浅拷贝 2: iOS 浅谈:深.浅拷贝与copy.strong 3: iOS开发——深...

  • [C++之旅] 15 深拷贝与浅拷贝

    [C++之旅] 15 深拷贝与浅拷贝 拷贝构造函数分为深拷贝和浅拷贝两种方式 浅拷贝只是将被拷贝的对象的成员直接赋...

  • 深拷贝VS浅拷贝

    深拷贝VS浅拷贝 本文主要对深拷贝&浅拷贝的解释及实现做一下简单记录。 之所以会有深拷贝与浅拷贝之分,是因为不同数...

网友评论

      本文标题:深拷贝与浅拷贝

      本文链接:https://www.haomeiwen.com/subject/wmaxwctx.html