【问题标题】:Validate reflected method return type and parms in Java在 Java 中验证反射方法返回类型和参数
【发布时间】:2010-09-29 10:45:57
【问题描述】:

我有一个通用的回调对象,它为 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 类型。

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

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

澄清

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

参数的验证也是如此。

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

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

【问题讨论】:

    标签: java reflection types closures callback


    【解决方案1】:

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

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

    然后您可以将F&lt;Double, Double&gt; 传递给需要F&lt;? extends Number, ? extends Number&gt; 的方法。

    编辑:

    您说您想为具有任意数量参数的函数类型提供一个类。这可以用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&lt;A extends L&gt;,它有两个子类C&lt;E, T extends L&lt;T&gt;&gt;,代表一个“缺点”,一个终结器类型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 接口的实现必须使用headtail 从列表中获取参数。因此,实际上,您是在 Java 中实现 LISP。 :)

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

    【讨论】:

    • 部分是因为这些是可公开注册的回调,我不想为 1 个 parm、2 个 parm 等创建一个接口,一直到 10 个。而且很大程度上是因为这些将具有原始回报也。单一界面无法捕捉到这种本质。
    • 另外,因为我希望一个类能够为任意数量的方法提供回调,而不是强制每个被调用的方法都在一个单独的类中(请不要说我应该使用匿名类)。
    • 单个界面可以捕捉到这一本质,但您可能会发现它过于繁琐。请参阅最后的编辑。匿名类有什么问题?
    • 不,这根本不是我要问的。我想验证一个方法是否会在调用调用时返回一个 Number 类型的对象(我可以从中调用 obj.doubleValue() 来获得我想要的双精度)。
    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-09-12
        • 2011-04-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-04-01
        • 2012-06-25
        相关资源
        最近更新 更多