В универсальном методе <T>doSth (Список <T>l) проверьте, реализует ли T Comparable? - PullRequest
0 голосов
/ 13 октября 2009

Название в основном говорит само за себя: если у меня есть Java-метод, который является общим для T, могу ли я узнать что-нибудь о T? В частности, могу ли я проверить, реализует ли T определенный интерфейс или расширяет определенный класс?

Я хотел бы сделать что-то вроде

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

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

  return l;
}

Есть подсказки?

Большое спасибо,

Johannes

Ответы [ 6 ]

10 голосов
/ 13 октября 2009

Не ясно, хотите ли вы выполнить проверку во время компиляции или во время выполнения. Если вы просто хотите убедиться, что параметр списка, переданный методу, содержит объекты определенного типа, переопределите T соответствующим образом.

Например, чтобы компилятор позволял передавать этому методу только List<Comparable>, переопределите T как:

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

Затем можно использовать перегрузку метода (вместо оператора if-else), чтобы гарантировать, что правильный код вызывается для любого значения T. Другими словами, замените это:

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

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

    return null
}

с этими:

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

Однако, вам нужно помнить выбор того, какой перегруженный метод вызывать, и проверка универсального типа выполняется только во время компиляции ! Например, следующий код:

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

фактически вызовет второй метод doSth, поскольку параметр типа времени компиляции (? extends Serializable) не реализует Comparable, хотя параметр типа времени выполнения (Integer) делает.

4 голосов
/ 13 октября 2009

Нет - из-за типа стирания . Во время выполнения вы вообще не знаете тип Т.

Один из вариантов - указать тип в качестве другого параметра:

public <T> List<T> doSth(List<T> l, Class<T> clazz) {
    if (Comparable.class.isAssignableFrom(clazz)) {
        ...
    }
}
1 голос
/ 13 октября 2009

Вы должны уже знать (даже до! :) времени компиляции, расширяет ли T Comparable или нет, так почему бы не сделать два метода?

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 октября 2009

да, вы можете:

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

Обратите внимание, что вы проверяете, какой тип элементов в "l", а НЕ T - это ключ.

Изменить: Изменен код для обработки факта, что это был список - я пропустил это в моем первоначальном чтении.

0 голосов
/ 13 октября 2009

Ну, для проверки времени компиляции Дон уже дал ответ. Для среды выполнения это возможно только в том случае, если вы также передаете явный объект, представляющий T, например:
static <T> List<T> doSth(List<T> l, Class<T> tClass) Имея объект tClass, представляющий реальный класс T, вы можете проверить, реализован ли он с помощью отражения. Но проверка во время компиляции намного лучше с моей точки зрения.

0 голосов
/ 13 октября 2009

Вы можете сделать

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

, что позволит вам использовать интерфейс Comparable для элементов в 'l'

...