Polymorphic copy in Java

大憨熊 提交于 2020-01-03 13:20:09

问题


I've suddenly encountered a problem of making a deep polymorphic copy in Java. Implementing Clonable solves the problem in my case, but it is often referred as a "bad" technique.

So, here are my attempts to find a "no-Clonable" solution:

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);
    }
}

the output is:

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

And another(shorter) way of doing the same (using Reflection):

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;
    }
}

No need for overriding copy() in the Child class. But i'm not sure how 'legal' it is to use getClass().newInstance() to construct a copy placeholder...

Are the solutions above worth using or there are more common/robust/simple approaches ?

Thank you !


回答1:


Your solution looks okay to me, for this particular use case.

The main limitations of using newInstance(), are that:

  • it only works with objects which have a no-arg constructor, and
  • it would be unable to clone objects which have final fields

There are some libraries which support cloning. Take a look at Kryo. It is a serialization library which also supports cloning (deep and shallow), including of objects without no-arg constructors or which have final fields.




回答2:


As an alternative to using a copy constructor or cloneable you could use serialization to perform your copy.

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




回答3:


I've never been a big fan of the "clone()" approach. Copy constructors seem to be more elegant 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;
    }
}

Note, this also has the added benefit of being able to do this if you need to:

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

You could of course prevent that behavior in the constructor by checking the concrete class type of the argument, but i don't see why you'd need to in most cases.



来源:https://stackoverflow.com/questions/13408202/polymorphic-copy-in-java

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!