2012-03-07 2 views
3

У меня есть вопрос относительно дженериков. У меня есть следующие интерфейсы:Привязать два типа типа

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) - снимок.

Но как это можно реализовать или переделать, чтобы избавиться от непроверенного кода?

+5

Использование однобуквенных имен классов «A» в вопросе о дженериках очень сбивает с толку – artbristol

+0

Так же, как и с использованием вложенных классов, 'AImpl' должен быть' AImplOne' или 'AImplTwo', есть опечатка в имени вопроса , у вас нет параметра типа для 'B' (здесь:' B *> '. Это может быть проблемой, но ваш пример кода немного сложнее. – rlegendi

+0

@artbristol: Good Point: Переименованы 'A' в' InterfaceA' и 'B' в' InterfaceB' – Peter

ответ

2

Вы фактически имеющие взаимное рекурсивное общее определение, что вы нарушаете с использованием сырьевых видов: в

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, допускает эту комбинацию расширений и супер, и поэтому может предложить решение вашей проблемы. Но я считаю это слишком сложным для того, что вы получаете, и будет либо придерживаться простого использования интерфейсов без дженериков, либо неконтролируемого актерского состава.

+0

Итак, это можно сделать только с использованием сырых типов. Но как это можно решить более элегантно? Обычно спрашивают, как сделать реализация, знающая друг друга в абстрактном подклассе? – Peter

+0

@Peter: см. мое обновление. HTH. – DaveFar

Смежные вопросы