2

我有以下课程:

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();
}
4

4 回答 4

5

将 MySelectBox 构造函数的声明更改为:

public MySelectBox(Provider<? extends Map<? extends Long, ? extends String>> providerArrayIdToLabel) 
于 2012-12-15T14:52:28.857 回答
2

为了扩展答案,您的标题是错误的并且不能反映问题。您可以将 a 传递给Map<Long, String>a Map<? extends Object, ? extends Object>。那不是问题。如果 X 和 Y 不同(这里 X 是并且 Y 是) ,您不能将 a 传递Provider<X>给 a 。X 是否是 Y 的子类型并不重要。这就像您不能传递给 a即使 String 是 Object 的子类型一样。但是,如果您在顶层使用通配符,这将允许您允许子类型——您可以传递给.Provider<Y>Map<Long, String>Map<? extends Object, ? extends Object>Provider<String>Provider<Object>Provider<X>Provider<? extends Y>

于 2012-12-15T22:09:27.160 回答
1

That's the effect of the Java generics being invariant.

Since that map is passed to the constructor, I think the best fix would be to declare the key and value types as class generics, so each instance will hold a map of specific keys and values:

class MySelectBox<K, V> {
    public MySelectBox(Provider<Map<K, V>> map) {}
}

Now you can safely write:

new MySelectBox<Long, String>(new Provider<Map<Long, String>>());
于 2012-12-15T15:04:39.533 回答
0

将您的代码更改为

    new MySelectBox(new Provider<Map<?, ?>>() {
        @Override
        public Map<Long, String> get() {
            return null;
        }
    });

这是我的解释尝试(这可能是错误的,因为我也很难使用泛型):

编译器不知道 Provider 只创建对象。它认为 aProvider<Map<?, ?>>是一个能够保存Map<?, ?>(就像 a List<Map<?, ?>>)实例的对象。而且由于 aProvider<Map<?, ?>>应该能够保存包含任何作为键和任何作为值的映射,因此 aProvider<Map<Long, String>>不是有效的类型替换。实际上, aProvider<Map<Long, String>>只能保存 的实例Map<Long, String>

于 2012-12-15T14:57:52.060 回答