Skip to main content

A Java example showing the dangers of implementation inheritance

I ended my previous post with a paragraph from Josh Bloch's book, Effective Java. In his book, Josh explains why inheriting classes from a different package (especially inheriting from a class that may not be designed and documented for inheritance) can be dangerous. Below you will find Josh's example (from Effective Java) that explains the concept. Many many thanks to Josh Bloch for graciously giving me permission to reproduce the example here :-)

The class InstrumentedHashSet is a subclass of HashSet, that maintains a count of the number of objects added. It overrides the add(Object o) and addAll(Collection c) methods from HashSet to maintain a count of objects added to it. These methods increment the count and then delegate responsibility for adding the element to HashSet. The number of objects added can be obtained from the method getAddCount().

This seems like a reasonable way to count objects added to the Set. Unfortunately it's not. But first let's have a look at the code of InstrumentedHashSet.

 InstrumentedHashSet.JPG

 

Below is a test case for the addAll(Collection c) method of InstrumentedHashSet. By the way, this test was written by me, so if there is anything wrong with it, it's entirely my fault :-)

 

InstrumentedHashSetTest.JPG 

 

Now let us run the unit test.

InstrumentedHashSetTestReport.JPG 

Oops :-( we expected a count of 3, but looks like InstrumentedHashSet is reporting 6. Now, how did that happen???

Look again at InstrumentedHashSet. The method addAll(Collection c) calls super.addAll(c) after incrementing the count. This ends up invoking a method implemented in AbstractCollection in the JDK (ver 1.6). It has implemented addAll(Collection c) to iterate through the given Collection and invoke add(Object o) for every element in the Collection. Since we have overriden add(Object o), it is our implementation that get's called. The count is added for every element of the Collection in addAll(Collection c) as well as in add(Object o), resulting in the count increasing by 2 for every object. That's the reason we got a count of 6 instead of 3.

So to summarize. Be very careful when you subclass a class that is not in your control. It might be safer to use composition that inheritance in such situations. It is also equally important to remember that if you create a non-final class with public methods, please design it carefuly to ensure that it does not break a subclass that may extend from it. If there are any caveats, be sure to document them clearly.



Note: This text was originally posted on my earlier blog at http://www.adaptivelearningonline.net
Here are the comments from the original post

-----
COMMENT:
AUTHOR: Sanket Daru
URL:
DATE: 10/20/2007 11:40:37 AM
This was a serious eye opener.

Learnt a very good OOP lesson.

Comments

Popular posts from this blog

Commenting your code

Comments are an integral part of any program, even though they do not contribute to the logic. Appropriate comments add to the maintainability of a software. I have heard developers complain about not remembering the logic of some code they wrote a few months back. Can you imagine how difficult it can be to understand programs written by others, when we sometimes find it hard to understand our own code. It is a nightmare to maintain programs that are not appropriately commented. Java classes should contain comments at various levels. There are two types of comments; implementation comments and documentation comments. Implementation comments usually explain design desicisions, or a particularly intricate peice of code. If you find the need to make a lot of implementation comments, then it may signal overly complex code. Documentation comments usually describe the API of a program, they are meant for developers who are going to use your classes. All classes, methods and variables ...

Inheritance vs. composition depending on how much is same and how much differs

I am reading the excellent Django book right now. In the 4th chapter on Django templates , there is an example of includes and inheritance in Django templates. Without going into details about Django templates, the include is very similar to composition where we can include the text of another template for evaluation. Inheritance in Django templates works in a way similar to object inheritance. Django templates can specify certain blocks which can be redefined in subtemplates. The subtemplates use the rest of the parent template as is. Now we have all learned that inheritance is used when we have a is-a relationship between classes, and composition is used when we have a contains-a relationship. This is absolutely right, but while reading about Django templates, I just realized another pattern in these relationships. This is really simple and perhaps many of you may have already have had this insight... We use inheritance when we want to allow reuse of the bulk of one object in other ...

Planning a User Guide - Part 3/5 - Co-ordinate the Team

Photo by  Helloquence  on  Unsplash This is the third post in a series of five posts on how to plan a user guide. In the first post , I wrote about how to conduct an audience analysis and the second post discussed how to define the overall scope of the manual. Once the overall scope of the user guide is defined, the next step is to coordinate the team that will work on creating the manual. A typical team will consist of the following roles. Many of these roles will be fulfilled by freelancers since they are one-off or intermittent work engagements. At the end of the article, I have provided a list of websites where you can find good freelancers. Creative Artist You'll need to work with a creative artist to design the cover page and any other images for the user guide. Most small to mid-sized companies don't have a dedicated creative artist on their rolls. But that's not a problem. There are several freelancing websites where you can work with great creative ...