Question

J'ai un objet Callback générique qui fournit une capacité de rappel (primitive) pour Java, en l'absence de fermeture. L'objet Callback contient une méthode et renvoie les types de paramètre et de retour pour la méthode via deux méthodes d'accès qui délèguent simplement les méthodes équivalentes dans la méthode.

J'essaie de valider qu'un rappel que j'ai reçu indique une méthode valide. J'ai besoin que l'affectation de type de retour compatible avec Number et tous les paramètres soient compatibles avec Double. Ma méthode de validation ressemble à ceci:

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");
            }
        }
    }

Le problème que je rencontre est que lorsque j'essaie, par exemple Math.abs (), une exception est générée pour le type de retour, comme suit:

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

Cela me surprenait car je m'attendais à ce que les primitives fonctionnent simplement car (a) elles sont reflétées à l'aide de leurs classes wrapper et (b) le Double.TYPE est déclaré de type Class < Double gt;.

Est-ce que quelqu'un sait comment je peux y arriver sans modifier mes contrôles pour être:

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

Clarification

Lorsque vous appelez la méthode double abs(double) à l'aide de Method.invoke (), vous transmettez un objet [] {Double} et récupérez un double. Cependant, ma validation semble échouer car Double.TYPE n'est pas assignable à un Double. Étant donné que j'ai besoin de tous ces rappels pour renvoyer une sorte de numéro, qui sera renvoyé par invoke () en tant que nombre, j'essaie de valider le fait que la méthode fournie renvoie un nombre ou une primitive numérique.

La validation des paramètres est similaire.

En d'autres termes, lors de l'utilisation de la réflexion, les types parm et return sont identiques et je souhaite les valider facilement en tant que tels.

EDIT: pour clarifier: je veux valider le fait qu'une méthode va appeler invoke () un objet de type Number (à partir duquel je peux appeler obj.doubleValue () pour obtenir le double que je veux).

Était-ce utile?

La solution

En examinant de plus près la documentation de Class.isAssignableFrom (), il est indiqué que les types d'une primitive ne correspondent à aucune classe, sauf à eux-mêmes. Il me faudra donc vérifier spécifiquement == l'égalité avec Byte.TYPE, Double.TYPE, Float.TYPE, Integer.TYPE, Long.TYPE et Short.TYPE pour le type de retour.

Autres conseils

Pourquoi ne pas demander au compilateur de le faire?

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

Ensuite, vous pouvez passer un F<Double, Double> à une méthode qui attend un F<? extends Number, ? extends Number>.

EDIT:

Vous dites que vous souhaitez fournir une classe unique pour le type d'une fonction avec un nombre quelconque d'arguments. Ceci peut être réalisé avec le système de types Java. Conceptuellement, chaque fonction n'a qu'un seul argument. Une fonction avec deux arguments est équivalente à une fonction qui retourne une autre fonction. Alors, voici une variable dont la valeur est une fonction qui prend deux doubles:

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

Voici une méthode qui attribue deux doubles à une fonction donnée:

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

Ou, considérons un type L<A extends L> avec deux sous-classes C<E, T extends L<T>> représentant un " contre " et un type de terminateur 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);
   }  
 }  

}  

Dans ce cas, vous pouvez implémenter un type de fonction comme suit:

public interface F<A extends L<A>, B> {
   public B $(A args);
}

La méthode suivante attend une fonction avec deux Double arguments (et renvoie un double), avec deux F s auxquels l'appliquer:

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

La mise en œuvre de l'interface head devrait extraire les arguments de la liste à l'aide de tail et <=>. En pratique, vous implémentez LISP en Java. :)

Ceci étant dit, consultez la Java fonctionnel , une bibliothèque qui contient déjà beaucoup de ces éléments. Je suis sûr qu'il y en a aussi un qui utilise la réflexion pour que vous n'ayez pas à l'écrire vous-même.

Le paramètre à Math.abs () est la double primitive. Je ne suis pas tout à fait sûr de ce que vous entendez par une primitive étant & «Assignation compatible &»; avec un objet (ce que l’API de réflexion signifie essentiellement est que & "peut être une distribution de &";). Mais si vous voulez dire que & "Peut passer dans un constructeur Double &", Alors c'est essentiellement un double primitif (ou une chaîne) !! Peut-être devriez-vous clarifier un peu plus ce que vous devez faire?

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top