I will end this post with the first paragraph from Item 17, of Joshua Bloch's excellent book, Effective Java. In the book this paragraph is followed by a code example that explains this very well, however, I am not sure if I can include the example under fair use. .

Inheritance is a powerful way to achieve code reuse, but it is not always the best tool forthe job. Used inappropriately, it leads to fragile software. It is safe to use inheritance withina package, where the subclass and the superclass implementation are under the control of thesame programmers. It is also safe to use inheritance when extending classes specificallydesigned and documented for extension (Item 15). Inheriting from ordinary concrete classesacross package boundaries, however, is dangerous. As a reminder, this book uses the word“inheritance” to mean implementation inheritance (when one class extends another).The problems discussed in this item do not apply to interface inheritance (when a classimplements an interface or where one interface extends another).

Can you think of a situation where subclassing an existing class can break the semantics of your code, because of a certain undocumented feature of the superclass? Let me give you a hint. Assume a collection class has 2 methods

add(Object o) - to add the specified object to the collection

addAll(Collection c) - to add each element of the specified Collection to this collection.

Now assume that addAll(Collection c) internally invokes add(Object o) for every object in the collection.

Can you think of a situation that will result in a bug, if we subclass this class and override the above methods to add a functionality that keeps track of how many elements have been added to the collection?