因此,我试图编写一种方法来回答我之前的一个问题:如何确定任意 java.lang.Method 是否覆盖另一个?为此,我正在阅读 JLS,在一个案例中似乎缺少一些部分。
假设您有以下课程:
public class A<T> {
public void foo(T param){};
}
public class B extends A<String> {
public void foo(String param){};
}
在这种情况下,很明显B.foo
overrides A.foo
,但是我不明白这种情况如何符合规范。
关于方法覆盖,JLS §8.4.8.1指出:
在类 C 中声明的实例方法 m1 覆盖在类 A 中声明的另一个实例方法 m2,前提是满足以下所有条件:
C 是 A 的子类。
m1 的签名是 m2 签名的子签名(第 8.4.2 节)。
任何一个:
- m2 是公共的、受保护的或在与 C 相同的包中声明为具有默认访问权限,或
- m1 覆盖方法 m3(m3 不同于 m1,m3 不同于 m2),这样 m3 会覆盖 m2。
显然第 1 点和第 3 点在我们的案例中得到满足。让我们在 JLS 中更深入地了解子签名的含义。JLS §8.4.2说:
如果两个方法具有相同的名称和参数类型,则它们具有相同的签名。
如果满足以下所有条件,则两个方法或构造函数声明 M 和 N 具有相同的参数类型:
它们具有相同数量的形式参数(可能为零)
它们具有相同数量的类型参数(可能为零)
令 A1, ..., An 为 M 的类型参数,令 B1, ..., Bn 为 N 的类型参数。将 N 的类型中出现的 Bi 重命名为 Ai 后,相应类型变量的边界为相同,并且M和N的形参类型相同。
在我们的例子中,第 1 点显然是正确的(两者都有 1 个参数)。
第 2 点有点混乱(这就是我不确定规范的确切含义的地方):这两种方法都没有声明自己的类型参数,而是A.foo
使用T
which 是对类进行参数化的类型变量。
所以我的第一个问题是:在这种情况下,在类中声明的类型变量是否计数?
好的,现在让我们假设这T
不算数,因此第 2 点是错误的(在这种情况下,我什至不知道如何应用第 3 点)。我们的两个方法没有相同的签名,但这并不妨碍B.foo
成为A.foo
.
在JLS §8.4.2中更进一步,它说:
方法 m1 的签名是方法 m2 签名的子签名,如果:
m2 与 m1 具有相同的签名,或
m1 的签名与 m2 签名的擦除(第 4.6 节)相同。
我们已经确定第 1 点是错误的。
根据JLS §4.6的方法的擦除签名是a signature consisting of the same name as s and the erasures of all the formal parameter types given in s
. 所以 A.foo 的擦除是foo(Object)
并且 B.foo 的擦除是foo(String)
。这两个是不同的签名,因此第 2 点也是错误的,并且 B.foo 不是 A.foo 的子签名,因此 B.foo 不会覆盖 A.foo。
除了它...
我错过了什么?是否有一些我没有看到的难题,或者在这种情况下规范真的不完整?