我有以下课程:
class MySelectBox {
public MySelectBox(Provider<Map<? extends Object, ? extends Object>> providerArrayIdToLabel) {
...
}
}
我正在尝试在使用此类的代码中传递此内容:
new MySelectBox(new Provider<Map<Long, String>>{
... my implementation of Provider ...
});
编译器出现以下错误:
The constructor MySelectBox(new Provider<Map<Long,String>>(){}) is undefined
为什么呢?为什么方法未定义?我应该在构造函数的签名中更改什么才能使其接受Provider<Map<Long, String>>
注意:Provider接口是:
public interface Provider<T> extends javax.inject.Provider<T> {
T get();
}
答案 0 :(得分:5)
将MySelectBox构造函数的声明更改为:
public MySelectBox(Provider<? extends Map<? extends Long, ? extends String>> providerArrayIdToLabel)
答案 1 :(得分:2)
要扩展答案,您的标题是错误的,并不反映问题。您可以将Map<Long, String>
传递给Map<? extends Object, ? extends Object>
。那不是问题。如果X和Y不同(此处X为Provider<X>
且Y为Provider<Y>
),则无法将Map<Long, String>
传递给Map<? extends Object, ? extends Object>
。如果X是Y的子类型并不重要。这就像你不能将Provider<String>
传递给Provider<Object>
一样,即使String是Object的子类型。但是,如果您在顶级使用通配符,则允许您允许子类型 - 您可以将Provider<X>
传递给Provider<? extends Y>
。
答案 2 :(得分:1)
这就是Java泛型不变的效果。
由于该映射被传递给构造函数,我认为最好的解决方法是将键和值类型声明为类泛型,因此每个实例都将包含特定键和值的映射:
class MySelectBox<K, V> {
public MySelectBox(Provider<Map<K, V>> map) {}
}
现在你可以安全地写:
new MySelectBox<Long, String>(new Provider<Map<Long, String>>());
答案 3 :(得分:0)
将您的代码更改为
new MySelectBox(new Provider<Map<?, ?>>() {
@Override
public Map<Long, String> get() {
return null;
}
});
这是我尝试解释(这可能是错误的,因为我也很难用泛型):
编译器不知道Provider只创建对象。它认为Provider<Map<?, ?>>
是一个能够容纳Map<?, ?>
实例的对象(就像List<Map<?, ?>>
)。并且由于Provider<Map<?, ?>>
应该能够将包含任何内容的地图保存为键,而将任何内容保存为值,因此Provider<Map<Long, String>>
不是有效的类型替换。实际上,Provider<Map<Long, String>>
只能保存Map<Long, String>
的实例。