类Class 的通用性质是什么意思?什么是T?

时间:2021-01-13 16:06:09

I understand generics when it comes to collections. But what does it mean in the case of the Class<T> class? When you instantiate a Class object, there's only one object. So why the T parameter? What is it specifying? And why is it necessary (if it is)?

在集合方面,我理解泛型。但是在Class 类的情况下它意味着什么?实例化Class对象时,只有一个对象。那么为什么T参数呢?这是什么规定的?为什么有必要(如果是)?

4 个解决方案

#1


46  

Type parameter <T> has been added to java.lang.Class to enable one specific idiom1 - use of Class objects as type-safe object factories. Essentially, the addition of <T> lets you instantiate classes in a type-safe manner, like this:

类型参数 已添加到java.lang.Class以启用一个特定的idiom1 - 使用Class对象作为类型安全的对象工厂。本质上,添加 允许您以类型安全的方式实例化类,如下所示:

T instance = myClass.newInstance();

Type parameter <T> represents the class itself, enabling you to avoid unpleasant effects of type erasure by storing Class<T> in a generic class or passing it in as a parameter to a generic method. Note that T by itself would not be sufficient to complete this task2: the type of T is erased, so it becomes java.lang.Object under the hood.

类型参数 表示类本身,通过将Class 存储在泛型类中或将其作为参数传递给泛型方法,可以避免类型擦除的令人不快的影响。请注意,T本身不足以完成此任务2:T的类型被删除,因此它成为引擎盖下的java.lang.Object。

Here is a classic example where <T> parameter of the class becomes important. In the example below, Java compiler is able to ensure type safety, letting you produce a typed collection from a SQL string and an instance of Class<T>. Note that the class is used as a factory, and that its type safety can be verified at compile time:

这是一个典型的例子,其中类的 参数变得重要。在下面的示例中,Java编译器能够确保类型安全,允许您从SQL字符串和Class 的实例生成类型集合。请注意,该类用作工厂,并且可以在编译时验证其类型安全性:

public static <T> Collection<T> select(Class<T> c, String sqlStatement) {
    Collection<T> result = new ArrayList<T>();
    /* run sql query using jdbc */
    for ( /* iterate over jdbc results */ ) {
        T item = c.newInstance();
        /* use reflection and set all of item’s fields from sql results */
        result.add(item);
    }
    return result;
}

Since Java erases the type parameter, making it a java.lang.Object or a class specified as the generic's upper bound, it is important to have access to the Class<T> object inside the select method. Since newInstance returns an object of type <T>, the compiler can perform type checking, eliminating a cast.

由于Java会删除type参数,使其成为java.lang.Object或指定为泛型上限的类,因此访问select方法中的Class 对象非常重要。由于newInstance返回类型为 的对象,因此编译器可以执行类型检查,从而消除了强制转换。


1 SUN Oracle has published a good article explaining all this.
2 This is different from implementations of generics without type erasure, such as one in .NET.
3Java Generics tutorial by Oracle.

#2


7  

The answer by dasblinkenlight already demonstrated one of the main uses of this parameter. There is one more aspect I consider relevant: using that parameter, you can restrict the kind of class you want to pass at a given location. So e.g.

dasblinkenlight的答案已经证明了这个参数的主要用途之一。还有一个我认为相关的方面:使用该参数,您可以限制要在给定位置传递的类的类型。所以例如

Class<? extends Number> cls

means that cls may be any class implementing the Number interface. This can help catching certain errors at compile time, and makes class argument requirements more explicit.

表示cls可以是实现Number接口的任何类。这有助于在编译时捕获某些错误,并使类参数要求更加明确。

Perhaps a comparison to the case without generics is in order

也许与没有泛型的情况进行比较是有道理的

// Java ≥5 with generics    // Java <5 style without generics
Class<? extends Foo> c;     Class c;
Foo t1 = c.newInstance();   Foo t1 = (Foo)c.newInstance();
Object obj;                 Object obj;
Foo t2 = c.cast(obj);       Foo t2 = (Foo)c.cast(obj);

As you can see, not having T as an argument would require a number of explicit casts, as the corresponding methods would have to return Object instead of T. If Foo itself is a generic type argument, then all those casts would be unchecked, resulting in a sequence of compiler warnings. You can suppress them, but the core issue remains: the compiler cannot check the validity of these casts unless you properly use the type argument.

正如您所看到的,没有T作为参数将需要许多显式强制转换,因为相应的方法必须返回Object而不是T.如果Foo本身是泛型类型参数,那么所有这些强制转换将被取消选中,结果在一系列编译器警告中。您可以抑制它们,但核心问题仍然存在:除非您正确使用type参数,否则编译器无法检查这些强制转换的有效性。

#3


1  

In Java there's a single metaclass: Class. Its instances (only one per type exists) are used to represent classes and interfaces, therefore the T in Class<T> refers to the type of the class or interface that the current instance of Class represents.

在Java中,有一个元类:Class。它的实例(每种类型只存在一个)用于表示类和接口,因此Class 中的T指的是当前Class实例所代表的类或接口的类型。

#4


0  

The use of generics in the Class type is top define the type of class. If I have ' Class obj' my object obj can holds only children of Charsequence. This is an optional argument. I'm often put an '?' to avoid warnings from the Eclipse IDE if I don't need an specific type of class.

在类类型中使用泛型是*定义类的类型。如果我有'Class obj',我的对象obj只能拥有Charsequence的子级。这是一个可选参数。我经常把'?'如果我不需要特定类型的类,请避免来自Eclipse IDE的警告。

#1


46  

Type parameter <T> has been added to java.lang.Class to enable one specific idiom1 - use of Class objects as type-safe object factories. Essentially, the addition of <T> lets you instantiate classes in a type-safe manner, like this:

类型参数 已添加到java.lang.Class以启用一个特定的idiom1 - 使用Class对象作为类型安全的对象工厂。本质上,添加 允许您以类型安全的方式实例化类,如下所示:

T instance = myClass.newInstance();

Type parameter <T> represents the class itself, enabling you to avoid unpleasant effects of type erasure by storing Class<T> in a generic class or passing it in as a parameter to a generic method. Note that T by itself would not be sufficient to complete this task2: the type of T is erased, so it becomes java.lang.Object under the hood.

类型参数 表示类本身,通过将Class 存储在泛型类中或将其作为参数传递给泛型方法,可以避免类型擦除的令人不快的影响。请注意,T本身不足以完成此任务2:T的类型被删除,因此它成为引擎盖下的java.lang.Object。

Here is a classic example where <T> parameter of the class becomes important. In the example below, Java compiler is able to ensure type safety, letting you produce a typed collection from a SQL string and an instance of Class<T>. Note that the class is used as a factory, and that its type safety can be verified at compile time:

这是一个典型的例子,其中类的 参数变得重要。在下面的示例中,Java编译器能够确保类型安全,允许您从SQL字符串和Class 的实例生成类型集合。请注意,该类用作工厂,并且可以在编译时验证其类型安全性:

public static <T> Collection<T> select(Class<T> c, String sqlStatement) {
    Collection<T> result = new ArrayList<T>();
    /* run sql query using jdbc */
    for ( /* iterate over jdbc results */ ) {
        T item = c.newInstance();
        /* use reflection and set all of item’s fields from sql results */
        result.add(item);
    }
    return result;
}

Since Java erases the type parameter, making it a java.lang.Object or a class specified as the generic's upper bound, it is important to have access to the Class<T> object inside the select method. Since newInstance returns an object of type <T>, the compiler can perform type checking, eliminating a cast.

由于Java会删除type参数,使其成为java.lang.Object或指定为泛型上限的类,因此访问select方法中的Class 对象非常重要。由于newInstance返回类型为 的对象,因此编译器可以执行类型检查,从而消除了强制转换。


1 SUN Oracle has published a good article explaining all this.
2 This is different from implementations of generics without type erasure, such as one in .NET.
3Java Generics tutorial by Oracle.

#2


7  

The answer by dasblinkenlight already demonstrated one of the main uses of this parameter. There is one more aspect I consider relevant: using that parameter, you can restrict the kind of class you want to pass at a given location. So e.g.

dasblinkenlight的答案已经证明了这个参数的主要用途之一。还有一个我认为相关的方面:使用该参数,您可以限制要在给定位置传递的类的类型。所以例如

Class<? extends Number> cls

means that cls may be any class implementing the Number interface. This can help catching certain errors at compile time, and makes class argument requirements more explicit.

表示cls可以是实现Number接口的任何类。这有助于在编译时捕获某些错误,并使类参数要求更加明确。

Perhaps a comparison to the case without generics is in order

也许与没有泛型的情况进行比较是有道理的

// Java ≥5 with generics    // Java <5 style without generics
Class<? extends Foo> c;     Class c;
Foo t1 = c.newInstance();   Foo t1 = (Foo)c.newInstance();
Object obj;                 Object obj;
Foo t2 = c.cast(obj);       Foo t2 = (Foo)c.cast(obj);

As you can see, not having T as an argument would require a number of explicit casts, as the corresponding methods would have to return Object instead of T. If Foo itself is a generic type argument, then all those casts would be unchecked, resulting in a sequence of compiler warnings. You can suppress them, but the core issue remains: the compiler cannot check the validity of these casts unless you properly use the type argument.

正如您所看到的,没有T作为参数将需要许多显式强制转换,因为相应的方法必须返回Object而不是T.如果Foo本身是泛型类型参数,那么所有这些强制转换将被取消选中,结果在一系列编译器警告中。您可以抑制它们,但核心问题仍然存在:除非您正确使用type参数,否则编译器无法检查这些强制转换的有效性。

#3


1  

In Java there's a single metaclass: Class. Its instances (only one per type exists) are used to represent classes and interfaces, therefore the T in Class<T> refers to the type of the class or interface that the current instance of Class represents.

在Java中,有一个元类:Class。它的实例(每种类型只存在一个)用于表示类和接口,因此Class 中的T指的是当前Class实例所代表的类或接口的类型。

#4


0  

The use of generics in the Class type is top define the type of class. If I have ' Class obj' my object obj can holds only children of Charsequence. This is an optional argument. I'm often put an '?' to avoid warnings from the Eclipse IDE if I don't need an specific type of class.

在类类型中使用泛型是*定义类的类型。如果我有'Class obj',我的对象obj只能拥有Charsequence的子级。这是一个可选参数。我经常把'?'如果我不需要特定类型的类,请避免来自Eclipse IDE的警告。