Cloneable接口中不包含任何的方法!
Cloneable接口的作用:
Object类中的clone()是protected的方法,在没有重写Object的clone()方法且没有实现Cloneable接口的实例上调用clone方法,会报CloneNotSupportedException异常。
实现Cloneable接口仅仅是用来指示Object类中的clone()方法可以用来合法的进行克隆,即实现了Cloneable接口在调用Object的clone方法时不会再报CloneNotSupportedException异常。
clone方法:
类在重写clone方法的时候,要把clone方法的属性设置为public。
克隆
为什么需要克隆?
在实际编程过程中,会需要创建与已经存在的对象A的值一样的对象B,但是是与A完全独立的一个对象,即对两个对象做修改互不影响,这时需要用克隆来创建对象B。通过new一个对象,然后各个属性赋值,也能实现该需求,但是clone方法是native方法,native方法的效率一般远高于非native方法(待了解)。
浅克隆
对于Object类中的clone()方法产生的效果是:现在内存中开辟一块和原始对象一样的内存空间,然后原样拷贝原始对象中的内容。对基本数据类型来说,这样的操作不会有问题,但是对于非基本类型的变量,保存的仅仅是对象的引用,导致clone后的非基本类型变量和原始对象中相应的变量指向的是同一个对象,对非基本类型的变量的操作会相互影响。
结论:
1、克隆一个对象不会调用对象的构造方法。
2、clone()方法有三条规则:1)x.clone() != x; 2)x.clone().getClass() == x.getClass(); 3)一般情况下x.clone().equals(x); 3)不是必须要满足的。
3、对对象基本数据类型的修改不会互相影响,浅克隆对对象非基本数据类型的修改会相互影响,所以需要实现深克隆。
深克隆
深克隆除了克隆自身对象,还对其非基本数据类型的成员变量克隆一遍。
深克隆的步骤:
1、首先克隆的类要实现Cloneable接口和重写Object的clone()方法。
2、在不引入第三方jar包的情况下,可以使用两种方法:1)先对对象进行序列化,紧接着马上反序列化 2)先调用super.clone()方法克隆出一个新对象,然后手动给克隆出来的对象的非基本数据类型的成员变量赋值。
在数据结构比较复杂的情况下,序列化和反序列化可能实现起来简单,方法2)实现比较复杂。经测试2)会比1)的执行效率高。
序列化实现深克隆的例子
package com.zxy.java.lang;
import java.io.Serializable;
/**
* @author
* @version 1.0
* description:Student类,Teacher类中的成员变量类型,也需要实现序列化
* date: 2018-06-29 15:04
*/
public class Student implements Serializable{
private String id;
private String name;
public Student(String id, String name) {
this.id = id;
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setId(String id) {
this.id = id;
}
public String getId() {
return id;
}
}
package com.zxy.java.lang;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
/**
* @author
* @version 1.0
* description:Teacher类,用序列化和反序列化实现深克隆,clone方法中对象写到内存中,再从内存中读出
* date: 2018-06-29 15:26
*/
public class Teacher implements Serializable, Cloneable{
private String tid; //教工编码
private String name; //姓名
private List<Student> student; //学生
public void setTid(String tid) {
this.tid = tid;
}
public String getTid() {
return tid;
}
public void setStudent(List<Student> student) {
this.student = student;
}
public List<Student> getStudent() {
return student;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public Object clone() throws CloneNotSupportedException {
Object t = null;
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(this);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
t = ois.readObject();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e2) {
e2.printStackTrace();
}
return t;
}
public static void main(String[] args) throws CloneNotSupportedException{
Teacher teacher = new Teacher();
teacher.setTid("111");
teacher.setName("张**");
List<Student> stus = new ArrayList<>();
Student student = new Student("001", "朱**");
stus.add(student);
teacher.setStudent(stus);
Teacher teacher1 = (Teacher) teacher.clone();
System.out.println(teacher1.getName());
System.out.println(teacher1.getTid());
List<Student> ss = teacher1.getStudent();
Student s = ss.get(0);
s.setId("002");
s.setName("朱**222");
System.out.println(teacher.getStudent().get(0).getId() + "-" + teacher.getStudent().get(0).getName());
System.out.println(teacher1.getStudent().get(0).getId() + "-" + teacher1.getStudent().get(0).getName());
}
}