我的方法通用参数有什么问题

时间:2014-04-10 12:18:48

标签: java android

我想用通用映射填充List,但我的代码不能编译。我已经为这个问题准备了最简单的例子。在上面的注释中,有问题的行我将错误放在下面的行中。

void populateList(List<? extends Map<String,?>> list) {
    list.clear();
    HashMap<String, ?>  map;
    map = new HashMap<String,String>();
    //The method put(String, capture#2-of ?) in the type HashMap<String,capture#2-of ?> is not applicable for the arguments (String, String)
    map.put("key", "value"); // this line does not compile
    // The method add(capture#3-of ? extends Map<String,?>) in the type List<capture#3-of ? extends Map<String,?>> is not applicable for the arguments (HashMap<String,capture#5-of ?>)
    list.add(map);      //This line does not compile
}

为什么会这样?有什么我不明白的吗?

编辑1

根据下面的一个答案,他指出了?代表未知类型而不是Object的后代。这是一个有效的观点。而且,在方法内部我知道进入map的类型,所以我相应地修改了我的简单代码。

void populateList(List<? extends Map<String,?>> list) {
    list.clear();
    HashMap<String, String>  map;  //known types
    map = new HashMap<String,String>(); 
    map.put("key", "value"); // this line now compiles
    // The method add(capture#3-of ? extends Map<String,?>) in the type List<capture#3-of ? extends Map<String,?>> is not applicable for the arguments (HashMap<String,capture#5-of ?>)
    list.add(map);      //This line STILL does not compile. Why is that?
}

我问这个的原因是因为android SDK的方法形式需要这样的列表,因为它似乎无法填充这样的列表。怎么做到这一点?强制转换?

编辑2

由于有几个改变我签名的提议,我会补充说我不能这样做。 Basicaly,我想填充SimpleExpandablaListAdapter的列表。

void test() {
    ExpandableListView expandableListView.setAdapter(new ArrayAdapterRetailStore(this, R.layout.list_item_retail_store, retailStores));

    List<? extends Map<String, ?>> groupData= new ArrayList<HashMap<String,String>>();
    populateGroup(groupData)
    // child data ommited for simplicity
    expandableListView.setAdapter(  new SimpleExpandableListAdapter(
            this,
            groupdata,
            R.layout.list_group,
            new String[] {"GroupKey"},
            new int[] {R.id.tvGroupText},
            childData,
            R.layout.list_item_child,
            new String[] {"ChildKey"},
            new int[] {R.id.tvChilText}));
}

// I want populateGroupData() to be generic
void populateGroupData(List<? extends Map<String,?>> groupData) {
    groupData.clear();
    HashMap<String,String>  map;
    map = new HashMap<String,String>();
    map.put("key", "value");
    groupData.add(map); // does not compile 
}

4 个答案:

答案 0 :(得分:6)

来自文档

  

当实际类型参数为?时,它代表某种未知类型。我们传递给add的任何参数都必须是这种未知类型的子类型。由于我们不知道它是什么类型,我们无法传递任何内容。唯一的例外是null,它是每种类型的成员。

所以,你只能添加

list.add(null);

请在Generics Wildcards

上阅读本教程

答案 1 :(得分:2)

这是工作代码

//also works with void populateList(List<Map<String,?>> list) {
void populateList(List<? super Map<String,?>> list) {
    list.clear();
    Map<String, String>  map;
    map = new HashMap<String,String>();
    map.put("key", "value"); // this line now compiles
    list.add(map);      //This line compiles
}

以及它的工作原理:

List<? super Map<String,?>> list or simply List<Map<String,?>> list 
// => this ensure you that the list can contains a Map<String,?>.

Map<String, String>  map is a Map<String,?> 
// =>that can ber inserted to the list, so you  don't need any cast

编辑:

常见的错误是通配符&#34;?扩展Map&#34;将函数调用限制为&#34;至少&#34;键入地图。这不是你想要的,因为你可以传递List < TreeMap <字符串,?>>例如不能包含HashMap。另外,您无法使用列表<对象>

来调用您的方法

- &GT;为了说明泛型限制,我添加了2个带超级和扩展的例子

void exampleWithExtends(List<? extends Map<String,?>> list) {

}
void exampleWithSuper(List<? super Map<String,?>> list) {

}

void funWithGenerics(){
    exampleWithExtends(new ArrayList<TreeMap<String,String>>());
    exampleWithExtends(new ArrayList<Map<String,?>>());//works in both cases
    //exampleWithExtends(new ArrayList<Object>()); /does not compile
    //exampleWithSuper(new ArrayList<TreeMap<String,String>>()); //does not compile
    exampleWithSuper(new ArrayList<Map<String,?>>());//works in both cases
    exampleWithSuper(new ArrayList<Object>());
}

答案 2 :(得分:0)

Java是类型安全的!至少在这一点上:)

这样可以解决问题:

HashMap<String, String> map = new HashMap<String,String>(); 
map.put("key", "value");
((List<Map<String,String>>)groupData).add(map);

答案 3 :(得分:0)

没有演员表,你无法写Map<String, String> map = getMap("abc"); 问题更多地与easymock以及expect和andReturn方法返回/预期的类型有关,我不熟悉这些方法。你可以写

Map<String, String> expected = new HashMap<String, String> ();
Map<?, ?> actual = getMap("someKey");
boolean ok = actual.equals(pageMaps);
//or in a junit like syntax
assertEquals(expected, actual);

不确定这是否可以与你的嘲弄混合。这可能会奏效:

EasyMock.expect((Map<String, String>) config.getMap("sillyMap")).andReturn(pageMaps);

另请注意,您无法使用通配符向通用集合添加任何内容。所以这个:

Map<?, ?> map = ...
map.put(a, b);

不会编译,除非a和b为空