Java: рекурсия внутри основного класса вызывает метод subclass вместо своего собственного метода

Пример:

class MainClass {
    public doIt() {
        ...
        else doIt();
    }
}

class SubClass extends MainClass {
    @Override
    public doIt() {
        super.doIt();
        ...
    }
}

Теперь проблема заключается в следующем:

  • Я вызываю SubClass.doIt ()
  • MainClass.doIt() вызывается
  • MainClass.doIt() делает рекурсию, вызывая doIt ()
    Но: SubClass.doIt () вызывается вместо MainClass.doIt()

Это очень странное поведение и проблемы запрограммированы! Я пытался вызвать рекурсию с помощью this.doIt (), но это не помогло. У кого-то есть идея?

Большое спасибо за ваши ответы, эта проблема решена.

2 ответа

Решение

Это предполагаемое поведение, не устанавливая метод finalэто означает, что это может быть overrideп, так что вы всегда должны учитывать, что кто-то может сделать это. Призывы к этому методу никогда не гарантированно относятся к методу на этом уровне.

Однако вы можете решить эту проблему элегантно, используя (protected) final метод:

class MainClass {

    protected final void innerDoIt () { //final: so no @Override
        ...
        else innerDoIt();
    }

    public void doIt() {
        innerDoIt();
    }

}

А потом:

class SubClass extends MainClass {

    @Override
    public doIt() {
        super.doIt();
        ...
    }
}

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

Так что, если вы не хотите, чтобы вызывающий абонент был переопределен, просто хеджируйте его в другой final метод. Делая это protectedэтот метод также может быть вызван SubClass,

public class Main {

    public static void main(String[] args) {
        B b = new B();
        b.doIt();
        System.out.println();
        A a = new B();
        a.doIt();
    }


    public static class A{
        boolean check=false;
        public void doIt(){
            System.out.println("A start");
            if(check){

            }
            else{
                check = true;
                doIt();
            }
            System.out.println("A end");
        }
    }
    public static class B extends A{
        @Override
        public void doIt() {
            System.out.println("B start");
            super.doIt();
            System.out.println("B end");
        }
    }
}

В этом примере оба b а также a являются экземплярами класса Bтак что, как вы, вероятно, ожидаете, a.doIt() и b.doIt() будут выводить один и тот же результат.

B start
A start
B start
A start
A end
B end
A end
B end

B start
A start
B start
A start
A end
B end
A end
B end

Когда вы звоните doIt()Вы неявно звоните this.doIt(), а также this это экземпляр класса B, Там нет синтаксиса, чтобы делать то, что вы хотите сделать, не разделяя содержимое doIt() (см. ответ CommuSoft)

Другие вопросы по тегам