Генераторы 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
в этом случае вы можете использовать обычный метод без дженериков