试图了解"两种方法都有相同的擦除,但都没有覆盖其他方法"

时间:2018-05-03 15:29:40

标签: java

我试图解决问题并且我已经提出了这个解决方案(简化):

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类,错误就消失了。

另外:你能提供一段代码的例子,编译器无法将变量绑定到这两种方法中的一种吗?

2 个答案:

答案 0 :(得分:3)

A的类定义意味着如果要覆盖foo,编译器会“期望”这样的内容:

private static class C<T> extends A<B<T>> {
    public void foo(B<T> t) {}
}

但是,由于您只是提供T作为该方法的类型而不是B<T>,因此它不是类fooA的有效覆盖 - 参数类型必须匹配。这不会导致非泛型类型的错误 - 您只是有一个重载方法(一个名称相同但参数类型/数量不同的方法)而不是一个覆盖的。

但是,由于泛型类型在编译时消失(通过类型擦除),这意味着您不能仅通过泛型类型区分两种方法,因为它们在字节码中的定义是相同的。

答案 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.

问题的根源在于CT意味着与A中的不同。我们假设您删除了fooC的声明,并且您有一个C<T>的实例。您想使用此实例调用foo。你需要通过什么参数?一个B<T>,对吗?如果foo被声明为接受T中的C,则不会覆盖A.foo,因为A.foo需要接受B<T>,而不是只是T

要实际覆盖foo,请将参数更改为B<T>类型。