歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> 深入Java克隆

深入Java克隆

日期:2017/3/1 11:14:55   编辑:Linux編程

重新學習了一遍java中的克隆,感覺原來學的太膚淺了,好多特性沒有了解到。

重新總結一遍:

1.java中的克隆對應設計模式中的prototype pattern。

2.如果一個對象想要被克隆,需要實現java.lang.Cloneable接口,這個接口和java.io.Serializable接口相似,都是不包含任何方法的接口,用來進行標志。

3.實現Cloneable接口後,需要覆蓋Object類中的clone方法,是Object中的一個native方法,需要注意的是Object本身並沒有實現Cloneable接口,所以不能對Object對象進行clone。

4.克隆分為shallow copy和deep copy

  1、淺復制(淺克隆)

  概念:被復制對象的所有變量都含有與原來的對象相同的值,而所有的對其他對象的引用仍然指向原來的對象。換言之,淺復制僅僅復制所考慮的對象,而不復制它所引用的對象。

  方法:類implements Cloneable,然後重寫clone()方法,在clone()方法中調用super.clone()即可,沒有其他操作了

  2、深復制(深克隆)

  概念:被復制對象的所有變量都含有與原來的對象相同的值,除去那些引用其他對象的變量。那些引用其他對象的變量將指向被復制過的新對象,而不再是原有的那些被引用的對象。換言之,深復制把要復制的對象所引用的對象都復制了一遍

  方法:

  (1)類implements Cloneable,然後重寫clone()方法,在clone()方法中調用super.clone(),然後還要對引用型變量所指的對象進行克隆。

  (2)序列化:將該對象寫出到對象輸出流,那麼用對象輸入流讀回的對象就是原對象的一個深度克隆

5.java文檔上推薦的克隆的實現標准

The general intent is that, for any object x, the expression:

 x.clone() != x
will be true, and that the expression:
 x.clone().getClass() == x.getClass()
will be true, but these are not absolute requirements. While it is typically the case that:
 x.clone().equals(x)
will be true, this is not an absolute requirement.

1) 克隆新生成了一個對象,所以引用不同。

2) 克隆的對象與原來的對象是相同的類型,所以getClass應該相同。

3) 按照java的規范,在調用一個對象的equals方法前,這個對象應該已經重寫了equals方法,這樣比較的不僅僅是引用,所以這裡指的是兩個對象的信息是否相同,克隆出來的對象信息當然相同,所以這裡應該為true。

6.記一下今天寫的測試代碼

重寫Dog類的equals方法,仿照String類寫的

  1. @Override
  2. public boolean equals(Object obj) {
  3. if(this == obj){
  4. return true;
  5. }
  6. if(obj instanceof Dog){
  7. Dog anotherDog = (Dog)obj;
  8. if(this.getName() == anotherDog.getName()){
  9. return true;
  10. }
  11. }
  12. return false;
  13. }
重寫Dog類的clone方法
  1. @Override
  2. public Dog clone() {
  3. Dog dog = null;
  4. try {
  5. dog = (Dog) super.clone();
  6. dog.setClothes(getClothes().clone());//深克隆時把復制的對象所引用的對象也要clone
  7. } catch (CloneNotSupportedException exception) {
  8. exception.printStackTrace();
  9. }
  10. return dog;
  11. }

PS:要想知道clone真正的用武之地還得在實際中。

又看了一眼Integer的toString方法,Dog的equals方法還可以優化,改為

  1. @Override
  2. public boolean equals(Object obj) {
  3. if(this == obj){
  4. return true;
  5. }
  6. if(obj instanceof Dog){
  7. return name == ((Dog)obj).getName();
  8. }
  9. return false;
  10. }
三行和一行是等價的......

寫完了又發現這篇文章有2個嚴重的錯誤,弄巧成拙最後測試結果對了,不在文章上直接改,為了能牢記錯誤~。

1.String name是引用,所以在淺克隆的時候name僅僅是復制的引用。

2.在equals方法中,比較兩個String是用的==比較的,好久沒有這種錯誤了。

正好name復制的是引用,所以 == 還是返回的true。

改正:

  1. @Override
  2. public boolean equals(Object obj) {
  3. if(this == obj){
  4. return true;
  5. }
  6. if(obj instanceof Dog){
  7. return name.equals(((Dog)obj).getName());
  8. }
  9. return false;
  10. }
以後記住在淺拷貝的時候String引用還是指向原來的內存空間。

String類型還有些不同,見 http://www.linuxidc.com/Linux/2011-10/44936.htm

Copyright © Linux教程網 All Rights Reserved