这个问题以前可能被问过一百万次,但我在为具有有界类型参数的抽象类编写复制构造函数时遇到了麻烦。我有一些代码看起来像这样:
public abstract class Superclass<T> {
Set<? extends Variable<T>> vars;
public abstract Superclass<? extends T> copy();
class Variable<T> {
T value;
}
}
class Foo extends Superclass<Integer> {
public Foo copy() {
Foo _newFoo = Foo();
Set<FooVariable> _newVars = new HashSet<FooVariable>();
_newVars.addAll(this.vars);
_newFoo.vars = _newVars;
}
class FooVariable extends Variable<Integer> { /* ... */ }
}
class Bar extends Superclass<String> {
public Bar copy() {
Bar _newBar = Bar();
Set<BarVariable> _newVars = new HashSet<BarVariable>();
_newVars.addAll(this.vars);
_newBar.vars = _newVars;
}
class BarVariable extends Variable<String> { /* ... */ }
}
由于Foo
和Bar
的copy
方法除了变量类型之外是相同的,所以我希望能够将代码移动到超类中的具体方法中。但我不知道(a)如果在Foo
上调用具体的public Superclass<? extends T> copy
方法,则如何返回Foo
实例,如果在Bar
上调用Bar
实例,以及(b)根据需要用FooVariable
s或BarVariable
s填充vars
集合。
有人能帮我告诉我缺了什么吗?谢谢
这种Superclass
怎么样?
public abstract class Superclass<T> {
Set<? extends Variable<T>> vars;
public Superclass<? extends T> copy() {
Superclass<T> _newSuperclass = this.getNewInstance();
Set<Variable<T>> _newVars = new HashSet<Variable<T>>();
_newVars.addAll(this.vars);
_newSuperclass.vars = _newVars;
return _newSuperclass;
}
public abstract Superclass<T> getNewInstance();
class Variable<T> {
T value;
}
}
重点是,您只需要在子类中实现getNewInstance()
,而不是在构造函数中实现。
所以Foo
看起来就像:
class Foo extends Superclass<Integer> {
@Override
public Superclass<Integer> getNewInstance() {
return new Foo();
}
class FooVariable extends Variable<Integer> { /* ... */ }
}
引入第二个泛型类型参数来表示Variable<T>
、U
。
然后,Foo.FooVariable<T>
和Bar.BarVariable<T>
满足U
的边界,并且可以从copy
方法返回。
编辑
我已经修改了代码,将copy
的实现转移到超类中。它依赖于newInstance
方法(@OndrejBozek已经介绍过)。
public abstract class Superclass<T, U extends Variable<T>> {
Set<U> vars;
class Variable<T> {
T value;
}
public Superclass<T, U> copy() {
Superclass<T, U> _newSuperclass = newInstance();
Set<U> _newVars = new HashSet<U>();
_newVars.addAll(vars);
_newSuperclass.vars = _newVars;
return _newSuperclass;
}
public abstract Superclass<T, U> newInstance();
}
class Foo extends Superclass<Integer, Foo.FooVariable> {
public Foo newInstance() { return new Foo(); }
class FooVariable extends Variable<Integer> { /* ... */ }
}
class Bar extends Superclass<String, Bar.BarVariable> {
public Bar newInstance() { return new Bar(); }
class BarVariable extends Variable<String> { /* ... */ }
}
测试了这个代码,它有几个警告,但它做了你想要的:
public <C extends Superclass<? extends T>> C copy() throws InstantiationException, IllegalAccessException {
C result= (C) this.getClass().newInstance();
HashSet newVars= new HashSet();
newVars.addAll(this.vars);
result.vars= newVars;
return result;
}
有一句话:这不是一个复制构造函数。这只是一种复制方法。构造函数没有返回类型,并且其名称等于类名。