Why isn't Java's Object class abstract?

This is the question which Ajiit Balan asked me a couple of days ago. As I told him, I have a answer, but I'm not sure if it's correct or complete - hence this blog post. If you have any points to add, please feel free to do so in the comments. But first, Ajit's question in full:

In Java the Object class is a concrete class. Now my question is why did the designers of the Java API make the Object class a concrete class.

According to the GOF design principles one must always program for interfaces and not implementation. The designers of the Java API could have used abstraction here which is one of the OO principles.

If everything in Java is an Object implicitly then why is the Object class a concrete class? It could have be an abstract class with common methods sitting in the Object class. It could have also been designed as a skeleton class where it implemented an Object interface and provided a skeletal implementation in an abstract class called AbstractObject similar to the way the Collection classes have been designed.
Here's my 2 paise:

Creating useful abstractions is good - however, this should not be confused with abstract classes. Similarly, programming to interfaces does not literally mean using the 'interface' keyword in Java. In fact, one can still do all this in languages like Ruby or Javascript where there are no 'abstract' or 'interface' keywords. In the case of Javascript, there isn't even a 'class' keyword, yet everything is still an object. The GoF patterns book provide solutions to specific problems, some of them created by the language itself. For example, you don't need the strategy pattern in Ruby or Javascript - you'd use a block. As Neal Ford explains, nomenclature is good, recipes - not so much.
To clarify, creating layers of abstraction helps you simplify the root problem you are trying to solve - the classic example being high level language vs. machine language. Programming to an interface is essentially defining a contract which your code will adhere to. A contrived example would be 'provided a motherboard supports PS/2, I can connect any mouse with a PS/2 interface to it.' The motherboard doesn't care whether the mouse uses a ball or a laser. Indeed, you're free to change it at any point, because the motherboard isn't aware of the implementation details. All it knows is the interface.

When deciding whether to make a base class abstract or not, I have a simple rule of thumb. I ask myself, 'Is there something I need to force child classes to do in a manner which I can't predict?'. Well, actually that's the second question. The first question is, 'What's changing and can I encapsulate it?' - some standard patterns which help answer this question are the strategy, visitor and command patterns. More often than not you shouldn't need an abstract base class. Favour composition over inheritance and all that...

But back to the second question. What is it that Object says every derivative class must do? In Java, these are described by methods like equals(), hashCode(), getClass(), toString() etc. Now which of these methods can the Object base class not provide a default implementation for? None of them - they can all be given default implementations very easily. Therefore there is no case for an abstract class.

Indeed, the 'is-a' (inheritance) relationship which Java objects have with the Object class is not the only way it's done. In Javascript, a similar result is achieved purely through 'has-a' relationships, in other words, by composition. Every object has a 'parent' object accessed through the prototype field. That object in turn has another parent object. Eventually the chain terminates with the base Object (remember, there is no distinction between objects and classes in javascript). Any attempt to access a field or method (again there is no distinction) will propagate up this prototype chain until either the field is found or the chain terminates at the base Object. Javascript has no inheritance at all, everything is done through composition.

The last part of your question is about using an Object interface and an AbstractObject. In the context of all that I have already said, the answer is 'We get nothing extra from creating an interface and an abstract implementation. So why bother?' or in short, YAGNI.
Post a Comment