2012-11-15 49 views
5

我突然遇到了在Java中製作深度多態拷貝的問題。實施可克隆解決了我的情況,但它通常被稱爲「壞」技術。Java中的多態拷貝

所以,這裏是我試圖找到一個「不可克隆」的解決方案:

public class Parent { 
    int x; 

    public Parent() {} 

    public Parent(int x0) { 
     x = x0; 
    } 

    public Parent copy() { 
     Parent b = new Parent(); 
     b.assign(this); 

     return b; 
    } 

    protected void assign(Parent c) { 
     x = c.x; 
    } 

    @Override 
    public String toString() { 
     return getClass().getName() + ", " + x; 
    } 
} 

public class Child extends Parent { 
    int y; 

    protected Child() {} 

    public Child(int x0, int y0) { 
     super(x0); 
     y = y0; 
    } 

    @Override 
    public Child copy() { 
     Child b = new Child(); 
     b.assign(this); 

     return b; 
    } 

    @Override 
    protected void assign(Child c) { 
     super.assign(c); 
     y = c.y; 
    } 

    @Override 
    public String toString() { 
     return getClass().getName() + ", " + x + "," + y; 
    } 
} 

public class Test { 
    public static void main(String[] args) { 
     Parent x = new Parent(5); 
     Child y = new Child(10, 20); 
     Parent z = x.copy(); 
     Parent w = y.copy(); 

     System.out.println(x); 
     System.out.println(y); 
     System.out.println(z); 
     System.out.println(w); 
    } 
} 

輸出爲:

com.xxx.zzz.Parent, 5 
com.xxx.zzz.Child, 10,20 
com.xxx.zzz.Parent, 5 
com.xxx.zzz.Child, 10,20 

而且做同樣的另一個(短)的方式(使用反射):

public class Parent { 
    int x; 

    public Parent() {} 

    public Parent(int x0) { 
     x = x0; 
    } 

    public Parent copy() { 
     try { 
      Parent b = getClass().newInstance(); 
      b.assign(this); 
      return b; 
     } catch (InstantiationException | IllegalAccessException e) { 
      e.printStackTrace(); 
      return null; 
     } 
    } 

    protected void assign(Parent c) { 
     x = c.x; 
    } 

    @Override 
    public String toString() { 
     return getClass().getName() + ", " + x; 
    } 
} 

public class Child extends Parent { 
    int y; 

    protected Child() {} 

    public Child(int x0, int y0) { 
     super(x0); 
     y = y0; 
    } 

    protected void assign(Child c) { 
     super.assign(c); 
     y = c.y; 
    } 

    @Override 
    public String toString() { 
     return getClass().getName() + ", " + x + "," + y; 
    } 
} 

沒有必要重寫Child類中的copy()。但我不知道如何使用getClass()。newInstance()構造一個副本佔位符'合法'...

上面的解決方案是值得使用還是有更常見/強大/簡單的方法?

謝謝!

+0

如果'Child'具有默認構造函數,則這不起作用。 –

回答

2

您的解決方案看起來不錯對我來說,這個特定用例。

使用newInstance()的主要侷限,是:

  • 只與具有一個無參數的構造函數對象的作品,並
  • 這將是無法克隆具有最終場
  • 對象

有一些庫支持克隆。看看Kryo。它是一個序列化庫,它還支持克隆(深層和淺層),包括沒有無參數構造函數的對象或有最終字段的對象。

0

我從來不是「克隆()」方法的忠實粉絲。拷貝構造函數似乎更優雅IMO:

public class Parent { 
    int x; 

    public Parent() { 
     super(); 
    } 

    public Parent(Parent other) { 
     super(); 
     this.x = other.x; 
    } 
} 

public class Child extends Parent { 
    int y; 

    public Child() { 
     super(); 
    } 

    public Child(Child other) { 
     super(other); 
     this.y = other.y; 
    } 
} 

注意,這也具有能夠做到這一點額外的好處,如果你需要:

Parent p = new Parent(new Child(...)); 

你當然可以阻止這種行爲該構造函數通過檢查具體的參數類型 ,但我不明白爲什麼你需要在大多數情況下。

+1

問題是複製構造函數不能正確處理多態 – user671786