又一个java泛型问题

时间:2011-07-04 10:04:01

标签: java generics

我再次面临泛型问题,我想我现在知道如何做到这一点。为了说明我创建了这个简单的例子。

鉴于此界面

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的参数

任何想法?

3 个答案:

答案 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;等