java中的三种拷贝方式
第一种 基本数据类型:
八大基本数据类型:
A a1 = a2
我们需要理解的是这实际上复制的是引用:
也就是说 a1 和 a2 指向的是同一个对象。因此,当 a1 变化的时候,a2 里面的成员变量也会跟着变化。
第二种 浅拷贝:(复制引用但不复制引用的对象)
创建一个新对象,然后将当前对象的非静态字段复制到该新对象,如果字段是值类型的,那么对该字段执行复制;
如果该字段是引用类型的话,则复制引用但不复制引用的对象。因此,原始对象及其副本引用同一个对象。
Student stu1 = new Student();
stu1.setNumber(12345);
Student stu2 = stu1;
System.out.println("学生1:" + stu1.getNumber()); // 学生1:12345
System.out.println("学生2:" + stu2.getNumber()); // 学生2:12345
但是如果:
stu2.setNumber(54321);
System.out.println("学生1:" + stu1.getNumber()); // 学生1:54321
System.out.println("学生2:" + stu2.getNumber()); // 学生2:54321
因为 stu1 和 stu2 指向内存堆中同一个对象
解决方法:
被复制的类需要实现Clonenable接口
覆盖clone()方法,访问修饰符设为public。方法中调用super.clone()方法得到需要的复制对象,(native为本地方法)
@Override
public Object clone() {
Student stu = null;
try{
stu = (Student)super.clone();
}catch(CloneNotSupportedException e) {
e.printStackTrace();
}
return stu;
}
Student stu1 = new Student();
stu1.setNumber(12345);
Student stu2 = (Student)stu1.clone();
System.out.println("学生1:" + stu1.getNumber()); // 学生1:12345
System.out.println("学生2:" + stu2.getNumber()); // 学生2:12345
stu2.setNumber(54321);
System.out.println("学生1:" + stu1.getNumber()); // 学生1:12345
System.out.println("学生2:" + stu2.getNumber()); // 学生2:54321
但是又如果:
Address addr = new Address();
addr.setAdd("杭州市");
Student stu1 = new Student();
stu1.setNumber(123);
stu1.setAddr(addr);
Student stu2 = (Student)stu1.clone();
System.out.println("学生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd()); // 学生1:123,地址:杭州市
System.out.println("学生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd()); // 学生2:123,地址:杭州市
addr.setAdd("西湖区");
System.out.println("学生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd()); // 学生1:123,地址:西湖区
System.out.println("学生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd()); // 学生2:123,地址:西湖区
原因是浅复制只是复制了addr变量的引用,将值复制后再将引用返回给新对象,并没有真正的开辟另一块空间。
浅拷贝:BeanUtils.copyProperties(executiveSummary, executiveSummaryOld);
第三种 深拷贝:(复制对象和其应用对象)
深拷贝不仅复制对象本身,而且复制对象包含的引用指向的所有对象。
将Address类可复制化
然后在student类中:
@Override
public Object clone() {
Student stu = null;
try{
stu = (Student)super.clone(); //浅复制
}catch(CloneNotSupportedException e) {
e.printStackTrace();
}
stu.addr = (Address)addr.clone(); //深度复制
return stu;
}
// 学生1:123,地址:杭州市
// 学生2:123,地址:杭州市
// 学生1:123,地址:西湖区
// 学生2:123,地址:杭州市
或者序列化实现:
在 Java 语言里深复制一个对象,常常可以先使对象实现 Serializable 接口,然后把对象(实际上只是对象的一个拷贝)写到一个流里,再从流里读出来,便可以重建对象。