user1613360
user1613360

Reputation: 1314

Java compareTo() method returns classCastException

Let's assume I have an Employee base class and Manager subclass which extends Employee.Now let's say I create an object x of type Employee and object y of type Manager and call x.compareTo(y) no exception is triggered and x and y is compared as Employees namely y is cast to an Employee but when I call y.compareTo(x) I get a classCastException.I need to know why this happens and how to prevent x.compareTo(y) to execute as x and y are from different classes.My idea is to use getclass() method in Reflection class like this:

if (getClass() != other.getClass()) 
throw new ClassCastException();

I also want to know is there any other way to implement this.

Upvotes: 3

Views: 2122

Answers (6)

user3709525
user3709525

Reputation: 281

You could perhaps use isAssignableFrom which will return true or false and then use it for doing further comparison or equals etc. Not sure why you would need this in compareTo; however.

Anyways assuming name , salary for an employee and set of reportees for manager and then for example further just comparing salaries as part of compareTo.

public class Test{   
    public static void main(String[] args) {
        class Employee implements Comparable<Employee> {
            public Employee(String string, int salary) {
                this.name = string;
                this.salary = salary;
            }

            public Employee() {
                name = "";
                salary = 0;
            }

            String name;
            Integer salary;

            public int compareTo(Employee o) {
                return o!=null && getClass().isAssignableFrom(Employee.class)
                        ? salary.compareTo(o.salary) : Integer.MIN_VALUE;
            }

        }

        class Manager extends Employee {
            public Manager(String name, String[] subordinates) {
                super(name, 1000000);
                reportees = subordinates;
            }

            String[] reportees;
        }

        Employee e = new Employee("me", 1000);
        Employee e1 = new Employee("mycolleague", 2000);
        Manager m = new Manager("myboss", "me mycolleague".split(" "));
        System.out.println(e1.compareTo(e));
        System.out.println(e.compareTo(m));
        System.out.println(m.compareTo(e)); // this gives INT.MIN as you cannot compare manager to employee
    }

}

Upvotes: 0

Sanjay Rabari
Sanjay Rabari

Reputation: 2081

here Manager is a Employee.

but Employee is not Manager.

Quote from Effective Java, Item 12:

Let’s go over the provisions of the compareTo contract. The first provision says that if you reverse the direction of a comparison between two object refer- ences, the expected thing happens: if the first object is less than the second, then the second must be greater than the first; if the first object is equal to the second, then the second must be equal to the first; and if the first object is greater than the second, then the second must be less than the first. The second provision says that if one object is greater than a second, and the second is greater than a third, then the first must be greater than the third. The final provision says that all objects that compare as equal must yield the same results when compared to any other object.

One consequence of these three provisions is that the equality test imposed by acompareTo method must obey the same restrictions imposed by the equals con- tract: reflexivity, symmetry, and transitivity. Therefore the same caveat applies: there is no way to extend an instantiable class with a new value component while preserving the compareTo contract, unless you are willing to forgo the benefits of object-oriented abstraction (Item 8). The same workaround applies, too. If you want to add a value component to a class that implements Comparable, don’t extend it; write an unrelated class containing an instance of the first class. Then provide a “view” method that returns this instance. This frees you to implement whatever compareTo method you like on the second class, while allowing its cli- ent to view an instance of the second class as an instance of the first class when needed.

Upvotes: 2

Abhishek Mishra
Abhishek Mishra

Reputation: 639

If your are using compareTo method then i am excepting you have implemented Comparable interface in your class and provide a implementation of the method compareTo. let me know how you are comparing object on what logic ,based on that only you get the solution.

I have little bit confuse on this 
if (getClass() != other.getClass()) 
throw new ClassCastException();

if it is the code in your compareTo method then rather then doing this create one more interface say "XYZ" and implement that Interface to both the class
check the logic 


    public int compareTo(T obj){
    if(this instanceof XYZ &&  obj instanceof XYZ)){
return 0;
    }else{
    throw new ClassCastException();
    }
    }

Upvotes: 0

Bipin Bhandari
Bipin Bhandari

Reputation: 2692

All Manager are Employee but not all Employee are Managers. Since all the attributes of Employee are available in Manager,Manager can be casted to Employee. But attributes of Manager is unavailable to Employee, so cast is not possible.

My suggestion is to override compareTo() method in your classes and cast the object Employee.

Upvotes: 0

Nir Alfasi
Nir Alfasi

Reputation: 53525

You should implement compareTo() in the class Employee and start it with:

Employee o = (Employee)other;

Then continue with comparing this to o - this will ensure you're comparing two Employees (which is the lowest common denominator).

Upvotes: 3

Deepak
Deepak

Reputation: 2895

Because your Manager is an Employee but Employee is not a Manager See below

http://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html

instance of can be usefull in such cases

Upvotes: 2

Related Questions