What does the generic nature of the class Class mean? What is T?
在集合方面,我理解泛型。 但是在Class< T >类的情况下它意味着什么? 实例化Class对象时,只有一个对象。 那么为什么T参数呢? 这是什么规定的? 为什么有必要(如果是)?
-
蒂姆,使用Source
-
这个答案是合适的。stackoverflow.com/a/19545123/3378204
类型参数< T >已添加到java.lang.Class以启用一个特定的idiom1 - 使用Class对象作为类型安全的对象工厂。本质上,添加< T >允许您以类型安全的方式实例化类,如下所示:
1
| T instance = myClass.newInstance(); |
类型参数< T >表示类本身,通过将Class< T >存储在泛型类中或将其作为参数传递给泛型方法,可以避免类型擦除的令人不快的影响。请注意,T本身不足以完成此任务2:T的类型被删除,因此它变为java.lang.Object。
这是一个典型的例子,其中类的< T >参数变得重要。在下面的示例中,Java编译器能够确保类型安全,允许您从SQL字符串和Class< T >的实例生成类型集合。请注意,该类用作工厂,并且可以在编译时验证其类型安全性:
1 2 3 4 5 6 7 8 9 10
| 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 re?ection and set all of item’s ?elds from sql results */
result. add(item );
}
return result ;
} |
由于Java会删除type参数,使其成为java.lang.Object或指定为泛型上限的类,因此访问select方法中的Class< T >对象非常重要。由于newInstance返回类型为< T >的对象,因此编译器可以执行类型检查,从而消除了强制转换。
1
SUN strike> Oracle发表了一篇很好的文章来解释这一切。
2这与没有类型擦除的泛型的实现不同,例如.NET中的类型擦除。
3 Oracle的Java Generics教程。
-
+1短而甜蜜。
-
@dasblinkenlight:我很抱歉,但我不太明白。你能不能给我一个例子,告诉你如何以及为什么这样做?
-
如果没有它,instance将是类Object,并且您需要进行类型转换以使其有用。
-
@dasblinkenlight:谢谢
-
类型擦除只是一个黑客,以支持从一开始就没有设计成语言的东西?或者它是否比非类型擦除泛型具有一些真正的好处(对不起,如果这是一个愚蠢的问题,我真的不熟悉C#样式泛型)
-
@ycomp类型擦除是一种将泛型实现完全保持在编译阶段,而不会"溢出"到JVM中的技术。另一方面,C#的方法将泛型的实现分解为编译器和CLR(C#的JVM对应物)。
dasblinkenlight的答案已经证明了这个参数的主要用途之一。还有一个我认为相关的方面:使用该参数,您可以限制要在给定位置传递的类的类型。所以例如
1
| Class<? extends Number> cls |
表示cls可以是实现Number接口的任何类。这有助于在编译时捕获某些错误,并使类参数要求更加明确。
或许可以与没有泛型的情况进行比较
1 2 3 4 5
| // 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 ); |
如您所见,没有T作为参数将需要许多显式强制转换,因为相应的方法必须返回Object而不是T。如果Foo本身是泛型类型参数,那么将取消选中所有这些强制转换,从而产生一系列编译器警告。您可以抑制它们,但核心问题仍然存在:除非您正确使用type参数,否则编译器无法检查这些强制转换的有效性。
-
+1我理解它,这有帮助!
-
@Redandwhite,如果你能通过点击我问题旁边漂亮的小向上箭头来表达这种"+1"情绪,我会很高兴,非常感谢你。 :-D
-
忘了做,纠正了!
-
顺便说一句,Java Reflection在现实生活中有多常见?这是我不理解的泛型的唯一部分。在近一年的专业Java开发中,我还没有找到对Reflection的需求,尽管我一直在Collections中使用泛型
-
@Redandwhite,反射由许多框架使用,用于类似序列化(例如jaxb),依赖注入(例如guice),方法枚举(例如junit)等等。因此,作为应用程序开发人员,不使用它们是正常的。作为库开发人员,它取决于库。请注意,对于像Collections.checkedList这样的运行时类型检查容器,您还需要正确的类型Class参数,并且朋友会提供它们。
在Java中有一个元类:Class。它的实例(每种类型只存在一个)用于表示类和接口,因此Class< T >中的T指的是当前Class实例所代表的类或接口的类型。
-
你的论证对我来说似乎不是很有说服力。你说的都是正确的,除了"因此"。您可以很容易地拥有一个带有表示类型的实例的元类,而不需要该类是通用的。在仿制药到来之前,它就是这样做的。
在类类型中使用泛型是最先定义类的类型。如果我有'Class obj',我的对象obj只能拥有Charsequence的子级。
这是一个可选参数。我经常把'?'如果我不需要特定类型的类,请避免来自Eclipse IDE的警告。