我有一个通用的Callback对象,它在没有闭包的情况下为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

这对我来说是令人惊讶的,因为我希望原语能够简单地工作,因为(a)它们使用它们的包装类来反映,并且(b)Double.TYPE被声明为Class <!> lt; Double <! > GT;

有人知道如何在不修改我的支票的情况下实现这一目标:

if(!Number.class.isAssignableFrom(ret)
     && ret!=Double.TYPE
     && ret!=Float.TYPE
     && ret!=...) {

澄清

使用Method.invoke()调用方法double abs(double)时,传入Object [] {Double}并返回Double。但是,我的验证似乎失败,因为Double.TYPE不能分配给Double。因为我要求所有这些回调返回某种数字,这将由invoke()作为数字返回,我试图验证提供的方法返回Number或数字原语。

同样验证了parms。

换句话说,当使用反射时,parm和返回类型Double和double是相同的,我想验证它们很容易

编辑:进一步澄清:我想验证一个方法将在调用invoke()时返回一个Number类型的Object(我可以从中调用obj.doubleValue()来获取我想要的double)。 / p>

有帮助吗?

解决方案

仔细查看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>>表示<!> quot; cons <!> quot;和一个终止符类型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),以及两个F s以将其应用于:

public Double operate(F<C<Double, C<Double, N>>, Double> f, double a, double b) {
   return f.$(N.nil().cons(b).cons(a));
}

head接口的实现必须使用tail和<=>从列表中获取参数。因此,实际上,您正在使用Java实现LISP。 :)

话虽如此,请查看功能性Java ,这是一个已经拥有大量此类内容的库。我相信还有一个使用反射,所以你不必自己写。

Math.abs()的参数是双原语。我不太确定你的原语是什么意思<!> quot; assignment compatible <!> quot;一个对象(反射API本质上意味着什么是<!> quot;可以是<!>的演员阵容;)。但是,如果你的意思是<!>“可以传入Double构造函数<!>”,那么这本质上是一个原始的双(或字符串)!!也许你需要澄清一下你需要做些什么?

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top