如何在Java中使用Class <T>?

在这个问题上 ,有很多关于generics的内容以及他们在幕后做了些什么,所以我们都知道Vector<int[]>是整数数组的向量,而HashTable<String, Person>是一个表的键是string和值Person 。 但是,什么让我难过的是Class<>的用法。

java class Class应该也是一个模板名,(或者我被eclipse中的黄色下划线所告知)。 我不明白我应该放在那里。 Class对象的全部重点是当你没有完全掌握一个对象的信息,reflection等等。 为什么它会让我指定Class对象将保持哪个类? 我显然不知道,或者我不会使用Class对象,我会使用具体的一个。

使用类的基因纯化版本,可以让你等等写东西

 Class<? extends Collection> someCollectionClass = someMethod(); 

然后你可以确定你接收到的Class对象inheritance了Collection ,而这个类的一个实例将是(至less)一个Collection。

我们所知道的是“ 任何类的所有实例共享该types类的相同java.lang.Class对象

例如)

 Student a = new Student(); Student b = new Student(); 

那么a.getClass() == b.getClass()是真的。

现在假设

 Teacher t = new Teacher(); 

没有generics下面是可能的。

 Class studentClassRef = t.getClass(); 

但现在这是错误的..?

例如) public void printStudentClassInfo(Class studentClassRef) {}可以用Teacher.class

这可以避免使用generics。

 Class<Student> studentClassRef = t.getClass(); //Compilation error. 

现在什么是T? T是types参数(也称为typesvariables); 用尖括号(<>)分隔,跟在类名之后。
T只是一个符号,就像在类文件写入时声明的variables名(可以是任何名字)。 之后T将被replace
初始化期间有效的类名( HashMap<String> map = new HashMap<String>();

例如) class name<T1, T2, ..., Tn>

所以Class<T>表示特定类types“ T ”的类对象。

假设你的类方法必须使用如下的未知types参数

 /** * Generic version of the Car class. * @param <T> the type of the value */ public class Car<T> { // T stands for "Type" private T t; public void set(T t) { this.t = t; } public T get() { return t; } } 

这里T可以用作Stringtypes作为CarName

OR T可以作为Integertypes作为modelNumber

OR T可以用作Objecttypes作为有效的汽车实例

现在在这里上面是简单的POJO,可以在运行时使用不同的POJO。
集合例如)List,Set,Hashmap是最好的例子,它们可以根据T的声明使用不同的对象,但是一旦我们声明T为String
例如) HashMap<String> map = new HashMap<String>(); 那么它只会接受String类的实例对象。

通用方法

generics方法是引入自己的types参数的方法。 这与声明genericstypes相似,但是types参数的作用域仅限于声明它的方法。 允许使用静态和非静态generics方法,以及generics类构造函数。

generics方法的语法包括一个types参数,尖括号内,并出现在方法的返回types之前。 对于generics方法,types参数部分必须出现在方法的返回types之前。

  class Util { // Generic static method public static <K, V, Z, Y> boolean compare(Pair<K, V> p1, Pair<Z, Y> p2) { return p1.getKey().equals(p2.getKey()) && p1.getValue().equals(p2.getValue()); } } class Pair<K, V> { private K key; private V value; } 

这里<K, V, Z, Y>是在方法参数中使用的types的声明,它应该在返回types之前是boolean

在下面; types声明<T>在方法级别是不需要的,因为它已经在类级别声明了。

 class MyClass<T> { private T myMethod(T a){ return a; } } 

但是下面是错误的,因为类级别types参数K,V,Z和Y不能在静态上下文中使用(这里是静态方法)。

 class Util <K, V, Z, Y>{ // Generic static method public static boolean compare(Pair<K, V> p1, Pair<Z, Y> p2) { return p1.getKey().equals(p2.getKey()) && p1.getValue().equals(p2.getValue()); } } 

其他有效的情景是

 class MyClass<T> { //Type declaration <T> already done at class level private T myMethod(T a){ return a; } //<T> is overriding the T declared at Class level; //So There is no ClassCastException though a is not the type of T declared at MyClass<T>. private <T> T myMethod1(Object a){ return (T) a; } //Runtime ClassCastException will be thrown if a is not the type T (MyClass<T>). private T myMethod1(Object a){ return (T) a; } // No ClassCastException // MyClass<String> obj= new MyClass<String>(); // obj.myMethod2(Integer.valueOf("1")); // Since type T is redefined at this method level. private <T> T myMethod2(T a){ return a; } // No ClassCastException for the below // MyClass<String> o= new MyClass<String>(); // o.myMethod3(Integer.valueOf("1").getClass()) // Since <T> is undefined within this method; // And MyClass<T> don't have impact here private <T> T myMethod3(Class a){ return (T) a; } // ClassCastException for o.myMethod3(Integer.valueOf("1").getClass()) // Should be o.myMethod3(String.valueOf("1").getClass()) private T myMethod3(Class a){ return (T) a; } // Class<T> a :: a is Class object of type T //<T> is overriding of class level type declaration; private <T> Class<T> myMethod4(Class<T> a){ return a; } } 

最后,静态方法总是需要显式的<T>声明; 它不会从类级别的Class<T>派生。 这是因为级别T与实例绑定在一起。

另请阅读generics的限制

从Java文档:

更令人惊讶的是,class级已经被基因化。 类文字现在用作types标记,提供运行时和编译时types信息。 这样可以在新的AnnotatedElement接口中启用由getAnnotation方法示例的静态工厂样式:

 <T extends Annotation> T getAnnotation(Class<T> annotationType); 

这是一个通用的方法。 它从它的参数中推断出它的types参数T的值,并返回一个适当的T实例,如下面的片段所示:

 Author a = Othello.class.getAnnotation(Author.class); 

仿制药之前,你必须把结果投给作者。 你也没有办法让编译器检查实际参数是否表示Annotation的子类。 […]

那么,我从来没有使用这种东西。 任何人?

当我创build服务registry查找时,发现class<T>很有用。 例如

 <T> T getService(Class<T> serviceClass) { ... } 

正如其他答案所指出的那样,为什么这个class是通用的,有很多很好的理由。 然而,有很多次你没有办法知道用Class<T>使用的genericstypes。 在这些情况下,你可以简单地忽略黄色的日食警告,或者你可以使用Class<?> …这就是我的做法;)

在@Kire Haglin的回答之后,在JAXB解组的文档中可以看到generics方法的另一个例子:

 public <T> T unmarshal( Class<T> docClass, InputStream inputStream ) throws JAXBException { String packageName = docClass.getPackage().getName(); JAXBContext jc = JAXBContext.newInstance( packageName ); Unmarshaller u = jc.createUnmarshaller(); JAXBElement<T> doc = (JAXBElement<T>)u.unmarshal( inputStream ); return doc.getValue(); } 

这允许unmarshal返回任意JAXB内容树types的文档。

你经常想用Class来使用通配符。 例如, Class<? extends JComponent> Class<? extends JComponent> ,将允许您指定该类是JComponent某个子类。 如果您从Class.forName检索到Class实例,则可以在尝试构build实例之前使用Class.asSubclass进行Class.asSubclass转换。

只是抛出另一个例子,Class( Class<T> )的通用版本允许编写如下所示的generics函数。

 public static <T extends Enum<T>>Optional<T> optionalFromString( @NotNull Class<T> clazz, String name ) { return Optional<T> opt = Optional.ofNullable(name) .map(String::trim) .filter(StringUtils::isNotBlank) .map(String::toUpperCase) .flatMap(n -> { try { return Optional.of(Enum.valueOf(clazz, n)); } catch (Exception e) { return Optional.empty(); } }); } 

这一开始是令人困惑的。 但是在下面的情况下它有帮助:

 class SomeAction implements Action { } // Later in the code. Class<Action> actionClass = Class.forName("SomeAction"); Action action = actionClass.newInstance(); // Notice you get an Action instance, there was no need to cast. 

只要使用牛肉类:

 public <T> T beefmarshal( Class<beef> beefClass, InputBeef inputBeef ) throws JAXBException { String packageName = docClass.getPackage().getBeef(); JAXBContext beef = JAXBContext.newInstance( packageName ); Unmarshaller u = beef.createBeef(); JAXBElement<T> doc = (JAXBElement<T>)u.beefmarshal( inputBeef ); return doc.getBeef(); }