105. Final Classes and Methods
A class marked with the final modifier cannot be extended (subclassed) by another class. In the example below we draw a line at SuperHero and the attempt to create a SuperSuperHero will cause a compilation error:
final cannot be extendedclass Person {
//...
}
final class SuperHero extends Person {
//...
}
//This isn't allowed as SuperHero is declared as final
class SuperSuperHero extends SuperHero {
//...
}
Why do this? Whilst reuse is highly regarded in programming it’s important to keep good encapsulation and code maintainability in mind. By marking a class as final we can lock down the implementation and ensure that no-one is tempted into believing that we’ll support their subclass implementation.
When a method is marked as final it cannot be overridden. This is very useful if you want to block future implementations from altering the implementation. In the example below, the getName method in SuperHero is marked as final and the attempt by the BizarroSuperHero to override it will cause a compilation error:
final cannot be overriddenclass Person {
private String name
final setName(name) {}
}
class SuperHero extends Person {
final String getName() {
'Unknown'
}
}
class BizarroSuperHero extends SuperHero {
//This will NOT be allowed:
String getName() {
name
}
}
Importantly, marking a method as final does not transfer to its overloaded siblings. In the example below, I try to protect my hero’s identity but am not thorough enough:
final cannot be overriddenclass Person {
String name
}
class SuperHero extends Person {
final String discoverName() {
'Unknown'
}
String discoverName(Boolean mindRead) {
'Unknown'
}
final setName(name) {}
}
class BizarroSuperHero extends SuperHero {
//This WILL be allowed:
@Override
String discoverName(Boolean mindRead) {
name
}
}
def batBoy = new BizarroSuperHero(name: 'Bryce Rain')
assert batBoy.discoverName() == 'Unknown'
assert batBoy.discoverName(true) == 'Bryce Rain'
In that last example, the BizarroSuperHero can’t override String discoverName() but is allowed to override String discoverName(Boolean mindRead). If I’d been thorough in my information hiding attempts I’d have marked all discoverName methods as final or been really certain and marked SuperHero as final.