【问题标题】:In Java, how does List<Object> differ from List<? extends Object>? [duplicate]在 Java 中,List<Object> 与 List< 有何不同?扩展对象>? [复制]
【发布时间】:2019-04-15 06:27:05
【问题描述】:

(注意:这this question about vs. !)

我对 Java 的泛型感到困惑。

ArrayList<? extends Object> x = new ArrayList<String>();
ArrayList<Object> y = new ArrayList<String>();

在本例中,第一行编译,而第二行不编译。这是为什么呢?

我认为形状 List&lt;A&gt; x = new ArrayList&lt;B&gt;() 的赋值应该与 B extends A 一样有效,即右侧比赋值的左侧具有更高的特异性,但显然我错了。

有人能详细说明这些陈述的异同吗?

【问题讨论】:

标签: java generics inheritance types


【解决方案1】:

在 Java 中,类型参数必须完全匹配。

考虑以下代码sn-p:

ArrayList<Object> list = new ArrayList<String>();
list.add(new SomeClass());

我们现在已经成功地将一个非字符串添加到ArrayList&lt;String&gt;。第二个语句没有任何问题:我们正在向ArrayList&lt;Object&gt; 添加一些对象。所以第一句话肯定有问题!这就是 Java 不允许你这样做的原因。

如果将 sn-p 更改为:

ArrayList<? extends Object> list = new ArrayList<String>();
list.add(new SomeClass());

您会注意到错误现在位于第二行。您不能将对象添加到列表中。

两者的区别如下:

  • ArrayList&lt;Object&gt; 表示“包含 Objects 的 ArrayList”。这样的列表当然也可以包含Object 的子类的实例。因为每个对象都是Object 的一个实例,所以这个列表可以包含任何对象(在这种情况下)。

  • ArrayList&lt;? extends Object&gt; 表示“一个 ArrayList,其中包含 Object 的某些未知子类的实例”。这样的 ArrayList 不能包含所有对象。只能将这个未知子类的实例添加到其中。由于不知道具体的子类,所以无法在此处添加元素。 (但在其他地方,同一个列表可能称为ArrayList&lt;String&gt;,当然也可以在其中添加元素。)

【讨论】:

  • 到你的第一个例子 - 但是Object[] z = new Integer[3]; 然后z[2] = "ALP3"; 都编译得很好。我只是在运行时收到一个 ArrayStoreException。
  • 您的两个要点很好地阐明了我的区别。非常感谢! :)
  • @ChrisOffner。是的,数组早于泛型并且工作方式不同。特别是,String[] 被视为Object[] 的子类型,但List&lt;String&gt; 不是List&lt;Object&gt; 的子类型。
【解决方案2】:

以下两种情况都不起作用,因为您正在初始化与预期不同的对象类型:

ArrayList<Object> y = new ArrayList<String>();
ArrayList<String> y2 = new ArrayList<Object>();

如果您使用? 通配符,您将获得更多不同的选项,但与继承类型相关(String 隐式扩展Object):

ArrayList<? extends Object> x = new ArrayList<String>();

考虑也使用diamond operator

ArrayList<Object> y = new ArrayList<>();

只要编译器可以从上下文推断类型参数,您就可以用一组空类型参数 () 替换调用泛型类的构造函数所需的类型参数。这对尖括号被非正式地称为菱形。

【讨论】:

    【解决方案3】:
    String abc = "abc";
    Object x = abc;
    

    有效但

    List<Object> list = new ArrayList<String>();
    

    不是因为如果泛型表达式不包含通配符,则它们必须完全匹配。

    请注意,在声明方面最好使用List(而不是ArrayList),因为它允许您在稍后阶段更改实现,例如到LinkedList

    【讨论】:

    • 为什么Object obj = new String(); 有效?泛型表达式的工作方式不同,或者只是历史上的不一致,是否存在逻辑和有意识的设计决策?
    • @ChrisOffner Object obj = new String(); 有效,因为每个字符串也是一个对象。但是List&lt;Object&gt; 也不是List&lt;String&gt;,因为您可以将Long 放入List&lt;Object&gt;,但您不能将Long 放入List&lt;String&gt;。这就是编译器不允许这种赋值的原因。
    猜你喜欢
    • 2012-12-22
    • 2023-03-14
    • 1970-01-01
    • 1970-01-01
    • 2021-12-15
    • 2021-08-08
    • 1970-01-01
    • 2014-04-14
    • 1970-01-01
    相关资源
    最近更新 更多