对象克隆
Object类中定义了一个clone方法
protected native Object() throws cloneNotSupportedException;
//native方法用于声明一个非java语言实现的代码,供java程序调用
//因为java语言程序是运行在JVM上的,如果要访问底层与操作系统相关的方式就没有办法了
//只能通过如C语言高进系统的语言来实现
浅克隆
- 被赋值的类需要实现
Cloneable
接口,该接口也是旗标接口,不包含任何方法 - 在当前类中覆盖
clone
方法,将访问限定词设置为public
。具体实现则是通过调用super.clone()
实现的
主类Person
Person类中包含值属性和对象属性
public class Person implements Cloneable {
private long id;
private Student stu;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public Student getStu() {
return stu;
}
public void setStu(Student stu) {
this.stu = stu;
}
@Override
public String toString() {
return "Person{" + "id=" + id + ", stu=" + stu + '}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
引用对象类Student
public class Student {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" + "name='" + name + '}';
}
}
浅克隆测试类Test
public class Test{
public static void main(String[] args) throws CloneNotSupportedException {
Person pClone = (Person)person.clone();//进行克隆对象
System.out.println("修改前pClone:"+pClone);
System.out.println("修改前person:"+person);
pClone.setId(2);
System.out.println("修改值引用后的pClone:"+pClone);
System.out.println("修改值引用后的person:"+person);
stu.setName("Hanmeimei");
person.setStu(stu);
System.out.println("修改对象引用后的pClone:"+pClone);
System.out.println("修改对象引用后的person:"+person);
}
}
//修改前pClone:Person{id=1, stu=Student{name='Liming'}}
//修改前person:Person{id=1, stu=Student{name='Liming'}}
//修改值引用后的pClone:Person{id=2, stu=Student{name='Liming'}}
//修改值引用后的person:Person{id=1, stu=Student{name='Liming'}}
//修改对象引用后的pClone:Person{id=2, stu=Student{name='Hanmeimei'}}
//修改对象引用后的person:Person{id=1, stu=Student{name='Hanmeimei'}}
//显而易见,修改对象引用中对象的属性,两个Person对象中的stu对象引用都进行了变化
浅克隆只会克隆引用类型属性的地址,并不是克隆引用类型属性。将会出现源对象和克隆对象的属性指向同一个对象属性。在浅克隆中当对象被复制时,他本身和其中包含的值类型的成员属性,而引用类型的成员对象并没有复制。
深克隆
在深克隆中无论原型对象的成员变量是值类型还是应用类型,都将复制一份给克隆对象
在java中实现深克隆有两种方案:
- 可以覆盖Object的clone方法实现
- 也可以通过实现序列化来实现
主类Person
public class Person implements Cloneable, Serializable {
private static final long serialVersionUID = 1L;
private long id;
private Student stu;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public Student getStu() {
return stu;
}
public void setStu(Student stu) {
this.stu = stu;
}
@Override
public String toString() {
return "Person{" + "id=" + id + ", stu=" + stu + '}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
try {
//序列化
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
//写入到当前类(也可以写入到文件)
oos.writeObject(this);
//反序列化
ByteArrayInputStream bais = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
return (Object) ois.readObject();
} catch (Exception e) {
e.printStackTrace();
System.out.println("克隆出错"+e.getStackTrace());
return null;
}
}
}
引用对象类Student
public class Student implements Cloneable, Serializable {
private static final long serialVersionUID = 1L;
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Student{" + "name='" + name + '}';
}
}
深克隆测试类Test
public class Test{
public static void main(String[] args) throws CloneNotSupportedException {
Person person = new Person();//创建一个Person对象
Student stu = new Student();//创建Person中的引用对象
person.setId(1);
stu.setName("Liming");
person.setStu(stu);
Person pClone = (Person)person.clone();//进行克隆对象
System.out.println("修改前pClone:"+pClone);
System.out.println("修改前person:"+person);
pClone.setId(2);
System.out.println("修改值引用后的pClone:"+pClone);
System.out.println("修改值引用后的person:"+person);
stu.setName("Hanmeimei");
person.setStu(stu);
System.out.println("修改对象引用后的pClone:"+pClone);
System.out.println("修改对象引用后的person:"+person);
}
}
//修改前pClone:Person{id=1, stu=Student{name='Liming'}}
//修改前person:Person{id=1, stu=Student{name='Liming'}}
//修改值引用后的pClone:Person{id=2, stu=Student{name='Liming'}}
//修改值引用后的person:Person{id=1, stu=Student{name='Liming'}}
//修改对象引用后的pClone:Person{id=2, stu=Student{name='Liming'}}
//修改对象引用后的person:Person{id=1, stu=Student{name='Hanmeimei'}}
//显而易见,修改了原类的引用对象的属性时(由stu.setName('LIMing')修改为'Hanmeimei'),克隆类对象的引用对象的属性并未发生变化依旧是
深克隆和浅克隆的区别
- 深克隆:对当前对象进行克隆,并克隆该对象所包含的8中基本数据类型和String类型属性(拷贝一份该对象并重新分配内存,即产生了新的对象);但如果被克隆的对象中包含除8中数据类型和String类型外的其他类型的属性,浅克隆并不会克隆这些属性(即不会为这些属性分配内存,而是引用原来对象中的属性)。
- 深克隆:深克隆是在浅克隆的基础上,递归地克隆除8种基本数据类型和String类型外的属性(即为这些属性重新分配内存而非引用原来对象中的属性)