【问题标题】:Java: "? extends I" cannot be converted to "? extends I"Java:“?扩展我”不能转换为“?扩展我”
【发布时间】:2014-02-25 19:19:59
【问题描述】:

这段代码:

interface I {}

public class Test {

    TableView<? extends I> table;

    Test(ObservableList<? extends I> list) {
        table = new TableView<>();
        table.setItems(list);
    }
}

...产生此消息:

error: method setItems in class TableView<S> cannot be applied to given types;
       table.setItems(list);
 required: ObservableList<CAP#1>
 found: ObservableList<CAP#2>
 reason: argument mismatch; ObservableList<CAP#2> cannot be converted to ObservableList<CAP#1>
 where S is a type-variable:
   S extends Object declared in class TableView
 where CAP#1,CAP#2 are fresh type-variables:
   CAP#1 extends I from capture of ? extends I
   CAP#2 extends I from capture of ? extends I

两个相同类型之间怎么会出现类型不匹配?我错过了什么?

【问题讨论】:

  • 昨天我吃了一些水果。即? extends Fruit 今天我吃了一些水果。 ? extends Fruit。有人可以从这些信息中假设,我两天都吃相同类型的水果吗?号some fruit #1 可能不是some fruit #2

标签: java generics


【解决方案1】:

在 Java 泛型中,? 通配符不能相同,因为它们代表未知类型。未知类型不能等于其他未知类型。

如果您希望类型匹配,则必须在 Test 类上定义一个泛型类型参数,并在整个类中引用它。

public class Test<T extends I> {

    TableView<T> table;

    Test(ObservableList<T> list) {
        table = new TableView<>();
        table.setItems(list);
    }
}

【讨论】:

    【解决方案2】:
    Collection<?> c = new ArrayList<String>();
    c.add(new Object()); // Compile time error
    

    "由于我们不知道 c 的元素类型代表什么,所以我们不能向它添加对象。add() 方法接受类型为 E 的参数,即集合的元素类型。当实际类型参数为?, 它代表一些未知类型。我们传递给 add 的任何参数都必须是这个未知类型的子类型。由于我们不知道那是什么类型,所以我们不能传递任何东西。唯一的例外是 null,它是所有类型的成员。

    另一方面,给定一个 List,我们可以调用 get() 并使用结果。结果类型是未知类型,但我们始终知道它是一个对象。因此,将 get() 的结果分配给 Object 类型的变量或将其作为参数传递给 Object 类型的变量是安全的。" (http://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html)

    【讨论】:

      【解决方案3】:

      不要在变量声明中使用“? extends I”。它没有增加语义价值,并且是您问题的根源。你看到编译器拒绝假设'?在一个声明中与“?”相同在另一个。这是自然的,因为不能保证它们是。我会省去'?一共:

      interface I {}
      
      public class Test {
      
          TableView<I> table;
      
          Test(ObservableList<? extends I> list) {
              table = new TableView<>();
              table.setItems(list);
          }
      }
      

      【讨论】:

      • 更好的是:不要使用泛型,除非你正在编写一些真正通用的组件来分发并允许扩展(通过开放/封闭原则)。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-08-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-20
      相关资源
      最近更新 更多