当前位置: 移动技术网 > IT编程>开发语言>c# > 一种c#深拷贝方式完胜java深拷贝(实现上的对比分析)

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

2019年07月18日  | 移动技术网IT编程  | 我要评论

楼主是一名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深拷贝(实现上的对比分析)就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持移动技术网。

单元测试:

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网