0

I am getting ClassCastException error. This error occurs when I insert the object that is derived from a class I have created. My code is below: When I run, I always get ClassCastException error. Also, the comparator of my class is shown as null in debugger.

I have written a comparator (as far as I know) and overridden necessary methods.

How can I use a Set<> with a class that I have created and use contains() method?

public class Person implements Comparable<Person>
{
    int age;
    double height;
    public Person(int age, double height)
    {
        this.age = age;
        this.height = height;
    }
    @Override
    public int compareTo(Person person) 
    {
        return age - person.age;
    }
    public boolean equals(Object obj)
    {
        final Person other = (Person) obj;
        if (this.age == other.age)
            return true;
        return false;
    }
    public static void main(String[] args)
    {
        Set<Person> people = new HashSet<>();
        Person p1 = new Person(10, 1.00);
        Person p2 = new Person(11, 1.10);
        Person p3 = new Person(12, 1.20);
        Person p4 = new Person(14, 1.40);
        people.add(p1);
        people.add(p2);
        people.add(p3);
        people.add(p4);
        if(people.contains(12))
            System.out.println("contains");
        else
            System.out.println("does not contain");
    }
}

I have managed to get rid of the error. But now, the output is "does not contain".

Charles
  • 50,943
  • 13
  • 104
  • 142
  • 3
    You should change that `equals` implementation, otherwise you will have a bad time... – Luiggi Mendoza Feb 19 '14 at 03:31
  • 2
    Where exactly are you getting the `ClassCastException`? And what is the error message? – Chthonic Project Feb 19 '14 at 03:35
  • I am getting ClassCastException when I try to call contains() method of a list with full of my objects "Adjacent". –  Feb 19 '14 at 03:49
  • So is the code above in the `Adjacent` class? And what type is the field called `adjacent`? – Dawood ibn Kareem Feb 19 '14 at 03:51
  • adjacent is type of Sensor. Same with the one returns from getSensor() method. –  Feb 19 '14 at 03:57
  • Can you show us the declaration and instantiation of your list, and your call to `contains`? Also, a stack trace would be nice. – Dawood ibn Kareem Feb 19 '14 at 04:02
  • I have written a similar code for you to understand better –  Feb 19 '14 at 04:09
  • OK, this is now a completely different question - but you've got a set of `Person`, and you're looking for an `int` inside. An `int` is not a `Person`. – Dawood ibn Kareem Feb 19 '14 at 04:09
  • 2
    The problem is completely different from what was originally wrote. I think `people.contains(12)` should be changed to `people.contains(p3)`. – tonga Feb 19 '14 at 04:13
  • I want to search the list with respect to ages i.e. "is there a person who is 12 years old?" is there a way to do this? –  Feb 19 '14 at 04:22
  • you should try `people.contains(new Person(12, 1.20))` instead of `people.contains(12)`. – Shoshi Feb 19 '14 at 04:29
  • Creating a brand new object for a comparison is redundant. Moreover, what if the person is not 1.20? –  Feb 19 '14 at 04:38
  • 1
    You completely changed the nature of the question. You should post another one (it's not a bad question). Long story short, you can't call `contains(int)` on a `HashSet`. You really need to wrap it in a `Person`. The contains will only check the identity fields so the "1.20" won't matter. The identity fields are the ones you use for `equals` and `hashcode`. – Joeri Hendrickx Feb 19 '14 at 13:18
  • Use completely changed the question and now answers are not matching up anymore. – Joeri Hendrickx Feb 19 '14 at 13:18

3 Answers3

0

I assume that your class Adjacent implements Comparable interface based on your code. And your class contains a method called getID(). So therefore when you override the compareTo() method, you want to make sure that the object comparison makes sense. I'm not sure what your getID() returns. But it seems like integer. So you might want to change the implementation of compareTo() as follows:

@Override
public int compareTo(Adjacent adj) {

    return this.getId() - adj.getId();
}

So this way the comparison will return negative/zero/positive depending on the ID comparison of two Adjacent class objects.

Also in your overrided equals() method, the implementation is incorrect because two objects are not necessarily equal even if they have the same hash code. A good example of overriding equals and hashCode methods is given in another SO post. Also, in your case, I think you probably don't even need to override equals method since your class implements Comparable interface already.

Community
  • 1
  • 1
tonga
  • 11,749
  • 25
  • 75
  • 96
  • None of that is going to help with the ClassCastException. – Dawood ibn Kareem Feb 19 '14 at 04:00
  • Without the actual code that throws the exception, I can't tell what the cause is. But those are the points I can see from the post where the problems might come from. – tonga Feb 19 '14 at 04:03
  • No, those issues won't cause ClassCastException. The reason why Stack Overflow lets us post comments under a question is so that we can ask for the actual information we need _before_ we post an answer, not the other way round. – Dawood ibn Kareem Feb 19 '14 at 04:05
0

Don't call contains with a parameter that's a different type; this behavior is actually documented. The contains() method is a non-generic method for legacy reasons, and it's not safe if you're using a TreeSet. If you implement hashCode() and equals() and switch to a HashSet, your problems will go away.

Do you really need people sorted by age?

Edit: I see what you're trying to do, now. You don't want a Set, you want Map<Integer, Collection<Person>>, or just a single pass loop to look for the given age.

for (Person p : people) {
    if (p.age == 12) ...;
}

or

Map<Integer, Set<Person> peopleByAge = new HashMap<Integer, Set<Person>>();
for (Person p : people) {
    if (!peopleByAge.contains(p.age)) {
        peopleByAge.put(p.age, new TreeSet<Person>();
    }
    peopleByAge.get(p.age).add(p);
}

if (people.age.containsKey(12)) ...
David Ehrmann
  • 7,366
  • 2
  • 31
  • 40
0

What I am about to suggest has nothing to do with ClassCastException, which is thrown simply because you are checking contains with an int argument on a set of objects of type Person ... short answer: you can't cast an object to a subclass of which it is not an instance. Even the javadoc says exactly that.

For situations like this, I really like to use Guava predicates. A predicate allows you to apply a boolean condition to any iterable, returning those elements that satisfy the specified condition. In your example, you can define predicates that return the subset of people of whatever age you want.

Predicate<Person> getAgePredicate(final int age) {
    return new Predicate<Person>() {
        public boolean apply(Person p) { return p.age == age; }
    };

}

Set<Person> people = new Hashset<>();
... // populate people
Set<Person> peopleOfAgeTwelve = Sets.filter(people, getAgePredicate(12));

Hope this helps.

Chthonic Project
  • 8,216
  • 1
  • 43
  • 92