Рассмотрим эту упрощенную задачу
interface Item<C extends Container<Item<C>>>
interface Container<I extends Item<Container<I>>>
Это не работает, потому что подтипы Container<Item<C>>
довольно ограничены - Container<MyItem>
не является его подтипом, так же как List<string>
не является подтипом List<Object>
Мы можем расслабиться с подстановочными знаками:
interface Item<C extends Container<? extends Item<C>>>
interface Container<I extends Item<? extends Container<I>>>
Теперь все отлично работает
class MyItem implements Item<MyContainer>
class MyContainer implements Container<MyItem>
в основном. Следующее объявление также допускается, но не то, что мы намеревались
class HerItem implements Item<MyContainer> // nooo!
Это потому, что мы слишком ослабили ограничения. Ну, это не очень серьезная проблема. Конечно, наша система типов не такая жесткая, как хотелось бы (система типов не существует), но программисты инстинктивно следуют намеченным ограничениям, не выходя из своих способов писать причудливые вещи только потому, что могут.
В идеале нам нужен тип This
, и наши предполагаемые ограничения могут быть выражены как
interface Item<C extends Container<This>>>
interface Container<I extends Item<This>>
Поскольку у нас нет This
, можно попытаться приблизиться к нему с помощью параметра типа
interface Item<C extends Container<This, C>>, This extends Item<C, This> >
interface Container<I extends Item<This, I>, This extends Container<I, This>>
(или, более симметрично
interface Item<C extends Container<I, C>>, I extends Item<C, I> >
interface Container<I extends Item<C, I>, C extends Container<I, C>>
) Тем не менее, это не так уж и сложно. This
на самом деле не «этот тип». Можно
class HerItem implements Item<MyContainer, MyItem> // uh?
Еще раз, мы должны полагаться на дисциплину программиста, чтобы не делать такие вещи.