我试图解决问题并且我已经提出了这个解决方案(简化):
package help;
public class Problem {
private static class A<T> {
public void foo(T t) {}
}
private static class B<T> {}
private static class C<T> extends A<B<T>> {
public void foo(T t) {}
}
}
它不会编译因为&#34; foo(T)在help.Problem.C中与help.Problem.A中的foo(T)冲突;两种方法都有相同的擦除,但都没有覆盖其他方法&#34;。
我不只是试图解决问题,我也想了解发生了什么。我注意到如果省略B类,错误就消失了。
另外:你能提供一段代码的例子,编译器无法将变量绑定到这两种方法中的一种吗?
答案 0 :(得分:3)
A
的类定义意味着如果要覆盖foo
,编译器会“期望”这样的内容:
private static class C<T> extends A<B<T>> {
public void foo(B<T> t) {}
}
但是,由于您只是提供T
作为该方法的类型而不是B<T>
,因此它不是类foo
中A
的有效覆盖 - 参数类型必须匹配。这不会导致非泛型类型的错误 - 您只是有一个重载方法(一个名称相同但参数类型/数量不同的方法)而不是一个覆盖的。
但是,由于泛型类型在编译时消失(通过类型擦除),这意味着您不能仅通过泛型类型区分两种方法,因为它们在字节码中的定义是相同的。
答案 1 :(得分:0)
要查看它们为什么要删除相同的类型,只需删除所有<>
及其中的内容,然后将所有通用参数类型替换为Object
:
class Problem {
private static class A {
public void foo(Object t) {}
}
private static class B {}
private static class C extends A {
public void foo(Object t) {}
}
}
现在你明白为什么了。
无法重载这样的方法是泛型的限制之一。 Read more here.
问题的根源在于C
,T
意味着与A
中的不同。我们假设您删除了foo
中C
的声明,并且您有一个C<T>
的实例。您想使用此实例调用foo
。你需要通过什么参数?一个B<T>
,对吗?如果foo
被声明为接受T
中的C
,则不会覆盖A.foo
,因为A.foo
需要接受B<T>
,而不是只是T
。
要实际覆盖foo
,请将参数更改为B<T>
类型。