我再次面临泛型问题,我想我现在知道如何做到这一点。为了说明我创建了这个简单的例子。
鉴于此界面
public interface Converter<A, B> {
B encode( A a);
}
为什么会出现以下错误:
void onRequest(ArrayList<String> a,Converter <? extends List<String>,String> conv) {
conv.encode(a);
}
我预计,使用这种表示法,conv.encode将接受任何扩展List的参数
任何想法?
答案 0 :(得分:2)
将其更改为:
void onRequest(ArrayList<String> a,Converter <? super List<String>,String> conv) {
conv.encode(a);
}
您希望使用ArrayList调用encode,因此ArrayList必须是Converter的furst类型参数的子类。因此,第一个类型参数必须是ArrayList的超级类。通过使它成为List的超级,这将自动得到保证。
答案 1 :(得分:2)
原因是Converter <? extends List<String>,String>
允许所有Converter
类型的第一个通用参数属于List
的子类型,例如Converter<LinkedList, String>
。如果我们假装您的代码可以键入check,在您的示例中,这将允许您调用onRequest:
void onRequest(ArrayList<String> a,Converter <? extends List<String>,String> conv) {
conv.encode(a);
}
void callsOnRequest() {
onRequest(new ArrayList<String>(), new Converter<LinkedList<String>,String>);
}
这不是您的意思。
如果您将extends
替换为super
,您基本上会告诉编译器,转换器的第二个参数必须不比 List
更具体,因此任何列表(例如您的ArrayList
)将可分配给a参数。
答案 2 :(得分:1)
“?extends String”并不意味着“List&lt; String&gt;”的任何子类型,而是“List&lt; String&gt;”的未知子类型。
方法onRequest接受一个Converter对象,该对象使用一些未知的List&lt; String&gt;进行参数化。亚型。因此,它说客户端可能会传递一个转换器&lt; ArrayList&lt; String&gt;,String&gt;以及转换器&lt; LinkedList&lt; String&gt;,String&gt; - 这不是你想要的。
在这个例子中,我认为根本不需要使用通配符。如果希望onRequest能够传递ArrayList,那么转换器&lt; List&lt; String&gt;,String&gt;就够了。
你也可以使用转换器&lt;?超级列表&lt; String&gt;,String&gt;,但这将允许客户端传递转换器&lt; Object,String&gt;以及转换器&lt; Collection&lt; String&gt;,String&gt;等