Универсальный интерфейс c обратной связью
Я хочу создать два интерфейса с обратными связями.
public interface Item <D extends Description,
C extends Category<D,Item<D,C>>> {
public C getCategory();
public void setCategory(C category);}
Я не уверен, что выражение C extends Category<D,Item<D,C>>
- это правильно, но по крайней мере нет ошибок компилятора.
public interface Category<D extends Description, I extends Item> {
public List<I> getItems();
public void setItems(List<I> items);}
I extends Item
дает предупреждение Item is a raw type. References to Item<D,C> should be parametrized
. Я пытался!--9-->
I extends Item<D,Category<D,I>>
но это приводит к ошибке Bound mismatch: The type Category<D,I> is not a valid substitute for the bounded parameter <C extends Category<D,Item<D,C>>> of the type Item<D,C>
. Как параметризовать интерфейс Category
правильно с дженерики?
5 ответов
Это, кажется, работает :). Я понятия не имею, как это объяснить ( обычно я стараюсь избегать подобных вещей), но вот оно:
interface Description {}
interface Item<D extends Description, I extends Item<D, I, C>, C extends Category<D, C, I>>
{
public C getCategory();
public void setCategory(C category);
}
interface Category<D extends Description, C extends Category<D, C, I>, I extends Item<D, I, C>> {
public List<I> getItems();
public void setItems(List<I> items);
}
class DescriptionImpl implements Description {}
class CustomItem implements Item<DescriptionImpl, CustomItem, CustomCategory> {
public CustomCategory getCategory() {
return null;
}
public void setCategory(CustomCategory category) {
}
}
class CustomCategory implements Category<DescriptionImpl, CustomCategory, CustomItem> {
public List<CustomItem> getItems() {
return null; }
public void setItems(List<CustomItem> items) {
}
}
Теперь, если вы сделаете это:
CustomCategory customCategory = new CustomCategory();
CustomItem customItem = new CustomItem();
DescriptionImpl description = new DescriptionImpl();
customItem.getCategory();
тип категории, возвращаемой customItem.getCategory()
является CustomCategory, который я думаю, что это то, что вы на самом деле хотите.
это компилируется без предупреждений:
interface Description {}
interface Item<D extends Description, C extends Category<D, Item<D, C>>> {
public C getCategory();
public void setCategory(C category);
}
public interface Category<D extends Description, I extends Item<D, ?>> {
public List<I> getItems();
public void setItems(List<I> items);
}
Я I extends Item<D, ?>
. Хотя это не имеет никаких предупреждений, это может вызвать у вас другие проблемы - дайте мне знать, если это произойдет, и я посмотрю, что я могу сделать.
найдите время, чтобы прочитать это: http://www.artima.com/forums/flat.jsp?forum=106&thread=136394&start=15&msRange=15#180733
давайте сначала забудем о описании и просто сделаем несколько хороших симметричных интерфейсов:
interface Item<C extends Category<Item<C>>> {}
interface Category<I extends Item<Category<I>>> {}
для описания может потребоваться два разных типа описания для элемента и категории.
в более общем плане, я не уверен, что ваш дизайн-это хорошая идея. Я не знаю, для чего вы будете использовать его, но похоже, что это будет трудно использовать правильно.
кроме того, что-то не так с item.setCategory(c)
С item
уже параметризован категорией.
рассмотрим эту упрощенную задачу
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?
еще раз, мы должны полагаться на дисциплину программиста, чтобы не делать такие вещи.