Java中的深拷贝(深复制)和浅拷贝(浅复制)介绍

深拷贝(深复制)和浅拷贝(浅复制)是两个比较通用的概念,尤其在C++语言中,若不弄懂,则会在delete的时候出问题,但是我们在这幸好用的是Java。虽然java自动管理对象的回收,但对于深拷贝(深复制)和浅拷贝(浅复制),我们还是要给予足够的重视,因为有时这两个概念往往会给我们带来不小的困惑。

浅拷贝是指拷贝对象时仅仅拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用指向的对象。深拷贝不仅拷贝对象本身,而且拷贝对象包含的引用指向的所有对象。举例来说更加清楚:对象A1中包含对B1的引用,B1中包含对C1的引用。浅拷贝A1得到A2,A2 中依然包含对B1的引用,B1中依然包含对C1的引用。深拷贝则是对浅拷贝的递归,深拷贝A1得到A2,A2中包含对B2(B1的copy)的引用,B2 中包含对C2(C1的copy)的引用。

若不对clone()方法进行改写,则调用此方法得到的对象即为浅拷贝,下面我们着重谈一下深拷贝。

运行下面的程序,看一看浅拷贝:

class Professor0 implements Cloneable {
  String name;
  int age; 

  Professor0(String name, int age) {
    this.name = name;
    this.age = age;
  } 

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

class Student0 implements Cloneable {
  String name;// 常量对象。
  int age;
  Professor0 p;// 学生1和学生2的引用值都是一样的。 

  Student0(String name, int age, Professor0 p) {
    this.name = name;
    this.age = age;
    this.p = p;
  } 

  public Object clone() {
    Student0 o = null;
    try {
      o = (Student0) super.clone();
    } catch (CloneNotSupportedException e) {
      System.out.println(e.toString());
    } 

    return o;
  }
} 

public class ShallowCopy {
  public static void main(String[] args) {
    Professor0 p = new Professor0("wangwu", 50);
    Student0 s1 = new Student0("zhangsan", 18, p);
    Student0 s2 = (Student0) s1.clone();
    s2.p.name = "lisi";
    s2.p.age = 30;
    s2.name = "z";
    s2.age = 45;
    System.out.println("学生s1的姓名:" + s1.name + "\n学生s1教授的姓名:" + s1.p.name + "," + "\n学生s1教授的年纪" + s1.p.age);// 学生1的教授
  }
}

s2变了,但s1也变了,证明s1的p和s2的p指向的是同一个对象。这在我们有的实际需求中,却不是这样,因而我们需要深拷贝:

class Professor implements Cloneable {
  String name;
  int age; 

  Professor(String name, int age) {
    this.name = name;
    this.age = age;
  } 

  public Object clone() {
    Object o = null;
    try {
      o = super.clone();
    } catch (CloneNotSupportedException e) {
      System.out.println(e.toString());
    }
    return o;
  }
} 

class Student implements Cloneable {
  String name;
  int age;
  Professor p; 

  Student(String name, int age, Professor p) {
    this.name = name;
    this.age = age;
    this.p = p;
  } 

  public Object clone() {
    Student o = null;
    try {
      o = (Student) super.clone();
    } catch (CloneNotSupportedException e) {
      System.out.println(e.toString());
    }
    o.p = (Professor) p.clone();
    return o;
  }
} 

public class DeepCopy {
  public static void main(String args[]) {
    long t1 = System.currentTimeMillis();
    Professor p = new Professor("wangwu", 50);
    Student s1 = new Student("zhangsan", 18, p);
    Student s2 = (Student) s1.clone();
    s2.p.name = "lisi";
    s2.p.age = 30;
    System.out.println("name=" + s1.p.name + "," + "age=" + s1.p.age);// 学生1的教授不改变。
    long t2 = System.currentTimeMillis();
    System.out.println(t2-t1);
  }
}

当然我们还有一种深拷贝方法,就是将对象串行化:

import java.io.*;
//Serialization is time-consuming
class Professor2 implements Serializable {
  /**
   *
   */
  private static final long serialVersionUID = 1L;
  String name;
  int age; 

  Professor2(String name, int age) {
    this.name = name;
    this.age = age;
  }
} 

class Student2 implements Serializable {
  /**
   *
   */
  private static final long serialVersionUID = 1L;
  String name;// 常量对象。
  int age;
  Professor2 p;// 学生1和学生2的引用值都是一样的。 

  Student2(String name, int age, Professor2 p) {
    this.name = name;
    this.age = age;
    this.p = p;
  } 

  public Object deepClone() throws IOException, OptionalDataException,
      ClassNotFoundException {
    // 将对象写到流里
    ByteArrayOutputStream bo = new ByteArrayOutputStream();
    ObjectOutputStream oo = new ObjectOutputStream(bo);
    oo.writeObject(this);
    // 从流里读出来
    ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
    ObjectInputStream oi = new ObjectInputStream(bi);
    return (oi.readObject());
  } 

} 

public class DeepCopy2 { 

  /**
   * @param args
   */
  public static void main(String[] args) throws OptionalDataException,
      IOException, ClassNotFoundException {
    long t1 = System.currentTimeMillis();
    Professor2 p = new Professor2("wangwu", 50);
    Student2 s1 = new Student2("zhangsan", 18, p);
    Student2 s2 = (Student2) s1.deepClone();
    s2.p.name = "lisi";
    s2.p.age = 30;
    System.out.println("name=" + s1.p.name + "," + "age=" + s1.p.age); // 学生1的教授不改变。
    long t2 = System.currentTimeMillis();
    System.out.println(t2-t1);
  } 

}

但是串行化却很耗时,在一些框架中,我们便可以感受到,它们往往将对象进行串行化后进行传递,耗时较多。

(0)

相关推荐

  • Java对象深复制与浅复制实例详解

     Java对象深复制与浅复制实例详解 我们在遇到一些业务场景的时候经常需要对对象进行复制,对于对象的复制一般有两种方式,深复制和浅复制 浅复制:对象的复制仅是对象本身,对象引用的其它对方并不会复制. 深复制:对象的复制包含对象引用的对象. Java所有对象的基类提供了clone方法,但是这个方法是protected native修饰,因此只暴露给之类去重写,外部是无法直接调用的. 我们现在来测试两种复制,首选是浅复制,浅复制要实现Cloneable接口. // 课程对象 class Class

  • Java 浅复制和深复制的实例详解

    Java 浅复制和深复制的实例详解 1 浅复制和深复制区别 浅复制:浅复制只是复制本对象的原始数据类型,如int.float.String,对于数组和对象引用等是不会复制的.因此浅复制是有风险的. 深复制:不但对原始数据类型进行复制,对于对象中的数组和对象引用也做复制的行为,从而达到对对象的完全复制. 2 代码示例 package com; import java.util.ArrayList; public class Test implements Cloneable { // 私有属性 p

  • Java中对象的深复制(深克隆)和浅复制(浅克隆)介绍

    1.浅复制与深复制概念 ⑴浅复制(浅克隆) 被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象.换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象. ⑵深复制(深克隆) 被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量.那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象.换言之,深复制把要复制的对象所引用的对象都复制了一遍. 2.Java的clone()方法 ⑴clone方法将对象复制了一份并返回

  • 理解java中的深复制和浅复制

    Java语言的一个优点就是取消了指针的概念,但也导致了许多程序员在编程中常常忽略了对象与引用的区别,本文会试图澄清这一概念.并且由于Java不能通过简单的赋值来解决对象复制的问题,在开发过程中,也常常要要应用clone()方法来复制对象.本文会让你了解什么是影子clone与深度clone,认识它们的区别.优点及缺点. 看到这个标题,是不是有点困惑:Java语言明确说明取消了指针,因为指针往往是在带来方便的同时也是导致代码不安全的根源,同时也会使程序的变得非常复杂难以理解,滥用指针写成的代码不亚于

  • Java中的深拷贝(深复制)和浅拷贝(浅复制)介绍

    深拷贝(深复制)和浅拷贝(浅复制)是两个比较通用的概念,尤其在C++语言中,若不弄懂,则会在delete的时候出问题,但是我们在这幸好用的是Java.虽然java自动管理对象的回收,但对于深拷贝(深复制)和浅拷贝(浅复制),我们还是要给予足够的重视,因为有时这两个概念往往会给我们带来不小的困惑. 浅拷贝是指拷贝对象时仅仅拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用指向的对象.深拷贝不仅拷贝对象本身,而且拷贝对象包含的引用指向的所有对象.举例来说更加清楚:对象A1中包含对B1的引用

  • 详解java中的深拷贝和浅拷贝(clone()方法的重写、使用序列化实现真正的深拷贝)

    1.序列化实现 public class CloneUtils { @SuppressWarnings("unchecked") public static <T extends Serializable> T clone(T object){ T cloneObj = null; try { ByteArrayOutputStream out = new ByteArrayOutputStream(); ObjectOutputStream obs = new Objec

  • Java中IO流文件读取、写入和复制的实例

    //构造文件File类 File f=new File(fileName); //判断是否为目录 f.isDirectory(); //获取目录下的文件名 String[] fileName=f.list(); //获取目录下的文件 File[] files=f.listFiles(); 1.Java怎么读取文件 package com.yyb.file; import java.io.File; import java.io.FileInputStream; import java.io.In

  • 浅谈Java中实现深拷贝的两种方式—clone() & Serialized

    clone() 方法麻烦一些,需要将所有涉及到的类实现声明式接口 Cloneable,并覆盖Object类中的clone()方法,并设置作用域为public(这是为了其他类可以使用到该clone方法). 序列化的方法简单,需要将所有涉及到的类实现接口Serializable package b1ch06.clone; import java.io.Serializable; class Car implements Cloneable, Serializable { private String

  • Java中的深拷贝和浅拷贝介绍

    一.引言   对象拷贝(Object Copy)就是将一个对象的属性拷贝到另一个有着相同类类型的对象中去.在程序中拷贝对象是很常见的,主要是为了在新的上下文环境中复用对象的部分或全部 数据.Java中有三种类型的对象拷贝:浅拷贝(Shallow Copy).深拷贝(Deep Copy).延迟拷贝(Lazy Copy). 二.浅拷贝 1.什么是浅拷贝   浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝.如果属性是基本类型,拷贝的就是基本类型的值:如果属性是内存地

  • js中如何复制一个数组(浅复制、深复制)

    目录 下面介绍数组的浅复制 方法一:concat() 方法二:slice() 方法三:扩展运算符 方法四: Object.assign() 下面是深复制 方法一:JSON.parse(JSON.stringify(arr)) 方法二:通用方法(数组或对象) 方法三:利用lodash的深拷贝函数 在Vue中使用 安装 在main.js中引入 使用 总结 在js中,我们经常会用到数组复制,Array是引用类型,如果用arrA=arrB简单的把一个数组赋值,并没有创造出一个新数组,arrA和arrB其

  • java中关于深拷贝的几种方式总结

    目录 前言 方式1:构造函数深拷贝 方式2:重载Clone()方法深拷贝 方式3:Apache Commons Lang序列化方式深拷贝 方式4:Gson序列化方式深拷贝 方式5:Jackson序列化方式 总结 前言 在java里,当我们需要拷贝一个对象时,有两种类型的拷贝:浅拷贝与深拷贝. 浅拷贝只是拷贝了源对象的地址,所以源对象的值发生变化时,拷贝对象的值也会发生变化. 深拷贝则是拷贝了源对象的所有值,所以即使源对象的值发生变化时,拷贝对象的值也不会改变. 方式1:构造函数深拷贝 我们可以调

  • java中静态变量和实例变量的区别详细介绍

    运行效果: 控制台效果: ================================================== 代码部分 ================================================== /hello_test/src/com/b510/test/StaticTest.java 复制代码 代码如下: /**  *   */ package com.b510.test; /**  * 在程序运行时的区别:实例变量属于某个对象的属性,必须创建了实例

  • java中数组list map三者之间的互转介绍

    三者之间转换关系,一张图清晰呈现.  上代码: 其中的maputils是apache的collection包. 复制代码 代码如下: package util; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.collections.MapUtil

随机推荐