`
键盘上的无奈
  • 浏览: 3584 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

Java深拷贝和浅拷贝的区别

阅读更多
首先我们看看浅拷贝和深拷贝的定义

浅拷贝:只复制一个对象,对象内部存在的指向其他对象数组或者引用则不复制
深拷贝:对象,对象内部的引用均复制
  为了更好的理解它们的区别我们假设有一个对象A,它包含有2对象,对象A1和对象A2
  对象A进行浅拷贝后,得到对象B但是对象A1和A2并没有被拷贝
  对象A进行深拷贝,得到对象B的同时A1和A2连同它们的引用也被拷贝
  在理解了深拷贝和浅拷贝后,我们来看看Java的深拷贝和浅拷贝实现.

Object 类的 clone方法执行特定的克隆操作。
首先,如果此对象的类不能实现接口 Cloneable,则会抛出 CloneNotSupportedException。(注意:所有的数组都被视为实现接口 Cloneable)
此方法会创建此对象的类的一个新实例,并像通过分配,严格使用此对象相应字段的内容初始化该对象的所有字段;这些字段的内容没有被自我克隆。所以,此方法执行的是该对象的“浅表复制”,而不“深层复制”操作。
Object 类本身不实现接口 Cloneable,所以在类为 Object的对象上调用 clone 方法将会导致在运行时抛出异常。

下面从三个复制的实例代码来看它们之间的区别,我们需建立Person类:

public class Person{
   private String name;
   private int age;
   public Person(String name, int age) {
       this.name = name;
       this.age = age;
    }
   public void setAge(int age) {
       this.age = age;
    }
   public void setName(String name) {
       this.name = name;
    }
   public void display() {
       System.out.println("Name:" + name + "/tAge:" + age);
    }
}


一、普通复制
即我们最容易想到的将一个对象赋值给另外一个对象。
public static void main(String[] args) {
       Person p1=new Person("jack",20);
       Person p2=p1;
       p1.setAge(49);//简单复制
        p2.display();
       p1.display();
       System.out.println(p1);
       System.out.println(p2);
    }


结果:        Name:jack    Age:49
               Name:jack   Age:49
               net.pcedu.clone.Person@c17164
               net.pcedu.clone.Person@c17164
说明p1和p2对象的是同一个引用,所以再改属性2个都是改变的。

二、浅拷贝
浅拷贝必需对Book类实现Cloneable接口的clone方法
public class Book implements Cloneable{
         String bookName;
         double price;
         Person author;
         public Book(String bn,double price,Person author){
                bookName = bn;
                this.price = price;
                this.author = author;   
         }   
         public Object clone(){
           Book b = null;
           try{
               b = (Book)super.clone();
           }catch(CloneNotSupportedExceptione){
               e.printStackTrace();
           }
            return b;
         }
         public void display(){
             System.out.print(bookName + "/t" +price + "/t") ;
              author.display();   
         }
        }
publicstatic void main(Stringargs[]){
      Book b1 = new Book("Java编程",30.50,new Person("张三",34));
      Book b2 = (Book)b1.clone();
      b2.price = 44.0;
      b2.author.setAge(45);
      b2.author.setName("李四");
      b2.bookName = "Java开发";
      b1.display();
      b2.display();
    }


结果:
Java编程  30.5   Name:李四 Age:45
Java开发  44.0   Name:李四 Age:45
说明b1和b2是不同的对象,但是b1.author和b2.author指向同一对象,。

问题如下: 发现在改变b2的author对象属性时b1的author对象的属性也改变了,说明在浅拷贝中的author这个对象没有被完全拷贝,而是使用同一引用,这样就要使用深拷贝了。

三、深拷贝
为了解决如上问题,我们需要用到深拷贝,其实很简单在拷贝book对象的时候加入如下语句
b.author =(Person)author.clone(); //将Person对象进行拷贝,Person对象需进行了拷贝
在运行上面的main方法,结果如下:
  Java编程30.5   Name:张三 Age:34
Java开发44.0   Name:李四 Age:45
说明b1和b2是不同的对象,b1.author和b2.author指向不同对象,。(含引用对象属性的拷贝)。

java.lang.t的clone()方法默认是返回一个前拷贝对象。因此如果要用clone()方法实现一个深拷贝,我们必须对每个对象的clone()方法进行特别实现。当对象层次复杂的时候,这样做不但困难而且浪费时间和容易出现错误,特别有时候你不但需要深拷贝同时你也对这个对象进行浅拷贝的时候,你会发现写这个clone()方法真不是一个好的解决方案。

那么除了clone()方法,我们还可以怎么实现呢?答案是序列化
序列化的对象要实现Serializable接口才能实现序列化,同时,对象的成员对象也要实现序列化.
A a=new A();
//写对象,序列化  
 ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); 
 ObjectOutputStream out= new ObjectOutputStream(byteOut); 
 out.writeObject(a);
 //读对象,反序列化 
  ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
 A b=(A)in.readObject();

序列化经常用于文件传递的读取。尤其是在缓存中用得比较多,通过序列化可以将对象缓存在硬盘中。这在登录系统缓存用户权限和角色等信息最常见。而用对克隆对象,也不失为一种很好的方法。


java.lang.Object类的clone方法是一个protected方法,在子类需要重写此方法并声明为public类型,而且还需实现Cloneable接口才能提供对象复制的能力,clone()是一个native方法,native方法的效率一般来说都是远高于java中的非native方法,对性能比较关心的话首先考虑这种方式,另一种方式——通过java的反射机制复制对象,这种方式效率可能会比clone()低,而且不支持深度复制以及复制集合类型,但通用性会提高很多,下边是进行复制的代码:
private <T> T getBean(T TargetBean, T SourceBean) {
        if (TargetBean== null) return null;
        Field[] tFields = TargetBean.getClass().getDeclaredFields();
        Field[] sFields = SourceBean.getClass().getDeclaredFields();
        try {
            for (Field field : tFields ) {
                String fieldName = field.getName();
                if (fieldName.equals("serialVersionUID")) continue;
                if (field.getType() == Map.class) continue;

                if (field.getType() == Set.class) continue;

                if (field.getType() == List.class) continue;
                for (Field sField : sFields) {
                    if(!sField .getName().equals(fieldName)){
                        continue;
                    }
                    Class type = field.getType();
                    String setName = getSetMethodName(fieldName);
                    Method tMethod = TargetBean.getClass().getMethod(setName, new Class[]{type});
                    String getName = getGetMethodName(fieldName);
                    Method sMethod = SourceBean.getClass().getMethod(getName, null);
                    Object setterValue = voMethod.invoke(SourceBean, null);
                    tMethod.invoke(TargetBean, new Object[]{setterValue});
                }
            }
        } catch (Exception e) {
            throw new Exception("设置参数信息发生异常", e);
        }
        return TargetBean;
}
该方法接收两个参数,一个是复制的源对象——要复制的对象,一个是复制的目标对象——对象副本,当然这个方法也可以在两个不同对象间使用,这时候只要目标对象和对象具有一个或多个相同类型及名称的属性,那么就会把源对象的属性值赋给目标对象的属性。
分享到:
评论

相关推荐

    Java Clone深拷贝与浅拷贝的两种实现方法

    Java Clone 是 Java 语言中的一种复制对象的机制,它可以将一个对象的所有属性和状态复制到另一个对象中,实现对象的深拷贝和浅拷贝。下面我们将讨论 Java 中的深拷贝和浅拷贝的两种实现方法。 一、浅拷贝 浅拷贝...

    Java中的深拷贝(深复制)和浅拷贝(浅复制) 示例代码

    为了理解深拷贝(深复制)和浅拷贝(浅复制),我们需要首先了解Java对象内存的分配方式以及引用的概念。 1. **对象复制的基础** 在Java中,当我们创建一个对象时,系统会在内存中为该对象分配一块空间,存储它的...

    java深入理解浅拷贝和深拷贝

    浅拷贝和深拷贝的区别在于复制对象时对内存中数据的处理方式。 浅拷贝(Shallow Copy)指的是创建一个新的对象,该对象与原对象具有相同的引用,也就是说,它们共享同一块内存空间。如果对象包含的是基本类型的数据...

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

    在Java编程语言中,深拷贝(Deep Copy)和浅拷贝(Shallow Copy)是两种不同的对象复制方式,它们涉及到内存中数据的复制和引用的处理。理解这两种拷贝方式对于开发过程中正确管理和操作对象至关重要。 浅拷贝,又...

    java对象的深拷贝和浅拷贝[归类].pdf

    在Java编程中,对象拷贝是常见的操作,主要分为两种类型:浅拷贝(Shallow Copy)和深拷贝(Deep Copy)。这两种拷贝方式在处理对象时有着本质的区别,对于理解对象复制机制以及在实际开发中正确地复制复杂对象至关...

    《剑指offer》Java浅拷贝和深拷贝.pdf

    Java中的对象拷贝是一个重要的...总之,理解Java中的浅拷贝和深拷贝对于编写可维护和可扩展的代码至关重要,尤其是在处理复杂的数据结构和对象依赖时。掌握这些概念可以帮助你更好地应对面试挑战和解决实际编程问题。

    Java 浅拷贝性能比较完整源码

    在Java编程中,对象的复制是一个常见的操作,主要分为浅拷贝(Shallow Copy)和深拷贝(Deep Copy)。本篇文章将详细讲解Java中的浅拷贝,并通过一个完整的源码示例进行性能比较。 浅拷贝是创建一个新的对象,然后...

    深拷贝拷贝的是内容,浅拷贝拷贝的是指针

    #### 一、深拷贝与浅拷贝的区别 在计算机编程领域中,深拷贝(Deep Copy)与浅拷贝(Shallow Copy)是两种常见的对象复制方法。这两种方法在处理复杂数据结构(如数组、列表等)时有着本质的不同。 **深拷贝**: -...

    使用java反射机制实现java的深拷贝

    在Java编程中,深拷贝和浅拷贝是两种常见的对象拷贝方式。它们主要区别在于,浅拷贝仅复制对象本身,而不复制它引用的对象;而深拷贝则会递归地复制对象及其所有引用的对象。在某些情况下,如需要完全独立的副本时,...

    浅析Java中的深拷贝与浅拷贝

    首先我们看看浅拷贝和深拷贝的定义 浅拷贝:只复制一个对象,对象内部存在的指向其他对象数组或者引用则不复制 深拷贝:对象,对象内部的引用均复制 为了更好的理解它们的区别我们假设有一个对象A,它包含...

    Java 细数浅拷贝和深拷贝

    在Java开发中,理解和掌握浅拷贝与深拷贝的概念及其实现方式是非常重要的。它们不仅关乎对象的内存管理和生命周期,也是解决复杂对象管理问题的基础。根据具体情况选择合适的拷贝策略,有助于提高程序的性能和维护性...

    java List 深度复制方法

    当我们需要复制一个List时,可能会遇到浅复制和深复制的概念。浅复制只复制对象本身,而不复制它引用的对象,而深复制则会递归复制所有引用的对象。这篇博客将探讨如何在Java中对List进行深度复制。 首先,我们来...

    java设计模式【之】原型模式、深拷贝与浅拷贝【源码】【场景:克隆羊】

    java设计模式【之】原型模式、深拷贝与浅拷贝【源码】【场景:克隆羊】 * 原型模式(Prototype) * 实现方式: * 需要被克隆的 class类, 重写Object中的clone()方法,并实现Cloneable接口(否则报错 ...

    android 浅复制和深复制-Java Generic Deep Copy 篇

    本文将深入探讨Java中的浅复制和深复制,并以Android为背景,结合具体的实例讲解如何实现Java泛型深拷贝。 首先,我们要理解浅复制和深复制的概念。浅复制(Shallow Copy)是指创建一个新的对象,然后将原对象引用...

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

    根据拷贝的深度,Java提供了浅拷贝和深拷贝两种方式,这两种拷贝方式处理对象属性的方式有所不同,对于含有引用类型的属性,它们的表现尤为关键。 一、浅拷贝(Shallow Copy) 浅拷贝是Java中最基础的拷贝形式,它...

    java值拷贝

    这个主题涉及到Java中的浅拷贝和深拷贝概念,以及如何利用工具库如Apache Commons BeanUtils进行对象属性的便捷复制。 Apache Commons BeanUtils是一个非常实用的Java库,它提供了一系列方法来简化JavaBean的操作,...

    浅拷贝(浅复制、浅克隆)、深拷贝(深复制、深克隆)实战工程

    在编程领域,尤其是在Java语言中,对象的复制是常见的操作,这涉及到两个主要概念:浅拷贝(浅复制、浅克隆)和深拷贝(深复制、深克隆)。这两个概念是理解对象生命周期和内存管理的关键部分。下面将详细阐述它们的...

    java 深拷贝与浅拷贝机制详解

    了解和掌握深拷贝与浅拷贝的概念以及如何在Java中实现它们,对于编写高效、健壮的代码至关重要,尤其是在处理复杂的对象结构和数据时。正确地使用拷贝机制可以帮助我们避免不必要的副作用,并确保程序的正确性。

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

    在Java编程中,深拷贝和浅拷贝是两种复制对象的方法,它们涉及到对象的内存管理以及对象引用的处理。本文将深入探讨这两种拷贝方式,并着重讲解如何通过重写`clone()`方法以及使用序列化来实现深拷贝。 1. 浅拷贝:...

Global site tag (gtag.js) - Google Analytics