Как полиморфный экземпляр выбирает свои методы? - PullRequest
0 голосов
/ 21 января 2019

У меня проблемы с пониманием поведения этого куска кода.a определяется как A, c определяется как C. Затем в конце открытого класса a = c.Когда вызов вызывает метод display (), он достигает его C-версии.Но когда a вызывает f (), он достигает только версии A, несмотря на то, что первые аргументы (байтовые и длинные) более соответствуют long, чем float.

Это упражнение из книги, но объяснениеявляется недостаточным или не существует.

class A{
    public void display(){
        System.out.println("I am an A ");
    }

    public void f(double x){
        System.out.println("A.f(double = " + x + ") ");
    }
}

class C extends A{
    public void display(){
        System.out.println("I am a C ");}

    public void f(long q){
        System.out.println("C.f(long = " + q + ") ");}
    }


public class PolySurStack{
    public static void main(String Args[]){
        byte bb =1; long q = 4; float x = 5.f;

        System.out.println(" ** A **");
        A a = new A(); a.display();
        a.f(bb); a.f(x);

        System.out.println();
        System.out.println(" ** C **");
        C c = new C(); c.display();
        c.f(bb); c.f(q); c.f(x);
        System.out.println();
        a = c; a.display();
        a.f(bb); a.f(q); a.f(x);
    }
} 

Ответы [ 4 ]

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

Я только что нашел это на другом форуме:

Перегрузка: (одно и то же имя функции, но другая подпись)

  1. Два или более метода с одинаковым именем с разными arugmentв том же классе известен как Перегрузка.

  2. Перегрузка используется, когда вы хотите расширить функциональность.

  3. Перегрузка известна как полиморфизм времени компиляции

Переопределение: (одно и то же имя функции, но одна и та же подпись)

  1. Два или более методов с одинаковым именем метода и одинаковым arugment в родительском классе идочерний класс называется переопределением.

  2. Переопределение используется, когда вы хотите повторно использовать существующий функционал.

  3. Переопределение называется полиморфизмом времени выполнения.

Таким образом, ответ на мой вопрос заключается в том, что переопределение разрешения (например, для display ()) происходит во время выполнения (здесь после a = c) при перегрузке разрешения (например, для f ()) происходит на компевремя, когда а - все еще A.

Я думаю.

Я также нашел эту страницу: https://beginnersbook.com/2013/04/runtime-compile-time-polymorphism/

, чтобы быть ясным и очень актуальным для этой темы.

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

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

A a = new A(); 
a.f(bb); a.f(x);

Для второй серии компилятор связывает методы с наиболее конкретным параметром, соответствующим вызову, поскольку C является A, и поэтому компилятор может связать любые открытые методы из них здесь:

C c = new C(); 
c.f(bb); c.f(q); c.f(x);   

Но в последнем фрагменте кода, который, вероятно, задается вопросом, a ссылается на C как объект времени выполнения, но на A как на объявленный тип:

A a = new A(); 
// ...
a = c; 
a.f(bb); a.f(q); a.f(x);

Таким образом, могут быть вызваны только методы, определенные в A.

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

Я постараюсь немного уточнить ответ @eran, чтобы вы могли его понять.

У подкласса есть все методы своего суперкласса, а затем, возможно, еще несколько в дополнение к ним. У вас есть переменная типа A, в которой вы храните объект типа C. C имеет все методы, определенные в классе A, а также дополнительный метод, f(long q). A не знает об этом новом методе, поэтому, поскольку вы храните объект в переменной A, вы не можете вызвать f(long q).

Вы можете однако вызвать display(), потому что он определен в A, но все равно это будет объект C, который его выполняет.

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

Когда вы вызываете a.f(bb) или a.f(q) или a.f(x), единственные сигнатуры методов, которые может выбрать компилятор, это те, которые определены в классе A (или в любом суперклассе A), поскольку aявляется ссылочной переменной типа A.

Следовательно, рассматривается только public void f(double x).Чтобы public void f(long q) был кандидатом на разрешение перегрузки, вам нужно привести a к типу C перед вызовом f(), поскольку только класс C определяет метод с этой сигнатурой.

Важно понимать, что разрешение перегрузки метода происходит во время компиляции.Только тип времени компиляции ссылочной переменной, для которой вы вызываете метод, определяет, какие сигнатуры методов являются кандидатами для разрешения перегрузки метода, а также какой кандидат будет выбран.

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