开发者

In generic method <T> doSth(List<T> 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 开发者_JAVA技巧thing
  } else {
    // do another
  }

  return l;
}

Any hints?

Thanks a lot,

Johannes


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.


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)) {
        ...
    }
}


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.


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;
}


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'


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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜