注意:是的,我知道我可以使调用方法使用Collection而不是子类或强制转换Collection或其他一些东西。并且可能会在等待答案的同时这样做。但是我很好奇这是否可行,而我的Google-fu却无济于事。 :-)
所以我有一个方法,该方法以Set或List作为参数,并返回相同的新方法(是的,还有Collection的其他子类,但是我将看到这两个)。所以我尝试使用泛型:
private <T extends Collection<String>> T doStuff(T input) {
T output = (input instanceof List)
? new ArrayList<String>()
: new HashSet<String>();
// do stuff to fill output from input
return output;
}
此版本带有红色墨水,表示我无法将ArrayList转换为T。我对此进行了尝试,没有运气。有什么想法吗?
编辑:感谢您的好奇心。我当然会使用更简单的方法,例如只返回一个Collection,但是很高兴知道问题出在哪里,以备将来参考。
答案 0 :(得分:2)
为避免编译错误,必须实例化类型T的对象,由于类型擦除,在Java中是不可能的。我建议使用两种重载方法,而不是通用方法。
答案 1 :(得分:0)
让S extends Collection<String>
是您要从方法中返回的集合的抽象类型,即List
或Set
。
让C extends S
为返回结果的运行时类型,即ArrayList
或HashSet
。
为了在编译时获得C
的实例,您将必须显式提供一个Class<C>
实例作为参数。
因此,方法变为:
public <S extends Collection<String>, C extends S> S doStuff(S input, Class<C> clazz) throws Exception {
C output = clazz.newInstance();
// do stuff to fill output from input
return output;
}
您可以使用以下方法调用此方法:
List<String> list = new ArrayList<String>() {{ add("Hello"); }};
doStuff(list, ArrayList.class);
Set<String> set = new HashSet<String>() {{ add("World"); }};
doStuff(set, HashSet.class);
当然,您应该注意可能会从clazz.newInstance()
回调引发的检查异常。
答案 2 :(得分:-2)
如果您确实能够返回Collection,则意味着您只需要Collection接口,并且不必担心各种Collection子类的速度/大小之间的取舍。
如果确实是这样,那么无论调用哪个列表,都无论返回列表还是集合都没关系。所以只要这样做:
private Collection doStuff(Collection input) {
// do stuff to fill output from input
return new ArrayList(input);
// or, return new HashSet(input);
}
如果您或您的调用者实际上确实在乎特定Collection子类的方法(或速度/大小保证),那么您将需要重载感兴趣的实际子类。
当然请注意,重载分辨率是在编译时使用静态(引用)类型确定的,而不是在运行时实际指向的动态类型。