JAVA中clone()方法与Cloneable接口详细说明
结合java.lang部分源码+内部资料+http://onlylove.iteye.com/blog/265113的博客
clone( )方法
clone( )方法创建调用它的对象的一个复制副本
简单地说, Clone 就是对于给定的一个对象实例 o ,得到另一个对象实例 o’ : o 与 o’ 类 型相同( o.getClass() == o’.getClass() ),内容相同(对于 o/o’ 中的字段 f ,如果 f 是基本数据类型,则 o.f == o’.f ;如果 f 是对象引用,则 o.f == o’.f 或 o.f 指向的对象与 o’.f 指向的对象的内容相同)。通常称 o’ 为 o 的克隆或副本。
当一个副本被创建时,并没有调用被复制对象的构造函数。副本仅仅是原对象的一个简单精确的拷贝。复制是一个具有潜在危险的操作,因为它可能引起不是你所期望的副作用。
例如,假如被复制的对象包含了一个称为obRef的引用变量,当副本创建时,副本中的obRef如同原对象中的obRef一样引用相同的对象。如果副本改变了被obRef引用的对象的内容,那么对应的原对象也将被改变。另一种情况,如果一个对象打开一个I/O流并被复制,两个对象将可操作相同的流。而且,如果其中一个对象关闭了流,而另一个对象仍试图对I/O流进行写操作的话,将导致错误。
java.lang.Object中对于clone()的定义
protected native Object clone() throws CloneNotSupportedException;
该方法是 protected 的,意味着子类需要显式重载clone()方法以使它变为public,或者调用super.clone()方法的类必须实现Cloneable接口
java.lang.Cloneable接口
public interface Cloneable {}
只有接口定义
看到这里可能觉得奇怪,Cloneable接口中什么都没有,要它有什么用?此时,回头再看一下clone()方法发现该方法又是native 的,必然做了与具体平台相关的底层工作。
事实上,类 Object 的 clone() 方法首先会检查 this.getClass() 是否实现了 Cloneable 接口。
Cloneable 只是一个标志接口而已,用来标志该类是否有克隆功能。
如果 this.getClass() 没有实现 Cloneable 接口, clone() 就会抛 CloneNotSupportedException 返回。
实现克隆的方法
第一种方法:下面的程序实现Cloneable接口并定义cloneTest( )方法,该方法在Object中调用clone( )方法:// Demonstrate the clone() method. class TestClone implements Cloneable { int a; double b; // This method calls Object's clone(). TestClone cloneTest() { try { // call clone in Object. return (TestClone) super.clone(); } catch(CloneNotSupportedException e) { System.out.println("Cloning not allowed."); return this; } } } class CloneDemo { public static void main(String args[]) { TestClone x1 = new TestClone(); TestClone x2; x1.a = 10; x1.b = 20.98; x2 = x1.cloneTest(); // clone x1 System.out.println("x1: " + x1.a + " " + x1.b); System.out.println("x2: " + x2.a + " " + x2.b); } }
这里,方法cloneTest( )在Object中调用clone( )方法并且返回结果。注意由clone( )方法
返回的对象必须被强制转换成它的适当类型(TestClone)。
第二种方法:下面的例子重载clone( )方法以便它能被其类外的程序所调用。为了完成这项功能,它
的存取说明符必须是public,如下所示:
// Override the clone() method. class TestClone implements Cloneable { int a; double b; // clone() is now overridden and is public. public Object clone() { try { // call clone in Object. return super.clone(); } catch(CloneNotSupportedException e) { System.out.println("Cloning not allowed."); return this; } } } class CloneDemo2 { public static void main(String args[]) { TestClone x1 = new TestClone(); TestClone x2; x1.a = 10; x1.b = 20.98; // here, clone() is called directly. x2 = (TestClone) x1.clone(); System.out.println("x1: " + x1.a + " " + x1.b); System.out.println("x2: " + x2.a + " " + x2.b); } }
以上两种方法调用的都是Object中的clone方法,而且,java类集中很多数据结构类都有克隆功能,观察其源码,只要调用了Object中的clone()就存在文章起始处说的那些副作用
那有没有一种方式能既克隆副本,又不用担心修改副本时将原本也一并修改呢?接着看
http://onlylove.iteye.com/blog/265113的博客中提出——Clone分两种
shallow clone 和 deep clone
Object 中是shallow clone 容易出现以上说的种种问题deep clone :
public class TestClone { /** * @param args */ public static void main(String[] args) { try { new TestClone().cloneObject(); } catch (CloneNotSupportedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public void cloneObject() throws CloneNotSupportedException { Person p = new Person(); Man man = new Man(); man.setSalory("111123"); p.setName("zhangfei"); p.setMan(man); //man.setSalory("122335");//(1) Person pp = p.getClonePerson(p); man.setSalory("122335");//(2) pp.setName("aa"); System.out.println("pp.getName()= " + pp.getName() + " pp.man.getSalory()= "+pp.getMan().getSalory()); System.out.println("p.getName()=" + p.getName()+" p.man.getSalory()= "+p.getMan().getSalory()); } } class Person implements Cloneable { private String name = ""; private Man man; public String getName() { return name; } public void setName(String name) { this.name = name; } public Person getClonePerson(Person p) throws CloneNotSupportedException { Person pp = (Person) p.clone(); return pp; } public Man getMan() { return man; } public void setMan(Man man) { this.man = man; } public Object clone() throws CloneNotSupportedException{ Person p = (Person) super.clone(); p.man = this.getMan().getCloneMan(this.getMan()); return p; } } class Man implements Cloneable{ private String salory = ""; public String getSalory() { return salory; } public void setSalory(String salory) { this.salory = salory; } public Man getCloneMan(Man man) throws CloneNotSupportedException{ Man ma = (Man)man.clone(); return ma; } }执行结果:
pp.getName()= aa pp.man.getSalory()= 111123 p.getName()=zhangfei p.man.getSalory()= 122335
大家不妨一试
(说明,以上文章结合自java.lang部分源码+内部资料+http://onlylove.iteye.com/blog/265113,如有侵权行为,速联)
阅读更多
- java 重写接口Cloneable的Clone方法 拷贝对象
- 五星-原型模式常使用于以下场景--而JAVA中的任何类只要实现了Cloneable标识接口,就可以使用clone方法来进行对象的拷贝
- Java 基础数据类型 和 深度克隆对象的2种方法(实现Cloneable接口或者实现对象序列化)
- Java第三课 Java中包的概念,类的说明符、方法的说明符、对象的销毁(JVM垃圾会受器的演示),Java中接口理解与掌握。
- Java ResultSet接口 详细说明
- java中的Cloneable接口
- 关于使用java调用海康威视的动态库的详细使用说明(即java调用海康威视SDK的方法)
- java.lang.String中的trim()方法的详细说明
- Java中Cloneable接口
- Cloneable接口和Object的clone()方法
- Java 深拷贝、浅拷贝及Cloneable接口
- Java调用动态库方法说明-最详细
- Java深拷贝除了通过实现Cloneable接口,另外还可以通过序列化实现对象的拷贝。
- java.lang.Cloneable接口
- Cloneable接口和Object的clone()方法
- Cloneable接口和Object的clone()方法
- java对象 深度克隆(不实现Cloneable接口)和浅度克隆
- java基础入门补充(002) Cloneable接口 深复制与浅复制
- Cloneable接口和Object的clone()方法
- Java中的Cloneable接口下的clone深拷贝,单纯的获取那个时刻的值