20 votes

Type de retour dynamique dans une méthode Java

J'ai vu une question similaire à celle-ci plusieurs fois ici, mais il y a une grande différence.

Dans les autres questions, le type de retour doit être déterminé par le paramètre. Ce que je veux/doit faire, c'est déterminer le type de retour par la valeur analysée d'un paramètre de type byte[] . D'après ce que j'ai compris, ce qui suit pourrait fonctionner :

public Comparable getParam(String param, byte[] data) {
    if(param.equals("some boolean variable")
        return data[0] != 0;
    else(param.equals("some float variable") {
        //create a new float, f, from some 4 bytes in data
        return f;
    }
    return null;
}

Je veux juste m'assurer que ça a une chance de fonctionner avant de tout bousiller. Merci d'avance.

28voto

hisdrewness Points 2643

Je ne sais pas de quoi ces gens parlent. Vous perdez la sécurité de type, ce qui est un souci, mais vous pourriez facilement accomplir ceci avec des génériques... quelque chose comme :

public <T> T getSomething(...) { }

o

interface Wrapper<T> { T getObject(); }

public <T> Wrapper<T> getSomething(...) { }

Ce dernier favorise la possibilité d'un schéma stratégique . Passez les octets à la stratégie, laissez-la s'exécuter et récupérez la sortie. Vous auriez une stratégie d'octets, une stratégie booléenne, etc.

abstract class Strategy<T> {
    final byte[] bytes;

    Strategy(byte[] bytes) { this.bytes = bytes; }

    protected abstract T execute();
}

puis

class BooleanStrategy extends Strategy<Boolean> {
    public BooleanStrategy(byte[] bytes) { super(bytes); }

    @Override
    public Boolean execute() {
        return bytes[0] != 0;
    }

}

Votre exemple de code est un mauvais cas d'utilisation et je ne le recommanderais pas. Votre méthode n'a pas beaucoup de sens.

26voto

Danieth Points 385

Ce site CAN être fait. Le code suivant fonctionnera :

public byte BOOLEAN = 1;
public byte FLOAT = 2;
public static <Any> Any getParam(byte[] data) {
    if (data[0] == BOOLEAN) {
        return (Any)((Boolean)(boolean)(data[1] != 0));
    } else if (data[0] == FLOAT) {
        return (Any)((Float)(float)data[1]);
    } else {
        return null;
    }
}

En utilisant un générique pour le type de retour, toute méthode Java peut retourner dynamiquement n'importe quel objet ou type primitif. Vous pouvez nommer le générique comme vous le souhaitez, et dans ce cas, je l'ai appelé "Any". En utilisant ce code, vous évitez le casting du type de retour lorsque la méthode est appelée. Vous utiliserez la méthode comme suit :

byte[] data = new byte[] { 1, 5 };
boolean b = getParam(data);
data = new byte[] { 2, 5 };
float f = getParam(data);

Le mieux que vous puissiez faire sans cette astuce est de couler manuellement un objet :

float f = (float)getParam(data);

Les types de retour dynamiques de Java peuvent réduire le code passe-partout.

16voto

ddyer Points 1546

Vous ne pouvez pas le faire. Les types de retour Java doivent être soit un type fondamental fixe ou une classe d'objet. Je suis presque sûr que le mieux que vous puissiez faire est de retourner un type de wrapper qui possède des méthodes pour récupérer les différents types de valeurs possibles, et un enum interne interne qui dit lequel est valide.

--- éditer --- après la correction de Danieth !

public <Any> Any getParam(boolean b){
return((Any)((Boolean)(!b)));
}
public <Any> Any getParam(float a) {
 return((Any)((Float)(a+1)));
}
public <Any> Any getParam(Object b) {
 return((Any)b);
}
public void test(){
  boolean foo = getParam(true);
  float bar = getParam(1.0f);
  float mumble = getParam(this); // will get a class cast exception
}

Vous subissez toujours certaines pénalités pour les éléments de la boîte et la vérification du type. les valeurs renvoyées, et bien sûr si votre appel n'est pas cohérent avec ce que les implémentations de getParam font réellement, vous obtiendrez une classe cast.

3voto

Thomas Decaux Points 2613

Mes deux centimes avec un exemple avec le client HTTP de Google :

static public <Any> Any getJson(final String url, final Class<Any> parseAs) throws IOException {
        HttpRequestFactory requestFactory
                = HTTP_TRANSPORT.createRequestFactory(
                (HttpRequest request) -> {
                    request.setParser(new JsonObjectParser(JSON_FACTORY));
                });

        HttpRequest request = requestFactory.buildRequest(HttpMethods.GET, new GenericUrl(url), null);

        return request.execute().parseAs(parseAs);
    }

On peut l'utiliser comme ça :

HashMap<String, Object> out = HttpUtils.getJson( "https://api.qwant.com", HashMap.class);

1voto

Kane Points 2099

Si vous ne renvoyez vraiment qu'un boolean ou un float alors le mieux que vous puissiez faire est Object .

Si vous retournez des objets variables, vous devez choisir un type de retour avec la superclasse la moins commune. Les primitives n'ont pas de superclasse, mais elles seront encadrées dans des représentations Object (comme Boolean y Float ) qui ont une superclasse commune de Object .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X