当前位置: 首页 > 知识库问答 >
问题:

为什么只有在基方法包含未使用的类型参数时,才重写此泛型方法?

华飞驰
2023-03-14

我在从事Java项目时遇到了一件非常奇怪的事情。

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

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

    @Nullable
    public <E extends F> T findType(@Nonnull String name);
}

显然,类型参数E完全没用,因为它既不用于返回类型也不用于参数。我的IDE也通知了我这一点。

我还有一个扩展注册表的接口:

public interface EntityRegistry extends Registry<EntityType<? extends Entity>, Entity> {

    @Nullable
    @Override
    <E extends Entity> EntityType<E> findType(@Nonnull String name);

}

对于上下文,Entity扩展FlakeEntityType

如您所见,我正在尝试从EntityType指定此方法的返回类型

逻辑上,<代码>?扩展实体和扩展实体在这种情况下的含义是相同的,因为扩展实体没有其他限制或类似的限制,因此基本上也是扩展实体类型的通配符。

这很好用。

然而,我注意到IDE(Intellij)通知我

类型参数E从不使用。

这让我觉得我可以删除它,因为它显然是无用的,并且与返回值或任何参数都没有任何关系。

重写方法提供了自己的类型参数,它与基方法中同名的无用类型参数没有任何关系。还是有?

因为一旦我将基本方法更改为:

@Nullable
    public T findType(@Nonnull String name);

无法再以相同的方式覆盖它:

实体注册表中的findType(String)与注册表中的findType(String)冲突;这两种方法具有相同的擦除,但都不重写另一种方法。

我现在的问题是:

>

  • 当重写方法想要指定返回值泛型类型时,为什么Java在base方法中需要一个无用的类型参数?重写方法提供的参数不应该足够吗?

    为什么在第二种情况下重写不起作用?除了使用另一个类型参数而不是显式通配符之外,签名与第一种情况完全相同,这难道不应该工作吗?但既然这意味着相同的事情,那么区别是什么呢?

    我肯定我对泛型做了一些错误的假设,这就是为什么我对此感到困惑。你能帮我澄清一下吗?

    提前感谢!

  • 共有3个答案

    潘学民
    2023-03-14

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

    <E>findType(String name)
    

    无效重写-由于删除了类型参数,签名变得不同:

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

    JLS§8.4.8.1和§8.4.2描述了覆盖规则以及方法签名在其中的作用。

    越嘉石
    2023-03-14

    请参阅Jorn Vernee的答案,了解其未能编译的原因的完整描述:

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

    要进行编译,只需在EntityRegistry中指定如下方法:

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

    这与原始版本一致,因为实际上没有定义,即

    单于善
    2023-03-14

    类型参数是方法签名的一部分。您可以在JLS§8.4.2中找到:

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

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

    >

    m1的签名与m2签名的擦除(§4.6)相同。

    当m1是m2的子签名或m2是m1的子签名时,这两个方法签名是覆盖等价的。

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

     类似资料:
    • 为什么<代码>列表 我不明白编译器的消息和编译错误的原因。 返回类型没有问题:

    • 我无法编译一个需要从抽象类超类型重写方法的方法,该类超类型使用泛型作为其中一个参数。编译器抱怨扩展类的setRef()方法没有重写超类型中的方法。 父摘要类: 参考是: 而Interf是: 扩展子类(setRef()不编译): 我也尝试过使用通配符,但收到了相同的错误。使用通配符时,抽象类“setRef()是: 扩展类setRef()是: 甚至: 我能让它编译的唯一方法是,如果扩展类“setRef

    • 安吉丽卡·兰格(Angelica Langer)在关于仿制药的常见问题解答中说(参见Technicalities.FAQ822): 如果这些方法具有具有不同边界的类型参数,则它们不会重写,因为这些方法的签名不是重写等价的。请记住,类型参数边界是泛型方法签名的一部分。 示例(泛型子类型方法重载泛型超类型方法;不推荐): 我不明白为什么方法在类中重载。据我所知,这应该是一个编译时错误,因为在和中具有相

    • 问题内容: 我有一个抽象类 Monitor.java ,它由类 EmailMonitor.java 子类 化 。 方法: 在 Monitor.java中 定义,并且必须在 EmailMonitor.java中 覆盖。 我目前在 EmailMonitor.java中 重写了如下方法: 但是,这会产生编译时错误: 是的子类,因此(至少在我看来)以这种方式覆盖它是很有意义的。看到编译器对我的逻辑不满意,

    • 我正在做一个体验,尝试用以下方式重写泛型类的方法: 为什么我不能?编译错误是 yGenFun。java:15:错误:对doX的引用不明确,Do中的方法doX(A)和MyGenFun中的方法doX(T)都匹配x.doX(“测试”);^其中A、T是类型变量:在类Do T中声明的extends对象扩展在类MyGenFun 1 error中声明的CharSequence 如果我注释“第1行”,我可以编译代

    • get1方法工作正常,但get2存在编译错误: > 类型A.B的方法get2(集合)必须重写或实现超类型方法 只有带有泛型的参数才会出现此错误<代码>get3编译,但当然有一个警告: > 显然还有其他方法可以解决这个问题,但在我的理解中,这应该是一个法律优先事项,我的问题更多的是为什么会有这个编译错误。提前谢谢! 编辑: 对不起,我的例子不够清楚。因此,这里有一个新的答案来回应你的一些观点。 与上