[英]Java generic type issue
考虑以下简化示例:
package com.test;
class B<S> {
B(Class<S> clazz) {}
}
class A<T> {
class SubB extends B<SubB> {
SubB() {
super(SubB.class);
}
}
}
尽管 IntelliJ 没有显示任何错误(就像存在编译错误时通常那样),但启动程序时的实际编译以位于super(SubB.class);
错误结束super(SubB.class);
:
错误:(8, 23) java:不兼容的类型:
java.lang.Class<com.test.A.SubB>
无法转换为java.lang.Class<com.test.A<T>.SubB>
我很好奇,为什么会这样? 我怎么能解决呢?
编译是使用 AdoptOpenJDK 11 完成的。
这种行为的原因有点复杂。 考虑java.util.List.class
,它的类型为Class<java.util.List>
,而不是Class<java.util.List<?>>
。 这是类文字的限制。
在您的示例中, SubB.class
的类型为Class<com.test.A.SubB>
,同样具有 SubB 的原始类型。 但是构造函数需要某种类型的Class<com.test.A<T>.SubB>
。
这就是为什么我们需要将文字转换为所需的类型:
super((Class<SubB>) (Class<?>) SubB.class);
这将产生警告,但快速检查将表明没有什么可担心的。
我觉得这很有趣。
这里的问题是,当你声明这个时:
class A<T> {
class SubB extends B<SubB> {
SubB() {
super...
}
}
}
B<SubB>
实际上是B<A<T>.SubB>
(我什至不知道这是可能的)。 这很容易为javap
证明 thx(只需反编译该类并亲自查看)。 一旦你把它写成“长”形式:
class A<T> {
class SubB extends B<A<T>.SubB> {
SubB() {
super(....);
}
}
}
它开始变得更有意义。
理想情况下,要使其正常工作,您必须能够编写:
super(A<T>.SubB.class);
但是 java 不允许这样做, .class
只能在原始类型上调用。
最好的方法是在这里明确:
class A<T> {
class SubB extends B<A.SubB> {
SubB() {
super(SubB.class);
}
}
}
在说:我正在使用A
的原始类型: B<A.SubB>
在泛型中,继承并不像我们通常所知道的那样,即让我们举个例子类ArrayList<String>
不是List
的子类。 而List<String>
与List
。
同样在泛型中,您通常不会轻易得到编译错误,因为在编译期间泛型类型被转换为它们的原始类型。
因此,我们需要按照@JohannesKuhn 所述进行转换。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.