"错误的论据类型"使用泛型

时间:2016-05-18 18:32:06

标签: java generics recursion

我有一个递归方法,它被标记为"错误的参数类型"错误,我不明白为什么。首次进入方法时,参数为:

checkMapping(Map<String, Object> inObjectMap, 
             In object, 
             List<DataGetter<In, Out>> inObjectDataGetters)

如果需要递归,则递归为:

checkMapping(Map<String, Object> outObjectMap, 
             Out object, 
             List<DataGetter<Out, ?>> outObjectDataGetters)

但是在递归时我收到List<DataGetter<Out, ?>> objectDataGetters的错误:

&#34;错误的第三种参数类型:找到List<DataGetter<Out, ?>> objectDataGetters:必需List<DataGetter<Out, Out>> objectDataGetters&#34;

从我的代码中我无法看到我做错了什么以及为什么不接受通配符:

private <In, Out> void checkMapping(Map<String, Object> objectMap, 
                                    In object, 
                                    List<DataGetter<In, Out>> objectDataGetters) {
    for(DataGetter<In, Out> getter : objectDataGetters) {
        String key = getter.getDataName();
        Out value = getter.getData(object);

        List<DataGetter<Out, ?>> valueGetters = getter.getOutGetters();
        if(valueGetters.size() == 0) {
            //Check mapping is correct
            assertThat(objectMap.get(key), isValue(value));
        } else {
            //Recursion
            try {
                Map<String, Object> valueMap = (Map<String, Object>) objectMap.get(key);
                checkMapping(valueMap, value, valueGetters); //***Error is here***//
            } catch (ClassCastException e) {
                fail();
            }
        }
    }
}

我正在编写一个测试来测试对象中成员变量到Map<String, Object>的映射(以测试一些JSON序列化)。 String是变量名,Object是值,如果成员是对象,也可以是Map。我使用上面的递归方法来检查映射是否正确。 DataGetter<In, Out>是一种调用映射对象的getter方法来比较成员变量值与Map中存储的值的方法:

abstract class DataGetter<In, Out> {
    private String mDataName;
    private List<DataGetter<Out, ?>> mOutGetters;

    public abstract Out getData(In item);

    public DataGetter(String dataName) {
        mDataName = dataName;
        mOutGetters = new ArrayList<>();
    }

    public DataGetter(String dataName, List<DataGetter<Out, ?>> outGetters) {
        mDataName = dataName;
        mOutGetters = outGetters;
    }

    public String getDataName() {
        return mDataName;
    }

    public List<DataGetter<Out, ?>> getOutGetters() {
        return mOutGetters;
    }
}

OutGetters是getData(In item)返回的变量的getter,如果恰好是另一个对象。

我希望这是有道理的。我做错了什么?

谢谢, RIZ

修改:解决方案继续下面的ILya回答,我猜它是列表中的外卡。如果我更改签名以获取DataGetter(只是为了看看会发生什么),则没有错误并且ILya的解决方案有效。我猜通配符并不意味着所有元素都可以保证属于同一类型,这就是CheckMapping(。)不接受它的原因。使用Ilya的答案(我已经接受了)我通过将循环中的代码拆分为CheckMappingForGetter来解决这个问题,CheckMappingForGetter调用CheckMappingRecursive进行递归:

private <In> void checkMappingRecursive(Map<String, Object> objectMap,
                                        In object,
                                        List<DataGetter<In, ?>> objectDataGetters) {
    for(DataGetter<In, ?> getter : objectDataGetters) {
        checkMappingForGetter(objectMap, object, getter);
    }
}

private <In, Out> void checkMapping(Map<String, Object> objectMap,
                                    In object,
                                    List<DataGetter<In, Out>> objectDataGetters) {
    for(DataGetter<In, Out> getter : objectDataGetters) {
        checkMappingForGetter(objectMap, object, getter);
    }
}

1 个答案:

答案 0 :(得分:0)

您收到此错误是因为checkMapping方法通过了Type Erasure进程。实际上你的根问题是this。要修复它,您可以从

重命名递归方法
checkMapping(Map<String, Object> outObjectMap, 
             Out object, 
             List<DataGetter<Out, ?>> outObjectDataGetters)

checkMappingRecursive(Map<String, Object> outObjectMap, 
             Out object, 
             List<DataGetter<Out, ?>> outObjectDataGetters)

并使用它

private <In, Out> void checkMapping(Map<String, Object> objectMap, 
                                    In object, 
                                    List<DataGetter<In, Out>> objectDataGetters) {
    for(DataGetter<In, Out> getter : objectDataGetters) {
        String key = getter.getDataName();
        Out value = getter.getData(object);

        List<DataGetter<Out, ?>> valueGetters = getter.getOutGetters();
        if(valueGetters.size() == 0) {
            //Check mapping is correct
            assertThat(objectMap.get(key), isValue(value));
        } else {
            //Recursion
            try {
                Map<String, Object> valueMap = (Map<String, Object>) objectMap.get(key);
                checkMappingRecursive(valueMap, value, valueGetters); 
            } catch (ClassCastException e) {
                fail();
            }
        }
    }
}