gpt4 book ai didi

java - 添加参数后覆盖具有泛型返回类型的方法失败

转载 作者:太空狗 更新时间:2023-10-29 22:41:26 25 4
gpt4 key购买 nike

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

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:

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:

  • ...
  • The signature of mC is a subsignature (§8.4.2) of the signature of mA.
  • ...

子签名在 JLS §8.4.2 中定义:

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.

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.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();

最佳答案

根据编译器输出,两个示例中的方法签名不同(使用 -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 has the same signature as m1, or

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

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

有效覆盖

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

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

<X>getSupplier()删除后等于getSupplier() .

无效覆盖

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

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

m1的签名:

getSuppliers(Collection<String> strings);

删除m2的签名:

getSuppliers(Collection strings);

Collection<String> 更改 m1 参数到原始Collection消除错误,在这种情况下 m1 成为 m2 的子签名。

结论

第一个代码片段(有效覆盖):父类和子类中的方法签名最初是不同的。但是,在对父方法应用删除后,签名变得相同。

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

关于java - 添加参数后覆盖具有泛型返回类型的方法失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50296958/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com