什么是克隆
java的克隆类似于对象的复制。
为什么需要克隆
想对一个对象进行处理,且保留原有的对象。 比如根据一个叫张三的学生信息,复制出李四、王五的学生信息,且保留张三的学生信息,然后组装三个学生的List。
java克隆分类
java克隆分为浅克隆与深克隆。
- 浅克隆:只克隆基本类型。引用类型没有克隆,只是新建一个引用,该引用仍然指向原有的对象。比如张三的学生信息中,有老师这个引用对象。克隆张三的学生信息修改成李四的信息后,老师信息并未被克隆,修改张三的老师,李四的老师也被修改。
- 深克隆:基本类型和引用类型都被克隆,引用类型的变量指向的是新克隆的对象。
下面上代码实例,为了保险起见,咱们上三层嵌套。Student里有Teacher,Teacher里有Course。
浅克隆
- Student代码
package org.ludk.clone;
public class Student implements Cloneable{
private String name;
private int age;
private Teacher teacher;
public Student(String name, int age, Teacher teacher) {
this.name = name;
this.age = age;
this.teacher = teacher;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", teacher=" + teacher +
'}';
}
}
- Teacher代码
package org.ludk.clone;
public class Teacher implements Cloneable{
private String name;
private int age;
private Course course;
public Teacher(String name, int age, Course course) {
this.name = name;
this.age = age;
this.course = course;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Course getCourse() {
return course;
}
public void setCourse(Course course) {
this.course = course;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Teacher{" +
"name='" + name + '\'' +
", age=" + age +
", course=" + course +
'}';
}
}
- Course代码
package org.ludk.clone;
public class Course {
private String name;
private int days;
public Course(String name, int days) {
this.name = name;
this.days = days;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getDays() {
return days;
}
public void setDays(int days) {
this.days = days;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Course{" +
"name='" + name + '\'' +
", days=" + days +
'}';
}
}
- 测试类代码
package org.ludk.clone;
public class TestClone implements Cloneable{
public static void main(String[] args) throws CloneNotSupportedException {
Student student=new Student("张三",24,new Teacher("王老师",40,new Course("英语",90)));
Student cloneStudent=(Student) student.clone();
System.out.println("学生张三和克隆学生是否为一个老师");
System.out.println(student.getTeacher()==cloneStudent.getTeacher());
System.out.println("学生张三和克隆学生是否为一个课程");
System.out.println(student.getTeacher().getCourse()==cloneStudent.getTeacher().getCourse());
System.out.println("学生张三的信息");
System.out.println(student);
System.out.println("克隆学生的信息");
System.out.println(cloneStudent);
}
}
- 测试类执行结果
D:\work\java\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=62957:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath D:\work\java\jre\lib\charsets.jar;D:\work\java\jre\lib\deploy.jar;D:\work\java\jre\lib\ext\access-bridge-64.jar;D:\work\java\jre\lib\ext\cldrdata.jar;D:\work\java\jre\lib\ext\dnsns.jar;D:\work\java\jre\lib\ext\jaccess.jar;D:\work\java\jre\lib\ext\jfxrt.jar;D:\work\java\jre\lib\ext\localedata.jar;D:\work\java\jre\lib\ext\nashorn.jar;D:\work\java\jre\lib\ext\sunec.jar;D:\work\java\jre\lib\ext\sunjce_provider.jar;D:\work\java\jre\lib\ext\sunmscapi.jar;D:\work\java\jre\lib\ext\sunpkcs11.jar;D:\work\java\jre\lib\ext\zipfs.jar;D:\work\java\jre\lib\javaws.jar;D:\work\java\jre\lib\jce.jar;D:\work\java\jre\lib\jfr.jar;D:\work\java\jre\lib\jfxswt.jar;D:\work\java\jre\lib\jsse.jar;D:\work\java\jre\lib\management-agent.jar;D:\work\java\jre\lib\plugin.jar;D:\work\java\jre\lib\resources.jar;D:\work\java\jre\lib\rt.jar;D:\work\springcloud-demo\target\classes org.ludk.clone.TestClone
学生张三和克隆学生是否为一个老师
true
学生张三的信息
Student{name='张三', age=24, teacher=Teacher{name='王老师', age=40, course=Course{name='英语', days=90}}}
克隆学生的信息
Student{name='张三', age=24, teacher=Teacher{name='王老师', age=40, course=Course{name='英语', days=90}}}
Process finished with exit code 0
从上面的例子,可以看到学生信息被复制了,但是里面的Teacher信息仍然是一个,仍然是一个对象。
深克隆
深克隆有两种方法。一种是遇到属性为引用类型,则对该引用类型对象进行复制。另一种是用序列化实现深克隆。
第一种方法性能高些,但是实现起来复杂,因为对象里可能还嵌套对象。第二种方法实现起来简单,但是性能差些。
自定义深克隆
- 修改Student的clone方法
@Override
protected Object clone() throws CloneNotSupportedException {
Student cloneStudent= (Student)super.clone();
cloneStudent.setTeacher((Teacher) this.getTeacher().clone());
return cloneStudent;
}
- 再次跑测试类的结果
D:\work\java\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=50882:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath D:\work\java\jre\lib\charsets.jar;D:\work\java\jre\lib\deploy.jar;D:\work\java\jre\lib\ext\access-bridge-64.jar;D:\work\java\jre\lib\ext\cldrdata.jar;D:\work\java\jre\lib\ext\dnsns.jar;D:\work\java\jre\lib\ext\jaccess.jar;D:\work\java\jre\lib\ext\jfxrt.jar;D:\work\java\jre\lib\ext\localedata.jar;D:\work\java\jre\lib\ext\nashorn.jar;D:\work\java\jre\lib\ext\sunec.jar;D:\work\java\jre\lib\ext\sunjce_provider.jar;D:\work\java\jre\lib\ext\sunmscapi.jar;D:\work\java\jre\lib\ext\sunpkcs11.jar;D:\work\java\jre\lib\ext\zipfs.jar;D:\work\java\jre\lib\javaws.jar;D:\work\java\jre\lib\jce.jar;D:\work\java\jre\lib\jfr.jar;D:\work\java\jre\lib\jfxswt.jar;D:\work\java\jre\lib\jsse.jar;D:\work\java\jre\lib\management-agent.jar;D:\work\java\jre\lib\plugin.jar;D:\work\java\jre\lib\resources.jar;D:\work\java\jre\lib\rt.jar;D:\work\springcloud-demo\target\classes org.ludk.clone.TestClone
学生张三和克隆学生是否为一个老师
false
学生张三的信息
Student{name='张三', age=24, teacher=Teacher{name='王老师', age=40, course=Course{name='英语', days=90}}}
克隆学生的信息
Student{name='张三', age=24, teacher=Teacher{name='王老师', age=40, course=Course{name='英语', days=90}}}
Process finished with exit code 0
其实上面的自定义深克隆方法只是深克隆了老师的信息,课程的信息依然为浅克隆。可以自己实现,继续扩展。
java序列化实现深克隆
- Teacer、Student、Course都得实现java.io.Serializable接口
- 修改Student的clone方法
@Override
protected Object clone() throws CloneNotSupportedException {
Student cloneObj = null;
try {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream obs = new ObjectOutputStream(out);
obs.writeObject(this);
obs.close();
ByteArrayInputStream ios = new ByteArrayInputStream(out.toByteArray());
ObjectInputStream ois = new ObjectInputStream(ios);
cloneObj = (Student) ois.readObject();
ois.close();
} catch (Exception e) {
e.printStackTrace();
}
return cloneObj;
}
- 重新跑测试类的结果
D:\work\java\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=55660:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath D:\work\java\jre\lib\charsets.jar;D:\work\java\jre\lib\deploy.jar;D:\work\java\jre\lib\ext\access-bridge-64.jar;D:\work\java\jre\lib\ext\cldrdata.jar;D:\work\java\jre\lib\ext\dnsns.jar;D:\work\java\jre\lib\ext\jaccess.jar;D:\work\java\jre\lib\ext\jfxrt.jar;D:\work\java\jre\lib\ext\localedata.jar;D:\work\java\jre\lib\ext\nashorn.jar;D:\work\java\jre\lib\ext\sunec.jar;D:\work\java\jre\lib\ext\sunjce_provider.jar;D:\work\java\jre\lib\ext\sunmscapi.jar;D:\work\java\jre\lib\ext\sunpkcs11.jar;D:\work\java\jre\lib\ext\zipfs.jar;D:\work\java\jre\lib\javaws.jar;D:\work\java\jre\lib\jce.jar;D:\work\java\jre\lib\jfr.jar;D:\work\java\jre\lib\jfxswt.jar;D:\work\java\jre\lib\jsse.jar;D:\work\java\jre\lib\management-agent.jar;D:\work\java\jre\lib\plugin.jar;D:\work\java\jre\lib\resources.jar;D:\work\java\jre\lib\rt.jar;D:\work\springcloud-demo\target\classes org.ludk.clone.TestClone
学生张三和克隆学生是否为一个老师
false
学生张三和克隆学生是否为一个课程
false
学生张三的信息
Student{name='张三', age=24, teacher=Teacher{name='王老师', age=40, course=Course{name='英语', days=90}}}
克隆学生的信息
Student{name='张三', age=24, teacher=Teacher{name='王老师', age=40, course=Course{name='英语', days=90}}}
Process finished with exit code 0
从上面的例子可以看到,java序列化实现深克隆,那是真的深克隆。
参考
下面是引用https://www.cnblogs.com/xzwblog/p/7230788.html博客的图片
- 深克隆
|