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

这个问题上有一个关于泛型的很好的讨论,以及它们在幕后的真正作用,所以我们都知道Vector<int[]>是一个整数数组的向量,而HashTable<String, Person>是一个表,其键是字符串和值Persons。 然而,难倒我的是Class<>.

的用法

java类Class也应该有一个模板名(或者是eclipse中的黄色下划线告诉我的)。我不知道我应该在里面写什么。Class对象的全部意义是当你没有关于一个对象的全部信息时,用于反射等。为什么它让我指定Class对象将包含哪个类?我显然不知道,否则我不会使用Class对象,我会使用特定的对象。

690605 次浏览

摘自Java文档:

< p >[…] 更令人惊讶的是,class已经被泛化了。类字面量现在用作类型标记,提供运行时和编译时类型信息。这就启用了一种静态工厂样式,例如新的AnnotatedElement接口中的getnotation方法:

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

这是一个泛型方法。它从参数中推断出类型形参T的值,并返回一个适当的T实例,如下面的代码片段所示:

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

在使用泛型之前,您必须将结果强制转换为Author。此外,您也没有办法让编译器检查实际参数是否表示Annotation的子类。[…]

我从来没用过这种东西。有人知道吗?

使用类的泛化版本class允许您编写类似于

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

然后你可以确定你接收到的Class对象扩展了Collection,并且这个类的实例(至少)是一个Collection。

你经常想在Class中使用通配符。例如,Class<? extends JComponent>允许你指定这个类是JComponent的某个子类。如果你已经从Class.forName中检索了Class实例,那么你可以在尝试构造实例之前使用Class.asSubclass进行强制转换。

正如其他答案所指出的,有许多充分的理由使class成为通用的。然而,很多时候你没有办法知道要用Class<T>使用的泛型类型。在这些情况下,你可以简单地忽略黄色的日食警告,或者你可以使用Class<?>…我就是这么做的;)

我发现class<T>在创建服务注册表查找时很有用。如。

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

一开始会让人困惑。但它在以下情况下会有所帮助:

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.

在@ kiire Haglin的回答之后,可以在JAXB解组的文档中看到泛型方法的进一步示例:

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内容树类型的文档。

只要使用牛肉类:

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();
}

我们只知道"任何类的所有实例都共享该类类型的同一个java.lang.Class对象"

如)

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

那么a.getClass() == b.getClass()为真。

现在假设

Teacher t = new Teacher();

没有泛型是可能的。

Class studentClassRef = t.getClass();

但现在这是错误的…?

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

使用泛型可以避免这种情况。

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

现在T是什么??T为类型参数(也称为类型变量);用尖括号(<>)分隔,跟在类名后面。
T只是一个符号,就像写入类文件时声明的变量名(可以是任何名称)一样。稍后,T将在初始化时被
有效的类名所取代(HashMap<String> map = new HashMap<String>();)

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

所以Class<T>表示特定类类型'T'的类对象。

假设您的类方法必须使用如下所示的未知类型参数

/**
* 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可以用作String类型,如CarName

OR T可以用作Integer类型,如modelNumber

OR T可以用作Object类型,如有效的汽车实例

现在,上面是一个简单的POJO,可以在运行时使用不同的方式。 例如,List, Set, Hashmap是最好的例子,它们将根据T的声明与不同的对象一起工作,但一旦我们将T声明为字符串
例如:HashMap<String> map = new HashMap<String>();那么它将只接受String类实例对象。

泛型方法

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

泛型方法的语法包括一个类型参数,位于尖括号内,出现在方法的返回类型之前。对于泛型方法,类型参数段必须出现在方法的返回类型之前。

 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>是方法参数中使用的类型的声明,它应该在返回类型boolean之前。

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

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

但是下面是错误的,因为类级类型参数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;
}
}

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

也可以读泛型的限制

通配符和子类型

类型参数

再举一个例子,Class (Class<T>)的泛型版本允许编写如下所示的泛型函数。

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();
}
});
}

在java中<T>表示泛型类。泛型类是一个可以在任何类型的数据类型上工作的类,换句话说,我们可以说它是独立于数据类型的。

public class Shape<T> {
// T stands for "Type"
private T t;


public void set(T t) { this.t = t; }
public T get() { return t; }
}

其中T表示类型。现在,当你创建这个Shape类的实例时,你需要告诉编译器它将处理什么数据类型。

例子:

Shape<Integer> s1 = new Shape();
Shape<String> s2 = new Shape();

整数是一个类型,字符串也是一个类型。

<T>特别代表泛型类型。根据Java文档-泛型类型是在类型之上参数化的泛型类或接口。