`
ArtShell
  • 浏览: 27962 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类

Java中的clone问题(浅克隆+深克隆)

阅读更多

认识:跟克隆有关的两个类型,Cloneable(接口类型)、Object(类类型);JDK API中这个两个类型的源代码和描述如下(添加了部分内容,以及内容顺序有改动):

 

1Cloneable

public interface Cloneable {}

 

对应 api document的描述:

 

实现了 Cloneable接口的类,以指示 Object.clone()方法可以合法地对该类实例进行按字段复制。

如果在没有实现 Cloneable接口的类实例上调用 Object clone 方法,则会导致抛出 CloneNotSupportedException异常【见example.1

按照惯例,实现此接口的类应该使用公共方法重写 Object.clone(它是受保护的)。请参阅 Object.clone(),以获得有关重写此方法的详细信息。

注意,此接口 包含 clone方法。因此,因为某个对象实现了此接口就克隆它是不可能的。即使 clone 方法是反射性调用的,也无法保证它将获得成功。(Object. clone()方法是protected类型的,反射时只有public类型的方法能够被获取(当且仅当该类实现Cloneable接口后并重写Object. clone()方法,才能被获取))

 

example.1

public class NotImplCloneable { //此类没有实现Cloneable接口
	public static void main(String[] args) throws CloneNotSupportedException {
		NotImplCloneable notIClone = new NotImplCloneable();
		notIClone.clone(); //Object类是所有类的父类,clone()从何而来不做解释
	}
}

 

 

 

2Object

public class Object {
   ……  // 其他方法省略
	protected native Object clone() throws CloneNotSupportedException;
}

 

对应 api document的描述:

 

创建并返回此对象的一个副本。副本的准确含义可能依赖于对象的类。这样做的目的是,对于任何对象 x,表达式:

x.clone() != x

true,表达式:

x.clone().getClass() == x.getClass()

也为 true,但这些并非必须要满足的要求。一般情况下:

x.clone().equals(x)

true,但这并非必须要满足的要求。

按照惯例,返回的对象应该通过调用 super.clone 获得。如果一个类及其所有的超类(Object 除外)都遵守此约定,则 x.clone().getClass() == x.getClass()

 

Object 类的 clone 方法执行特定的复制操作。首先,如果此对象的类没有实现接口 Cloneable,则会抛出 CloneNotSupportedException注意,所有的数组对象都被视为已经实现Cloneable接口,但并不一定代表数组元素对象实现了Cloneable接口(前提是数组元素对象对应的类已经实现Cloneable接口后并重写Object. clone()方法),创建此对象的类的一个新实例,并像通过分配那样,严格使用此对象相应字段的内容初始化该对象的所有字段;这些字段的内容没有被自我复制。所以,此方法执行的是该对象的浅表复制,而不深层复制操作。【这段文字描述的是浅克隆,见example.2

 

按照惯例,此方法返回的对象应该独立于该对象(正被复制的对象)。要获得此独立性,在 super.clone 返回对象之前,有必要对该对象的一个或多个字段进行修改。这通常意味着要复制包含正在被复制对象的内部深层结构的所有可变对象,并使用对副本的引用替换对这些对象的引用。如果一个类只包含基本类型(primitive)字段或对不可变类型(final)字段的引用,那么通常不需要修改 super.clone 返回的对象中的字段【这段文字描述的深克隆,见example.3】。

 

Object 类本身不实现接口 Cloneable,所以在类为 Object 的对象上调用 clone 方法将会导致在运行时抛出异常。

 

 

【浅克隆example.2

class DeepStructure {
	public boolean boo = true; // 基本类型字段
	public final char ch = 'a'; // final类型字段,即:不可变引用
}

public class ImplCloneable implements Cloneable {
	public int i = 0; // 基本类型字段
	public final String str = "abcd"; // final类型字段,即:不可变引用
	public DeepStructure deepStructure = new DeepStructure(); // 可变引用
	
	@Override
	public ImplCloneable clone() throws CloneNotSupportedException {
		return (ImplCloneable) super.clone();// 浅克隆
	}
	public static void main(String[] args) throws CloneNotSupportedException {
		ImplCloneable implClone1 = new ImplCloneable();
		ImplCloneable implClone2 = (ImplCloneable)implClone1.clone();
		
		System.out.println("---------implClone1 of attribute---------");
		System.out.println("implClone1.i: " + implClone1.i);
		System.out.println("implClone1.str: " + implClone1.str);
		System.out.println("implClone1.deepStructure.boo: " + implClone1.deepStructure.boo);
		System.out.println("implClone1.deepStructure.ch: " + implClone1.deepStructure.ch);
		
		System.out.println("---------implClone2 of attribute---------");
		System.out.println("implClone2.i: " + implClone2.i);
		System.out.println("implClone2.str: " + implClone2.str);
		System.out.println("implClone2.deepStructure.boo: " + implClone2.deepStructure.boo);
		System.out.println("implClone2.deepStructure.ch: " + implClone2.deepStructure.ch);
		
		/*
		 * 修改 implClone2 对象的属性,观察implClone1和implClone2的输出变化
		 */
		implClone2.i = 10;
		implClone2.deepStructure.boo = false;
		
		System.out.println("---------implClone1 of attribute---------");
		System.out.println("implClone1.i: " + implClone1.i);
		System.out.println("implClone1.str: " + implClone1.str);
		System.out.println("implClone1.deepStructure.boo: " + implClone1.deepStructure.boo);
		System.out.println("implClone1.deepStructure.ch: " + implClone1.deepStructure.ch);
		
		System.out.println("---------implClone2 of attribute---------");
		System.out.println("implClone2.i: " + implClone2.i);
		System.out.println("implClone2.str: " + implClone2.str);
		System.out.println("implClone2.deepStructure.boo: " + implClone2.deepStructure.boo);
		System.out.println("implClone2.deepStructure.ch: " + implClone2.deepStructure.ch);
	}
}

 

 

 

 

 

【深克隆example.3

class DeepStructure implements Cloneable {
	public boolean boo = true; // 基本类型字段
	public final char ch = 'a'; // final类型字段,即:不可变引用
	
	@Override
	public DeepStructure clone() throws CloneNotSupportedException {
		return (DeepStructure)super.clone();
	}
}

public class ImplCloneable implements Cloneable {
	public int i = 0; // 基本类型字段
	public final String str = "abcd"; // final类型字段,即:不可变引用
	public DeepStructure deepStructure = new DeepStructure(); // 可变引用
	
	@Override
	public ImplCloneable clone() throws CloneNotSupportedException {
		ImplCloneable object =(ImplCloneable)super.clone();
		object.deepStructure = (DeepStructure)deepStructure.clone();// 深克隆
		return object;
	}
	public static void main(String[] args) throws CloneNotSupportedException {
		ImplCloneable implClone1 = new ImplCloneable();
		ImplCloneable implClone2 = (ImplCloneable)implClone1.clone();
		
		/*
		 *修改 implClone2 对象的属性,观察implClone1和implClone2的输出变化
		 */
		implClone2.i = 10;
		implClone2.deepStructure.boo = false;
		
		System.out.println("---------implClone1 of attribute---------");
		System.out.println("implClone1.i: " + implClone1.i);
		System.out.println("implClone1.str: " + implClone1.str);
		System.out.println("implClone1.deepStructure.boo: " + implClone1.deepStructure.boo);
		System.out.println("implClone1.deepStructure.ch: " + implClone1.deepStructure.ch);
		
		System.out.println("---------implClone2 of attribute---------");
		System.out.println("implClone2.i: " + implClone2.i);
		System.out.println("implClone2.str: " + implClone2.str);
		System.out.println("implClone2.deepStructure.boo: " + implClone2.deepStructure.boo);
		System.out.println("implClone2.deepStructure.ch: " + implClone2.deepStructure.ch);
	}
}

 

 

以下:这段文字内容摘自;http://gabrielcjx.iteye.com/blog/445388

Cloning is a potentially dangerous action, because it can cause unintended side effects. For example, if the object being cloned contains a reference variable called obRef, then when the clone is made, obRef in the clone will refer to the same object as does obRef in the original. If the clone makes a change to the contents of the object referred to by obRef, then it will be changed for the original object, too. Here is another example. If an object opens an I/O stream and is then cloned, two objects will be capable of operating on the same stream. Further, if one of these objects closes the stream, the other object might still attempt to write to it, causing an error.

 复制是一种存在潜在危险的行为,因为它会引起一些意想不到的负作用。例如,如果被复制的对象包含一个名为 obRef引用变量,在复制时,复制对象的 obRef原来对象的 obRef都会指向同一个对象。如果复制对象对 obRef指向的对象的内容做出一些改变,对于原来对象来说,也就相当于它也被改变了。还有另一个例子,如果一个操作I/O流的对象被复制了,这两个对象都能对同一I/O流进行操作。进一步说,如果它们两个中的一个关闭了I/O 流,而另一个对象可能试图对I/O流进行写操作,这就会引起错误。

 

综上所述:上边这段文字描述的是【浅克隆,见example.2】,如果按照【深克隆,见example.3】的方法来避免上边这段文字中描述的问题,显得非常的笨拙(笨在何处:如果ImplCloneable类对象持有多个可变引用,那么就会去为每一个可变引用的所属类都实现一遍Object. clone()方法)。下边介绍终极解决方案:通过【序列化和反序列化】来实现一次性深克隆,请移步:http://www.cnblogs.com/kadinzhu/archive/2011/07/14/2106254.html

 

 

参考:JDK1.6  API Document

           http://gabrielcjx.iteye.com/blog/445388

         

 http://www.cnblogs.com/kadinzhu/archive/2011/07/14/2106254.html

 

      请各位大神多拍砖!多谢!

  • 大小: 29.9 KB
  • 大小: 74.9 KB
  • 大小: 43 KB
分享到:
评论

相关推荐

    java 深克隆与浅克隆

    Java 深克隆与浅克隆 Java 中的克隆机制可以让我们方便地制造出一个对象的...Java 中的克隆机制可以方便地制造出对象的副本,但是需要注意浅克隆和深克隆的区别,并且需要正确地使用 Clone 方法,以避免不利的结果。

    java 深克隆 浅克隆

    在Java编程语言中,克隆是...理解深克隆和浅克隆的概念对于编写复杂的、性能敏感的Java程序至关重要,尤其是在处理大量对象或需要保持数据独立性时。根据具体需求选择合适的克隆策略,可以提高代码的灵活性和可维护性。

    JAVA浅克隆与深克隆

    克隆分为两种主要类型:浅克隆(Shallow Clone)和深克隆(Deep Clone)。这篇博客文章将探讨这两种克隆方式以及如何在Java中实现它们。 首先,我们来理解一下浅克隆。浅克隆是通过调用对象的`clone()`方法创建一个...

    java 深克隆浅克隆

    Java提供了两种主要的克隆方式:深克隆和浅克隆。 1. 浅克隆(Shallow Clone): 浅克隆是通过调用对象的`clone()`方法来实现的,这个方法是Object类提供的。当一个对象被浅克隆时,新创建的对象将拥有原始对象的...

    Java中的克隆(Clone)机制

    总结来说,Java中的克隆机制提供了一种创建对象副本的方式,分为浅克隆和深克隆两种形式,适用于不同的对象结构需求。正确理解和使用克隆机制,可以帮助开发者更有效地管理和复制复杂的数据结构,避免因共享数据导致...

    Java深浅clone

    在本文中,我们将深入探讨Java中的浅克隆(shallow clone)和深克隆(deep clone),并结合测试代码进行分析。 首先,让我们理解`Cloneable`接口。在Java中,如果一个类想要支持`clone()`方法,它必须实现`...

    Java对象的深克隆与浅克隆详解.zip(wcb2003)

    总的来说,理解Java对象的深克隆和浅克隆是优化代码和解决特定问题的关键。根据具体需求选择合适的克隆方式,可以提高代码的可维护性和灵活性。在设计类和系统时,应考虑对象复制的需求,并决定是否实现`Cloneable`...

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

    在Java中,克隆分为两种类型:浅克隆(Shallow Clone)和深度克隆(Deep Clone)。 1. 浅克隆(Shallow Clone) 浅克隆是Java克隆机制的默认行为。当一个对象被克隆时,如果它的成员变量是基本类型(如int、double...

    实例分析java对象中浅克隆和深克隆

    浅克隆和深克隆在Java对象中的应用 在Java编程语言中,克隆(Clone)是一种常见的对象复制机制。克隆可以分为浅克隆(Shallow Clone)和深克隆(Deep Clone)两种。浅克隆仅复制对象的引用,而深克隆则完全复制对象...

    java Clone

    `clone`方法分为两种类型:浅克隆(Shadow Clone)和深克隆(Deep Clone)。浅克隆是指只复制对象本身,而不复制其引用的对象。如果对象中包含其他对象的引用,那么这些引用的对象不会被复制,而是共享同一份引用。...

    java 对象的克隆(浅克隆和深克隆)

    在Java中,有两种主要的克隆方式:浅克隆(Shallow Clone)和深克隆(Deep Clone)。接下来,我们将详细讨论这两种克隆方式及其区别。 1. 对象的浅克隆: 浅克隆是指创建一个新对象,这个新对象复制了原对象的所有...

    java clone的小例子

    在Java编程语言中,`clone()`方法是一个非常重要的概念,特别是在对象复制和克隆方面。这个小例子将帮助初学者理解如何在Java中使用`clone()`来创建对象的副本。让我们深入探讨`clone()`方法以及它在实际编程中的...

    Java中clone方法共6页.pdf.zip

    在Java编程语言中,`clone()`方法是一个非常重要的概念,特别是在对象复制和克隆方面。这个方法来源于`java.lang.Object`类,所有Java类都默认继承了这个方法。本资料"Java中clone方法共6页.pdf.zip"可能包含了关于...

    java clone

    在Java编程语言中,`clone`是一个非常重要的概念,它涉及到对象复制和对象克隆。本文将深入探讨Java中的`clone`方法,包括其工作原理、使用场景、注意事项以及一些个人实践心得。 首先,让我们理解什么是`clone`。...

    java中的指针,引用及对象的clone

    本文将深入探讨Java中的引用以及对象的克隆机制,包括浅拷贝和深拷贝的区别及其应用场景。 #### 二、Java中的引用 在Java中,当使用`new`关键字创建一个对象时,实际上创建的是一个指向该对象的引用。例如,以下...

    浅拷贝(浅复制、浅克隆)、深拷贝(深复制、深克隆)实战工程

    在编程领域,尤其是在Java语言中,对象的复制是常见的操作,这涉及到两个主要概念:浅拷贝(浅复制、浅克隆)和深拷贝(深复制、深克隆)。这两个概念是理解对象生命周期和内存管理的关键部分。下面将详细阐述它们的...

    Java浅克隆与深克隆

    Java中的浅克隆和深克隆是对象复制的两种方式,它们主要区别在于对对象内部引用类型字段的处理。在Java中,实现克隆通常需要重写`Object`类的`clone()`方法。 **浅克隆(Shallow Clone)** 浅克隆创建一个新对象,...

    java的深度克隆的例子

    首先,Java提供了两种基本的克隆方式:浅克隆(shallow clone)和深克隆。浅克隆仅仅复制对象本身,而不复制对象所引用的对象。而深克隆则会递归地复制对象及所有引用的对象,确保新创建的对象和原始对象及其引用的...

    Java深复制与浅复制&Clone

    在Java中,浅复制可以通过`Object`类的`clone()`方法实现。但是,`clone()`方法默认的是浅复制,且需要被克隆的对象实现`Cloneable`接口。以下是一个简单的例子: ```java public class MyClass implements ...

Global site tag (gtag.js) - Google Analytics