Переопределение с помощью объекта или строки в качестве аргумента - PullRequest
0 голосов
/ 17 января 2020

Мы ожидаем "ACBD" для вывода с этим кодом, но мы получаем "ACBB". Почему?

class A{
public void f(Object o){
    System.out.println("A");
}
}
class B{
   public void f(String s){
    System.out.println("B");
}
}
class C extends A{
  public void f(String s){
    System.out.println("C");
}
}
 class D extends B{
  public void f(Object o){
    System.out.println("D");
}
}
public class JavaApplication40 {
  public static void main(String[] args) {
     A a=new C(); a.f("mee");
     C c=new C(); c.f("mee");
     B b=new D(); b.f("mee");
     D d=new D(); d.f("mee");
  }
  }

Я думаю, что должен вызвать f класса A, c должен вызвать f класса C, b должен вызвать f из класса B, d должен вызвать f из класса D. Но похоже, что это изменение с аргументом функции. Почему?

Ответы [ 4 ]

1 голос
/ 17 января 2020

Ваш параметр "mee" ближе к String, чем к Object, и поэтому

public void f(String s){
    System.out.println("B");
}

выбирается из

public void f(Object o){
    System.out.println("D");
}

Если вы ожидаете ACBB, вам нужно определить D как

class D extends B{
  public void f(String s){
    System.out.println("D");
}
1 голос
/ 17 января 2020

Поскольку класс D расширяет класс A, и вы передаете String в качестве параметра, он примет метод с параметром, который соответствует вашему вводу в d.f("mee"), а именно public void f(String s).

С другой стороны, если бы в классе 'D' функция была не public void f(Object o), а public void f(String s), вы бы получили "D" как вывод в журнале.

1 голос
/ 17 января 2020

Существует разница между перегрузкой и переопределением. В вашем коде вы используете методы перегрузки (создавая методы с одинаковыми именами, но разными типами параметров). Перегрузка разрешается компилятором во время компиляции (в отличие от переопределения, которое разрешается во время выполнения).

Для a компилятор видит, что его тип - A, поэтому он выбирает метод A.

Для c компилятор видит, что его типы C, поэтому он выбирает метод с наиболее конкретной c сигнатурой, которая является C методом (String более специфична c, чем Object).

Для b компилятор видит, что его тип - B, поэтому он выбирает метод B.

Для d компилятор видит, что его тип - D, поэтому он выбирает метод с наиболее c подпись, которая является методом B (строка более конкретна c, чем Object).

1 голос
/ 17 января 2020

В Java идентификатор метода связан не только с его именем, но и с его набором параметров. То есть

public void f(Object o)

и

public void f(String s)

являются отдельными методами в D. Java определяет, какой из них выполнять во время выполнения, в зависимости от типа параметра, который вы ему даете. Вы на самом деле не переопределяете никакие методы в этом примере, просто добавляете новые с похожими именами, но разными наборами параметров.

Обратите внимание, что во всех ваших тестовых примерах Java выбирает объект, ближайший к String. Если версия метода принимает String, а другая версия - Object, то выиграет более конкретная c String.

Если вместо этого вы позвоните d.f(a) или любой другой объект, который не является строкой, тогда вы должны увидеть его "D". Аналогично, если вы вызываете b.f(a) с любым аргументом, который не является строкой, он должен вывести "A".

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...