【发布时间】:2015-07-04 21:14:22
【问题描述】:
我正在阅读关于 jdk6 的令人难以置信的书“java scjp 认证程序员指南”,其中有一个关于泛型覆盖的部分。上面描述了子签名和覆盖等效项,并描述了我引用的一些覆盖等效项的示例:
给定一个类中的以下三个泛型方法声明:
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) { /*...*/ }擦除后,三个方法的签名都是:
merge(MyStack, MyStack)即,方法的签名是等效的,因此这些方法 没有超载。
我不完全同意这些方法是等效的,事实上我认为这些方法有“名称冲突由擦除”但没有一个是另一个的子签名......可能我错了,所以我想对此有所了解。
子签名的定义让我觉得它们之间不是子签名。
在 JSL 6 #8.4.2 方法签名中 (http://docs.oracle.com/javase/specs/jls/se6/html/classes.html#8.4.2)
如果两个方法具有相同的名称和参数类型,则它们具有相同的签名。 如果满足以下所有条件,则两个方法或构造函数声明 M 和 N 具有相同的参数类型:
他们。具有相同数量的形参(可能为零)
它们具有相同数量的类型参数(可能为零)
令
<A1,...,An>为M 的形式类型参数,让<B1,...,Bn>为N 的形式类型参数。将N 的类型中出现的每个Bi 重命名为Ai 后,相应类型变量的边界和M 和 N 的参数类型相同。方法 m1 的签名是方法 m2 的签名的子签名,如果有的话 m2与m1具有相同的签名,或m1的签名与m2的签名擦除相同
...如果 m1 是 m2 的子签名或 m2 是 m1 的子签名,则两个方法签名 m1 和 m2 是覆盖等效的。
在 JSL 8 # 8.4.2 中。方法签名 (http://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.2)
如果两个方法或构造函数 M 和 N 具有相同的名称、相同的类型参数(如果有)(第 8.4.4 节),并且在将 N 的形式参数类型调整为M的类型参数,形式参数类型相同。
如果满足以下任一条件,方法 m1 的签名是方法 m2 签名的子签名:
m2 与 m1 具有相同的签名,或者
m1的签名和m2的签名擦除一样。
如果 m1 是 m2 的子签名或 m2 是 m1 的子签名,则两个方法签名 m1 和 m2 是覆盖等效的。
编辑 1
简单地说,我怀疑从关于擦除的子签名定义中我明白 “没有擦除的一个签名等于另一个签名的擦除”..而不是 “擦除后的两个签名是相等的”.. 它微妙但重要 (顺便说一下,覆盖等效定义是基于子签名定义的,这就是为什么我在子签名方面提出问题)
【问题讨论】:
-
但是
merge只有<T>作为正式类型参数,对吧?据我所知,merge的所有版本都具有相同的擦除签名。 -
我同意 aioobe。不确定我是否误解了这一点,但是当您引用“m1 的签名与擦除 m2 的签名”时,您是说这些方法都不是另一个方法的子签名.据我所知,它们都有相同的擦除(检查字节码),所以我不确定你误解了什么。我什至在您的第一个报价中都没有看到任何子签名。如果我错了,请纠正我
-
@vince-emigh (和 aioobe)..这是我的怀疑伙计们,从关于擦除的子签名定义我明白“一个签名 没有 擦除等于从另一个签名中擦除”.. 而不是“擦除后的两个签名相等”.. 它微妙但重要。
-
@VinceEmigh (在我的第一个引用中,我没有提到子签名,但覆盖等效定义是基于子签名的......看看其他 qoutes)
-
这是一个奇怪的例子——因为 Java 不允许覆盖静态方法,所以我想知道为什么这本书会讨论静态方法的覆盖等效性。我在网上找到了这本书——我只是想看看你正在看第 14.12 节。如果是这样,我认为这本书措辞不佳和/或混乱。在它给出的示例中,它并不是真正谈论 overriding - 而是为什么这些方法不能存在于同一个类中并且被 overloaded 。如果您确认这是您正在寻找的地方,我会尝试将其放入明确的答案中。
标签: java generics signature erasure