Je voudrais faire du casting dynamic pour une variable java, le type de casting est stocké dans une variable différente.
c’est un casting régulier:
Ssortingng a = (Ssortingng) 5;
C’est ce que je veux:
Ssortingng theType = 'Ssortingng'; Ssortingng a = (theType) 5;
c’est possible? et si oui comment? Merci!
J’essaie de remplir une classe avec un hashMap que j’ai reçu.
c’est le constructeur:
public ConnectParams(HashMap obj) { for (Map.Entry 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 ici est que certaines des variables de classes sont de type Double, et si le nombre 3 est reçu, il le voit comme Integer et j’ai un problème de type.
En ce qui concerne votre mise à jour, le seul moyen de résoudre ce problème en Java est d’écrire du code qui couvre tous les cas avec beaucoup d’expressions
if
etelse
etinstanceof
. Ce que vous essayez de faire ressemble à la programmation de langages dynamics. Dans les langages statiques, ce que vous essayez de faire est presque impossible et vous choisirez probablement une approche totalement différente pour ce que vous essayez de faire. Les langages statiques ne sont pas aussi flexibles que les langages dynamics 🙂Les bons exemples de bonnes pratiques Java sont la réponse de BalusC (c.-à-d.
ObjectConverter
) et la réponse d’Andreas_D (c.-à-d.Adapter
) ci-dessous.
Cela n’a pas de sens, en
Ssortingng a = (theType) 5;
le type de a
étant statiquement lié à Ssortingng
, cela n’a aucun sens d’avoir une conversion dynamic pour ce type statique.
PS: la première ligne de votre exemple pourrait être écrite comme Class
mais quand même, vous ne pouvez pas utiliser ssortingngClass
pour lancer des variables.
Oui c’est possible en utilisant la reflection
Object something = "something"; Ssortingng theType = "java.lang.Ssortingng"; Class> theClass = Class.forName(theType); Object obj = theClass.cast(something);
mais cela n’a pas beaucoup de sens puisque l’object résultant doit être enregistré dans une variable de type object. Si vous avez besoin de la variable d’une classe donnée, vous pouvez simplement lancer cette classe.
Si vous voulez obtenir une classe donnée, Number par exemple:
Object something = new Integer(123); Ssortingng theType = "java.lang.Number"; Class extends Number> theClass = Class.forName(theType).asSubclass(Number.class); Number obj = theClass.cast(something);
mais il est toujours inutile de le faire, vous pouvez simplement passer à Number.
Lancer un object ne change rien; c’est juste la façon dont le compilateur le traite.
La seule raison de faire quelque chose comme ça, est de vérifier si l’object est une instance de la classe donnée ou d’une sous-classe donnée, mais cela serait mieux fait en utilisant instanceof
ou Class.isInstance()
.
Selon votre dernière mise à jour, le véritable problème est que vous avez un nombre entier dans votre HashMap qui doit être affecté à un double. Ce que vous pouvez faire dans ce cas, c’est vérifier le type du champ et utiliser les méthodes xxxValue()
de Number
... 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); ...
(pas sûr si j’aime l’idée d’avoir le mauvais type dans la carte)
Pour cela, vous devez écrire une sorte de ObjectConverter
. Cela est faisable si vous avez à la fois l’object que vous voulez convertir et que vous connaissez la classe cible à laquelle vous souhaitez convertir. Dans ce cas particulier, vous pouvez obtenir la classe cible par Field#getDeclaringClass()
.
Vous pouvez trouver ici un exemple d’un tel ObjectConverter
. Cela devrait vous donner l’idée de base. Si vous voulez plus de possibilités de conversion, ajoutez-y simplement d’autres méthodes avec l’argument et le type de retour souhaités.
Vous pouvez le faire en utilisant la méthode Class.cast()
, qui Class.cast()
dynamicment le paramètre fourni en type d’instance de classe. Pour obtenir l’instance de classe d’un champ particulier, utilisez la méthode getType()
sur le champ en question. J’ai donné un exemple ci-dessous, mais notez qu’il omet toute gestion des erreurs et ne devrait pas être utilisé sans modification.
public class Test { public Ssortingng var1; public Integer var2; } public class Main { public static void main(Ssortingng[] args) throws Exception { Map map = new HashMap(); map.put("var1", "test"); map.put("var2", 1); Test t = new Test(); for (Map.Entry 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); } }
Cela fonctionne et il y a même un modèle commun pour votre approche: le modèle d’adaptateur . Mais bien sûr, (1) cela ne fonctionne pas pour lancer des primitives java sur des objects et (2) la classe doit être adaptable (généralement en implémentant une interface personnalisée).
Avec ce modèle, vous pouvez faire quelque chose comme:
Wolf bigBadWolf = new Wolf(); Sheep sheep = (Sheep) bigBadWolf.getAdapter(Sheep.class);
et la méthode getAdapter dans la classe Wolf:
public Object getAdapter(Class clazz) { if (clazz.equals(Sheep.class)) { // return a Sheep implementation return getWolfDressedAsSheep(this); } if (clazz.equals(Ssortingng.class)) { // return a Ssortingng return this.getName(); } return null; // not adaptable }
Pour vous, idée spéciale, c’est impossible. Vous ne pouvez pas utiliser une valeur Ssortingng pour la diffusion.
Vous pouvez écrire une simple méthode castMet comme celle ci-dessous.
private T castObject(Class clazz, Object object) { return (T) object; }
Dans votre méthode, vous devriez l’utiliser comme
public ConnectParams(HashMap object) { for (Map.Entry entry : object.entrySet()) { try { Field f = this.getClass().getField(entry.getKey()); f.set(this, castObject(entry.getValue().getClass(), entry.getValue()); /* <= CASTING PROBLEM */ } catch (NoSuchFieldException ex) { log.error("did not find field '" + entry.getKey() + '"'); } catch (IllegalAccessException ex) { log.error(ex.getMessage()); } } }
Votre problème n’est pas le manque de “casting dynamic”. Cast Integer
to Double
n’est pas du tout possible. Vous semblez vouloir donner à Java un object d’un type, un champ d’un type éventuellement incompatible, et le faire automatiquement comprendre comment convertir entre les types.
Ce genre de chose est anathème pour un langage fortement typé comme Java et IMO pour de très bonnes raisons.
Qu’essayez-vous de faire? Toute cette utilisation de la reflection est assez louche.
Ne fais pas ça. Juste un constructeur correctement paramétré à la place. L’ensemble et les types de parameters de connexion sont fixes, il est donc inutile de le faire tous de manière dynamic.
Pour ce que cela vaut, la plupart des langages de script (comme Perl) et les langages de compilation non statiques (comme Pick) prennent en charge la chaîne dynamic d’exécution automatique avec des conversions d’objects (relativement arbitraires). Cela peut se faire aussi bien en Java sans perdre la sécurité de type et les langages de qualité statiques fournissent les SANS effets secondaires désagréables de certains autres langages qui font du mal avec le casting dynamic. Un exemple Perl qui fait des calculs douteux:
print ++($foo = '99'); # prints '100' print ++($foo = 'a0'); # prints 'a1'
En Java, ceci est mieux accompli (IMHO) en utilisant une méthode que j’appelle “cross-casting”. Avec le cross-casting, la reflection est utilisée dans un cache chargé paresseux de constructeurs et de méthodes découvertes dynamicment via la méthode statique suivante:
Object fromSsortingng (Ssortingng value, Class targetClass)
Malheureusement, aucune méthode Java intégrée telle que Class.cast () ne le fait pour Ssortingng to BigDecimal ou Ssortingng to Integer ou toute autre conversion pour laquelle aucune hiérarchie de classe n’est prise en charge. Pour ma part, le but est de fournir un moyen totalement dynamic d’y parvenir – pour lequel je ne pense pas que la référence antérieure soit la bonne approche – le fait de devoir coder chaque conversion. En termes simples, l’implémentation consiste simplement à lancer à partir de chaîne si c’est légal / possible.
Donc, la solution est une reflection simple à la recherche de membres publics des deux:
STRING_CLASS_ARRAY = (new Class [] {Ssortingng.class});
a) Member member = targetClass.getMethod (method.getName (), STRING_CLASS_ARRAY); b) membre membre = targetClass.getConstructor (STRING_CLASS_ARRAY);
Vous constaterez que toutes les primitives (Integer, Long, etc.) et toutes les bases (BigInteger, BigDecimal, etc.) et même java.regex.Pattern sont toutes couvertes par cette approche. Je l’ai utilisé avec un succès significatif sur des projets de production où il existe une quantité énorme d’entrées de valeur de chaîne arbitraires où une vérification plus ssortingcte était nécessaire. Dans cette approche, s’il n’y a pas de méthode ou lorsque la méthode est appelée, une exception est levée (car il s’agit d’une valeur illégale telle qu’une entrée non numérique dans un BigDecimal ou un RegEx illégal pour un modèle). la logique inhérente à la classe cible.
Il y a quelques inconvénients à ceci:
1) Vous devez bien comprendre la reflection (c’est un peu compliqué et pas pour les novices). 2) Certaines classes Java et certaines bibliothèques tierces ne sont pas (sursockets) correctement codées. Autrement dit, il existe des méthodes qui prennent un seul argument de chaîne en entrée et renvoient une instance de la classe cible, mais ce n’est pas ce que vous pensez … Prenez la classe Integer:
static Integer getInteger(Ssortingng nm) Determines the integer value of the system property with the specified name.
La méthode ci-dessus n’a rien à voir avec les entiers en tant qu’objects enveloppant les primitives ints. Reflection trouvera cela comme un candidat possible pour créer un nombre entier à partir d’une chaîne par rapport aux membres décodeurs, valueof et constructeurs – qui conviennent à la plupart des conversions de chaînes arbitraires où vous n’avez vraiment aucun contrôle sur vos données d’entrée. savoir si c’est possible un entier.
Pour remédier à ce problème, la recherche de méthodes qui lancent des exceptions est un bon début, car les valeurs de saisie non valides qui créent des instances de tels objects doivent générer une exception. Malheureusement, les implémentations varient selon que les exceptions sont déclarées vérifiées ou non. Integer.valueOf (Ssortingng) lève une exception NumberFormatException vérifiée, mais les exceptions Pattern.comstack () ne sont pas trouvées lors des recherches de reflection. Encore une fois, ce n’est pas un échec de cette approche dynamic du “cross-casting”, mais plutôt une implémentation très peu standard des déclarations d’exceptions dans les méthodes de création d’objects.
Si quelqu’un souhaite plus de détails sur la façon dont ce qui précède a été mis en place, faites-le moi savoir, mais je pense que cette solution est beaucoup plus flexible / extensible et avec moins de code sans perdre les bonnes parties de la sécurité. Bien sûr, il est toujours préférable de “connaître vos données” mais, comme beaucoup d’entre nous le constatent, nous ne sums parfois que des destinataires de contenus non gérés et nous devons faire de notre mieux pour les utiliser correctement.
À votre santé.
Donc, ceci est un ancien message, mais je pense pouvoir y consortingbuer.
Vous pouvez toujours faire quelque chose comme ceci:
package com.dyna.test; import java.io.File; import java.lang.reflect.Constructor; public class DynamicClass{ @SuppressWarnings("unchecked") public Object castDynamicClass(Ssortingng className, Ssortingng value){ Class> dynamicClass; try { //We get the actual .class object associated with the specified name dynamicClass = Class.forName(className); /* We get the constructor that received only a Ssortingng as a parameter, since the value to be used is a Ssortingng, but we could easily change this to be "dynamic" as well, getting the Constructor signature from the same datasource we get the values from */ Constructor> cons = (Constructor>) dynamicClass.getConstructor(new Class>[]{Ssortingng.class}); /*We generate our object, without knowing until runtime what type it will be, and we place it in an Object as any Java object extends the Object class) */ Object object = (Object) cons.newInstance(new Object[]{value}); return object; } catch (Exception e) { e.printStackTrace(); } return null; } public static void main(Ssortingng[] args) { DynamicClass dynaClass = new DynamicClass(); /* We specify the type of class that should be used to represent the value "3.0", in this case a Double. Both these parameters you can get from a file, or a network stream for example. */ System.out.println(dynaClass.castDynamicClass("java.lang.Double", "3.0")); /* We specify a different value and type, and it will work as expected, printing 3.0 in the above case and the test path in the one below, as the Double.toSsortingng() and File.toSsortingng() would do. */ System.out.println(dynaClass.castDynamicClass("java.io.File", "C:\\testpath")); }
Bien sûr, ce n’est pas vraiment un casting dynamic, comme dans les autres langages (Python par exemple), car java est un langage de type statique. Cependant, cela peut résoudre certains cas marginaux dans lesquels vous avez réellement besoin de charger des données de différentes manières, en fonction d’un identifiant. En outre, la partie où vous obtenez un constructeur avec un paramètre Ssortingng pourrait probablement être rendue plus flexible en faisant passer ce paramètre à partir de la même source de données. Par exemple, à partir d’un fichier, vous obtenez la signature du constructeur que vous souhaitez utiliser et la liste des valeurs à utiliser, par exemple, lorsque vous associez, par exemple, le premier paramètre est une chaîne, avec le premier object, en le transformant en chaîne. object suivant est un Integer, etc, mais certainshwea le long de l’exécution de votre programme, vous obtenez maintenant un object File d’abord, puis un Double, etc.
De cette manière, vous pouvez prendre en compte ces cas et effectuer un casting quelque peu “dynamic” à la volée.
J’espère que cela aidera tout le monde, car cela continue à apparaître dans les recherches Google.
J’ai récemment ressenti que je devais le faire aussi, mais j’ai ensuite trouvé un autre moyen qui peut rendre mon code plus élégant et qui utilise mieux la POO.
J’ai beaucoup de classes frères qui implémentent chacune une certaine méthode doSomething()
. Pour accéder à cette méthode, je devrais d’abord avoir une instance de cette classe, mais j’ai créé une super-classe pour toutes mes classes de frères et sœurs et maintenant je peux accéder à la méthode à partir de la super-classe.
Ci-dessous, je montre deux manières différentes de “casting dynamic”.
// Method 1. mFragment = getFragmentManager().findFragmentByTag(MyHelper.getName(mUnitNum)); switch (mUnitNum) { case 0: ((MyFragment0) mFragment).sortNames(sortOptionNum); break; case 1: ((MyFragment1) mFragment).sortNames(sortOptionNum); break; case 2: ((MyFragment2) mFragment).sortNames(sortOptionNum); break; }
et ma méthode actuellement utilisée,
// Method 2. mSuperFragment = (MySuperFragment) getFragmentManager().findFragmentByTag(MyHelper.getName(mUnitNum)); mSuperFragment.sortNames(sortOptionNum);
Je pensais juste que je publierais quelque chose que je trouvais très utile et qui pourrait être possible pour quelqu’un qui éprouve des besoins similaires.
La méthode suivante était une méthode que j’ai écrite pour mon application JavaFX pour éviter d’avoir à lancer et éviter également d’écrire si object x instance d’object b instructions chaque fois que le contrôleur était renvoyé.
public Optional getController(Class castKlazz){ try { return Optional.of(fxmlLoader.getController()); }catch (Exception e){ e.printStackTrace(); } return Optional.empty(); }
La déclaration de méthode pour obtenir le contrôleur était
public T getController()
En utilisant le type U passé dans ma méthode via l’object class, il pourrait être transmis à la méthode get controller pour lui indiquer quel type d’object renvoyer. Un object facultatif est renvoyé si une classe incorrecte est fournie et qu’une exception se produit, auquel cas une option facultative vide sera renvoyée, ce que nous pouvons vérifier.
Voici à quoi ressemblait l’appel final à la méthode (s’il est présent dans l’object facultatif
getController(LoadController.class).ifPresent(controller->controller.onNotifyComplete());
Essayez ceci pour le casting dynamic. Ça va marcher!!!
Ssortingng something = "1234"; Ssortingng theType = "java.lang.Integer"; Class> theClass = Class.forName(theType); Constructor> cons = theClass.getConstructor(Ssortingng.class); Object ob = cons.newInstance(something); System.out.println(ob.equals(1234));