Приведение потомка к родителю - ошибка времени компиляции из-за отсутствия метода - почему? - PullRequest
1 голос
/ 15 октября 2019

Вот краткий пример приведения дочернего класса к родительскому, а затем вызова метода.

Я ожидал, что метод foo будет вызван в дочернем классе, а не в родительском классе. Но я получаю ошибку компиляции, говорящую, что у родительского класса нет этого метода.

Почему Java заботится о том, есть ли у родительского класса, если я вызываю его только в дочернем классе?

public static void main(String[] args)
{
    A a = new A();
    B b = new B();

    b.foo(1, 2, 3); // Ok

    ((A) b).foo(1, 2); // Also ok. 
                       // Prints "In foo(int, int) method of class B"

    ((A) b).foo(1, 2, 3); // Will not compile

}

// позже в коде ...

class A 
{
    public int foo(int a, int b) 
    {
        System.out.println("In foo(int, int) method of class A");
        return 1;
    }
}

class B extends A 
{

    public int foo(int a, int b) 
    {
        System.out.println("In foo(int, int) method of class B");
        return 0;
    }
    public int foo(int a, int b, int c) 
    {
        System.out.println("In foo(int, int, int) method of class B");
        return -1;
    }
}

Ответы [ 4 ]

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

((A) b) рассматривается как A, хотя foo(int, int) соответствует значению B.

Это означает, что, поскольку ((A) b) известен как A, вы можете тольковызовите методы, которые есть у A.

A имеет только foo(int, int), поэтому вы не можете вызвать foo(int, int, int).

0 голосов
/ 15 октября 2019

((A) b).foo(1, 2); Работает, потому что A имеет метод foo с соответствующей подписью, но вместо этого он выполняет foo B, поскольку во время выполнения jvm может понять, что он работает с экземпляром B. Это недоступно в другом методе.

((A) b).foo(1, 2, 3); 
//is equivalent to
A b1 = new B();
b1.foo(1, 2, 3);

Тип Java статически типизирован, и, насколько видит компилятор, вы пытаетесь вызвать несуществующий метод для типа A и жалоб. Компилятор не знает, какой тип среды выполнения.

0 голосов
/ 15 октября 2019
((A) b).foo(1, 2, 3);

Приведенный выше код может быть визуализирован как:

A a = (A)b;
a.foo(1, 2, 3);

Как вы можете видеть, ссылочная переменная имеет тип 'A', и все разрешения имен методов должны основываться на типе 'А». foo (...) с тремя параметрами (перегруженный метод) не существует в A и поэтому выдает ошибку.

0 голосов
/ 15 октября 2019

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

foo(int a, int b, int c) - это не метод в A. Хотя все методы, которые вы определили, имеют одно и то же имя, они рассматриваются как отдельные методы, потому что у каждого из них разное количество параметров.

Когда вы пытаетесь вызвать ((A) b).foo(1, 2, 3), b обрабатывается какэкземпляр A. Java пытается найти метод с именем foo в A с тремя параметрами , но не может найти его, потому что он не существует.

...