Cloneable接口
1、Cloneable接口
Cloneable
是一个接口,实现这个接口后,可以在类中重写Object
中的clone
方法,然后通过类调用clone
方法进行克隆,如果不实现Cloneable
接口,则会抛出CloneNotSupportedException
异常。Object
中clone
方法:
1
| protected native Object clone() throws CloneNotSupportedException
|
2、Object中的clone方法是一个空的方法,那么他是如何判断类是否实现了Cloneable接口呢?
原因在于这个方法中有一个native
关键字修饰。
native
修饰的方法都是空的方法,但是这些方法都是有实现体的(这里也就间接说明了native
关键字不能与abstract
同时使用。因为abstract
修饰的方法与java
的接口中的方法类似,他显式的说明了修饰的方法,在当前是没有实现体的,abstract
的方法的实现体都由子类重写),只不过native
方法调用的实现体,都是非java
代码编写的(例如:调用的是在jvm
中编写的C
的接口),每一个native
方法在jvm
中都有一个同名的实现体,native
方法在逻辑上的判断都是由实现体实现的,另外这种native
修饰的方法对返回类型,异常控制等都没有约束。
由此可见,这里判断是否实现cloneable
接口,是在调用jvm
中的实现体时进行判断的。
3、为什么要克隆?
clone
方法克隆的对象包含已经修改过的属性,而new
出来的对象是一个新的对象,对应的属性没有值。所以我们还要重新给这个对象赋值。所以当需要一个新的对象来保存当前对象的状态时可以使用clone
方法。
4、如何实现克隆?
- 对象的类实现
Cloneable
接口。
- 覆盖
Object
类的clone()
方法 。
- 在
clone()
方法中调用super.clone()
。
5、浅克隆(ShallowClone)和深克隆(DeepClone)
5.1 浅克隆
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| public class Student implements Cloneable { private String name; private int age; private StringBuffer sex; 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 StringBuffer getSex() { return sex; } public void setSex(StringBuffer sex) { this.sex = sex; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + ", sex=" + sex + '}'; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| public class School implements Cloneable{ private String schoolName; private int stuNums; private Student stu; public String getSchoolName() { return schoolName; } public void setSchoolName(String schoolName) { this.schoolName = schoolName; } public int getStuNums() { return stuNums; } public void setStuNums(int stuNums) { this.stuNums = stuNums; } public Student getStu() { return stu; } public void setStu(Student stu) { this.stu = stu; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public String toString() { return "School{" + "schoolName='" + schoolName + '\'' + ", stuNums=" + stuNums + ", stu=" + stu + '}'; } @Test public void test1() throws CloneNotSupportedException { School s1 = new School(); s1.setSchoolName("实验小学"); s1.setStuNums(100); Student stu1 = new Student(); stu1.setAge(20); stu1.setName("zhangsan"); stu1.setSex(new StringBuffer("男")); s1.setStu(stu1); System.out.println("s1: "+s1+"\ns1的hashcode:"+s1.hashCode()+" s1中schoolName的hashcode:"+s1.getSchoolName().hashCode()+" s1中stu1的hashcode:"+s1.getStu().hashCode()); School s2 = (School)s1.clone(); System.out.println("s2: "+s2+"\ns2的hashcode:"+s2.hashCode()+" s2中schoolName的hashcode:"+s2.getSchoolName().hashCode()+" s2中stu1的hashcode:"+s2.getStu().hashCode()); } }
|
1 2 3 4
| s1: School{schoolName='实验小学', stuNums=100, stu=Student{name='zhangsan', age=20, sex=男}} s1的hashcode:1535128843 s1中schoolName的hashcode:737493093 s1中stu1的hashcode:1567581361 s2: School{schoolName='实验小学', stuNums=100, stu=Student{name='zhangsan', age=20, sex=男}} s2的hashcode:849460928 s2中schoolName的hashcode:737493093 s2中stu1的hashcode:1567581361
|
s1的hashcode不等于s2的hashcode
s1中schoolName的hashcode等于s2中schoolName的hashcode
s1中stu1的hashcode等于s2中stu1的hashcode
5.2 深克隆
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| package dao;
import org.junit.Test;
public class School implements Cloneable{ private String schoolName; private int stuNums; private Student stu; public String getSchoolName() { return schoolName; } public void setSchoolName(String schoolName) { this.schoolName = schoolName; } public int getStuNums() { return stuNums; } public void setStuNums(int stuNums) { this.stuNums = stuNums; } public Student getStu() { return stu; } public void setStu(Student stu) { this.stu = stu; }
@Override protected Object clone() throws CloneNotSupportedException { School school = (School) super.clone(); school.setSchoolName(new String(getSchoolName())); school.setStu((Student) stu.clone()); return school; }
@Override public String toString() { return "School{" + "schoolName='" + schoolName + '\'' + ", stuNums=" + stuNums + ", stu=" + stu + '}'; }
@Test public void test1() throws CloneNotSupportedException { School s1 = new School(); s1.setSchoolName("实验小学"); s1.setStuNums(100); Student stu1 = new Student(); stu1.setAge(20); stu1.setName("zhangsan"); stu1.setSex(new StringBuffer("男")); s1.setStu(stu1); System.out.println("s1: "+s1); System.out.println("s1的hashcode:"+s1.hashCode()+" s1中schoolName的hashcode:"+s1.getSchoolName().hashCode()+" s1中stu1的hashcode:"+s1.getStu().hashCode()); School s2 = (School)s1.clone(); System.out.println("s2: "+s2); System.out.println("s2的hashcode:"+s2.hashCode()+" s2中schoolName的hashcode:"+s2.getSchoolName().hashCode()+" s2中stu1的hashcode:"+s2.getStu().hashCode()); System.out.println("s1.getSchoolName().equals(s2.getSchoolName()):"+s1.getSchoolName().equals(s2.getSchoolName())); System.out.print("s1.getSchoolName()==s2.getSchoolName()"); System.out.println(s1.getSchoolName()==s2.getSchoolName()); }
}
|
1 2 3 4 5 6
| s1: School{schoolName='实验小学', stuNums=100, stu=Student{name='zhangsan', age=20, sex=男}} s1的hashcode:1535128843 s1中schoolName的hashcode:737493093 s1中stu1的hashcode:1567581361 s2: School{schoolName='实验小学', stuNums=100, stu=Student{name='zhangsan', age=20, sex=男}} s2的hashcode:849460928 s2中schoolName的hashcode:737493093 s2中stu1的hashcode:580024961 s1.getSchoolName().equals(s2.getSchoolName()):true s1.getSchoolName()==s2.getSchoolName()false
|
s1的hashcode不等于s2的hashcode
s1中schoolName的hashcode等于s2中schoolName的hashcode
s1中stu1的hashcode不等于s2中stu1的hashcode
s1.getSchoolName().equals(s2.getSchoolName())为true
s1.getSchoolName()==s2.getSchoolName()为false