IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

API standards et tierces Java Discussion :

[Reflect] Créer un array d'objets avec le nom de leur classe


Sujet :

API standards et tierces Java

  1. #1
    Membre habitué

    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    118
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Octobre 2004
    Messages : 118
    Points : 137
    Points
    137
    Par défaut [Reflect] Créer un array d'objets avec le nom de leur classe
    Avec le nom d'une classe, on peut créer une instance:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Class.forName("org.me.MyClass").newInstance();
    Mais comment faire pour avoir un array?
    Autrement dit faire mais avec la réflection.
    "MyClass" peut être donné comme String ou même Class (via getType) directement. C'est surtout l'instanciation de l'array qui m'intéresse.

  2. #2
    Expert confirmé
    Avatar de le y@m's
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2005
    Messages
    2 636
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Février 2005
    Messages : 2 636
    Points : 5 943
    Points
    5 943
    Par défaut
    Tu peus déclarer un Tableau d'Object et le remplir d'instances de MyClass
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Object[] myClasses = new Object[x];
    for(int i = 0; i < x; i ++) {
         myClasses[i] = Class.forName("org.me.MyClass").newInstance();
    }
    Je ne répondrai à aucune question technique par MP.

    Pensez aux Tutoriels et aux FAQs avant de poster (pour le java il y a aussi JavaSearch), n'oubliez pas non plus la fonction Rechercher.
    Enfin, quand une solution a été trouvée à votre problème
    pensez au tag

    Cours Dvp : http://ydisanto.developpez.com
    Blog : http://yann-disanto.blogspot.com/
    Page perso : http://yann-disanto.fr

  3. #3
    Membre habitué

    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    118
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Octobre 2004
    Messages : 118
    Points : 137
    Points
    137
    Par défaut
    Mais je reste avec un Object[] alors que j'ai besoin d'une référence sur un array de MyClass...

    En fait, j'ai une référence à affecter.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    /* addmettons que container contienne un member de type MyClass */
    container.myClass = new Object[0]; /* => type mismatch, en fait: IllegalArgumentException avec Field.set(object, value) */
    container.myClass = new MyClass[0]; /* => c'est cela qu'il me faut */

  4. #4
    Expert confirmé
    Avatar de le y@m's
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2005
    Messages
    2 636
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Février 2005
    Messages : 2 636
    Points : 5 943
    Points
    5 943
    Par défaut
    Il te suffit de transtyper
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    Class clazz = Class.forName("org.me.MyClass");
     
    Object[] myClasses = new Object[x];
    for(int i = 0; i < x; i ++) {
         myClasses[i] = clazz.newInstance();
    }
     
    /* ... */
     
    container.myClass = (MyClass) myClasses[0];
    Je ne répondrai à aucune question technique par MP.

    Pensez aux Tutoriels et aux FAQs avant de poster (pour le java il y a aussi JavaSearch), n'oubliez pas non plus la fonction Rechercher.
    Enfin, quand une solution a été trouvée à votre problème
    pensez au tag

    Cours Dvp : http://ydisanto.developpez.com
    Blog : http://yann-disanto.blogspot.com/
    Page perso : http://yann-disanto.fr

  5. #5
    Membre confirmé Avatar de spekal
    Inscrit en
    Mai 2005
    Messages
    502
    Détails du profil
    Informations forums :
    Inscription : Mai 2005
    Messages : 502
    Points : 510
    Points
    510
    Par défaut
    ... et en utilisant Array.newInstance je pense que ça fait tout de même mieux ce qu'on pense en plus rapide

  6. #6
    Membre habitué

    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    118
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Octobre 2004
    Messages : 118
    Points : 137
    Points
    137
    Par défaut
    Citation Envoyé par le y@m's
    Il te suffit de transtyper
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    container.myClass = (MyClass) myClasses[0];
    Ce code n'utilise pas la réflection pour le casting.
    Class.getName() retourne un format particulier dans le cas des arrays:
    http://java.sun.com/j2se/1.5.0/docs/...html#getName()

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    fieldClassName = "[Lorg.me.MyClass;"; /* retourné par Class.getName() */
    Class.forName(fieldClassName.substring(2, fieldClassName.length()-1) + "[]").cast(new Object[0])
    Et là j'ai une ClassNotFoundException, probablement à cause des "[]" ...

    Mais c'est bien un array de MyClass que je veux instancier.

  7. #7
    Membre habitué

    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    118
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Octobre 2004
    Messages : 118
    Points : 137
    Points
    137
    Par défaut
    Citation Envoyé par spekal
    ... et en utilisant Array.newInstance je pense que ça fait tout de même mieux ce qu'on pense en plus rapide
    Array.newInstance retourne un Object, comment caster çà en MyClass[] ?

  8. #8
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Salut,

    Citation Envoyé par Onarap
    Array.newInstance retourne un Object, comment caster çà en MyClass[] ?
    La méthode renvoit un objet, mais son type est bien un tableau de la classe passé, donc ceci fonctionne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    MyClass[] array = (MyClass[]) Array.newInstance(Class.forName("org.me.MyClass"), 1);
    Mais maintenant si tu utilises la reflection tu ne devrais pas avoir à caster sinon autant créer directement le tableau...

    a++

  9. #9
    Membre éclairé Avatar de g_rare
    Profil pro
    Inscrit en
    Novembre 2005
    Messages
    608
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2005
    Messages : 608
    Points : 683
    Points
    683
    Par défaut
    Citation Envoyé par adiGuba
    Mais maintenant si tu utilises la reflection tu ne devrais pas avoir à caster sinon autant créer directement le tableau...
    +1
    " Jag blev dömd för fildelning och allt jag fick var en sketen t-shirt. " (tankafritt.nu)
    PAS DE REPONSE PAR MESSAGE PRIVE ! Penser au bouton Résolu en bas de la discussion...

  10. #10
    Membre confirmé Avatar de spekal
    Inscrit en
    Mai 2005
    Messages
    502
    Détails du profil
    Informations forums :
    Inscription : Mai 2005
    Messages : 502
    Points : 510
    Points
    510
    Par défaut
    Je sens que tu es un peu perdu sur tes bases...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
        String[] tab;
     
        tab = (String[]) java.lang.reflect.Array.newInstance(String.class, 10);

  11. #11
    Membre habitué

    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    118
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Octobre 2004
    Messages : 118
    Points : 137
    Points
    137
    Par défaut
    adiGuba: justement si, je veux utiliser la réflection et la récursivité d'ailleurs car container contient des tas de sous-containers etc...

    Je parcours les Field du container avec
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    for (Field f : container.getClass().getDeclaredFields())
    et je voudrais instancier chaque membre. Lorsque ce membre est un type primitif, pas de problème:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if (f.getType() == Boolean.TYPE) { f.setBoolean(obj, false); }
    Si c'est une référence, pas de problème:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    f.getType().newInstance()
    Si c'est un array de type primitif, pas de problème:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if (f.getType().getName() == "[B") { f.set(obj, new byte[0]); }
    Mais si c'est un array de MyClass.... Je suis bloqué là.
    Mais c'est sûrement possible.

    spekal: ton casting n'est pas fait par réflection.

  12. #12
    Membre confirmé Avatar de spekal
    Inscrit en
    Mai 2005
    Messages
    502
    Détails du profil
    Informations forums :
    Inscription : Mai 2005
    Messages : 502
    Points : 510
    Points
    510
    Par défaut
    Citation Envoyé par Onarap
    spekal: ton casting n'est pas fait par réflection.
    Mais... tu ne peux pas faire un casting par reflexion, cela n'a aucun sens !

    Ecris un casting par reflexion comme si c'était possible, et tu verras de toi même que tu écris un truc complètement incohérent.

  13. #13
    Membre habitué

    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    118
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Octobre 2004
    Messages : 118
    Points : 137
    Points
    137
    Par défaut
    Citation Envoyé par spekal
    Mais... tu ne peux pas faire un casting par reflexion, cela n'a aucun sens !
    Ce serait pourtant tout l'intérêt de Class.cast()

    Mais bon... Reprenons.

    Ce code fonctionne:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    MyClass[] myClass = MyClass[].class.cast(Array.newInstance(MyClass.class, 0));
    System.out.println("myClass[] => " + Arrays.toString(myClass));
    Effectivement dans ce cas je pourrais faire le casting moi-même mais ce serait trop simple non

    Je cherche à faire pareil mais en partant de Field.getType() donc une Class dont getName() me retourne "[LMyClass;" ce qui signifie: array de MyClass.
    Comment, à partir de là, instancier un tel array? (Est-ce seulement possible?)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    /* container contient un array de MyClass */
    for (Field f : container.getClass().getDeclaredFields()) {
      if (f.getType().isArray() && f.getType().getName().startsWith("[L")) {
        /* ici je veux instancier un array de f.getType() */
        /* et l'affecter avec f.set(container, ary); ... */
      }
    }
    Je suis bien conscient qu'à ce stade je connais les types de tous les membres de container, mais là n'est pas la question.
    C'est une structure de données hiérarchique assez profonde, relativement grande et susceptible de changer souvent.
    D'où l'intérêt de la réflection pour pouvoir l'initializer une bonne fois pour toute.
    Ce que je veux éviter à tout prix c'est d'avoir des référence à null. Donc new MyClass[0] suffit.

    C'est clair que je ne suis pas obligé d'utiliser la réflection.
    Mais si je commence à faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    container.myClass = new MyClass[0]
    je devrais changer l'initialisation lorsque container aura un nouveau membre de type MyNewClass.

    [edit]
    Une dernière chose: la structure de donnée est générée et je n'ai pas la possibilité de changer ce générateur. Sinon c'est clair qu'on pourrait faire en sorte que toutes les références soient créées en cascade lors d'un appel du constructeur du top container.

  14. #14
    Membre confirmé Avatar de spekal
    Inscrit en
    Mai 2005
    Messages
    502
    Détails du profil
    Informations forums :
    Inscription : Mai 2005
    Messages : 502
    Points : 510
    Points
    510
    Par défaut
    Citation Envoyé par Onarap
    Effectivement dans ce cas je pourrais faire le casting moi-même mais ce serait trop simple non
    Ah ! Il fallait nous le dire tout de suite que tu cherchais à pas faire trop simple !

    Bon... c'est bientôt le week-end on va aller se reposer, hein, les idées seront certainement plus aérées au retour.

    A+.

  15. #15
    Membre habitué

    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    118
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Octobre 2004
    Messages : 118
    Points : 137
    Points
    137
    Par défaut
    Il y un moyen avec la méthode newArray de adiGuba présentée ici.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    /* par adiGuba */
        @SuppressWarnings("unchecked") // ne peut pas arriver, sauf avec les types primitifs
        public static <T> T[] newArray(Class<T> type, int lenght) {
            return (T[]) Array.newInstance(type, lenght);
        }
    J'appelle cette méthode comme ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    f.set(obj, newArray(Class.forName(f.getType().getName().substring(2, f.getType().getName().length()-1)), 0));
    Je note non sans ironie que le code de adiGuba contient un casting et que je l'appelle en utilisant la réflection

  16. #16
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Onarap
    Je note non sans ironie que le code de adiGuba contient un casting et que je l'appelle en utilisant la réflection
    Mais tu n'en as pas besoin dans ce cadre là !!!
    Le casting et les Generics sont quasiment inutile avec la reflection dans la plupart des cas, puisque justement tu ne connais pas le type à l'avance...


    Qu' est-ce qui t'empéchait de faire ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    f.set(obj, Array.newInstance(Class.forName(f.getType().getName().substring(2, f.getType().getName().length()-1)), 0));

    a++

  17. #17
    Membre habitué

    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    118
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Octobre 2004
    Messages : 118
    Points : 137
    Points
    137
    Par défaut
    Citation Envoyé par adiGuba
    Qu' est-ce qui t'empéchait de faire ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    f.set(obj, Array.newInstance(Class.forName(f.getType().getName().substring(2, f.getType().getName().length()-1)), 0));
    Avec çà j'ai une erreur à l'exécution (si je me souvient bien, une ClassCastException) car f (Field) est de type MyClass[] alors que Array.newInstance retourne Object. C'est un problème d'affectation, car contrairement au titre de ce sujet, je ne veux pas seulement instancier mais aussi affecter.
    C'est la même erreur qu'en écrivant
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    MyClass[] mc = Array.newInstance(MyClass.class, 0);
    sauf que là, elle vient déjà à la compilation (type mismatch).

    Mais c'est clair que c'est une utilisation particulière de la réflection puisque je connais tous les types é l'avance. J'utilise la réflection pour parcourir un type connu et instancier/affecter tous ses membres afin de ne jamais avoir de référence à null.
    Je pourrais manuellement affecter tous les champs mais la structure complète tient sur 7 pages imprimées, et en plus je sais déjà qu'elle va changer
    Donc avec la réflection je gagne en souplesse.

    Finalement çà marche, je dois dire que je suis satisfait de Java: avoir en même temps du typage statique et la dynamicité de la réflection, c'est excellent!
    (j'ai bien envie de tenter la même opération en C# pour voir, mais bon faut déjà que je mettes la main sur une machine windows)

  18. #18
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Onarap
    Avec çà j'ai une erreur à l'exécution (si je me souvient bien, une ClassCastException) car f (Field) est de type MyClass[] alors que Array.newInstance retourne Object.
    Mais si tu passe le bon type, l'objet retourné par Array.newInstance(MyClass.class) est bien du type MyClass[] donc tu ne devrais pas avoir d'exception...

    De plus la méthode set() attent un Object donc le cast est bien inutile...

    Citation Envoyé par Onarap
    C'est la même erreur qu'en écrivant
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    MyClass[] mc = Array.newInstance(MyClass.class, 0);
    sauf que là, elle vient déjà à la compilation (type mismatch).
    Non ce n'est pas la même chose car ici tu n'attend pas un type de retour Object mais un MyClass[], donc le cast est explicite :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    MyClass[] mc = (MyClass[]) Array.newInstance(MyClass.class, 0);
    Mais alors l'utilisation de la reflection est inutile car ceci est bien plus clair :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    MyClass[] mc = new MyClass[0];
    a++

  19. #19
    Membre habitué

    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    118
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Octobre 2004
    Messages : 118
    Points : 137
    Points
    137
    Par défaut
    Citation Envoyé par adiGuba
    De plus la méthode set() attent un Object donc le cast est bien inutile...
    Effectivement Cà devrait le faire aussi.
    J'imagine que je ne passais pas le bon type, sinon je ne vois pas...
    Mais bref çà marche maintenant. Je vais la garder avec casting, hein, après tous ces efforts

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Comment créer un array à deux dimensions avec une boucle
    Par m4riachi dans le forum Collection et Stream
    Réponses: 2
    Dernier message: 11/05/2015, 16h17
  2. Réponses: 4
    Dernier message: 13/06/2014, 11h37
  3. Créer un array d'objets
    Par iBadGamer dans le forum jQuery
    Réponses: 1
    Dernier message: 31/10/2013, 16h11
  4. [POO] Instancier un objet avec le nom de la classe
    Par shinchun dans le forum Langage
    Réponses: 4
    Dernier message: 08/06/2006, 13h44
  5. [Débutant] Créer une instance avec le nom d'une classe
    Par Quetzalcoatl dans le forum Langage
    Réponses: 7
    Dernier message: 23/01/2006, 20h43

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo