Inheritance and Recursion

Suppose we have the following classes:

class A { void recursive(int i) { System.out.println("A.recursive(" + i + ")"); if (i > 0) { recursive(i - 1); } } } class B extends A { void recursive(int i) { System.out.println("B.recursive(" + i + ")"); super.recursive(i + 1); } } 

Now call recursive in class A:

 public class Demo { public static void main(String[] args) { A a = new A(); a.recursive(10); } } 

The output is expected to be reckoned with 10.

 A.recursive(10) A.recursive(9) A.recursive(8) A.recursive(7) A.recursive(6) A.recursive(5) A.recursive(4) A.recursive(3) A.recursive(2) A.recursive(1) A.recursive(0) 

Let's move on to the confusing part. Now we call recursive in class B.

Expected

 B.recursive(10) A.recursive(11) A.recursive(10) A.recursive(9) A.recursive(8) A.recursive(7) A.recursive(6) A.recursive(5) A.recursive(4) A.recursive(3) A.recursive(2) A.recursive(1) A.recursive(0) 

Actual

 B.recursive(10) A.recursive(11) B.recursive(10) A.recursive(11) B.recursive(10) A.recursive(11) B.recursive(10) ..infinite loop... 

How does this happen? I know this is an invented example, but it makes me wonder.

Old question with specific use case .

+83
java inheritance recursion
Dec 30 '15 at 14:11
source share
6 answers

Expected. This is what happens for instance B

 class A { void recursive(int i) { // <-- 3. this gets called System.out.println("A.recursive(" + i + ")"); if (i > 0) { recursive(i - 1); // <-- 4. this calls the overriden "recursive" method in class B, going back to 1. } } } class B extends A { void recursive(int i) { // <-- 1. this gets called System.out.println("B.recursive(" + i + ")"); super.recursive(i + 1); // <-- 2. this calls the "recursive" method of the parent class } } 

Thus, calls alternate between A and B

This does not happen with instance A , because the overriden method will not be called.

+74
Dec 30 '15 at 14:14
source share

Because recursive(i - 1); in A refers to this.recursive(i - 1); which is B#recursive in the second case. Thus, super and this will be called in a recursive function alternatively.

 void recursive(int i) { System.out.println("B.recursive(" + i + ")"); super.recursive(i + 1);//Method of A will be called } 

in a

 void recursive(int i) { System.out.println("A.recursive(" + i + ")"); if (i > 0) { this.recursive(i - 1);// call B#recursive } } 
+29
Dec 30 '15 at 14:14
source share

In other answers, everyone explained the essential point: after the instance method is overridden, it remains overridden and does not return, except through super . B.recursive() calls A.recursive() . A.recursive() then calls recursive() , which allows overriding in B And we ping pong back and forth to the end of the universe or StackOverflowError , whichever comes first.

It would be nice if you could write this.recursive(i-1) in A to get your own implementation, but it would probably break things and bring other unfortunate consequences, so this.recursive(i-1) in A calls B.recursive() and so on.

There is a way to get the expected behavior, but this requires foresight. In other words, you must know in advance that you want super.recursive() in subtype A to fall into a trap, so to speak, in implementation A This is done like this:

 class A { void recursive(int i) { doRecursive(i); } private void doRecursive(int i) { System.out.println("A.recursive(" + i + ")"); if (i > 0) { doRecursive(i - 1); } } } class B extends A { void recursive(int i) { System.out.println("B.recursive(" + i + ")"); super.recursive(i + 1); } } 

Since A.recursive() calls doRecursive() and doRecursive() can never be overridden, A guaranteed to call its own logic.

+27
Dec 30 '15 at 2:54
source share

super.recursive(i + 1); in class B explicitly calls the superclass method, so the recursive from A is called once.

Then recursive(i - 1); in class A, it will call the recursive method in class B , which overrides the recursive class A because it runs on an instance of class B

Then B recursive will explicitly call A recursive , etc.

+16
Dec 30 '15 at 14:13
source share

It cannot go otherwise.

When you call B.recursive(10); then it prints B.recursive(10) and then calls the implementation of this method in A using i+1 .

So, you call A.recursive(11) , which prints A.recursive(11) , which calls the recursive(i-1); method recursive(i-1); for the current instance, which is B with the input parameter i-1 , so it calls B.recursive(10) , which then calls super with i+1 , which is 11 , which then recursively calls the current instance, recursive with i-1 , which is 10 , and you get the loop that you see here.

This is all because if you call the instance method in the superclass, you will still call the implementation of the instance on which you are calling it.

Imagine,

  public abstract class Animal { public Animal() { makeSound(); } public abstract void makeSound(); } public class Dog extends Animal { public Dog() { super(); //implicitly called } @Override public void makeSound() { System.out.println("BARK"); } } public class Main { public static void main(String[] args) { Dog dog = new Dog(); } } 

You will get a "BARK" instead of a compilation error, such as an "abstract method cannot be called on this instance" or an AbstractMethodError runtime error or even a pure virtual method call or something like that. So, this is all to support polymorphism .

+16
Dec 30 '15 at 14:24
source share

When method B a recursive instance calls the implementation of the super class, the executable instance still has the value B Therefore, when a superclass implementation calls recursive without additional qualifications, it is a subclass implementation. The result is the endless cycle that you see.

+14
Dec 30 '15 at 14:15
source share



All Articles