Java中的可克隆接口
Java.lang.Cloneable 接口是一个标记接口。它是在JDK 1.0中引入的。Object类中包含一个clone()方法。实现 Cloneable 接口的类可以使Object.clone()方法合法,从而使字段为字段的复制成为可能。这个接口允许实现类克隆其对象,而不是使用 new 运算符进行创建。
声明
public interface Cloneable
示例1: 以下程序说明:如果你尝试克隆一个没有实现Cloneable接口的对象,那么会引发CloneNotSupportedException,你可能需要处理它。
// Java program to Demonstrate the
// application of Cloneable interface
import java.io.*;
import java.util.*;
class Student {
// attributes of Student class
String name = null;
int id = 0;
// default constructor
Student() {}
// parameterized constructor
Student(String name, int id)
{
this.name = name;
this.id = id;
}
public static void main(String[] args)
{
// create an instance of Student
Student s1 = new Student("Ashish", 121);
// Try to clone s1 and assign
// the new object to s2
Student s2 = s1.clone();
}
}
输出:
prog.java:28: error: incompatible types: Object cannot be converted to Student
Student s2 = s1.clone();
^
1 error
示例2: 以下代码说明了使用克隆接口使Object.clone()方法合法的正确用法。实现此接口的类应该重写Object.clone()方法(它是受保护的),以便它可以被调用。
// Java program to illustrate Cloneable interface
import java.lang.Cloneable;
// By implementing Cloneable interface
// we make sure that instances of class A
// can be cloned.
class A implements Cloneable {
int i;
String s;
// A class constructor
public A(int i, String s)
{
this.i = i;
this.s = s;
}
// Overriding clone() method
// by simply calling Object class
// clone() method.
@Override
protected Object clone()
throws CloneNotSupportedException
{
return super.clone();
}
}
public class Test {
public static void main(String[] args)
throws CloneNotSupportedException
{
A a = new A(20, "GeeksForGeeks");
// cloning 'a' and holding
// new cloned object reference in b
// down-casting as clone() return type is Object
A b = (A)a.clone();
System.out.println(b.i);
System.out.println(b.s);
}
}
输出:
20
GeeksForGeeks
使用clone()方法进行深度复制
Deep Object Cloning 就像通过从原始对象复制字段到克隆对象来创建原始对象的精确副本一样。为克隆对象分配了单独的内存,其中复制了原始对象内容。clone()方法可以基于其实现创建原始对象的浅层和 深层复制 。深层复制创建具有与原始对象相同内容的新内存。这就是为什么在克隆之后更改原始对象的内容时,更改不会反映在克隆对象中。还有一些副本类型,例如深层、浅层和惰性。下面的代码使用clone()方法解释了深层副本。
//一个Java程序用于演示使用clone()进行深层副本
import java.util.ArrayList;
//由Test2包含的Test类对象引用
class Test {
int x, y;
}
// 包含一个Test的引用,并使用深拷贝实现clone。
class Test2 implements Cloneable {
int a, b;
Test c = new Test();
public Object clone() throws CloneNotSupportedException
{
//将浅层副本分配给新的引用变量t
Test2 t = (Test2)super.clone();
t.c = new Test();
//为字段c创建一个新对象,并将其分配给获得的浅层副本,
//使其成为深层副本
return t;
}
}
public class Main {
public static void main(String args[])
throws CloneNotSupportedException
{
Test2 t1 = new Test2();
t1.a = 10;
t1.b = 20;
t1.c.x = 30;
t1.c.y = 40;
Test2 t3 = (Test2)t1.clone();
t3.a = 100;
//对t2的原始类型进行更改不会
//反映在t1字段中
t3.c.x = 300;
//在t2的对象类型字段中进行更改不会
//反映在t1中(深层副本)
System.out.println(t1.a + " " + t1.b + " " + t1.c.x
+ " " + t1.c.y);
System.out.println(t3.a + " " + t3.b + " " + t3.c.x
+ " " + t3.c.y);
}
}
输出
10 20 30 40
100 20 300 0
注意: 此接口不包含clone方法。因此,仅通过实现此接口就无法克隆对象。即使通过反射调用clone方法,也不能保证它会成功。
参考: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Cloneable.html
极客教程