Clonable 是Java内置的接口之一,而它也是一个非常有用的接口。
什么是接口?
接口(英文:Interface),在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明。
在Java开发中,常常会出现对象克隆,对于对象克隆一定会涉及到深拷贝(深复制)和浅拷贝(浅复制):
浅拷贝:
浅拷贝是指拷贝时只拷贝对象本身,而不拷贝对象包含的引用所指向的对象,拷贝出来的对象的所有变量的值都与原来对象的值相同,而所有对其他对象的引用都指向原来的对象。
深拷贝:
深拷贝不仅拷贝对象本身,而且还拷贝对象包含的引用所指向的对象,拷贝出来的对象的所有变量(不包含那些引用其他对象的变量)的值都含有与原来对象的相同的值,那些引用其他对象的变量将指向新复制出来的新对象,而不指向原来的对象。
//本段代码只作为解释说明!!!
class Student implements Cloneable{
public String name;
public Score m = new Score();
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
'}';
}
}
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Student student1 = new Student();
…… …… ……
}
}
在本段代码中,如果想克隆student1所指的对象时,有一个前提:Student必须是可克隆的!并且如果要实现克隆,它一定要实现Cloneable接口。
当我们点击这个接口进入底层代码中(按住Ctrl的同时单击Cloneable),我们可以观察到,这个接口是一个空接口, 其作用为:表示当前对象是可以被克隆的。
//本段代码只作为解释说明!!! @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); }
要想实现“ student1 . clone( ) ” ,就一定要重写其方法!
//本段代码只作为解释说明!!!
class Student implements Cloneable{
…… …… ……
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Test {
public static void main(String[] args) {
Student student1 = new Student();
Student student2 = (Student) student1.clone();
}
}
重写之后我们会发现在方法的后面多了一个异常“ throws CloneNotSupportedException ”,在Java开发中有两种异常,分别是编译时的异常和运行时的异常,而这里涉及到的异常是编译时出现的异常。
遇到这种情况时,我们只需按照重写的方法给予同样的声明即可!
但是,给予声明之后又出现了错误,出现这种错误的原因是什么呢?
那是因为重写的clone方法的返回值为 Object ,而 Object 是所有类的父类 ,但是 Student 是子类,这时就发生了向下转型(向下转型是不安全的!)。所以在这我们要进行强制类型转换,而这样写也是具有一定风险的!
Student student2 = (Student) student1.clone();
这时,我们的代码就可以运行了,具体代码如下:
class Student implements Cloneable{
public String name;
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Student student1 = new Student();
student1.name = "奶油不含糖";
Student student2 = (Student) student1.clone();
System.out.println(student1);
System.out.println(student2);
}
}
运行结果如下:
说到这里,暂时还没实现深浅拷贝,只是可以对自定义类型进行拷贝了。
浅拷贝
class Score implements Cloneable{
public int score = 59;
}
class Student implements Cloneable{
public String name;
public Score s = new Score();
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Student student1 = new Student();
Student student2 = (Student) student1.clone();
System.out.println(student1.s.score);
System.out.println(student2.s.score);
System.out.println("================");
student2.s.score = 99;
System.out.println(student1.s.score);
System.out.println(student2.s.score);
}
}
深拷贝
class Score implements Cloneable{
public int score = 59;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class Student implements Cloneable{
public String name;
public Score s = new Score();
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
// 只是克隆了Student对象
Student student = (Student)super.clone();
// 克隆了 Student对象 里面的Money对象
student.m = (Money) this.m.clone();
return student;
}
}
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Student student1 = new Student();
Student student2 = (Student) student1.clone();
System.out.println(student1.s.score);
System.out.println(student2.s.score);
System.out.println("================");
student2.s.score = 99;
System.out.println(student1.s.score);
System.out.println(student2.s.score);
}
}
当我们修改student2这个引用s的值后,运行之后我们会发现,student1 这个引用访问s的时候,值没有发生变化。所以,这时就是发生了深拷贝。
既然要实现深拷贝,那代码中的 Money 类也要实现 Cloneable 接口 ,并且重写 clone () 方法。
深拷贝示例图(仅供参考):
ending ~ Cloneable 接口的部分相关内容到这里就结束啦~~~