`
piaoshen1
  • 浏览: 5154 次
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

Cloneable 接口为何不声明clone 方法?

阅读更多
刚接触 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;
	}
}
分享到:
评论

相关推荐

    clone()方法示例(对象克隆)_对象克隆_nervouse78_源码

    2. **重写`clone()`方法**:默认的`clone()`方法是受保护的,为了在类外部使用,我们需要将其声明为公共的(`public`)。同时,通常需要对内部的非基本类型属性进行深拷贝,以确保完整独立的副本。 下面是一个简单...

    编程语言java对象复制.pdf

    需要注意的是,Cloneable接口并不是 Clone()方法的调用点,克隆行为的实现仍然需要在具体的类中通过重写clone()方法来完成。 知识点三:clone()方法的工作原理 clone()方法是Object类中的一个受保护方法,它会返回...

    java clone

    如果需要在不同包的类中使用`clone`,需要将它声明为`public`。 2. 避免空指针异常:在覆盖`clone`方法时,确保检查并处理可能的空引用,以防止`NullPointerException`。 3. 类的可变性:如果类的对象是可变的(即...

    clone()示例源码

    通常,为了能够正确地克隆一个对象,你需要确保类的每个属性都是可克隆的,并且覆盖`Object`类中的`clone()`方法,声明为`protected`或`public`,因为默认它是`protected`的。 ```java public class MyClass ...

    java_clone用法

    // 假设User类也实现了Cloneable接口 return clonedAccount; } ``` #### 七、何时选择深拷贝 并非所有的引用类型都需要进行深拷贝。如果引用的对象是不可变的(如`String`),则无需深拷贝,因为它们的状态无法...

    2型模式-MOOC课程内容.pdf

    clone()方法默认是protected类型的,这意味着它不能在类外直接调用,除非在类中将其声明为public。所有类都继承自Object类,因此所有Java类都可以调用clone()方法,但前提是类必须实现Cloneable接口,否则会抛出...

    浅析Java中clone()方法浅克隆与深度克隆

    在Java的Object类中,clone()方法被声明为protected,这限制了其直接使用。这样做是为了防止任意对象被克隆,只允许特定类的实例进行克隆。如果一个类想要实现克隆,它需要实现Cloneable接口,并重写clone()方法,...

    java 原型模式

    1. 需要为类实现`Cloneable`接口,并重写`clone()`方法,这可能会增加类的复杂性。 2. 如果对象包含复杂的关联结构,实现深拷贝可能会很困难。 3. 当对象包含不可克隆的成员变量时,需要特殊处理。 在实际应用中,...

    day16-Map、可变参数、Cloneable.pdf

    总的来说,Map接口提供了一种高效的方式来存储和检索键值对数据,可变参数简化了函数调用,Cloneable接口支持对象的克隆,而多线程则为并发编程提供了基础。理解和掌握这些知识点对于Java开发至关重要。

    JAVA_对象克隆

    `Cloneable`接口本身不包含任何方法,只是一个标记接口,表明该类的对象可以被克隆。`Object`类的`clone()`方法会创建一个新的对象,并尽可能地复制原对象的数据。如果一个对象没有实现`Cloneable`接口,调用`clone...

    Java原型模式

    在Java中,原型模式通过实现Cloneable接口和覆盖clone()方法来复制对象,避免了使用构造函数进行深度复制的复杂性。接下来我们将深入探讨Java原型模式的核心概念、实现方式以及实际应用。 ### 核心概念 1. **原型...

    java object 之clone方法全面解析

    2. **protected修饰符**:默认情况下,`clone()`方法被声明为`protected`,这意味着只有同一包内的类或者该类的子类可以直接调用。如果要从其他包的类中克隆对象,你需要将`clone()`方法的访问修饰符更改为`public`...

    原型模式类

    但是需要注意的是,`clone()`方法默认是保护类型的,需要在类中显式地声明为公开的(public)并进行适当的实现。 在描述中提到的“原型模式类”可能是一个包含多个类的项目,这些类可能是为了演示如何使用原型模式...

    Java实验3.pdf

    10. **`Cloneable`接口和`clone`方法**:`Cloneable`接口表明一个类支持克隆。实现此接口的类可以覆盖`Object`类的`clone`方法,创建对象的副本。浅复制仅复制对象的引用,而深复制则复制对象及所引用的对象。在实验...

    java原型模型

    1. **定义原型接口或抽象类**:在Java中,虽然不强制,但通常会定义一个接口`Prototype`,声明`clone()`方法。 ```java public interface Prototype { Prototype clone(); } ``` 2. **实现原型接口**:为需要克隆...

    JAVA_高级特性(hashCode,clone,比较器,Class反射,序列化)

    为了支持 `clone` 操作,类必须实现 `Cloneable` 接口。实现 `clone` 方法时,通常会调用父类 `Object` 的 `clone` 方法,并强制转换类型。 示例代码展示了如何在 `Person03` 类中实现 `clone` 方法: ```java ...

    2022年抽象类和接口2.ppt

    当一个对象实现了 `Cloneable` 接口,就可以通过 `Object` 类的 `clone()` 方法创建该对象的副本。不过需要注意的是,`clone()` 方法默认只是浅复制,对于复杂的数据结构,可能需要重写 `clone()` 方法实现深复制。 ...

    01-02-02-原型模式详解1

    需要注意的是,`clone()`方法默认是保护权限的,因此需要在类中显式地声明为公共方法。 例如: ```java public class Prototype implements Cloneable { private String someField; // 省略getter和setter @...

Global site tag (gtag.js) - Google Analytics