5

Java でディープ ポリモーフィック コピーを作成する際に、突然問題が発生しました。私の場合、 Clonableを実装することで問題は解決しますが、これは「悪い」手法と呼ばれることがよくあります。

したがって、「クローン不可」のソリューションを見つけるための私の試みは次のとおりです。

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() を使用してコピープレースホルダーを作成することが「合法」であるかどうかはわかりません...

上記のソリューションは使用する価値がありますか、それともより一般的/堅牢/シンプルなアプローチがありますか?

ありがとうございました !

4

3 に答える 3

2

この特定のユースケースでは、あなたのソリューションは私には問題ないように見えます。

を使用する場合の主な制限は次のnewInstance()とおりです。

  • 引数のないコンストラクターを持つオブジェクトでのみ機能し、
  • 最終フィールドを持つオブジェクトを複製することはできません

クローニングをサポートするライブラリがいくつかあります。クリオを見てください。これは、引数のないコンストラクターのないオブジェクトや final フィールドを持つオブジェクトを含め、クローニング (ディープおよびシャロー) もサポートするシリアライゼーション ライブラリです。

于 2012-11-16T00:21:31.110 に答える
0

私は「clone()」アプローチの大ファンではありませんでした。コピーコンストラクターは、より洗練された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(...));

もちろん、引数の具体的なクラス型をチェックすることで、コンストラクターでその動作を防ぐことができますが、ほとんどの場合、なぜそうする必要があるのか​​わかりません。

于 2012-11-16T02:50:20.303 に答える
0

コピー コンストラクターまたはクローン可能オブジェクトを使用する代わりに、シリアル化を使用してコピーを実行できます。

http://www.javaworld.com/javaworld/javatips/jw-javatip76.html?page=2

于 2012-11-16T00:20:28.640 に答える