使用Java泛型来明确指定返回的集合类型和集合元素的类型。

问题描述 投票:2回答:1

正如标题所说。

假设我有一个方法可以将JSON数组字符串转换为Java集合,并且它可以指定集合中元素的类型.例如。

// variable 'json' is a String, like "[{...}, {...}, ...]"
List<Person> persons = MyUtil.convert(json, List.class, Person.class);
Set<Address> set = MyUtil.convert(json, Set.class, Address.class);

目前,我定义的方法签名是这样的。

public static <C extends Collection<E>, E> C convert(String content, Class<C> collectionClass, Class<E> elementClass) {
    ....
}

当我使用这个方法时,有一个警告:

Unchecked assignment: 'java.util.List' to 'java.util.List<my.package.Person> '。

我可以理解为什么会出现这个警告,但我不知道如何优化我的方法签名。(除了使用@SuppressWarnings)

我可以明确声明返回的集合和它的元素类型吗?也许它看起来像这样。

public static C<E> convert(String content, Class<C> collectionClass, Class<E> elementClass) {
    ...
}

(当然,我知道这完全不可能编译,我只是想举个例子)


非常感谢 多纳特的回答.我试了两种方法。

private static <C extends Collection<E>, E> C convert(String content, Supplier<C> supplier, Class<E> element) {
    ...
}

private static <C extends Collection<E>, E> C convert(String content, Class<C> collection, Class<E> element) {
    ...
}

打电话给他们

List<Person> l0 = convert("...", ArrayList::new, Person.class);  // No warning
List<Person> l1 = convert("...", ArrayList.class, Person.class); // Unchecked warning

是的,问题解决了,但我还是很困惑。这两个方法的返回值声明是一样的。为什么会造成不同的结果呢?

java generics
1个回答
2
投票

你最好给该方法传递一个集合工厂。

public static <C extends Collection<E>, E> C convert(String content, Supplier<C> collectionFactory, Class<E> elementClass) {
  C collection = collectionFactory.get();
  ...
  return collection;
}

例如你可以这样调用它。

List<Integer> list = convert("", ArrayList::new, Integer.class);

使用供应商的主要原因是: 对于一个类来说,在方法的主体中建立一个新的实例是很困难的。你不能依赖无参数构造函数的存在。你会得到未选中的警告,或者必须在签名中扩展一个Exception来抛出。

为什么在调用你的方法时出现未选中的警告?这是因为你必须传递一个类型为 Class<ArrayList<Integer>> 在我的例子中。但这是没有意义的。我认为类型变量为 Class 必须是一个真正的类(reifiable),如 ArrayList. 没有比这更高级的了 ArrayList<Integer> 因为类属会被编译器删除。所以这个类值无法与例如. ArrayList<String>.

© www.soinside.com 2019 - 2024. All rights reserved.