Friday, 11 October 2013

Overriding Methods in Java - How it works?

Background


Method overloading and method overriding are two important concepts in Java. It is very crucial to know the way they are work and the way they are used.

The main motive of this post is to understand Method overriding and it's usage. Lets quickly understand what both terms mean and move on to the overriding part for details.


Method Overloading

Method or Function overloading means two or more functions with same name but different number and type of arguments(Signature). The purpose of this is to provide common functionality but in different possible scenarios. Example -

public void setEmployeeInfo(String name);
public void setEmployeeInfo(String name, int age);
public void  setEmployeeInfo(String name, int age, String id);


Name of the function remains the same but the number and type of arguments changes.

Note : return type has noting to do with overloading. In fact return type of a method is not a part of it's signature. Only the function name and the arguments form a part of method signature. Also as we know that two methods with same signature are not allowed following scenario is not allowed -

public String getEmployee(String name);
public Employee getEmployee(String name);



Note :  Also keep in mind method overloading is a compile time phenomenon. Which if the overloaded method is to be executed is decided at compile time based the method signature.

Method overloading has some resolution rules that decides which method to pick up at compile time. Compilation will fail if no methods are matched. For example consider following methods -

  • public void getData(String dataName)
  • public void getData(Object dataName)
Now what happens when you call getData("employeeName"). The one with String argument will be chosen because it is more specific. Anyway that was just a simple example. Things can be more complicated. Refer to following post to see the rules java applies for this resolution -

Method Overriding

Method overriding comes into picture only when there is inheritance involved. If there is a method in a super class then a sub class can override it. Let us first see an example and then dive into various aspects of it.
Lets say we have a Animal class in a package called worldEnteties. It has  a move method as follows.

package worldEnteties;



public class Animal {
    
    public void move() {
        System.out.println("Animal is moving");
    }
}

Also we have a Dog class which extends this Animal class. In this Dog class we override the move() method to do some different movement(Dog specific).

package worldEnteties;

public class Dog extends Animal {
   
    @Override
    public void move(){
        System.out.println("Dog is moving");        
    }
}

Now when you create a normal Animal object and call move() on it, it will simply execute the function in Animal class.

Code : 

    public static void main(String args[]) {       
        Animal animal = new Animal();
        animal.move();
    }

Output :
Animal is moving

Now when we create a Dog object and call move() on it, it will execute the corresponding move() function.

Code : 

    public static void main(String args[]) {      
        Dog dog = new Dog();
        dog.move();
    }
Output :
Dog is moving

 Now the question may arise -
Q ) What if I wast to invoke move() in Animal when move() in Dog is invoked? After all Dog is an Animal. 

Ans ) The answer is you can call super.move() inside the overridden function to call corresponding function in the superclass. Yes it happens by default in constructors but in normal functions you have to explicitly invoke super.functionName() call. A sample code would be as follows - 

Modify the overridden move() method in Dog class as follows

 package worldEnteties;

public class Dog extends Animal {
    
    @Override
    public void move(){
        super.move();
        System.out.println("Dog is moving");        
    }
}

Now execute the following code and examine the results -

Code :

    public static void main(String args[]) {        
        Dog dog = new Dog();
        dog.move();
    }
Output :
Animal is moving
Dog is moving
 

Method Overriding is a runtime phenomenon!!!!

  So far so good!! Now lets involve polymorphism in it and lets see what makes method overriding a runtime phenomenon.[Always remember polymorphism as superclass reference to subclass object] Consider the following code(No super call just plain simple inheritance and explained in the 1st case above) - 
code :
    public static void main(String args[]) {        
        Animal dog = new Dog();
        dog.move();
    } 

Output:
Dog is moving

How it works?

At compile time all that java compiler knows is the reference type Animal in our case. All compiler does is check whether move() method is present(or at-least declared) in the Animal class(If not compilation error will occur). As in our case it is present and code compiles fine. Now When we run the code, it is at this time the JVM will know the runtime class of the object [You can also print it using dog.getClass()] which is class Dog in our case. Now JVM will execute the function in Dog and we get our output.

Code Snap :

 

Another important point to note is that the access modifier of the overriding function can be liberal! Meaning if access modifier of super class is private than modifier of overriding method is subclass can be default(no modifier), protected or public. It cannot be the other way around(overriding method cannot have more strict access modifier).

Note : Access to static/instance fields and static methods depend on class of the polymorphic reference variable and not the actual object to which reference point to. Also variables are never overridden. They are shadowed.

So if you have

public class A {
    public static String test = "testA";
    public static void test() {
        System.out.println(test);
    }
}


and

public class B extends A {
    public static String test = "testB";
    public static void test() {
        System.out.println(test);
    }
}


and you run

public class Test {
    public static void main(String args[]) {
        A a  = new B();
        a.test();
    }
}


it will print testA

Note : In method overridden return type can be same or subclass of the super class method. Same goes for Exception thrown. Exception thrown by the overridden method can be same or subclass of Exception thrown by method in the super class. However the access modifies for the overridden method should be more strict. (See Rules below)

Rules for method overriding


For overriding, the overridden method has a few rules:
  1. The access modifier must be the same or more accessible.
  2. The return type must be the same or a more restrictive type, also known as covariant return types.
  3. If any checked exceptions are thrown, only the same exceptions or subclasses of those
    exceptions are allowed to be thrown.
  4. The methods must not be static. (If they are, the method is hidden and not
    overridden.)

Related Links


No comments:

Post a comment

t> UA-39527780-1 back to top