我有一些类似的代码:
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的东西。
答案 0 :(得分: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
的内容(或一些子类)并且可以像这样使用。
答案 1 :(得分:0)
您要做的不是类型安全。如果你有:
private static class OtherSubBar extends Bar {}
然后你可以这样做:
Baz<SubBar> baz = new Baz<SubBar>();
foo(baz, new OtherSubBar());