0

I'm working on deeper understanding of Java and I was experimenting with comparing the same objects.

I have created two string objects with the same value, but assigned to different variable. It turned out that they have the same hash codes.

After that I have created simple class representing person and created two instances of this class with the same parameters passed to constructor. It turned out that they have different hash codes.

Now I'm confused how does it work. Could you please explain me that?

my code:

 public static class Person {

        public String name;
        public String lastName;

        public Person(String name, String lastName) {
            this.name = name;
            this.lastName = lastName;
        }
    }

    public static void main(String[] args) {

        String s1 = new String("foo");
        String s2 = new String("foo");
        System.out.println("String1 hashcode: " + s1.hashCode());
        System.out.println("String2 hashcode: " + s2.hashCode());
        System.out.println("Is String1 equal to String2?: " + s1.equals(s2));

        Person p1 = new Person("John", "Doe");
        Person p2 = new Person("John", "Doe");
        System.out.println("Person1 hashcode: " + p1.hashCode());
        System.out.println("Person2 hashcode: " + p2.hashCode());
        System.out.println("Is Person1 equal to Person2?: " + p1.equals(p2));

    }
}

my output:

String1 hashcode: 101574
String2 hashcode: 101574
Is String1 equal to String2?: true
Person1 hashcode: 325040804
Person2 hashcode: 1173230247
Is Person1 equal to Person2?: false
s-kaczmarek
  • 161
  • 1
  • 13
  • 1
    Have you read the documentation of [`Object#hashCode`](https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#hashCode--)? It explains the results – UnholySheep May 10 '18 at 19:55

3 Answers3

9

The hashCode method in String computes it hash code solely on the contents of the string.

Returns a hash code for this string. The hash code for a String object is computed as

s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]

However, you haven't declared a hashCode method in Person, so it inherits that method from Object.

As much as is reasonably practical, the hashCode method defined by class Object does return distinct integers for distinct objects.

If a class doesn't override hashCode, then we should expect different hash codes for different objects, regardless of the contents of the object.

Like String, you can define your own hashCode method that determines a Person's hash code based solely on its content.

You should also override equals(Object) so the Person class defines how Person instances are equal to each other; these two methods must be defined consistently:

The general contract of hashCode is:

  • 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.
Community
  • 1
  • 1
rgettman
  • 176,041
  • 30
  • 275
  • 357
  • Thank you for this answer. Could you please give me example of overwritten hashCode and equals method that could be useful in this situation? – s-kaczmarek May 11 '18 at 18:03
1

By default, hashcode is inherited from Object class.

It's native method which returns the integer representation of the memory address. It's clearly explains why two different objects which look like the same are different.

The only case when they could be equal and have the same hashcode - they should refer to the same memory address.

Content-based hashcode (like in String) could be achived overriding hashcode() method inherited from Object.

You must override hashCode in every class that overrides equals. If you fail to do so, your class will violate the general contract for hashCode, which will prevent it from functioning properly in collections such as HashMap and HashSet.

J-Alex
  • 6,881
  • 10
  • 46
  • 64
0

String internal Class has a strong implementation of hashcode and equals and hence when you create two instances of String which would have same memory addresses and check the hashcode it returns same hash.

But the class Person you have implemented doesn't inherit the hashcode and equals of the java.lang.Object implementation to check if both objects are same.

Have updated your code below for your reference by overriding the java.lang.Object hashcode and equals method implementation. This should return you the expected results.

public static class Person {
    public String name;
    public String lastName;

    public Person(String name, String lastName) {
        this.name = name;
        this.lastName = lastName;
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, lastName);

    }

    @Override
    public boolean equals(Object obj) {
        if(obj==null || !(obj instanceof Person))
           return false;
        Person u=(Person) obj;
        return u.name.equals(name) && u.lastName.equals(lastName);
    }
}

public static void main(String[] args) {

    String s1 = new String("foo");
    String s2 = new String("foo");
    System.out.println("String1 hashcode: " + s1.hashCode());
    System.out.println("String2 hashcode: " + s2.hashCode());
    System.out.println("Is String1 equal to String2?: " + s1.equals(s2));

        Person p1 = new Person("John", "Doe");
        Person p2 = new Person("John", "Doe");
        System.out.println("Person1 hashcode: " + p1.hashCode());
        System.out.println("Person2 hashcode: " + p2.hashCode());
        System.out.println("Is Person1 equal to Person2?: " + p1.equals(p2));

    }
}
Eby Jacob
  • 1,418
  • 1
  • 10
  • 28
  • Adding hashcodes is not a good implementation, just use `Objects.hash(name, lastName)`. Also better to use `Objects.equals` in case the fields are null. – Sean Van Gorder May 10 '18 at 20:15