天天看點

java 反射實作深拷貝_一種c#深拷貝方式完勝java深拷貝(實作上的對比)

java 反射實作深拷貝_一種c#深拷貝方式完勝java深拷貝(實作上的對比)

是我自己的原因,還是真的不存在這樣的純用反射實作的深拷貝方式....(c#是有純反射實作的)

但也不能算自己白忙活吧,也找到了其他實作深拷貝的方式(但是每種方式我都覺得并不是太合理,也許是因為c#的方式帶入了吧,最後貼出c#版本純反射實作深拷貝的代碼)

方式一:實作Cloneable接口,重寫clone方法

實體類:一個輪胎類,一個車輛類,車輛中包含輪胎

java 反射實作深拷貝_一種c#深拷貝方式完勝java深拷貝(實作上的對比)

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 }

java 反射實作深拷貝_一種c#深拷貝方式完勝java深拷貝(實作上的對比)

單元測試:

java 反射實作深拷貝_一種c#深拷貝方式完勝java深拷貝(實作上的對比)

1 @Test

2 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 }

java 反射實作深拷貝_一種c#深拷貝方式完勝java深拷貝(實作上的對比)

輸出結果:

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方法:

java 反射實作深拷貝_一種c#深拷貝方式完勝java深拷貝(實作上的對比)

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 }

java 反射實作深拷貝_一種c#深拷貝方式完勝java深拷貝(實作上的對比)

輸出結果:

car:1223737555 car.tire:906199566

car_copy:542081238 car_copy.tire:1133736492

car_copy:blue car:white

這樣最終實作了,但這種方式用到項目中并不是很合适吧,每個需要深拷貝的類,都要實作Cloneable接口,并覆寫其clone方法,遇到引用其他類時候更是需要修改clone方法,要是引用其他類,其他類再引用其他類呢?這不好吧......

方式二:通過序列化與反序列化實作(實作Serializable接口)

實體類:與第一種方式類似,換成實作Serializable接口,去掉clone方法

java 反射實作深拷貝_一種c#深拷貝方式完勝java深拷貝(實作上的對比)

@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;

}

}

java 反射實作深拷貝_一種c#深拷貝方式完勝java深拷貝(實作上的對比)

深拷貝方法:

java 反射實作深拷貝_一種c#深拷貝方式完勝java深拷貝(實作上的對比)

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 }

java 反射實作深拷貝_一種c#深拷貝方式完勝java深拷貝(實作上的對比)

單元測試:

java 反射實作深拷貝_一種c#深拷貝方式完勝java深拷貝(實作上的對比)

1 @Test

2 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 }

java 反射實作深拷貝_一種c#深拷貝方式完勝java深拷貝(實作上的對比)

輸出結果:

car:2019524978 car.tire:855703640

car_copy:1407965019 car_copy.tire:545768040

car_copy:blue car:white

從結果集中可以看出是深拷貝是正确的,但是每個類還是需要實作Serializable,好像也不合适吧......

優化一下深拷貝方法:将其換成泛型,這樣拷貝出來就不需要強轉了(好吧,其實也沒比上面的方法好到哪去...)

java 反射實作深拷貝_一種c#深拷貝方式完勝java深拷貝(實作上的對比)

1 @SuppressWarnings("unchecked")

2 public static 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 }

java 反射實作深拷貝_一種c#深拷貝方式完勝java深拷貝(實作上的對比)

通過序列化與反序列化深拷貝還有更簡單的實作方式,就是需要導個包(拷貝的類也必須實作Serializable接口),當然,我已經為你們準備好了 點選->

深拷貝方法:就一行代碼...

1 public Object deepClone(Object obj){

2 return org.apache.commons.lang.SerializationUtils.clone((Serializable)obj);

3 }

好了,java的暫時就到這裡了,當然對于這兩種方式并不是很滿意...

-------------------------------------------------

C#深拷貝 反射實作

下面方法是c#的深拷貝,純反射實作,無需實作任何接口,哦對,需要實體類有個無參的構造方法,簡單使用強大,微軟大法好啊......有需要用到的同學就拿去用吧,目前經過一個幾百W的項目架構中考驗,真的強大實用

java 反射實作深拷貝_一種c#深拷貝方式完勝java深拷貝(實作上的對比)

1 ///

2 /// 對象拷貝

3 ///

4 /// 被複制對象

5 /// 新對象

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 obj)

{

using (var ms = new MemoryStream())

{

var formatter = new BinaryFormatter();

formatter.Serialize(ms, obj);

ms.Position = 0;

return (T) formatter.Deserialize(ms);

}

}