泛型方法继承
Generic method inheritance
问题是关于以下代码块:
public class SomeClass {
public static class A {
public void f(int x) {
System.out.println("1");
}
public void f(Object x) {
System.out.println("2");
}
}
public static class B extends A {
public <T> void f(T x) { // *
System.out.println("3");
}
}
}
第 *
行未编译,出现以下错误:
Description Resource Path Location Type
Name clash: The method f(T) of type SomeClass.B has the same erasure as f(Object) of type SomeClass.A but does not override it
为避免重复:
我看过: Type erasure, overriding and generics , Method has the same erasure as another method in type 并且虽然我收到了答案(部分原因是因为我仍然没有完全理解它)为什么会出现编译错误(以避免由于类型擦除而产生歧义?是这个吗?它?)主要问题是我不明白为什么,如果我在 f(Object x)
和 f(T x)
两种方法之间切换,那么代码将是这样的:
public class SomeClass {
public static class A {
public void f(int x) {
System.out.println("1");
}
public <T> void f(T x) {
System.out.println("3");
}
}
public static class B extends A {
public void f(Object x) {
System.out.println("2");
}
}
}
我没有收到编译错误。
为什么会这样?对于第一个代码我得到一个编译错误而对于第二个我没有得到的关键区别是什么。希望对此有一些解释,谢谢!
这里的问题是键入擦除,如错误中所写。这意味着你的泛型类型 constraint/definition <T>
in class B
只被编译器视为进行类型检查。但是,您将 <T>
放在运行时字节代码中无法执行方法解析。
因此,当类型被删除时,请查看您的 public void <T> f(T x)
- 剩下的就是 Object
(这只是您可以作为第一个参数填充的东西)。但这与 class A
中的签名相同 - 给您带来错误。
在第二种情况下它完全没问题,因为你的 class B
方法将接受任何对象 - 所以它当然会接受你在 [的签名中指定的任何 <T>
=15=].
One of the answers to one of the questions you linked 基本上已经解决了这个问题:
For overriding with instance methods you need the overriding method to be a subsignature of the overridden method.
为了更深入地研究这一点,JLS 8.4.8.1 说:
An instance method mC declared in or inherited by class C, overrides from C another method mA declared in class A, iff all of the following are true:
[...]
The signature of mC is a subsignature (§8.4.2) of the signature of mA.
子签名定义在JLS 8.4.2:
The signature of a method m1 is a subsignature of the signature of a method m2 if either:
[...]
the signature of m1 is the same as the erasure (§4.6) of the signature of m2.
您正在考虑以下两个签名:
void f(Object x)
<T> void f(T x)
#2的擦除是void f(Object x)
,因此#1是它的子签名。然而,反之则不然。
问题是关于以下代码块:
public class SomeClass {
public static class A {
public void f(int x) {
System.out.println("1");
}
public void f(Object x) {
System.out.println("2");
}
}
public static class B extends A {
public <T> void f(T x) { // *
System.out.println("3");
}
}
}
第 *
行未编译,出现以下错误:
Description Resource Path Location Type Name clash: The method f(T) of type SomeClass.B has the same erasure as f(Object) of type SomeClass.A but does not override it
为避免重复:
我看过: Type erasure, overriding and generics , Method has the same erasure as another method in type 并且虽然我收到了答案(部分原因是因为我仍然没有完全理解它)为什么会出现编译错误(以避免由于类型擦除而产生歧义?是这个吗?它?)主要问题是我不明白为什么,如果我在 f(Object x)
和 f(T x)
两种方法之间切换,那么代码将是这样的:
public class SomeClass {
public static class A {
public void f(int x) {
System.out.println("1");
}
public <T> void f(T x) {
System.out.println("3");
}
}
public static class B extends A {
public void f(Object x) {
System.out.println("2");
}
}
}
我没有收到编译错误。 为什么会这样?对于第一个代码我得到一个编译错误而对于第二个我没有得到的关键区别是什么。希望对此有一些解释,谢谢!
这里的问题是键入擦除,如错误中所写。这意味着你的泛型类型 constraint/definition <T>
in class B
只被编译器视为进行类型检查。但是,您将 <T>
放在运行时字节代码中无法执行方法解析。
因此,当类型被删除时,请查看您的 public void <T> f(T x)
- 剩下的就是 Object
(这只是您可以作为第一个参数填充的东西)。但这与 class A
中的签名相同 - 给您带来错误。
在第二种情况下它完全没问题,因为你的 class B
方法将接受任何对象 - 所以它当然会接受你在 [的签名中指定的任何 <T>
=15=].
One of the answers to one of the questions you linked 基本上已经解决了这个问题:
For overriding with instance methods you need the overriding method to be a subsignature of the overridden method.
为了更深入地研究这一点,JLS 8.4.8.1 说:
An instance method mC declared in or inherited by class C, overrides from C another method mA declared in class A, iff all of the following are true:
[...]
The signature of mC is a subsignature (§8.4.2) of the signature of mA.
子签名定义在JLS 8.4.2:
The signature of a method m1 is a subsignature of the signature of a method m2 if either:
[...]
the signature of m1 is the same as the erasure (§4.6) of the signature of m2.
您正在考虑以下两个签名:
void f(Object x)
<T> void f(T x)
#2的擦除是void f(Object x)
,因此#1是它的子签名。然而,反之则不然。