sys static ima lis equal 复制 main 使用
Cloneable 接口表明这样的对象时允许克隆的,但这个接口并没有成功达到这个目的,主要是因为它缺少一个 clone 方法,Object 的 clone 方法是受保护的。如果不借助反射,就不能仅仅因为一个对象实现了 Colneable 就可以钓鱼 clone 方法,即使是反射调用也不能保证这个对象一定具有可访问 clone 方法。
既然 Cloneable 并没有包含任何方法,那么它到底有什么用呢?它其实觉得了 Object 中受保护的 clone 方法实现的行为,如果一个类实现了 Cloneable 那么 Object 的 clone 方法就返回该对象的逐域拷贝,否则会抛出 CloneNotSupportedException。但真说接口一种极端非典型用法,不值得提倡。
如果实现 Cloneable 接口是要对某个类起到作用,类和它的所有超类都必须遵守一个一定协议,言外之意就是无需调用构造器就可以创建对象。
Clone 它的通用约定非常弱:
创建和返回该对象的一个拷贝。这个拷贝的精确含义取决于该对象的类。一般含义是,对于任何对象 x,表达式 x.clone() != x 将会是 true,并且,表达式 x.clone().getClass() == x.getClass() 将会是 true,但这些不是绝对的要求,通常情况下,表达式 x.clone().equals(x) 将会是 true,这也不是一个绝对的要求,拷贝对象往往是创建它的类的一个新实例,但它同时也会要求拷贝内部的数据结构。
下面我们看下一个例子:
- public classStudentimplements Cloneable{
- String name;
- int age;
- publicStudent(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=newStudent("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 classStudentimplements 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=newProfessor("wangwu",50);
- Student s1=newStudent("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 进行修改,如下所示即可
- classProfessorimplements 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();
- 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 时,一定要分清需要克隆的对象属性。
第 11 条:谨慎地覆盖 clone
来源: http://www.bubuko.com/infodetail-2031331.html