Почему переопределяющие методы не могут указать параметр типа, если переопределенный метод этого не делает?
Следующий код не компилируется, однако, если я изменяю 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 x
в Object t
он все еще не компилируется, так в чем же разница? и кроме того, почему он не просто отменяет функцию из A? (оба имеют одинаковую подпись после стирания типа
1 ответ
Класс 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)
от A
,
Метод public <T> void f(Object x)
принадлежит подклассу и может быть вызван с использованием ссылки суперкласса как a.<Integer>f(null);
или же a.<String>f(null);
, Поскольку переопределенные методы разрешаются во время выполнения, но обобщенные типы проходят стирание типов во время самой компиляции, компилятор не может узнать, следует ли заменить T
с Integer
или же String
во время компиляции.
Все еще законно повернуть методы так, чтобы у вас был метод public <T> void f(Object x)
в A
и метод public void f(Object x)
в B
так как у компилятора есть вся информация, необходимая, чтобы решить, что <T>
следует заменить на.