问题
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