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.

8 comments:

braincells2pixels.net said...

A very good question and even better explanation. Well done!!

Ajit Balan said...

Hey Sidu,

I like the way you covered different languages to explain your answer. I totally agree with you on your thoughts on this question. However here are my thoughts on the same question.

Firstly the object class is a collection of final methods, native methods and others methods which can be overriden like toString() , hashcode() , equals() etc. The Object class has default implementation for all methods which means the class is a complete class and hence no need for abstraction.

Secondly sometimes you need a lightweight object for the purpose of locking when it comes to threads. In Java the lightweight object is the Object class and you can perform synchronization using the object class.

What do you think Sidu?

koundinya said...

Hi Sidu,

A very enlightening post on the design intentions behind the Object Class in the Java.

Keep it up.

Ramesh

Stacy Curl said...

Just because the methods in Object can be accepted as default should not exclude making Object abstract simply because it's too vague. When I want to instantiate an object I always have a particular purpose in mind, Object should be abstract not to force implementation of equals / hashcode etc, but to name that purpose.

Anonymous said...

I have seen so many explanations and disscussions of java Object, it's need, why is it not interface or maybe abstract, or not only implicit, in sense that compiler should "know" about it methods and implicitly cretate them when needed.

There are so many academic explanations, yet nobody has ever thought of something simple, like beeing practical. Not everything has to have deep theoretical meaning.

Imagine that Object was interface or abstract class. In that case you will have to implement several methods in every class you ever wrote!!! Sounds practical? I guess it would never become THE #1 teaching object oriented lang in the world in THAT case. Just image how many classes you wrote that never called base methods.

Last option is why it is not implicit, like "class" field for example. I guess answer is still simply practical: it would unneccessary complicate compiler and language definition. It is probably not impossible to make a compiler that recognizes if you call number of "special" methods that belongs to Object class. Further it would need to now if those classes are user defined to exchange "implicit" ones for users. But then one has to change language deff as well. To me it seems more practical to make one exception (of having single inhertiance) for Object class and let language mechanism deal with other issues, then to implement Object and it's methods "implicitly" in compiler, rather as real class.

So my answer is simply, Object class is not abstract or interface for practical reasons, both for programmers, and for compiler makers.

Anonymous said...

And I forgott to mention, haveing one common base let's you have heterogeonus objects in one and same collection. Now that Java got generics, it is probably less obvious, but when lang was invented it didn't have generics. Furthermore, generics are actually resting on exactly that design of having one common Object as mother of all other classes .... So Object has otehr reasons to be concrete class but only having methods in Object cthat an be accepted as default, as Stacy perceives it. That is yet another practical reason of having common base for all objects.

Pravin Jain said...

Not only the Object class should have been abstract, but even there should be rule that the compiler should not allow abstract sub class for a concrete class. This is in accordance to the basic inheritance philosophy, that a sub class can only add to the functionality provided by the super class. In the current scenario the we stop instantiation of a sub class (which is abstract) which is allowed in the super-class.

Troff said...

I don't think it's a question of defining methods at all. The real question is, can you come up with a case where you want to instantiate Object and Ajit has done that in his comment 3 years ago.