以下是该方案:
public static <T> List<T> isTriggeredByBlackList(Map<String, T> params, Class<T> clz) {
System.out.println(clz.getName());
return null;
}
我想要的是将String
或List<String>
传递给此方法。
说到String
,它的效果很好:
Map<String, String> map1 = new HashMap<String, String>();
map1.put("11", "22");
isTriggeredByBlackList(map1, String.class);
但是当我试图传递List<String>
时,它就出错了:
Map<String, List<String>> map = new HashMap<String, List<String>>();
List<String> l = new ArrayList<String>();
l.add("11");
l.add("22");
map.put("1", l);
isTriggeredByBlackList(map, List.class); //compile error!
编译错误如下:
The method isTriggeredByBlackList(Map<String,T>, Class<T>) in the type CommonTest is not applicable for the arguments (Map<String,List<String>>, Class<List>)
我需要的是只编写一种适合String
类型和List<String>
类型的方法。
有人可以帮帮我吗?非常感谢!
答案 0 :(得分:9)
更改方法的签名:
public static <T> List<T> isTriggeredByBlackList(Map<String, ? extends T> params, Class<T> clz)
为什么这样做?
表达式? extends T
只表示接受T
(当然还有T
本身的子类型的任何类型。
所以当方法isTriggeredByBlackList
被调用时:
isTriggeredByBlackList(map, List.class);
... T
被指定为(原始)List
类型,因此第一个参数必须为Map<String, any-type-that-extends-raw-List>
,Map<String, List<String>>
为真(因为List<String>
是(原始)List
)的子类型。
但为什么List是(原始)List的子类型?
泛型是棘手的,因为多态性不能按预期工作(第一眼看上去)。 List<String>
是-NOT-a List<Object>
,但String
延伸Object
!所以这不起作用:
List<Object> objList = new ArrayList<String>(); // compile error
(注意:这是不可能的,但这是另一个故事)
但是List<String>
IS-a (原始)List
(而是-a List<?>
)。所以这有效:
List rawList = new ArrayList<String>(); // just compiler warning
List<?> unknownList = new ArrayList<String>();
原因是:仍然支持原始类型向后兼容!否则,现在无法使用不支持泛型的旧代码。因此,具体参数化类型的任何实例(例如ArrayList<String>
)都可以分配给其原始类型(例如ArrayList
)或超类型(例如List
)的引用!
为什么我们不能传递List<String>.class
因为参数化类型没有确切的运行时类型表示!
Why is there no class literal for concrete parameterized types?
但我希望获得List<List<String>>
作为返回值!
这没问题!只需将作业的左侧定义为List<List<String>>
,然后java执行其余操作:
List<List<String>> l = isTriggeredByBlackList(map, List.class);
BUT!这只适用于您稍微修改方法声明:
public static <T> List<T> isTriggeredByBlackList(
Map<String, ? extends T> params, Class<? super T> clz)
(否则你不能将原始List.class
作为第二个参数传递。)
如果所有这些修改和调整都有意义,取决于您的方法应该完成的任务!它只是从params
读取吗?它如何使用泛型类型参数?在这里使用泛型有什么好处?等
顺便说一句:以is...
开头的方法应返回boolean
值。考虑重命名您的方法!
顺便说一句2:您的方法的返回类型为List<T>
,因此如果您将T
指定为List
,您将获得List<List>
。这是为了吗?
答案 1 :(得分:2)
此处有3个相关点,使用此代码。
public static <T> List<T> isTriggeredByBlackList(Map<String, T> params, Class<T> clz) {
System.out.println(clz.getName());
return null;
}
1)要求仅支持String
或List<String>
作为地图值中的参数。
这在单一(通用)方法中是不可能的。
它将需要重载方法(如Steve P.所提到的)而不是Generic。
2)如果我们放松并使用通用方法。如果我们更改地图的类型,则可以按原样使用上面的定义。
Map<String, List> m = new HashMap<String, List>(); // The Raw List.
isTriggeredByBlackList(m, List.class);
3)如果方法签名更改为:
static <T> List<T> isTriggeredByBlackList(Map<String, ? extends T> params, Class<T> clz)
正如@ isnot2bad已经解释得很好,它接受所有列表,就像#2一样。