对称拷贝就是将一个对象的属性拷贝到另一个类有着相同类类型的对象中
浅拷贝
浅拷贝就是按位拷贝对象,它会创建一个新的对象,这个对象有着原始对象属性值的一份精确拷贝,如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址值,因此如果其中一个对象改变了这个地址就会影响其他的对象
用demo来测试下
public class ShallowCopyTest {
public static void main(String[] args) {
Stu stu = new Stu("张三","Android开发");
System.out.println("name-->"+stu.getName()+"subjectName="+stu.getSubject().getName());
//拷贝对象
try {
Stu stu1 = (Stu) stu.clone();
System.out.println("拷贝name-->"+stu1.getName());
System.out.println("拷贝subjectName="+stu1.getSubject().getName());
System.out.println("对比二个对象是否相等-->"+(stu==stu1));
System.out.println("对比浅拷贝中的引用类型是否相等-->"+(stu.getSubject()==stu1.getSubject()));
//修改原始数据中的name
stu.setName("李四");
System.out.println("修改原始数据name-->"+stu1.getName());
//修改拷贝的对象中的name属性值
stu1.setName("王五");
System.out.println("修改拷贝后的数据name-->"+stu1.getName());
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
class Subject{
private String name;
public Subject(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class Stu implements Cloneable{
private String name;
private Subject subject;
public Stu(String name, String subject) {
this.name = name;
this.subject = new Subject(subject);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Subject getSubject() {
return subject;
}
public void setSubject(Subject subject) {
this.subject = subject;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
打印结果:
name-->张三subjectName=Android开发
拷贝name-->张三
拷贝subjectName=Android开发
对比二个对象是否相等-->false
对比浅拷贝中的引用类型是否相等-->true
拷贝name-->张三
拷贝name-->王五
从中发现,修改原始数据并不影响拷贝对象中的属性 但是修改拷贝中的对象数据会影响到原始对象中的数据
实现浅拷贝的类要实现Cloneable接口,原始对象和拷贝对象不是同一个对象,其实就是要拷贝的对象中定义的属性是和原始对象一样,然后通过set方法把值赋值给拷贝对象
如果有人问你创建对象有几种方式 你可以回答 1:new. 2:反射 3:克隆
浅拷贝的弊端
当拷贝的对象中如果有引用类型,一旦这个引入类型中的属性变化了,不管是原始对象中的引用类型还是拷贝对象中的引用类型变量发生了改变,二者都会变,因为拷贝和原始对象中的引用类型在内存都是同一份,这个时候就出现了深拷贝
new关键字和反射创建对象的弊端
如果需求是要求创建出一系列相同的对象,那么使用这二者方法创建对象后每次都要通过set或者其他方式去给属性赋值,很麻烦
深拷贝
深拷贝会拷贝所有的属性,并拷贝属性指向的动态内存分配,当对象和它所引用的对象一起拷贝时即是深拷贝,深拷贝比浅拷贝的速度慢而且开销大,因为内存地址要动态创建了而不是共同一份了.
demo如下:
public class DeepCopyTest {
public static void main(String[] args) {
Student student = new Student("张三","Android开发");
Person person1 = student.getPerson();
try {
Student student1 = student.clone();
Person person2 = student1.getPerson();
System.out.println("person-name--"+person1.getName());
System.out.println("person-name--"+person2.getName());
//修改原始对象中的Person 对象中的那么
person1.setName("java 开发");
System.out.println("person-name--"+person1.getName());
System.out.println("person-name--"+person2.getName());
//修改拷贝后的引入对象person中的name
person2.setName("ios 开发");
System.out.println("person-name--"+person1.getName());
System.out.println("person-name--"+person2.getName());
System.out.println("----=="+(person1==person2));
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
class Person implements Cloneable{
private String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
protected Person clone() throws CloneNotSupportedException {
return (Person) super.clone();
}
}
class Student implements Cloneable{
private String name;
private Person person;
public Student(String name, String subject) {
this.name = name;
this.person = new Person(subject);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
@Override
public Student clone() throws CloneNotSupportedException {
Student student = (Student) super.clone();
student.setPerson(person.clone());
return student;
}
}
深拷贝中如果有引用类型的话,这个引用对象也要实现拷贝,但它是浅拷贝,在所包含引用类型的对象中要实现深拷贝.
深拷贝的弊端
如果一个对象中有好几个引用对象的话,每个引用对象都实现Cloneable 并复写clone接口,而且所持有这个引用对象的对象也要修改clone中的方法,如果引用对象过多,对内存消耗也慢慢变大,因为深拷贝的引用对象都是要进行重新在堆内存中分配内存
上面除了使用Object中的clone来实现深拷贝,也可以使用序列化的方式来实现深拷贝,这个比较麻烦,而且这是个IO操作,性能上不高,不写demo了