[英]Java generic type issue
Consider the following simplified example:考虑以下简化示例:
package com.test;
class B<S> {
B(Class<S> clazz) {}
}
class A<T> {
class SubB extends B<SubB> {
SubB() {
super(SubB.class);
}
}
}
Although IntelliJ is not showing any error (as it usually does when compile errors exist), the actual compilation when starting the program ends with error located in super(SubB.class);
尽管 IntelliJ 没有显示任何错误(就像存在编译错误时通常那样),但启动程序时的实际编译以位于
super(SubB.class);
错误结束super(SubB.class);
: :
Error:(8, 23) java: incompatible types:
java.lang.Class<com.test.A.SubB>
cannot be converted tojava.lang.Class<com.test.A<T>.SubB>
错误:(8, 23) java:不兼容的类型:
java.lang.Class<com.test.A.SubB>
无法转换为java.lang.Class<com.test.A<T>.SubB>
I am curious, why is this happening?我很好奇,为什么会这样? And how could I solve it?
我怎么能解决呢?
Compilation is done with AdoptOpenJDK 11.编译是使用 AdoptOpenJDK 11 完成的。
The reason for this behavior is a bit complicated.这种行为的原因有点复杂。 Consider
java.util.List.class
, which has the type Class<java.util.List>
, not Class<java.util.List<?>>
.考虑
java.util.List.class
,它的类型为Class<java.util.List>
,而不是Class<java.util.List<?>>
。 This is a limitation of the class literal.这是类文字的限制。
In your example, SubB.class
has the type Class<com.test.A.SubB>
, again with the raw type of SubB.在您的示例中,
SubB.class
的类型为Class<com.test.A.SubB>
,同样具有 SubB 的原始类型。 But the constructor expects some type of Class<com.test.A<T>.SubB>
.但是构造函数需要某种类型的
Class<com.test.A<T>.SubB>
。
That's why we need to cast the literal to it's desired type:这就是为什么我们需要将文字转换为所需的类型:
super((Class<SubB>) (Class<?>) SubB.class);
This will produce a warning, but a quick examination will show that there is nothing to worry about.这将产生警告,但快速检查将表明没有什么可担心的。
I found this very interesting.我觉得这很有趣。
The problem here is that when you declare this:这里的问题是,当你声明这个时:
class A<T> {
class SubB extends B<SubB> {
SubB() {
super...
}
}
}
that B<SubB>
is actually B<A<T>.SubB>
(I was not even aware this is possible). B<SubB>
实际上是B<A<T>.SubB>
(我什至不知道这是可能的)。 This is easy to prove thx for javap
(just decompile the class and see for yourself).这很容易为
javap
证明 thx(只需反编译该类并亲自查看)。 Once you write that in the "long" form:一旦你把它写成“长”形式:
class A<T> {
class SubB extends B<A<T>.SubB> {
SubB() {
super(....);
}
}
}
it starts to make a lot more sense.它开始变得更有意义。
Ideally for this to work, you have to be able to write:理想情况下,要使其正常工作,您必须能够编写:
super(A<T>.SubB.class);
but java does not allow this, .class
can only be invoked on raw types.但是 java 不允许这样做,
.class
只能在原始类型上调用。
The best way to do it is to be explicit here:最好的方法是在这里明确:
class A<T> {
class SubB extends B<A.SubB> {
SubB() {
super(SubB.class);
}
}
}
in saying: I am using the raw type of A
: B<A.SubB>
在说:我正在使用
A
的原始类型: B<A.SubB>
In generics the inheritance is not as we usually know, ie lets take an example class ArrayList<String>
is not a subclass of List
.在泛型中,继承并不像我们通常所知道的那样,即让我们举个例子类
ArrayList<String>
不是List
的子类。 Whereas List<String>
is not same as List
.而
List<String>
与List
。
Also in generics you will not generally get a compilation error easily since the Generic types are been transformed to their raw types during the compilation.同样在泛型中,您通常不会轻易得到编译错误,因为在编译期间泛型类型被转换为它们的原始类型。
Hence we need to cast as mentioned by @JohannesKuhn.因此,我们需要按照@JohannesKuhn 所述进行转换。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.