【问题标题】:Java Generics - cannot be applied to given typeJava 泛型 - 不能应用于给定类型
【发布时间】:2012-10-05 02:47:36
【问题描述】:

我有一些类似的代码:

public class Main {

    private static abstract class Bar {}

    private static class SubBar extends Bar {}

    private static abstract class Baz<T extends Bar> {

        private T t;

        public void setT(T t) {
            this.t = t;
        }

    }

    private static class SubBaz extends Baz<SubBar> {}


    private void foo(Baz<? extends Bar> baz, Bar bar) {
        baz.setT(bar);
    }
 }

这会导致错误:

error: method setT in class Baz<T> cannot be applied to given types;
required: CAP#1
found: Bar
reason: actual argument Bar cannot be converted to CAP#1 by method invocation conversion
where T is a type-variable:
T extends Bar declared in class Baz
where CAP#1 is a fresh type-variable:
CAP#1 extends Bar from capture of ? extends Bar

我不明白为什么。方法 setT 应该接受扩展 Bar 的东西,我正在传递类 Bar 的东西。

【问题讨论】:

  • 我不是。抽象的名字只会让我感到困惑。

标签: java generics


【解决方案1】:

setT 方法应该接受扩展 Bar 的东西,而我传递的是 Bar 类的东西。

这正是问题所在:&lt;? extends Bar&gt; 的意思是“某种未知类型,即 Bar 或其子类”。由于您不知道它是哪种类型,因此实际上不可能在这种情况下调用 setT(),除非使用 null 参数。

这将按预期工作:

private void foo(Baz<Bar> baz, Bar bar) {
    baz.setT(bar);
}

我敢肯定,Stackoverflow 上有数百种此类问题的变体。似乎几乎每个程序员起初都误解了? 通配符的用途并错误地使用了它。

它的实用性在于您的Bar 类具有public T getT() 方法。 Baz&lt;? extends Bar&gt; 类型的变量可以同时保存 Baz&lt;Bar&gt;Baz&lt;SubBar&gt; 的对象,并且您可以在其上调用 getT() 以获取 Bar(或某个子类)的内容,并且可以像这样使用。

【讨论】:

  • 也许写Baz&lt;? super Bar&gt; 会更好,因为baz 充当消费者。
  • @axtavt 这可能是也可能不是预期的。
  • @axtavt 我认为最好的选择是&lt;T extends Bar&gt; void foo(Baz&lt;? super T&gt; baz, T bar)。您正确地识别出它正在充当消费者,但是如果您再次扩展 Sub 类,则额外的类型参数会更加灵活。例如,这允许您传入 SubBazSubSubBar
【解决方案2】:

您正在尝试做的不是类型安全。如果你有:

private static class OtherSubBar extends Bar {}

你可以这样做:

Baz<SubBar> baz = new Baz<SubBar>();
foo(baz, new OtherSubBar());

【讨论】:

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