2012-11-15 9 views
5

Javaで深い多形コピーを作成するという問題が突然発生しました。 を実装するClonableは私の場合は問題を解決しますが、しばしば「悪い」手法と呼ばれます。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