正如标题所说。
假设我有一个方法可以将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
是的,问题解决了,但我还是很困惑。这两个方法的返回值声明是一样的。为什么会造成不同的结果呢?
你最好给该方法传递一个集合工厂。
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>
.