The Details of Object Class in Java

Introduction

With some clarity in the Type Definition in Java, now it is time to know some details of the language. If you missed the critical posts in this series, please visit the link More about reference types in Java.

In this post, I trust that you have knowledge about what I wrote in the above link. We will primarily discuss some core classes and their properties in the language.

The Object class

This Object class is a super class for all other classes. Please note that it is a super class only for all the classes, there are times when people get confused or have doubts if the interfaces also have Object as their super class. The answer is NO.

Another piece which adds to the confusion is that, why are we able to invoke the methods in the Object class over a reference of Interface type. Look at the below code:

[one_half]All the classes and array types inherit the methods present in the Object class. There is a very famous interview question in core java which goes like this. In the above code snippet it is perfectly legal to invoke any of the methods of the object class which are shown in the adjoining image. Why? Read the answer below:[/one_half][one_half_last]Object Class in Java[/one_half_last]

Why is it legal to do so if the Object is not the root or super class off all interfaces?

The Java Language Specification has an answer for that as well. Quoting the JLS § 9.2 Interface Members.

If an interface has no direct super interfaces, then the interface implicitly declares a public abstract member method m with signature s, return type r, and throws clause t corresponding to each public instance method m with signature s, return type r, and throws clause t declared in Object, unless a method with the same signature, same return type, and a compatible throws clause is explicitly declared by the interface.

It is a compile-time error if the interface explicitly declares such a method m in the case where m is declared to be final in Object.
It follows that is a compile-time error if the interface declares a method with a signature that is override-equivalent to a public method of Object, but has a different return type or incompatible throws clause.

In simple words it means that every interface which doesn’t have a super interface will implicitly declare the abstract version of all non static visible methods in the Object class. That is why the image above shows all the methods even on an Interface Reference Type.

Methods in the Object class

.
There are many other famous interview questions around the methods in the Object class.

clone

This method is used to make a duplicate of the current object. If you see the source of the Object class. The method is declared as below:
protected native Object clone() throws CloneNotSupportedException;

What does this definition mean?
The protected modifier dictates that all the sub classes of the Object class in all possible packages will inherit this method. This precisely means that this method can be invoked within a subclasss, using this operator.

The native keyword says that the method is implemented in the native code using JNI. (More on this in coming posts)

The return type Object suggests that the method will always return an Object. Further you can type cast this returned value to a more specific type.

The throws clause, says that any attempt to invoke this method on an instance of a class will throw a CloneNotSupportedException for any implementing class, if it does not implement the Cloneable interface.

Apart from the definition, we also need to set our expectations clear from the clone method.
What is the clone method supposed to do?

  • Create a copy of the object.
  • The intent is that, for any object x, the expression x.clone() == x returns false.
  • The expression x.clone().getClass() == x.getClass() returns true.
  • Also, the expression x.clone().equals(x) typically returns true.

However, these are not absolute requirements, but this when honored will make clone the method for which it is written.
Now, the second point means that the object returned by the clone method is independent of the object x. This means that if we modify/alter the object x, the change of state will not reflect in the cloned copy.

An object can be a specialization of some other class (super class) or may contain references to another classes. In such cases the clone method for these classes must also be overridden for an absolute cloning behavior.

The clone method must recursively call the clone method of the super class too. This is necessary to maintain the independence relation between and object and its clone.

Deep Copying
A cloning or copying process in which the object is copied field by field and if there is any instance variable which is of Reference Type in the field list of the object, then a deep copy of that variable is also made. This is a recursive definition and hence it will clone all super types and all the contained objects in this object.

Shallow Copying
A cloning or copying mechanism in which a new instance of the object is created and all its fields are initialized with the contents of the corresponding fields as if it is an assignment operation on the fields.

equals

It defines a notion of object equality based on values of the two objects to be compared. This method only works for non null object references.
The intent behind this method is pretty simple and obvious.

  • The expression x.equals(x) returns true.
  • The expression x.equals(y) only returns true if y.equals(x) returns true.
  • If the expression x.equals(y) returns true and expression y.equals(z) returns true, then the expression x.equals(z) must return true.
  • No matter how many times we invoke the equals method if x.equals(y) returns true, then it will always return true, provided the information used for comparisons in the equals method is unchanged.
  • For any x.equals(null) it should always return false.

In the Object class the code within the equals method is return (this == obj); . This means that the two objects x and y will be equal only if the object reference x and y contain the same 32 bit (or 64 bit) values (both the references are pointing to the exact same object) as discussed in my previous post More About Reference Types in Java.

hashCode

This method returns an int value upon invocation. It is expected that if the hashCode method is invoked multiple times during an execution of a Java Application, it returns the same integer provided no information used in the equals comparison on the object is modified.

The integer need not remain same in different set of executions of the application. A lot needs to be discussed about the hashCode and equals method and I reserve this discussion when we will discuss Collections or Serialization

If two objects are equal as per the equals method, then the invocation of hashCode on both the object references must return the same integer.

If two objects are not equal as per the equals method, then it is not required for the hashCode invocation to return different integers. It may return same of different integers.

For practical purposes, the JVM returns distinct hash codes for different objects (typically by converting the internal address of the object into an integer).

getClass

This method returns the runtime class of the object on which this method is invoked.
A Class object exists for each reference type. This means that if we declare a Reference Type as below, then there exists an object o1 of type Class which is named as MyCoolCar, another object o2 of type Class which is named as Drivable and an object o3 of type Class with name integerArray. Definitely there will be scopes assigned for all these objects.

Just for the sake of mentioning, if there is a static synchronized method m defined in the class MyCoolCar then the monitor of o1 will be acquired by the thread which is currently executing the method m.

If you didn’t get the last line, no need to worry, we will discuss this in full length in the Multi Threading post.

toString

The method upon invocation returns the string representation of the object. For the Object class a string which contains the class name followed by the ‘@’ sign which is followed by a hex representation of the hashCode. If this method is not overridden in the sub classes, then the invocation of toString() for them will also return a similar string. The purpose of this method is to just return a human readable string for any object.

notify

Every object can have a wait set, which is a set of threads which desire to acquire the monitor of this object. A thread can be added to the wait set by invoking any of the overloaded versions of the wait method.

This notify method when invoked on an instance of an object wakes up a single thread from the wait set of this object. If multiple threads are in the wait set of this object then an arbitrary choice (majorly based on the implementation) is made to wake up one single thread. Then the woken thread can compete for the monitor of this object and if lucky will acquire the monitor. In this process the woken thread is removed from the wait set and is eligible for thread scheduling.

notifyAll

This method is slightly different from the notify method. It wakes up all the threads in the wait set. Ideally only one of the threads will be able to acquire the object monitor because at a given time the monitor can be held only by one thread.

Both notify and notifyAll can only be invoked by a thread who is the owner of the object’s monitor.

wait, wait(long), wait(long, int)

Three overloaded versions of this method is present. It is mostly used in the context of multi threaded programming. This method when invoked upon an object causes the current thread to be placed in a wait set for this object, until either of the below conditions are met:

  • Another thread invokes the notify or notifyAll method.
  • The time specified in the argument has elapsed
  • Some other thread interrupts this waiting thread

During the wait time the object’s monitor will be released by the thread which is waiting. The waiting thread doesn’t participate in any thread scheduling activity. Once this thread wakes up, it has to struggle to acquire the monitor and it will not get any preference.

finalize

This method is invoked by the garbage collector when the garbage collector determines that the object is eligible for garbage collection (no more references to the object exists). The usual purpose of finalize, however, is to perform cleanup actions before the object is irrevocably discarded. This method is never invoked more than once for a given object by the JVM.

Conclusion

We still missed a lot of details about multi-threading and garbage collection, but we covered the Object class in detail. After this post, I believe that everyone can answer all the questions related to the basics of Object and its methods.

There is a bigger discussion around the wait and notify mechanism which can be discussed later during multi-threading. But this is a good place to begin with.

If you had difficulty understanding any part of this post, please write your comments. You can also write comments if you liked the post.

Don’t forget to subscribe to TechieMe to get updates on latest posts.