Bits of Java – Episode 16: Method overriding vs method hiding
Last week we started looking into the difference between method overriding and method overloading. This episode will cover, instead, the difference between method overriding and method hiding.
We will not go into all the technical details of method overriding, since we already discussed them. What’s important to remember from last time is that one of the rules about method overriding stated that you cannot override a static
method. Indeed, static
methods can only be hidden.
But, what exactly does it mean for a method to be hidden? Well, as for overriding, you can hide a method which your class inherits from one of its super classes or from one of its interfaces. If the method in question is static
you can implement your own version, through method hiding, following all the rules we have learned about method overriding, so:
- The hiding version of the method must have the same signature of its original version (same name and same parameter list);
- The hiding version of the method must have the same or a more permissive access modifier with respect to its original version;
- The hiding version of the method must have the same or a less broader list of declared checked Exceptions with respect to its original version;
- The hiding version of the method must have the same or a covariant return type with respect to its original version.
In addition to these rules, since hiding is possible only for static
method, also the “new” version of the method must be static
. Let’s look at some examples.
class ParentClass {
protected static void myMethod(String name) {
System.out.println("Hi " + name);
}
}
public class ChildClass extends ParentClass{
public static void myMethod(String name) {
System.out.println("Hola " + name);
}
}
n the previous example, ChildClass
extends ParentClass
, and so it inherits all the visible methods of its parent. Among them there is the static
method myMethod
. In ChildClass
we hide the parent version of such method, by providing our own implementation. This is a valid implementation, since the signature is the same, the return type is also the same, the access modifier is different but more permissive with respect to the original version, and we kept the static
specifier.
Let’s now look at some invalid examples.
class ParentClass {
protected static void myMethod(String name) {
System.out.println("Hi " + name);
}
}
class ChildClass1 extends ParentClass{
/*
* NOT VALID: access modifier is the default one, so Package-Private,
* which is more restrictive than protected
*/
static void myMethod(String name) {
System.out.println("Hola " + name);
}
}
class ChildClass2 extends ParentClass{
/*
* NOT VALID: return type is not the same, nor a covariant type
*/
public static String myMethod(String name) {
String msg = "Hola " + name;
System.out.println(msg);
return msg;
}
}
class ChildClass3 extends ParentClass{
/*
* NOT VALID: signature is not the same because the parameter list
* is now an array of String instead of just a String
*/
public static void myMethod(String[] names) {
System.out.println("Hola " + name);
}
}
class ChildClass4 extends ParentClass{
/*
* NOT VALID: the static specifier is missing
*/
public void myMethod(String[] names) {
System.out.println("Hola " + name);
}
}
OK, so now we know how to properly hide a parent static
method. If some of you followed our last post, you could ask at this point what is the difference then between overriding and hiding, a part from the fact that one is applied to non-static methods and one to static
ones.
Well, the difference is precisely that! But is not just a difference in the definition; the static
keyword is what makes the difference in how an hiding method behaves with respect to an overriding one. Let’s try to explain it!
When we talked about the static
keyword in episode 14, we started our discussion by saying that static
means something which is referred to the class, and not to every instance of the class. Indeed, a static
class variable is a variable which is shared among all the instances of that class.
When we introduced method overriding we said that once you have your own version of a parent method in a sub class, if you call that method through an instance of the subclass the overridden version is actually called.
class ParentClass {
protected void printMessage(String name) {
System.out.println("Hi " + name);
}
}
public class ChildClass extends ParentClass {
public void printMessage(String name) {
System.out.println("Hola " + name);
}
public static void main(String[] args) {
ChildClass child = new ChildClass();
child.printMessage("Ilenia"); //prints "Hola Ilenia"
}
}
Then, what happens when you call printMessage
, for instance, inside another inherited method that you chose not to override?
class ParentClass {
protected void printMessage(String name) {
System.out.println("Hi " + name);
}
public void printAnotherMessage(String name) {
printMessage(name);
System.out.println("How are you?");
}
}
public class ChildClass extends ParentClass {
public void printMessage(String name) {
System.out.println("Hola " + name);
}
public static void main(String[] args) {
ChildClass child = new ChildClass();
child.printAnotherMessage("Ilenia"); //prints "Hola Ilenia \nHow are you?"
}
}
Let’s look at this example. In our sub class ChildClass
we override the printMessage
method, but we kept the parent version of printAnotherMessage
. In this method, however, there is a call to printMessage
. When we call printAnotherMessage
from an instance of ChildClass
it enters the parent version (the only one we have) of printAnotherMessage
, but then it calls the ChildClass
version of printMessage
.
So, here is the key point. An overridden version of a method substitute the parent version at runtime, even if the method is called inside the parent class itself!
Let’s now look at a similar example, but with method hiding.
class ParentClass {
protected static void printMessage(String name) {
System.out.println("Hi " + name);
}
public static void printAnotherMessage(String name) {
printMessage(name);
System.out.println("How are you?");
}
}
public class ChildClass extends ParentClass {
public static void printMessage(String name) {
System.out.println("Hola " + name);
}
public static void main(String[] args) {
ChildClass.printMessage("Ilenia"); //prints "Hola Ilenia"
ChildClass.printAnotherMessage("Ilenia"); //prints "Hi Ilenia \nHow are you?"
}
}
Now the two methods in the parent class are static
and we are hiding just one of them, printMessage
, as we did before. In the main
we are calling first ChildClass.printMessage
. This realizes that in our subclass ChildClass
we have a new version for it, and thus it calls that one, printing "Hola Ilenia"
. Then, we call ChildClass.printAnotherMessage
, which then needs to rely on the parent class implementation, since we do not have one in ChildClass
. In printAnotherMessage
there is a call to printMessage
, exactly as before, but this time the method was just hidden in the sub class, not overridden, meaning that from the parent class we will call the parent class version of the method, resulting in printing "Hi Ilenia"
, and not "Hola Ilenia"
!
So, here is the big difference! At runtime, an overridden version of a method will substitute the parent version also in the parent class, while for an hiding method this is not the case! In this sense hiding is weaker than overriding, because if you end up in the parent class implementation and from this you need to call a static
method, it does not matter if you had hidden it in your sub class. You are now in the parent one, and so the parent version will be called. When you have a non-static method and you override it, instead, even if you end up in the parent implementation, it will always remember where you started from and that you had provided a different implementation for the method, and so the sub class version will be called!
This was all about method overriding vs method hiding. Next week we will talk about modules in Java!
by Ilenia Salvadori