I've only really seen this on Java's wrapper classes (String
, Integer
, etc.), but never in open-source projects, and I was never taught about it in any books or classes. I know it means the class can't be extended, but I don't know when that would be useful for any class outside the aforementioned JVM-low classes. So, when would I want to use the final
modifier on a class, if ever?
-
2stackoverflow.com/questions/218744/…– user120251Sep 22, 2014 at 5:19
1 Answer
Whenever you don't want the class to be extended. Designing for extension has a cost (see also Eric Lippert's Blog: Why Are So Many Of The Framework Classes Sealed?) - you need to make sure you provide the right hooks for the class, that people can implement those hooks without breaking things, that you can be reasonably sure that subclasses won't be nefarious (this is especially important with core language classes like String
and Integer
), that the contracts that the superclasses implement are clear (so that subclasses don't break them easily).
This takes work, time, and thought to put into it. It isn't easy developing a class that is meant to be extended. And sometimes, you know you don't want it to be extended - that it can be put to nefarious use and cause havoc with your implementation if someone passes you a mutable String
rather than an immutable one.
And so, you make the classes final
. There can be no mutable String
, because its an immutable class and its final. You know when you get it, it won't be changed from under you in some way. You can save it and be sure that that it will behave like a String
, always - no subclasses can be made to make it be otherwise.
Thus, there is a bit of design that some follow that all classes start out as default to be final
. How often are you going to subclass that DTO? And when you do want to subclass it for some reason, you should spend some time thinking about the implications of removing the modifier.
There is a check style rule Design For Extension. Personally, I like it. In every non-final class, every method must be one of:
- abstract
- final
- empty implementation
This sort of thinking then allows you to write subclasses that are clearly implemented the proper way - providing hooks and preventing the superclass fro being broken by the subclass not knowing about tinkering the innards of it in an unexpected way. Though, admittedly, this design philosophy means that the subclasses are more limited in their flexibility - but they can't corrupt the state of their superclass.
Again, if you're not prepared or willing to design a class so that it can be extended cleanly, it is best to design the class so it can't be extended at all.
-
-
2I think it's one that looks to instill good use of superclasses and avoid the lazy extension of a class that later prohibits me from other code in what is now a superclass because I'll break something in some subclass. I don't trust the next coder whoever he or she may be to do it right unless forced along that path.– user40980Sep 22, 2014 at 5:36
-
1It's worth noting that
final
is also handy for preventing someone from extending a utility class likeMath
which in theory is possible, but it makes no sense to do so.– NeilSep 22, 2014 at 8:25 -
1also, by sealing a class for extension, you are FORCING people to prefer composition over inheritance, so there's that too :D– saraJul 1, 2016 at 22:11