2016-11-02 7 views
3

EDIT: Да, это может быть дубликат. Но в то время как другой вопрос сродни: «Что такое бензопила и как ее использовать?» моя больше похожа на «Я пытаюсь просверлить отверстие этой машиной здесь, и это не сработает - что случилось?». Конечно, ответ: «Не используйте бензопилу!» и легко найти, как только вы знаете, что имеете дело с бензопилой.Java Generics: параметры типа «вложенные»?

Но я даже не знал, что мой вопрос был связан с «сырыми типами против диких карт» и поэтому не нашел этого вопроса - так что, возможно, этот вопрос по-прежнему полезен для других, подобных мне.

ORIGINAL ВОПРОС: Скажем, у меня есть следующая структура данных, которая представляет собой элемент в моем пользовательском интерфейсе:

public static abstract class RowItem<T> { 

    public final T value; 

    public RowItem(T value) { 
     this.value = value; 
    } 
} 

Теперь, я хотел бы сделать следующее:

public static abstract class EpgRowItem<T> extends RowItem<Pair<String, T>> { 

    public EpgRowItem(Pair<String, T> value) { 
     super(value); 
    } 
} 

public static final class EpgRowProgramItem extends EpgRowItem<Program> { 

    public EpgRowProgramItem(Pair<String, Program> value) { 
     super(value); 
    } 
} 

public static final class EpgRowOtherDateItem extends EpgRowItem<LocalDate> { 

    public EpgRowOtherDateItem(Pair<String, LocalDate> value) { 
     super(value); 
    } 
} 

Итак, на словах: EpgRowItem - это RowItem, который содержит Pair, первым элементом которого всегда является String, а второй элемент может быть любым. Кроме того, EpgRowProgramItem является EpgRowItem, в котором вторым элементом пары является Program. Аналогично, EpgRowOtherDateItem представляет собой EpgRowItem, в котором вторым элементом пары является LocalDate.

Это похоже на работу, пока у меня это в другом месте в моем коде:

List<OverlayPresenter.EpgRowItem> programs = ...; 
OverlayPresenter.EpgRowItem epgRowItem = programs.get(0); 
String channelId = epgRowItem.value.first; // DOESN'T COMPILE?! 

Я чувствую, что компилятор должен знать, что epgRowItem.value должен всегда быть Pair<String, ?>, и, следовательно, epgRowItem.value.first должны ВСЕГДА быть String.

На самом деле, это даже не похоже на первую часть, т.е. е. следующее не компилируется либо:

Pair<String, ?> pair = epgRowItem.value; // epgRowItem.value is an Object?! 

Что я делаю неправильно? Я просто спрашиваю слишком много о дженериках Java?

+0

Да, теперь я знаю ответ, это я конечно, дубликат. Но так как я спросил «наоборот» - начиная с конкретной проблемы, а не с ключевого слова высокого уровня, я думаю, что это все еще правильный вопрос и может быть полезен для других. –

ответ

4

Вы получаете в беду, потому что вы используете необработанный тип EpgRowItem (сырьевой тип параметризованный тип, для которого вы не задаете параметры типа, они существуют из-за обратной совместимости с Java 1.4 и старше):

List<OverlayPresenter.EpgRowItem> programs = ...; 
OverlayPresenter.EpgRowItem epgRowItem = programs.get(0); 

См: What is a raw type and why shouldn't we use it?

Используйте параметр типа или, по крайней мере, подстановочные:

List<OverlayPresenter.EpgRowItem<?>> programs = ...; 
OverlayPresenter.EpgRowItem<?> epgRowItem = programs.get(0); 
String channelId = epgRowItem.value.first; // OK 
+0

О, это интересно. До сих пор я всегда чувствовал себя достаточно уверенно в использовании Java Generics, но это было ново для меня. Большое спасибо! –