Search code examples
javaclasscastexceptioncomparatorcompareto

I'm getting ClassCastException even though I overriden compareTo()


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".


Solution

  • 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.