0

我有一个通用的回调对象,它为 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<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() 作为数字返回,因此我试图验证提供的方法是否返回数字或数字原语。

参数的验证也是如此。

换句话说,当使用反射时,参数和返回类型 Double 和 double 是相同的,我想这样轻松地验证它们。

编辑:进一步澄清:我想验证一个方法是否会在调用 invoke() 时返回一个 Number 类型的对象(我可以从中调用 obj.doubleValue() 来获得我想要的双精度)。

4

3 回答 3

1

为什么不让编译器来做呢?

public interface F<A, B> {
   public B $(A a);
}

然后,您可以将 an 传递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>>代表一个“cons”和一个终结器类型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参数的函数(并返回 a Double),以及double将其应用于的两个 s:

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。因此,实际上,您是在 Java 中实现 LISP。:)

话虽如此,请查看Functional Java,这是一个已经包含很多此类内容的库。我敢肯定还有一个使用反射的,所以你不必自己写。

于 2009-01-04T03:17:36.330 回答
1

更仔细地查看 Class.isAssignableFrom() 的文档,它明确指出基元的类型不匹配除自身之外的任何类。因此,我需要专门检查 == 与 Byte.TYPE、Double.TYPE、Float.TYPE、Integer.TYPE、Long.TYPE 和 Short.TYPE 的返回类型是否相等。

于 2009-01-04T06:38:42.867 回答
0

Math.abs() 的参数是双原语。我不太确定基元与对象“赋值兼容”是什么意思(反射 API 本质上的意思是“可以转换”)。但是,如果您的意思是“可以传递给 Double 构造函数”,那么这本质上是一个原始双精度(或字符串)!也许您需要澄清一下您需要做什么?

于 2009-01-04T04:22:07.400 回答