Java中的多态副本

时间:2012-11-15 23:42:51

标签: java reflection polymorphism deep-copy

我突然遇到了在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()构建一个副本占位符是多么“合法”...

上述解决方案是否值得使用,或者有更常见/强大/简单的方法?

谢谢!

3 个答案:

答案 0 :(得分:2)

对于这个特定的用例,您的解决方案对我来说没问题。

使用newInstance()的主要限制是:

  • 它只适用于具有无参数构造函数的对象
  • 它将无法克隆具有最终字段的对象

有一些库支持克隆。看看Kryo。它是一个序列化库,它还支持克隆(深度和浅层),包括没有无参数构造函数或具有最终字段的对象。

答案 1 :(得分:0)

作为使用复制构造函数或克隆的替代方法,您可以使用序列化来执行复制。

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

答案 2 :(得分: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(...));

您当然可以通过检查具体来阻止构造函数中的行为 参数的类类型,但我不明白为什么在大多数情况下你需要这样做。