Skip to content

Common Methods

The Object class sits on top of the Java class hierarchy and every other object in Java is inherited from it indirectly. As such, the set of methods defined in Object class is inherited by all classes, most notably the following:

  • boolean equals(Object obj): indicates if this object is “equal to” the other one.
  • protected void finalize(): called by the garbage collector on an object when garbage collection determines that there are no more references to the object.
  • int hashCode(): returns a hash code value for the object.
  • String toString() returns a string representation of the object.
  • protected Object clone(): creates and returns a copy of this object.
  • void notify(), void notifyAll(): wakes up a single thread that is waiting on this object’s monitor.
  • void wait(), void wait(long timeout), void wait(long timeout, int nanos): causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object.

equal

Java allows the classes to define their own rules of equality by overriding the method equals(Object class). It sounds like a powerful idea but the correct implementation of the equals method should adhere to a set of rules and satisfy the following constraints:

  • Reflexive: Object x must be equal to itself and equals(x) must return true.
  • Symmetric: If equals(y) returns true then y.equals(x) must also return true.
  • Transitive: If equals(y) returns true and y.equals(z) returns true, then x.equals(z) must also return true.
  • Consistent: Multiple invocation of equals() method must result into the same value, unless any of the properties used for equality comparison are modified.
  • Equals To Null: The result of equals(null) must be always false.
public class User {
  private final String firstName;
  private final String lastName;
  private final String email;
  public User( final String firstName, final String lastName, final String email ) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.email = email;
  }
  public String getEmail() {
    return email;
  }
  public String getFirstName() {
    return firstName;
  }
  public String getLastName() {
    return lastName;
  }
  // @Override annotation change the default implementation.
  @Override
  public boolean equals( Object obj ) {
    // Step 1: Check if the ’obj’ is null
    if ( obj == null ) {
      return false;
    }
    // Check if the ’obj’ is pointing to the this instance
    if ( this == obj ) {
      return true;
    }
    // Check classes equality
    if ( getClass() != obj.getClass() ) {
      return false;
    }
    // Check individual fields equality
    final User other = (User) obj;
    if ( email == null ) {
      if ( other.email != null ) {
        return false;
      }
    } else if( !email.equals( other.email ) ) {
      return false;
    }
    if ( firstName == null ) {
      if ( other.firstName != null ) {
        return false;
      }
    } else if ( !firstName.equals( other.firstName ) ) {
      return false;
    }
    if ( lastName == null ) {
      if ( other.lastName != null ) {
        return false;
      }
    } else if ( !lastName.equals( other.lastName ) ) {
      return false;
    }
    return true;
  }
}

finalize

finalize() method is a protected and non-static method of java.lang.Object class. This method will be available in all objects you create in java. This method is used to perform some final operations or clean up operations on an object before it is removed from the memory. you can override the finalize() method to keep those operations you want to perform before an object is destroyed. Here is the general form of finalize() method.

protected void finalize() throws Throwable {
    // Keep some resource closing operations here
}

hashCode

By overriding equals() method, you override the hashCode() method as well. If any of two objects equals() method returns true, then the hashCode() method of each must return the same integer value (the opposite way is not as strict: if any of two objects equals() method returns false, their hashCode() methods may or may not return the same integer value). Let us take a look on hashCode() method for the User class.

@Override
public int hashCode() {
  final int prime = 31;
  int result = 1;
  result = prime * result + ( ( email == null ) ? 0 : email.hashCode() );
  result = prime * result + ( ( firstName == null ) ? 0 : firstName.hashCode() );
  result = prime * result + ( ( lastName == null ) ? 0 : lastName.hashCode() );
  return result;
}

toString

The toString() is one of the most interesting method among the others and is used more frequently. It to provide the string representation of the object. It can simplify debugging and troubleshooting of the issues in the running systems. The default toString() implementation is too simple and just returns the class name and object hash code, separated by @, for example: com.kobdan.advanced.objects.User@7105e2fe

We can improve the implementation and override the toString() method for the User class from above example.

@Override
public String toString() {
  return String.format( "%s[email=%s, first name=%s, last name=%s]",
               getClass().getSimpleName(), email, firstName, lastName );
}

toString() provides the string version of the User class instance with all its fields included. For example:

final User user = new User( "John", "Smith", "john.smith@domain.com" );
System.out.println( user.toString() );
/* the output will be:
  User[email=john.smith@domain.com, first name=John, last name=Smith]

clone

clone() method creates a new instance of the current object class and initializes all of its fields with exactly the contents of that object's corresponding fields.

for implementing the clone() method the following points must be considered: * the method is declared protected in Object class, so in order to make it visible, it should be overridden as public with return type of the overriding class itself. * the overriding class should implement the Cloneable interface (which is a marker or interface) otherwise CloneNotSupportedException exception will be raised. * the implementation should call super.clone() first and then perform additional actions if needed.

public class Person implements Cloneable {
  @Override
  public Person clone() throws CloneNotSupportedException {
    return ( Person ) super.clone();
  }
}

Exercise

  • Exercise 1:
    • Write the class Person with first name, last name, email address and telephon:
      • Override:
        • equal method
        • hashCode method
        • toString method
        • clone method