Проверка типа возвращаемого значения отраженного метода и параметров в Java

StackOverflow https://stackoverflow.com/questions/410343

Вопрос

У меня есть общий объект обратного вызова, который обеспечивает (примитивную) возможность обратного вызова для Java при отсутствии замыканий.Объект обратного вызова содержит метод и возвращает параметры и типы возвращаемых значений для метода через пару методов доступа, которые просто делегируют эквивалентные методы в методе.

Я пытаюсь проверить, что предоставленный мне обратный вызов указывает на действительный метод.Мне нужно, чтобы назначение типа возвращаемого значения было совместимо с 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.Поскольку мне требуется, чтобы все эти обратные вызовы возвращали какое-то число, которое будет возвращено вызовом() как число, я пытаюсь проверить, что предоставленный метод возвращает либо число, либо числовой примитив.

Проверка параметров аналогична.

Другими словами, при использовании отражения типы parm и return Double и double идентичны, и я хотел бы проверить их. легко как таковой.

РЕДАКТИРОВАТЬ:Чтобы уточнить:Я хочу проверить, что метод при вызове метода вызова() возвращает объект типа Number (из которого я могу вызвать obj.doubleValue(), чтобы получить желаемый двойной результат).

Это было полезно?

Решение

При более внимательном рассмотрении документации Class.isAssignableFrom() в ней конкретно указано, что типы примитива не соответствуют ни одному классу, кроме самого себя.Поэтому мне нужно будет специально проверить равенство == для Byte.TYPE, Double.TYPE, Float.TYPE, Integer.TYPE, Long.TYPE и Short.TYPE для типа возвращаемого значения.

Другие советы

Почему бы не поручить это компилятору?

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), вместе с двумя doubles, чтобы применить его к:

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

Параметр Math.abs() — это двойной примитив.Я не совсем понимаю, что вы подразумеваете под примитивом, «совместимым по присваиванию» с объектом (по сути, API отражения означает «может быть приведением»).Но если вы имеете в виду «может перейти в конструктор Double», то это, по сути, примитивный двойной элемент (или строка)!Возможно, вам нужно уточнить немного больше, что вам нужно сделать?

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top