一种c#深拷贝方式完胜java深拷贝(实现上的对比分析)
楼主是一名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#窗体程序判断是否闰年