一種c#深拷貝方式完勝java深拷貝(實(shí)現(xiàn)上的對(duì)比分析)
樓主是一名asp.net攻城獅,最近經(jīng)常跑java組客串幫忙開(kāi)發(fā),所以最近對(duì)java的一些基礎(chǔ)知識(shí)特別上心。卻遇到需要將一個(gè)對(duì)象深拷貝出來(lái)做其他事情,而原對(duì)象保持原有狀態(tài)的情況。(實(shí)在是不想自己new一個(gè)出來(lái),然后對(duì)著一堆字段賦值......好吧,再此之前我沒(méi)有關(guān)心是否項(xiàng)目框架有深拷貝的方法),然后就想著用反射實(shí)現(xiàn)吧....接下來(lái)
是我自己的原因,還是真的不存在這樣的純用反射實(shí)現(xiàn)的深拷貝方式....(c#是有純反射實(shí)現(xiàn)的)
但也不能算自己白忙活吧,也找到了其他實(shí)現(xiàn)深拷貝的方式(但是每種方式我都覺(jué)得并不是太合理,也許是因?yàn)閏#的方式帶入了吧,最后貼出c#版本純反射實(shí)現(xiàn)深拷貝的代碼)
方式一:實(shí)現(xiàn)Cloneable接口,重寫clone方法
實(shí)體類:一個(gè)輪胎類,一個(gè)車輛類,車輛中包含輪胎
/**輪胎類**/ 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); }
輸出結(jié)果:
car:1223737555 car.tire:906199566 car_copy:542081238 car_copy.tire:906199566 car_copy:blue car:white
從結(jié)果可以的之,car與car_copy的內(nèi)存地址并不一致,但car.tire與car_copy.tire的內(nèi)存地址卻是一致的,說(shuō)明“奔馳”車確實(shí)又造出了一輛,但卻公用同一幅輪胎(這種情形....哈哈哈),好吧,也就是只復(fù)制了tire的引用,這可以說(shuō)是深拷貝的不徹底 (hashCode()的值可以當(dāng)作是內(nèi)存地址來(lái)理解),那么要怎樣才能徹底,真正的深拷貝?
修改Car類中的clone方法:
@Override protected Object clone() throws CloneNotSupportedException { Car car = (Car)super.clone(); car.tire = (Tire)car.tire.clone(); return car; }
輸出結(jié)果:
car:1223737555 car.tire:906199566 car_copy:542081238 car_copy.tire:1133736492 car_copy:blue car:white
這樣最終實(shí)現(xiàn)了,但這種方式用到項(xiàng)目中并不是很合適吧,每個(gè)需要深拷貝的類,都要實(shí)現(xiàn)Cloneable接口,并覆蓋其clone方法,遇到引用其他類時(shí)候更是需要修改clone方法,要是引用其他類,其他類再引用其他類呢?這不好吧......
方式二:通過(guò)序列化與反序列化實(shí)現(xiàn)(實(shí)現(xiàn)Serializable接口)
實(shí)體類:與第一種方式類似,換成實(shí)現(xiàn)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; }
單元測(cè)試:
@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); }
輸出結(jié)果:
car:2019524978 car.tire:855703640 car_copy:1407965019 car_copy.tire:545768040 car_copy:blue car:white
從結(jié)果集中可以看出是深拷貝是正確的,但是每個(gè)類還是需要實(shí)現(xiàn)Serializable,好像也不合適吧......
優(yōu)化一下深拷貝方法:將其換成泛型,這樣拷貝出來(lái)就不需要強(qiáng)轉(zhuǎn)了(好吧,其實(shí)也沒(méi)比上面的方法好到哪去...)
@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; }
通過(guò)序列化與反序列化深拷貝還有更簡(jiǎn)單的實(shí)現(xiàn)方式,就是需要導(dǎo)個(gè)包(拷貝的類也必須實(shí)現(xiàn)Serializable接口),當(dāng)然,我已經(jīng)為你們準(zhǔn)備好了 點(diǎn)擊->org.apache.commons.lang
深拷貝方法:就一行代碼...
public Object deepClone(Object obj){ return org.apache.commons.lang.SerializationUtils.clone((Serializable)obj); }
好了,java的暫時(shí)就到這里了,當(dāng)然對(duì)于這兩種方式并不是很滿意...
-------------------------------------------------
C#深拷貝 反射實(shí)現(xiàn)
下面方法是c#的深拷貝,純反射實(shí)現(xiàn),無(wú)需實(shí)現(xiàn)任何接口,哦對(duì),需要實(shí)體類有個(gè)無(wú)參的構(gòu)造方法,簡(jiǎn)單使用強(qiáng)大,微軟大法好啊......有需要用到的同學(xué)就拿去用吧,目前經(jīng)過(guò)一個(gè)幾百W的項(xiàng)目框架中考驗(yàn),真的強(qiáng)大實(shí)用
/// <summary> /// 對(duì)象拷貝 /// </summary> /// <param name="obj">被復(fù)制對(duì)象</param> /// <returns>新對(duì)象</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); //創(chuàng)建引用對(duì)象 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深拷貝(實(shí)現(xiàn)上的對(duì)比分析)就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
單元測(cè)試:
相關(guān)文章
DevExpress實(shí)現(xiàn)GridControl單元格編輯驗(yàn)證的方法
這篇文章主要介紹了DevExpress實(shí)現(xiàn)GridControl單元格編輯驗(yàn)證的方法,很實(shí)用的功能,需要的朋友可以參考下2014-08-08C#實(shí)現(xiàn)簡(jiǎn)單的飛行棋小游戲
這篇文章主要為大家詳細(xì)介紹了C#實(shí)現(xiàn)簡(jiǎn)單的飛行棋小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下<BR>2021-11-11使用xmltextreader對(duì)象讀取xml文檔示例
這篇文章主要介紹了使用xmltextreader對(duì)象讀取xml文檔的示例,需要的朋友可以參考下2014-02-02