Вы фактически имеющие взаимное рекурсивное общее определение, что вы нарушаете с использованием сырьевых видов: в
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<?>
.
Update, так как вы просили общий дизайн:
Я бы думать о InterfaceB (на самом деле, интерфейсы в целом), как абстракции от конкретной реализации: Вам нужно только интерфейс InterfaceB, а не его детали реализации, в вашей реализации InterfaceA. Подумайте о InterfaceB как о контракте, и вам не нужна реализация. Следовательно, нет необходимости в связывании осуществления InterfaceA осуществлению InterfaceB:
public interface InterfaceA {
public interface InterfaceB {
void setA(InterfaceA a);
}
}
Только если, по причинам, я не могу видеть, вы хотите иметь один и тот же тип для всех экземпляров InterfaceB, что вы используются, вам нужны дженерики. И наоборот для InterfaceA. В приведенном выше примере дженериков вы, по крайней мере, можете исправить типы для InterfaceA и InterfaceB, и вам нужно будет только динамически утверждать, что A и B являются одинаковыми.
Показано, что ни один тип проверил решения не существует в Java трудно, но, возможно, это становится правдоподобным следующим примером, который был бы решением, если Java допускается сочетание расширяет и супер:
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);
}
}
.. ,подумайте об этом, система Pluggable Type System, которая добавляет дополнительную типизацию на Java, допускает эту комбинацию расширений и супер, и поэтому может предложить решение вашей проблемы. Но я считаю это слишком сложным для того, что вы получаете, и будет либо придерживаться простого использования интерфейсов без дженериков, либо неконтролируемого актерского состава.
Использование однобуквенных имен классов «A» в вопросе о дженериках очень сбивает с толку – artbristol
Так же, как и с использованием вложенных классов, 'AImpl' должен быть' AImplOne' или 'AImplTwo', есть опечатка в имени вопроса , у вас нет параметра типа для 'B' (здесь:' B *> '. Это может быть проблемой, но ваш пример кода немного сложнее. –
rlegendi
@artbristol: Good Point: Переименованы 'A' в' InterfaceA' и 'B' в' InterfaceB' – Peter