简体   繁体   English

不兼容的通用类型:使用带有泛型类型的.class时,无法指定子类型

[英]Incompatible Generic Types: Cannot specify sub-type when using .class with generic type

There are many threads relating to Java Generics, and I'm having trouble sorting out why exactly Java doesn't support this (or alternatively, what I need to do to make it work). 有很多与Java Generics有关的线程,我很难理解为什么Java不支持这个(或者我需要做些什么来使它工作)。

public interface Thinger<T> {

    Class<? extends Thinger<T>> getThingers();
}

public class Thingy<Qwerty> implements Thinger<String> {

    @Override
    public Class<? extends Thinger<String>> getThingers() {
        return Thingx.class;
    }
}

public class Thingx implements Thinger<String> {

    @Override
    public Class<? extends Thinger<String>> getThingers() {
        return Thingy.class;    // Incompatible types error
    }
}

I can fix the compile error two ways, but both of them end up dropping some kind of typing information that I want to keep! 我可以通过两种方式修复编译错误,但是它们最终都会丢弃我想保留的某种类型的输入信息!

Option 1 选项1

Drop the generic Qwerty in Thingy<Qwerty> . Thingy<Qwerty>删除通用Qwerty

public class Thingy implements Thinger<String> {
    ..
// Ends up fixing the compile error in Thingx

Option 2 选项2

Drop the generic String in Class<? extends Thinger<String>> 删除Class<? extends Thinger<String>>的泛型String Class<? extends Thinger<String>>

public class Thingx implements Thinger<String> {

    @Override
    public Class<? extends Thinger> getThingers() {
        return Thingy.class;    // Fixed!

Thingy.class returns a Class<Thingy> where Thingy is a raw type since it doesn't specify a value for Qwerty . Thingy.class返回一个Class<Thingy> ,其中Thingy是一个原始类型,因为它没有为Qwerty指定值。 Since, it's a raw type, the compiler is only aware of Thingy implementing Thinger , instead of Thinger<String> , since that information is lost due to type erasure. 因为,它是一个原始类型,编译器只知道Thingy实现Thinger而不是Thinger<String> ,因为该信息因类型擦除而丢失。

To fix it, you can convert the Class<Thingy> to a Class<? extends Thinger> 要解决此问题,您可以将Class<Thingy>转换为Class<? extends Thinger> Class<? extends Thinger> using Class#asSubclass , and then the compiler allows the implicit cast to Thinger<String> . 使用Class#asSubclass Class<? extends Thinger> ,然后编译器允许隐式转换为Thinger<String>

return Thingy.class.asSubclass(Thinger.class);

This produces no compiler or runtime errors when tested: 测试时不会产生编译器或运行时错误:

Class<? extends Thinger<String>> c = new Thingx().getThingers();
System.out.println(c.getGenericInterfaces()[0]);

Output is: 输出是:

Thinger<java.lang.String>

I'm having trouble sorting out why exactly Java doesn't support this 我无法解决为什么Java不支持这一点

Thingy.class has type Class<Thingy> , which is not a subtype of Class<? extends Thinger<String>> Thingy.class类型为Class<Thingy> ,它不是Class<? extends Thinger<String>>的子类型Class<? extends Thinger<String>> Class<? extends Thinger<String>> , because Thingy is not a subtype of Thinger<String> . Class<? extends Thinger<String>> ,因为Thingy不是Thinger<String>的子类型。

Note that since Thingy is a generic class (it is declared with a type parameter), using Thingy by itself without a type argument is a raw type . 请注意,由于Thingy是一个泛型类(它使用类型参数声明),因此使用Thingy本身而不使用类型参数是原始类型 When you use a raw type, you disable all generics, so the supertype of Thingy (the raw type) is Thinger (the raw type), not Thinger<String> (even though Qwerty is not involved in the relationship). 当你使用原始类型时,你禁用所有泛型,所以Thingy (原始类型)的超类型是Thinger (原始类型),而不是Thinger<String> (即使Qwerty没有参与关系)。 This is similar to how if you call a method on a raw type like Thingy , all generics are turned off in the parameter and return types of the method, even if they have nothing to do with Qwerty . 这类似于如果在像Thingy这样的原始类型上调用方法,所有泛型都在参数和方法的返回类型中关闭,即使它们与Qwerty无关。 This is just one of the reasons to avoid raw types. 这只是避免原始类型的原因之一。

It works for Thingx.class because Thingx is a subtype of Thinger<String> , as Thingx is not a raw type because the class Thingx is not generic. 它适用于Thingx.class因为Thingx Thinger<String>的子类型,因为Thingx不是原始类型,因为类Thingx不是通用的。

As others have noted, there doesn't seem to be any reason why Thingy is generic, as the type parameter Qwerty is never used inside Thingy . 正如其他人所指出的那样,似乎没有任何理由为什么Thingy是通用的,因为类型参数Qwerty从未在Thingy使用Thingy So the best choice would be to remove it. 因此,最好的选择是删除它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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