具有相同擦除的两种方法不一定是等效的(或者它们之间的签名不是子签名)?

Two methods with same erasure aren't necessary override-equivalent (or they signatures aren't subsignatures between them)?

我正在阅读关于 jdk6 的令人难以置信的书“java scjp 认证的程序员指南”,其中有一节是关于泛型覆盖的。在上面描述了子签名和覆盖等价物,并描述了我引用的一些覆盖等价物的例子:

Given the following three generic method declarations in a class:

static <T> void merge (MyStack<T> s1, MyStack<T> s2) { /*...*/ }

static <T> void merge (MyStack<T> s1, MyStack<? extends T> s2) { /*...*/ }

static <T> void merge (MyStack<T> s1, MyStack<? super T> s2) { /*...*/ }

After erasure, the signature of all three methods is: merge(MyStack, MyStack) i.e., the signatures of the methods are override-equivalent, hence these methods are not overloaded.

我不完全同意这些方法是覆盖等效的,事实上我认为这些方法有一个“擦除的名称冲突”但是 none 是另一个的子签名......可能我错了所以我想对此有一些了解。

子签名的定义让我觉得它们之间不是子签名。

在 JSL 6 #8.4.2 方法签名中 (http://docs.oracle.com/javase/specs/jls/se6/html/classes.html#8.4.2)

Two methods have the same signature if they have the same name and argument types. Two method or constructor declarations M and N have the same argument types if all of the following conditions hold:

  • They. have the same number of formal parameters (possibly zero)

  • They have the same number of type parameters (possibly zero)

  • Let <A1,...,An> be the formal type parameters of M and let <B1,...,Bn> be the formal type parameters of N. After renaming each occurrence of a Bi in N's type to Ai the bounds of corresponding type variables and the argument types of M and N are the same.

The signature of a method m1 is a subsignature of the signature of a method m2 if either m2 has the same signature as m1, or the signature of m1 is the same as the erasure of the signature of m2

...

Two method signatures m1 and m2 are override-equivalent iff either m1 is a subsignature of m2 or m2 is a subsignature of m1.

在 JSL 8 # 8.4.2 中。方法签名 (http://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#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 has the same signature as m1, or

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

Two method signatures m1 and m2 are override-equivalent iff either m1 is a subsignature of m2 or m2 is a subsignature of m1.

编辑 1

简单来说,我怀疑从关于擦除的子签名定义我理解 "one signature without erasure is equal to the erasure from the other signature".. 而不是 "both signatures after erasure are equal" .. 它微妙但重要 (顺便说一下,覆盖等价定义是基于子签名定义的,这就是为什么我要问子签名)

TL;DR

在我看来,这本书的措辞并没有很好地结合在一起。重载是根据 JLS (8.4.9) 对覆盖等效性的否定来定义的(释义:如果存在两个具有相同名称但不是覆盖等效的方法,则它们将重载)。

但给出的示例中的方法是 NOT 重写等效方法,但是 DO 由于其他原因(名称冲突 - JLS 8.4.8.3 中指定的特定编译时错误)导致编译时错误,因此不要重载。


前言

据我了解,您提出的问题是关于这句话从句的确切语义:

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

结合

m1 and m2 are override-equivalent iff either m1 is a subsignature of m2 or m2 is a subsignature of m1.


你的书暗示这应该解释为

"or the erasure of the signature of m1 is the same as the erasure of the signature of m2"

(添加的单词以粗斜体显示)。

而您会将其解释为

"or the signature of m1 (without erasure) is the same as the erasure of the signature of m2"

你的解释是正确的。我不认为这句话有歧义,因此我认为用第一种方式解释它(即 erasure 两个签名是一样的)是不正确的。你可能想 look at this related answer 在这里增加我的意见(我发现它是因为我也想检查我的理解)。


回答(但是...)

您引用的书中的部分实际上是在描述重载。

现在 - 在考虑重载时 - JLS (8.4.9) says 即:

If two methods of a class (whether both declared in the same class, or both inherited by a class, or one declared and one inherited) have the same name but signatures that are not override-equivalent, then the method name is said to be overloaded.

这至少从 Java 6 开始就是一致的。这就是 override-equivalent 和重载之间的 link 的来源。

好的 - 所以你的方法会重载,因为它们不是严格的重写等效的。对吗?

错了。

因为就在 in 8.4.8.3, the JLS 部分的上方,出现了特定的编译时错误:

It is a compile-time error if a type declaration T has a member method m1 and there exists a method m2 declared in T or a supertype of T such that all of the following are true:

  • m1 and m2 have the same name.

  • m2 is accessible from T.

  • The signature of m1 is not a subsignature (§8.4.2) of the signature of m2.

  • The signature of m1 or some method m1 overrides (directly or indirectly) has the same erasure as the signature of m2 or some method m2 overrides (directly or indirectly).

这就是您示例中的场景。就在该部分的下方,它阐明了为什么有必要:

These restrictions are necessary because generics are implemented via erasure. The rule above implies that methods declared in the same class with the same name must have different erasures. It also implies that a type declaration cannot implement or extend two distinct invocations of the same generic interface.

旁注

书中的例子很奇怪,因为 Java 不允许覆盖静态方法(子类中的方法签名可以隐藏超类中的方法签名)。在我看来,这使得不被覆盖等效的概念对于学习者来说有点棘手。但是,您可以删除 static 并仍然看到他们试图展示的效果。