OCA Java SE 8 Class Design - Java Override Method








Overriding a Method

What if there is a method defined in both the parent and child class?

You can override a method a method by declaring a new method with the signature and return type as the method in the parent class.

When you override a method, you may reference the parent version of the method using the super keyword.

The keywords this and super allow you to select between the current and parent version of a method, respectively.

class Shape { 
  public double getSize() { 
    return 50; 
  } 
} 

class Rectangle extends Shape { 
  public double getSize() { 
    return super.getSize()+20; 
  } 
  public static void main(String[] args) { 
    System.out.println(new Shape().getSize()); 
    System.out.println(new Rectangle().getSize()); 
  } 
} 

what would the following code output if we removed the super keyword in the getSize() method of the Rectangle class?

public double getSize() { 
  return getSize()+20;  // INFINITE LOOP 
} 

The compiler performs the following checks when you override a nonprivate method:

The method from child class must have the same signature as the method in the parent class.

The method from child class must be at least as accessible or more accessible than the method in the parent class.

The method from child class may not throw a checked exception that is new or broader than the class of any exception thrown from the parent class method.

If the method returns a value, it must be the same or a subclass of the method in the parent class.





Overloading vs. Overriding

Overloading a method and overriding a method both involve redefining a method using the same name.

An overloaded method will use a different signature than an overridden method.

For example, take a look at the following code sample:

class Shape { 

  public void enlarge() { 
    System.out.println("Shape is enlarging"); 
  } 
  public void shrink(int f) { 
    System.out.println("Shape is shrinking "+f); 
  } 
} 

class Rectangle extends Shape { 
  public int enlarge(int height) { 
    System.out.println("Shape is enlarging at "+height+" meters"); 
    return height; 
  } 
  public int shrink(int f) { // DOES NOT COMPILE 
    System.out.println("Shape is shrinking "+food); 
    return food; 
  } 
} 

The first method, enlarge(), is overloaded in the subclass Rectangle, since the signature changes from a no-argument constructor to a constructor with one int argument.

Because the method is being overloaded and not overridden, the return type can be changed from void to int without issue.

The second method, shrink(), is overridden in the subclass Rectangle, since the signature is the same as it is in the parent class Shape-they both take a single argument int.

Because the method is being overridden, the return type of the method in Rectangle must be a subclass of the return type of the method in Shape.

In the code above he return type void is not a subclass of int; therefore, the compiler will throw an exception on this method definition.

The following code does not compile.

class Shape { 
  protected String getEdge() { 
    return "Undefined"; 
  } 
} 

class Rectangle extends Shape { 
  private int getEdge() {  // DOES NOT COMPILE 
    return 2; 
  } 
} 

The child method must be at least as accessible as the parent. In the example, the parent method uses the protected modifier, but the child method uses the private modifier, making it less accessible.

The return type of the parent method and child method must be covariant. In this example, the return type of the parent method is String, whereas the return type of the child method is int, neither of which is covariant with each other.





Example

Let's take a look at some example methods that use exceptions:

class MyException extends Exception {} 

class Shape { 
  protected boolean hasBorder() throws MyException { 
    throw new MyException(); 
  } 
  protected double getSize() throws Exception { 
    return 2; 
  } 
} 

class Rectangle extends Shape { 
  protected boolean hasBorder() { 
    return false; 
  } 
  protected double getSize() throws MyException{ 
    return 2; 
  } 
} 

In this example, both parent and child classes define two methods, hasBorder() and getSize().

The first method, hasBorder(), throws an exception MyException in the parent class but doesn't throw an exception in the child class.

This does not violate the third rule of overriding methods.

In other words, a child method may hide or eliminate a parent method's exception without issue.

getSize() throws Exception in the parent class and MyException in the child class.

This is permitted, as MyException is a subclass of Exception by construction.

Example 2

The following code would not compile.

class MyException extends Exception {} 

class Shape { 
  protected double getHeight() throws MyException { 
    return 2; 
  } 
  protected int getLength() { 
    return 10; 
  } 
} 

class Rectangle extends Shape { 
  protected double getHeight() throws Exception {  // DOES NOT COMPILE 
    return 2; 
  } 
  protected int getLength() throws MyException { // DOES NOT COMPILE 
    return 10; 
  } 
} 

getHeight() in the parent class throws an MyException, whereas the method in the child class throws an Exception.

Since Exception is not a subclass of MyException.

getLength() method doesn't throw an exception in the parent class, but it does throw an exception, MyException, in the child class.

The child class defines a new exception that the parent class did not, which is a violation of the third rule of overriding methods.

Redeclaring private Methods

Java is not possible to override a private method in a parent class since the parent method is not accessible from the child class.

Java can redeclare a new method in the child class with the same or modified signature as the method in the parent class.

This method in the child class is a separate and independent method, unrelated to the parent version's method.

For example, let's return to the Shape example we used in the previous section and show two related classes that define the same method:

class Shape { 
  private String getEdges() { 
    return "Undefined"; 
  } 
} 

class Rectangle extends Shape { 
  private int getEdges() { 
    return 2; 
  } 
} 

This code compiles without issue.

The return type differs in the child method from String to int.

getEdges() in the parent class is hidden, so the method in the child class is a new method and not an override of the method in the parent class.

If the method in the parent class were public or protected, the method in the child class would not compile since it would violate two rules of overriding methods.

The parent method in this example is private, so there are no such issues.