95 votes

java: comment puis-je faire dynamique de la coulée d'une variable d'un type à l'autre?

je voudrais faire dynamique casting pour une variable java, la conversion de type est stocké dans une variable différente.

c'est régulier casting:

 String a = (String) 5;

c'est ce que je veux:

 String theType = 'String';
 String a = (theType) 5;

est-il possible? et si oui, comment? merci!

mise à jour

Je suis en train de remplir une classe avec une hashMap que j'ai reçu.

c'est le constructeur:

public ConnectParams(HashMap<String,Object> obj) {

    for (Map.Entry<String, Object> entry : obj.entrySet()) {
        try {
            Field f =  this.getClass().getField(entry.getKey());                
            f.set(this, entry.getValue()); /* <= CASTING PROBLEM */
        } catch (NoSuchFieldException ex) {
            log.error("did not find field '" + entry.getKey() + '"');
        } catch (IllegalAccessException ex) {
            log.error(ex.getMessage());         
        }
    }

}

le problème, c'est que certaines classes de variables sont de type Double, et si le nombre 3 est reçu, il le voit comme un Entier et j'ai du type de problème.

129voto

Carlos Heuberger Points 11804

Oui, il est possible à l'aide de la Réflexion

    Object something = "something";
    String theType = "java.lang.String";
    Class<?> theClass = Class.forName(theType);
    Object obj = theClass.cast(something);

mais qui n'a pas beaucoup de sensesince l'objet résultant doit être enregistrée dans une variable de type Objet. Si vous avez besoin de la variable d'une classe donnée, vous pouvez les jeter à la classe.

Si vous souhaitez obtenir une classe donnée, le Nombre pour l'exemple:

    Object something = new Integer(123);
    String theType = "java.lang.Number";
    Class<? extends Number> theClass = Class.forName(theType).asSubclass(Number.class);
    Number obj = theClass.cast(something);

mais il n'y a pas encore de point de le faire, vous pouvez simplement exprimés en Nombre.

Casting d'un objet ne change rien; c'est juste la façon dont le compilateur traite.
La seule raison pour faire quelque chose comme ça, est de vérifier si l'objet est une instance de la classe donnée ou de toute sous-classe, mais ce serait mieux fait en utilisant instanceof ou Class.isInstance().

Mise à jour

selon votre dernière mise à jour le vrai problème, c'est que vous avez un nombre Entier dans votre table de hachage qui doit être attribué à un Double. Ce que vous pouvez faire dans ce cas, est de vérifier le type du champ et de l'utilisation de l' xxxValue() méthodes de Nombre

        ...
        Field f =  this.getClass().getField(entry.getKey());
        Object value = entry.getValue();
        if (Integer.class.isAssignableFrom(f.getType())) {
            value = Integer.valueOf(((Number) entry.getValue()).intValue());
        } else if (Double.class.isAssignableFrom(f.getType())) {
            value = Double.valueOf(((Number) entry.getValue()).doubleValue());
        } // other cases as needed (Long, Float, ...)
        f.set(this, value);
        ...

(je ne sais pas si j'aime l'idée d'avoir le mauvais type de la Carte)

23voto

BalusC Points 498232

Vous aurez besoin d'écrire sorte d' ObjectConverter pour cette. C'est faisable si vous avez à la fois l'objet que vous voulez à convertir et vous savez la classe cible à laquelle vous souhaitez convertir. Dans ce cas particulier, vous pouvez obtenir la classe cible en Field#getDeclaringClass().

Vous pouvez trouver ici un exemple d'un tel ObjectConverter. Il devrait vous donner l'idée de base. Si vous voulez plus de possibilités de conversion, il suffit d'ajouter plus de méthodes pour elle avec des argument et le type de retour.

14voto

akuhn Points 12241

Concernant votre mise à jour, la seule façon de résoudre ce problème en Java est d'écrire du code qui couvre tous les cas avec beaucoup d' if et else et instanceof expressions. Ce que vous tentez de le faire est comme si sont utilisés pour programmer avec des langages dynamiques. Dans les langages statiques, ce que vous tentez de le faire est presque impossible, et l'on ne serait probablement choisir une approche totalement différente de ce que vous essayez de faire. Langages statiques sont tout simplement pas aussi souple comme dynamiques :)

De bons exemples de Java meilleures pratiques sont la réponse par BalusC (ie ObjectConverter) et de la réponse par Andreas_D (ie Adapter) ci-dessous.


Qui n'a pas de sens, dans

String a = (theType) 5;

le type d' a est statistiquement lié à la String donc cela n'a aucun sens d'avoir une dynamique de fonte à ce type statique.

PS: La première ligne de votre exemple peut être écrite comme Class<String> stringClass = String.class; mais encore, vous ne pouvez pas utiliser stringClass de jeter des variables.

13voto

Jared Russell Points 3616

Vous pouvez faire cela en utilisant l' Class.cast() méthode, de manière dynamique, jette les paramètres fournies par le type de l'instance de classe que vous avez. Pour obtenir l'instance de classe d'un domaine particulier, vous utilisez l' getType() méthode sur le champ en question. J'ai donné l'exemple ci-dessous, mais notez qu'il omet toute erreur de manipulation et ne doit pas être utilisé sans modification.

public class Test {

    public String var1;
    public Integer var2;
}

public class Main {

    public static void main(String[] args) throws Exception {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("var1", "test");
        map.put("var2", 1);

        Test t = new Test();

        for (Map.Entry<String, Object> entry : map.entrySet()) {
            Field f = Test.class.getField(entry.getKey());

            f.set(t, f.getType().cast(entry.getValue()));
        }

        System.out.println(t.var1);
        System.out.println(t.var2);
    }
}

5voto

Andreas_D Points 64111

Il fonctionne et il y a même un modèle commun pour votre approche: l' Adaptateur. Mais bien sûr, (1) il ne fonctionne pas pour la coulée de java primitives à des objets et (2) la classe doit être adaptable (généralement par la mise en œuvre d'une interface personnalisée).

Avec ce modèle, vous pourriez faire quelque chose comme:

Wolf bigBadWolf = new Wolf();
Sheep sheep = (Sheep) bigBadWolf.getAdapter(Sheep.class);

et le getAdapter méthode dans le Loup de la classe:

public Object getAdapter(Class clazz) {
  if (clazz.equals(Sheep.class)) {
    // return a Sheep implementation
    return getWolfDressedAsSheep(this);
  }

  if (clazz.equals(String.class)) {
    // return a String
    return this.getName();
  }

  return null; // not adaptable
}

Pour vous idée particulière - ce qui est impossible. Vous ne pouvez pas utiliser une valeur de Chaîne pour la coulée.

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