Почему эта статическая привязка не работает так, как я ожидал? - PullRequest
2 голосов
/ 23 октября 2019

У меня есть вопрос о том, как эта программа выбирает метод.

Код (без конструкторов):

class Father {
   int x;
   ..

   public int m(Father f) {
      return (f.x - this.x);
   }
}

class Son extends Father {
   int y;
   ...

   public int m(Father f) {
       return 100;
   }

   public int m(Son s) {
       return super.m(s) + (s.y - this.y);
   }
}

Main:

Father f1, f2; 
Son s1;
f1 = new Father(3);
f2 = new Son(3,10);
s1 = new Son(4,21);
System.out.println(f1.m(s1) + f2.m(s1)); 

Не знаюне понимаю, почему f2.m(s1) печатает 100. Лично я понял, что если есть 2 метода с одинаковым именем, если есть перегрузка, выбор делается со статическими типами, а при переопределении - с динамическими типами;

f1.m(s1) динамически ищет метод Father.m(Son), но он не существует, и вместо него выбирается Father.m(Father)

f2.m(s1) динамически ищет метод Son.m(Son), который существует и является перегрузкой,поэтому я думаю, что теперь он должен определять приоритеты статических типов и искать метод Father.m(Son), который не существует, но самый близкий - Father.m(Father). Вместо этого выбирается метод Son.m(Father): это метод, который перегружен методом Son.m (Son), но он не выходит из статического поиска, так почему он выбран?

Ответы [ 3 ]

2 голосов
/ 23 октября 2019

f2 является ссылкой типа Father. Даже если объект, на который он ссылается, является Son, компилятор по-прежнему разрешает использовать только те методы, которые существуют в Father, при обращении к ссылке этого типа. Поэтому нет другого выбора, кроме как использовать метод с подписью int m(Father) (так как он единственный в Father). Поскольку Son имеет переопределение для этого метода, это переопределение выполняется.

f2.m (s1) динамически ищет метод Son.m (Son)

Вот где ваша ошибка коренится. Он не ищет метод Son.m(Son), он ищет метод Father.m(Son) и находит метод Father.m(Father). Вызов переопределения происходит на более позднем этапе.

2 голосов
/ 23 октября 2019

f2 объявлен Сыном как Отец, а затем создан. Дело в том, что в классе Father единственный метод m - это метод, который принимает Father в качестве входного параметра. Таким образом, когда вы создаете экземпляр класса f2 классом Son, только int m(Father f) доступен для переопределения. (если речь идет о f2, метод int m(Son f) отсутствует), поэтому f2.m (s1) возвращает 100.

1 голос
/ 23 октября 2019

Давайте проанализируем один за другим.

f2 = new Son(3,10);

Согласно концепции, объект Son будет связан во время выполнения.

Затем вы вызвали

f2.m(s1)

Теперькогда он ищет метод m в объекте Son. Было обнаружено, что их два: 1. m (Отец f) и 2. m (Сын s).

Но ссылка f2 была типа Отца, и только m (Отец f) является общим для Сына и Отцаобъект, следовательно, m (Отец f) объекта Сын будет выбран в кратчайшие сроки для выполнения (короче говоря, m (Сын s) не будет виден с Отцом в качестве ссылки). Вот почему вы видите этот результат.

Вы также можете отлаживать код. Он покажет вам тот же поток выполнения.

...