27

I want to define a class that implements the generic Comparable interface. While in my class I also defined a generic type element T. In order to implement the interface, I delegate the comparison to T. Here is my code:

public class Item<T extends Comparable<T>> implements Comparable<Item> {

    private int s;
    private T t;

    public T getT() {
        return t;
    }

    @Override
    public int compareTo(Item o) {
        return getT().compareTo(o.getT());
    }
}

When I try to compile it, I get the following error information:

Item.java:11: error: method compareTo in interface Comparable<T#2> cannot be applied to given types;
        return getT().compareTo(o.getT());
                     ^
  required: T#1
  found: Comparable
  reason: actual argument Comparable cannot be converted to T#1 by method invocation conversion
  where T#1,T#2 are type-variables:
    T#1 extends Comparable<T#1> declared in class Item
    T#2 extends Object declared in interface Comparable
1 error

Can anybody tell me why and how to fix it?

Radiodef
  • 37,180
  • 14
  • 90
  • 125
frank.liu
  • 477
  • 1
  • 5
  • 11

4 Answers4

27

Item (without any type argument) is a raw type, so:

  1. We could pass any kind of Item to Item.compareTo. For example, this would compile:

    new Item<String>().compareTo(new Item<Integer>())
    
  2. The method o.getT() returns Comparable instead of T, which causes the compilation error.

    In the example under the 1st point, after passing Item<Integer> to Item.compareTo, we would then erroneously pass an Integer to String.compareTo. The compilation error prevents us from writing the code which does that.

I think you just need to remove the raw types:

public class Item<T extends Comparable<T>>
implements Comparable<Item<T>> {

    ...

    @Override
    public int compareTo(Item<T> o) {
        return getT().compareTo(o.getT());
    }
}
Radiodef
  • 37,180
  • 14
  • 90
  • 125
10

You're using raw types in your class definition (Item<T> is generic, but you're omitting the type parameter <T>), change it to:

class Item<T extends Comparable<T>> implements Comparable<Item<T>>

(Note the last <T>)

The compareTo method will then have to be changed as well:

public int compareTo(Item<T> o) { // again, use generics
    return getT().compareTo(o.getT());
}
Njol
  • 3,271
  • 17
  • 32
1

I think, this makes more sense. I have compiled and tested the following :

class Item<E extends Comparable<E>> implements Comparable<E> {

 private int s;
 private E t;

 public E getE() {
     return t;
 }

 @Override
 public int compareTo(E e) {
     return getE().compareTo(e);
 }

 public int compareTo(Item<E> other)
    {
        return getE().compareTo(other.getE());
    }

 }

Notice that you now need to have two compareTo methods.

aditya
  • 182
  • 4
  • 13
  • 1
    The asker wants items to be comparable (by comparing their values). – Njol Feb 04 '14 at 13:16
  • It's possible if T implements Comparable, which is the case here. – Njol Feb 05 '14 at 11:22
  • Ya, please have a look at the other solution that I have given now. – aditya Feb 05 '14 at 11:40
  • Your answer doesn't make much sense at all. "we are extending comparable and not implementing it." - one implements interfaces and extends classes. `extends` is used in generics for both cases though. "because we are using a generic type T, we must not override compareTo method" - generic types don't prevent us from implementing interfaces, e.g. `ArrayList` implements `List`. "T can be anything [...] Specifically, it has to be something that is Comparable" - T already is `Comparable`, in both the OP's code and your code, in particular it is comparable to itself. – Njol Feb 06 '14 at 14:30
  • PLease have a look at the current answer, have changed it completely. – aditya Feb 07 '14 at 06:42
  • 1
    That's certainly better. – Njol Feb 07 '14 at 09:10
0

A bit of a related issue that I ran into, and couldn't find a concrete answer.

Suppose you have an interface

public interface myInt extends Comparable<myInt>

And a class MyClass that implements myInt.

Now you only want to compare MyClass with MyClass objects. How should we rewrite the interface and the class?

Answer:

public interface myInt<T extends myInt<T>> extends Comparable<T>
public class MyClass implements myInt<MyClass>
keesp
  • 301
  • 2
  • 13