Подтвердить что ты не робот

Почему этот общий код создает NoSuchMethodError?

Скажем, у вас есть метод, который

  • принимает пороговое значение и ввод
  • вызывает исключение, если вход меньше порогового значения
  • в противном случае возвращает вход

он выглядит примерно так:

<N extends Number & Comparable<N>, S extends N> S ensureLessThan(N threshold, S input) {
    if (input.compareTo(threshold) >= 0) {
        throw new IllegalArgumentException("Input " + input + " is not less than " + threshold);
    }
    return input;
}

При запуске этот метод выдает NoSuchMethodError:

Exception in thread "main" java.lang.NoSuchMethodError: java.lang.Number.compareTo(Ljava/lang/Object;)I

Добавление того, что выглядит как избыточный бросок, заставляет его работать:

...
    if (((N) input).compareTo(threshold) >= 0) {
...

Итак, что здесь происходит?

UPDATE: моя версия Java

java version "1.6.0_37"
Java(TM) SE Runtime Environment (build 1.6.0_37-b06-434-11M3909)
Java HotSpot(TM) 64-Bit Server VM (build 20.12-b01-434, mixed mode)

И вот пример: https://gist.github.com/4526536

4b9b3361

Ответ 1

Я подозреваю, что это ошибка в компиляторе. Он статически связан с Number.compareTo(Object), который не существует, когда он должен быть Comparable.compareTo(Object).

Ответ 2

if (threshold.compareTo(input) < 0) {

будет работать.

Конечно, это ошибка компилятора. Причина этого заключается в том, что компилятор генерирует проверенный листинг в Comparable. В то время как другой путь вокруг этого не делает.

ensureLessThan(Ljava/lang/Number;Ljava/lang/Number;)Ljava/lang/Number;
  L0
        LINENUMBER 11 L0
        ALOAD 1
        CHECKCAST java/lang/Comparable
        ALOAD 2
        INVOKEINTERFACE java/lang/Comparable.compareTo (Ljava/lang/Object;)I
        IFGE L1

против

ensureLessThan(Ljava/lang/Number;Ljava/lang/Number;)Ljava/lang/Number;
        LINENUMBER 11 L0
        ALOAD 1
        ALOAD 2
        INVOKEVIRTUAL java/lang/Number.compareTo (Ljava/lang/Object;)I
        IFGE L1

Ответ 3

Что странно, следующий код компилируется и работает с моей стороны:

/**
 * @author Buhake Sindi
 * @since 14 January 2013
 *
 */
public class Test {

    public static <N extends Number & Comparable<N>, S extends N> S ensureLessThan(N threshold, S input) {
        if (input.compareTo(threshold) >= 0) {
            throw new IllegalArgumentException("Input " + input + " is not less than " + threshold);
        }
        return input;
    }

    public static void main(String[] args) {
        ensureLessThan(10, 5);
    }
}

Протестировано в Eclipse Juno (Java EE) со следующим JDK:

  • JDK 1.6.0_21.
  • JDK 1.7.0_09-b05