我有一个基类,说Base
指定抽象方法deepCopy
,以及无数的子类,比如A
,B
,C
,...... Z
。如何定义deepCopy
以使其每个类public X deepCopy()
的签名为X
?
是的,现在,我有:
abstract class Base {
public abstract Base deepCopy();
}
不幸的是,这意味着如果我有一个来自子类的对象,比如a
A
,那么我总是必须为更具体的深层副本执行未经检查的强制转换:
A aCopy = (A) a.deepCopy();
有没有办法,也许使用泛型,以避免施法?我想保证任何深层副本都返回相同运行时类的对象。
编辑:让我扩展我的答案,因为协变打字是不够的。说,然后我想实现一个方法:
static <N extends Base> List<N> copyNodes(List<N> nodes) {
List<N> list = Lists.newArrayList();
for (N node : nodes) {
@SuppressWarnings("unchecked")
N copy = (N) node.deepCopy();
list.add(copy);
}
return list;
}
我怎样才能避免未经检查的警告?
答案 0 :(得分:5)
Java 5支持协变返回类型,这意味着您可以在每个子类中实现deepCopy()
方法以返回特定的子类实例; e.g。
public class Z extends Base {
@Override
public Z deepCopy() {
}
}
有关协变返回类型的更多信息here。
答案 1 :(得分:2)
这真的不太漂亮,我可能不会自己做,但是:
public abstract class Base<T extends Base<T>> {
public abstract T deepCopy();
}
public class Extender extends Base<Extender> {
@Override
public Extender deepCopy() {
// TODO Auto-generated method stub
return null;
}
}
或者....
public abstract class Base<T extends Base<T>> {
public abstract T deepCopy();
}
public class Extender<T extends Base<T>> extends Base<T> {
@Override
public T deepCopy() {
// TODO Auto-generated method stub
return null;
}
}
答案 2 :(得分:1)
怎么样......
public interface DeeplyCloneable <T extends Cloneable> {
public T deepClone();
}
然后......例如......(有错误,但有良好的意图;帮助!)
public class DeeplyClonableHashTable
<T1 extends DeeplyCloneable<?>,T2 extends DeeplyCloneable<?>>
extends Hashtable<T1,T2>
implements DeeplyCloneable<Hashtable<T1,T2>>{
@Override
public Hashtable<T1, T2> deepClone() {
Object o = super.clone();
if ((o == null) || (! (o instanceof DeeplyClonableHashTable<?,?>)))
{
throw new DeepCloneException(
"Object instance does not support deepCloneing.");
}
@SuppressWarnings("unchecked")
DeeplyClonableHashTable<T1,T2> copy = (DeeplyClonableHashTable<T1,T2>)o;
Set<T1> keys = copy.keySet();
for (T1 key: keys){
T2 value = this.get(key);
T1 keyCopy = key.deepClone(); // this line is in error
T2 valueCopy = value.deepClone(); // this line is in error
copy.put(keyCopy, valueCopy);
}
return copy;
}
}