Java 为什么仅当基方法包含未使用的类型参数时,重写此泛型方法才起作用?

Java 为什么仅当基方法包含未使用的类型参数时,重写此泛型方法才起作用?,java,generics,overriding,Java,Generics,Overriding,我在处理Java项目时遇到了一件相当奇怪的事情 我在界面中有这个基本方法: public interface Registry<T extends FlakeType<? extends F>, F extends Flake> { @Nullable public <E extends F> T findType(@Nonnull String name); } 对于上下文,Entity扩展Flake,EntityType扩展FlakeT

我在处理Java项目时遇到了一件相当奇怪的事情

我在
界面中有这个基本方法

public interface Registry<T extends FlakeType<? extends F>, F extends Flake> {

    @Nullable
    public <E extends F> T findType(@Nonnull String name);
}
对于上下文,
Entity
扩展
Flake
EntityType
扩展
FlakeType


如您所见,我试图从
EntityType指定此方法的返回类型。类型参数是方法签名的一部分。您可以在以下内容中找到:

如果两个方法或构造函数M和N具有相同的名称,相同的类型参数(如果有)(),则它们具有相同的签名,并且在将N的形式参数类型调整为M的类型参数后,具有相同的形式参数类型

方法m1的签名是方法m2签名的子签名,如果:

  • m2
    具有与
    m1
    相同的签名,或

  • m1
    的签名与
    m2
    签名的擦除()相同

m1
m2
的子符号或
m2
m1
的子符号时,两个方法签名
m1
m2
是覆盖等价的

如果注册表中没有类型参数,
EntityRegistry
中的方法没有基本接口方法的子签名,因此它不被视为重写。

有关编译失败原因的完整说明,请参阅:


类型参数是方法签名的一部分

要使其可编译,只需在
EntityRegistry
中指定如下方法:

@Nullable
@Override
EntityType<? extends Entity> findType(@Nonnull String name);
@Nullable
@凌驾

EntityType有效覆盖-两个接口中的
findType
方法的签名相同:

<E>findType(String name)

JLS并描述覆盖规则和方法签名在其中的作用。

原始代码的一个重要问题是,它不必要地复杂。此外,如果不接受未经检查的强制转换,就无法实现原始的
EntityRegistry.findType()

...warning: [unchecked] unchecked cast
         return ( EntityType< E > ) new EntityType< >(  new Entity( name ) );
                                    ^
  required: EntityType<E>
  found:    EntityType<Entity>
  where E is a type-variable:
    E extends Entity declared in method <E>findType(String)
1 warning

interface EntityRegistry<E>findType(String name)
<E>findType(String name)

findType(String name)
...warning: [unchecked] unchecked cast
         return ( EntityType< E > ) new EntityType< >(  new Entity( name ) );
                                    ^
  required: EntityType<E>
  found:    EntityType<Entity>
  where E is a type-variable:
    E extends Entity declared in method <E>findType(String)
1 warning
interface Registry< T extends FlakeType<? extends Flake> > {

    T findType(String name);
}
interface EntityRegistry< U extends EntityType<? extends Entity> > extends Registry<U> {

    @Override
    U findType(String name);
}
...
EntityRegistry<EntityType<Entity>> registry = (name) -> { return new EntityType<Entity>(new Entity(name)); };
...
...
Registry<EntityType<Entity>> registry = (name) -> { return new EntityType<Entity>(new Entity(name)); };
...