其实克隆对我们来说并不陌生,就像初中学的生物中克隆羊多莉一样,就是一个非常典型的例子。那在java中什么是克隆呢?
java中的克隆就是将一个类的实例的属性逐一复制出来。
克隆实现方式:
1、让要进行克隆的类实现Cloneable接口,否则提示java.lang.CloneNotSupportedException异常。
2、让克隆的类去重写Object的clone()方法。
在java中克隆分为两种:浅度克隆和深度克隆
浅度克隆
浅度克隆只会完全复制一个你要复制的对象出来,但是对于其内部的引用数据类型来说浅度克隆只会复制该对象的一个引用,并不会独立出来只是相当于复制了一份引用;因此修改克隆出来的对象会影响到原对象。
深度克隆
深度克隆会将复制的对象,包括该对象内部的引用数据类型完全的复制一份出来,额外开辟空间去存储这些复制出来的数据;完全独立于原来的对象,修改克隆出来的对象并不会影响到原来的对象。
浅度克隆例子:
实体类:
public class Student implements Cloneable{
private String studentName;
private int studentAge;
public String getStudentName() {
return studentName;
}
public void setStudentName(String studentName) {
this.studentName = studentName;
}
public int getStudentAge() {
return studentAge;
}
public void setStudentAge(int studentAge) {
this.studentAge = studentAge;
}
//该方法为Object中的clone方法,Object原方法为protected访问修饰符,将其改为public
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
测试类:
public class TestMain{
public static void main(String[] args){
//原对象
Student student=new Student();
student.setStudentName("张三");
student.setStudentAge(18);
//克隆出来的对象
Student studentClone;
try {
studentClone = (Student) student.clone();
System.out.println(student==studentClone);
System.out.println(student.getStudentName()==studentClone.getStudentName());
studentClone.setStudentName("李四");
System.out.println(studentClone.getStudentName());
System.out.println(student.getStudentName());
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
输出结果:
false
true
李四
张三
上述结果说明:虽然是复制出来的对象,但是两者并不是同一个对象。
上面的String是引用数据类型,上面我说: 浅度克隆对于类的属性是引用类型的话,并不会独立复制出来一个对象,只是相当于复制了一份引用;因此修改克隆出来的对象会影响到原对象的属性。 但是这里我修改了studentClone的studentName为什么没有影响到原来的student呢?
原因就是:String类型是不可变的,每次修改他的值都会重新分配内存空间,因此这里一开始指向的是同一个对象,但是后面修改了克隆出来的对象之后,并没有影响到原对象。
浅度克隆例子:
班级类
public class Classes implements Serializable,Cloneable{
private int classId;
private String className;
public int getClassId() {
return classId;
}
public void setClassId(int classId) {
this.classId = classId;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
实体类:
//学生实体类
public class Student implements Cloneable,Serializable{
private String studentName;
private int studentAge;
private Classes classes;
public Classes getClasses() {
return classes;
}
public void setClasses(Classes classes) {
this.classes = classes;
}
public String getStudentName() {
return studentName;
}
public void setStudentName(String studentName) {
this.studentName = studentName;
}
public int getStudentAge() {
return studentAge;
}
public void setStudentAge(int studentAge) {
this.studentAge = studentAge;
}
//深度克隆方式
public Object deepClone(){
//将对象序列化到一个位置
File file=new File("C:"+File.separator+"Users"+File.separator+
"Administrator"+File.separator+"Desktop"+File.separator+"student.dat");
ObjectOutputStream os=null;
FileOutputStream fos=null;
FileInputStream fis=null;
ObjectInputStream ois=null;
Student student2=null;
try {
fos=new FileOutputStream(file);
os=new ObjectOutputStream(fos);
os.writeObject(this);
fis=new FileInputStream(file);
ois=new ObjectInputStream(fis);
student2=(Student) ois.readObject();
} catch (SecurityException | IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally {
try {
os.close();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return student2;
}
//浅度克隆方式
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
//深度克隆,但是这种方式不适用于类属性多的情况
/*
@Override
public Object clone() throws CloneNotSupportedException {
Classes cls=this.clone();
cls.setClasses(this.getClasses().clone());
return cls;
}
*/
}
测试类:
public class TestMain{
public static void main(String[] args) throws Exception{
Student student=new Student();
student.setStudentAge(18);
student.setStudentName("张三");
Classes cls=new Classes();
cls.setClassesName("计算机一班");
student.setClasses(cls);
//深度克隆出来的对象
Student student2=(Student) student.clone();
System.out.println(student.getClasses()==student2.getClasses());
student2.getClasses().setClassesName("软件一班");
System.out.println(student2.getClasses().getClassName());
System.out.println(student.getClasses().getClassName());
}
}
输出结果:
false
软件一班
计算机一班
以上就是深度克隆。
深度克隆实现方式:
1、使用序列化实现深度克隆(比较常用,使用起来较为简单),一般搭配ByteArrayInputStream和ByteArrayOutputStream使用,因为该类中包含一个内部缓冲区,可以临时存储读取到的序列化对象。
2、对每一个类实现Cloneable接口,然后实现Object的clone方法,在最外层的的类中,一层层的调用类属性的clone方法以达到深度克隆的效果。(实现较为复杂,不适用引用类型的多情况)