irr*_*ble -9 java oop generics
如果我们有一个泛型类的变量,比如List,它应该是什么类型的?
List<Class> c1;
Run Code Online (Sandbox Code Playgroud)
要么
List<Class<?>> c2;
Run Code Online (Sandbox Code Playgroud)
Meh*_*dad 10
第二个,因为第一个使用原始类型而不是泛型.
即List是原始的,但是List<?>是通用的,你不应该在原始和泛型之间混合搭配.
您想表示运行时类或类型吗?(的区别在于List<String>与List<Integer>不同类型的,但共享相同的运行时类).
类型:使用类似标记之类的东西.
运行时类:自从
List<String> ls = new ArrayList<String>();
Class<? extends List> c1 = ls.getClass();
Class<List> c2 = List.class;
Run Code Online (Sandbox Code Playgroud)
编译但是
Class<? extends List<?>> c3 = ls.getClass();
Class<List<?>> c4 = List.class;
Run Code Online (Sandbox Code Playgroud)
不,我选择在类型表达式中使用原始类型.指定类型参数确实没有任何好处,List因为类没有确定它,并且使用通配符类型将需要奇怪的转换才能使其成为正确的类型,例如:
Class<?> rawClass = List.class; // kludge: do not inline this variable, or compilation will fail
Class<List<?>> classForBadAPI = (Class<List<?>>) rawClass;
Run Code Online (Sandbox Code Playgroud)
编辑:为什么它不编译
从评论中解脱出来:
为什么不编译第二个代码?代码非常有意义.这是JDK的设计错误吗?或者是否有正确的选择理由?
List.class是类型的Class<List>.由于List<?>和List是不同的类型,Class<List<?>>并且Class<List>是不相关的类型,但是赋值的右手类型必须是左手类型的子类型.的getClass()情况下是类似的.
我不会责怪JDK,他们只实现了语言规范本身规定的规则,特别是:
类文字的类型
C.Class,其中C,类,接口或数组类型的名称是Class<C>.
(来源)
e.getClass()表达式e具有静态类型的方法调用的类型T是Class<? extends |T|>.
(来源)
我们写
|T|的是类型的擦除T.
(来源)
......为什么这样定义?
编译器知道完整的泛型类型
e,但为什么e.getClass()必须返回已擦除的类型.
很难给出明确的答案,因为该规范没有扩展该定义的原因.但是,这可能是因为运行时类型可能不是静态类型的子类型,这是一种可能由于未经检查的警告的错误抑制而产生的病态情况(参见堆污染).通过指定返回类型仅包含擦除,规范确保即使存在堆污染,返回的类对象getClass()也是声明的返回类型的实例getClass().它还提醒我们,程序员即将使用反射API访问的运行时只考虑擦除类型.