In the Java programming language, both overriding and overloading mean re-using method name, but they are quite different. This article provides some comparisons between these two techniques. For details about each, see the following articles:
For the comparison, the following table gives us the similarities and differences between overriding and overloading methods:
Overriding methods | Overloading methods | |
Usage context | A subclass re-implements methods inherited from a superclass. | Provide multiple versions of a method with different signatures. |
Method name | Must be the same. | |
Arguments list | Must be the same. | Must change the arguments lists. |
Return type | Must have the same return type, | May have different return types. |
throws clause | Must not throw new or broader checked exceptions. | May throw different exceptions. |
Access modifiers | Must not have more restrictive access modifiers. | May have different access modifiers. |
Method invocation resolution | Which method to invoke is decided at runtime. | Which method to invoke is decided at compile time. |
Constructors | Cannot be overridden. | Can be overloaded. |
Allowed methods | Only inherited methods can be overridden. | No restriction. |
Disallowed methods | Static and final methods cannot be overridden. | No restriction. |
From the above table, we can see that the rules of overriding are more restrictive than overloading. Let’s see some examples. Suppose that we have this superclass - Animal:
public class Animal { protected void eat() { System.out.println("Animal eats"); } }
And a subclass - Dog:
public class Dog extends Animal { public Dog() { System.out.println("I am a general dog"); } public Dog(String breed) { System.out.println("I am a dog of this kind: " + breed); } @Override public void eat() { System.out.println("Dog eats default food"); } public void eat(String food) { System.out.println("Dog eats this food: " + food); } }
Here, the Dog class has two overloaded constructors:
The Dog class also has two versions of eat() method which are both overriding and overloading, because:
Here is the testing code:
Animal anim = new Dog(); anim.eat(); Dog bulldog = new Dog("Bulldog"); bulldog.eat("Bones");
Output:
I am a general dog Dog eats default food I am a dog of this kind: Bulldog Dog eats this food: Bones
Here, two overloaded constructors are invoked to create two different instances of the Dog class:
Animal anim = new Dog(); Dog bulldog = new Dog("Bulldog");
Consider the following statements:
Animal anim = new Dog(); anim.eat();
Here, we can see that which method to be invoked is decided at runtime, based on the actual object. The anim reference variable is of type Animal, but it points to the actual object Dog, thus the overriding version of eat() method in the Dog class is invoked:
Dog eats default food
Consider the following class:
public class AnimalRanch { public void raise(Animal anim) { System.out.println("Raises an animal"); } public void raise(Dog dog) { System.out.println("Raises a dog"); } }
Here, the AnimalRanch class has two overloaded methods raise(), the first accepts an Animal and the second accepts a Dog. Now let’s see the following code:
AnimalRanch ranch = new AnimalRanch(); Animal anim = new Dog(); Dog bull = new Dog("Bull"); ranch.raise(anim); ranch.raise(bull);
Guess which raise() method will be called? Well, because overloaded methods are decided at compile time, so the call ranch.raise(anim) will invoke the raise(Animal) method as the anim reference variable is declared as Animal, though its actual object type is Dog. The second call, ranch.raise(bull) will invoke the raise(Dog) method because the bull reference variable is declared as Dog. Thus the following output:
I am a general dog I am a dog of this kind: Bull Raises an animal Raises a dog