【问题标题】:Why generic type is not applicable for argument extends super class for both?为什么泛型类型不适用于参数扩展了两者的超类?
【发布时间】:2014-01-30 09:50:59
【问题描述】:

这是我一直在努力寻找解决方案的问题。

我们有两个类定义。两个之一扩展另一个。

    class T{}
    class TT extends T{}

要求是要有一个list keep object extends T

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

但是当我尝试放置一个 TT 对象时会出现问题(几乎看起来它是 T 的子类) 进入列表。

    list.add(new TT());

编译错误信息

类型List中的add(capture#2-of ? extends Cell)方法不适用于参数(Cell)

【问题讨论】:

标签: java generics extends


【解决方案1】:

你可以直接创建一个List&lt;T&gt; list = new ArrayList&lt;T&gt;();,这样可以允许T的所有子类型进入列表。这实际上有点难以理解。当您将其声明为

List<? extends T> list = ...

这意味着它可以允许T 的任何未知子类型进入列表。但是,根据该声明,我们无法确定 T 的确切子类型。所以,我们只能在其中添加null

【讨论】:

    【解决方案2】:

    List&lt;? extends T&gt; 表示任何可以从中产生的东西都可以转换为 T,因此真正的列表可以是以下任何一种:

    • List&lt;T&gt;
    • List&lt;T2&gt;
    • List&lt;TT&gt;

    您可以看到,即使是新的 T 也无法安全地添加到此类集合中,因为它可能是无法放入 TList&lt;T2&gt;。因此,此类列表不能添加非空条目。

    在这种情况下,您可能只需要List&lt;T&gt;

    那你为什么要使用这个?!

    这种逆变性对于方法参数或返回很有用,其中将读取而不是添加到集合。这样做的一个用途可能是创建一个方法,该方法接受任何包含 T 或扩展 T 项的集合。

    public static void processList(Collection<? extends Vector3d> list){
        for(Vector3d vector:list){
            //do something
        }
    }
    

    这个方法可以接受任何扩展 Vector3d 的对象集合,所以ArrayList&lt;MyExtendedVector3d&gt; 是可以接受的。

    同样,一个方法可以返回这样一个集合。 Returning a Collection<ChildType> from a method that specifies that it returns Collection<ParentType> 中描述了一个用例示例。

    【讨论】:

    • 是否可以实例化类型参数包含有界通配符的List?例如,List&lt;? extends T&gt; list = new ArrayList&lt;? extends T&gt;()?我假设没有,因为我收到编译器错误,但是当钻石运算符像在 OP 的示例中那样使用时会发生什么?
    • @KevinBowersox With &lt;&gt; 它可以编译,但它完全没有意义
    【解决方案3】:

    要求是要有一个list keep object extends T

    如果您只想要一个List,您可以在其中存储从T 扩展的任何类的对象,那么只需像这样创建一个List

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

    您当前创建列表的方式不允许您向其中添加除null 之外的任何内容。

    【讨论】:

    • @ᴍarounᴍaroun 我试图在my answer 中解释这一点,但这是因为该列表不能保证接受除 null 之外的任何对象类型
    • @ᴍarounᴍaroun 啊!对不起,我不在,但我想你已经得到了答案。
    • @codelovesme 我无法完全理解您的评论。你能不能即兴一点语法。否则,我想你明白了。
    【解决方案4】:

    在使用通配符时为 Java 泛型定义了边界规则

      **extends Wildcard Boundary**
    

    List 表示作为 T 类或 T 的子类(例如 TT)的实例的对象列表。这意味着 Read 很好,但是插入会失败,因为您不知道该类是否被键入到 T

    **super Wildcard Boundary**
    

    当您知道列表类型为 T 或 T 的超类时,将 T 的实例或 T 的子类(例如 TT )插入列表是安全的。

    在你的例子中,你应该使用“super”

    【讨论】:

      【解决方案5】:

      除了此处发布的其他答案之外,我只想补充一点,我只对方法参数和返回类型使用通配符。它们用于方法签名,而不是实现。当我将通配符放入变量声明时,我总是会遇到麻烦。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-02-21
        • 1970-01-01
        • 2012-01-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多