添加参数后,覆盖具有泛型返回类型的方法失败 [英] Overriding a method with a generic return type fails after adding a parameter
问题描述
我想知道为什么这是一个有效的覆盖:
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屋!