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