java 对象复制 反射_java中复制对象通过反射或序列化

在使用缓存读取数据后修改发现缓存被修改。于是找了下复制对象的方法。

关于对象克隆

按我的理解,对象是包含引用+数据。通常变量复制都是将引用传递过去。比如:

1 Person p1 = newPerson();2 Person p2 = p1;

这两句话,创建两个引用p1,p2,但指向共同的内存大堆数据。修改任何一个,另一个的数据也将修改。

直接引用传递测试用例:

1.实体类:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 packagecom.test.java;2

3 importjava.io.Serializable;4

5 /**

6 * Created by Administrator on 2015/9/16.7 */

8 public class Person implementsSerializable{9 /**

10 *11 */

12 private static final long serialVersionUID = 1L;13 intid;14 String name;15 intage;16 Country Country;17

18

19 @Override20 publicString toString() {21 return "Person{" +

22 "id=" + id +

23 ", name='" + name + '\'' +

24 ", age=" + age +

25 ", Country=" + Country +

26 ", hashcode=" + hashCode() +

27 '}';28 }29

30 publicPerson() {31 }32

33 public Person(Country country, intid, String name) {34 Country =country;35 this.id =id;36 this.name =name;37 }38

39 public intgetId() {40 returnid;41 }42

43 public void setId(intid) {44 this.id =id;45 }46

47 publicString getName() {48 returnname;49 }50

51 public voidsetName(String name) {52 this.name =name;53 }54

55 public intgetAge() {56 returnage;57 }58

59 public void setAge(intage) {60 this.age =age;61 }62

63 publiccom.test.java.Country getCountry() {64 returnCountry;65 }66

67 public voidsetCountry(com.test.java.Country Country) {68 this.Country =Country;69 }70

71 public Person(String name,intage){72

73 this.name=name;74 this.age=age;75 }76 }77

78 class Country implementsSerializable{79 /**

80 *81 */

82 private static final long serialVersionUID = 1L;83 intcode;84 String name;85

86 publicCountry() {87 }88

89 public Country(intcode) {90 this.code =code;91 }92

93 public Country(intcode, String name) {94 this.code =code;95 this.name =name;96 }97

98 public intgetCode() {99 returncode;100 }101

102 public void setCode(intcode) {103 this.code =code;104 }105

106 publicString getName() {107 returnname;108 }109

110 public voidsetName(String name) {111 this.name =name;112 }113

114 @Override115 publicString toString() {116 return "Country{" +

117 "code=" + code +

118 ", name='" + name + '\'' +

119 ", hashcode='" + hashCode() + '\'' +

120 '}';121 }122 }

View Code

2.测试类

1 packagecom.test.java;2

3 /**

4 * Created by Administrator on 2015/11/26.5 * 测试对象引用6 */

7 public classTestRef {8

9 public static voidmain(String[] args) {10 Country country = new Country(1,"china");11 Person person = new Person(country,1,"test");12

13 Country country1 =country;14 Person person1 =person;15

16 System.out.println("创建国家 :"+country);17 System.out.println("引用传递国家 :"+country1);18 System.out.println("创建人 :"+person);19 System.out.println("引用传递创建人:"+person1);20

21 }22

23 }

3.打印结果:

a5683564705fd8bf98c7420d97db4b89.png

4.分析:

通过hashcode可以证明,数据实体的地址是相同的。关于基本类型和引用类型的内存关系,可以参考这篇。

同样,通过实现clone接口,重载clone方法,然后调用person.clone()来复制对象的浅克隆是一样。参考这篇。

当然,采用深度克隆的话就可以生成两个完全不同的对象。

然而,我们创建的实体通常是不会实现和覆盖clone的,这种办法只能提前写好对应的类才可以实现。因此,不推荐使用。

那么,我们可以通过反射或者序列化来实现。

关于序列化

参考博客,Java序列化是指把Java对象转换为字节序列的过程;而Java反序列化是指把字节序列恢复为Java对象的过程。字节码可以存储,无状态,而对象在内存中开辟空间,有地址。

由此,可以把对象序列化后反序列化。相当于破碎重组。

前提是:实体类需要实现序列化接口

1.序列化实现对象复制

1 //用序列化与反序列化实现深克隆

2 public staticObject cloneBySer(Object baseObj) {3 Object o = null;4 try{5 ByteArrayOutputStream baos = newByteArrayOutputStream();6 ObjectOutputStream oos = newObjectOutputStream(baos);7 oos.writeObject(baseObj);8 oos.close();9 ByteArrayInputStream bais = newByteArrayInputStream(baos10 .toByteArray());11 ObjectInputStream ois = newObjectInputStream(bais);12 o =ois.readObject();13 ois.close();14 } catch(IOException e) {15 e.printStackTrace();16 } catch(ClassNotFoundException e) {17 e.printStackTrace();18 }19 returno;20 }

2.测试用例:

1 public static voidmain(String[] args) {2 Country country = new Country(1,"china");3 Person person = new Person(country,1,"test");4 //引用传递

5 Country country1 =country;6 Person person1 =person;7 //序列化和反序列化

8 Object person2 =ObjectCopy.cloneBySer(person);9 Object country2 =ObjectCopy.cloneBySer(country);10

11 //person.setAge(12);

12

13 System.out.println("创建国家 :"+country);14 System.out.println("引用传递国家 :"+country1);15 System.out.println("序列化复制国家 :"+country2);16 System.out.println("创建人 :"+person);17 System.out.println("引用传递人:"+person1);18 System.out.println("序列化复制人:"+person2);19

20 }

3.控制台打印:

dd9a12574a305e823cfbbc124f653c2d.png

4.分析

序列化完全实现了对象拷贝。要求:对象都实现序列化,对象hashcode和equals方法默认或者包含全部信息。

通过反射

反射可以复制一个对象的属性,从而实现对象拷贝

反射代码:

1 /**

2 * COPY对象(毛病还是很多的。。)3 *对基本类型的过滤4 *@authorLv95 *@since2010.03.096 * baseObject 要拷贝的对象7 * noCopyClassNames 不深度拷贝的对象属性8 */

9 public staticObject coloneByRef(Object baseObject,10 String... noCopyClassNames) throwsException {11 Object copyObject =baseObject.getClass().newInstance();12 Field[] fields =baseObject.getClass().getDeclaredFields();13 for(Field field : fields) {14 field.setAccessible(true);15 if(checkClassType(field.getType().getName(), noCopyClassNames)) {16 field.set(copyObject, field.get(baseObject));17 } else{18 field.set(copyObject, coloneByRef(field.get(baseObject),19 noCopyClassNames));20 }21 }22 returncopyObject;23 }24

25 public static booleancheckClassType(String className,26 String[] noCopyClassNames) {27 for(String noCopyClassName : noCopyClassNames) {28 if(className.equals(noCopyClassName)) {29 return true;30 }31 }32 return false;33 }

一个失败的用例:

反射用的不太会

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 packagecom.test.reflect;2

3 import java.io.*;4 importjava.lang.reflect.Field;5

6 /**

7 * Created by Administrator on 2015/11/25.8 * 对象复制9 */

10 public classObjectCopy {11

12 public static void main(String[] args) throwsException {13 A baseObject = new A(new B(new C("bString1", "bString2"), 1, 2), newC(14 "cString1", "cString2"));15 A copyObject = (A) coloneByRef(baseObject, "java.lang.Integer",16 "java.lang.String");17

18 System.out.println(baseObject);19 System.out.println(copyObject);20 System.out.println("===================分割线===================");21 System.out.println("原对象修改前:"+baseObject);22 A a =(A)cloneBySer(baseObject);23 System.out.println("复制对象 :"+a);24 a.setC(new C("cchange1","cchange2"));25 System.out.println("复制后修改对象:"+a);26 System.out.println("原对象修改后 :"+baseObject);27

28 }29

30 /**

31 * COPY对象(毛病还是很多的。。)32 *对基本类型的过滤33 *@authorLv934 *@since2010.03.0935 * baseObject 要拷贝的对象36 * noCopyClassNames 不深度拷贝的对象属性37 */

38 public staticObject coloneByRef(Object baseObject,39 String... noCopyClassNames) throwsException {40 Object copyObject =baseObject.getClass().newInstance();41 Field[] fields =baseObject.getClass().getDeclaredFields();42 for(Field field : fields) {43 field.setAccessible(true);44 if(checkClassType(field.getType().getName(), noCopyClassNames)) {45 field.set(copyObject, field.get(baseObject));46 } else{47 field.set(copyObject, coloneByRef(field.get(baseObject),48 noCopyClassNames));49 }50 }51 returncopyObject;52 }53

54 public static booleancheckClassType(String className,55 String[] noCopyClassNames) {56 for(String noCopyClassName : noCopyClassNames) {57 if(className.equals(noCopyClassName)) {58 return true;59 }60 }61 return false;62 }63

64 //用序列化与反序列化实现深克隆

65 public staticObject cloneBySer(Object baseObj) {66 Object o = null;67 try{68 ByteArrayOutputStream baos = newByteArrayOutputStream();69 ObjectOutputStream oos = newObjectOutputStream(baos);70 oos.writeObject(baseObj);71 oos.close();72 ByteArrayInputStream bais = newByteArrayInputStream(baos73 .toByteArray());74 ObjectInputStream ois = newObjectInputStream(bais);75 o =ois.readObject();76 ois.close();77 } catch(IOException e) {78 e.printStackTrace();79 } catch(ClassNotFoundException e) {80 e.printStackTrace();81 }82 returno;83 }84 }85

86 class A implementsSerializable{87 /**

88 *89 */

90 privateB b;91 privateC c;92

93 publicA() {94

95 }96

97 publicA(B b, C c) {98 this.b =b;99 this.c =c;100 }101

102 publicB getB() {103 returnb;104 }105

106 public voidsetB(B b) {107 this.b =b;108 }109

110 publicC getC() {111 returnc;112 }113

114 public voidsetC(C c) {115 this.c =c;116 }117

118

119 @Override120 publicString toString() {121 return "A{" +

122 " b=" + b +

123 ", c=" + c +

124 '}';125 }126 }127

128 class B implementsSerializable{129 /**

130 *131 */

132 privateC c;133 privateInteger int1;134 privateInteger int2;135

136 publicB() {137

138 }139

140 publicB(C c, Integer int1, Integer int2) {141 this.c =c;142 this.int1 =int1;143 this.int2 =int2;144 }145

146 publicC getC() {147 returnc;148 }149

150 public voidsetC(C c) {151 this.c =c;152 }153

154 publicInteger getInt1() {155 returnint1;156 }157

158 public voidsetInt1(Integer int1) {159 this.int1 =int1;160 }161

162 publicInteger getInt2() {163 returnint2;164 }165

166 public voidsetInt2(Integer int2) {167 this.int2 =int2;168 }169

170 @Override171 publicString toString() {172 return "[B: int1 = " + int1 + ",int2 = " + int2 + ",c = " +c173 + ",hashCode = " + hashCode() + "]";174 }175 }176

177 class C implementsSerializable{178 /**

179 *180 */

181 privateString string1;182 privateString string2;183

184 publicC() {185

186 }187

188 publicC(String string1, String string2) {189 this.string1 =string1;190 this.string2 =string2;191 }192

193 publicString getString1() {194 returnstring1;195 }196

197 public voidsetString1(String string1) {198 this.string1 =string1;199 }200

201 publicString getString2() {202 returnstring2;203 }204

205 public voidsetString2(String string2) {206 this.string2 =string2;207 }208

209 @Override210 publicString toString() {211 return "[C: string1 = " + string1 + ",string2 = " +string2212 + ",hashCode = " + hashCode() + "]";213 }214 }

View Code

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值