添加参数后,覆盖具有泛型返回类型的方法失败 [英] Overriding a method with a generic return type fails after adding a parameter

查看:164
本文介绍了添加参数后,覆盖具有泛型返回类型的方法失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I wonder why this is a valid override:

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,iff以下所有条件都为真:

An instance method mC declared in or inherited by class C, overrides from C another method mA declared in class A, iff all of the following are true:


  • ...

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

  • ...

子标签在JLS§8.4.2


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

Two methods or constructors, M and N, have the same signature if they have the same name, the same type parameters (if any) (§8.4.4), and, after adapting the formal parameter types of N to the the type parameters of M, the same formal parameter types.

方法m1的签名是签名的一个子签名。方法m2如果:

The signature of a method m1 is a subsignature of the signature of a method m2 if either:




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

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

  • 所以它似乎 B.getSupplier A.getSupplier 的子签名,但是 B.getSuppliers A.getSuppliers 的子签名。

    So it seems like B.getSupplier is a subsignature of A.getSupplier but B.getSuppliers is not a subsignature of A.getSuppliers.

    I想知道情况如何。

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

    If B.getSupplier is a subsignature of A.getSupplier because it has the same erasure, then B.getSuppliers must also have the same erasure as A.getSuppliers. This should suffice for overriding getSuppliers to be legal - but it does not.

    如果 B.getSupplier A.getSupplier 的子签名,因为它有相同的签名,然后我想知道相同的类型参数(如果有的话) 确实意味着。

    If B.getSupplier is a subsignature of A.getSupplier because it has the same signature, then I wonder what "the same type parameters (if any)" exactly means.

    如果考虑类型参数,则它们应具有不同的类型参数: A.getSupplier 具有类型参数 X B.getSupplier 没有。

    如果不考虑类型参数那么 getSuppliers 不同?

    If type parameters are considered, then they should have different type parameters: A.getSupplier has type parameter X, B.getSupplier has none.
    If type parameters are not considered then how's getSuppliers different?

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

    This is more of an academic question about overrides and generics so please don't suggest refactoring code (like moving type parameter X to the class etc.).

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

    I am looking for a formal, JLS-based answer.

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

    From my point of view B.getSupplier should not be able override A.getSupplier as they don't have the same type parameters. This makes the following code (which produces ClassCastException) legal:

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


    推荐答案

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

    According to the compiler output, the method signatures are different in both examples (compile the code with -Xlint:unchecked option to confirm it):

    <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 规范,方法m 1 的签名是方法签名的子签名 m 2 如果:

    According to the JLS specification, the signature of a method m1 is a subsignature of the signature of a method m2 if either:



    • m 2 与m 具有相同的签名1

    m 1 的签名与删除相同m 2 的签名。

    the signature of m1 is the same as the erasure of the signature of m2.

    第一个声明不在游戏中 - 方法签名不同。但是第二个声明和删除呢?

    The first statement is out of the game - method signatures are different. But what about the second statement and erasure?

    B.getSupplier ()(m 1 )是 A的子签名。< X> getSupplier()(m 2 ),因为:

    B.getSupplier() (m1) is a subsignature of A.<X>getSupplier() (m2), because:



    • m 1的签名与m 2的签名擦除相同

    • the signature of m1 is the same as the erasure of the signature of m2



    < X> getSupplier()等于 getSupplier()

    B.getSuppliers(...)(m 1 )不是 A< X> getSuppliers(...)(m 2 )的子签名,因为:

    B.getSuppliers(...) (m1) is not a subsignature of A.<X>getSuppliers(...) (m2), because:



    • m 1 的签名与删除的不同m 2的签名

    • the signature of m1 is not the same as the erasure of the signature of m2

    m 的签名1

    getSuppliers(Collection<String> strings);
    

    删除m 2的签名

    getSuppliers(Collection strings);
    

    集合< String>更改m 1 参数; 到原始集合消除了错误,在这种情况下,m 1 成为m 2的子签名

    Changing m1 argument from Collection<String> to the raw Collection eliminates an error, in this case m1 becomes a subsignature of m2.

    1st 代码段(有效覆盖):父类和子类中的方法签名最初是不同的。但是,在将擦除应用于父方法之后,签名变得相同。

    1st  code snippet (valid override): the method signatures in the parent and child classes are different initially. But, after applying the erasure to the parent method the signatures becomes the same.

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

    2nd code snippet (invalid override): the method signatures are different initially and remains different after applying the erasure to the parent method.

    这篇关于添加参数后,覆盖具有泛型返回类型的方法失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆