Cloneable接口代表这样的对象时容许克隆的,但这个接口并无成功达到这个目的,主要是由于它缺乏一个clone方法,Object的clone方法是受保护的。若是不借助反射,就不能仅仅由于一个对象实现了Colneable就能够钓鱼clone方法,即便是反射调用也不能保证这个对象必定具备可访问clone方法。数据结构
既然Cloneable并无包含任何方法,那么它到底有什么用呢?它其实以为了Object中受保护的clone方法实现的行为,若是一个类实现了Cloneable那么Object的clone方法就返回该对象的逐域拷贝,不然会抛出CloneNotSupportedException。但真说接口一种极端非典型用法,不值得提倡。this
若是实现Cloneable接口是要对某个类起到做用,类和它的全部超类都必须遵照一个必定协议,言外之意就是无需调用构造器就能够建立对象。spa
Clone它的通用约定很是弱:code
建立和返回该对象的一个拷贝。这个拷贝的精确含义取决于该对象的类。通常含义是,对于任何对象x,表达式x.clone() != x 将会是true,而且,表达式x.clone().getClass() == x.getClass() 将会是true,但这些不是绝对的要求,一般状况下,表达式x.clone().equals(x) 将会是true,这也不是一个绝对的要求,拷贝对象每每是建立它的类的一个新实例,但它同时也会要求拷贝内部的数据结构。对象
下面咱们看下一个例子:blog
public class Student implements Cloneable{ String name; int age; public Student(String name,int age){ this.name = name; this.age = age; } public Object clone(){ Object o = null; try{ o = (Student)super.clone();//Object 中的clone()识别出你要复制的是哪一个对象 }catch(CloneNotSupportedException e){ System.out.println(e.toString()); } return o; } public static void main(String[] args){ Student s1=new Student("zhangsan",18); Student s2=(Student)s1.clone(); System.out.println("克隆后s2:name="+s2.name+","+"age="+s2.age); s2.name="lisi"; s2.age=20; //修改学生2后,不影响学生1的值。 System.out.println("克隆修改后s1:name="+s1.name+","+"age="+s1.age); System.out.println("克隆修改后s2:name="+s2.name+","+"age="+s2.age); } }
这时候,若是类的每一个域包含一个基本类型的值,或者包含一个指向不可变对象的引用,那么被返回的对象则正是所须要的对象,只须要简单地调用super.clone() 而不用作进一步的处理。可是!若是对象中其余对象的引用时,那么只是简单的clone就没法作到彻底的克隆了,下面的例子咱们就能够体会到接口
class Professor { String name; int age; Professor(String name,int age){ this.name=name; this.age=age; } } public class Student implements Cloneable{ String name;// 常量对象。 int age; Professor p;// 学生1和学生2的引用值都是同样的。 Student(String name,int age,Professor p){ this.name=name; this.age=age; this.p=p; } public Object clone(){ Student o=null; try{ o=(Student)super.clone(); }catch(CloneNotSupportedException e){ System.out.println(e.toString()); } return o; } public static void main(String[] args){ Professor p=new Professor("wangwu",50); Student s1=new Student("zhangsan",18,p); Student s2=(Student)s1.clone(); System.out.println("克隆后s1:name="+s1.p.name+","+"age="+s1.p.age); System.out.println("克隆后s2:name="+s2.p.name+","+"age="+s2.p.age); s2.p.name="lisi"; s2.p.age=30; System.out.println("克隆后s1:name="+s1.p.name+","+"age="+s1.p.age); System.out.println("克隆后s2:name="+s2.p.name+","+"age="+s2.p.age); } }
从结果上咱们能够看出,s2对s1进行克隆时,对s1的属性Professor p并无进行克隆,致使s1和s2对其引用指向同一个,这会形成s2若改变了值,s1则也被动改变了。那应该如何实现深层次的克隆,即修改s2的教授不会影响s1的教授?其实很简单,只须要对Professor进行修改,以下所示便可get
class Professor implements Cloneable{ String name; int age; Professor(String name,int age){ this.name=name; this.age=age; } public Object clone(){ Object o = null; try{ o = super.clone(); }catch(CloneNotSupportedException e){ System.out.println(e.toString()); } return o; } }
修改Professor后,还须要在Student的clone方法中加入一句代码:o.p=(Professor)p.clone(); io
public Object clone(){ Student o=null; try{ o=(Student)super.clone(); }catch(CloneNotSupportedException e){ System.out.println(e.toString()); } o.p=(Professor)p.clone(); return o; }
看到结果就如咱们所但愿的那样。所以,在使用clone时,必定要分清须要克隆的对象属性。class