Method Overriding in Java
Method Overriding
Method overriding can be used when extending a class or implementing an interface. Method overriding is where you provide a different implementation of a method in a subclass that is defined in a superclass. This is shown in the price() method in the following example:
public class PreciousMetal {
public double price() {
return 0;
}
}
public class Gold extends PreciousMetal {
@Override
public double price() {
return 2_011.28;
}
}
public class Silver extends PreciousMetal {
@Override
public int price() {
return 31.01;
}
}
Each of these implementations will produce different values when the price() method is called.
System.out.println(new PreciousMetal().price());
System.out.println(new Gold().price());
System.out.println(new Silver().price());
This will produce the following output:
0
2011.28
31.01
Method overriding is not to be confused with method overloading. Method overloading is where you have the same method name with different parameter types or a different number of parameters.
Covariant Return Type
A covariant return type is a feature that allows for an overridden method to return a different type that what is defined in the superclass. A superclass method signature can have a superclass as the return type, and when a subclass overrides that method, it can provide a subclass of the superclass instead.
public class PreciousMetal {
@Override
public PreciousMetal copy() {
return new PreciousMetal();
}
}
public class Gold extends PreciousMetal {
@Override
public Gold copy() {
return new Gold();
}
}
public class Silver extends PreciousMetal {
@Override
public Silver copy() {
return new Silver();
}
}
In this example, you will notice that the copy() method in PreciousMetal has a return type of PreciousMetal. In each of the subclasses, when copy() is overridden, it returns the subclass instead of PreciousMetal.
You cannot override a method and specify a superclass instead for the return type. It has to be the same type or a subclass of that type, or it will result in a compiler error.
public class FoolsGold extends Gold {
// Compiler Error:
// copy() in FoolsGold cannot override copy() in Gold
// return type PreciousMetal is not compatible with Gold
@Override
public PreciousMetal copy() {
return new FoolsGold();
}
}
When working with primitive types, the return type has to stay the same when overriding a method. When overriding a method that returns void, the overridden method must also return void. This feature is only supported with object types.
@Override Annotation
The @Override annotation is used when overriding a method. Marking a method with @Override, the compiler will ensure that the method is overriding a method in an interface or class. If it isn't overriding anything, it will generate a compiler error.
public class PreciousMetal {
public double price() {
return 0;
}
}
public class Gold extends PreciousMetal {
// Compiler Error:
// Method does not override method from its superclass
@Override
public void printPrice() {
// ...
}
}
Always use the @Override annotation when overriding methods.
Preventing Method Overriding
Sometimes you need to restrict the ability to override a method. You can prevent someone from overriding a method by marking it with the final keyword.
public class Metal {
public final void printPrice() {
// ...
}
}
The printPrice() method in Metal is marked as final. If a subclass tries to override it, it will result in a compiler error.
public class Gold extends Metal {
// Compiler Error:
// printPrice() in Gold cannot override printPrice() in Metal
// overridden method is final.
@Override
public void printPrice() {
}
}
Conclusion
Overriding methods is where you override a method and provide a new implementation of that method in a subclass. It is important to use the @Override annotation so the compiler verifies that the method is actually overridden. Also, when overriding a method that returns an object, you can return a subclass instead.