【问题标题】:Using generics with wildcards does not allow using methods with generic as a parameter使用带有通配符的泛型不允许使用带有泛型作为参数的方法
【发布时间】:2010-07-12 12:51:20
【问题描述】:

如果我将泛型类声明为类似

public class Driver<V extends Car>

Car 是一个接口。

然后,我将它与这样的东西一起使用:

Driver<?> driver = new Driver<Chevrolet>();

我不想将 car 的特定实现指定为泛型。

为什么我不能调用在以泛型类为参数的驱动中实现的方法?

例如,如果 Driver 有类似的方法

public void drive(V vehicle)

它不允许我用我的驱动程序实例 (Driver&lt;?&gt;) 调用它。

【问题讨论】:

  • 添加了java标签,因为它看起来像java...如果我错了请更正:)

标签: java generics wildcard compiler-errors


【解决方案1】:

因为编译器不知道driver.drive(? vehicle) 会接受什么类型的参数。应该是雪佛兰、本田还是其他类型?

有关更多详细信息,您可能会发现 Gilad Bracha's Generics Tutorial 很有帮助。

您的 drive() 方法的目的是什么。 vehicle 参数是否需要键入 Car 的特定子类型?简单地接受Car 是否更合适?


以下是我原始答案的一部分,但在 cmets 中的讨论证明它是不正确的。我把它留在这里,以免 cmets 成为孤儿。

尝试像这样声明你的方法:

public <T extends V> void drive(T vehicle)

看看这是否更适合你。

【讨论】:

  • 我仍然看不出这是如何回答这个问题的。你还是不行driver.drive(aChevrolet),可以吗?
  • 你是对的,假设 driver 仍然被声明为 Driver>,但是,由于类 Driver 要求其泛型参数是 Car 或 Car 的子类,因此声明 driver 是合理的作为类型驱动程序 而不损失任何灵活性。有了这个额外的改变,我认为我的答案是有效的。
  • 不,Driver&lt;? extends Car&gt; 可能是Driver&lt;BMW&gt;,并且由于Chevrolet 没有扩展BMW(我希望我没看错,我不懂汽车),你还是不能drive(aChevrolet)
  • @polygenelubricants:是的,你是对的。我要再次编辑我的帖子。
【解决方案2】:

这个问题很模糊,但我相信 Angelika Langer 的 Java 泛型常见问题解答的摘录可以回答这个问题:

哪些方法和字段可以通过通配符参数化类型的引用变量访问/不可访问?

这取决于通配符的种类。

通过通配符参数化类型的引用变量使用对象受到限制。考虑以下类:

示例(泛型类):

class Box<T> {
  private T t;
  public Box(T t) { this.t = t; }
  public void put(T t) { this.t = t;}
  public T take() { return t; }
  public boolean equalTo(Box<T> other) {
     return this.t.equals(other.t);
  }
  public Box<T> copy() {
     return new Box<T>(t);
  }
} 

当我们使用 Box 类型的通配符实例化的引用变量来 编译器将访问被引用对象的方法和字段 拒绝某些调用。

示例(通过通配符参数化类型访问):

class Test {
  public static void main(String[] args) {
    Box<?> box = new Box<String>("abc");

    box.put("xyz");    // error
    box.put(null);     // ok

    String s = box.take();  // error
    Object o = box.take();  // ok

    boolean equal = box.equalTo(box);            // error
    equal = box.equalTo(new Box<String>("abc")); // error

    Box<?> box1 = box.copy();       // ok
    Box<String> box2 = box.copy();  // error
  }
}

基本上? 对泛型类型系统的信息较少,因此为了强制类型安全,某些调用必须被拒绝,因为它们不是类型安全的。

Box&lt;?&gt; 可能是 Box&lt;Integer&gt;Box&lt;String&gt;,甚至是 Box&lt;Box&lt;?&gt;&gt;。因此给定一个Box&lt;?&gt; boxbox.put("xyz") 必须被拒绝。

参考文献

相关问题

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多