Java 泛型:"Nested" 类型参数?

Java Generics: "Nested" type parameters?

编辑: 是的,这可能是重复的。但是另一个问题类似于 "What is a chainsaw and how do I use it?" 我的更像是 "I am trying to drill a hole with this machine here and it doesn't work - what's up?"。当然,答案是 "Don't use a chainsaw!",一旦您知道自己在处理电锯,就很容易找到。

但我什至不知道我的问题与 "raw types vs. wild cards" 有关,因此没有找到那个问题 - 所以也许这个问题对像我这样的其他人仍然有用。

原始问题:假设我有以下数据结构,代表我的用户界面中的一个项目:

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 是包含 PairRowItem,其中第一个成员始终是 String,第二个成员可以是任何东西。此外,EpgRowProgramItemEpgRowItem,其中该对的第二个成员是 Program。同样,EpgRowOtherDateItemEpgRowItem,其中第二个成员是 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.

实际上,它似乎连第一部分都不知道,我。 e.以下也不编译:

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

我哪里做错了?我是不是对Java的泛型要求太多了?

您遇到麻烦是因为您使用的是原始类型 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