views:

89

answers:

3

I'm currently reading Effective Java by Joshua Bloch and Item 17 is 'Design and document for inheritance or else prohibit it'. The author suggest to prohibit inheritance by default.

Is it safe to declare classes final by default and in a later release remove the final keyword if there is a need to extend the class? Will it break backwards compatibility against code that was compiled with a previous version?

If so it appears that it is a safer bet to make all classes final and only remove it in a future release if there is a well supported demand.

+7  A: 

It breaks neither binary nor source compatibility. That's one of the reasons it's a good idea to make classes final; it's always OK to change your mind about it.

The Java Language Specification, §13.4.2, has the following to say about binary compatibility:

Changing a class that was declared final to no longer be declared final does not break compatibility with pre-existing binaries.

I suppose you still could make up a construed example where it actually could break a program; like bytecode-generating a class inheriting from the supposedly final class, and then loading that generated class and relying on getting a VerifyError.

gustafc
A: 

My thoughts on this:

Removing the final on a class won't cause immediate problems. But consider this:

There was a final class called AdamsFactory which you change to non-final. Two months from now, a new programmer called Dilbert joins your team.
He subclasses your used-to-be-final class into ScottFactory, but breaks the Liskov's Substitutability Principle.

Then he has your ComicStripPrinter class use ScottFactory instead of AdamsFactory. Something is bound to break.

Which brings us back to what Joshua Block says:

If you intend inheritance: design it with deliberation, and document it. If you do not intend inheritance, then prevent it.

I hope what I said was not a big load-a-crap.


EDIT:

Go the the preface of Java Langauge Specification, and search for Joshua Bloch :)

Here Be Wolves
The person who designed AdamsFactory did not know whether to make it final/non-final, so PHB mandated it be non-final (by default). Later Dilbert makes a compelling case for AdamsFactory to be final, but by this time there are about one trillion classes extending AdamsFactory some breaking Liskov's Principle. If Dilbert makes the change all those classes are broken. Everone hates Dilbert.
emory
+2  A: 

If you are designing something like Java Standard API, that millions of programmers will use for many years, yes, think like Joshua Bloch. FORWARD EVOLUTION is crucial.

99% of Java programs are not. They are developed for internal use, the impact of API change is tiny, usually all source code are available for refactoring. SIMPLICITY is key for such programs. If you have complex and fancy designs, or you spend all your time thinking about final or not, you are wasting time.

I blame Joshua for not setting proper disclaimers for his suggestions.

irreputable
Well, YAGNI is all fine and dandy, but changing your IDE Java class template to declare all classes as `final` is a one time thing to do, and sensible class design always makes long and medium term maintenance easier (often but not always, it helps even in short term), and navigating to a class declaration and removing `final` is a very easy thing to do, if you feel you should need it.
gustafc
while you are at it, make all fields and methods final too.
irreputable