使用T
参数通用的方法肯定很方便。但是,我很好奇如果将Class<T> clazz
之类的参数传递给方法,泛型方法的用途是什么。我想出了一个可能有用的案例。也许您只想根据类的类型运行方法的一部分。例如:
/** load(File, Collection<T>, Class<T>)
* Creates an object T from an xml. It also prints the contents of the collection if T is a House object.
* @return T
* Throws Exception
*/
private static <T> T void load(File xml, Collection<T> t, Class<T> clazz) throws Exception{
T type = (T) Jaxb.unmarshalFile(xml.getAbsolutePath(), clazz); // This method accepts a class argument. Is there an alternative to passing the class here without "clazz"? How can I put "T" in replace of "clazz" here?
if (clazz == House.class) {
System.out.println(t.toString());
} else {
t.clear();
}
return T;
}
这是一种公认的做法吗? Class<T> clazz
参数何时对泛型方法有用?
答案 0 :(得分:11)
这是一种公认的做法吗?
好吧,对我来说......不是没有。对我来说,当你可以简单地在T
的类型上定义一些边界时,似乎毫无意义。例如:
private static <T extends House> void load(Collection<T> t)
这将保证对象属于House
类型或House
的子类,但如果您只想要类型{{1或者它的子类,它应该只是:
House
泛型的想法是使方法或类更具有可塑性和可扩展性,因此对于我来说,开始比较方法体中的类类型似乎是违反直觉的,当泛型的概念是从这样的抽象中抽象出来时的信息。
答案 1 :(得分:4)
如果无法导出泛型类型,我只会传递类对象。在您的情况下,编译器应该能够从集合中推断出T
。为了区别对待特定对象,我使用多态 - 例如House#something()
和Other#something()
,只需致电anyObject.something()
。
答案 2 :(得分:4)
我认为可以接受但如果可以避免那么你应该这样做。通常情况下,如果您可以使用接受不同类型的不同方法,那么请执行此操作,而不是使用if
子句根据参数类型执行不同操作的方法。您还可以将特定于给定类型的操作委托给类。
在您的情况下,您可以使用instanceof
简单地测试集合中每个元素的类型,以执行特定类型所需的操作。但如果列表为空,它将无效。
一个典型的用法是你需要获得创建它的类型,你可以从另一种方式找到它。例如,Spring将其用于load a bean from its name:
<T> T getBean(Class<T> requiredType)
在这种情况下,无法避免(无需投射)。
答案 3 :(得分:3)
如果返回的值或其他参数类型依赖或需要相等,则泛型将添加编译时检查,因此无需强制转换为T
。
<T> T createNewInstanceOfType(Class<T> type);
<T> void addValueToCollection(Collection<T> collection,T value);
<T> List<Class<? extends T>> findSubClassesInClasspath(Class<T> superType);
仍然可以将一个转换错误推迟到运行时(ClassCastException
)与某些强制转换,例如:使用从非通用(原始)类型到通用类型的隐式转换:
List nonGenericList = new ArrayList();
nonGenericList.add(new Integer(42));
List<String> wreckedList = nonGenericList;
编译器将生成一堆警告,除非您使用注释或编译器设置来抑制它们。
编译器设置(Eclipse):
例如,原始类型的使用会在默认情况下生成警告,可以将警告视为错误甚至是致命错误:
答案 4 :(得分:3)
如果且仅当您在泛型之前传递Class<T>
参数时,您将在泛型中传递Class
参数。换句话说,仅当以某种方式使用Class
对象时。泛型用作编译时类型检查工具。但是,你传递的参数应该由程序的运行时逻辑决定,并且应该与泛型无关。
答案 5 :(得分:2)
我没有看到传递Class
对象以检查对象的运行时类型作为泛型的常见用例。如果你这样做,很有可能有更好的方法来设置你的班级结构。
我看到的是否需要创建相关类的新实例,或者使用反射。在这种情况下,您必须传递Class
对象,因为由于类型擦除,Java无法在运行时派生它。
答案 6 :(得分:1)
在您的情况下,实际上并不严格需要Generic参数。 由于您描述的函数的输出不依赖于输入的类型,您也可以使用通配符。
private static void stuff(Collection<?> t){
Object next = t.iterator().next(); //this is ugly and inefficient though
if(next instanceof House){
System.out.print(next.toString());
}else{
t.clear();
}
}
您应该使用泛型参数的唯一时间是函数结果的类型将取决于参数的类型。
当您的代码需要时,您需要传递与该类型相对应的类;大多数情况下,这种情况发生在: - 您需要将检查对象转换/输入到T - 涉及序列化/反序列化。 - 您无法在函数中访问任何T实例,并且在需要时无法调用getClass()方法。
在每个泛型函数上传递一个类会导致你在大多数时间传递一个不必要的参数,这被认为是不好的做法。
我过去回答了类似的讨论: When to use generic methods and when to use wild-card?