简介
在我们日常的工作中,会进行一些Java基础知识的学习,在前段时间学习的就是有关Java中的克隆,下面我们对克隆做简单的介绍。
正文
Java中的克隆分为两种,一种我们叫做浅克隆(浅复制),一种叫做深克隆(深复制)
1.浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。
第一步:定义一个student类,并实现Cloneable接口(teacher类同student相同,不贴代码)
//克隆的对象必须实现Cloneable这个接口,而且需要重写clone方法
public class Student implements Cloneable {private int age;//定义为private说明这个成员变量只能被被当前类中访问,如果外部需要获得,那么就只能通过getAge方法进行获取private String name;private Teacher teacher;public int getAge(){return age;}public void setAge(int age){this.age = age;}public String getName(){return name;}public void setName(String name){this.name = name;}public Teacher getTeacher() {return teacher;}public void setTeacher(Teacher teacher) {this.teacher = teacher;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Student student = (Student) o;return age == student.age &&Objects.equals(name, student.name) &&Objects.equals(teacher, student.teacher);}@Overridepublic int hashCode() {return Objects.hash(age, name, teacher);}@Overridepublic Object clone() throws CloneNotSupportedException{Object object = super.clone();return object;}
}
第二步:创建一个调用的测试类:
public class Demo {public static void main(String[] args) {try{Student student = new Student();student.setAge(18);student.setName("这就是我");Teacher teacher = new Teacher();teacher.setAge(55);teacher.setName("我是老师");student.setTeacher(teacher);Student student2 = (Student)student.clone();//这个是调用下面的那个方法,然后把这个这个对象Clone到studentSystem.out.println("Age:" + student2.getAge() + " " + "Name:" + student2.getName());student.setName("我还是那个我");teacher.setName("我还是那个老师");System.out.println("teacherName:"+student2.getTeacher().getName());}catch (Exception e){e.printStackTrace();System.out.println("报错了");}}
}
通过上面的代码,我们可以得到我们上面对“浅克隆”的描述,指向原有的内存地址。结果如下:
我们通过对上面的student中的属性先进行赋值,然后进行clone,然后在重新为teacher中的name赋值,为student中的name赋值,我们得到上面的结果“非基本类型属性,还是指向原来的内存地址”,这样会导致我们在使用过程中出现数据错乱的情况。
2.深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。
第一步:还是创建上面的student类,只是重写上面的clone()方法(这里只贴重写的clone方法)
@Overridepublic Object clone() throws CloneNotSupportedException{Student o = null;try {o = (Student) super.clone();} catch (CloneNotSupportedException e) {System.out.println(e.toString());}o.teacher = (Teacher) teacher.clone();return o;}
第二步:创建一个调用的测试类(这里只贴main()方法)
public static void main(String[] args) {try{Student student = new Student();student.setAge(18);student.setName("这就是我");Teacher teacher = new Teacher();teacher.setAge(55);teacher.setName("我是老师");student.setTeacher(teacher);Student student2 = (Student)student.clone();student.setName("我还是那个我");teacher.setName("我还是那个老师");System.out.println("Age:" + student2.getAge() + " " + "Name:" + student2.getName());System.out.println("teacherName:"+student2.getTeacher().getName());}catch (Exception e){e.printStackTrace();System.out.println("报错了");}}
我们还是进行浅克隆中的赋值操作,克隆完成后,对原对象进行赋值,修改源对象的内容,但是我们会发现,我们得到的结果没有发生变化,下面是操作结果
总结:
实现Cloneable接口并重写clone接口只能进行浅克隆。但是如果类的引用类型属性(以及属性的引用类型属性)都进行浅克隆,直到没有引用类型属性或者引用类型属性为null时,整体上就形成了深克隆。既对象的引用类型属性和属性的应用类型属性都实现Coloneable,重写clone方法并在clone方法中进行调用。
在选择深克隆方法时,应根据对象的复杂成都,如引用类型属性是否有多层引用类型属性关系。如果对象只有一层或者两层引用类型的属性,选择上面提到的方法较为方便,反之则使用对象流。