欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-05-03 16:32:10
楼主是一名asp.net攻城狮,最近经常跑java组客串帮忙开发,所以最近对java的一些基础知识特别上心。却遇到需要将一个对象深拷贝出来做其他事情,而原对象保持原有状态的...

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

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

是我自己的原因,还是真的不存在这样的纯用反射实现的深拷贝方式....(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深拷贝(实现上的对比分析)就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。

单元测试: