Nain Nain - 2 months ago 8
Java Question

Output in case of chaining inheritance

class Monster {
boolean frighten(int x) {
System.out.println("Monster");
return true;
}
}

class Vampire extends Monster {
boolean frighten(byte x) {
System.out.println("Vampire");
return true;
}
}

class Dragon extends Monster {
boolean frighten(int x) {
System.out.println("Dragon");
return true;
}
}


class Sample {
public static void main(String s[]) {
Monster[] inst = new Monster[3];
inst[0] = new Monster();
inst[1] = new Vampire();
inst[2] = new Dragon();

for (int i = 0; i < 3; i++) {
inst[i].frighten(i);
}
}
}


When I run the above code with
x
as
int
in
Monster
or
Dragon
class, the code works fine in the way I expect. However, when I run the code by changing the type of
x
from
int
to
long
either in
Monster
or
Dragon
classes, it prints the following:

Monster
Monster
Monster


Can someone explain the logic behind the output?

Answer

When you write

inst[i].frighten(i);

Because inst[i] is of type Monster, the compiler has to find a frighten method on the Monster class which matches the parameter - in the case of your actual code here, it is frighten(int).

It invokes this method on all of the instances of Monster that you pass it - it doesn't matter what the class is at runtime, the method is chosen at compile time.

What this means is that the Vampire.frighten(byte) method is never invoked - it is an overload, rather than an override, because the signatures frighten(int) and frighten(byte) do not match.

If you change the parameter of the frighten method to long on Monster, the compiler can only pick from methods defined on Monster, so the only method it knows it can safely invoke on all instances is frighten(long): neither of the subclasses overrides this method - so the behaviour is that of the base class.

If you change the parameter of the frighten method to long on Dragon, it no longer overrides the method in the base class - so the behaviour is that of the base class.

The way to stop this "unexpected" behaviour is to always add @Override to methods that you think override methods in the base class. The compiler will complain if methods with that annotation do not actually override a method on the base class.