我对仿制药有疑问。
我有以下界面:
public interface InterfaceA<B extends InterfaceA.InterfaceB> {
public interface InterfaceB<A extends InterfaceA> {
void setA(A a);
}
}
以及
InterfaceA
的以下抽象实现:public abstract class AImplOne<B extends InterfaceA.InterfaceB> implements InterfaceA<B> {
private final B b;
public AImplOne(B b) {
this.b = b;
b.setA(this); // <-- Unchecked call...
}
}
我很清楚,对
b.setA(this)
的调用是未经检查的-但我不喜欢它,因此我尝试了第二种抽象实现:public abstract class AImplTwo<A extends InterfaceA, B extends InterfaceA.InterfaceB<A>> implements InterfaceA<B> {
private final B b;
public AImplTwo(B b) {
this.b = b;
b.setA((A)this); // <-- Unchecked cast
}
}
同样,对我来说很清楚,调用
b.setA((A)this)
是未选中的强制转换。但是,为了摆脱未经检查的代码,应该如何实现或重新设计它呢?
最佳答案
实际上,您有一个相互递归的通用定义,使用原始类型会破坏该定义:
b.setA((A)this); // <- Unchecked cast
this
的类型为InterfaceA<? extends InterfaceA.InterfaceB<? extends InterfaceA>>
,但应为InterfaceA<? extends InterfaceA.InterfaceB<? extends InterfaceA<? extends InterfaceA.InterfaceB<...>>>>
的类型。您将不得不使用public interface InterfaceA<B extends InterfaceA.InterfaceB<?>> {
public interface InterfaceB<A extends InterfaceA<B>> { //<- cannot make a static reference to the non-static type B
void setA(A a);
}
}
但是您不能在静态接口声明中使用非静态的
B
(接口声明始终为静态)。有关详细信息,请进一步尝试:使用替代方法
public interface InterfaceA<B extends InterfaceA.InterfaceB<?>> {
public interface InterfaceB<A extends InterfaceA<? extends InterfaceA.InterfaceB<?>>> {
void setA(A a);
}
}
abstract class AImplTwo<B extends InterfaceA.InterfaceB<A>, A extends InterfaceA<B>> implements InterfaceA<B> {
private final B b;
public AImplTwo(B b) {
this.b = b;
b.setA((A)this); // <-- Unchecked cast
}
}
再次导致未经检查的转换,因为现在
InterfaceA
中的interface InterfaceB<A extends InterfaceA<? extends InterfaceA.InterfaceB<?>>>
的嵌套类型参数再次是InterfaceA.InterfaceB<?>
的任意子类。更新,因为您已要求一般设计:
我会认为InterfaceB(实际上是一般的接口)是从一个具体实现中抽象出来的:在InterfaceA的实现中,只需要接口InterfaceB,而无需实现细节。可以将InterfaceB视为合同,而无需考虑实现。因此,无需将InterfaceA的实现绑定到InterfaceB的实现:
public interface InterfaceA {
public interface InterfaceB {
void setA(InterfaceA a);
}
}
仅出于某种原因(出于我看不到的原因),您确实希望所使用的InterfaceB的所有实例都具有相同的类型,才需要泛型。反之亦然。在上面的最后一个泛型示例中,您至少可以修复InterfaceA和InterfaceB的类型,而只需动态断言A的B和B的A相同。
显示Java中不存在类型检查解决方案是很困难的,但也许可以通过以下示例来弄清楚,如果Java允许将extends和super结合使用,那么这将是一个解决方案:
public interface A<TB extends A.B<?>> {
public interface B<TA extends A<? extends A.B<?>>> {
void setA(TA a);
}
}
class AImplTwo<TB extends A.B<TA>, TA extends AImplTwo<TB, TA> super AImplTwo<TB, TA>> implements A<TB> {
private final TB b;
public AImplTwo(TB b) {
this.b = b;
b.setA((TA)this);
}
}
...想到了这一点,可插入类型系统将Java的更多类型添加进来,允许扩展和超级的这种组合,因此可能为您的问题提供解决方案。但是我发现它对于您获得的结果来说太复杂了,要么要么坚持只使用不带泛型的接口,要么坚持使用未经检查的类型转换。
关于java - 绑定(bind)两种通用类型,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/9598538/