Какой метод выбран в полиморфизме при вызове метода, доступного в родительском и дочернем классах? - PullRequest
0 голосов
/ 14 января 2019

Я не понимаю, почему метод ab.m3() вызывает функцию родительского класса, а не дочернего. Я подумал, что, возможно, передача нового Integer методу может вызвать метод родительского класса, потому что Integer - это Object, поэтому я попробовал его с int, но все равно он дал мне тот же результат!

public class A {

    public void m1(){
        System.out.println("A.m1");
    }
    public void m2(){
        System.out.println("A.m2");
    }
    public void m3(Object x){
        System.out.println("A.m3");
    }
}

public class B extends A{

    public void m1(){
        System.out.println("B.m1");
    }
    public void m2(int x){
        System.out.println("B.m2");
    }
    public void m3(int x){
        System.out.println("B.m3");
    }

    public static void main(String[] argv){
        A aa = new A();
        A ab = new B();

        int num = 2;

        ab.m1();
        ab.m2();
        ab.m3(new Integer(2));
        ab.m3(num);

    }
}

Выход:

B.m1
A.m2
A.m3
A.m3

Ответы [ 3 ]

0 голосов
/ 14 января 2019

B.m3 не переопределяет A.m3, поскольку списки параметров несовместимы.

Поскольку единственный метод сопоставления в A - это A.m3, а поскольку в B нет переопределения, будет вызван A.m3.

0 голосов
/ 14 июля 2019

Этот пример кода довольно запутан, потому что, хотя цель состоит в том, чтобы продемонстрировать переопределение , он фактически демонстрирует перегрузку .

Поскольку B.m3(int) не соответствует сигнатуре A.m3(Object) (см. JLS 8.4.8.1 ), метод не переопределяется . Вместо этого он перегружен .

Но почему вызов метода с аргументом int не выбирает правильный? В этой упрощенной версии кода:

A ab = new B();
ab.m3(2);

аргумент m3 является int, поэтому похоже, что подпись должна соответствовать B.m3(int). Тем не менее, как правильно указано в вопросе, это A.m3(Object), который называется. Причина в том, что в случаях перегрузки выбор метода основан на статическом типе ссылки на объект , а не на тип времени выполнения, как для переопределения.

Поскольку статический тип ab равен A, алгоритм выбора метода начинает поиск метода m3 в классе A. Единственное, что он находит, это m3(Object), но из-за автобокса аргумент может быть адаптирован для соответствия сигнатуре, поэтому код компилируется.

Так что, если вы измените код и просто объявите ab типа B:

B ab = new B();
ab.m3(2);

тогда, удивительно, это B.m3(int), что называется.

Из-за этой потенциальной глубокой путаницы эту ситуацию следует избегать любой ценой, и для ее помощи доступно множество инструментов и функций. @Override является одним из примеров. Многие IDE также имеют декорации желоба для обозначения переопределения (как показано ниже с зеленым треугольником для Eclipse).

gutter decoration for overriding in Eclipse

0 голосов
/ 14 января 2019

Ваша ссылка ab имеет тип A.

При компиляции ab.m3(num); компилятор не смотрит на тип объекта. В общем, он не всегда будет знать, что это за тип объекта. Вместо этого он смотрит на тип ссылки. Он не может соответствовать B.m3(int), поскольку ссылочный тип не относится к типу B.

Таким образом, компилятор выбирает метод A.m3(Object), который может быть переопределен во время выполнения. Но это не так, поэтому реализация A называется.

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