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

添加参数后,用泛型返回类型重写方法失败

夏知
2023-03-14

我想知道为什么这是一个有效的覆盖:

public abstract class A {

    public abstract <X> Supplier<X> getSupplier();

    public static class B extends A {

        @Override
        public Supplier<String> getSupplier() {
            return String::new;
        }
    }
}

鉴于这不是:

public abstract class A {

    public abstract <X> Supplier<X> getSuppliers(Collection<String> strings);

    public static class B extends A {

        @Override
        public Supplier<String> getSuppliers(Collection<String> strings) {
            return String::new;
        }
    }
}

根据JLS§8.4.8.1,B.getSupplier必须是子签名a.getSupplier

C类中声明或继承的实例方法mC重写C类中声明的另一个方法mA,如果以下所有为真:

  • ...
  • mC的签名是mA签名的子签名(§8.4.2)。
  • ...

子签名在JLS§8.4.2中定义:

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

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

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

因此,似乎B.getSuppliera.getSupplier的子签名,但B.getSuppliers不是a.getSuppliers的子签名。

我不知道怎么会是这样。

如果B.getSuppliera.getSupplier的子签名,因为它具有相同的擦除,那么B.getSuppliers也必须具有与a.getSuppliers相同的擦除。这应该足以覆盖getSuppliers,使其合法-但事实并非如此。

如果B.getSuppliera.getSupplier的子签名,因为它具有相同的签名,那么我想知道“相同类型参数(如果有)”的确切含义是什么。

如果考虑类型参数,则它们应该具有不同的类型参数:A.getSupplier具有类型参数XB.getSupplier没有
如果不考虑类型参数,那么getSuppliers有什么不同?

这更像是一个关于覆盖和泛型的学术问题,所以请不要建议重构代码(比如将类型参数X移动到类等)。)。

我正在寻找一个正式的,基于JLS的答案。

在我看来,B.getSupplier不应该能够覆盖A.getSupplier,因为它们没有相同的类型参数。这使得以下代码(产生ClassCastException)合法:

A b = new B();
URL url = b.<URL>getSupplier().get();

共有2个答案

夏祯
2023-03-14

添加参数的那一刻,它就不再是重写,而是过载。

泛型与此无关。

欧阳高昂
2023-03-14

根据编译器输出,两个示例中的方法签名不同(使用-Xlint:unchecked选项编译代码以确认):

<X>getSupplier() in A (m2)
                                 1st snippet
getSupplier()    in B (m1)


<X>getSuppliers(Collection<String> strings) in A (m2)
                                                           2nd snippet
getSuppliers(Collection<String> strings)    in B (m1)

根据JLS规范,方法m1的签名是方法m2签名的子签名,如果:

>

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

    m1的签名与删除m2的签名相同。

    第一种说法是出局——方法签名不同。但是第二个语句和擦除呢?

    (m1)是A的子签名。

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

    <代码>

    (m1)不是A的子签名。

    • m1的签名与m2的签名的擦除不同

    m1的签名:

    getSuppliers(Collection<String> strings);
    

    删除m2的签名:

    getSuppliers(Collection strings);
    

    集合更改m1参数

    第一

    第二个代码片段(无效覆盖):方法签名最初是不同的,在对父方法应用擦除后仍然不同。

  •  类似资料:
    • 我试图创建一个返回泛型类型参数的方法。 我有一个类车辆订单扩展抽象类订单。在类订单中,我创建了一个抽象方法接收HiredObject。这个方法不会接收任何参数,并将返回一个泛型。 我在VehicleOrder类中实现了这个方法,并将其设置为返回类参数vehicle。 问题是,当我实例化一个新的VeilceOrderorororororororororororororderororororororo

    • 我有一个问题,从抽象类中重写泛型方法。 这是我的抽象类: 当我创建类(B)来实现类(a)时,如下所示: 显示了(getData)方法中的以下编译错误: ”“B。getData“(“字符串函数(字符串)”不是“a”的有效重写。getData'('字符串函数(类型)‘)。dart(无效覆盖) 以及返回语句中的此错误: 类型为“String”的值不能从方法'getData'返回,因为它的返回类型为'St

    • 我试图创建一个Java方法,它接受一个对象类型和它应该转换成的数据类型。 例如,如果我应该能够返回一个值1作为Int或双根据需要。我使用类传递数据类型作为参数。 问题:如何使方法泛型以接受基于输入参数的返回类型? 下面的代码只是一个示例,它可能在语法上不正确,用于解释我的问题。

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

    • 可以使用泛型将返回类型与参数类型匹配吗? 实例案例: 我有一个抽象类,可以从不同的POJO导入数据,这个类包含一个abstract方法importData。 importData返回的对象必须与传递给该方法的对象类型相同。 由于抽象方法的每个实现的对象类型不同,并且类型不扩展另一个,如何定义抽象方法,以便实现返回类型和传递类型必须匹配? 经过考验: 结果: 方法的返回类型不必与传递的对象类型匹配。