我正在使用类似的方法将非通用Collection安全地转换为同类通用Collection,即立即抛出ClassCastException:
public static <T> Collection<T> safeCastCollection(final Collection collection, final Class<T> targetClass) {
if (collection == null) {
return null;
}
collection.forEach(targetClass::cast);
return (Collection<T>) collection;
}
现在,让该方法不返回Collection,而是与输入参数具有相同基本类型(Set,List等)的collection会很好。我能做的最好的是:
public static <T, C extends Collection<T>, I extends C> C safeCastCollection2(final I collection, final Class<T> targetClass) {
if (collection == null) {
return null;
}
collection.forEach(targetClass::cast);
return (C) collection;
}
这在大多数情况下都适用,除了最后一种:
List listOfStrings = Arrays.asList(new String[]{"a", "b", "c"});
Set setOfNumbers = new HashSet(Arrays.asList(new Integer[]{1, 2, 3}));
Collection<String> l0 = safeCastCollection(listOfStrings, String.class);
// Collection<Integer> l1 = safeCastCollection(listOfStrings, String.class); // compiler error :-)
// List<String> l2 = safeCastCollection(listOfStrings, String.class); // compiler error :-(
Collection<String> l3 = safeCastCollection2(listOfStrings, String.class);
// Collection<Integer> l4 = safeCastCollection(listOfStrings, String.class); // compiler error :-)
List<String> l5 = safeCastCollection2(listOfStrings, String.class); // no compiler error :-)
Set<Number> l6 = safeCastCollection2(setOfNumbers, Integer.class);
Collection<Number> l7 = safeCastCollection2(setOfNumbers, Integer.class);
// List<Number> l8 = safeCastCollection2(setOfNumbers, Integer.class); // compiler error :-)
Collection<String> l9 = safeCastCollection2(setOfNumbers, Integer.class); // no compiler error :-(
final String next = l9.iterator().next(); // runtime exception
有什么想法可以改善对输入参数的约束吗?
答案 0 :(得分:0)
这样对您来说太冗长吗?
@SuppressWarnings("unchecked")
public static <T> Collection<T> safeCastCollection(final Collection collection, final Class<T> targetClass) {
return (Collection<T>) typeCheckedCollection(collection, targetClass);
}
@SuppressWarnings("unchecked")
public static <T> List<T> safeCastCollection(final List list, final Class<T> targetClass) {
return (List<T>) typeCheckedCollection(list, targetClass);
}
@SuppressWarnings("unchecked")
public static <T> Set<T> safeCastCollection(final Set set, final Class<T> targetClass) {
return (Set<T>) typeCheckedCollection(set, targetClass);
}
// etc. for other Collection subinterfaces
@SuppressWarnings("rawtypes,unchecked")
private static Collection typeCheckedCollection(final Collection collection, final Class<?> targetClass) {
if (collection != null) {
collection.forEach(targetClass::cast);
}
return collection;
}
这将满足您的要求(请注意,我将<Number>
替换为<? extends Number>
,因为无法将Set<Integer>
分配给Set<Number>
):
List listOfStrings = Arrays.asList(new String[]{"a", "b", "c"});
Set setOfNumbers = new HashSet(Arrays.asList(new Integer[]{1, 2, 3}));
Collection<String> l0 = safeCastCollection(listOfStrings, String.class);
// Collection<Integer> l1 = safeCastCollection(listOfStrings, String.class); // compiler error :-)
// List<String> l2 = safeCastCollection(listOfStrings, String.class); // compiler error :-(
Collection<String> l3 = safeCastCollection(listOfStrings, String.class);
// Collection<Integer> l4 = safeCastCollection(listOfStrings, String.class); // compiler error :-)
List<String> l5 = safeCastCollection(listOfStrings, String.class); // no compiler error :-)
Set<? extends Number> l6 = safeCastCollection(setOfNumbers, Integer.class);
Collection<? extends Number> l7 = safeCastCollection(setOfNumbers, Integer.class);
// List<Number> l8 = safeCastCollection(setOfNumbers, Integer.class); // compiler error :-)
// Collection<String> l9 = safeCastCollection(setOfNumbers, Integer.class); // compiler error :-)