我正在为jdk6阅读一本不可思议的书“java认证的程序员指南”,还有一个关于泛型覆盖的章节。在它上面描述了子签名和覆盖等价,并描述了一些重写等效的例子,我引用如下:
给定类中的以下三个泛型方法声明:
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's型Bi的每一次发生改名为Ai后,相应类型变量的界与M和N的参数类型相同.方法m1的签名是方法m2的签名的一个子签名,如果m2具有与m1相同的签名,或者m1的签名与m2的签名擦除相同。
...
两个方法签名m1和m2是重写的当且仅当m1是m2的子签名或m2是m1的子签名。
在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签名的子签名,条件是:
两个方法签名m1和m2是重写的当且仅当m1是m2的子签名或m2是m1的子签名。
编辑1
简单地说,我怀疑的是,从关于擦除的子签名定义来看,我的理解是,“一个不擦除的签字等于另一个签字的擦除”。而不是说“擦除后的签名是平等的”。它微妙但重要(顺便说一句,覆盖等价的定义是基于子签名定义的,这就是为什么我要求使用子签名)。
发布于 2015-07-06 11:12:03
TL;DR
在我看来,这本书的措辞在这里并没有很好地结合起来。重载定义为对覆盖等价性的否定,如司法协助(8.4.9) (释义:如果两个名称相同但不是覆盖等效的方法存在,则它们将重载)。
但是给出的例子是,方法是而不是覆盖--等价的,但是 do 由于其他原因(名称冲突--JLS 8.4.8.3中指定的特定编译时错误)而导致编译时错误,因此不会超载。
前言
据我所知,你提出了一个关于这个句子的确切语义的问题:
...or m1的签名与擦除m2的签名相同
结合在一起
m1和m2是重写的当且仅当m1是m2的子签名或m2是m1的子签名。
你的书暗示这应该被解释为
或者擦除m1的签名与擦除m2的签名是相同的
(用黑体斜体加词)。
而你会把它解释为
或m1 (无擦除)的签名与m2签名的擦除相同
你的解释是正确的。我不认为这个句子是模棱两可的,因此我认为用第一种方式来解释它(即两个签名的擦除是相同的)是不正确的。您可能希望看看这个相关的答案在这里增加我的意见(我发现它,因为我也想检查我的理解)。
回答(不过.)
书中你引用的部分实际上是试图描述超载。
现在,当考虑到重载时,JLS (8.4.9)说表示:
如果一个类的两个方法(无论是在同一个类中声明的方法,还是由类继承的方法,或者一个已声明的方法和一个继承的方法)具有相同的名称,但是签名是不相同的,则该方法名称被称为重载。
这一点至少从Java 6开始就一直是一致的,这就是override-equivalent和重载之间的链接来源。
好的-所以您的方法会超载,因为它们不是严格覆盖的-等效的。对吗?
不对。
因为就在这一节的前面,在8.4.8.3中,JLS引入了一个特定的编译时错误:
如果类型声明T有成员方法m1,并且存在在T中声明的方法m2或T的超类型,则这是编译时错误,因此以下所有内容都是真的:
这是您的示例中的场景。在这一节的下面,它澄清了为什么有必要:
这些限制是必要的,因为泛型是通过擦除实现的。上面的规则意味着在同一个名称的类中声明的方法必须有不同的擦除。它还意味着类型声明不能实现或扩展对同一个泛型接口的两个不同的调用。
旁注
书中的例子很奇怪,因为Java不允许重写静态方法(相反,子类中的方法签名可以将其隐藏在超类中)。在我看来,这使得不被覆盖的概念--等价的概念--对于一个学习者来说有点棘手。但是,您可以删除static,仍然可以看到他们试图演示的效果。
https://stackoverflow.com/questions/31225155
复制相似问题