Good reasons to prohibit inheritance in Java?
Your best reference here is Item 19 of Joshua Bloch's excellent book "Effective Java", called "Design and document for inheritance or else prohibit it". (It's item 17 in the second edition and item 15 in the first edition.) You should really read it, but I'll summarize.
The interaction of inherited classes with their parents can be surprising and unpredictable if the ancestor wasn't designed to be inherited from.
Classes should therefore come in two kinds:
Classes designed to be **extended**, and with enough documentation to describe how it should be done
Classes marked **final**
If you are writing purely internal code, this may be a bit of overkill. However, the extra effort involved in adding five characters to a class file is very small. If you are writing only for internal consumption, then a future coder can always remove the 'final' - you can think of it as a warning saying "this class was not designed with inheritance in mind".
When to prevent class inheritance?
In fact, the practice that I try to follow, and that Josh Bloch recommends, in his Effective Java book, is exactly the inverse rule of the one you've been told: Unless you have thought about inheritance, designed your class to be inherited, and documented how your class must be inherited, you should always disable inheritance.
I would recommend reading this chapter of Effective Java (you won't regret buying it), and showing it to the person who told you about this rule.
The most obvious reason to disallow inheritance is immutability. An immutable object is simple to use (only one state), can be cached, shared between many objects, and is inherently thread-safe. If the class is inheritable, anyone can extend the class and make it mutable by adding mutable attributes.
Does inheritance cause waste of space?
The JVM specification page 570 implies that the answer to your question is "no"; a virtual method that is not overriden will use the superclass's version of that method directly, rather than make a copy of it for its own use.
See this previous answer for more info on vtable dispatch.
Why use inheritance at all?
If you delegate everything that you haven't explicitly overridden to some other object implementing the same interface (the "base" object), then you've basically Greenspunned inheritance on top of composition, but (in most languages) with a lot more verbosity and boilerplate. The purpose of using composition instead of inheritance is so that you can only delegate the behaviors you want to delegate.
If you want the object to use all the behavior of the base class unless explicitly overridden, then inheritance is the simplest, least verbose, most straightforward way to express it.
prevent inheritance of interface outside of package
From the java tutorial:
.. All abstract, default, and static methods in an interface are implicitly public, so you can omit the public modifier.
It means that you can't unless you restrict the interface visibility to package. But i guess that you can't.
package foo;
interface Foo
{
}
I suppose that you could write a custom annotation (somelink like @InstanciableOnlyInMyPackage
) and put it on the interface. And then using raise a compiler error using Annotation Processing Tool.
Keeping a value class non-final for possible future extensibility
In my opinion, it is good practice to make simple value types final
. If you want to guarantee immutability, you actually have to do so. That's also (partially) why String
, Integer
, etc are all final
.
If your class is not final
, somebody could extend it by adding methods that mutate it. A client who is passed an instance of the extended type (upcasted to your type) would falsely believe to deal with an immutable object when it actually isn't.
In my own code, I actually go a little further and make almost any class final
if I didn't design it with extensibility explicitly in mind. If you want to support extension, consider providing an abstract class or an interface. This is also in line with the abstract, final or empty rule for methods.
Update: Why does immutability require a class to be final
? Of course, there are other ways to ensure a particular attribute of an object is not changed.
Consider for example a RGBColor
class with three attributes red
, green
and blue
of type byte
. We make all three final
and set them in the constructor once for all time. (We can additionally make them private
and add appropriate getter methods but that's not important for the sake of this discussion.) Of course, we override the equals
method to return true
if and only if the compared object is an instance of RGBColor
with the same red
, green
and blue
values.
This looks innocent but what if somebody decides to extend our class to a RGBAColor
class by adding an alpha
attribute? Naturally, the extender would desire to override equals
to also take into account the alpha
value. Suppose our extender also isn't very careful about immutability and thus makes alpha
non-final
and supplies a setter for it.
Now, if we are given an object of type RGBColor
, we cannot safely assume that if it compared equal to another one, it will still do so a minute from now. We could have prevented this (particular problem) by also declaring equals
as final
in our RGBColor
class. But then, we could have equally well made the entire class final
because extending a value type without the possibility to extend the notion of equality is close to useless. (Thre are other problems with overriding equals
such as it not being symmetric. I generally feel not too comfortable about it.)
Related Topics
Varying Behavior for Possible Loss of Precision
Difference Between List, List<>, List<T>, List<E>, and List<Object>
How to Create 2 Separate Log Files with One Log4J Config File
How to Merge Two PDF Files into One in Java
How to Sort an Arraylist of Objects by a Property
Isn't the Size of Character in Java 2 Bytes
Correct Way to Close Nested Streams and Writers in Java
Looking for an Example for Inserting Content into the Response Using a Servlet Filter
Swing on Osx: How to Trap Command-Q
Is the Buildsessionfactory() Configuration Method Deprecated in Hibernate
Why Do We Need Immutable Class
How to Schedule a Task to Run at Periodic Intervals
Safe String to Bigdecimal Conversion
How to Implement Dynamic Gui in Swing
Installed Java 7 on MAC Os X But Terminal Is Still Using Version 6