Генераторы Java и класс Number

Я хочу создать метод, который сравнивает число, но может иметь вход, который является любым из подклассов Number.

Я посмотрел на это следующим образом...

public static <T extends Number> void evaluate(T inputNumber) {
  if (inputNumber >= x) {
    ...
  }
}

Мне нужно получить фактический примитив, прежде чем я смогу выполнить сравнение, класс Number имеет методы для получения этого для каждого примитива, но я хочу, чтобы чистый способ выбрать правильный.

Возможно ли это?

Приветствия

Ответ 1

К сожалению, нет способа получить примитивный тип из типа оболочки без использования блоков if/else.

Проблема заключается в том, что реализовать такой метод было бы невозможно в общем виде. Вот некоторые, казалось бы, возможные подходы, которые можно было бы найти в классе Number:

public abstract X getPrimitiveValue();

Это было бы хорошо, не так ли? Но это невозможно. Существует не возможный X, который может быть абстракцией над int, float, double и т.д.

public abstract Class<?> getCorrespondingPrimitiveClass();

Это тоже не поможет, потому что невозможно создать примитивные классы.

Итак, единственное, что вы можете сделать, это общее для всех типов - использовать методы longValue() или doubleValue(), но в любом случае вы теряете информацию, если имеете дело с неправильным типом.

Итак, нет: иерархия номеров java просто не подходит для решения таких проблем общим способом.

Ответ 2

API Number не предлагает чистый способ получить значение; вам нужно использовать instanceof.

Одним из решений является "сбросить" значения на два типа: long и double. Таким образом, вы можете использовать этот код:

if( inputNumber instanceof Float || inputNumber instanceof Double ) {
    double val = inputNumber.doubleValue();
    ...
} else {
    long val = inputNumber.longValue();
    ...
}

Обратите внимание, что это работает только для стандартных типов номеров, но Number также реализуется множеством других типов (AtomicInteger, BigDecimal).

Если вы хотите поддерживать все типы, трюк заключается в использовании BigDecimal:

BigDecimal value = new BigDecimal( inputNumber.toString() );

Это всегда должно работать и дать вам самый точный результат.

Ответ 3

Методы с <T extends Number> всегда неприятны, так как вы не можете ничего делать на Number (все операторы определены для детей). Вам нужно будет либо сделать тонну instanceof для каждого дочернего элемента Number, и обработать этот случай, выполнив приведение к подтипу. Или (лучше я думаю, что способ, которым Sun это делает), просто иметь метод для каждого типа ребенка, возможно, используя бокс/распаковку для таких операторов, как +, -, > и т.д., Где это возможно (все обертки, а не для BigInteger/BigDecimal или любых пользовательских типов).

Ответ 4

Если это действительно просто сравнение аргумента с другим значением параметра того же типа, вы можете сделать следующее (просто добавив в T x для простоты)

   public static <T extends Number & Comparable<? super Number>> int evaluate(T inputNumber, T x) {
          if (inputNumber.compareTo(x) > 0) { ... }
   }

Ответ 5

в этом случае вы можете использовать обычный метод без дженериков