Java 泛型问题 - Class<T> 和 T 有什么区别?

9

我正在使用Hibernate验证器,并尝试创建一个小的工具类:

public class DataRecordValidator<T> {
    public void validate(Class<T> clazz, T validateMe) {
        ClassValidator<T> validator = new ClassValidator<T>(clazz);
        InvalidValue[] errors = validator.getInvalidValues(validateMe);
        [...]
    }
}

问题是,在执行new ClassValidator<T>(clazz)时,为什么需要提供Class<T> clazz参数?为什么不能指定以下内容:
  1. T,如ClassValidator<T>(T)
  2. validateMe.getClass(),如ClassValidator<T>(validateMe.getClass())
当我尝试这两个选项时,会出现错误。
编辑:我明白为什么#1不起作用。但我不明白为什么#2不起作用。我目前在#2中获得以下错误:
cannot find symbol
symbol  : constructor ClassValidator(java.lang.Class<capture#279 of ? extends java.lang.Object>)
location: class org.hibernate.validator.ClassValidator<T>

注意:Hibernate API方法在此处(点击这里)。
3个回答

8

因为T不是一个值 - 它只是编译器的提示。JVM不知道T。你只能将泛型用作在编译时进行类型检查的类型。


谢谢。那么为什么您不能使用validateMe.getClass()呢? - Marcus Leon
1
你可以在任何对象引用上使用 getClass()... 我刚刚检查了,编译器可以接受这个。 - Ondra Žižka
2
您可以使用validateMe.getClass(),但有一些注意事项:如果validateMenull,则会引发NullPointerException,这可能是您想要的,也可能不是。并且使用当前代码,您可以传递一个基本类(例如,使用其基类Person的规则验证此Employee实例)。如果省略Class参数,则不再可能。 - Joachim Sauer

1
如果您自己编写了validate方法,那么您可以安全地跳过Class属性。
public void validate(T validateMe) {
    ClassValidator<T> validator = 
           new ClassValidator<T>((Class<T>) validateMe.getClass());
    ...
}

但是ClassValidator构造函数需要一个Class参数。

使用不安全的强制转换并不是首选,但在这种情况下,如果您没有像这样的东西,它实际上是安全的:

class A {..}
class B extends A {..}

new DataRecordValidator<A>.validate(new B());

如果您认为需要执行类似的操作,请在方法中包含“Class”参数。否则,您可能会在运行时遇到“ClassCastException”,但这很容易调试,尽管这并不完全符合泛型的思想。

谢谢,(Class<T>) 是关键! - Marcus Leon

0

因为ClassValidator需要一个类对象作为其参数,而不是所讨论的类的实例。请记住,您可能可以使用以下代码来完成您想要做的事情:

ClassValidator<? extends T> validator = new ClassValidator<? extends T>(validateMe.getClass());

谢谢。为什么不能使用 validateMe.getClass()T.class - Marcus Leon
我也曾这样想过...但是我收到了这个错误:无法找到符号 / 符号: 构造函数 ClassValidator(java.lang.Class<capture#454 of ? extends java.lang.Object>) / 位置: 类 org.hibernate.validator.ClassValidator<T> - Marcus Leon
不行:found : ? extends T / required: class or interface without boundssymbol : method getInvalidValues(T) location: class org.hibernate.validator.ClassValidator<capture#536 of ? extends T> - Marcus Leon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接