Partage
  • Partager sur Facebook
  • Partager sur Twitter

Équivalent PHP des tableaux dimensionnels.

Et comment s'en servir ^_^

Sujet résolu
    13 février 2012 à 23:16:01

    Bonsoir, j'ai débuté Java y a moins d'une semaine.

    Je viens de PHP/JavaScript, bref du web, j'ai des connaissances en C# et C mais ça s'arrête là.

    je souhaiterais savoir comment coder l'équivalent d'un tableau associatif multidimensionnel en Java.

    En php ça donnerai ça:
    <?php
    $montableau['Titres']['colonne1'] = "Poissons";
    $montableau['Titres']['colonne2'] = "Canidés";
    


    L'accès ou l'écriture du tableau est très simple, le parcours se fait avec un boucle foreach, bref, facile.

    En Java, j'ai regardé quelques tutos, j'ai vu que l'équivalent était l'objet Hashtable.
    Faux, je viens de lire ça ce soir avec les tutos SDZ, apparemment Hashtable est obsolète depuis plus de 10 ans...
    Donc l'objet Map ? Mais il est pas instanciable (et Eclipse fournit pas plus de précision et j'ai pas encore cherché pourquoi).

    Voilà la classe que j'avais faite: (Le code est pas terminé, incomplet et c'est pas un exemple vu l'utilisation d'objets obsolètes mais c'est pour comprendre le principe)

    /**
     * 
     */
    package coucheClient;
    
    import java.util.*;
    import javax.swing.*;
    
    /**
     * @author Ambroise Dhenain
     *
     */
    public class MenuPrincipal extends JMenuBar {
    	private Hashtable menuPrincipal;
    
    	/**
    	 * Constructeur basique:
    	 * @desc: Initialise la HashTable (Equivalent à un tableau associatif).
    	 */
    	public MenuPrincipal() {
    		super();
    		this.menuPrincipal = new Hashtable();
    	}
    	
    	/**
    	 * @name: ajouterMenu
    	 * @desc: Ajoute une entrée dans la Hashtable principale qui servira de titre de menu déroulant.
    	 * @param: String - nomMenu - Nom du menu qui référencera la seconde Hastable contenue dans la Hastable principale.
    	 */
    	public void ajouterMenu(String nomMenu){
    		this.menuPrincipal.put(nomMenu, new Hashtable());
    	}
    	
    	/**
    	 * @name: ajouterSousMenu
    	 * @desc: Ajoute une entrée dans une Hashtable secondaire qui servira de choix dans le menu déroulant.
    	 * @param: String - nomMenu - Nom du menu auquel appartiendra cette Hashtable.
    	 * @param: String - nomSousMenu - Nom du menu qui référencera la troisième Hastable contenue dans la Hastable secondaire.
    	 */
    	public void ajouterSousMenu(String nomMenu, String nomSousMenu){
    		Hashtable menuActuel = (Hashtable) this.menuPrincipal.get(nomMenu);
    		menuActuel.put(nomSousMenu, new Hashtable());
    	}
    
    	/**
    	 * @name: getMenu
    	 * @desc: Retourne la variable menuPrincipal sous forme de JMenuBar.
    	 */
    	public JMenuBar getMenu() {
    		
    		return this;
    	}
    	
    	
    }
    


    En gros cette classe est sensée correspondre au menu principal d'un logiciel, le menu qui contient généralement Fichier, Aide, etc...

    Ce que je souhaite faire est tout simplement une classe qui le représente et permet l'ajout et la génération du menu de manière dynamique (le tout stocké dans un tableau associatif multidimentionnel).
    L'idée est donc via des méthodes setMenu/setSousmenu de mettre le menu complet dans un hashtable puis via la méthode get lire ce Hashtable et via une boucle convertir chaque élément en objet, ajouter les objets au menu et retourner le menu de facon à ce qu'il soit ajouté au JFrame.

    Bref je bloque, parce que si j'arrive à voir comment je peux allouer dans un Hashtable d'autres hashtable et écrire/lire dans ses hashtables.

    Si vous avez un exemple concret et fonctionnel je dis pas non, pour le moment la seule solution auquel j'ai pensé est que lors de la modification d'un sous menu je récupère le menu(qui est un hashtable secondaire) et je lui ajoute des options puis je place le hashtable modifié à la place de son équivalent précédent.

    Mais bon, c'est lourd, long à coder, pas pratique du tout et je vais pas réinventer la roue...

    Je vous remercie par avance ;)
    • Partager sur Facebook
    • Partager sur Twitter
      13 février 2012 à 23:23:43

      Map est une interface qui doit être utilisée avec une implémentation de Map : http://java.developpez.com/faq/java/?p [...] IONS_info_map

      PS : Ta structure de données peut être représentée de cette manière en Java :
      Map<String, Map<String, String>> monTableau;
      // ... initialisation de monTableau ...
      
      // Récupération d'une valeur :
      String bidule = monTableau.get("Titres").get("colonne1"); // Poissons
      String truc = monTableau.get("Titres").get("colonne2"); // Canidés
      

      Mais c'est clair que c'est moins immédiat à utiliser que les tables de hashage de PHP.
      • Partager sur Facebook
      • Partager sur Twitter
        13 février 2012 à 23:47:20

        Merci !
        Au passage, quel est selon toi la meilleure méthode pour lister en boucle tous les éléments contenus dans un HashMap ?

        Quand j'utilise un foreach il me dit que je peux avoir qu'un tableau ou enumération, pas de hashMap, et j'ai pas de méthode pour transformer un hashMap en tableau ou itération ><

        En tout cas la récupération de cette manière reste toujours plus simple que la mienne xD
        • Partager sur Facebook
        • Partager sur Twitter
          13 février 2012 à 23:49:11

          Un peu plus bas dans la même FAQ : http://java.developpez.com/faq/java/?p [...] parcourir_map
          (Cette FAQ est à avoir dans ses favoris quand on fait du Java, surtout quand on débute).
          • Partager sur Facebook
          • Partager sur Twitter
            14 février 2012 à 0:04:17

            Hum, je n'y arrive pas, toujours un problème de type (vive le haut niveau, ça fait mal de revenir au Java ^^').

            public class MSG {
            	
            	private HashMap data;
            	
            	/**
            	 * Constructeur basique:
            	 * @desc: Initialise la HashTable (Equivalent à un tableau associatif).
            	 */
            	public MSG() {
            		this.data =  new HashMap();
            	}
            
            /**
            	 * @name: afficherDatas
            	 * @desc: Affiche le contenu de la variable privée datas.
            	 */
            	public void afficherDatas() {
            		Entry datas = (Entry) this.data;
            		System.out.println("--------------------- --------------------------");
            		System.out.println("----------- Contenu de l'objet MSG -------------");
            		System.out.println("--------------------- --------------------------");
            
            		for (Map.Entry data : datas.entrySet()){
            		    System.out.println(data.getKey() + " : " + data.getValue());
            		}
            	}
               }
            


            Je bloque sur afficherDatas(), je comprends pas comment (datas est un HashMap) afficher datas dans un foreach.
            Soit le cast passe pas, soit le type est invalide soit mon data n'a pas les méthodes getKey/getValue, bref quoi que je tente y a toujours un problème.

            Merci de ton aide, j'ai mis le lien en raccourcis ^^'

            • Partager sur Facebook
            • Partager sur Twitter
              14 février 2012 à 8:49:12

              Pourquoi tu cast ?


              Et pour "vive le haut-niveau..." j'avoue avoir esquissé un large sourire. :)
              • Partager sur Facebook
              • Partager sur Twitter
                15 février 2012 à 16:14:29

                Allez, tu y es presque ;)

                public class MSG {
                
                        // HashTable est obsolète, on utilise map
                	private Map<String, String> data;
                
                	/**
                	 * Constructeur basique:
                	 * 
                	 * @desc: Initialise la HashTable (Equivalent à un tableau associatif).
                	 */
                	public MSG() {
                                // On instancie avec l'implémentation HashMap
                		this.data = new HashMap<String, String>();
                	}
                
                	/**
                	 * @name: afficherDatas
                	 * @desc: Affiche le contenu de la variable privée datas.
                	 */
                	public void afficherDatas() {
                
                		// Set est l'interface d'une liste sans doublon
                		// Cette liste contient l'ensemble des pairs clef-valeur
                		Set<Entry<String, String>> entrySet = this.data.entrySet();
                
                		System.out.println("--------------------- --------------------------");
                		System.out.println("----------- Contenu de l'objet MSG -------------");
                		System.out.println("--------------------- --------------------------");
                
                		// On crée un itérieur sur la "Set"
                		Iterator<Entry<String, String>> it = entrySet.iterator();
                
                		while (it.hasNext()) {
                			Entry<String, String> entry = it.next();
                
                			System.out.println(entry.getKey() + " : " + entry.getValue());
                		}
                
                	}
                }
                
                • Partager sur Facebook
                • Partager sur Twitter
                  17 février 2012 à 20:09:52

                  Merci ;)

                  As tu testé chez toi ? Car ça ne fonctionne pas, voilà l'erreur fournie par Eclispe:
                  Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
                  at coucheMetier.MSG.afficherDatas(MSG.java:101)
                  at coucheClient.ClassePrincipale.main(ClassePrincipale.java:31)

                  Alors du coup j'ai mis en commentaire ton
                  System.out.println(entry.getKey() + " : " + entry.getValue());

                  et j'ai affiché:
                  System.out.println(entry.toString());

                  Ca fonctionne comme ça. J'ai tenté un cast en String auparavant mais ça n'a pas fonctionné :/ Bizarre d'ailleurs, je comprends pas pourquoi il peut pas caster un Integer en String ><

                  En tout cas merci, je pourrais voir mon objet de cette manière.

                  Par contre je ne comprends pas cette écriture:
                  Set<Entry<String, String>> entrySet = this.data.entrySet();

                  Si j'essaye de traduire en français, ça serait:
                  Je crée un entrySet de type Entry<String, String> prenant la place d'un Set en mémoire (interface).

                  En quoi la classe Entry est-elle spéciale pour l'utiliser elle et pas un ArrayMap ou autre type de List ?

                  Merci ;)

                  PS: Code complet de la classe:
                  /**
                   * 
                   */
                  package coucheMetier;
                  
                  import java.lang.reflect.Array;
                  import java.util.*;
                  import java.util.Map.Entry;
                  
                  /**
                   * @author Ambroise Dhenain
                   *
                   */
                  public class MSG {
                  	
                  	private HashMap data;
                  	
                  	/**
                  	 * Constructeur basique:
                  	 * @desc: Initialise la HashTable (Equivalent à un tableau associatif).
                  	 */
                  	public MSG() {
                  		this.data =  new HashMap();
                  	}
                  	
                  	/**
                  	 * Constructeur surchargé:
                  	 * @desc: Initialise la HashTable avec une HashTable existante. (Equivalent à un tableau associatif).
                  	 */
                  	public MSG(HashMap data) {
                  		this.data = data;
                  	}
                  
                  	/*
                  	 * ---------------------- Accesseurs: ----------------------
                  	 */
                  	
                  	/**
                  	 * @name: getData
                  	 * @desc: Retourne la veleur de la clé du HashTable data.
                  	 * @param: Object - key - Clé du HashTable à retourner.
                  	 */
                  	public Object getData(Object key) {
                  		return this.data.get(key);
                  	}
                  	
                  	/**
                  	 * @name: getDatas
                  	 * @desc: Retourne le HashTable data.
                  	 */
                  	public Object getDatas() {
                  		return this.data;
                  	}
                  	
                  	
                  	/*
                  	 * ---------------------- Mutateurs: ----------------------
                  	 */
                  	
                  	/**
                  	 * @name: setData
                  	 * @desc: Met à jour / Ajoute la value dans la key.
                  	 * @param: 	Object - key - Clé du HashTable.
                  	 * 			Object - value - Valeur à mettre dans la clé.
                  	 */
                  	public void setData(Object key, Object value) {
                  		this.data.put(key, value);
                  	}
                  	
                  	/**
                  	 * @name: setDatas
                  	 * @desc: Remplace le HashTable data courant par le HashTable datas fourni.
                  	 * @param: 	Hashtable - datas - HashTable à mettre dans la variable data de l'objet courant.
                  	 */
                  	public void setDatas(HashMap datas) {
                  		this.data = datas;
                  	}
                  	
                  	/*
                  	 * ---------------------- Méthodes: ----------------------
                  	 */
                  	
                  	/**
                  	 * @name: afficherDatas
                  	 * @desc: Affiche le contenu de la variable privée datas.
                  	 */
                  	public void afficherDatas() {
                  		// Set est l'interface d'une liste sans doublon
                  		// Cette liste contient l'ensemble des pairs clef-valeur
                  		Set<Entry<String, String>> entrySet = this.data.entrySet();
                  
                  		System.out.println("--------------------- --------------------------");
                  		System.out.println("----------- Contenu de l'objet MSG -------------");
                  		System.out.println("--------------------- --------------------------");
                  
                  		// On crée un itérieur sur la "Set"
                  		Iterator<Entry<String, String>> it = entrySet.iterator();
                  
                  		while (it.hasNext()) {
                  			Entry<String, String> entry = it.next();
                  //			System.out.println(entry.toString());
                  			System.out.println(entry.getKey() + " : " + entry.getValue());
                  		}
                  	}
                  
                  
                  
                  	/* (non-Javadoc)
                  	 * @see java.lang.Object#clone()
                  	 */
                  	@Override
                  	protected Object clone() throws CloneNotSupportedException {
                  		// TODO Auto-generated method stub
                  		return this.clone();
                  	}
                  }
                  
                  • Partager sur Facebook
                  • Partager sur Twitter
                    18 février 2012 à 18:04:52

                    Pour répondre à ta première question: oui mon code fonctionne parfaitement.
                    Si tu as une erreur, c'est parce que tu ne l'utilises pas :p


                    Déjà petit rappel sur le polymorphisme.

                    HashMap est une "implémentation" d'une "interface".
                    C'est à dire que pour une "Interface" qui de définit le fonctionnement globale d'un objet (c'est à dire les méthodes disponible), il existe également un objet qui "implemente" ces méthodes (c'est à dire qu'il effectue l'action).

                    L'idée, est de permettre, par une même interface, d'avoir des implémentations différentes, et donc des fonctionnement différent, tout en proposant exactement les même méthodes.


                    L'interface "Map" fournis les méthodes nécessaires au stockage de clef-valeur.
                    Il existe donc également plusieurs implémentation de cette interface (ex: HashMap, IdentityHashMap, TreeMap, ConcurrentHashMap, LinkedHashMap....)

                    Celle basique, qui correspond à tes besoin est "HashMap". Mais prend l'habitude de ne manipuler que son interface !

                    Map maMap = new HashMap();
                    




                    Ensuite concernant ton erreur de cast. Je ne peut que supposer que tu enregistre dans ta map un entier. Mais à la récupération tu demande un String => erreur

                    Java est un langage typé. Même s'il est possible de sauvegarder n'importe quel type de valeur ou objet dans une collection, il n'en conserve pas moins leur type !
                    A la récupération, tu dois effectuer un cast explicite dans le bon type d'objet attendu ! Si tu ne le fais pas, tu obtiens un ClassCastException.


                    Mais comment savoir quel type d'objet on a stocké ?
                    La réponse est simple: on ne peut pas. (pas propremenet en tout cas).


                    C'est pourquoi, il est OBLIGATOIRE de définir le type des valeurs stockés. Le java te permet de ne pas déclarer les types principalement pour des problèmes de rétrocompatibilités.

                    Exemple de déclaration:
                    // La clef est de type String, et la valeur de type Integer
                    Map<String, Integer> maMap = new HashMap<String, Integer>();
                    
                    // La clef est de type String, et la valeur de type String
                    Map<String, String> maMap = new HashMap<String, String>();
                    
                    // La clef est de type Integer, et la valeur de type Float
                    Map<Integer, Float> maMap = new HashMap<Integer, Float>();
                    
                    // La clef est de type String, et la valeur de type Object (n'importe quoi donc, mais attention au cast ! )
                    Map<String, Object> maMap = new HashMap<String, Object>();
                    





                    Ta remarque sur le Set est pertinente. Voilà l'explication:

                    L'interface Map ne permet pas facilement de lire les éléments qu'elle contient. En effet, il n'y a pas d'itérateur direct.

                    Il faut donc récupérer une liste intermédiaire. 3 méthodes existes pour celà:

                    keySet() Retourne une liste de type "Set<K>" qui ne contient que les clef.
                    values() Retourne une liste de type "Collection<V>" qui ne retourne que les valeurs.
                    entrySet() Retourne une liste de type "Set<Map.Entry<K,V>>", c'est à dire une liste de "Entry", où chaque "Entry" possède la clef et la valeur associé.

                    A partir de l'une de ces listes, on peut donc utiliser un itérateur pour lire son contenu.

                    http://docs.oracle.com/javase/6/docs/a [...] util/Map.html


                    On remarque que les listes retourne sont des "Set" (exception pour values() ). Alors pourquoi l'interface Set plutôt que List ?
                    La différence se trouve au niveau des doublons. Set est une collection d'objet qui n'accepte pas deux fois la même valeur, alors que List le permet.

                    exemple:

                    MonObjet obj = new MonObjet;
                    
                    Set<MonObjet> maSet = new HashSet<MonObjet>();
                    List<MonObjet> maList = new ArrayList<MonObjet>();
                    
                    maList.add(monObjet);
                    maList.add(monObjet); // pas de problème pour la deuxième insertion
                    
                    maSet.add(monObjet);
                    maSet.add(monObjet); // refusé, car l'objet est déjà présent
                    



                    Comme dans une Map, chaque clef est unique, la collection Set est plus approprié pour retourne les valeurs qu'elle contient.


                    Quelques exemples ici:
                    http://java.developpez.com/faq/java/?p [...] parcourir_map
                    • Partager sur Facebook
                    • Partager sur Twitter
                      20 février 2012 à 17:15:38

                      Merci beaucoup pour tes explications, j'ai pu tout comprendre même si une deuxième lecture s'est imposée ^^

                      Voilà le code de la méthode afficherDatas():

                      /**
                      	 * @name: afficherDatas
                      	 * @desc: Affiche le contenu de la variable privée datas.
                      	 */
                      	public void afficherDatas() {
                      		// Set est l'interface d'une liste sans doublon
                      		// Cette liste contient l'ensemble des pairs clef-valeur
                      		Set<Entry<Object, Object>> entrySet = this.data.entrySet();
                      
                      		System.out.println("--------------------- --------------------------");
                      		System.out.println("----------- Contenu de l'objet MSG -------------");
                      		System.out.println("--------------------- --------------------------");
                      
                      		// On crée un itérieur sur la "Set"
                      		Iterator<Entry<Object, Object>> it = entrySet.iterator();
                      
                      		while (it.hasNext()) {
                      			Entry<Object, Object> entry = it.next();
                      			System.out.println(entry.getKey() + "("+entry.getValue().getClass()+")" + " = " + entry.getValue()+ "("+entry.getValue().getClass()+")");
                      		}
                      		
                      	}
                      


                      J'avais totalement zappé le typage quand j'avais testé.
                      Merci aussi pour les explications concernant Map et List, j'ai aussi compris un coup ça retourne un Set et un autre une collection, c'est dû à l'intégrité des données, impossible de doubler les clés, pas bête...

                      Que de chemin pour simplement faire ça en tout cas !

                      Voici ce que m'affiche ma méthode:
                      0(class java.lang.Integer) = 1(class java.lang.Integer)
                      0,25(class java.lang.String) = Test3(class java.lang.String)

                      Il y a un moyen pour récupérer uniquement 'String' ou 'Integer' ? j'ai essayé via split() mais ça me donne un résultat surprenant ^^ (C'est pas une chaîne de caractère)

                      Dans le but de savoir exactement de quel type est la variable étant donné que je cast tout en Object par facilité. Et que class java.lang.String c'est moche ^^

                      Merci ;)

                      __
                      Ah, Eclipse m'a répondu, j'avais pas pensé à regarder les méthodes associées ;)
                      getSimpleName()
                      • Partager sur Facebook
                      • Partager sur Twitter

                      Équivalent PHP des tableaux dimensionnels.

                      × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                      × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                      • Editeur
                      • Markdown