【问题标题】:Generic types in Java - advanced polymorphismJava 中的泛型类型 - 高级多态性
【发布时间】:2013-10-11 16:00:04
【问题描述】:

我有 3 个简单的类如下:

public class ElementA {}
public class ElementB extends ElementA {}
public class ElementC extends ElementB {}

然后,如果我想创建,例如,只接受 ElementA 类的子类的泛型 List,我可以将其声明为:

List<? super ElementA> list = new ArrayList<>();

然后按如下方式使用:

list.add(new ElementA());
list.add(new ElementB());
list.add(new ElementC());

这很好,可以无错误地编译。但是如果我想存储除 ElementC 或 ElementB 或 ElementA 之外的任何东西,我就会感到困惑。我声明这样的列表如下:

List<? extends ElementC> list = new ArrayList<>();

我根本不能使用它,因为它只能存储空值。当我将 List 声明为时也会发生同样的事情(请注意,我使用的是“在家庭中”的类):

List<? extends ElementB>

为什么会这样?

【问题讨论】:

  • 你为什么希望 List&lt;? extends ElementC&gt; list = new ArrayList&lt;&gt;(); 存储任何东西,你没有任何扩展 ElementC 的类?
  • 请阅读我的问题的结尾。即使使用 Object 类,我也尝试过,但 List 仍然只能存储空值
  • List &lt;? extends Object&gt; list = new ArrayList &lt;&gt;(); ?您应该使用如下元素初始化您的列表:List&lt;? extends ElementB&gt; list = new ArrayList&lt;ElementC&gt;();
  • Java 7 不需要这个。
  • This 几乎涵盖了它。

标签: java oop generics object polymorphism


【解决方案1】:

问题是? 的值在运行时是未知的。你必须替换一个具体的类/接口才能做你想做的事。

如果你这样做:

List<ElementA> list = new ArrayList<ElementA>();

你很好,因为ElementB 同时是一个 ElementA。同样代表ElementC

List&lt;? extends ElementA&gt; 是有意义的,例如,如果你在一个类和一个子类中声明它,你可以用一些具体的东西作为类型参数。笨拙的例子:

public class SomeClass<T> {
    private List<? extends T> list;

    public void setList(List<? extends T> list) {
        this.list = list;
    }
}

public class SomeConcreteClass extends SomeClass<Integer> {

    public void doSomething() {
        List<Integer> list = new ArrayList<Integer>();
        setList(list);
    }
}

【讨论】:

    【解决方案2】:

    List&lt;ElementA&gt; 接受 ElementAElementBElement C 的实例。

    List&lt;ElementB&gt; 接受 ElementBElement C 的实例。

    List&lt;ElementC&gt; 接受 ElementC 的实例。

    您的示例中没有使用通配符的理由。

    List&lt;? super ElementA&gt; 表示某种类型的列表,即ElementA 或超类。

    List&lt;? extends ElementB&gt; 表示某种类型的列表,它是ElementB 的子类。如果您get 一个元素,它将是ElementB 或子类,但它不知道该类是什么,因此无法确定您添加的元素是正确的类型,因为它是未知的(尽管它确实知道它是ElementB 的子类)。

    通配符有多种用途,但您的示例不是其中之一。

    【讨论】:

    • 关于List&lt;? super ElementA&gt; 看看here:“通配符参数化类型Comparator&lt;? super String&gt;Comparator 接口的所有实例化系列,用于类型参数类型是超类型String"。你似乎在说相反的说法。
    • "List&lt;? extends ElementB&gt; 表示某种类型的列表,它是ElementB 的子类" -- 实际上,它也可以是ElementB 的列表;它不限于ElementB子类
    • 好收获。错字就我而言。固定。
    【解决方案3】:

    你像这样创建List

    List<? extends ElementC> list = new ArrayList<>();
    

    但是让我们说,因为你得到这样的List 仍然有效

    List<? extends ElementC> list = getElementCSubclassList(); // declared as returning a `List<ElementCSubclass>`
    

    现在编译器无法知道您的list 对象包含ElementCSubclass 对象,它只能确定它包含一些 类型的ElementC。因此,它不能让您使用任何期望实际泛型类型的方法。

    想象一下

    public class ElementCSubclass1 extends ElementC {}
    public class ElementCSubclass2 extends ElementC {}
    ...
    List<? extends ElementC> list = getElementCSubclass1List(); // declared as returning a `List<ElementCSubclass1>`
    
    list.add(new ElementCSubclass2()); // this would immediately have to fail
    

    编译器这样做是为了避免以前的情况发生。

    【讨论】:

      猜你喜欢
      • 2023-03-05
      • 2011-07-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-06-15
      相关资源
      最近更新 更多