A lot of good answers has been given above but it seems to me that lacks a conceptual cornerstone: the distinction between state and instance identity.
If hashCode() method is not overridden in a class, it means that two instances of that class, even if they have the same state (i.e. identical class fields) and therefore are not substantially distinguishable, remain two distinct objects, with their own identity. For example, if they are added to a Set, they occupy two different slot in the underlying Map.
If instead you redefine hashCode() you usually do this to identify an instance of the class with its state. For example, if you have a Person class with the name (String) and age (int) fields, in hashCode() you will create a function that uniquely maps the name/age pair so that if you have two distinct instances of Person but with the same values for name and age, in Java they will be treated as the same instance respect to equals operator. If you add them to a Set, for example, they occupy the same slot. A lot of objects in JDK do this thing, for example java.io.File class.
Even if the hashCode() method is redefined in a class to reflect its state, two instances with identical state are still two distinct objects for the JVM, each occupying its own memory area. The identity hash of these objects, stored in the object header (in the mark word), is always distinct because it is calculated by the JVM and this value is the one returned by System.identityHashCode() .
Returning to the Person class example the following code
Person p1 = new Person("jack", 20); Person p2 = new Person("jack", 20); System.out.println(p1.equals(p2)); System.out.println(p1 == p2);
returns both false if hashCode() method is not overwritten, otherwise return true and false.
Note that == operator doesn't care of hashCode() method: it simply compares if two object references points to the same physical object, regardless of its state, and so uses always System.identityHashCode().