JAVA 对象拷贝
JAVA 对象拷贝
为什么需要有对象拷贝?
对象拷贝相对的自然是引用拷贝。java初学者经常会问,我这个方法要改变一个对象的属性,可以把参数传进去了,为什么没有改变了?
——基本数据类型传值,而对象传引用或引用的拷贝。
而有时候我们要获取到一个当前状态的对象复制品,他们是两个独立对象。不再是引用或者引用拷贝(实质都是指向对象本身)。就是说a是b的拷贝,b发生变化的时候,不要影响a。
对象拷贝有浅拷贝和深度拷贝两种。
1)浅拷贝
浅拷贝是指对象中基本数据类型得到拷贝,而引用数据类型并未拷贝。
提到拷贝自然和clone联系起来了,所有具有clone功能的类都有一个特性,那就是它直接或间接地实现了Cloneable接口。
否则,我们在尝试调用clone()方法时,将会触发CloneNotSupportedException异常。
eg:
 public   class  DOG  implements  Cloneable2
 {3
     public  DOG(String name,  int  age)4
      {5
         this .name  =  name;6
         this .age  =  age;7
    } 8
 9
     public  String getName()10
      {11
         return   this .name;12
    } 13
 14
     public   int  getAge()15
      {16
         return   this .age;17
    } 18
 19
     public  Object clone()20
      {21
         try 22
          {23
             return   super .clone();24
 25
        }   catch  (CloneNotSupportedException e)26
          {27
             return   null ;28
        } 29
    } 30
 31
     public  String name;32
 33
     private   int  age;34
 35
     // test 36
      public   static   void  main(String[] args)37
      {38
        DOG dog1  =   new  DOG( " xiaogou " ,  2 );39
        DOG dog2  =  (DOG) dog1.clone();40
        dog1.name  =   " dagou " ;41
        System.out.println(dog2.getName());42
        System.out.println(dog2.getAge());43
        System.out.println(dog1.getName());44
        System.out.println(dog1.getAge());45
 46
    } 47
 48
} 49

运行结果:
xiaogou
2
dagou
2
2)深度拷贝
相对浅拷贝。实现对象中基本数据类型和引用数据类型的拷贝。
请先看下面代码:
 class  AAA2
 {3
     public  AAA(String name)4
      {5
         this .name  =  name;6
    } 7
 8
     public  String name;9
} 10
 11
 class  DOG  implements  Cloneable12
 {13
     public  DOG(String name,  int  age, AAA birthday)14
      {15
         this .name  =  name;16
         this .age  =  age;17
         this .birthday  =  birthday;18
    } 19
 20
     public  String getName()21
      {22
         return  name;23
    } 24
 25
     public   int  getAge()26
      {27
         return  age;28
    } 29
 30
     public  AAA getBirthday()31
      {32
         return  birthday;33
    } 34
 35
     public  String getBirth(AAA a)36
      {37
         return  a.name;38
    } 39
 40
     public  String name;41
 42
     private   int  age;43
 44
     public  AAA birthday;45
 46
     public  Object clone()47
      {48
         try 49
          {50
             super .clone();51
             return   super .clone();52
        }   catch  (Exception e)53
          {54
             return   null ;55
        } 56
    } 57
} 58
 59
 public   class  TestClone60
 {61
     public   static   void  main(String[] args)62
      {63
        AAA Day  =   new  AAA( " test " );64
        DOG dog1  =   new  DOG( " xiaogou " ,  2 , Day);65
        DOG dog2  =  (DOG) dog1.clone();66
         //   dog2.birthday = (AAA) dog1.birthday.clone();  67
         dog1.birthday.name  =   " 333 " ;68
        System.out.println(dog1.getBirth(dog1.birthday));69
        System.out.println(dog2.getBirth(dog2.birthday));70
    } 71
} 72

运行结果是:
333
333
而真正要实现拷贝还的加点代码,如下请对比上面和下面代码的异同之处:
 class  AAA  implements  Cloneable2
 {3
     public  AAA(String name)4
      {5
         this .name  =  name;6
    } 7
 8
     public  Object clone()9
      {10
         try 11
          {12
             super .clone();13
             return   super .clone();14
        }   catch  (Exception e)15
          {16
             return   null ;17
        } 18
    } 19
 20
     public  String name;21
} 22
 23
 class  DOG  implements  Cloneable24
 {25
     public  DOG(String name,  int  age, AAA birthday)26
      {27
         this .name  =  name;28
         this .age  =  age;29
         this .birthday  =  birthday;30
    } 31
 32
     public  String getName()33
      {34
         return  name;35
    } 36
 37
     public   int  getAge()38
      {39
         return  age;40
    } 41
 42
     public  AAA getBirthday()43
      {44
         return  birthday;45
    } 46
 47
     public  String getBirth(AAA a)48
      {49
         return  a.name;50
    } 51
 52
     public  String name;53
 54
     private   int  age;55
 56
     public  AAA birthday;57
 58
     public  Object clone()59
      {60
         try 61
          {62
             super .clone();63
             return   super .clone();64
        }   catch  (Exception e)65
          {66
             return   null ;67
        } 68
    } 69
} 70
 71
 public   class  TestClone72
 {73
     public   static   void  main(String[] args)74
      {75
        AAA Day  =   new  AAA( " test " );76
        DOG dog1  =   new  DOG( " xiaogou " ,  2 , Day);77
        DOG dog2  =  (DOG) dog1.clone();78
        dog2.birthday  =  (AAA) dog1.birthday.clone(); // 特别注意这里 79
         dog1.birthday.name  =   " 333 " ;80
        System.out.println(dog1.getBirth(dog1.birthday));81
        System.out.println(dog2.getBirth(dog2.birthday));82
    } 83
} 84

运行结果:
333
test
这样基本就达到了我们当初的母的。
但是明显的这种方法还是有许多不足,人们总是希望一个clone就是对象直接克隆。而上面还要对对象中的对象递归使用clone。下面提供一种更高级点的做法:
 import  java.io. * ;2
 3
 class  AAA  implements  Serializable4
 {5
     public  AAA(String name)6
      {7
         this .name  =  name;8
    } 9
 10
     public  String name;11
} 12
 13
 class  DOG  extends  SerialCloneable14
 {15
     public  DOG(String name,  int  age, AAA birthday)16
      {17
         this .name  =  name;18
         this .age  =  age;19
         this .birthday  =  birthday;20
    } 21
 22
     public  String getName()23
      {24
         return  name;25
    } 26
 27
     public   int  getAge()28
      {29
         return  age;30
    } 31
 32
     public  AAA getBirthday()33
      {34
         return  birthday;35
    } 36
 37
     public  String getBirth(AAA a)38
      {39
         return  a.name;40
    } 41
 42
     public  String name;43
 44
     private   int  age;45
 46
     public  AAA birthday;47
 48
     public  Object clone()49
      {50
         try 51
          {52
             super .clone();53
             return   super .clone();54
        }   catch  (Exception e)55
          {56
             return   null ;57
        } 58
    } 59
} 60
 61
 public   class  TestClone62
 {63
     public   static   void  main(String[] args)64
      {65
        AAA Day  =   new  AAA( " test " );66
        DOG dog1  =   new  DOG( " xiaogou " ,  2 , Day);67
        DOG dog2  =  (DOG) dog1.clone();68
         // dog2.birthday = (AAA) dog1.birthday.clone(); 69
         dog1.birthday.name  =   " 333 " ;70
        System.out.println(dog1.getBirth(dog1.birthday));71
        System.out.println(dog2.getBirth(dog2.birthday));72
    } 73
} 74
 75
 class  SerialCloneable  implements  Cloneable, Serializable76
 {77
     public  Object clone()78
      {79
         try 80
          {81
            ByteArrayOutputStream bout  =   new  ByteArrayOutputStream();82
            ObjectOutputStream out  =   new  ObjectOutputStream(bout);83
            out.writeObject( this );84
            out.close();85
            ByteArrayInputStream bin  =   new  ByteArrayInputStream(bout86
                    .toByteArray());87
            ObjectInputStream in  =   new  ObjectInputStream(bin);88
            Object ret  =  in.readObject();89
            in.close();90
             return  ret;91
        }   catch  (Exception e)92
          {93
             return   null ;94
        } 95
    } 96
} 97

输出:
333
test
上面的代码用序列化与反序列化实现了对象拷贝。比较通用。但是得注意的是其中的类得implements Serializable。
3)后记
我们如果利用强大的反射机制+序列化与反序列化,能做出更加灵活的对象拷贝。有兴趣的朋友可以自行去研究。
我在javaeye上看到一篇短文:http://www.javaeye.com/post/367014 主要讲的就是反射在对象拷贝中的应用。
                    
                
                
            
        
浙公网安备 33010602011771号