Showing posts with label java.lang.Object Class. Show all posts
Showing posts with label java.lang.Object Class. Show all posts

Tuesday, 23 June 2015

java.lang.Object Class

1.Introduction

The Object class is at the root of all the hierarchies in Java. This class is part of the java.lang package. All classes extend the Object class, either directly or indirectly. Even if you write a simple class (i.e. it is not extending any base-class), it implicitly extends built-in Object class.

Thus the features of this class will be available in all the classes because of inheritance.

2. Important Methods in Object class

The object class defines following methods, which are inherited by all the classes.
  • public int hashCode()
  • public boolean  equals(Object obj)
  • public final Class getClass()
  • public String toString()
  • public protected void finalize() throws Throwable
  • public protected Object clone() throws CloneNotSupportedException
  • public final void wait(long timeout) throws InterruptedException
  • public final void wait(long timeout, int nanos) throws InterruptedException
  • public final void wait() throws InterruptedException
  • public final void notify()
  • public final void notifyAll()

2.1 public int hashCode()

When storing objects in hash tables, this method can be used to get a hash value for an object.

This value is guaranteed to be consistent during the execution of the program. If the objects of a class are to be maintained in hash based collections and maps of the java.util package, the class must provide appropriate implementation of the following methods from class Object:
  • hashCode()
  • equals()

As a general rules for implementing these methods a class that overrides the equals() method must also override the hashCode() method.

General contract of the hashCode() method:

(a) Consistency during execution: Multiple invocations of the hashCode() method on an object must consistently return the same hash code during the execution of an application, provided the object is not modified to affect the results returned by the equals() method.

(b) Object value equality implies hash value equality.

(c) Object value inequality places no restrictions on the hash value. If two objects are unequal according to equals() method, then the hashCode() method need not produce distinct hash code for these objects. It is strongly recommended that the hashCode() method produce unequal hash codes for unequal objects.

Note: The hash contract does not imply that objects with equal hash codes are equal. Not producing unequal hash codes for unequal objects can have an adverse effect on performance, as unequal objects will hash to same bucket, which will result in collision.

2.2 boolean equals(Object obj)

If every object is to be considered unique, then it is not necessary to override the equals() method of the Object class. This method implements object reference equality. It implements the most discriminating equivalence relation possible on objects. Each instance of the class is equal to itself.

The equals() method is usually overridden to provide the semantics of object value equality, as is the case for the wrapper classes and the String class.

2.3 final Class getClass()

Returns the runtime class of the object, which is represented by an object of the class java.lang.Class at runtime.

Example: The following example illustrates that this method can be used to get the Class object corresponding to any java Object. We can then use method of the class Class to get information about the object's class using reflection/introspection.

import java.lang.reflect.Method;

import java.lang.reflect.Field;

class DispClassInfo

{

public static void main(String args[]) throws ClassNotFoundException

{

String s = new String ("Hello");

Class c = s.getClass();

Method m[] = c.getMethods();

int l;

l = m.length;

System.out.println (".........Public Methods (" + l + ")......");

for(int i = 0; i < l; i++)

{

System.out.println (m[i]);

}

Field f[] = c.getFields();

l = f.length;

System.out.println (".........Public Fields (" + l + ")......");

for(int i = 0; i < l; i++)

{

System.out.println (f[i]);

}

m = c.getDeclaredMethods();

l = m.length;

System.out.println ("......... Declared Methods (" + l + ")......");

for(int i = 0; i < l; i++)

{

System.out.println (m[i]);

}

f = c.getDeclaredFields();

l = f.length;

System.out.println (".........Declared Fields (" + l + ")......");

for(int i = 0; i < l; i++)

{

System.out.println (f[i]);

}

}

}

Example: The previous example is modified so as to read the fully qualified class name as command line argument and then display the information about the class's methods and fields using reflection/introspection.

import java.lang.reflect.Method;

import java.lang.reflect.Field;

class DispClassInfo

{

public static void main(String args[]) throws ClassNotFoundException

{

Class c = Class.forName(args[0]);

Method m[] = c.getMethods();

int l;

l = m.length;

System.out.print();

System.out.println (".........Public Methods (" + l + ")......");

for(int i = 0; i < l; i++)

{

System.out.println (m[i]);

}

Field f[] = c.getFields();

l = f.length;

System.out.println (".........Public Fields (" + l + ")......");

for(int i = 0; i < l; i++)

{

System.out.println (f[i]);

}

m = c.getDeclaredMethods();

l = m.length;

System.out.println ("......... Declared Methods (" + l + ")......");

for(int i = 0; i < l; i++)

{

System.out.println (m[i]);

}

f = c.getDeclaredFields();

l = f.length;

System.out.println (".........Declared Fields (" + l + ")......");

for(int i = 0; i < l; i++)

{

System.out.println (f[i]);

}

}

}

2.4 String toString()

If a sub class does not override this method, it returns a textual representation of the object, which has the following format:

“<name of the class>@<hash code value of object>”

The method is usually overridden and used for debugging purposes. The method call System.out.println(Objref) will implicitly convert its argument to a textual representation using toString() method.

Example: This example demonstrates what gets displayed if we try to display object of class Box1. The object is converted to the textual representation using the toString() method of the object class.

class Box1

{ double w, h, d;

Box1(double w, double h, double d)

{ this.w=w; this.h=h; this.d=d;

}

}

class ToStringDemo1

{ public static void main(String args[])

{ Box1 b=new Box1(10,12,14);

String s="Box1 b: "+b; //concatenates box object

System.out.println(b);

System.out.println(s);

}

}

Output:

Box1@82ba41

Box1 b: Box1@82ba41

Example: This example demonstrates that if we override the toString() method in the Box1 class then the overridden method is used to convert the object to its textual representation.

class Box1

{ double w, h, d;

Box1(double w, double h, double d)

{ this.w=w; this.h=h; this.d=d;

}

public String toString()

{ return "Dimensions are "+w+" by "+h+" by "+d+".";

}

}

class ToStringDemo2

{ public static void main(String args[])

{ Box1 b=new Box1(10,12,14);

String s="Box1 b: "+b; //concatenates box object

System.out.println(b);

System.out.println(s);

}

}

Output:

Dimensions are 10.0 by 12.0 by 14.0.

Box1 b: Dimensions are 10.0 by 12.0 by 14.0.

2.5 protected void finalize() throws Throwable

It is called on an object just before it is garbage collected, so that any cleaning up can be done.

However, the default finalize() method in the object class does not do anything useful. This may be useful for releasing non-java resources but not recommended.  It is possible that finalize() method may never be called if enough memory is available and in that case resources may never be released.

2.6 protected Object clone() throws CloneNotSupportedException

New objects that are exactly the same (i.e., have identical states) as the current object can be created by the clone() method, that is, primitive values and reference values are copied. This is called shallow cloning.

A class can override the clone() method to provide its own notion of cloning. For example, cloning a composite object by recursively cloning the constituent objects is called deep cloning.

When overridden, the method in the subclass is usually declared public to allow any client to clone objects of the class.

If overriding clone() method relies on the clone() method in the Object class, then the subclass must implement the Cloneable marker interface to indicate that its objects can be safely cloned. Otherwise, the clone() method in the Object class will throw a checked CloneNotSupportedException.

Using clone() and the Cloneable interface

The clone() method generates a duplicate copy of the object on which it is called.

These are few important faces related to clone() method.

  • Only classes that implement the Cloneable interface can be cloned.
  • The Cloneable interface defines no members. It is used to indicate that a class allows a bit-wise copy ofan object (that is, a clone) to be made. If you try to call clone() on object of a class that does not implement Cloneable interface, CloneNotSupportedException is thrown.
  • Cloneable interface is an empty interface. Such an interface is called marker/tag interface.
  • When a clone is made, the constructor for the object being cloned is not called.
  • A clone is simply an exactly copy of the original. Cloning is potentially a dangerous action, because it can cause unintended side effects. For example, if the object being cloned contains a reference variable called objRef, then when the clone is made the objRef in clone will refer to the same object as does objRef in original. If the clone makes a change to the contents of the object referred to by objRef, then it will be changed for the original object, too.

Example: The following example demonstrate the use of clone() method. The CloneDemo1 class is making clone of the object of class TestClone by indirectly calling the clone method through cloneTest() method because clone() method of the object class is protected.

class TestClone implements Cloneable

{

int a;

double b;

public TestClone cloneTest() throws CloneNotSupportedException

{

}

return (TestClone) clone();

}

class CloneDemo1

{

public static void main(String a[]) throws CloneNotSupportedException

{

TestClone tc1 = new TestClone();

TestClone tc2;

tc1.a = 10;

tc1.b = 3.5;

tc2 = tc1.cloneTest();

System.out.println (tc2.a);

System.out.println (tc2.b);

}

}

Output:

10

3.5

Here, the method cloneTest() calls clone() of Object class and returns the result. Notice that the object returned by clone() must be cast into its appropriate type i.e. TestClone.

Example: In the following example the clone() method is overridden so that it can be called from code outside of its class. To do this, its access modifier must be public.

class TestClone1 implements Cloneable

{

int a;

double b;

public Object clone() throws CloneNotSupportedException

{

}

}

class CloneDemo2

{

public static void main(String a[]) throws CloneNotSupportedException

{

return super.clone();

TestClone1 tc1 = new TestClone1();

TestClone1 tc2;

tc1.a = 10;

tc1.b = 3.5;

tc2 = (TestClone1) tc1.clone();

System.out.println (tc2.a);

System.out.println (tc2.b);

}

}

Output:


10

3.5

Example: In the following example the clone() method is overridden such that it does not make use of the clone() method of the Object class. We are writing our own clone() method.

class TestClone2

{

int a;

double b;

public Object clone()

{

TestClone2 tc = new TestClone2();

tc.a = a;

tc.b = b;

return tc;

}

}

class CloneDemo3

{

public static void main(String a[])

{

TestClone2 tc1 = new TestClone2();

TestClone2 tc2;

tc1.a = 10;

tc1.b = 3.5;

tc2 = (TestClone2) tc1.clone();

System.out.println (tc2.a);

System.out.println (tc2.b);

}

}

Note: You need not declared CloneNotSupportedException and need not implement Cloneable interface if implementing your own clone() method.

Side Effects of Cloning

The side effects caused by cloning are sometimes difficult to see at first. It is easy to think that a class is safe for cloning when it actually is not. In general, you should not implement Cloneable interface for any class without good reason.

Example: This example demonstrates the side effect of cloning.

class TestShallowClone implements Cloneable

{

int a;

double b;

int c[];

public Object clone() throws CloneNotSupportedException

{

}

}

class ShallowCloneDemo

{

public static void main(String a[]) throws CloneNotSupportedException

{

return super.clone();

TestShallowClone tc1 = new TestShallowClone();

TestShallowClone tc2;

tc1.a = 10;

tc1.b = 3.5;

int c[] = new int[4];

for(int i = 0; i < 4; i++)

c[i] = i;

tc1.c = c;

for(int i = 0; i < 4; i++)

System.out.println ("tc1.c["+i+"]="+tc1.c[i]);

tc2 = (TestShallowClone) tc1.clone();

System.out.println ("tc2.a="+tc2.a);

System.out.println ("tc2.b="+tc2.b);

for(int i = 0; i < 4; i++)

System.out.println ("tc2.c["+i+"]="+tc2.c[i]);

for(int i = 0; i < 4; i++)

tc2.c[i] = i+4;;

for(int i = 0; i < 4; i++)

System.out.println ("tc2.c["+i+"]="+tc2.c[i]);

for(int i = 0; i < 4; i++)

System.out.println ("tc1.c["+i+"]="+tc1.c[i]);

}

}

Output:

tc1.c[0]=0

tc1.c[1]=1

tc1.c[2]=2

tc1.c[3]=3

tc2.a=10

tc2.b=3.5

tc2.c[0]=0

tc2.c[1]=1

tc2.c[2]=2

tc2.c[3]=3

tc2.c[0]=4

tc2.c[1]=5

tc2.c[2]=6

tc2.c[3]=7

tc1.c[0]=4

tc1.c[1]=5

tc1.c[2]=6

tc1.c[3]=7

Example: The following code eliminates the problem faced in the previous example by implementing deep cloning.

class TestDeepClone implements Cloneable

{

int a;

double b;

int c[];

public Object clone() throws CloneNotSupportedException

{

TestDeepClone tc = (TestDeepClone) super.clone();

int c[] = new int[4];

for(int i = 0; i < 4; i++)

c[i] = tc.c[i];

return super.clone();

}

}

class DeepCloneDemo

{

public static void main(String a[]) throws CloneNotSupportedException

{

TestDeepClone tc1 = new TestDeepClone();

TestDeepClone tc2;

tc1.a = 10;

tc1.b = 3.5;

int c[] = new int[4];

for(int i = 0; i < 4; i++)

c[i] = i;

tc1.c = c;

for(int i = 0; i < 4; i++)

System.out.println ("tc1.c["+i+"]="+tc1.c[i]);

tc2 = (TestDeepClone) tc1.clone();

System.out.println ("tc2.a="+tc2.a);

System.out.println ("tc2.b="+tc2.b);

for(int i = 0; i < 4; i++)

System.out.println ("tc2.c["+i+"]="+tc2.c[i]);

for(int i = 0; i < 4; i++)

tc2.c[i] = i+4;;

for(int i = 0; i < 4; i++)

System.out.println ("tc2.c["+i+"]="+tc2.c[i]);

for(int i = 0; i < 4; i++)

System.out.println ("tc1.c["+i+"]="+tc1.c[i]);

}

}

Output:

tc1.c[0]=0

tc1.c[1]=1

tc1.c[2]=2

tc1.c[3]=3

tc2.a=10

tc2.b=3.5

tc2.c[0]=0

tc2.c[1]=1

tc2.c[2]=2

tc2.c[3]=3

tc2.c[0]=4

tc2.c[1]=5

tc2.c[2]=6

tc2.c[3]=7

tc1.c[0]=0

tc1.c[1]=1

tc1.c[2]=2

tc1.c[3]=3

2.7 Methods useful in multi-threaded environment

In addition to methods discussed above, Object class provides support for thread communication in synchronized code through the following methods:

final void wait()

Causes current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object.

final void wait(long timeout) throws InterruptedException

Causes current thread to wait until either another thread invokes the notify() method or the notifyAll() method for this object, or some other thread interrupts the current thread, or the specified amount of time has elapsed.

final void wait(long timeout, int nanos) throws InterruptedException


Causes current thread to wait until either another thread invokes the notify() method or the notifyAll() method for this object, or some other thread interrupts the current thread, or the certain amount of time has elapsed.

final void notify()


Wakes up a single thread that is waiting on this object's monitor.

final void notifyAll()

Wakes up all threads that are waiting on this object's monitor. A thread waits on an object's monitor by calling one of the wait methods.

A thread invokes these methods on the object whose lock it holds. A thread waits for notification by another thread.