Метод вызывает другой метод, который переопределяется, который вызывается в подклассе? - PullRequest
0 голосов
/ 07 ноября 2011

Если у меня есть 2 класса, один из которых является родительским со следующим:

public class Parent {
    ...
    public void method1() {
        method2();
    }

    public void method2() {
    }
}

И затем в подклассе

public class Child extends Parent {
    ...
    public void method2() {
        ...
    }
}

Если я запускаю следующий код:

Child c = new Child();
c.method1();

Какая версия метода2 вызывается?

Ответы [ 5 ]

5 голосов
/ 07 ноября 2011

Все методы являются виртуальными в Java, что означает, что будет вызываться Child.method2 (даже если вызов выполняется из контекста Parent) .

Если корректность Parent.method1 зависит от реализации method2, вы должны разработать ее по-другому:

public class Parent {
    ...
    public void method1() {
        method2impl();
    }

    public void method2() {
        method2impl();
    }

    // make it private or final.
    public final method2impl() {
        ...
    }
}
3 голосов
/ 07 ноября 2011

Как только вы создали объект типа Child, это его тип во время выполнения.Это не изменится, независимо от приведения или того, что вы с ним делаете.Когда вы вызываете метод, будет выполняться реализация этого типа среды выполнения.Если этот тип не имеет собственной реализации, он делегирует родительскому классу.

Даже если вы вызываете method1, который был определен в Parent, как только этот метод вызывает method2это будет разрешать реализацию типа объекта во время выполнения.Если это Child, то это метод класса, который будет вызываться.

Помните, что это динамическое поведение отличается от выбора метода на основе типов параметров, который выполняется статически.Возьмем следующее с вашими определениями классов ...

public void methodTest(Parent p) {} //Let's call this "first method"
public void methodTest(Child c) {} //Let's call this "second method"

Parent p = new Parent();
Child c = new Child();

//Assume a is a variable of some type that implements the above methods
a.methodTest(p); //Will call first method
a.methodTest(c); //Will call second method
a.methodTest((Parent)c); //WILL CALL FIRST METHOD!

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

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

3 голосов
/ 07 ноября 2011
Будет вызван

Child#method2, поскольку он переопределяет родительский.

0 голосов
/ 07 ноября 2011

У меня к вам есть еще несколько вопросов:

public interface CanDoMethod1 {
    public void method1();
}

public class Parent implements CanDoMethod1 {
    public void method1() {
        System.err.println("Parent doing method1");
    }
}

public class Child extends Parent {
    public void method1() {
        System.err.println("Child doing method1");
    }    
}

Теперь вы запускаете следующий код:

CanDoMethod1 instance = new Parent();
instance.method1();

Что выводится?

А когда выrun:

CanDoMethod1 instance = new Child();
instance.method1();

Тогда что это за выход?

А когда вы запустите:

Parent instance = new Child();
instance.method1();

Тогда что за выход?Почему здесь не требуется приведение?

А когда вы запускаете:

Child instance = (Child) new Parent();
instance.method1();

Компилируется ли это?Если это так, то каков результат?

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

0 голосов
/ 07 ноября 2011
public class Parent {
    public void method1() {
        method2();
    }
    public void method2() {
        System.out.println("parent m 2");
    }
}
public class Child extends Parent {
    public void method2(){
        System.out.println("child m 2");
    }
}
public class Main {
    public static void main(String[] args) {
        Child c = new Child();
        c.method1();
        System.out.println("________________");
        c.method2();
    }
}

И на выходе будет:

child m 2
________________
child m 2
...