一种c#深拷贝方式完胜java深拷贝(实现上的对比分析)_C#教程

楼主是一名asp.net攻城狮,最近经常跑java组客串帮忙开发,所以最近对java的一些基础知识特别上心。却遇到需要将一个对象深拷贝出来做其他事情,而原对象保持原有状态的情况。(实在是不想自己new一个出来,然后对着一堆字段赋值......好吧,再此之前我没有关心是否项目框架有深拷贝的方法),然后就想着用反射实现吧....接下来

是我自己的原因,还是真的不存在这样的纯用反射实现的深拷贝方式....(c#是有纯反射实现的)

但也不能算自己白忙活吧,也找到了其他实现深拷贝的方式(但是每种方式我都觉得并不是太合理,也许是因为c#的方式带入了吧,最后贴出c#版本纯反射实现深拷贝的代码)

方式一:实现Cloneable接口,重写clone方法

实体类:一个轮胎类,一个车辆类,车辆中包含轮胎

/**轮胎类**/
public class Tire implements Cloneable {
  public String color;
  public int radius;
  public Tire(){}
  public Tire(String color, int radius) {
    this.color = color;
    this.radius = radius;
  }

  @Override
  protected Object clone() throws CloneNotSupportedException {
    return super.clone();
  }
}
/**车辆类**/
public class Car implements Cloneable{
  public String name;
  public String color;
  public Tire tire;
  public Car() {}
  public Car(String name, String color, Tire tire) {
    this.name = name;
    this.color = color;
    this.tire = tire;
  }
  public void whistle(){
    System.out.println("汽车"+this.name+" 鸣笛...");
  }
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public String getColor() {
    return color;
  }
  public void setColor(String color) {
    this.color = color;
  }
  public Tire getTire() {
    return tire;
  }
  public void setTire(Tire tire) {
    this.tire = tire;
  }
  @Override
  protected Object clone() throws CloneNotSupportedException {
    return super.clone();
  }
}
@Test
  public void test() throws CloneNotSupportedException {
    Tire tire = new Tire("black",100);
    Car car = new Car("奔驰","white",tire);
    Car car_copy = (Car)car.clone();
    System.out.println("car:"+car.hashCode()+" car.tire:"+car.tire.hashCode());
    System.out.println("car_copy:"+car_copy.hashCode()+" car_copy.tire:"+car_copy.tire.hashCode());
    car_copy.color = "blue";
    System.out.println("car_copy:"+car_copy.color+" car:"+car.color);
  }

输出结果:

car:1223737555 car.tire:906199566
car_copy:542081238 car_copy.tire:906199566
car_copy:blue car:white

从结果可以的之,car与car_copy的内存地址并不一致,但car.tire与car_copy.tire的内存地址却是一致的,说明“奔驰”车确实又造出了一辆,但却公用同一幅轮胎(这种情形....哈哈哈),好吧,也就是只复制了tire的引用,这可以说是深拷贝的不彻底 (hashCode()的值可以当作是内存地址来理解),那么要怎样才能彻底,真正的深拷贝?

修改Car类中的clone方法:

@Override
  protected Object clone() throws CloneNotSupportedException {
    Car car = (Car)super.clone();
    car.tire = (Tire)car.tire.clone();
    return car;
  }

输出结果:

car:1223737555 car.tire:906199566
car_copy:542081238 car_copy.tire:1133736492
car_copy:blue car:white

这样最终实现了,但这种方式用到项目中并不是很合适吧,每个需要深拷贝的类,都要实现Cloneable接口,并覆盖其clone方法,遇到引用其他类时候更是需要修改clone方法,要是引用其他类,其他类再引用其他类呢?这不好吧......

方式二:通过序列化与反序列化实现(实现Serializable接口)

实体类:与第一种方式类似,换成实现Serializable接口,去掉clone方法

/**轮胎类**/
@SuppressWarnings("serial")
public class Tire implements java.io.Serializable {
  public String color;
  public int radius;
  public Tire(){}
  public Tire(String color, int radius) {
    this.color = color;
    this.radius = radius;
  }
}
/**车辆类**/
@SuppressWarnings("serial")
public class Car implements java.io.Serializable{
  public String name;
  public String color;
  public Tire tire;
  public Car() {}
  public Car(String name, String color, Tire tire) {
    this.name = name;
    this.color = color;
    this.tire = tire;
  }
  public void whistle(){
    System.out.println("汽车"+this.name+" 鸣笛...");
  }
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public String getColor() {
    return color;
  }
  public void setColor(String color) {
    this.color = color;
  }
  public Tire getTire() {
    return tire;
  }
  public void setTire(Tire tire) {
    this.tire = tire;
  }
}

深拷贝方法:

@SuppressWarnings("unchecked")
  public static Object deepClone(Object obj)
  {
    Object copyObj = null;
    ObjectOutputStream out = null;
    ObjectInputStream in = null;
    try {
      // 序列化
      ByteArrayOutputStream bufferOut = new ByteArrayOutputStream();
      out = new ObjectOutputStream(bufferOut);

      out.writeObject(obj);

      // 反序列化
      ByteArrayInputStream bufferIn = new ByteArrayInputStream(bufferOut.toByteArray());
      in = new ObjectInputStream(bufferIn);
      copyObj = in.readObject();
    } catch (Exception e) {
      e.printStackTrace();
      throw new RuntimeException(e);
    }finally{
       try{
         if(in != null){
           in.close();
         }
         if(out!=null){
           out.close();
         }
       }catch(IOException e){
         throw new RuntimeException(e);
       }
    }
    return copyObj;
  }

单元测试:

@Test
  public void test() throws CloneNotSupportedException {
    Tire tire = new Tire("black",100);
    Car car = new Car("奔驰","white",tire);
    Car car_copy = (Car)deepClone(car);
    System.out.println("car:"+car.hashCode()+" car.tire:"+car.tire.hashCode());
    System.out.println("car_copy:"+car_copy.hashCode()+" car_copy.tire:"+car_copy.tire.hashCode());
    car_copy.color = "blue";
    System.out.println("car_copy:"+car_copy.color+" car:"+car.color);
  }

输出结果:

car:2019524978 car.tire:855703640
car_copy:1407965019 car_copy.tire:545768040
car_copy:blue car:white

从结果集中可以看出是深拷贝是正确的,但是每个类还是需要实现Serializable,好像也不合适吧......

优化一下深拷贝方法:将其换成泛型,这样拷贝出来就不需要强转了(好吧,其实也没比上面的方法好到哪去...)

@SuppressWarnings("unchecked")
  public static <T> T deepClone(T obj)
  {
    T copyObj = null;
    ObjectOutputStream out = null;
    ObjectInputStream in = null;
    try {
      // 序列化
      ByteArrayOutputStream bufferOut = new ByteArrayOutputStream();
      out = new ObjectOutputStream(bufferOut);

      out.writeObject(obj);

      // 反序列化
      ByteArrayInputStream bufferIn = new ByteArrayInputStream(bufferOut.toByteArray());
      in = new ObjectInputStream(bufferIn);
      copyObj = (T)in.readObject();
    } catch (Exception e) {
      e.printStackTrace();
      throw new RuntimeException(e);
    }finally{
       try{
         if(in != null){
           in.close();
         }
         if(out!=null){
           out.close();
         }
       }catch(IOException e){
         throw new RuntimeException(e);
       }
    }
    return copyObj;
  }

通过序列化与反序列化深拷贝还有更简单的实现方式,就是需要导个包(拷贝的类也必须实现Serializable接口),当然,我已经为你们准备好了 点击->org.apache.commons.lang

深拷贝方法:就一行代码...

public Object deepClone(Object obj){
     return org.apache.commons.lang.SerializationUtils.clone((Serializable)obj);
   }

好了,java的暂时就到这里了,当然对于这两种方式并不是很满意...

-------------------------------------------------

C#深拷贝 反射实现

下面方法是c#的深拷贝,纯反射实现,无需实现任何接口,哦对,需要实体类有个无参的构造方法,简单使用强大,微软大法好啊......有需要用到的同学就拿去用吧,目前经过一个几百W的项目框架中考验,真的强大实用

/// <summary>
    /// 对象拷贝
    /// </summary>
    /// <param name="obj">被复制对象</param>
    /// <returns>新对象</returns>
    private object CopyOjbect(object obj) {
      if (obj == null) {
        return null;
      }
      Object targetDeepCopyObj;
      Type targetType = obj.GetType();
      //值类型
      if (targetType.IsValueType == true) {
        targetDeepCopyObj = obj;
      }
      //引用类型
      else {
        targetDeepCopyObj = System.Activator.CreateInstance(targetType);  //创建引用对象
        System.Reflection.MemberInfo[] memberCollection = obj.GetType().GetMembers();

        foreach (System.Reflection.MemberInfo member in memberCollection) {
          //拷贝字段
          if (member.MemberType == System.Reflection.MemberTypes.Field)
          {
            System.Reflection.FieldInfo field = (System.Reflection.FieldInfo)member;
            Object fieldValue = field.GetValue(obj);
            if (fieldValue is ICloneable)
            {
              field.SetValue(targetDeepCopyObj, (fieldValue as ICloneable).Clone());
            }
            else
            {
              field.SetValue(targetDeepCopyObj, CopyOjbect(fieldValue));
            }

          }//拷贝属性
          else if (member.MemberType == System.Reflection.MemberTypes.Property) {
            System.Reflection.PropertyInfo myProperty = (System.Reflection.PropertyInfo)member;

            MethodInfo info = myProperty.GetSetMethod(false);
            if (info != null) {
              try {
                object propertyValue = myProperty.GetValue(obj, null);
                if (propertyValue is ICloneable) {
                  myProperty.SetValue(targetDeepCopyObj, (propertyValue as ICloneable).Clone(), null);
                }
                else {
                  myProperty.SetValue(targetDeepCopyObj, CopyOjbect(propertyValue), null);
                }
              }
              catch (System.Exception ex) {

              }
            }
          }
        }
      }
      return targetDeepCopyObj;
    }

以上这篇一种c#深拷贝方式完胜java深拷贝(实现上的对比分析)就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。

单元测试:

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索c#深拷贝
c语言是一种什么语言、c语言是一种、c 属性是一种用于、c语言是一种什么编程、c是一种面向 的语言,以便于您获取更多的相关知识。

时间: 2024-11-03 22:11:54

一种c#深拷贝方式完胜java深拷贝(实现上的对比分析)_C#教程的相关文章

Java泛型类型通配符和C#对比分析_java

c#的泛型没有类型通配符,原因是.net的泛型是CLR支持的泛型,而Java的JVM并不支持泛型,只是语法糖,在编译器编译的时候都转换成object类型 类型通配符在java中表示的是泛型类型的父类 public void test(List<Object> c) { for(int i = 0;i < c.size();i++) { System.out.println(c.get(i)); } } //创建一个List<String>对象 List<String&g

C#与Java的MD5简单验证(实例代码)_C#教程

C#端 using System; using System.IO; using System.Security.Cryptography; namespace 计算文件的MD5值 { class MD5_Helper { /// <summary> /// 文件MD5校验 /// </summary> /// <param name="pathName">文件绝对路径</param> /// <returns>MD5校验码&

Java 深拷贝与浅拷贝的分析_java

在正式的进入主题之前,我们先来了解下深拷贝和前拷贝的概念: 浅拷贝: 会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝,如果属性是基本类型,拷贝的是基本类型的值:如果属性是内存地址,拷贝的就是内存地址,因此如果一个对象改变了这个地址就会影响到另一个对象: 深拷贝: 不仅要复制对象的所有非引用成员变量值,还要为引用类型的成员变量创建新的实例,并且初始化为形式参数实例值: 了解完概念之后,我们来测试下普通的对象赋值操作属于深拷贝还是浅拷贝: 测试代码: public class Depth

虚拟磁带库三种主要实现方式及发展趋势

虚拟磁带库作为近年来兴起的 众多 磁盘备份( Backup to http://www.aliyun.com/zixun/aggregation/29800.html">Disk)解决方案中最受瞩目的一项,正在深刻地改变着传统的备份市场格局和用户的数据保护模式. 虚拟磁带库的三种主要实现方式 目前市场上的虚拟磁带库依照架构不同,大概可以分为三种类型:备份软件型(D2D).应用服务器型(VTL Appliance).智能化专用型(Intelligent High Preformance VT

java 深拷贝探讨

java 深拷贝探讨 本文将讨论以下4个问题 1. java Cloneable接口实现深拷贝 2. java 序列化实现深拷贝 3. 号称最快的深拷贝二方库cloning源码分析 4. 几种拷贝方式速度的比较 深拷贝的概念本文就不说了.在C++中实现深拷贝一般情况下重载赋值操作符 "=" 来实现同一个类的对象间的深拷贝,所以很自然的在java中我们也同样可以定义一个copy函数,在函数内部为对象的每一个属性作赋值操作.这种方式简单自然,但存在一个致命性的问题:如果有一天在类中新增加了

探讨java深拷贝_java

本文将讨论以下4个问题     1. java Cloneable接口实现深拷贝     2. java 序列化实现深拷贝     3. 号称最快的深拷贝二方库cloning源码分析     4. 几种拷贝方式速度的比较 深拷贝的概念本文就不说了.在C++中实现深拷贝一般情况下重载赋值操作符 "=" 来实现同一个类的对象间的深拷贝,所以很自然的在java中我们也同样可以定义一个copy函数,在函数内部为对象的每一个属性作赋值操作.这种方式简单自然,但存在一个致命性的问题:如果有一天在类

Java 字符终端上获取输入三种的方式分享_java

在Java 字符终端上获取输入有三种方式: 1.java.lang.System.in (目前JDK版本均支持)2.java.util.Scanner (JDK版本>=1.5)3.java.io.Console(JDK版本>=1.6),特色:能不回显密码字符 参考:这里记录Java中从控制台读入信息的几种方式(1)JDK 1.4(JDK 1.5和JDK 1.6也都兼容这种方法) 复制代码 代码如下: public class TestConsole1 {      public static

JavaScript的9种继承实现方式归纳

  这篇文章主要介绍了JavaScript的9种继承实现方式归纳,本文讲解了原型链继承.原型继承(非原型链).临时构造器继承.属性拷贝.对象间继承等继承方式,需要的朋友可以参考下 不同于基于类的编程语言,如 C++ 和 Java,JavaScript 中的继承方式是基于原型的.同时由于 JavaScript 是一门非常灵活的语言,其实现继承的方式也非常多. 首要的基本概念是关于构造函数和原型链的,父对象的构造函数称为Parent,子对象的构造函数称为Child,对应的父对象和子对象分别为pare

ArrayList和LinkedList的几种循环遍历方式及性能对比分析

主要介绍ArrayList和LinkedList这两种list的五种循环遍历方式,各种方式的性能测试对比,根据ArrayList和LinkedList的源码实现分析性能结果,总结结论. 通过本文你可以了解(1)List的五种遍历方式及各自性能 (2)foreach及Iterator的实现 (3)加深对ArrayList和LinkedList实现的了解. 阅读本文前希望你已经了解ArrayList顺序存储和LinkedList链式的结构,本文不对此进行介绍. 相关:HashMap循环遍历方式及其性