复制一个对象时,对象的属性使用深拷贝更合理,浅拷贝可能会出一些问题
- 浅拷贝:拷贝了对象的基本类型属性,引用类型属性仅拷贝了引用;
- 深拷贝:不仅仅拷贝了对象的基本类型,引用类型的属性还进行了对象的克隆拷贝 。
//主体类
//学生类
public class Student {
private String name; //name是引用类型
private int age0; //age0是基本类型
private MyInt age; //age是引用类型
private String clazz; //clazz是引用类型
//toString和Getter&Setter方法不再显示
}
//MyInt引用类型代替基本类型int用于测试
public class MyInt {
private int value;
public MyInt(int value) {
this.value = value;
}
//toString和Getter&Setter方法不再显示
}
测试及结果
浅拷贝ShallowCopy
/**
* 浅拷贝方式,拷贝一个学生对象
* @param stu 待拷贝的原对象
* @return 拷贝后的新对象
*/
public static Student shallowCopy(Student stu){
Student newStu = new Student();
newStu.setName(stu.getName());
newStu.setAge0(stu.getAge0());
newStu.setAge(stu.getAge());
newStu.setClazz(stu.getClazz());
return newStu;
}
//测试
public static void testShallowCopy(){
Student stu = new Student();
stu.setName("张三");
stu.setAge0(10);
stu.setAge(new MyInt(25));
stu.setClazz("软件1班");
System.out.println("待拷贝的原学生对象:" + stu);
Student shallowStu = shallowCopy(stu);
System.out.println("浅拷贝出的学生对象:" + shallowStu);
System.out.println("下面开始改变姓名、年龄:");
stu.setName("李四");
stu.setAge0(11);//浅拷贝基本类型
stu.getAge().setValue(28);//只改变了老学生对象的年龄,未改变新拷贝出的学生对象的年龄
//(但是结果二者都显示的同一数值,拷贝后的数值跟拷贝前原数值改变后的数值一样)
System.out.println("改变后,原学生对象:" + stu);
System.out.println("新学生对象:" + shallowStu);
}
结果显示:
待拷贝的原学生对象:Student{name='张三', age0=10, age=MyInt{value=25}, clazz='软件1班'}
浅拷贝出的学生对象:Student{name='张三', age0=10, age=MyInt{value=25}, clazz='软件1班'}值一样,但是是两个对象
下面开始改变年龄:下面开始改变名字、年龄:
改变后,原学生对象:Student{name='李四', age0=11, age=MyInt{value=26}, clazz='软件1班'}
新学生对象:Student{name='张三', age0=10, age=MyInt{value=26}, clazz='软件1班'}
浅拷贝的为新对象,改原对象中的基本类型,浅拷贝的新对象中的基本类型不变(原因:常量变量的本质区别(常量只能赋值一次,变量可以赋值多次;常量在程序运行过程中不能改变,变量可以改变。
浅拷贝后的对象引用类型还是指向原地址(地址占内存),内容不变,基本类型改变
类似浅拷贝只是学习了某人炒股的能力,但是此后该人的盈亏也能体现在你的账户上
深拷贝DeepCopy
内存分开了,费内存,但是安全性高
//补充主体类
public class MyInt {
private int value;
public MyInt(int value) {
this.value = value;
}
@Override
public String toString() {
return "MyInt{" +
"value=" + value +
'}';
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
}
/**
* 深拷贝方式,拷贝一个学生对象
* @param stu 待拷贝的原对象
* @return 拷贝后的新对象
*/
public static Student deepCopy(Student stu){
Student newStu = new Student();
//深拷贝的关键之处,在于引用类型的属性,要指向新的对象!!!
newStu.setName(new String(stu.getName()));
MyInt newAge = new MyInt(stu.getAge().getValue());
newStu.setAge(newAge);
newStu.setClazz(new String(stu.getClazz()));
return newStu;
}
//测试
public static void testDeepCopy(){
Student stu = new Student();
stu.setName("张三");
stu.setAge0(10);
stu.setAge(new MyInt(25));
stu.setClazz("软件1班");
System.out.println("待拷贝的原学生对象:" + stu);
Student shallowStu = deepCopy(stu);
System.out.println("深拷贝出的学生对象:" + shallowStu);
System.out.println("下面开始改变名字、年龄:");
stu.setName("李四");
stu.setAge0(11);
stu.getAge().setValue(28);//只改变了老学生对象的年龄,未改变新拷贝出的学生对象的年龄
System.out.println("改变后,原学生对象:" + stu);
System.out.println("新学生对象:" + shallowStu);//原对象改变值后,新的对象值不会随着原对象的值改变而改变
}
结果显示:
待拷贝的原学生对象:Student{name='张三', age0=10, age=MyInt{value=25}, clazz='软件1班'}
深拷贝出的学生对象:Student{name='张三', age0=0, age=MyInt{value=25}, clazz='软件1班'}
下面开始改变名字、年龄:
改变后,原学生对象:Student{name='李四', age0=11, age=MyInt{value=28}, clazz='软件1班'}
新学生对象:Student{name='张三', age0=0, age=MyInt{value=25}, clazz='软件1班'}
注意
假深拷贝,指向新的对象,但是新的对象往下还是引向同一个对象(深拷贝和原对象指向的对象都是一一对应),字符串和八种包装类不需要深拷贝,因为设计为内容不可变,变的只有引用指向新对象,而不是对象内容的改变。
深拷贝、浅拷贝归根结底其实是基本类型,引用类型,对象的区别