As per the rule, while overriding a method in subclass, parameters cannot be changed and have to be the same as in the super class. What if we pass subclass of parameter while overriding method ? Will it be called as overloading or overriding?
Based on my query I have written some code below.
I was expecting the output as "Dog eats Flesh Food" but to my surprise the output is "Animal eats Flesh Food"
Will appreciate if someone can explain how does Animal method gets called when the object assigned is of type Dog ?
class Food {
public String toString(){
return "Normal Food";
}
}
class Flesh extends Food {
public String toString(){
return "Flesh Food";
}
}
class Animal {
public void eat(Food food){
System.out.println("Animal eats "+ food);
}
}
class Dog extends Animal{
public void eat(Flesh flesh){
System.out.println("Dog eats "+ flesh);
}
}
public class MyUtil {
public static void main(String[] args) {
Animal animal = new Dog();
Flesh flesh = new Flesh();
animal.eat(flesh);
}
}
The method
eat
inDog
does not override the methodeat
inAnimal
. This is because the arguments are different (one requiresFlesh
, the other requiresFood
).The
eat
methods are overloads.Choosing between overloads takes place at compile time, not runtime. It is not based on the actual class of the object on which the method is invoked, but the compile-time type (how the variable is declared).
animal
has compile-time typeAnimal
. We know this because the declaration of the variableanimal
wasAnimal animal = ...
. The fact that it is actually aDog
is irrelevant - it is the version ofeat
inAnimal
that must be invoked.On the other hand, the
toString
method inFlesh
does override thetoString
method inFood
.When one method overrides another it is the actual class of the object that the method is invoked on that determines which version runs.
In the
eat
method ofAnimal
, even though the argument has compile-time typeFood
, if you pass an instance ofFlesh
to it, it is thetoString
method inFlesh
that will execute.Therefore you get the message
"Animal eats Flesh Food"
.When you do this:
Animal animal = new Dog();
it's upcasting.And you do not override the method
so it calls the method
eat(Food food)
ofAnimal
You can use the
@override
annotation to inform the compiler that you are trying to override a method within the superclass.e.g.
In your code, now the compiler will generate an error, because this method does not override
eat
, you need to have the same parameter type.However, changing the
Flesh
parameter toFood
type will resolve the problem:Now you can do the following:
In java, Can we override a method by passing subclass of the parameter used in super class method?
NO.
Explanation with example :
Assume we can override a method by passing subclass of the parameter used in super class method.
But think what happens during runtime ?
During runtime, method is called on the actual object to which reference is pointing to. In our case it is pointing to class B. So JVM will look into class B for method execution and it would be a great shock to JVM because class B does not have a overriden method with signature public void print(Integer in) and it will fail at runtime.
The consequence of this is application will crash at runtime rather than compile time.
Overriding rules in Java :
=============================
In your example what happens is :
During compile time : compiler makes sure that eat method can be called on reference type(which is Aniaml class). Since Animal class has a method public void eat(Food food) which can take any Food type and subclass of Food type as input parameter(polymorphism), compilation passes.
In general, compiler guarantees that particular method is callable for a specific reference type.
During run time : Actual method called is, most specific version of the method for that object type(Dog class).Since JVM is not able to find the overriden method i.e with the same method name and same argument type declared in sub class (Dog class), it checks its superclass(Animal class) and finds the method and executes.
public void eat(Food food) and public void eat(Flesh flesh) are not same from the perspective of overriding methods.
In general, when you call a method on an object reference, you're calling the most specific version of the method for that object type during runtime. But if it doesn't find one it will go up the hierarchy.Worst case Super class will definitely have the method implementation otherwise compilation wont pass.
No, we can not in this case you can check it by adding @Override above the eat method in Dog class so compilation error will appear like this :
Make sure that in override the parameters should be as parent class in type and order.