文章转载自:http://www.cnblogs.com/gw811/archive/2012/10/07/2712252.html
首先,看一下源码:
public class Object { protected native Object clone() throws CloneNotSupportedException; }
由源代码我们会发现:
第一:Object类的clone()方法是一个native方法,native方法的效率一般来说都是远高于Java中的非native方法。这也解释了为什么要用Object中clone()方法而不是先new一个类,然后把原始对象中的信息复制到新对象中,虽然这也实现了clone功能。(JNI是Java Native Interface的 缩写。从Java 1.1开始,Java Native Interface (JNI)标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互。JNI一开始是为了本地已编译语言,尤其是C和C++而设计 的,但是它并不妨碍你使用其他语言,只要调用约定受支持就可以了。使用java与本地已编译的代码交互,通常会丧失平台可移植性。但是,有些情况下这样做是可以接受的,甚至是必须的,比如,使用一些旧的库,与硬件、操作系统进行交互,或者为了提高程序的性能。JNI标准至少保证本地代码能工作在任何Java 虚拟机实现下。)
第二:Object类中的 clone()方法被protected修饰符修饰。这 也意味着如果要应用 clone()方 法,必须继承Object类,在 Java中所有的类是缺省继承 Object类的,也就不用关心这点了。然后重 载 clone()方法。还有一点要考虑的是为了让其它类能调用这个 clone类的 clone()方法,重载之后要把 clone()方法的属性设置 为 public。
第三:Object.clone()方法返回一个Object对象。我们必须进行强制类型转换才能得到我们需要的类型。
浅层复制与深层复制概念:
浅层复制: 被复制的对象的所有成员属性都有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅层复制仅仅复制所考虑的对象,而不复制它所引用的对象。(概念不好理解,请结合下文的示例去理解)
深层复制:被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不是原有的那些被引用的对象。换言之,深层复制要复制的对象引用的对象都复制一遍。
Java中对象的克隆
1)在派生类中实现Cloneable借口。
2)为了获取对象的一份拷贝,我们可以利用Object类的clone方法。
3)在派生类中覆盖积累的clone方法,声明为public。
4)在派生类的clone方法中,调用super.clone()。
实现Cloneable接口
首先,看一下源码:
public interface Cloneable { }
我们奇怪的发现Cloneable竟然是空的,那么我们为什么要实现Cloneable接口呢?其 实Cloneable接口仅仅是一个标志,而且这个标志也仅仅是针对 Object类中 clone()方法的,如果 clone 类没有实 现 Cloneable 接口,并调用了 Object 的 clone() 方法(也就是调用了 super.Clone() 方法),那么 Object 的 clone() 方法就会抛出 CloneNotSupportedException 异常。
程序示例分析:
public class Person { private String name; private int age; public Person(){} public Person(String name,int age){ this.name=name; this.age=age; } public Object clone(){ Object o=null; try { o=super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return o; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
public class PersonTest { public static void main(String[] args) { Person p1=new Person("zhangsan",18); Person p2=(Person)p1.clone(); p2.setName("lis"); p2.setAge(20); System.out.println("name=" +p1.getName()+",age="+p1.getAge()); //修改p2后,没有对p1产生影响。 } }
说明:
1)为什么我们在派生类中覆盖Object的clone()方法时,一定要调用super.clone()呢?在运行时刻,Object中的 clone()识别你要复制的是哪一个对象,然后为此对象分配空间,并进行对象的复制,将原始对象的内容一一复制到新对象的存储空间中。
2)继承自java.lang.Object.clone()方法是浅层复制。一下代码可以证明之:
public class Student implements Cloneable { private String name; private int age; private Professor pro; public Student(){} public Student(String name,int age,Professor pro){ this.name=name; this.age=age; this.pro=pro; } public Object clone(){ Object o=null; try { //Object中的clone()识别出你要复制的是哪一个对象。 o=super.clone(); } catch (CloneNotSupportedException e) { System.out.println(e.toString()); } return o; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Professor getPro() { return pro; } public void setPro(Professor pro) { this.pro = pro; } } class Professor{ private String name; private int age; public Professor(){} public Professor(String name,int age){ this.name=name; this.age=age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
public class StudentTest { public static void main(String[] args) { Professor p=new Professor("wangwu",50); Student s1=new Student("zhangsan",18,p); Student s2=(Student)s1.clone(); s2.getPro().setName("maer"); s2.getPro().setAge(40); System.out.println("name="+s1.getPro().getName() +",age="+s1.getPro().getAge()); //name=maer,age=40 } }
那么我们如何实现深层复制的克隆,即在修改s2.Professor时不影响s1.Professor?代码改进如下:
public class Student implements Cloneable { private String name; private int age; Professor pro; public Student(){} public Student(String name,int age,Professor pro){ this.name=name; this.age=age; this.pro=pro; } public Object clone(){ Student o=null; try { //Object中的clone()识别出你要复制的是哪一个对象。 o=(Student)super.clone(); } catch (CloneNotSupportedException e) { System.out.println(e.toString()); } o.pro=(Professor)pro.clone(); return o; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Professor getPro() { return pro; } public void setPro(Professor pro) { this.pro = pro; } } class Professor implements Cloneable{ private String name; private int age; public Professor(){} public Professor(String name,int age){ this.name=name; this.age=age; } public Object clone(){ Object o=null; try { o=super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return o; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
public class StudentTest { public static void main(String[] args) { Professor p=new Professor("wangwu",50); Student s1=new Student("zhangsan",18,p); Student s2=(Student)s1.clone(); s2.getPro().setName("maer"); s2.getPro().setAge(40); System.out.println("name="+s1.getPro().getName() +",age="+s1.getPro().getAge()); //name=wangwu,age=50 } }