一种c#深拷贝方式完胜java深拷贝(实现上的对比)
樓主是一名asp.net攻城獅,最近經常跑java組客串幫忙開發,所以最近對java的一些基礎知識特別上心。卻遇到需要將一個對象深拷貝出來做其他事情,而原對象保持原有狀態的情況。(實在是不想自己new一個出來,然后對著一堆字段賦值......好吧,再此之前我沒有關心是否項目框架有深拷貝的方法),然后就想著用反射實現吧....接下來
是我自己的原因,還是真的不存在這樣的純用反射實現的深拷貝方式....(c#是有純反射實現的)
但也不能算自己白忙活吧,也找到了其他實現深拷貝的方式(但是每種方式我都覺得并不是太合理,也許是因為c#的方式帶入了吧,最后貼出c#版本純反射實現深拷貝的代碼)
方式一:實現Cloneable接口,重寫clone方法實體類:一個輪胎類,一個車輛類,車輛中包含輪胎
1 /**輪胎類**/2 public class Tire implements Cloneable {3 public String color;4 public int radius;5 public Tire(){}6 public Tire(String color, int radius) {7 this.color = color;8 this.radius = radius;9 } 10 11 @Override 12 protected Object clone() throws CloneNotSupportedException { 13 return super.clone(); 14 } 15 } 16 /**車輛類**/ 17 public class Car implements Cloneable{ 18 public String name; 19 public String color; 20 public Tire tire; 21 public Car() {} 22 public Car(String name, String color, Tire tire) { 23 this.name = name; 24 this.color = color; 25 this.tire = tire; 26 } 27 public void whistle(){ 28 System.out.println("汽車"+this.name+" 鳴笛..."); 29 } 30 public String getName() { 31 return name; 32 } 33 public void setName(String name) { 34 this.name = name; 35 } 36 public String getColor() { 37 return color; 38 } 39 public void setColor(String color) { 40 this.color = color; 41 } 42 public Tire getTire() { 43 return tire; 44 } 45 public void setTire(Tire tire) { 46 this.tire = tire; 47 } 48 @Override 49 protected Object clone() throws CloneNotSupportedException { 50 return super.clone(); 51 } 52 }?
單元測試:
1 @Test2 public void test() throws CloneNotSupportedException {3 Tire tire = new Tire("black",100);4 Car car = new Car("奔馳","white",tire);5 Car car_copy = (Car)car.clone();6 System.out.println("car:"+car.hashCode()+" car.tire:"+car.tire.hashCode());7 System.out.println("car_copy:"+car_copy.hashCode()+" car_copy.tire:"+car_copy.tire.hashCode());8 car_copy.color = "blue";9 System.out.println("car_copy:"+car_copy.color+" car:"+car.color); 10 }?
輸出結果:
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方法:
1 @Override 2 protected Object clone() throws CloneNotSupportedException { 3 Car car = (Car)super.clone(); 4 car.tire = (Tire)car.tire.clone(); 5 return car; 6 }?
輸出結果:
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;} }?
深拷貝方法:
1 @SuppressWarnings("unchecked")2 public static Object deepClone(Object obj)3 {4 Object copyObj = null;5 ObjectOutputStream out = null;6 ObjectInputStream in = null;7 try {8 // 序列化9 ByteArrayOutputStream bufferOut = new ByteArrayOutputStream(); 10 out = new ObjectOutputStream(bufferOut); 11 12 out.writeObject(obj); 13 14 // 反序列化 15 ByteArrayInputStream bufferIn = new ByteArrayInputStream(bufferOut.toByteArray()); 16 in = new ObjectInputStream(bufferIn); 17 copyObj = in.readObject(); 18 } catch (Exception e) { 19 e.printStackTrace(); 20 throw new RuntimeException(e); 21 }finally{ 22 try{ 23 if(in != null){ 24 in.close(); 25 } 26 if(out!=null){ 27 out.close(); 28 } 29 }catch(IOException e){ 30 throw new RuntimeException(e); 31 } 32 } 33 return copyObj; 34 }?
單元測試:
1 @Test2 public void test() throws CloneNotSupportedException {3 Tire tire = new Tire("black",100);4 Car car = new Car("奔馳","white",tire);5 Car car_copy = (Car)deepClone(car);6 System.out.println("car:"+car.hashCode()+" car.tire:"+car.tire.hashCode());7 System.out.println("car_copy:"+car_copy.hashCode()+" car_copy.tire:"+car_copy.tire.hashCode());8 car_copy.color = "blue";9 System.out.println("car_copy:"+car_copy.color+" car:"+car.color); 10 }?
輸出結果:
car:2019524978 car.tire:855703640 car_copy:1407965019 car_copy.tire:545768040 car_copy:blue car:white從結果集中可以看出是深拷貝是正確的,但是每個類還是需要實現Serializable,好像也不合適吧......
?
優化一下深拷貝方法:將其換成泛型,這樣拷貝出來就不需要強轉了(好吧,其實也沒比上面的方法好到哪去...)
1 @SuppressWarnings("unchecked")2 public static <T> T deepClone(T obj)3 {4 T copyObj = null;5 ObjectOutputStream out = null;6 ObjectInputStream in = null;7 try {8 // 序列化9 ByteArrayOutputStream bufferOut = new ByteArrayOutputStream(); 10 out = new ObjectOutputStream(bufferOut); 11 12 out.writeObject(obj); 13 14 // 反序列化 15 ByteArrayInputStream bufferIn = new ByteArrayInputStream(bufferOut.toByteArray()); 16 in = new ObjectInputStream(bufferIn); 17 copyObj = (T)in.readObject(); 18 } catch (Exception e) { 19 e.printStackTrace(); 20 throw new RuntimeException(e); 21 }finally{ 22 try{ 23 if(in != null){ 24 in.close(); 25 } 26 if(out!=null){ 27 out.close(); 28 } 29 }catch(IOException e){ 30 throw new RuntimeException(e); 31 } 32 } 33 return copyObj; 34 }?
通過序列化與反序列化深拷貝還有更簡單的實現方式,就是需要導個包(拷貝的類也必須實現Serializable接口),當然,我已經為你們準備好了 點擊->org.apache.commons.lang
深拷貝方法:就一行代碼...
1 public Object deepClone(Object obj){ 2 return org.apache.commons.lang.SerializationUtils.clone((Serializable)obj); 3 }?
好了,java的暫時就到這里了,當然對于這兩種方式并不是很滿意...
-------------------------------------------------
C#深拷貝 反射實現下面方法是c#的深拷貝,純反射實現,無需實現任何接口,哦對,需要實體類有個無參的構造方法,簡單使用強大,微軟大法好啊......有需要用到的同學就拿去用吧,目前經過一個幾百W的項目框架中考驗,真的強大實用
1 /// <summary>2 /// 對象拷貝3 /// </summary>4 /// <param name="obj">被復制對象</param>5 /// <returns>新對象</returns>6 private object CopyOjbect(object obj) {7 if (obj == null) {8 return null;9 } 10 Object targetDeepCopyObj; 11 Type targetType = obj.GetType(); 12 //值類型 13 if (targetType.IsValueType == true) { 14 targetDeepCopyObj = obj; 15 } 16 //引用類型 17 else { 18 targetDeepCopyObj = System.Activator.CreateInstance(targetType); //創建引用對象 19 System.Reflection.MemberInfo[] memberCollection = obj.GetType().GetMembers(); 20 21 foreach (System.Reflection.MemberInfo member in memberCollection) { 22 //拷貝字段 23 if (member.MemberType == System.Reflection.MemberTypes.Field) 24 { 25 System.Reflection.FieldInfo field = (System.Reflection.FieldInfo)member; 26 Object fieldValue = field.GetValue(obj); 27 if (fieldValue is ICloneable) 28 { 29 field.SetValue(targetDeepCopyObj, (fieldValue as ICloneable).Clone()); 30 } 31 else 32 { 33 field.SetValue(targetDeepCopyObj, CopyOjbect(fieldValue)); 34 } 35 36 }//拷貝屬性 37 else if (member.MemberType == System.Reflection.MemberTypes.Property) { 38 System.Reflection.PropertyInfo myProperty = (System.Reflection.PropertyInfo)member; 39 40 MethodInfo info = myProperty.GetSetMethod(false); 41 if (info != null) { 42 try { 43 object propertyValue = myProperty.GetValue(obj, null); 44 if (propertyValue is ICloneable) { 45 myProperty.SetValue(targetDeepCopyObj, (propertyValue as ICloneable).Clone(), null); 46 } 47 else { 48 myProperty.SetValue(targetDeepCopyObj, CopyOjbect(propertyValue), null); 49 } 50 } 51 catch (System.Exception ex) { 52 53 } 54 } 55 } 56 } 57 } 58 return targetDeepCopyObj; 59 }public static T DeepClone<T>(T obj) {using (var ms = new MemoryStream()){var formatter = new BinaryFormatter();formatter.Serialize(ms, obj);ms.Position = 0;return (T) formatter.Deserialize(ms);} }
轉載于:https://www.cnblogs.com/WarBlog/p/5646075.html
總結
以上是生活随笔為你收集整理的一种c#深拷贝方式完胜java深拷贝(实现上的对比)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: javascript数组的操作
- 下一篇: POJ 2492 A Bug's Lif