问题描述
我想知道为什么这是一个有效的覆盖:
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.
这篇关于添加参数后,覆盖具有泛型返回类型的方法失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!