Java Language


Object Class Methods and Constructor All Versions

Java SE 1.0
Java SE 1.1
Java SE 1.2
Java SE 1.3
Java SE 1.4
Java SE 5
Java SE 6
Java SE 7
Java SE 8
Java SE 9 (Early Access)

This draft deletes the entire topic.

expand all collapse all

Examples

  • 18

    When a Java class overrides the equals method, it should override the hashCode method as well. As defined in the method's contract:

    • Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.
    • If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
    • It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hash tables.

    Hash codes are used in hash implementations such as HashMap, HashTable, and HashSet. The result of the hashCode function determines the bucket in which an object will be put. These hash implementations are more efficient if the provided hashCode implementation is good. An important property of good hashCode implementation is that the distribution of the hashCode values is uniform. In other words, there is a small probability that numerous instances will be stored in the same bucket.

    An algorithm for computing a hash code value may be similar to the following:

    public class Foo {
        private int field1, field2;
        private String field3;
    
        public Foo(int field1, int field2, String field3) {
            this.field1 = field1;
            this.field2 = field2;
            this.field3 = field3;
        }
    
        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if (obj == null || getClass() != obj.getClass()) {
                return false;
            }
    
            Foo f = (Foo) obj;
            return field1 == f.field1 &&
                   field2 == f.field2 &&
                   (field3 == null ? f.field3 == null : field3.equals(f.field3);
        }
    
        @Override
        public int hashCode() {
            int hash = 1;
            hash = 31 * hash + field1;
            hash = 31 * hash + field2;
            hash = 31 * hash + (field3 == null ? 0 : field3.hashCode());
            return hash;
        }
    }
    

    Using Arrays.hashCode() as a short cut

    Java SE 1.2

    In Java 1.2 and above, instead of developing an algorithm to compute a hash code, one can be generated using java.util.Arrays#hashCode by supplying an Object or primitives array containing the field values:

    @Override
    public int hashCode() {
        return Arrays.hashCode(new Object[] {field1, field2, field3});
    }
    
    Java SE 7

    Java 1.7 introduced the java.util.Objects class which provides a convenience method, hash(Object... objects), that computes a hash code based on the values of the objects supplied to it. This method works just like java.util.Arrays#hashCode.

    @Override
    public int hashCode() {
        return Objects.hash(field1, field2, field3);
    }
    

    Note: this approach is inefficient, and produces garbage objects each time your custom hashCode() method is called:

    • A temporary Object[] is created. (In the Objects.hash() version, the array is created by the "varargs" mechanism.)
    • If any of the fields are primitive types, they must be boxed and that may create more temporary objects.
    • The array must be populated.
    • The array must iterated by the Arrays.hashCode or Objects.hash method.
    • The calls to Object.hashCode() that Arrays.hashCode or Objects.hash has to make (probably) cannot be inlined.

    Internal caching of hash codes

    Since the calculation of an object's hash code can be expensive, it can be attractive to cache the hash code value within the object the first time that it is calculated. For example

    public final class ImmutableArray {
        private int[] array;
        private volatile int hash = 0;
    
        public ImmutableArray(int[] initial) {
            array = initial.clone();
        }
    
        // Other methods
    
        @Override
        public boolean equals(Object obj) {
             // ...
        }
    
        @Override
        public int hashCode() {
            int h = hash;
            if (h == 0) {
                h = Arrays.hashCode(array);
                hash = h;
            }
            return h;
        }
    }
    

    This approach trades off the cost of (repeatedly) calculating the hash code against the overhead of an extra field to cache the hash code. Whether this pays off as a performance optimization will depend on how often a given object is hashed (looked up) and other factors.

    You will also notice that if the true hashcode of an ImmutableArray happens to be zero (one chance in 232), the cache is ineffective.

    Finally, this approach is much harder to implement correctly if the object we are hashing is mutable. However, there are bigger concerns if hash codes change; see the contract above.

  • 9

    The toString() method is used to create a String representation of an object by using the object´s content. This method should be overridden when writing your class. toString() is called implicitly when an object is concatenated to a string as in "hello " + anObject.

    Consider the following:

    public class User {
        private String firstName;
        private String lastName;
        
        public User(String firstName, String lastName) {
            this.firstName = firstName;
            this.lastName = lastName;
        }
        
        @Override
        public String toString() {
            return firstName + " " + lastName;
        }
        
        public static void main(String[] args) {
            User user = new User("John", "Doe");
            System.out.println(user.toString()); // Prints "John Doe"
        }   
    }
    

    Here toString() from Object class is overridden in the User class to provide a meaningful data of the object while printing it.

    While using println(), the object's toString() method is implicitly called. Therefore, these statements do the same thing:

    System.out.println(user); // toString() is implicitly called on `user`
    System.out.println(user.toString());
    

    If the toString() is not overridden in the above mentioned User class, System.out.println(user); may return User@659e0bfd as the output, referring to the objects location in memory.

    This is the default implementation of toString() the Object class. If you want to change this functionality in your class, simply override the method.

  • 6

    TL;DR

    == tests for reference equality (whether they are the same object)

    .equals() tests for value equality (whether they are logically "equal")


    equals() is a method used to compare two objects for the equality. The default implementation of the equals() method in the Object class returns true if and only if both references are pointing to the same instance. It therefore behaves the same as comparison by ==.

    public class Foo {
        int field1, field2;
        String field3;
    
        public Foo(int i, int j, String k) {
            field1 = i;
            field2 = j;
            field3 = k;
        }
    
        public static void main(String[] args) {
            Foo foo1 = new Foo(0, 0, "bar");
            Foo foo2 = new Foo(0, 0, "bar");
    
            System.out.println(foo1.equals(foo2)); // prints false
        }
    }
    

    Even though foo1 and foo2 are created with the same fields, they are pointing to two different objects in memory. The default equals() implementation therefore evaluates to false.

    To compare the contents of an object for equality, equals() has to be overridden.

    public class Foo {
        int field1, field2;
        String field3;
    
        public Foo(int i, int j, String k) {
            field1 = i;
            field2 = j;
            field3 = k;
        }
    
        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if (obj == null || getClass() != obj.getClass()) {
                return false;
            }
    
            Foo f = (Foo) obj;
            return field1 == f.field1 &&
                   field2 == f.field2 &&
                   (field3 == null ? f.field3 == null : field3.equals(f.field3));
        }
    
        @Override
        public int hashCode() {
            int hash = 1;
            hash = 31 * hash + this.field1;
            hash = 31 * hash + this.field2;
            hash = 31 * hash + (field3 == null ? 0 : field3.hashCode());
            return hash;
        }
    
        public static void main(String[] args) {
            Foo foo1 = new Foo(0, 0, "bar");
            Foo foo2 = new Foo(0, 0, "bar");
    
            System.out.println(foo1.equals(foo2)); // prints true
        }
    }
    

    Here the overridden equals() method decides that the objects are equal if their fields are the same.

    Notice that the hashCode() method was also overwritten. The contract for that method states that when two objects are equal, their hash values must also be the same. That's why one must almost always override hashCode() and equals() together.

    Pay a special attention to the argument type of the equals method. It is Object obj, not the Foo obj. If you put the latter, that is not an override of the equals method.

    When writing your own class, you will have to write similar logic when overriding equals() and hashCode(). Most IDEs can automatically generate this for you.

    An example of an equals() implementation can be found in the String class, which is part of the core Java API. Rather than comparing pointers, the String class compares the content of the String.

    Java SE 7

    Java 1.7 introduced the java.util.Objects class which provides a convenience method, equals, that compares two potentially null references, so it can be used to simplify implementations of the equals method.

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null || getClass() != obj.getClass()) {
            return false;
        }
    
        Foo f = (Foo) obj;
        return field1 == f.field1 && field2 == f.field2 && Objects.equals(field3, f.field3);
    }
    

    Class Comparison

    Since the equals method can run against any object, one of the first things the method often does (after checking for null) is to check if the class of the object being compared matches the current class.

    @Override
    public boolean equals(Object obj) {
        //...check for null
        if (getClass() != obj.getClass()) {
            return false;
        }
        //...compare fields
    }
    

    This is typically done as above by comparing the class objects. However, that can fail in a few special cases which may not be obvious. For example, some frameworks generate dynamic proxies of classes and these dynamic proxies are actually a different class. Here is an example using JPA.

    Foo detachedInstance = ...
    Foo mergedInstance = entityManager.merge(detachedInstance);
    if (mergedInstance.equals(detachedInstance)) {
        //Can never get here if equality is tested with getClass()
        //as mergedInstance is a proxy (subclass) of Foo
    }
    

    One mechanism to work around that limitation is to compare classes using instanceof

    @Override
    public final boolean equals(Object obj) {
        if (!(obj instanceof Foo)) {
            return false;
        }
        //...compare fields
    }
    

    However, there are a few pitfalls that must be avoided when using instanceof. Since Foo could potentially have other subclasses and those subclasses might override equals() you could get into a case where a Foo is equal to a FooSubclass but the FooSubclass is not equal to Foo.

    Foo foo = new Foo(7);
    FooSubclass fooSubclass = new FooSubclass(7, false);
    foo.equals(fooSubclass) //true
    fooSubclass.equals(foo) //false
    

    This violates the properties of symmetry and transitivity and thus is an invalid implementation of the equals() method. As a result, when using instanceof, a good practice is to make the equals() method final (as in the above example). This will ensure that no subclass overrides equals() and violates key assumptions.

Please consider making a request to improve this example.

Syntax

  • public final native Class<?> getClass()
  • public final native void notify()
  • public final native void notifyAll()
  • public final native void wait(long timeout) throws InterruptedException
  • public final void wait() throws InterruptedException
  • public final void wait(long timeout, int nanos) throws InterruptedException
  • public native int hashCode()
  • public boolean equals(Object obj)
  • public String toString()
  • protected native Object clone() throws CloneNotSupportedException
  • protected void finalize() throws Throwable

Parameters

Parameters

Remarks

Remarks

Still have a question about Object Class Methods and Constructor? Ask Question

Topic Outline