我有两个抽象的泛型类。他们合作,因此相互依赖。偶尔需要将this
传递给另一个。我正在努力找到一种安全的方式来做到这一点。
public abstract class AbstractA<T extends AbstractB<? extends AbstractA<T>>> {
protected void foo() {
T aB = createB();
aB.setA(this);
}
/** factory method */
abstract public T createB();
}
public abstract class AbstractB<T extends AbstractA<? extends AbstractB<T>>> {
private T theA;
@SuppressWarnings("unchecked")
public void setA(AbstractA<? extends AbstractB<?>> theA) { // dreamed of parameter list (T theA)
// Unchecked cast from AbstractA<capture#1-of ? extends AbstractB<?>> to T
this.theA = (T) theA;
}
protected T getA() {
return theA;
}
}
我的问题是我是否能找到更清洁的方式,以避免AbstractB.setA()
中未经检查的演员表。我原本希望声明它setA(T theA)
,但是对它的调用将无法编译:方法setA(捕获#1-of?extends AbstractA&lt; T&gt;)在AbstractB&lt; capture#1-of?中?扩展AbstractA&lt; T&gt;&gt;不适用于参数(AbstractA&lt; T&gt;)。我仍在努力了解编译器是否应该知道是否允许它。
我在想我的问题可能与Java generics compilation error - The method method(Class<capture#1-of ? extends Interface>) in the type <type> is not applicable for the arguments中讨论的问题有关。我的未经检验的演员从那里受到启发。我喜欢Tom Hawtin的回复 - 攻击,但我还没有办法将它应用到我的情况中。
我的用户将声明具体的子类并实例化一个ConcreteA
和任意数量的ConcreteB
s:
public class ConcreteA extends AbstractA<ConcreteB> {
@Override
public ConcreteB createB() {
return new ConcreteB();
}
public void concreteAMethod() {
// ...
}
}
public class ConcreteB extends AbstractB<ConcreteA> {
public void bar() {
ConcreteA a = getA();
a.concreteAMethod();
}
}
(class AbstractA<T extends AbstractB<? extends AbstractA<T>>>
看起来有点复杂;我认为我需要它来具体的子类来了解彼此的确切类型,但显然它并没有给我这个。)
答案 0 :(得分:0)
如果我理解正确,那么应该创建你想要的绑定。
class Demo {
public static void main(String[] args) {
ConcreteA a = new ConcreteA();
ConcreteB b = new ConcreteB();
a.foo(b);
b = (ConcreteB) a.getB();
}
}
abstract class AbstractA<T extends AbstractB<?>>{
private AbstractB<?> b;
public AbstractB<?> getB(){
return b;
}
void foo(AbstractB<?> aB) {
b = aB;
aB.bar(this);
}
}
abstract class AbstractB<T extends AbstractA<?>> {
private AbstractA<?> a;
public AbstractA<?> getA(){
return a;
}
public void bar(AbstractA<?> theA) {
a = theA;
theA.foo(this);
}
}
class ConcreteA extends AbstractA<ConcreteB>{
}
class ConcreteB extends AbstractB<ConcreteA>{
}
我认为这就是你自己的结果。我无法将转换移到ConcreteB,getB()根本无法确定它所持有的类型。我现在明白为什么你的声明中有多个通用语句。 :)
如果你准备好了,继续搜索,如果找到答案就发布你自己的答案,我很乐意看到它。
我希望解决你的一半问题。 ;)
答案 1 :(得分:0)
我想我现在知道为什么我不能在public void setA(T theA)
中声明AbstractB
,然后在aB.setA(this)
中将其称为foo()
。假设我们有:
class IntermediateConcreteA extends AbstractA<ConcreteB> {
@Override
public ConcreteB createB() {
return new ConcreteB();
}
}
class SubConcreteA1 extends IntermediateConcreteA {}
class SubConcreteA2 extends IntermediateConcreteA {}
class ConcreteB extends AbstractB<SubConcreteA2> {}
现在,如果我有一个SubConcreteA1
并调用其foo()
,那么createB()
将返回一个可以作为AbstractB<SubConcreteA2>
传递但不能作为{{1}传递的对象}}。因此,AbstractB<SubConcreteA1>
不应接受setA()
作为参数。毕竟编译器错误消息是合乎逻辑的。
答案 2 :(得分:0)
每个抽象类都将使用两个类型参数进行参数化,一个用于实际的具体类A,另一个用于实际的具体类B:
public abstract class AbstractA<A extends AbstractA<A,B>, B extends AbstractB<A,B>> {
protected void foo() {
B aB = createB();
aB.setA(getThis());
}
abstract public A getThis();
abstract public B createB();
}
public abstract class AbstractB<A extends AbstractA<A,B>, B extends AbstractB<A,B>> {
private A theA;
public void setA(A theA) {
this.theA = theA;
}
protected A getA() {
return theA;
}
}
public class ConcreteA extends AbstractA<ConcreteA, ConcreteB> {
@Override
public ConcreteA getThis() {
return this;
}
@Override
public ConcreteB createB() {
return new ConcreteB();
}
public void concreteAMethod() {
// ...
}
}
public class ConcreteB extends AbstractB<ConcreteA, ConcreteB> {
public void bar() {
ConcreteA a = getA();
a.concreteAMethod();
}
}
答案 3 :(得分:0)
工厂可以解决它:
public abstract class AbstractA {
public void abstractAMethod() {
// ...
}
}
public abstract class AbstractB<A> {
private A theA;
public void setA(A theA) {
this.theA = theA;
}
protected A getA() {
return theA;
}
}
public abstract class AbstractFactory<A extends AbstractA, B extends AbstractB<A>> {
private A theA = createA();
public A getA() {
return theA ;
}
public B getNextB() {
B newB = createB();
newB.setA(theA);
return newB;
}
protected abstract A createA();
protected abstract B createB();
}
现在用户可以去:
public class ConcreteA extends AbstractA {
public void concreteAMethod() {
// ...
}
}
public class ConcreteB extends AbstractB<ConcreteA> {
public void bar() {
ConcreteA a = getA();
a.abstractAMethod();
a.concreteAMethod();
}
}
public class ConcreteFactory extends AbstractFactory<ConcreteA, ConcreteB> {
@Override
protected ConcreteA createA() {
return new ConcreteA();
}
@Override
protected ConcreteB createB() {
return new ConcreteB();
}
}
我不认为这是抽象工厂模式的典型应用,但是......
@Chris Wohlert,我确实放弃了我的生产代码,因为我认为工厂过度杀伤,但我无法理解这个理论问题。答案 4 :(得分:0)
我已经意识到我的问题实际上是将两个概念填充到不属于一起的AbstractA / ConcreteA层次结构中。虽然对很多人来说可能没什么兴趣,但我发布这个见解有两个原因:(1)我觉得我欠Chris Wohlert的答案我发现自己(2)更重要的是,我喜欢激励其他任何面临类似狡猾的人泛型问题,从更高层次审查您的设计,而不仅仅是解决泛型和/或类演员问题。它当然帮助了我。演员/仿制品问题表明一些更基本的东西并不完全正确。
public abstract class AbstractA {
public void foo() {
AbstractB aB = createB();
aB.setA(this);
}
/** factory method */
abstract public AbstractB createB();
}
public abstract class AbstractB {
private AbstractA theA;
public void setA(AbstractA theA) {
this.theA = theA;
}
// methods that use theA
}
没有泛型,也没有课堂演员。取出不属于A类层次结构的东西到ConcreteC(没有AbstractC):
public class Client {
public void putTheActTogether() {
ConcreteC theC = new ConcreteC();
// the concrete A
AbstractA theA = new AbstractA() {
@Override
public AbstractB createB() {
return new ConcreteB(theC);
}
};
// call methods in theA
}
}
public class ConcreteB extends AbstractB {
private final ConcreteC c;
public ConcreteB(ConcreteC c) {
super();
this.c = c;
}
public void bar() {
c.concreteCMethod();
}
}
public class ConcreteC {
public void concreteCMethod() { // was concreteAMethod(); moved and renamed
// ...
}
}
客户需要比以前更多的线路。在我的真实世界代码中,我需要在AbstractA和ConcreteC中复制一个最终字段,但这样做是有意义的。总而言之,我认为对于纯粹而简单的设计而言,它的价格很低。