How to avoid traps and correctly override methods from java.lang.Object

Avoid incorrect implementations and bugs by following these guidelines

Page 2 of 3
  1. Don't fail to implement the Cloneable interface if you want your class to be cloneable. The clone method from Object checks that the Cloneable interface has been implemented. If the Cloneable interface hasn't been implemented, a CloneNotSupportedException is thrown when clone is called.

  2. Don't implement clone by using a constructor. The javadoc for the clone method states that it:

    Creates a new object of the same class as this object. It then initializes each of the new object's fields by assigning it the same value as the corresponding field in this object. No constructor is called.

    Notice that "no constructor is called." Avoid implementing clone as follows:

    public class BaseClass implements Cloneable { public BaseClass (/* parameters */) { // Code goes here... }

    // Rest of the class.

    public Object clone () throws CloneNotSupportedException { return new BaseClass (/* parameters */); } }

    There are two reasons to avoid such an approach: First, the contract for clone states that no constructor is called. Second, and more importantly, child classes now return the wrong type from clone. In the example below, the object returned by clone is a BaseClass, not a ChildClass!

        public class ChildClass extends BaseClass
            // Use clone from BaseClass

    Further, the child class cannot override clone to make a deep copy of the member variables in the ChildClass. The following code demonstrates this problem:

    public class ChildClass extends BaseClass { private SomeOtherClass data;

    // Rest of the class.

    public Object clone () throws CloneNotSupportedException { // The cast in the line below throws an exception! // ChildClass newObject = (ChildClass)super.clone();

    // You _never_ get here because the line above throws // an exception. if ( != null) = (SomeOtherClass);

    return newObject; } }

    The first line in clone throws an exception because the clone method in BaseClass returns a BaseClass object not a ChildClass object.

    Summary: Don't implement clone by using a copy constructor.

  3. Avoid using constructors to copy subobjects when possible. Another mistake is to use constructors to copy subobjects when implementing clone. Consider the following example class, which uses Dimension as the subobject:

    import java.awt.Dimension;

    public class Example implements Cloneable { private Dimension dim;

    public void setDimension (Dimension dim) { this.dim = dim; }

    public Object clone () throws CloneNotSupportedException { Example newObject = (Example)super.clone();

    // Notice the use of a constructor below instead of // a clone method call. If you have a sub-class of // Dimension, any data in the sub-class (e.g. a third // dimension value like z) will be lost. // if (this.dim != null) newObject.dim = new Dimension (dim);

    return newObject; } }

    If a child class of Dimension is passed to setDimension, the object returned by clone will be different from the original object. The preferred way to write this clone method would be:

    import java.awt.Dimension;

    public class Example implements Cloneable { private Dimension dim;

    public void setDimension (Dimension dim) { this.dim = dim; }

    public Object clone () throws CloneNotSupportedException { Example newObject = (Example)super.clone();

    // Call 'this.dim.clone()' instead of // 'new Dimension(dim)' // if (this.dim != null) newObject.dim = (Dimension)this.dim.clone();

    return newObject; } }

    Now, if a child class of Dimension is passed to setDimension, it is copied properly when clone is called.

    Unfortunately, while the preferred code above compiles under the Java 2 platform (formerly known as JDK 1.2), it won't compile under JDK 1.1.7. Dimension doesn't implement Cloneable in JDK1.1 and the clone method for Dimension is protected so Example can't call it anyway. This means that under JDK 1.1 you must write Example's clone method using a copy constructor for the Dimension member variable even though you don't want to. If a child of Dimension is passed to setDimension, you'll have a problem if you try to clone an Example object.

    Testing explicitly for Dimension in the clone method is one workaround:

    import java.awt.Dimension;

    public class Example implements Cloneable { private Dimension dim;

    public void setDimension (Dimension dim) { this.dim = dim; }

    public Object clone () throws CloneNotSupportedException { Example newObject = (Example)super.clone();

    if (this.dim != null) { // Test explicitly for Dimension here. Don't test // using the instanceof operator -- it doesn't do // what you want it to. // if (this.dim.getClass() != Dimension.class) throw new CloneNotSupportedException("Wrong sub-class for 'dim'");

    newObject.dim = new Dimension (dim); } return newObject; } }

    This is better than returning a clone object with the wrong data for dim, but it still isn't a good solution.

    Summary: Make copies of member variables using their clone methods if possible.

  4. Pay attention to synchronization on the clone method. clone is a method just like any other. In a multithreaded environment you want to synchronize clone so that the underlying object stays internally consistent while being copied. You must then also synchronize the mutator methods. Note that this is different from a constructor, which almost never needs synchronization.

  5. Sometimes you should treat clone like a constructor. Even though the clone method isn't a constructor, sometimes you should treat it like one. If you do something special in each constructor, like incrementing an "objects created" count, you probably want to do the same thing in the clone method.

  6. Classes used by others should usually implement clone. This is most important when the class is part of a class library used by others who don't have access to the source code. Failing to implement the clone method can cause problems for clients attempting to write their own clone methods -- see the problems with Dimension in (2) above. If you're producing a third-party library, don't force your customers to work around a lack of cloning.

    If you're not producing a third-party library, waiting to implement clone until it's needed for each class is reasonable. This is especially true because once you've overridden clone, you must pay careful attention to overriding clone in all the child classes.

  7. Child classes must pay attention to clone methods inherited from parent classes. Well-written third-party library classes will often implement clone. However, once a class becomes cloneable, that class's children become cloneable, too. If you extend a class that is cloneable, you must consider whether the clone method you inherit (which will make a shallow copy of all of the data in your subclass) does what you want it to. If it doesn't, you must override clone.

Implementing equals and hashCode

Because of their contracts, if you override either the equals or hashCode methods from Object, you must almost certainly override the other method as well. The complicated contracts that go with these methods make overriding them correctly very difficult. Some of the code shipped with the standard Java libraries gets it wrong.

Here are the important contract requirements for the two methods, as documented in the javadoc documentation for java.lang.Object:

  1. The hashCode method must return the same integer value every time it is invoked on the same object during the entire execution of a Java application or applet. It need not return the same value for different runs of an application or applet. The Java 2 platform (Java 2) documentation further allows the hashCode value to change if the information used in the equals method changes.

  2. If two objects are equal according to the equals method, they must return the same value from hashCode.

  3. The equals method is reflexive, which means that an object is equal to itself: x.equals(x) should return true.

  4. The equals method is symmetric: If x.equals(y) returns true, then y.equals(x) should return true also.

  5. The equals method is transitive: If x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true.

  6. The equals method is consistent. x.equals(y) should consistently return either true or false. The Java 2 javadoc clarifies that the result of x.equals(y) can change if the information used in the equals comparisons change.

  7. Finally, x.equals(null) should return false.

Object provides a simple implementation of equals. It just tests the two objects for referential equality: does x equal y? Some of the standard Java classes override this to provide a more useful notion of equality -- usually content equality (i.e., is some or all of the data in the two objects identical?).

The equals implementation of java.lang.String, for example, returns true if the two objects are both String objects containing exactly the same characters in exactly the same order. The equals method of java.awt.Dimension returns true if the passed-in object is a dimension with the same width and height as the Dimension object executing the equals method.

The default implementation of hashCode provided by Object returns something corresponding to the object's address in memory or location in the Java virtual machine's global object array. Again, some of the standard Java classes override this method.

String, for example, overrides the hashCode implementation in Object to return a hash of some or all of the characters making up the String. This allows two String objects with the same characters in the same order to return the same hash value. Dimension uses the hashCode method provided by Object.

Now for the bad news: It's almost impossible to override equals and hashCodefor mutable classes and provide useful, correct and safe implementations for both methods.

To see why, consider the class java.awt.Dimension. This class overrides equals, but not hashCode. Dimension's JDK 1.1 implementation of equals looks like this:

public boolean equals(Object obj) { if (obj instanceof Dimension) { Dimension d = (Dimension)obj; return (width == d.width) && (height == d.height); }

return false; }

This is a fairly reasonable implementation of content equality: if two Dimension objects have the same width and height they're equal, otherwise they aren't. So, what's wrong?

The first problem is that because Dimension doesn't override hashCode, it's possible to have two Dimension objects that are equal, but return different hashCode values. This violates requirement (2) from above.

Second, testing the input parameter using instanceof Dimension creates problems of its own. Consider a child class: ThreeDeeDimension. Objects of type ThreeDeeDimension should test as equal only if they have identical height, width and depth. ThreeDeeDimension might look like this:

import java.awt.Dimension;

public class ThreeDeeDimension extends Dimension { // I don't like public data, but I'll make this public // to be similar to Dimension's width and height. // public int depth;

public ThreeDeeDimension (int width, int height, int depth) { super (width, height); this.depth = depth; }

public boolean equals (


o) { if ((super.equals (o) == true) &&(o.getClass().equals(this.getClass()))) return ((ThreeDeeDimension)o).width == this.width; else return false; } }

Unfortunately, this implementation of equals doesn't meet requirement (4) listed above. The following code snippet shows this:

import java.awt.Dimension;

public class Main { static public void main (String[] args) { Dimension dim = new Dimension (1, 2); ThreeDeeDimension threeDeeDim = new ThreeDeeDimension (1, 2, 3);

// This will print out that the two objects are equal. System.out.println ("dim.equals(threeDeeDim) = " +dim.equals(threeDeeDim));

// And this will print out that the two objects are not equal. System.out.println ("threeDeeDim.equals(dim) = " +threeDeeDim.equals(dim));

// And requirement (4) is that both tests should return the // same result. } }

I can fix this problem by rewriting the equals method of Dimension. If I write equals in Dimension like this, the ThreeDeeDimension class above meets requirement (4):

public boolean equals(Object obj) { if (obj != null && (obj.getClass().equals(this.getClass()))) { Dimension d = (Dimension)obj; return (width == d.width) && (height == d.height); }

return false; }

Now, objects of type ThreeDeeDimension won't return true when compared to objects of type Dimension. You still have a problem with both Dimension and ThreeDeeDimension because they don't meet requirement (2): objects that test as equal should have identical hashCode values. So, how is content-equality implemented in mutable classes? One example with both equals and hashCode is:

public class MutableExample { private int x;

// Constructors and other methods.

public boolean equals (Object o) { // Test for null to meet requirement (7) and also to // avoid a NullPointerException when calling getClass() // below. // // Comparing classes ensures that parent class objects won't test // equal to child class objects. Parent objects should almost // never test equal to child objects. This makes meeting requirements // (4) and (5) possible. // if ((o != null) && (o.getClass().equals(this.getClass()))) { // If you were inheriting directly from a class that // overrode equals, you would insert a line here that // looked like this: // if (super.equals (o) == false) // return false; // // If overriding the equals method from Object, don't // call super.equals(). //

// This is the point. We have already tested the equality // of our parent class. Now we test for equality of the // data added by _this_ child class. This also meets requirement (3).

return ((MutableExample)o).x == this.x; }

return false; }

public int hashCode () { // This meets requirements (1) and (2). You always return the // same value for each object because you always return the // same value for all objects. You also return identical // hashCode values when two objects test as equals because // you always return identical hashCode values. There is no // requirement to return different hashCode values when // two objects test as not equal. // // The only real problem with this implementation is that it // is an almost totally useless implementation of hashCode. // It can turn a Hashtable lookup into a linear search. // // With JDK 1.1 you can't return 'x', because it can change // and the requirements for hashCode are that the same value // must be returned each time hashCode is called on the same object. // // Java 2 (formerly JDK 1.2) allows 'return x'; because Java 2 allows the hashCode // value to change if the underlying data changes. This is more // friendly, but still allows data to be lost in hashtables // if the underlying hashCode value changes. // return 0; } }

This implementation meets all the requirements, including requirement (6) with the clarification provided by Java 2.

Immutable classes make implementing a useful and safe hashCode easier. In this case, you can use the data in the class to generate a hash value because that data will never change. In the example above, if "x" was guaranteed to never change, I could have implemented hashCode like this:

    public int hashCode()
        // Legal, useful and safe, but only because 'x' never changes.
        return x;

The key points to remember when implementing equals and hashCode:

  • These are not simple methods to implement. There are many details specified in each method's contract.

  • You must implement these two methods together. You can rarely implement just one of them.

  • It is difficult to implement a correct, useful, and safe hashCode method for mutable classes. Making classes immutable makes implementing the hashCode and equals methods much easier. Java 2 allows the value returned by hashCode to change if the underlying data changes, but you should be wary of doing this because data can then be stranded in hashtables.

  • You must pay attention to inheritance, especially when implementing equals. This means comparing classes with getClass rather than with instanceof.

  • Once a class has overridden equals and hashCode, the child classes may also require their own implementations.

Implementing toString

The toString method is the easiest of all the methods in Object to override correctly. This is because the contract is so loosely defined. The javadoc for toString reads:

[toString] returns a string representation of the object. In general, the toString method returns a string that "textually represents" this object. The result should be a concise but informative representation that is easy for a person to read. It is recommended that all subclasses override this method.

The toString method for class Object returns a string consisting of the name of the class of which the object is an instance, the at-sign character `@', and the unsigned hexadecimal representation of the hash code of the object.

All of the above requirements are fuzzy. The method must return a "string representation" that in general "textually represents" the objects and should be "concise," but "informative." None of these requirements are as precise as the requirements for clone, hashCode or equals. Nevertheless, it is still possible to implement this method somewhat incorrectly. Consider the following example:

public class BaseClass { private int x;

// Constructors and other member data and methods ...

public String toString() { // This implementation is not quite correct.

return "BaseClass[" + x + "]"; } }

Calling toString on objects of this class will result in output that looks something like this (assuming x equals 4):


The problem here is that someone might extend BaseClass and might not override toString. An example of this is:

    public class Extension extends BaseClass
        // Constructors, member data and methods ...

Now, calling toString on objects of class Extension results in output that looks like this:


The class name reported by toString is wrong! The object is an Extension object and the toString method is reporting it as a BaseClass object. You could blame the Extension class for not implementing toString itself, but the contract for toString only recommends that child classes implement their own version. There is no requirement that child classes do so.

Instead, you should write toString in BaseClass so that it behaves correctly in child classes. You can do this by writing the toString implementation like this:

public String toString() { // This implementation behaves properly in child classes.

return getClass().getName() + "[" + x + "]"; }

Now calling toString on objects of class Extension results in this output:


which is correct.

Implementing finalize

There are only three relatively simple things to remember if you choose to override finalize. First, you should call the finalize method of the parent class in case it has cleanup to do.

| 1 2 3 Page 2