F_JustWei's Studio.

Cloneable接口

字数统计: 1.4k阅读时长: 6 min
2021/04/21 Share

Cloneable接口

1、Cloneable接口

Cloneable是一个接口,实现这个接口后,可以在类中重写Object中的clone方法,然后通过类调用clone方法进行克隆,如果不实现Cloneable接口,则会抛出CloneNotSupportedException异常。Objectclone方法:

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、如何实现克隆?

  1. 对象的类实现Cloneable接口。
  2. 覆盖Object类的clone()方法 。
  3. 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

CATALOG
  1. 1. Cloneable接口
    1. 1.0.1. 1、Cloneable接口
    2. 1.0.2. 2、Object中的clone方法是一个空的方法,那么他是如何判断类是否实现了Cloneable接口呢?
    3. 1.0.3. 3、为什么要克隆?
    4. 1.0.4. 4、如何实现克隆?
    5. 1.0.5. 5、浅克隆(ShallowClone)和深克隆(DeepClone)
      1. 1.0.5.0.1. 5.1 浅克隆
      2. 1.0.5.0.2. 5.2 深克隆