The documentation for compareTo says:
Finally, the implementor must ensure that x.compareTo(y)==0 implies that sgn(x.compareTo(z)) == sgn(y.compareTo(z)), for all z.
Your proposed method does not meet this requirement. For example, suppose
x = Athlete, age = 35, start date = 2000
y = Human, age = 35
z = Athlete, age = 35, start date = 2001
In this example
x.compareTo(y) == 0 // y is not an athlete
x.compareTo(z) < 0 // Both athletes, different start dates.
y.compareTo(z) == 0 // y is not an athlete
If you do not obey the contract for Comparable, the behaviour of Arrays.sort or Collections.sort is unspecified. Ideally you'd get an exception, but the trouble is these sorting methods use different algorithms depending on the size of the array or list, and you are more likely to get an exception thrown for an incorrect compareTo method if the input array or list has a large number of elements. This means that you should test your compareTo method very carefully using long randomly generated arrays, otherwise you may have subtle, hard-to-detect bugs in your code.
A correct compareTo method looks something like this:
public int compareTo(Human other) {
int result = Integer.compare(age, other.age);
if (result != 0)
return result;
if (!(this instanceof Athlete))
return other instanceof Athlete ? -1 : 0;
return other instanceof Athlete
? Long.compare(((Athlete) this).startDate(), ((Athlete) other).startDate())
: 1;
}
This method sorts first by age. If two humans have the same age they are sorted first by type (with athletes coming first). Athletes with the same age are sorted by start date. Non-athletes with the same age do not appear in any particular order.
Finally, note that it is generally better to use polymorphism rather than instanceof. The problem here is that Human implements Comparable<Human>. Therefore the compareTo method must accept a Human, not an Athlete. Even if you override compareTo in Athlete, the argument must be a Human, and you'd have to use instanceof to check the type of the argument anyway (as in @GentianKasa's answer) or write a completely separate method compareToAthlete(Athlete athlete) and do the following in Athlete
@Override
public int compareTo(Human human) {
return -human.compareToAthlete(this); // Note the minus sign!
}
compareToAthlete would need two versions as well. While this works, it means that the logic of the compareTo method is spread over four methods, making it harder to reason about its correctness. In this case, I'd hold my nose and use instanceof.