Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to compare Classes and Inherited Classes in Java

I have two classes - Task (which implements Comparable) and DeadlinedTask (where DeadlinedTask extends Task). And for each of them I have written an overloaded compareTo function (each has compareTo(Task) and compareTo(DeadlinedTask)).

The idea is that I can sort normal Tasks by category, and DeadlinedTasks by deadline, but I also want all of the DeadlinedTasks to be sorted above the Tasks.

When I call Collections.sort(myListOfTasks) on a list of only Tasks (no DeadlinedTasks), everything works like a charm. However when I have a list of both Tasks and DeadlinedTasks, the objects change order, but they are not fully sorted.

I have tried returning numbers other than 1 on the interclass compares (1, 1000, 1000000 all did the same thing). Is there any way to do this through compareTo and Collections.sort, is there a different java functionality I can use, or do I have to write my own search function (as a Comparator?)?

Task compareTo Methods:

public int compareTo(Task other){
    if(this.GetCategory().compareTo(other.GetCategory())==0)
        return this.GetName().compareTo(other.GetName());
    else 
        return this.GetCategory().compareTo(other.GetCategory());
}
public int compareTo(DeadlinedTask other){
    return 1;
}

DeadlinedTask compareTo Methods:

public int compareTo(Task other){
    return -1;
}
public int compareTo(DeadlinedTask other){
    if(this.GetDeadline().compareTo(other.GetDeadline())==0)
        return this.GetName().compareTo(other.GetName());
    else 
        return this.GetDeadline().compareTo(other.GetDeadline());
}

Thanks for any help

like image 854
Peter Avatar asked Jan 21 '23 12:01

Peter


2 Answers

... or do I have to write my own search function (as a Comparator?)?

Yes. I think that's the best way.

The normal way to handle equals and compareTo is to return false (for equals) or throw ClassCastException (for compareTo) if the arguments actual type doesn't match the actual type of this.

If you try to implement equals or compareTo for subtypes, you can easily create semantic anomalies such as:

  • a.equals(b) and b.equals(a) returning different values, or
  • a.compareTo(b) and b.compareTo(a) returning inconsistent values.

Avoiding those anomalies would entail making the supertype aware of the subtype. That is a bad from a design perspective because it restricts your ability to create more subtypes in the future.

For use-cases where you need to implement a rule that orders instances of two or more different classes, a Comparator is the best solution.

like image 105
Stephen C Avatar answered Jan 30 '23 01:01

Stephen C


Per class, only one compareTo method can be used to implement the Comparable interface. If you use Comparable without generics, then this is

public int compareTo(Object o)

If you're using generics, e.g. Comparable<Task>, then it's

public int compareTo(Task o)

Your compareTo(DeadlinedTask o) method will be ignored concerning the Comparable<Task> interface. It just "accidentally" has the same name, but it's an independent overloading.

(By the way, it's not possible to implement both Comparable<Task> and Comparable<DeadlineTask>).

So what you'll have to do instead, is change your Task.compareTo(Task o) method to use instanceof (it has to use runtime information after all). I agree with Stephen, that it would even be better to write a Comparator.

like image 43
Chris Lercher Avatar answered Jan 30 '23 00:01

Chris Lercher