String toString ()
should always be overridden to provide a simple summary of the state of the object (ie, the values of its fields). The inherited version only gives the value of the reference (the JVM's ticket number for finding the object), which is not useful.boolean equals (Object b)
should always be overridden to make it possible to compare two objects by the values of their fields. The version inherited from Object simply compares the references.int hashCode ()
should always be overridden to enable objects of your class to be used as keys in hash tables (we will study those soon). It is very important that hashCode ()
should use the same fields as equals ()
so that a.equals (b)
always implies a.hashCode () == b.hashCode ()
.Object clone ()
should always be overridden so that objects of your class can be copied (not just the references).Class getClass ()
is not normally overridden.void finalize ()
is not normally overriden except for debugging difficult cases. It will be called by the JVM when garbage collection has found there is no longer any reference to the object. May be useful for debugging but do not use in production code.
void notify ()
void notifyAll ()
void wait ()
void wait (long ms)
void wait (long ms, int ns)
We will now look at how to override the first 4 of those.
Should provide a summary of the state of the object, derived from the values of its fields - all of them, or the most important ones if there are very many. In the case of object fields call their toString ()
methods, assuming they have been overridden (programmers too often skip it though).
Very useful for debugging.
public class X extends Y
{
int i; String s; // ... and other data
@Override
public String toString ()
{
return super.toString () + "; " + i + "; " + s;
// ... and all other data.toString ()
// if that is what you want as a string
// representation of the object.
}
//... rest of class definition
If you ever want to test whether 2 objects are identical (not just the same reference) you need to override this method. Some people say you really must always override it for every class you ever write. You certainly must override it for any class whose objects may be used as hash keys. It is also important for unit testing - how else will you test whether the expected result of a method under test is equal to the actual result?
There are some subtleties to beware of though, so again programmers are tempted to skip overriding this method.
public class MyClass
{
@Override
public boolean equals (Object another)
{
if (null == another) return false;
if (!getClass().equals (another.getClass())) return false;
MyClass other = (MyClass) another; // Now safe to cast
if (field1primitive != other.field1primitive) return false;
if (!field2object.equals (other.field2object)) return false;
// ... for all fields
return true; // All tests passed
} // equals
Notice a few things here:
getClass ()
, not just instanceof
. The test must be symmetric: a.equals (b)
must imply b.equals (a)
and that might not be the case with instanceof
: we know that a Customer
is an instance of Person
but not vice versa.equals ()
. And that again assumes that all of their classes have overridden equals ()
- a further reason why you really should get into the habit of doing it.equals ()
even for private fields.transient
in front of them (this is also picked up in the object serialisation process which we will come to soon) and (b) it is vital that you also skip such fields when overriding hashCode ()
.The inherited version returns an integer based on the reference of the object, nothing to do with its contents.
Overridden in String (but not StringBuffer) to make a useful value from the text of the string.
You must override for any class whose objects will be used as keys for a hash table (java.util.HashMap
, etc). The point of a hash table is to be able to look up an object directly from its contents, without searching. We will see how that works soon.
public class MyClass
{
@Override
public int hashCode ()
{
return 7 * field1.hashCode () + 13 * field2.hashCode () + field3;
// ... (say field3 happens to be an int)
} // hashCode
People use prime numbers as multipliers here to try to reduce the chances of two objects ending up with the same hash code. I am not sure whether there is any true mathematical basis for this.
You must use all the same fields you used in your overridden equals ()
method, to ensure that a.equals (b)
always implies a.hashCode () == b.hashCode ()
.
public class Person implements Cloneable
{
private String name;
@Override
public Object clone ()
{
try
{
// Always clone the superclass first, in this case Object:
Person copy = (Person) super.clone ();
// Then copy the fields of this class, using their clone()
// or perhaps a constructor:
copy.name = new String (name);
return copy;
}
catch (CloneNotSupportedException ex)
{
throw new Error ("Should never occur!");
}
} // clone
java.lang.Cloneable
is a marker interface, showing that our class has overridden clone ()
. Marker interfaces have no methods for us to implement.