stonar96
stonar96

Reputation: 1461

Java HashSet contains Object

I made my own class with an overridden equals method which just checks, if the names (attributes in the class) are equal. Now I store some instances of that class in a HashSet so that there are no instances with the same names in the HashSet.

My Question: How is it possible to check if the HashSet contains such an object. .contains() wont work in that case, because it works with the .equals() method. I want to check if it is really the same object.

edit:

package testprogram;

import java.util.HashSet;
import java.util.Set;

public class Example {
    private static final Set<Example> set = new HashSet<Example>();
    private final String name;
    private int example;

    public Example(String name, int example) {
        this.name = name;
        this.example = example;
        set.add(this);
    }

    public boolean isThisInList() {
        return set.contains(this);
        //will return true if this is just equal to any instance in the list
        //but it should not
        //it should return true if the object is really in the list
    }

    public boolean remove() {
        return set.remove(this);
    }

    //Override equals and hashCode
}

Sorry, my english skills are not very well. Please feel free to ask again if you don't understand what I mean.

Upvotes: 3

Views: 14377

Answers (6)

DoubleDouble
DoubleDouble

Reputation: 1493

HashSet contains uses the equals method to determine if the object is contained - and duplicates are not kept within the HashSet.

Assuming your equals and hashcode are only using a name field...

HashSet<MyObject> objectSet = new HashSet<MyObject>();
MyObject name1Object = new MyObject("name1");

objectSet.add(new MyObject("name1"));
objectSet.add(name1Object);
objectSet.add(new MyObject("name2"));
//HashSet now contains 2 objects, name1Object and the new name2 object
//HashSets do not hold duplicate objects (name1Object and the new object with name1 would be considered duplicates)

objectSet.contains(new MyObject("name1")) // returns true
objectSet.contains(name1Object)           // returns true
objectSet.contains(new MyObject("name2")) // returns true
objectSet.contains(new MyObject("name3")) // returns false

If you wanted to check if the object in the HashSet is the exact object you are comparing you would have to pull it out and compare it directly using ==

for (MyObject o : objectSet)
{
    if (o == name1Object)
    {
        return true;
    }
}

If you do this alot for specific objects it might be easier to use a HashMap so you don't have to iterate through the list to grab a specific named Object. May be worth looking into for you because then you could do something like this:

(objectMap.get("name") == myNameObject) // with a HashMap<String, MyNameObject> where "name" is the key string.

Upvotes: 0

that other guy
that other guy

Reputation: 123470

I made my own class with an overridden equals method which just checks, if the names (attributes in the class) are equal.

This breaks the contract of .equals, and you must never do it no matter how convenient it seems.

Instead, if you want to index and look up elements by a certain attribute such as the name, use a HashMap<Name, YourType> to find them. Alternatively, use a TreeSet and pass it a Comparator that compares the name only. You can then remove the incorrect equals method.

There are then three ways if you want to find objects by reference equality:

  1. Your objects have no inherent or useful notion of equality.

    Don't implement equals. Leave it to its default. You can then use a HashSet to look for reference equality, and a HashMap or TreeSet to index them by any specific attributes.

  2. Your objects do have a useful, universal notion of equality, but you want to find equivalent instances efficiently anyways.

    This is almost never the case. However, you can use e.g. an Apache IdentityMap.

  3. You don't care about efficiency.

    Use a for loop and == every element.

Upvotes: 0

aadi53
aadi53

Reputation: 449

try this.. Considering only one property 'name' of your Objects to maintain uniqueness.

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

@Override
public boolean equals(Object obj) {
    if (this == obj) {
        return true;
    }
    if (obj == null) {
        return false;
    }
    if (getClass() != obj.getClass()) {
        return false;
    }
    User other = (User) obj;
    if (name == null) {
        if (other.name != null) {
            return false;
        }
    } else if (!name.equals(other.name)) {
        return false;
    }
    return true;
}

Upvotes: 1

Frank
Frank

Reputation: 33

The way to check if objects are the same object is by comparing them with == to see that the object references are equal.

Kind Greetings, Frank

Upvotes: 2

GreyBeardedGeek
GreyBeardedGeek

Reputation: 30088

In your situation, the only way to tell if a particular instance of an object is contained in the HashSet, is to iterate the contents of the HashSet, and compare the object identities ( using the == operator instead of the equals() method).

Something like:

boolean isObjectInSet(Object object, Set<? extends Object> set) {
   boolean result = false;

   for(Object o : set) {
     if(o == object) {
       result = true;
       break;
     }
   }

   return result;
}

Upvotes: 2

MJSG
MJSG

Reputation: 1025

You will have to override the hashCode method also.

Upvotes: 0

Related Questions