方法参数的泛型类型

时间:2013-12-02 11:28:37

标签: java generics generic-list

以下是该方案:

public static <T> List<T> isTriggeredByBlackList(Map<String, T> params, Class<T> clz)   {
    System.out.println(clz.getName());

    return null;
}

我想要的是将StringList<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>类型的方法。

有人可以帮帮我吗?非常感谢!

2 个答案:

答案 0 :(得分:9)

更改方法的签名:

public static <T> List<T> isTriggeredByBlackList(Map<String, ? extends T> params, Class<T> clz)

为什么这样做?

表达式? extends T只表示接受T(当然还有T本身的子类型的任何类型。

What is a wildcard?

所以当方法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)的引用!

Why are raw types permitted?

为什么我们不能传递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)要求仅支持StringList<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一样。