0

クロージャがない場合に、Javaの(プリミティブ)コールバック機能を提供する汎用のCallbackオブジェクトがあります。Callbackオブジェクトにはメソッドが含まれており、メソッド内の同等のメソッドに委任するだけの2つのアクセサーメソッドを介して、メソッドのパラメーターと戻り値のタイプを返します。

提供されたコールバックが有効なメソッドを指していることを検証しようとしています。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()によって数値として返されるある種の数値を返す必要があるため、提供されたメソッドが数値または数値プリミティブのいずれかを返すことを検証しようとしています。

parmsの検証も同様です。

つまり、リフレクションを使用する場合、parmタイプとreturnタイプのDoubleとdoubleは同じであり、そのように簡単に検証したいと思います。

編集:さらに明確にするために:invoke()が呼び出されたときに、メソッドがNumber型のオブジェクトを返すことを検証したいと思います(そこからobj.doubleValue()を呼び出して必要なdoubleを取得できます)。

4

3 に答える 3

1

なぜコンパイラにそれをさせないのですか?

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

次に、F<Double, Double>を期待するメソッドにを渡すことができますF<? extends Number, ? extends Number>

編集:

任意の数の引数を持つ関数の型に単一のクラスを提供したいとします。これは、Java型システムで実行できます。概念的には、すべての関数には1つの引数しかありません。2つの引数を持つ関数は、別の関数を返す関数と同等です。したがって、値が2つのdoubleを取る関数である変数を次に示します。

F<Double, F<Double, Double>> f;

これは、2つのdoubleを特定の関数に渡すメソッドです。

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

または、「短所」を表すL<A extends L>2つのサブクラスを持つタイプと、ターミネータタイプについて考えてみます。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次のメソッドは、2つの引数を持つ関数(およびを返すDouble)と、doubleそれを適用する2つの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()のパラメーターはdoubleプリミティブです。プリミティブがオブジェクトと「割り当て互換」であることの意味がよくわかりません(リフレクションAPIが本質的に意味するのは、「キャストになることができる」ということです)。しかし、「Doubleコンストラクターに渡すことができる」という意味の場合、それは本質的にプリミティブなdouble(または文字列)です!! おそらく、あなたがしなければならないことをもう少し明確にする必要がありますか?

于 2009-01-04T04:22:07.400 に答える