您的位置 首页 java

Java的深拷贝和浅拷贝

Java的深拷贝和浅拷贝

¶ 对象拷贝

在展开说深拷贝和浅拷贝之前,先来阐述阐述一下什么是对象拷贝。对象拷贝(Object Copy)就是将一个对象的属性拷贝到另一个有着相同类类型的对象中去。

可以简单类比为在电脑上复制文件,这时候,复制普通文件和复制链接就产生了差异,这个差异就是接下来需要分析的深拷贝和浅拷贝的差异。

¶ 对象拷贝的实现

在Java中如果想要实现拷贝(忽略对象之间使用=号),只能使用clone方法。clone方法使用protect修饰,声明在Object上,也就是所有Object子对象都可以使用clone方法进行对象拷贝。

 protected native Object clone() throws CloneNotSupportedException;

  

Java

在注释中可以看到,如果这个类没有继承自Cloneable接口,那么它会抛出CloneNotSupportedException 异常。

在实现接口,并调用clone时,就能完成对象的拷贝。

¶ 深拷贝和浅拷贝

在对象拷贝章节类比电脑上复制文件一样,针对普通文件和链接文件有不同的处理方式,这种处理方式在Java对象拷贝的上的体现就是深拷贝。

在 Java 中,除了 基本数据类型 (元类型)之外,还存在 类的实例对象 这个引用数据类型。如果在拷贝对象的过程中,只对基本类型的变量进行了值得复制,却对引用类型只做了引用的复制(也就是内存地址引用),没有真正复制引用到的对象。此时的对象拷贝就叫做 浅拷贝

与之相反,不光对基本数据类型执行了值得复制,而且在复制引用类型复制时,不是仅仅传递引用,而是将引用到的对象真正的复制(分配内存),此时的对象拷贝就叫做 深拷贝

¶ 深拷贝和浅拷贝的区别

其实上面在引申概念时,就已经得出深拷贝和浅拷贝的区别了,深拷贝不光要拷贝进本数据类型的值,还要完成对引用类型创建一个新的对象,并复制其内的成员变量。

¶ 深拷贝和浅拷贝的实例

  • 浅拷贝用例
 public class CloneTest implements Cloneable {
  public int x;
  public SonClone son;

  public int getX() {
      return x;
  }

  public void setX(int x) {
      this.x = x;
  }

  public SonClone getSon() {
      return son;
  }

  public void setSon(SonClone son) {
      this.son = son;
  }

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

  	@Test
  public void testClone(){
      CloneTest test = new CloneTest();
      test.setX(127);
      test.setSon(new SonClone());
      try {
          CloneTest clone = (CloneTest) test.clone();
          // 比较test和复制对象copy
          System.out.println("test == clone --> "
                  +(test == clone));
          System.out.println("test.hash == clone.hash --> "
                  +(test.hashCode() == clone.hashCode()));
          System.out.println("test.getClass() == clone.getClass() --> "
                  + (test.getClass() == clone.getClass()));
          System.out.println("test.son == clone.son --> " 
                  +(test.getSon() == clone.getSon()));
          System.out.println("test.son.hash == clone.son.hash --> " 
                  +(test.getSon().hashCode() == clone.getSon().hashCode()));
      } catch (CloneNotSupportedException e) {
          e.printStackTrace();
      }
  }
  class SonClone implements Cloneable{
      int a;
  }

}
  

Java

浅拷贝的执行结果如下:

 test == clone --> false
test.hash == clone.hash --> false
test.getClass() == clone.getClass() --> true
test.son == clone.son --> true
test.son.hash == clone.son.hash --> true

  

可以看到,使用clone可以复制对象,对象的hashcode已经不相同了,但是引用对象却没有执行复制对象的过程,返回的hashcode值仍然是相同的,也就是仅仅复制了引用。

  • 深拷贝用例
 public class DeepClone implements Cloneable{ public int x; public SonClone son;
  public int getX() {
      return x;
  }

  public void setX(int x) {
      this.x = x;
  }

  public SonClone getSon() {
      return son;
  }

  public void setSon(SonClone son) {
      this.son = son;
  }

  class SonClone implements Cloneable{
      int name;

      public int getName() {
          return name;
      }

      public void setName(int name) {
          this.name = name;
      }

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

  @Override
  protected Object clone() throws CloneNotSupportedException {
      DeepClone clone = (DeepClone) super.clone();
      clone.son = (SonClone) this.son.clone();
      return clone;
  }

  @Test
  public void testClone(){
      DeepClone test = new DeepClone();
      test.setX(127);
      test.setSon(new SonClone());
      try {
          DeepClone clone = (DeepClone) test.clone();
          // 比较test和复制对象copy
          System.out.println("test == clone --> "
                  +(test == clone));
          System.out.println("test.hash == clone.hash --> "
                  +(test.hashCode() == clone.hashCode()));

          System.out.println("test.getClass() == clone.getClass() --> "
                  + (test.getClass() == clone.getClass()));
          System.out.println("test.x == clone.x --> "
                  +(test.getX() == clone.getX()));
          System.out.println("test.son == clone.son --> "
                  +(test.getSon() == clone.getSon()));
          System.out.println("test.son.hash == clone.son.hash --> "
                  +(test.getSon().hashCode() == clone.getSon().hashCode()));
      } catch (CloneNotSupportedException e) {
          e.printStackTrace();
      }
  }
}
  

Java

这里深度拷贝可以看出在父类使用clone时,会手动将clone出的父类中的引用指向复制clone出来的子类对象。这时对父类执行了深拷贝,但实则对子类进行了一次浅拷贝。结果显而易见,最后的引用类型值和hashcode都不相同。

¶ 总结

拷贝对象需要使用clone方法,并需要继承Cloneable接口,如果不手动重写clone方法,则默认会只能执行浅拷贝。

浅拷贝只会复制基本数据类型的值,而不会复制引用类型的对象,而深拷贝需要手动编写clone方法来达到既能复制基本数据值,又能够完成对引用类型的对象的复制。

文章来源:智云一二三科技

文章标题:Java的深拷贝和浅拷贝

文章地址:https://www.zhihuclub.com/181794.shtml

关于作者: 智云科技

热门文章

网站地图