Sharpshooter 0 Posté(e) le 22 septembre 2006 Partager Posté(e) le 22 septembre 2006 Bonjour, J'ai une question à propos des types génériques en Java (des fois que Gfx trainerait encore ici ). J'ai une classe qui commence comme ceci : public class Personne dans laquelle il y a un objet comme ceci : P profession; Le problème est que je ne peux pas accéder aux méthodes de cet objet comme ceci par exemple : String nom = profession.getNom(); Le compilateur me dit qu'il ne trouve pas la méthode getNom() dans java.lang.Object ce qui me parait normal. Mais pourquoi mon objet profession a-t-il perdu le type P pour redevenir de type Object ? Je précise qu'à l'initialisation P est bien de type Medecin, Enseignant, ... Est-ce une limitation de la généricité dans Java ou suis-je passé à côté de quelque chose ? Lien à poster
Gfx 0 Posté(e) le 22 septembre 2006 Partager Posté(e) le 22 septembre 2006 Les generics de Java ne sont pas les templates du C++ Java utilise la type erasure : au runtime les generics sont traités comme des Object. Pour résoudre ton problème voici ce qu'il faut faire : public class Personne Maintenant le compilateur sait que P sera forcément du type Profession (dans lequel tu ne manqueras pas de déclarer la méthode getNom()). Java utilise cette approche pour éviter le latent typing qui conduit à bien des problèmes. Plus d'infos ici : http://www.progx.org/index.php?section=replies&newsid=212 Lien à poster
Sharpshooter 0 Posté(e) le 22 septembre 2006 Auteur Partager Posté(e) le 22 septembre 2006 Hum... Ca marche mais j'utilise la méthode getNom() de la classe Profession, or je voudrais pouvoir utiliser celle de la classe P. Si j'ai bien compris ce que tu dis ce n'est pas possible ? En fait je voudrais pouvoir créer une personne qui soit médecin ou enseignant ou autre. La classe personne sera la plus utilisée je ne veux donc pas créer une classe médecin qui hérite de personne mais plutôt une sorte de classe personne qui hérite de médecin ou d'instituteur selon le cas. Je ne sais pas si je suis très clair. Faudrait que je dorme un peu Lien à poster
thev 0 Posté(e) le 22 septembre 2006 Partager Posté(e) le 22 septembre 2006 L'approche est bizarre je pense. Un médecin ou un instituteur sont des genres de personnes, personne devrait donc être la super classe. A mon avis si tu résonnes différemment tu vas arriver à quelque chose de tordu. Ou alors je n'ai pas compris ton problème. Après tu peux peut être résoudre ça avec des interfaces médecin, instituteur, et ta personne implemente l'une ou l'autre... Sinon Gfx nous sortira bien une notion de derrière les fagots @+ Lien à poster
Sharpshooter 0 Posté(e) le 22 septembre 2006 Auteur Partager Posté(e) le 22 septembre 2006 Oui je sais, je prends un peu le problème à l'envers mais en fait la classe Personne sera utilisée sans cesse et contient beaucoup de données alors que la classe Medecin ne rajoute qu'un ou deux trucs. Je vois plus la classe Médecin comme une caractéristique de la personne, pas comme un objet à part entière à utiliser. C'est pour ça que les types génériques m'allaient bien. Tant pis je vais faire autrement. Lien à poster
thev 0 Posté(e) le 23 septembre 2006 Partager Posté(e) le 23 septembre 2006 Bah si tu fais public class Personne { Profession p; } où Profession est une interface public interface Profession { public String getNom(); } et où Medecin, Enseignant implémentent Profession, ça ne répond pas au problème ? Alors après tu avais peut être une vision particulière d'utilisation par les generics, mais j'avoue ne pas les avoir trop utilisé pour bien en parler. @+ Lien à poster
nworr 0 Posté(e) le 23 septembre 2006 Partager Posté(e) le 23 septembre 2006 La généricté en Java, c'est depuis quand ? Mais sinon le pattern Décorateur ça irait pas pour ton probleme ? Lien à poster
Sharpshooter 0 Posté(e) le 23 septembre 2006 Auteur Partager Posté(e) le 23 septembre 2006 Je suis pas trop au jus à propos des patterns (faudrait mais bon). La généricité c'est depuis java 1.5 avec plein d'autres trucs hyper intéressants comme les enumérations qui évitent les constantes à tours de bras, les transtypages automatiques pour certains types (Int en int, ...), des méthodes avec un nombre d'arguments variables et la possibilité d'importer les membres statiques d'un package. Bah je voulais utiliser les types générique parce que ça me semblait sympa mais tant pis je vais faire de profession une variable quelconque (de type Profession) et j'utiliserai un enum et un switch / case. J'aime pas trop mais bon. Lien à poster
Gfx 0 Posté(e) le 23 septembre 2006 Partager Posté(e) le 23 septembre 2006 Sharpshooter : Il n'y a pas de problème avec ma solution. Si tu surcharges getNom() dans les classes qui héritent de Profession, ce sont ces méthodes qui seront appelée, pas celle de Profession. Révises ta POO Java n'est pas comme le C++ avec les méthodes virtuelles et autres. Exemple : class A { public String getNom() { return "A"; } } class B extends A { public String getNom() { return "B"; } } A objet = new B(); objet.getNom(); // Renvoie "B", pas "A" Lien à poster
nworr 0 Posté(e) le 23 septembre 2006 Partager Posté(e) le 23 septembre 2006 Le décorateur : description sommaire sur #progx Et je ne suis plus très sur que le pattern Décorateur est celui auquel je pensais :sorry. Mais euh pourquoi faire un enum avec switch cas ? un héritage profession -> medécin, plombier, etc ... n'irrait pas ? Lien à poster
Sharpshooter 0 Posté(e) le 23 septembre 2006 Auteur Partager Posté(e) le 23 septembre 2006 Pfff ! Étant donné que le nom de la profession ne change pas je l'avais mis en "static final"... et du coup son accesseur aussi ! Quand je disais qu'il fallait que je dorme. Bien évidemment j'avais regardé sur Progx avant de poster ici mais je n'avais pas trouvé l'article sur les classes génériques ... ... Merci à tous pour tout. Je vais adopter la solution de Gfx et aller me coucher Lien à poster
PoP 0 Posté(e) le 25 septembre 2006 Partager Posté(e) le 25 septembre 2006 Sharpshooter.sleep(462 * NIGHT); Lien à poster
Sharpshooter 0 Posté(e) le 26 septembre 2006 Auteur Partager Posté(e) le 26 septembre 2006 En tout cas ça marche maintenant (avec la solution de Gfx). La généricité est vraiment très pratique. Du coup j'ai une autre question : est-il possible d'effectuer une initialisation de la forme P profession = new P(). ? Bien entendu tel quel j'ai essayé et ça ne marche pas. Java est décidément un langage très élégant. Lien à poster
PoP 0 Posté(e) le 26 septembre 2006 Partager Posté(e) le 26 septembre 2006 Pourquoi tu veux faire ça? J'ai l'impression que tu veux absolument utiliser des generics alors que tu n'en as pas forcément besoin. Sinon oui Java c'est élégant comme langage, ça fait 15 jours que je me bats avec du C# et j'ai du mal avec les 462 paramètres qu'il faut passer pour instancier le moindre truc. Lien à poster
Sharpshooter 0 Posté(e) le 26 septembre 2006 Auteur Partager Posté(e) le 26 septembre 2006 Si si, ce cas là est typiquement le cas d'utilisation des types génériques. Je ne veux pas utiliser l'héritage car je n'utiliserais les sous-classes créées quasiment qu'une seule fois (à l'initialisation). Lien à poster
thev 0 Posté(e) le 26 septembre 2006 Partager Posté(e) le 26 septembre 2006 Sharpshooter> P profession = P.class.newInstance(); (P doit avoir un constructeur par défaut, sinon tu obtiendras une IllegalAccessException). http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Class.html#newInstance() @+ Lien à poster
Gfx 0 Posté(e) le 26 septembre 2006 Partager Posté(e) le 26 septembre 2006 thev : Non on ne peut pas faire ça avec les generics. Lien à poster
Gfx 0 Posté(e) le 26 septembre 2006 Partager Posté(e) le 26 septembre 2006 Sharpshooter, thev> Pour faire votre truc voici la marche à suivre : public class Conteneur { public T createInstance(Class klass) { try { return klass.newInstance(); } catch (InstantiationException ie) { return null; } catch (IllegalAccessException iae) { return null; } } } C'est juste un exemple pour montrer qu'on doit avoir un Class pour faire une instance de T. Sharp, tu peux jeter un oeil au code source de ma lib Fuse (http://fuse.dev.java.net) qui est générifiée à mort pour transformer du texte en object Java en fonction de types découverts par introspection. Lien à poster
thev 0 Posté(e) le 26 septembre 2006 Partager Posté(e) le 26 septembre 2006 Comment obtient-on un Class à partir de T (cette question peut paraître bizarre car des choses m'échappent) ? Faudra que je regarde les generics de manière plus approfondie car je vois que je n'en connais rien (hormis la simple utilisation à travers les Collection et Cie.) @+ Lien à poster
Gfx 0 Posté(e) le 1 octobre 2006 Partager Posté(e) le 1 octobre 2006 Ben comme ça : new Conteneur(JLabel.class) Lien à poster
Sharpshooter 0 Posté(e) le 1 octobre 2006 Auteur Partager Posté(e) le 1 octobre 2006 Heu... il y a un truc qui m'échappe. Ce bout de code : public class Conteneur { public T createInstance(Class klass) { try { return klass.newInstance(); } catch (InstantiationException ie) { return null; } catch (IllegalAccessException iae) { return null; } } } Permet de créer une instance de type T quelque soit le T que l'on passe en paramètre... mais du coup il faut passer T en paramètre de la classe Conteneur. non ? Lien à poster
Gfx 0 Posté(e) le 2 octobre 2006 Partager Posté(e) le 2 octobre 2006 Oui : Machin m = new Conteneur().createNewInstance(Machin.class); Cela dit on peut aussi faire ceci : public class Conteneur { public static T createInstance(Class klass) throws Exception { return klass.newInstance(); } public static void main(String... args) throws Exception { System.out.println(Conteneur.createInstance(javax.swing.JButton.class)); } } C'est juste très con cette façon-là puisqu'en appelan createInstance() on connaît forcément le type, donc autant faire un Class<?>.newInstance() nous-mêmes. Là où ça devient intéressant, c'est avec les jokers : public class Conteneur { public static T createInstance(Class klass) throws Exception { return klass.newInstance(); } public static void main(String... args) throws Exception { // pass System.out.println(Conteneur.createInstance(javax.swing.JButton.class)); // fail System.out.println(Conteneur.createInstance(java.io.File.class)); } } Dans ce cas, la méthode createInstance() ne peut-être appelée que lorsque le type T passé en paramètre hérite de JComponent, ce qui n'est bien sûr pas le cas de la classe File. Dans tous les cas, ces exemples montrent deux choses : - On peut créer une instance à partir d'un type T à condition d'avoir également le Class correspondant ; - Cela ne sert pour ainsi dire à rien d'avoir une telle fonctionnalité dans une API publique. J'ai écrit du code qui utilise cette technique mais ce n'est qu'une partie d'un process plus important et ce n'est pas une API publique. Lien à poster
Sharpshooter 0 Posté(e) le 2 octobre 2006 Auteur Partager Posté(e) le 2 octobre 2006 Je vais sûrement dire une bétise mais est-ce qu'on ne pourrait pas faire un truc du genre : class Personne { public static Personne creer(Medecin m) { return new Personne(); } public static Personne creer(Enseignant e) { return new Personne(); } ... } Une sorte de constructeur bis qui permettrait de faire appel à : creer(profession) et la personne serait créée quel uqe soit le type de profession. Lien à poster
Gfx 0 Posté(e) le 3 octobre 2006 Partager Posté(e) le 3 octobre 2006 Il y a plus simple : class Personne { public static Personne creer(T profession) { return new Personne(); } } Lien à poster
Sharpshooter 0 Posté(e) le 3 octobre 2006 Auteur Partager Posté(e) le 3 octobre 2006 Pour l'instant il me répond : type parameter T is not within its bound Lien à poster
Messages recommandés