关于Clone克隆对象的讲解
本人以前被问到有哪些方法创建对象
我回答,new,反序列化,反射。后来才知道还有个克隆(汗颜)
克隆clone,这个方法我经常在object类中看到,之前也一直没关注过它,直到最近看克隆的时候才开始关注
什么是克隆?
这得先讲解下new一个对象的原理,简单来说就是先在内存中分配一个对象(所要new的对象)大小的内存,然后通过构造方法往这个内存里面注入值,然后这个对象的引用
而clone与new相似,也是先在内存中分配一个对象大小的内存,然后根据原对象的值赋值给新对象。然后返回这个对象的引用
而要实现clone必须重写Object类中的clone方法,且实现Cloneable否则报CloneNotSupportedException异常。这个接口是个标记接口,即使接口内部没有任何方法
而clone克隆又分浅拷贝和深拷贝
浅拷贝的意思是简单的赋值数据,而不重新开辟新的对象,super.clone()直接调用这个方法为浅拷贝
深拷贝的意思的,先开辟对象在从原来对象中获取数据,赋值给新开辟的对象中
public class Person implements Cloneable{
public String name;
public int age;
/**
* public 开放权限,从object继承过来是protected
* 若是类中有对象属性,应该实现深拷贝(先开辟对象在复制值),类中只有简单类型则直接调用父类super.clone()
*/
@Override
public Object clone() throws CloneNotSupportedException {
/*
* 1、执行super.clone()方法 先从内存中开辟一个对象的空间,
* 在从原来对象中赋值给该对象,简单值传递。传递引用变量,这意味着都是浅拷贝
* 这就意味着原来的对象的复杂类型的值发生改变则clone的对象里面的相同属性也将发送改变
* 2、但是String除外String是无法改变对象内值的复杂类型,
* String类型发送改变也只是在内存中新创建一个字符串对象,将该对象的引用返回而原字符串还存在内存中!
*
*/
Person person = (Person)super.clone();//返回一个浅拷贝的对象
person.name = new String(((Person)super.clone()).name);//手动new出新的对象出来并且赋值
//实际上String类型并不需要new一个新对象,因为无法改变String的值,所以无法导致原数据的改变而影响现在数据
return person;
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
//需要克隆的对象必须实现Cloneable接口,否则报CloneNotSupportedException
public class School implements Cloneable{
public Person person;
public int number;
/**
* 实现克隆的对象中如果有其他类的对象,需要调用其他类的clone方法
*/
@Override
public Object clone() throws CloneNotSupportedException {
School school = (School)super.clone();
school.person = (Person)person.clone();
return school;
}
public School(Person person, int number) {
this.person = person;
this.number = number;
}
}
public class CloneTest {
public static void main(String[] args) {
Person p = new Person("wxt",12);
try {
Person p1 = (Person) p.clone();
System.out.println(p1==p); // false 不是相同对象
System.out.println(p1.name.equals(p.name)); //true 值相同
System.out.println(p1.name==p.name); //false name属性不是相同对象
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
/************************************/
System.out.println("/************************************/"); // false 不是相同对象
School school = new School(p,55);
try {
School s1 = (School)school.clone();
System.out.println(school==s1); // false 不是相同对象
System.out.println(school.person.name.equals(s1.person.name)); //true person属性的name值相同
System.out.println(school.person==s1.person); //false person属性不是相同对象
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}