简体   繁体   English

Java泛型类型问题

[英]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 to java.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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM