Alex Rivera | Logout

HashSet contains problem with custom objects

Asked 2011-02-24T20:56:41.277
16

My Custom class that will be contained by HashSet

public class Person {
    String name;
    int age;

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

    @Override
    public String toString() {
        return "Person{" +
                "hashcode='" + this.hashCode() + '\'' +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Person)) return false;

        Person person = (Person) o;

        if (age != person.age) return false;
        if (!name.equals(person.name)) return false;

        return true;
    }

    @Override
    public int hashCode() {
        int result = name.hashCode();
        result = 31 * result + age;
        return result;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

My HashSet test that fails

   public void hashSetTest() {
        Set<Person>  personSet = new HashSet<Person>();
        Person p1 = new Person("raghu", 12);
        Person p2 = new Person("rimmu", 21);

        personSet.add(p1);
        personSet.add(p2);


       p1.setName("raghus");
       p1.setAge(13);

       int i2 =p1.hashCode();
       System.out.println(personSet.size() + ": "+ p1.hashCode()+" : "+personSet.contains(p1)+ " : "+i2);
    }

Iam expecting personSet.contains(p1) to pass. Why is it returning false? Thanks sri

Edit
Report

1 Answer

1

Hashes are simple pairing of key and values. Here's how the state of your code would look before and after the renaming in pseudo-code:

Before:

personSet => {
    SOME_NUM1 => Person(name=>"raghu", 12),
    SOME_NUM2 => Person(name=>"rimmu", 21)
}

p1.setName("raghus"); #p1.hashcode() = SOME_NEW_NUM
p1.setAge(13);#p1.hashcode() = SOME_OTHER_NEW_NUM

After:

personSet => {
    SOME_NUM1 => Person(name=>"raghu", 13),
    SOME_NUM2 => Person(name=>"rimmu", 21)
}

Since you have direct access to the p1 the object within the HashSet is updated correctly, but HashSet does not pay attention to contained objects hashcodes being updated. When a call to personSet.contains(p1) is called, the HashSet looks for an entry with the new value of p1.hashcode().

The p1 object is associated with its previous hashcode at the time when it was added to the HashSet.

answered 2011-02-24T21:37:24.790

Your Answer