2011年5月17日 星期二

【Java】Object 的 clone 運用

Java 中  java.lang.Object 複製(Clone),提供了複製一個物件的新做法

通常在複製物件的時候,大多數直覺都是直接把一個物件 assign 給另外一個物件

譬如以下範例:

  //....
    Book book1 = new Book();
  book1.setId(1);
  book1.setBookName("Java Study");

    /*以下複製一個新的Book物件*/
  Book book2 = book1;
  System.out.println("Id " + book2.getId() + "Name : " + book2.getName());
  //....

以上程式用很直覺的方法複製了一個物件,之後book2 Console 出來的值,即會同 book1

如果要採用 Object 的 clone() 方法複製物件的話,需如以下指定的步驟

1.在欲被複製的類別中實作 Cloneable 介面
public class Book implements Cloneable{
    //.....
}

2.在Book類別中實作 clone() 方法
public class Book implements Cloneable{
    //....
    public Object clone(){
        try{
      super.clone(); 
        } catch (CloneNotSupportedException e){
            e.printStackTrace();
        }
    }
}

3.需要複製時,讓 Book 物件呼叫 clone() 方法
  Book book1 = new Book();
  book1.setId(1);
  book1.setBookName("Java Study");
  
  Book book2 = book1.clone();


通常這個 clone 的作法不太常被使用,不過最近工作上去到一個問題就是

譬如:今天要將很多的 Book 物件放到到一個 List 中

但是有某個 Book 物它可能只是某個屬性不同,例如有10本書,他的其他屬性都一樣

只有書名不同,如果用很直覺的方式寫就如一開始那樣
Book book1 = new Book();  //第一本書

book1.setName("Java Study");
book1.setCategory("Tech");

list.add(book1);   //加入 List

for(int i=0;i<9;i++){    //剩下的 9 本
    Book tempBook = new Book();
    tempBook = book1;
    book1.setName(/*這裡取出書名*/);
    list.add(tempBook);
}
說到這裡會發生一個問題,在 Java 的 List 中,當加入某個實體時 

它會去比對加入 List 中的實體判斷是不是已經重複,如果已經重複 它就會進行類似更新的動作,

也就是 List 中還是會多出那一筆資料 但是之前的實體會被更新為目前加入的這個實體,

也就是說最後10筆資料都是一樣的 所以這就發生錯誤了!!

解決辦法中 你可以很簡單的就不要使用複製的作法,每筆資料就乾脆直接 New 一個實體 然後屬性直就慢慢設定上去,

雖然本例屬性不多,但是要是一個類別有超過50個屬性呢

 所以如果這裡我們採用 Object 的 clone() 方法,就可以輕易解決這件事情

 因為在 JAVA 執行 clone() 這個機制時,他是再記憶體外額外再新增一個實體 所以加入 List 之後會被當作是不同的實體物件,固程式稍改一下

Book book1 = new Book();  //第一本書

book1.setName("Java Study");
book1.setCategory("Tech");

list.add(book1);   //加入 List

for(int i=0;i<9;i++){    //剩下的 9 本
    Book tempBook = book1.clone();   //執行 clone 方法
    book1.setName(/*這裡取出書名*/);
    list.add(tempBook);
}

沒有留言:

張貼留言