刚接触 clone 的人会觉得奇怪,当克隆一个对象时,除了声明 public Object clone() 方法之外,还需要实现 Cloneable 接口。而Cloneable 是一个没有声明任何方法的空接口。
既然如此,为何不在Cloneable 接口中声明clone 方法:
public Object clone() throws CloneNotSupportedException;
Java API 没有这样做,我们可以手动实现:
//自定义接口
public interface MyCloneable extends Cloneable{
public Object clone() throws CloneNotSupportedException;
}
如此,我们可以将所有需要实现克隆的类统一对待。
public class TestClone implements MyCloneable {
int i;
TestClone(int i) {
this.i = i;
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
public static void main(String[] args) {
TestClone t1 = new TestClone(10);
TestClone t2 = (TestClone) cloneObject(t1);
t1.i = 88;
System.out.println(t1.i); //88
System.out.println(t2.i); //10
}
//将所有可克隆对象统一对待,调用其 clone 方法。
public static Object cloneObject(MyCloneable mc){
try {
return mc.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
}
Java 机制为所有对象提供了clone 方法,又出于安全考虑,将它设置为保护属性:
package java.lang;
public class Object{
//...
protected native Object clone() throws CloneNotSupportedException;
//...
}
尽管如此,我们还是可以通过反射(reflect)机制在任意对象中调用该方法:
//没有声明clone 方法的类
class NotDeclareCloneMethod implements Cloneable {
int i;
public String toString() {
return "" + i;
}
}
public class Main {
public static void main(String[] args) throws NoSuchMethodException,
SecurityException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
NotDeclareCloneMethod n = new NotDeclareCloneMethod();
n.i = 77;
java.lang.reflect.Method m = Object.class.getDeclaredMethod("clone");//得到clone 方法
m.setAccessible(true); //获得访问权限
Object o = m.invoke(n); //调用
n.i = 99;
System.out.println(n); //99
System.out.println(o); //77
}
}
这样一来,对象能否被克隆,就与声明类是否声明clone 方法无关,保护对象不被克隆只能在Object.clone() 方法中进行,API 采用的是判断是否实现空接口Cloneable 的方法:如果被克隆对象所属类没有实现该接口,则抛出NotDeclareCloneMethod 异常。
要防止类被克隆有两种方式:1、声明final 类;2、重写clone 方法。
final class NotCloneable1{
//不被继承,也无法被克隆
}
class NotCloneable2{
//子类即使实现了Cloneable ,调用clone() 时,无法经过这里调用Object 的clone 方法
@Override
protected Object clone() throws CloneNotSupportedException{
throw new CloneNotSupportedException();
}
}
回到标题,
Cloneable 接口为何不声明clone 方法?因为clone 方法不是必要。通过下面工具可以轻松克隆Cloneable 对象:
import java.lang.reflect.Method;
public class CloneUtil {
@SuppressWarnings("unchecked")
public static <T extends Cloneable> T clone(T obj) {
T rtn = null;
try {
Method method = Object.class.getDeclaredMethod("clone");
method.setAccessible(true);
rtn = (T) method.invoke(obj);
} catch (Throwable t) {
//继承链中的clone() 方法被重写
t.printStackTrace();
}
return rtn;
}
}
分享到:
相关推荐
2. **重写`clone()`方法**:默认的`clone()`方法是受保护的,为了在类外部使用,我们需要将其声明为公共的(`public`)。同时,通常需要对内部的非基本类型属性进行深拷贝,以确保完整独立的副本。 下面是一个简单...
需要注意的是,Cloneable接口并不是 Clone()方法的调用点,克隆行为的实现仍然需要在具体的类中通过重写clone()方法来完成。 知识点三:clone()方法的工作原理 clone()方法是Object类中的一个受保护方法,它会返回...
如果需要在不同包的类中使用`clone`,需要将它声明为`public`。 2. 避免空指针异常:在覆盖`clone`方法时,确保检查并处理可能的空引用,以防止`NullPointerException`。 3. 类的可变性:如果类的对象是可变的(即...
通常,为了能够正确地克隆一个对象,你需要确保类的每个属性都是可克隆的,并且覆盖`Object`类中的`clone()`方法,声明为`protected`或`public`,因为默认它是`protected`的。 ```java public class MyClass ...
// 假设User类也实现了Cloneable接口 return clonedAccount; } ``` #### 七、何时选择深拷贝 并非所有的引用类型都需要进行深拷贝。如果引用的对象是不可变的(如`String`),则无需深拷贝,因为它们的状态无法...
clone()方法默认是protected类型的,这意味着它不能在类外直接调用,除非在类中将其声明为public。所有类都继承自Object类,因此所有Java类都可以调用clone()方法,但前提是类必须实现Cloneable接口,否则会抛出...
在Java的Object类中,clone()方法被声明为protected,这限制了其直接使用。这样做是为了防止任意对象被克隆,只允许特定类的实例进行克隆。如果一个类想要实现克隆,它需要实现Cloneable接口,并重写clone()方法,...
1. 需要为类实现`Cloneable`接口,并重写`clone()`方法,这可能会增加类的复杂性。 2. 如果对象包含复杂的关联结构,实现深拷贝可能会很困难。 3. 当对象包含不可克隆的成员变量时,需要特殊处理。 在实际应用中,...
总的来说,Map接口提供了一种高效的方式来存储和检索键值对数据,可变参数简化了函数调用,Cloneable接口支持对象的克隆,而多线程则为并发编程提供了基础。理解和掌握这些知识点对于Java开发至关重要。
`Cloneable`接口本身不包含任何方法,只是一个标记接口,表明该类的对象可以被克隆。`Object`类的`clone()`方法会创建一个新的对象,并尽可能地复制原对象的数据。如果一个对象没有实现`Cloneable`接口,调用`clone...
在Java中,原型模式通过实现Cloneable接口和覆盖clone()方法来复制对象,避免了使用构造函数进行深度复制的复杂性。接下来我们将深入探讨Java原型模式的核心概念、实现方式以及实际应用。 ### 核心概念 1. **原型...
2. **protected修饰符**:默认情况下,`clone()`方法被声明为`protected`,这意味着只有同一包内的类或者该类的子类可以直接调用。如果要从其他包的类中克隆对象,你需要将`clone()`方法的访问修饰符更改为`public`...
但是需要注意的是,`clone()`方法默认是保护类型的,需要在类中显式地声明为公开的(public)并进行适当的实现。 在描述中提到的“原型模式类”可能是一个包含多个类的项目,这些类可能是为了演示如何使用原型模式...
10. **`Cloneable`接口和`clone`方法**:`Cloneable`接口表明一个类支持克隆。实现此接口的类可以覆盖`Object`类的`clone`方法,创建对象的副本。浅复制仅复制对象的引用,而深复制则复制对象及所引用的对象。在实验...
1. **定义原型接口或抽象类**:在Java中,虽然不强制,但通常会定义一个接口`Prototype`,声明`clone()`方法。 ```java public interface Prototype { Prototype clone(); } ``` 2. **实现原型接口**:为需要克隆...
为了支持 `clone` 操作,类必须实现 `Cloneable` 接口。实现 `clone` 方法时,通常会调用父类 `Object` 的 `clone` 方法,并强制转换类型。 示例代码展示了如何在 `Person03` 类中实现 `clone` 方法: ```java ...
当一个对象实现了 `Cloneable` 接口,就可以通过 `Object` 类的 `clone()` 方法创建该对象的副本。不过需要注意的是,`clone()` 方法默认只是浅复制,对于复杂的数据结构,可能需要重写 `clone()` 方法实现深复制。 ...
需要注意的是,`clone()`方法默认是保护权限的,因此需要在类中显式地声明为公共方法。 例如: ```java public class Prototype implements Cloneable { private String someField; // 省略getter和setter @...