2010-03-25 40 views
2

Java中的Object.clone()方法非常特殊,因爲它不返回要用Object類型克隆的對象的副本,而是返回正確的Object類型。這可以用下面的代碼可以更好地描述:是否有可能在Java中實現類似於Object.clone()的東西?

class A implements Cloneable 
{ 
    public Object clone() throws CloneNotSupportedException { 
     return super.clone(); 
    } 
} 

class B extends A { 
} 

public class MainABC { 
    public static void main(String[] args) throws CloneNotSupportedException { 
     B b = new B(); 
     B b1 = (B)b.clone(); //see here that we are using A's .clone(). The only 
          //thing it does is call Object's clone(). 
     System.out.println(b1.getClass()); //but as we see here, its not an Object 
              //its a B! 
    } 
} 

所以,如果是有反正裏面複製什麼Object.clone發生的()方法,任何人都可以解釋如果可能的話?

+1

你想達到什麼目的。如果它只是代碼,請將其明確寫出。 – 2010-03-25 18:31:55

+0

這段代碼甚至沒有編譯,也沒有任何意義。檢查Savvas Dalkitsis的答案。你需要澄清一下你究竟想達到什麼目的。 – BalusC 2010-03-25 18:48:55

+0

現在應該更有意義了.. – 2010-03-25 18:55:51

回答

2

Object.clone()肯定是做了一些在Java中無法實現的東西。

Josh Bloch on Design: Copy Constructor versus Cloning(重點煤礦):

對象的克隆方法是非常棘手的。它基於現場副本,它是「超語言」。它不調用構造函數就創建一個對象。不保證它保留了構造函數建立的不變量。

Object.clone()做的事情不應該被語言所允許。這就是爲什麼在其他原因中,clone()被打破。

(如果你還沒有準備好,你應該也看過他的書有效的Java,理解爲什麼他(和其他許多人)認爲Java的clone()Cloneable被打破)。


如果你只是想創建同一個類的對象作爲另一個任意對象,那麼這還算是可以實現的,有一些需要注意的(即不是所有的類型都公開實例化)通過使用反射。

這裏有一個如何使用反射來一個例子:

  • 找出類對象的類型在運行時
  • 列出其聲明的字段,方法和構造
  • 找到它的拷貝構造函數(如果有),並嘗試使用給定對象作爲 參數調用它。

import java.lang.reflect.*; 

public class NewInstance { 
    static void print(String label, Object[] arr) { 
     System.out.println(label); 
     for (Object o : arr) { 
     System.out.println(o); 
     } 
     System.out.println("---"); 
    } 

    static Object newInstance(Object o) { 
     Class<?> c = o.getClass(); 
     System.out.println("Class is " + c); 
     print("FIELDS:", c.getDeclaredFields()); 
     print("METHODS:", c.getDeclaredMethods()); 
     print("CONSTRUCTORS:", c.getDeclaredConstructors()); 

     try { 
     Constructor<?> cc = c.getDeclaredConstructor(c); 
     o = cc.newInstance(o); 
     } catch (NoSuchMethodException e) { 
     System.out.println("No copy constructor found!"); 
     } catch (IllegalAccessException e) { 
     System.out.println("Copy constructor inaccessible!"); 
     } catch (InstantiationException e) { 
     System.out.println("Instantiation failed!"); 
     } catch (InvocationTargetException e) { 
     System.out.println("Copy constructor threw " + e.getCause()); 
     } 
     return o; 
    } 

    public static void main(String args[]) { 
     Object o1 = "hello"; 
     Object o2 = newInstance(o1); 
     boolean success = (o1 != o2) && (o1.equals(o2)); 
     System.out.println("Attempt " + (success ? "succeeded!" : "failed :(")); 
    } 
} 

輸出:

Class is class java.lang.String 
FIELDS: 
// (omitted) 
METHODS: 
// (omitted) 
CONSTRUCTORS: 
public java.lang.String() 
public java.lang.String(java.lang.String) // this is what we're looking for! 
// (rest omitted) 
--- 
Attempt succeeded! 

請注意,這只是爲了顯示類型的例子可以在運行時間和拷貝構造函數可以尋找和調用進行檢查。原因是,如果oArrayList,則它不起作用,因爲它沒有構造函數,其取值爲ArrayList(它的確有一個取值爲Collection,其值爲ArrayList)。

我會把它留給你作爲練習如何擴大複製構造函數的搜索以包含這些兼容的重載。

1

我從未聽說過或看到過一種語言構造,它爲您提供clone免費提供的功能。

你可以模仿它,但我不相信你可以複製行爲。

+0

在新對象上避免調用構造函數不會使用可驗證的字節碼飛行(串行化是使用破壞的字節碼生成實現的)。 – 2010-03-25 18:30:58

0

我想你還沒有測試過你在這裏輸入的代碼!

如果您嘗試編譯此代碼,您會收到錯誤消息。首先返回super.clone()給你一個錯誤「Type mismatch:can not convert from Object to A」

其次(我會認爲這是一個錯誤類型),你沒有創建一個B的實例。說

B = new B(); 

即使我們改變,要

B b = new B(); 
B b1 = b.clone(); 

,你會得到一個錯誤,因爲b.clone()將返回A級

很抱歉的實例,但你確實描述不會發生......你需要演員才能得到你想要的。

所以總結起來:

public class A extends Object { 
    public A clone() { 
     return super.clone(); // Error "Type mismatch: cannot convert from Object to A" 
    } 

    public static void main(String[] args) { 
     B b = new B(); 
     B b1 = b.clone(); // Error "Type mismatch: cannot convert from A to B" 
    } 
} 

class B extends A { 
} 

編輯:恐怕你得到它一錯再錯。你所做的是返回一個B的實例,因爲你將它轉換爲B實例。它將返回b即使你投完全不同的東西...例如

B b = (B)(new JLabel()); 
System.out.println(b.class); 

這將打印的B類的其實是將打印的B類的,如果它曾經到了那裏你...在它到達那裏之前會得到一個異常...爲了得到你想要的,你必須手動覆蓋clone方法並提供你自己的實現。你的問題根本無效..你應該刪除它,但你不能,因爲你已經有了upvoted的答案...我會投票結束至少...

+0

是的,我輸入它沒有檢查,並得到它完全錯誤:P似乎現在是正確的。 – 2010-03-25 18:53:26

+0

我認爲你再錯了...檢查我編輯的答案... – 2010-03-25 19:02:30

+0

檢查此代碼: 對象abc =(Object)new Integer(5); System.out.println(abc.getClass()); 它將打印Integer,因爲這是堆上的對象真的是。所以,在我的代碼中,打印B不是因爲轉換(這是隻有編譯器關心的東西),而是因爲運行時的對象是B類型的! – 2010-03-25 19:06:36

1

Objenesis library可用於創建實例任意類,即使它們沒有無參數構造函數。它爲每個JVM使用各種技巧來實現這一點。您可以將它與一些反射代碼一起使用,以將源對象中的所有字段值複製到目標。

0

這個怎麼樣?

public class A { 
    public static void main(String[] args) { 
     B b = new B(); 
     B b1 = (B)b.getNew(); 
     System.out.println(b1.getClass()); 
    } 

    public Object getNew() { 
     try { 
      return getClass().newInstance(); 
     } catch (InstantiationException e) { 
      e.printStackTrace(); 
     } catch (IllegalAccessException e) { 
      e.printStackTrace(); 
     } 
     return null; 
    } 
} 

class B extends A { 

} 
+0

仍然是不一樣的..閱讀多基因的帖子。 – 2010-03-28 03:14:18

相關問題