user2391210
user2391210

Reputation: 63

Overriding a compareTo from an extended class - what's going on?

I've been trying to override a compareTo in such a way: This is the original:

@Override
public int compareTo(ProductPart6 s)
{
    return this.getproductName().compareTo(s.getproductName());

}

this is what i'm trying to override it with: it throws an error The method compareTo(SubClass) of type SubClass must override or implement a supertype method.

@Override
    public int compareTo(SubClass s)
    {
        return this.getTitle().compareTo(s.getTitle());

    }

I'm thinking this is very wrong. My ProductPart6 doesn't have a getTitle() and that causes it

@Override
    public int compareTo(ProductPart6 s)
    {
        return this.getTitle().compareTo(s.getTitle());

    }

to throw an error (getTitle() is undefined for the type ProductPart6) - if I defined it there there'd be no point overriding it. What am I doing wrong? I have the SubClass extending ProductPart6 and ProductPart6 implements Comparable - I thought I could implement it on SubClass, but no. That was a no go.

Upvotes: 6

Views: 4958

Answers (2)

ajb
ajb

Reputation: 31699

To expand on @ATG's answer: If you have this class:

public class Alpha implements Comparable<Alpha> {
    @Override
    public int compareTo(Alpha a) {
        ...
    }
}

you can use this class in contexts that require Comparable, such as SortedSet<Alpha>. But when you have a SortedSet<Alpha>, the elements of the set can be of class Alpha or any subclass, including Bravo:

public class Bravo extends Alpha {...}

Since the set can have both objects of type Alpha and Bravo in it, the set operations need the ability to compare objects of one type with that of the other, in either order. It might call

A.compare(B);

where A is an Alpha and B is a Bravo. This will call the compareTo method you wrote in Alpha. It might also call

B.compare(A);

where again A is an Alpha and B is a Bravo. That's why it's wrong to declare

@Override
public int compareTo(Bravo b) { ... }

in the Bravo class, because this would prevent B.compare(A) from being called. Not only do you need to declare it like this:

@Override
public int compareTo(Alpha a) { ... }

it also has to work right when it's called with a Bravo and an Alpha. Also, the method in Alpha must work right when its parameter is a Bravo, and the effect has to be that compareTo gives you a proper total ordering no matter which combination of types is passed to it.

If your intent is that each array or collection will contain only objects whose class is Alpha, or only objects whose class is Bravo, you'd need some other mechanism to ensure that everything is the same class, or else don't use a subclass at all (which is what I think @ATG was getting at).

Upvotes: 4

ATG
ATG

Reputation: 1707

When a class implements Comparable<T> you have to specify the type of object (T) against which instances of your class can be compared. All sub-implementations of compareTo must also accept the same type parameter, T.

Let's consider two classes:

public class Alpha implements Comparable<Alpha> {
    @Override
    public int compareTo(Alpha a) {
        ...
    }
}

and...

public class Bravo extends Alpha {...}

If you try to override compareTo in Bravo you must provide a parameter of type Alpha because Alpha is the type that satisfies T in the class declaration (where implements Comparable is included). Otherwise, it won't override the supertype method and thus the compiler complains about the @Override annotation, which is what you're seeing here.

In your case, I think you need to consider whether ProductPart6 and SubClass are compatible enough to be used in this way. If not, consider using separate Comparator instances instead or refactoring to create a common type that will satisfy T in both cases.

Upvotes: 5

Related Questions