Почему вызывается метод, который получает класс Father в качестве параметра, а не метод, который получает дочерний класс в качестве параметра? - PullRequest
0 голосов
/ 06 февраля 2019

У меня есть класс с именем A и класс с именем B, который расширяет A. Играя с некоторыми методами, чтобы понять полиморфное поведение, я столкнулся со странной ситуацией.

public class Main {
    public static void main(String[] args){
        B b = new B();
        A a = b;
        b.f1(a);
    }
}

public class A {
.
.
.
    public void f1(A a){
        if(a instanceof B)
            f1((B)a);
        else
            System.out.println("Nothing");
    }
.
.
.
}

public class B extends A {
.
.
.
    public void f1(B b){
        System.out.println("B::f1(B)");
    }
.
.
.
}

Я ожидал, что f1 в классе Aбыть вызванным первым (потому что тип А), что на самом деле произошло.Тогда я ожидал линию f1 ((B) a);быть вызванным, так как a является экземпляром B. До сих пор все шло как ожидалось.Однако я подумал, что следующий метод, который будет вызван, это f1 (B) в классе B. Вместо этого, f1 (A) в классе A вызывался снова и снова, вызывая исключение переполнения стека.Почему не был назван f1 (B) в классе B?Экземпляр B был вызывающим, и параметр был приведен к типу B.

Ответы [ 3 ]

0 голосов
/ 06 февраля 2019

Ваш класс A не подозревает, что класс B где-то существует и имеет функцию B.f1 (B b).На самом деле f1 (A a) и f1 (B b) - две разные функции.то, что вы, вероятно, хотите достичь, должно быть сделано немного по-другому:

public class A {
//...
    public void f1(A a) {
         System.out.println("Nothing");
    }
//...
}

public class B {
//...
    public void f1(B a) {
        // this is different function, because of another parameters
    }

    public void f1(A a) {
        if(a instanceof B)
            f1((B)a);
        else
            super.f1(a);
    }
//...
}
0 голосов
/ 06 февраля 2019

Код должен вызывать вызывающего метода следующим образом:

public class A {

    public void f1(A a){
        if(a instanceof B)
            ((B) this).f1(a);
        else
            System.out.println("Nothing");
    }
}

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

Если вместо этого вы вызываете вызывающую функцию, вы сообщаете JVM, что вам нравится вызывать метод в подклассе, чтобы вы могли выйти из методанемедленно.

Важно Обратите внимание, что при вызове преобразования в вызывающем объекте в зависимости от параметра может генерироваться исключение преобразования класса, например, в следующем контексте:

    B b = new B();
    A a = new A();
    a.f1(b);

Вы не можете быть уверены, что метод f1, принимающий параметр B, вызывается для объекта B .

0 голосов
/ 06 февраля 2019

f1(A a) - это метод экземпляра класса A.Он не знает методов подклассов A.Следовательно, он не может вызвать void f1(B b) класса B.Следовательно, f1((B)a) снова выполняет void f1(A a).

Если вы хотите вызвать f1(B b), вам придется вызвать f1 для переменной экземпляра класса B:

public void f1(A a){
    if(a instanceof B) {
        B b = (B)a;
        b.f1(b);
    } else {
        System.out.println("Nothing");
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...