2017-02-12 19 views
1

Следующий код не скомпилируется, если я изменяю f (объект) на f (String) или f (Integer), который он компилирует. Я прочитал другие сообщения о предмете, но я до сих пор не понимаю, почему компилятор не знает, какой метод использовать (в случае нового экземпляра A a = new B();)Почему методы переопределения не задают параметр типа, если метод overriden не поддерживает?

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? . (Оба имеет ту же подпись после типа стирания

+0

Я не уверен, почему этот вопрос был опущен. Это, похоже, довольно хороший вопрос ИМО. – CKing

+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) от A.

Метод public <T> void f(Object x) относится к подклассу и может быть вызван с использованием ссылки суперкласса как a.<Integer>f(null); или a.<String>f(null);. Так как переопределенные методы разрешаются во время выполнения BUT дженерики проходят через стирание стилей во время компиляции, поэтому компилятор не знает, следует ли заменить T на Integer или String во время компиляции.

Это еще законно, чтобы полностью изменить методы такие, что у вас есть метод public <T> void f(Object x) в A и метод public void f(Object x) в B, так как компилятор имеет всю информацию, необходимую, чтобы решить, что <T> следует заменить.

+0

Но если я изменю T x на Object t, он скомпилируется, так в чем же разница? и, кроме того, почему он не просто переопределяет функцию от A? (оба имеют одну и ту же подпись после типа erasure – DsCpp

+0

Это не скомпилируется здесь. Если вы также не удалитеиз подписи метода. В этом случае вы просто переопределяете базовый метод. –

+0

@DsCpp Мое предыдущее объяснение было неполным, так как предполагалось, что некоторые более глубокое понимание на вашем уровне. См. редактирование для более четкого объяснения. – CKing

 Смежные вопросы

  • Нет связанных вопросов^_^