3

我有一些类似的代码:

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 的东西。

4

2 回答 2

4

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

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

这将按预期工作:

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

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

它的实用性在于你的Bar类有一个public T getT()方法。一个类型的变量Baz<? extends Bar>可以同时包含Baz<Bar>和的对象Baz<SubBar>,并且您可以调用getT()它来获取一个Bar(或某个子类)并且可以像这样使用的东西。

于 2012-10-04T18:47:36.060 回答
0

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

private static class OtherSubBar extends Bar {}

然后你可以这样做:

Baz<SubBar> baz = new Baz<SubBar>();
foo(baz, new OtherSubBar());
于 2012-10-04T18:47:16.607 回答