您可以在运行时确定genericField中任何给定对象的类型,但无法确定TestClass< X>之间的差异.和TestClass< Y>在运行时,不检查您知道的某些成员恰好受泛型类型的约束.那就是你无法确定TestClass的类型参数< ...>给出一个TestClass的实例.
您的代码显示genericField值的类型,而不是TestClass实例的参数化类型.尝试打印this.getClass(),你会发现它在两种情况下都是相同的.
你“缺少”的是这样的:你(可以理解)在genericField本身拥有一个对象(带有一个类型)和TestClass有一个泛型类型参数这一事实之间建立了一个不正确的联系.您正在混淆确定genericFields值类型的能力,并且能够确定为TestClass指定的类型参数.也就是说,虽然您可以根据您对genericField为T的知识推断出类型参数是什么,但这与直接确定T是什么不同,这是不可能的.
查看上一段的另一种方法是考虑以下几点:
>如果TestClass没有类型T的成员,则没有其他方法可以提取T.您的代码仅“确定”T基于您自己的个人知识,即genericField被声明为持有相同类型(因此其中的对象)必须是那种类型,因此你可以得出结论,泛型参数可能是相同的类型或它的一些超类型).
>如果您没有使用泛型,并且genericField只是一个Object,您仍然可以在genericField中确定对象的类型.也就是说,它的类型与泛型类型“独立”,除非使用泛型,否则编译器会对类型进行约束.编译后它仍然只是一个任意对象,无论你是否使用泛型(这实际上只是一种方便,因为你可以在没有泛型的情况下完成所有这些,只需使用Object和大量的强制转换).
还要考虑TestClass< Base>的可能性,其中genericField被分配了Derived.您的代码将正确显示genericField是Derived,但您无法知道类型参数是Base与Derived,因为信息已被删除.
此外,将以上几点进一步归结为家:
TestClass genericString = new TestClass("Hello");
TestClass> kludge = genericString;
TestClass genericLongButNotReally = (TestClass)kludge;
genericLongButNotReally.printTypeInfo();
输出字符串的信息(这就是给出那些“未经检查的转换”警告的原因,以防止出现这种奇怪的事情),而不关心使用Long类型参数指定genericLongButNotReally的事实.当您使用泛型类型时,必须克服编译器提供的良好保护;但在运行时它并不关心.