use*_*652 8 java generics signature erasure
我正在为jdk6阅读令人难以置信的书"java scjp认证的程序员指南",以及关于泛型覆盖的部分.在它上面描述了subsignature和override-equivalent,并描述了一些我引用的覆盖等价的例子:
给定以下三个类中的泛型方法声明:
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的类型艾一碧的每次出现相应类型变量的范围和参数类型M和N都是一样的了.如果m2与m1具有相同的签名,或者m1的签名与m2的签名擦除相同,则方法m1的签名是方法m2的签名的子签名.
...如果m1是m2的子签名或m2是m1的子签名,则两个方法签名m1和m2是覆盖等价的.
在JSL 8#8.4.2中.Method Signature(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是覆盖等价的.
简单来说,我的疑问是,从擦除方面的子签名定义我明白"没有擦除的一个签名等于来自其他签名的擦除"......而不是"擦除后的两个签名是相等的".它的微妙但重要(顺便说一句,覆盖等效定义是基于子签名定义,这就是为什么我用子签名来问)
在我看来,这本书的措辞在这里并没有很好地结合在一起。根据JLS (8.4.9),重载是根据重写等价性的否定来定义的(释义:如果存在两个同名的方法,但不是重写等价的,那么它们将重载)。
\n但给出的示例中的方法不是等效覆盖的,但确实会因其他原因导致编译时错误(名称冲突 - JLS 8.4.8.3中指定的特定编译时错误),因此不会重载。
\n据我了解,您提出了关于这句话的确切语义的问题:
\n\n\n“...或者m1的签名与m2签名的擦除相同”
\n
结合
\n\n\nm1 和 m2 是覆盖等效的,当且仅当 m1 是 m2 的子签名或 m2 是 m1 的子签名。
\n
你的书暗示这应该解释为
\n\n\n“或删除与m2签名的擦除相同”
\n
(添加的单词以粗体斜体显示)。
\n而你会把它解释为
\n\n\n“或 m1 的签名(不擦除)与m2的签名的擦除相同”
\n
你的解释是正确的。 我不认为这句话有歧义,因此我认为以第一种方式解释它(即两个签名的擦除是相同的)是不正确的。您可能想看看这个相关答案,以增加我在这里的观点的分量(我发现它是因为我也想检查我的理解)。
\n您引用的书中的部分实际上是在尝试描述重载。
\n现在 - 当考虑重载时 - JLS (8.4.9) 说:
\n\n\n如果一个类的两个方法(无论是在同一个类中声明,还是都由一个类继承,或者一个声明一个继承)具有相同的名称,但签名不是重写等效的,则该方法名称被称为超载。
\n
至少从 Java 6 开始,这一点是一致的。这就是两者之间的联系所在override-equivalent和重载之间的联系的根源。
好的 - 所以你的方法会重载,因为它们不是严格覆盖等价的。正确的?
\n错误的。
\n因为就在 8.4.8.3 中该部分的上方,JLS放入了一个特定的编译时错误:
\n\n\n如果类型声明 T 具有成员方法 m1 并且存在在 T 或 T 的超类型中声明的方法 m2 且满足以下所有条件,则会出现编译时错误:
\n\n
\n- \n
m1 和 m2 具有相同的名称。
\n- \n
m2 可从 T 访问。
\n- \n
m1 的签名不是 m2 签名的子签名 (\xc2\xa78.4.2)。
\n- \n
m1 或 m1 覆盖(直接或间接)的某些方法的签名与 m2 或 m2 覆盖(直接或间接)的某些方法的签名具有相同的擦除。
\n
这就是您的示例中的场景。就在该部分的下方,它阐明了为什么有必要:
\n\n\n这些限制是必要的,因为泛型是通过擦除来实现的。上面的规则意味着在同一个类中声明的具有相同名称的方法必须具有不同的擦除。它还意味着类型声明不能实现或扩展同一泛型接口的两个不同调用。
\n
书中的示例很奇怪,因为 Java 不允许重写静态方法(而子类中方法的签名可能会在超类中隐藏该方法)。在我看来,这使得不覆盖等效的概念对于学习者来说有点棘手。但是,您可以删除它们static,但仍然可以看到它们试图演示的效果。
| 归档时间: |
|
| 查看次数: |
359 次 |
| 最近记录: |