In generic method doSth(List l), check whether T implements Comparable?

The title basically says it all: if I have a java method that is generic in T, can I find out anything about T? In particular, can I check whether T implements a certain interface or extends a certain class?

I would like to do something like

public <T> List<T> doSth(List<T> l) {

  if(T extends Comparable) {
    // do one thing
  } else {
    // do another
  }

  return l;
}

Any hints?

Thanks a lot,

Johannes

13.10.2009 16:48:48
6 ОТВЕТОВ

No - due to type erasure. At execution time, you don't know the type of T at all.

One option would be to specify the type as another parameter:

public <T> List<T> doSth(List<T> l, Class<T> clazz) {
    if (Comparable.class.isAssignableFrom(clazz)) {
        ...
    }
}
4
13.10.2009 16:52:55
Ergh. Why bring Class into this??
Tom Hawtin - tackline 13.10.2009 18:31:13
@Tom: Because it answers the question? I know having to supply the class is icky, but it does the job...
Jon Skeet 13.10.2009 18:33:16

yes, you can:

public <T> List<T> doSth(List<T> l) {
  //You could also check every element, if there is a chance only some will be comparable
  if (l.size() >0 && l.get(0) instanceof Comparable) {
    // do one thing
  } else {
    // do another
  }

  return l;
}

Note that you are checking what type the elements in "l" are, NOT T - that is the key.

Edit: Changed the code to handle the fact that it was a list - I had missed that in my original reading.

1
13.10.2009 17:05:39
That's wrong for two reasons. 'l' is List so it's not going to be Comparable and it's not what OP wants.
ChssPly76 13.10.2009 16:55:30
@tangens - you are correct, I have corrected my solution for the list problem. Apologies for missing that - apparently my brain is on vacation today
aperkins 13.10.2009 17:06:09
@ChssPly76 I am attempting to infer what they want based on their code, and I edited it to handle to collection metaphor, which I had missed.
aperkins 13.10.2009 17:07:05
@aperkins - your update would work better but it still doesn't handle a case where the collection is empty (and by "doesn't handle" I mean routes control to "do another" which is not what OP implied he wanted). The bottom line here is you can't cheat type erasure. The downvote is not mine, perhaps it'll be removed once they see your update.
ChssPly76 13.10.2009 17:16:18
@ChssPly76 I figured it wasn't. I was simply showing them another way to attempt to determine the type that was inside the list without passing the class of T.
aperkins 13.10.2009 17:25:18

It's not clear whether you want to perform the check at compile-time or at runtime. If you simply want to ensure that the list parameter passed to the method contains certain types of objects, then redefine T appropriately.

For example, to ensure that the compiler will only allow a List<Comparable> to be passed to this method, redefine T as:

public <T extends Comparable<? super T>> List<T> doSth(List<T> l) {
    // Method body omitted
}

You can then use method-overloading (instead of an if-else statement), to ensure the correct code is called for any value of T. In other words, replace this:

public <T> List<T> doSth(List<T> l) {

    if(T extends Comparable) {
        // do one thing
    } else {
        // do another
    }

    return null
}

with these:

public <T extends Comparable<? super T>> List<T> doSth(List<T> l) {
    // do one thing
    return null;
}

public <T> List<T> doSth(List<T> l, Class<T> clazz) {
    // do another
    return null;
}

However, you need to remember choosing which overloaded method to call and generic-type checking is compile-time only! For example, the following code:

List<? extends Serializable> alist = new ArrayList<Integer>();
doSth(alist);

will actually call the second doSth method, because the compile-time type parameter (? extends Serializable) does not implement Comparable, even though the runtime type parameter (Integer) does.

10
13.10.2009 17:21:04

You can do a

public <T extends Comparable<T>> List<T> doSth(List<T> l)

which will allow you to use the Comparable interface on items in 'l'

0
13.10.2009 16:59:57

Well for compile time check Don already gave an answer. For the runtime it's only possible if you also pass a explicit object representing T, for example:
static <T> List<T> doSth(List<T> l, Class<T> tClass) having tClass object representing real class of T you can check if it have implemented comparable via reflection. But compile-time check is much, much better from my point of view.

0
13.10.2009 17:04:33

You should already know at (even before! :) compile time whether T extends Comparable or not, so why not make two methods?

public <T extends Comparable<T>> List<T> doSthComp(List<T> l) {
  // do one thing
  return l;
}

public <T> List<T> doSth(List<T> l) {
  // do another
  return l;
}
1
13.10.2009 17:06:25
You can probably be more generous with the bounds there.
Tom Hawtin - tackline 13.10.2009 18:30:32
Of course you may not know this at compile-time if you're calling it from another generic type... at which point you'd still need the appropriate Class object for my solution to work too. I do hate type erasure...
Jon Skeet 13.10.2009 18:34:30