1

但是,如果我将 f(object) 更改为 f(String) 或 f(Integer),则以下代码无法编译。我已经阅读了有关该主题的其他帖子,但我仍然不明白,编译器为什么不知道使用哪种方法(如果是新实例 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 xObject t仍然无法编译,那有什么区别?此外,为什么它不只是覆盖 A 中的函数?(类型擦除后两者具有相同的签名

4

1 回答 1

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)from的有效覆盖A

该方法public <T> void f(Object x)属于子类,可以使用 superlcas 引用作为a.<Integer>f(null);或来调用a.<String>f(null);。由于被覆盖的方法在运行时解决,泛型在编译时本身会进行类型擦除,因此编译器无法知道是在编译时替换T还是IntegerString编译时替换。

反转方法仍然是合法的,因为编译器拥有决定应该替换什么所需的所有信息,因此您拥有方法public <T> void f(Object x)inA和方法public void f(Object x)in 。B<T>

于 2017-02-12T14:30:24.657 回答