7

如果我想做这样的事情:

List<?> unknownList = new ArrayList<>();

然后代码编译并运行良好,但是创建了哪种类型ArrayList

在这一行之后,如果我这样做了:

        unknownList.add("str"); //compilation error

它给出了编译错误:

error: no suitable method found for add(String)
        unList.add("str");
              ^
method List.add(int,CAP#1) is not applicable
  (actual and formal argument lists differ in length)
method List.add(CAP#1) is not applicable
  (actual argument String cannot be converted to CAP#1 by method invocation conversion)
method Collection.add(CAP#1) is not applicable
  (actual argument String cannot be converted to CAP#1 by method invocation conversion)
where CAP#1 is a fresh type-variable:
    CAP#1 extends Object from capture of ?

这是什么错误,将菱形运算符与通配符一起使用是否很好?如果是,那么在哪里???

4

3 回答 3

4

但是创建 ArrayList 的类型是什么?

类型参数只是在编译时应用的约束,但类型擦除会用擦除替换所有出现的类型参数(在你的情况下,Object)。因此,如果您询问运行时类型,它将是一个普通的ArrayList(您可以将其视为ArrayList<Object>)。

将菱形运算符与通配符一起使用是否很好?如果是,那么在哪里???

不。当您使用菱形运算符创建泛型类的新对象时,这意味着您不希望在类型参数上变得多余。它不应与没有具体类型参数的通配符声明的变量结合使用。

总而言之,你永远不应该写:

List<?> unknownList = new ArrayList<>();

<?>当类型真的无关紧要时,您应该只使用通配符。特别是,如果您想将项目添加到列表中,请不要使用通配符,因为添加项目意味着您知道要添加什么类型

例如,它很可能用作方法的参数,当您不访问值而只是传递列表时,或者您只是将列表项作为普通对象访问。

于 2014-04-08T11:35:31.987 回答
2

你的错误是你有一个 type 的变量List<?>,你正在调用add它,并传递一个String.

如果你的变量是 type 的,你可以这样做List<String>——但由于它只是 type List<?>,编译器无法知道将 a 添加String到变量引用的任何列表是否合法。

如果您要存储字符串,请确保您有一个类型的变量List<String>(或其他一些字符串集合)来存储它们。

使用菱形运算符创建将存储在类型为通配符的变量中的东西是非常好的。菱形运算符对您在运行时获得的结果没有影响;在运行时,没有类型参数。您对创建的对象执行的任何后续操作都将在编译时根据变量的类型进行检查,而不是根据您用于创建对象的代码行进行检查。

于 2014-04-08T11:38:36.087 回答
0

但是 ArrayList 创建了哪种类型?

可能是ArrayList<Object>。可能是ArrayList<String>。可能是ArrayList<SomeBogusUnrelatedClass>。这真的没关系,因为无论如何它们之间的编译代码没有区别,而且你得到的只是 aList<?>所以你不能假设类型参数是什么。

将菱形运算符与通配符一起使用是否很好?

没有。对新创建的通用对象进行通配符参数化引用是没有意义的。

于 2014-04-08T23:41:25.143 回答