3

I am struggling to get an interface implementation to be inherited in another class:

I have a generic class that requires compareTo to be implemented. The class is called GenericList and is implemented as:

public class GenericList<T extends Comparable<T>> {
    private T[] items;
    private int count;
    public GenericList() {
        items = (T[]) new Comparable[10];
        count = 0;
    }
}

I have a User class that implements compareTo:

public class User implements Comparable<User> {
    private String email;

    public User(String email) {
        this.email = email;
    }

    @Override
    public int compareTo(User o) {
        return (email.compareTo(o.email));

    }
}

I have no problem creating a GenericList of Users:

var users = new GenericList<User>();

If I create a class that extends User and try to create a generic list of that type, I get an error. I have created a class called Instructor:

public class Instructor extends User{
    public Instructor(String email){
        super(email);
    }
}

If I create a generic list using that class:

var instructors = new GenericList<Instructor>();

I get an error:

Type parameter 'com.martin.Instructor' is not within its bound; should implement 'java.lang.Comparable<com.martin.Instructor>'

Shouldn't it use the inherited compareTo method?

I've tried lots of different ways but I can't get GenericList to use an inherited class like this.

Thanks

6
  • 3
    Instructor inherits compareTo(User). The interface requires compareTo(Instructor). Commented Jan 24, 2022 at 22:25
  • 3
    To clarify, Instructor needs to implement int compareTo(Instructor) even if it just delegates to its superclass. Commented Jan 24, 2022 at 22:27
  • 1
    youcan try to declare public class GenericList<T extends Comparable<? super T>> { private T[] items; Commented Jan 24, 2022 at 22:29
  • 1
    Also, that cast in the GenericList constructor skates by now with type erasure, but would break if we ever get reified generics. Commented Jan 24, 2022 at 22:30
  • 1
    Martin... think about the previous two comments logically. Instructor can have additional fields that are not accounted for when you compare just a generic User. That's why Instructor must have a compareTo() method. Commented Jan 24, 2022 at 22:30

2 Answers 2

4

public class GenericList<T extends Comparable<T>>

When you declare GenericList<Instructor>, then the above declaration replaces T with Instructor. So now it says that Instructor must extend (or implement, really) Comparable<Instructor>. The problem is that Instructor extends User which implements Comparable<User> but doesn't implement Comparable<Instructor>.

So the problem is well before trying to find the inherited compareTo() method. One way to fix the immediate compiler error is to change the GenericList declaration:

public class GenericList<T extends Comparable<? super T>>

This uses a type capture on the Comparable interface.

Now fair warning, I have check that this change will compile here, but otherwise I have not tested it because your question doesn't provide any usages of GenericList once you create it.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks so much for all the advice - worked a treat!
1

The overall logic seems to be correct: User and Comperable are the supertypes of the Instructor class, i.e. instance of Instructor can represent them both. But here's a catch:

var ints1 = (Comparable<Instructor>) new Instructor("name"); // this line will not compline
var ints2 = (Comparable<User>) new Instructor("name"); // no errors here

The first line will cause a compilation error because there's no implementation of the Comparable<Instructor> in the inheritance chain of the Instructor class, but there's an implementation of the Comparable<User> which is the class User itself. And hence the signature of compareTo() method that Instructor class inherits will be compareTo(User user).

A quick reminder: generics are invariant, i.e. to a variable of type List<Object> we can assign only List<Object>, not List<Person> or List<Cat>. Similarly types Comparable<User> and Comparable<Instructor> are not comparable with each other regardless of the fact that User is a super-type of Instructor. That's what is called invariance and the main purpose of it is to enforce type-safety.

As the conscience of this, it isn't possible to coerce Instructor object to Comparable<Instructor> type.

A possible remedy is to implement Comparable in the Instructor class, it will be useful only if Instructor defines some own properties that establish uniqueness of its instances, or change the declaration of generic type as already shown here

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.