У меня есть общий объект обратного вызова, который обеспечивает (примитивную) возможность обратного вызова для Java при отсутствии замыканий. Объект Callback содержит Method и возвращает параметр и типы возвращаемых данных для метода через пару методов доступа, которые просто делегируют эквивалентным методам в Method.
Я пытаюсь проверить, что полученный мной обратный вызов указывает на действительный метод. Мне нужно, чтобы присвоение типа возвращаемого значения было совместимо с Number, и все параметры были совместимы с присваиванием Double. Мой метод проверки выглядит так:
static public void checkFunctionSpec(Callback cbk) {
Class[] prms=cbk.getParmTypes();
Class ret =cbk.getReturnType();
if (!Number.class.isAssignableFrom(ret)) {
throw new IllegalArgumentException(
"A function callback must return a Number type " +
"(any Number object or numeric primitive) - function '" +
cbk + "' is not permitted");
}
for(Class prm: prms) {
if (!Double.class.isAssignableFrom(prm)) {
throw new IllegalArgumentException(
"A function callback must take parameters of " +
"assignment compatible with double " +
"(a Double or Float object or a double or float primitive) " +
"- function '" + cbk + "' is not permitted");
}
}
}
Проблема, с которой я сталкиваюсь, заключается в том, что когда я пытаюсь это сделать, например Math.abs () генерирует исключение для возвращаемого типа следующим образом:
java.lang.IllegalArgumentException:
A function callback must return a Number type (any Number object or numeric primitive)
- function 'public static double java.lang.Math.abs(double)' is not permitted
Это было для меня неожиданностью, потому что я ожидал, что примитивы будут просто работать, потому что (а) они отражаются с помощью их классов-оболочек, и (б) Double.TYPE объявлен как имеющий тип Class <Double>.
Кто-нибудь знает, как я могу добиться этого, не изменяя свои проверки:
if (!Number.class.isAssignableFrom(ret)
&& ret!=Double.TYPE
&& ret!=Float.TYPE
&& ret!=...) {
Когда вы вызываете метод double abs(double) с помощью Method.invoke (), вы передаете Object [] {Double} и получаете обратно Double. Однако моя проверка, похоже, не выполняется, потому что Double.TYPE не может быть назначен Double. Поскольку мне нужно, чтобы все эти обратные вызовы возвращали какое-то число, которое будет возвращено invoke () как Number, я пытаюсь проверить, что предоставленный метод возвращает либо Number, либо числовой примитив.
Аналогичным образом проводится валидация пармов.
Другими словами, при использовании отражения типы parm и return Double и double идентичны, и я хотел бы проверить их как без труда.
Обновлено: Для дальнейшего пояснения: я хочу подтвердить, что метод при вызове invoke () будет возвращать объект типа Number (из которого я могу вызвать obj.doubleValue (), чтобы получить двойной, который я хочу).




Почему бы не сделать это компилятору?
public interface F<A, B> {
public B $(A a);
}
Затем вы можете передать F<Double, Double> методу, который ожидает F<? extends Number, ? extends Number>.
Обновлено:
Вы говорите, что хотите предоставить один класс для типа функции с любым количеством аргументов. Этот может должен быть выполнен с помощью системы типов Java. Концептуально каждая функция имеет только один аргумент. Функция с двумя аргументами эквивалентна функции, возвращающей другую функцию. Итак, вот переменная, значение которой является функцией, которая принимает два двойных значения:
F<Double, F<Double, Double>> f;
Вот метод, который передает два двойных значения заданной функции:
public Double operate(F<Double, F<Double, Double>> f, double a, double b) {
return f.$(a).$(b);
}
Или рассмотрим тип L<A extends L> с двумя подклассами C<E, T extends L<T>>, представляющими «минусы», и тип терминатора N:
public abstract class L<A extends L<A>> {
private L() {}
private static final N nil = new N();
public static N nil() {
return nil;
}
public static final class N extends L<N> {
private N() {}
public <E> C<E, N> cons(final E e) {
return new C<E, L>(e, this);
}
}
public static final class C<E, L extends L<L>> extends L<C<E, L>> {
private E e;
private L l;
private C(final E e, final L l) {
this.e = e;
this.l = l;
}
public E head() {
return e;
}
public L tail() {
return l;
}
public <E> C<E, C<E, L>> cons(final E e) {
return new C<E, C<E, L>>(e, this);
}
}
}
В таком случае вы можете реализовать тип функции следующим образом:
public interface F<A extends L<A>, B> {
public B $(A args);
}
Следующий метод ожидает функцию с двумя аргументами Double (и возвращает Double) вместе с двумя double, к которым она будет применяться:
public Double operate(F<C<Double, C<Double, N>>, Double> f, double a, double b) {
return f.$(N.nil().cons(b).cons(a));
}
Реализация интерфейса F должна получить аргументы из списка, используя head и tail. По сути, вы реализуете LISP на Java. :)
Сказав это, обратите внимание на Функциональная Java, библиотеку, в которой уже есть много всего этого. Я уверен, что есть еще один, который использует отражение, поэтому вам не нужно писать его самостоятельно.
Кроме того, потому что я хочу, чтобы один класс мог предоставлять обратные вызовы для любого количества методов, а не заставлять каждый вызываемый метод находиться в отдельном классе (и, пожалуйста, не говорите, что я должен использовать анонимные классы).
Единый интерфейс может отражает эту суть, но вы можете найти его слишком громоздким. См. Последнее изменение. Что не так с анонимными классами?
Нет, я вообще не об этом спрашиваю. Я хочу подтвердить, что метод при вызове вызова возвращает объект типа Number (из которого я могу вызвать obj.doubleValue (), чтобы получить желаемое значение double).
Параметр Math.abs () - это двойной примитив. Я не совсем понимаю, что вы подразумеваете под примитивом, «совместимым по назначению» с объектом (что, по сути, означает API отражения, это «может быть приведением»). Но если вы имеете в виду «может перейти в конструктор Double», то это, по сути, примитивный тип double (или строка) !! Возможно, вам нужно немного пояснить, что вам нужно сделать?
Если более внимательно присмотреться к документации для Class.isAssignableFrom (), в ней конкретно указано, что типы для примитива не соответствуют ни одному классу, кроме самих себя. Поэтому мне нужно будет специально проверить == равенство Byte.TYPE, Double.TYPE, Float.TYPE, Integer.TYPE, Long.TYPE и Short.TYPE для возвращаемого типа.
Отчасти потому, что это открыто регистрируемые обратные вызовы, и я не хочу создавать интерфейс для 1 параметра, 2 параметров и т. д., Возможно, до 10. А также во многом потому, что они также будут иметь примитивные результаты. Единый интерфейс не может уловить эту суть.