Master java skills

Method Overriding

Method overriding is a concept where a subclass or a child class has exactly same method as its parent class but its own definition of the same method. In this way, subclass overrides the method definition of parent class.

So, when child class’ object calls the method, it calls the overridden method.

Important points about method overriding

  1. Overriding can happen only between parent and child class.
  2. Method in the parent class and child class must have same name and same number and type of parameters.
  3. Return type should be either exactly same or child classes return type should be the child class of return type of parent class.
  4. If parent class method doesn’t throw an exception, child class method can still throw an exception of runtime exception but it cannot throw a compile time exception.
  5. If parent class method throws an unchecked/runtime exception, child class method may or maynot throw same or any other exception.
  6. If parent class method throws an exception, child class method should also throw either same exception or a child class of that exception.

Example to understand overriding

In the below example, we are going to create four classes.

Player is the parent of all classes.

Cricketer is child class of Player. TennisPlayer is another child class of Player.

PlayerTest is the class with main method. We are going to create object of Player, Cricketer and TennisPlayer classes and call same overridden method play() using the same parent class reference variable.

Now, method of which class will be called is decided depending upon the type of object being created.

Player.java

package com.sks;

public class Player {

	protected String name;
	
	public Player(String name) {
		super();
		this.name = name;
	}

	public void play() {
		System.out.println(name + " plays.");
	}
	
}

Cricketer.java

package com.sks;

public class Cricketer  extends Player {
	
	public Cricketer(String name) {
		super(name);
	}

	public void play() {
		System.out.println(super.name + " plays cricket.");
	}
	
}

TennisPlayer.java

package com.sks;

public class TennisPlayer extends Player {
	
	public TennisPlayer(String name) {
		super(name);
	}

	public void play() {
		System.out.println(super.name + " plays Tennis.");
	}

}

PlayerTest.java

package com.sks;

public class PlayerTest {

	public static void main(String[] args) {
		
		Player p1 = new Player("Geet Sethi");
		p1.play();
		
		Player p2 = new Cricketer("Virat Kohli");
		p2.play();
		
		Player p3 = new TennisPlayer("N Djokovic");
		p3.play();
	}
	
}
Output :
Geet Sethi plays.
Virat Kohli plays cricket.
N Djokovic plays Tennis.

Covariant return type

Overridden methods must have same name and same signature as its parent class’ method. But what about return type? It should either be exactly same as the return type of parent method, or it should be child class of return type of parent class’ method.

For example, if parent class’ method return Player class object, then child class’ overridden method can either return Player object itself, or it can return Cricketer or TennisPlayer object also, since these classes are child classes of Player class.

In the below example, getPlayer() method has been overridden with covariant return type.

package com.javatrainingschool;

public class Player {

	protected String name;
	
	public Player(String name) {
		super();
		this.name = name;
	}

	public Player getPlayer() {
		return this;
	}


	@Override
	public String toString() {
		return "Player [name=" + name + "]";
	}
	
}
package com.javatrainingschool;

public class Cricketer  extends Player {
	
	public Cricketer(String name) {
		super(name);
	}
	
	public Cricketer getPlayer() {
		return this;
	}

	@Override
	public String toString() {
		return "Cricketer [name=" + name + "]";
	}
	
}
package com.javatrainingschool;

public class TennisPlayer extends Player {
	
	public TennisPlayer(String name) {
		super(name);
	}
	
	public TennisPlayer getPlayer() {
		return this;
	}

	@Override
	public String toString() {
		return "TennisPlayer [name=" + name + "]";
	}

}
package com.javatrainingschool;

public class PlayerTest {

	public static void main(String[] args) {
		
		Player p1 = new Player("Geet Sethi");
		p1.getPlayer();
		
		Player p2 = new Cricketer("Virat Kohli");
		p2.getPlayer();
		
		Player p3 = new TennisPlayer("N Djokovic");
		p3.getPlayer();
		
		System.out.println(p1);
		System.out.println(p2);
		System.out.println(p3);
	}
	
}
Output :
Player [name=Geet Sethi]
Cricketer [name=Virat Kohli]
TennisPlayer [name=N Djokovic]

Can static methods be overridden?

No. But why? We know that overriding of methods depends on type of object in working. Now, since static methods are not associated with any object. Rather they are associated with a class, and it doesn’t matter which object is calling them. In fact, they are not called using objects of a class. They are called using class name. That is why they are not overridden.

Now, the question, is what happens if we try to write the same static method as parent class?

It will not give any error. And it is absolutely fine to have exactly similar static methods in both parent and child classes. Since, they are specific to their own classes, they will be accessed using their respective class names.

Method resolution is not a problem here since the methods are accessed using class names.

Method hiding

When we define the same static method in child class same as parent class, there are two copies of the same method, since parent class’ static method is also inherited in the child class. But child class’ static method hides the one that is inherited from the parent class. This is known as method hiding. Let’s see one example

package com.javatrainingschool;

public class Player {

	private static String country = "India";
	
	public static void getPlayerInfo() {
		System.out.println("Player plays for " + country);;
	}
	
}
package com.javatrainingschool;

public class Cricketer  extends Player {
	
	private static String iplTeam = "Mumbai Indians";
	
	public static void getPlayerInfo() {
		System.out.println("Cricketer plays for " + iplTeam);
	}
	
}
package com.javatrainingschool;

public class PlayerTest {

	public static void main(String[] args) {
		
		Player.getPlayerInfo();
		
		Cricketer.getPlayerInfo();
	}
}
Output :
Player plays for India
Cricketer plays for Mumbai Indians

Rules for exceptions in method overriding

There are following rules for exceptions in method overriding.

  1. If parent class method doesn’t throw an exception, child class method can still throw an exception of runtime exception but it cannot throw a compile time exception.
  2. If parent class method throws an unchecked/runtime exception, child class method may or maynot throw same or any other exception.
  3. If parent class method throws a compile time or checked exception, child class method may not throw any exception. But is it needs to throw then it should throw either same exception or a child class of that exception.
package com.javatrainingschool;

public class Player {

	public void getPlayerInfo() throws Exception {
		System.out.println("Player name is " + name);;
	}
	
}
package com.javatrainingschool;

public class Cricketer  extends Player {
	
	public void getPlayerInfo() throws RuntimeException {
		System.out.println("Cricketer name is " + super.name);
	}
	
}

The above example will compile successfully since RuntimeException is a child class of Exception. But vice versa would not be possible.

The below example will give compile time error because Parent class method throws ArithmeticException which is a type of runtime exception, whereas child class method throws IOException which is a type of compile time exception.

package com.javatrainingschool;

public class Calculation {
	
	public void calculate(int a, int b) throws ArithmeticException {
		System.out.println(a/b);
	}

}
package com.javatrainingschool;

import java.io.IOException;

public class Division extends Calculation{
	
	public void calculate(int a, int b) throws IOException { //Exception IOException is not 
                                                                 //compatible with throws clause in
                                                                 //Calculation.calculate(int, int)
		System.out.println(a/b);
	}

}

For more details and examples, follow the below link