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

问题描述

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

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;
        }
    }
}

根据, B.getSupplier 必须是子签名 A.getSupplier


  • ...

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

  • ...

子标签在:

方法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)
    

    根据规范,方法m 的签名是方法签名的子签名 m 如果:

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

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

    the signature of m is the same as the erasure of the signature of m.

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

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

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

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



    < X> getSupplier()等于 getSupplier()

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

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

    m :

    getSuppliers(Collection<String> strings);
    

    删除m :

    getSuppliers(Collection strings);
    

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

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

    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.

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

10-10 18:06