2015-11-18 2 views
2

Проблемы с пониманием того, почему выходные данные «3» и «4» для двух вызовов функций. Ибовызов функции полиморфизма Java

g2.foo(t1); 

Во время компиляции, g2 является тип А, он ищет Foo (тип C), что он не находит в своем основном классе, так что он смотрит на ее детей класса В, то С. Поэтому foo (...) следует связывать с

public void foo(C p) { 
    System.out.println("5"); 
} 

является подклассом C справа?

Затем во время выполнения g2 будет иметь тип C и вызывает foo (C p), что приведет к выходу «5». Я не уверен, где моя логика/понимание полиморфизма неверна.

class A { 
    public void foo(A p) { 
     System.out.println("1"); 
    } 
} 

class B extends A { 
    public void foo(B p) { 
     System.out.println("2"); 
    } 
} 

class C extends B { 
    public void foo(A p) { 
     System.out.println("3"); 
    } 

    public void foo(B p) { 
     System.out.println("4"); 
    } 

    public void foo(C p) { 
     System.out.println("5"); 
    } 
} 

public class HelloWorld { 
    public static void main(String[] args) { 
     A g2 = new C(); 
     B r2 = new C(); 
     C t1 = new C(); 

     g2.foo(t1); // 3 

     r2.foo(new C()); // 4 
    } 
} 

ответ

0

Во время компиляции, g2 является тип А, он ищет обув (тип C), который Безразлично» t найти в своем основном классе , поэтому он смотрит на своих детей класса B, затем на C. Поэтому foo (...) следует связывать с ...

Это понимание неверно.

Во время компиляции, так как не foo(C) в типе A, он отмечает, что метод foo(A) будет называться (С A является супертипом C и это самый конкретный метод, который соответствует).

Во время выполнения, C Выполнение определенного метода (foo(A)) вызывается и печатает 3. Аналогично для следующего звонка.

2

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

g2.foo (t1)

g2 имеет тип компиляции A, что означает, может быть выбран только public void foo(A p) во время компиляции. Во время выполнения g2 в экземпляре C, что означает public void foo(A p) из C называется, который печатает 3.

r2.foo (новый C())

r2 имеет тип компиляции B, поэтому во время компиляции можно выбрать либо public void foo(A p), либо public void foo(B p). public void foo(B p) - лучший перегруженный матч (с B более конкретно, чем A). В время выполнения r2 является экземпляром C, так public void foo(B p) из C называется, и печатает 4.

0

Когда вы вызываете g2.Foo (t1) д2 получает тип объекта Compile из А, который означает, что этот метод A, т.е.

public void foo(A p) 

, но на время выполнения g2 является объектом класса C, так общественной пустот Foo (A р) называется

1

Всякий раз, когда функция переопределяется, виртуальная таблица (v-table) производного класса имеет эту функцию, сопоставленную с ее реализацией. Таким образом, вызов функции вызовет реализацию, заданную v-таблицей этого конкретного класса.

В вашем случае A g2 = новый C(); создает экземпляр C и, следовательно, v-таблица будет иметь функцию foo, отображаемую с ее (C) реализацией.

Теперь, когда вызов функции происходит, то есть на g2.foo (t1), реализация класса C будет вызываться по мере ее отображения и, следовательно, 3 будет напечатана.