无法将Map <long,string =“”>传递给带有参数Map <! - 的构造函数? extends Object,? extends Object - >。为什么?</长,>

时间:2012-12-15 14:35:53

标签: java generics

我有以下课程:

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 个答案:

答案 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>的实例。