11

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参数对泛型方法有用?

4

7 回答 7

11

这是公认的做法吗?

好吧,对我来说..不,不是真的。对我来说,当您可以简单地定义T. 例如:

private static <T extends House> void load(Collection<T> t)

这将保证对象是类型House或子类House,但是如果您只想要类型的实例House或其子类,它应该只是:

private static void load(Collection<House> houses)

泛型的想法是使方法或类更具延展性和可扩展性,因此在我看来,开始比较方法主体中的类类型似乎违反直觉,而泛型的概念正是从这些细节中抽象出来。

于 2013-08-22T12:54:41.820 回答
4

如果无法以其他方式派生泛型类型,我只会传递类对象。在您的情况下,编译器应该能够T从集合中推断。为了区别对待特定对象,我会使用多态性——例如House#something()and Other#something(),然后调用anyObject.something().

于 2013-08-22T12:53:05.503 回答
4

我认为这是可以接受的,但如果可以避免,那么你应该这样做。通常,如果您可以有不同的方法来接受不同的类型,那么就使用它来代替使用if子句根据参数类型执行不同操作的方法。您还可以将要针对给定类型进行的特定操作委托给类。

在您的情况下,您可以简单地使用 , 测试集合中每个元素的类型instanceof,以执行特定类型所需的操作。但如果列表为空,它将不起作用。

一个典型的用途是,如果您需要获取类型来创建它,并且您可以通过其他方式找到它。例如,Spring 使用它从 name 加载一个 bean

<T> T getBean(Class<T> requiredType)

在这种情况下,它是无法避免的(无需强制转换)。

于 2013-08-22T12:57:12.173 回答
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):

例如,原始类型的使用默认会生成一个警告,可以将警告视为错误甚至是致命错误:

在此处输入图像描述

于 2013-08-22T13:10:52.830 回答
3

Class<T>当且仅当您将在泛型之前传递一个参数时,您才会在Class泛型中传递一个参数。换句话说,只有当Class对象以某种方式使用时。泛型用作编译时类型检查工具。但是,您传递的参数应该由程序的运行时逻辑决定,并且应该与泛型无关。

于 2013-08-23T10:42:37.367 回答
2

我还没有看到传递Class对象以检查对象的运行时类型作为泛型的常见用例。如果你这样做,很有可能有更好的方法来设置你的类结构。

看到的是,如果您需要创建相关类的新实例,或者以其他方式使用反射。在这种情况下,您必须传递Class对象,因为 Java 无法在运行时派生它,这要归功于类型擦除。

于 2013-08-22T13:02:48.260 回答
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() 方法。

在每个泛型函数上传递一个类会导致你在大多数情况下传递一个不必要的参数,这被认为是不好的做法。

我之前回答过一个类似的讨论: 什么时候使用泛型方法,什么时候使用通配符?

于 2013-08-22T13:13:45.927 回答