如果overriden方法没有,为什么不能覆盖方法指定类型参数?

时间:2017-02-12 14:24:46

标签: java generics erasure

以下代码无法编译,但是,如果我将f(对象)更改为f(String)或f(整数),则编译。 我已经阅读了关于这个主题的其他帖子,但我仍然没有得到它,为什么编译器不知道使用哪种方法 (如果是新实例A a = new B();)

public class SampleTester { 
    public static class A {
        public void f(int x) { System.out.print("1"); } 
        public void f(Object x) { System.out.print("2"); } 
    } 
    public static class B extends A { 
           public <T> void f(T x) { System.out.print("3"); } //compiler error
    }   
    public static void main(String[] args) { 
         A a = new A();
         B b= new B(); 
         a.f(3);
         a.f("foo"); 
         b.f(3);
         b.f("foo"); 
    } 
} 

如果我将T x更改为Object t,它仍然无法编译,那么有什么区别?此外,为什么它不只是覆盖A的功能? (在类型擦除后两者都具有相同的签名

1 个答案:

答案 0 :(得分:3)

B扩展A,因此继承了A中存在的所有方法。这意味着B将有3种方法:

public void f(int x)
public void f(Object x)
public <T> void f(T x)

问题是f(T x)将在编译期间进行类型擦除,T将替换为Object,从而导致重复方法,因为您已经有一个方法需要Object论点。

要解决此问题,请删除采用Object参数的方法或提供T的上限。 (示例T extends Number,以便在类型删除期间T替换为Number

解决您的评论(我现在已添加到您的问题中):

public <T> void f(Object x)无法编译,因为它不是来自public void f(Object x)的{​​{1}}的有效覆盖。

方法A属于子类,可以使用superlcass引用作为public <T> void f(Object x)a.<Integer>f(null);进行调用。由于overriden方法在运行时解析 BUT 泛型在编译时自行进行类型擦除,因此编译器无法知道是否用a.<String>f(null);替换T或{ {1}}在编译时。

由于编译器具有必要的所有信息,因此在Integer中使用方法String和在public <T> void f(Object x)中使用方法A来反转方法仍然是合法的。决定应该用public void f(Object x)代替什么。