Résolu [JAVA] utilisé une variable pour cast
-
Hey ! Oui c’est encore moi
Je vous rassure, cette fois ci mon problème n’es pas très compliquer, et concerne UNIQUEMENT un aspect de java : soit vous savez, soit vous ne savez pas… Et apparemment google ne sais pas donc bon ^^’
Après avoir résolue le problème sur ma classe de block, je me suis rendu compte qu’il me manquais un détail : le cas ou je veux une texture venus d’un autre mods (ou vanilla).
Du coup, j’ai commencé a réfléchir a comment faire, et la je me suis rendu compte de quelque chose : 3 classes (a l’heure actuel) utilise EXACTEMENT la même procédure (a 1 fonction près pour être exacte). Du coup, pour simplifier, j’ai voulus créer une fonction générique pour le gerer.Jusque la pas de problème, sauf que voila, pour que cette classe soit générique, je lui donne comme paramètre une variable de type Objet.
Je compté ensuite caster ma variable en fonction d’une variable de type Class.
En théorie c’étais cool… En pratique, il c’est avéré bien plus compliqué de mettre ceci en place. J’ai donc chercher sur internet comment faire, et le peu de solution que j’ai trouvé ne m’on pas aidé…Voila les deux variante que j’ai trouvé sur internet, mais aucune d’elle ne semble fonctionné
C’est loin d’être un problème urgent (je peu toujours faire une chier de condition avec instanceof, mais ce serai beaucoup moins pratique), mais je dois avoué que çà me chiffonne de ne pas trouvé de solution pour un problème si simple à premier vue…
En tous cas, merci d’avance si quelqu’un se penche sur le sujet ^^
public static void commonInit(String name, String modid, Object obj, String oreDictionnaryName) { Class myClass; if(obj instanceof JBlock) { myClass = Class.forName("fr.jodge.jodgeLibrary.common.block.JBlock"); } else if(obj instanceof JItem) { myClass = Class.forName("fr.jodge.jodgeLibrary.common.item.JItem"); } else { myClass = Class.forName("fr.jodge.jodgeLibrary.common.extendWeapons.JWeapons"); } String m = JFunction.convertNameToUnLocalizedName(name); ((myClass)obj).setUnlocalizedName(m); GameRegistry.registerBlock(((myClass)obj), m); Main.proxy.registerBlockTexture(((myClass)obj), m, modid); if (((myClass)obj).oreDictionnaryName.isEmpty()) { ((myClass)obj).oreDictionnaryName = JFunction.convertNameToOreDictionaryName(name); } OreDictionary.registerOre(oreDictionnaryName, ((myClass)obj)); }
public static void commonInit(String name, String modid, Object obj, String oreDictionnaryName) { Class myClass; if(obj instanceof JBlock) { myClass = Class.forName("fr.jodge.jodgeLibrary.common.block.JBlock"); } else if(obj instanceof JItem) { myClass = Class.forName("fr.jodge.jodgeLibrary.common.item.JItem"); } else { myClass = Class.forName("fr.jodge.jodgeLibrary.common.extendWeapons.JWeapons"); } String m = JFunction.convertNameToUnLocalizedName(name); (obj.getClass()).setUnlocalizedName(m); GameRegistry.registerBlock((obj.getClass()), m); Main.proxy.registerBlockTexture((obj.getClass()), m, modid); if ((obj.getClass()).oreDictionnaryName.isEmpty()) { (obj.getClass()).oreDictionnaryName = JFunction.convertNameToOreDictionaryName(name); } OreDictionary.registerOre(oreDictionnaryName, (obj.getClass())); }
-
Le plus simple dans ce cas est de faire soit une classe générique soit une interface.
-
Je ne peu pas faire de classe générique car chacun des classes qui fait appelle a cette fonction est déjà une extension d’une classe de Minecraft.
Par contre, je vais me renseigner sur les interfaces, c’est un truc que je ne connais absolument pas (je ne crois pas que a existe en C++)
Okay, alors j’ai compris (plus ou moins) le principe des interfaces.EDIT :
J’ai bien compris que je pouvais utilisé l’interface pour identifier les éléments qui font appelle a ma grosse procédure.
Pour les fonctions que j’ai créer moi même, ils suffiraient d’en ajouter un exemplaire vide dans l’interface. C’est la je ne comprend pas très bien : comment je peu évité de remplir la fonction sur chacune des mes classes (sachant qu’il s’agit toujours de la même action, à savoir attribuer une valeurs a une variable que j’ai créer dans la classe (variable strictement identique entre chaque classe). J’ai cru comprendre qu’il n’étais pas possible de mettre des fonctions dans l’interface (en tous cas pas avec Java 6 et 7), et que l’on ne pouvais mettre que des constantes, du coup, il faut forcément re-écrire chaque comportement ? On ne peu pas lui en donner un par défaut (un peu comme une fonction hérité que l’on re-écrit) ?
Ensuite, viens le problème des classes déjà implémentés par Minecraft. Je suis obliger de créer une fonction passerelle dans mes classes que j’applique dans l’interface, ou je peu directement l’appeler comme celle fournis par Minecraft (avec l’héritage) ? -
Non, pas moyen de donner un comportement par défaut à une fonction qui se trouve dans une interface.
Dans l’interface il me semble que tu peux remettre une fonction qui a le même nom qu’une fonction qui se trouve dans la classe mère. Donc pas besoin de “fonction passerelle”.Mais je capte pas très bien ce que tu veux faire avec ta fonction
public static void commonInit(String name, String modid, Object obj, String oreDictionnaryName)
J’ai plus l’impression que tu complique les choses pour rien.
Surtout que GameRegistry.registerBlock((obj.getClass()), m); ne marchera jamais, puisqu’il faut l’instance de l’objet et non la classe. -
Tu peux tout à fait mettre des fonctions par défaut dans une interface (j’ai remarqué çà y’a pas longtemps, c’est une particularité du java), tu as juste à rajouter le modifier “default” à ta méthode, exemple : default void test(T paramT, E paramE){ton code…}.
Par contre, je vois pas où tu utilises ta variable “myClass” et à quoi elle te sert.
PS : je pense faire un tuto quand je rentrerais de vacances sur comment bien organiser ses mods proprement.
-
@‘robin4002’:
Non, pas moyen de donner un comportement par défaut à une fonction qui se trouve dans une interface.
Dans l’interface il me semble que tu peux remettre une fonction qui a le même nom qu’une fonction qui se trouve dans la classe mère. Donc pas besoin de “fonction passerelle”.J’ai effectué des tests, et en effet cela fonctionne, bien qu’a cause des arguments cela me limites beaucoup
@‘robin4002’:
Mais je capte pas très bien ce que tu veux faire avec ta fonction
public static void commonInit(String name, String modid, Object obj, String oreDictionnaryName)
J’ai plus l’impression que tu complique les choses pour rien.
Surtout que GameRegistry.registerBlock((obj.getClass()), m); ne marchera jamais, puisqu’il faut l’instance de l’objet et non la classe.En faite, j’ai programmer des classes dite “primitives” pour m’assisté (des extensions de classe Minecraft qui me servent de base). Dans ces classes, on retrouve notamment une gestion de l’OreDictionnary, et de la création des textures.
Grâce a ça, je peu créer à peu près n’importe qu’elle blocks / item basique d’une simple ligne ( Item monItem = new JItem(“Mon Item”); ), le reste est automatisé. Plus récemment, j’ai créer ma classe “primitive” pour les armes du mod que je suis en train de codé. Cette classe reprend alors ce même bout de code. De même, lorsque j’ai voulus créer un type de block fallable (toujours pour le même mod). Je me retrouve donc avec 4 fois le même bout de code, à une exception près : Item ou Block (et peu être d’autre type après).
C’est uniquement pour automatisé certaine fonctionnalité, et évité de créer 70 classe différente pour 70 Item très similaire (lingot différent par exemple)La, je cherchais a faire une fonction générique pour éviter de copier coller sur chaque constructeurs (donc déjà 4) mon bout de code.
@‘SCAREX’:
Tu peux tout à fait mettre des fonctions par défaut dans une interface (j’ai remarqué çà y’a pas longtemps, c’est une particularité du java), tu as juste à rajouter le modifier “default” à ta méthode, exemple : default void test(T paramT, E paramE){ton code…}.
Ha bon ? J’avais crus lire que ça ne fonctionnais que sur Java 8… Je testerai du coup.
@‘SCAREX’:Par contre, je vois pas où tu utilises ta variable “myClass” et à quoi elle te sert.
Ma variable “myClass” est de type Class, c’est a dire qu’elle étais censé recevoir comme valeurs une classe. Pour mon cas du block, elle devais recevoir comme valeur JBlock. Je comptais utilisé cette variable pour le cast : ((myClass)obj).setOreDictionnaryName(“blockMon”); -> devenais a l’exécution (pour le block) -> ((JBlock)obj).setOreDictionnaryName(“blockMon”);
Etant donner que je rentrais une variable object en paramètre, je voulais utilisé la variable myClass pour enregistrer la class de mon object (pas la classe Object, mais la classe JBlock par exemple). Elle devais ensuite me permettre de caster pour accéder au fonction (ou planté le cas échéant).
@‘SCAREX’:
PS : je pense faire un tuto quand je rentrerais de vacances sur comment bien organiser ses mods proprement.
T’inquiète, mon mod est plutôt bien organisé (si ce n’est tous les commentaire qui ont sauté quand j’ai dus récupérer mes source depuis une release a cause du GitHub ), c’est juste que j’ai tendance à avoir la flemme de copier coller des portions de code (surtout à cause de la phase mettre a jour), du coup j’ai tendance à faire des fonctions générique que j’utilise ensuite partout, et qui nécessiterons beaucoup moins de maintenance vue qu’elle ne dupliquerons pas le code ^^ La preuve : JodgeLibrary_A1.0.12
-
@‘SCAREX’:
Tu peux tout à fait mettre des fonctions par défaut dans une interface (j’ai remarqué çà y’a pas longtemps, c’est une particularité du java), tu as juste à rajouter le modifier “default” à ta méthode, exemple : default void test(T paramT, E paramE){ton code…}.
Par contre, je vois pas où tu utilises ta variable “myClass” et à quoi elle te sert.
PS : je pense faire un tuto quand je rentrerais de vacances sur comment bien organiser ses mods proprement.
Mais ça ne fonctionnera qu’en Java 8
Java est un langage avec un typage fort, ton système de classe primitive ne sert a rien et est très instable et source de nombreux bugs. Utilise l’héritage pour éviter la redondance de code.
-
Effectivement, c’est possible que le default ne soit disponible qu’avec java 1.8. Mais vu que tu utilises des classes dont tu hérites tes items et blocks, pourquoi tu ne mets pas ce code dans ces classes ?
-
Mes classes dite primitives sont des extensions de classe Vanilla (héritage donc) qui ne me servent qu’a ajouter des fonctionnalité basique pour créer des block/item basique, et commune (enregistrement de l’objet, de la texture, du nom, de l’OreDictionnary…) ainsi que certaine fonctionnalité (par exemple, pour créer un outils, il suffit de donner un item (le lingot), et le reste est automatique. Ça évite de faire un héritage par élément pour avoir au final les même fonction, à la condition prêt (en l’occurance, l’objet pour réparer, crafter).
Si j’ai besoin de rajouter des fonctionnalité, j’ai plus qu’a créer une extension de cette dite classe propre a mon objet.
C’est même pas du modding au final, juste de la POO tous ce qu’il y a de plus basique.
Mais si vraiment sa te chagrine, je t’invite a regarder les sources sur le lien GitHub (post d’avant) et de me proposé des améliorations
SCAREX :
C’est ce que je fais actuellement. Le problème c’est que j’en suis a 5 classe (outils) + 3 classe (item, block, blockfallable) et 1 classe (base de mes armes) donc au total 9. 9 fois la même portion de code a item/block pres… Du coup, comme je dois modifier une partie (pour ajouter la gestion des texture minecraft que j’avais zapper), je dois modifier le code, puis le copier coller a 9 endroit…
-
Relis ce que j’ai mis, j’ai pas dis que c’était stupide, c’est même une bonne idée. La question c’est pourquoi tu mets ta fonction générique dans ces classes “primitives” ?
-
Bien a l’heure actuel les fonctions sont situé dans chacune des classe, car elle devais être appeler a la création, et faisais référence a des fonctions interne. Ça me semblais être l’endroit le plus logique, jusqu’à ce que je me rende compte que je dupliquais mon code a chaque fois ^^’
Du coup, j’ai décidé de le déplacer ailleurs. J’aurai alors pus copier coller le code 1 fois par classe minecraft (Block et Item à l’heure actuel) mais je me retrouvais a dupliquer le code.
Certe, pour un mod ça aurai suffit, mais je cherche toujours a apprendre des choses de plus en plus compliqué, du coup j’ai cherché à faire une fonction générique qui fonctionne avec tous (adaptant juste la le type de l’objet, et une le nom d’une des fonctions.Quand a ce que tu a dis, je ne pense pas que tu sois stupide au point de faire référence à modifier les classes Vanilla, du coup j’ai crue comprendre que tu me disais de mètre mes fonctions dans mes classe “primitive”, ce qui est actuellement le cas, et reste un comportement qui me déplaît (à cause de la duplication du code)
-
Essaye avec çà:
public static void register<t>(T obj, String name,String oreDicName){ if (obj instanceof JBlock) { JBlock jb = (JBlock)obj; jb.setBlockName(JFunction.convertNameToUnLocalizedName(name)); GameRegistry.registerBlock(jb, name); if (!("".equals(jb.oreDictionnaryName))) { // Si le nom est vide ou la variable est null, retourne false (çà évite les NPE) jb.oreDictionnaryName = JFunction.convertNameToOreDictionaryName(name); } OreDictionnary.registerOre(oreDicName, jb); } else if (obj instanceof JItem) { JItem ji = (JItem) obj; ji.setUnlocalizedName(JFunction.convertNameToUnLocalizedName(name)); GameRegistry.registerItem(ji, name); if (!("".equals(ji.oreDictionnaryName))) { // Si le nom est vide ou la variable est null, retourne false (çà évite les NPE) ji.oreDictionnaryName = JFunction.convertNameToOreDictionaryName(name); } OreDictionnary.registerItem(oreDicName, ji); } else { return; // WUT ?! } }
PS : le code est tapé à la main donc il risque d’y avoir quelques erreurs.</t>
-
public static void register<t>(T obj, String name,String oreDicName)
Je dois avoué que je n’ai aucune idée de comment cela fonctionne, et qu’évidemment, c’est la partie qui ne fonctionne pas ^^’
<t>correspond a quoi ? une sort de classe objet temporaire ?EDIT :
public static void commonInit(String name, String modid, JCommonCreate obj, String modidTexture, String textureName, String oreDictionnaryName) { String m = convertNameToUnLocalizedName(name); if(name.equalsIgnoreCase(textureName)) { textureName = m; } if (oreDictionnaryName.isEmpty()) { oreDictionnaryName = convertNameToOreDictionaryName(name); } obj.setOreDictionnaryName(oreDictionnaryName); if(obj instanceof Block) { GameRegistry.registerBlock((Block) obj, m); Main.proxy.registerBlockTexture((Block) obj, textureName, modidTexture); OreDictionary.registerOre(oreDictionnaryName, (Block) obj); ((Block) obj).setUnlocalizedName(m); } else if(obj instanceof Item) { GameRegistry.registerItem((Item) obj, m); Main.proxy.registerItemTexture((Item) obj, textureName, modidTexture); OreDictionary.registerOre(oreDictionnaryName, (Item) obj); ((Item) obj).setUnlocalizedName(m); } else { JLog.write("[WARNING] The object name : " + name + " Isn't instance of autorized class."); } }
(j’ai un problème avec les espaces avec le copier/coller…)
Grâce à l’interface j’ai pus simplifier certaine partie. Je dois (malheureusement) toujours définir les 2 fonctions dans ma classe.
En contrepartie, je peu directement faire appelle au classe de Minecraft pour instanceof, ce qui me réduit le nombre de condition de 8 a 2. C’est pas si mal, bien qu’il reste 3 fonctions qui sont strictement similaire au cast prés ^^" (4 si l’on considère que je peu ajuster le registerTexture avec une condition)</t></t> -
le <t>veut dire que la méthode est générique donc que tu peux lui fournir en paramètre n’importe quelle objet. Vu que ici tu veux pouvoir utiliser cette méthode pour les items ET les blocs, je ne peux pas préciser de super classe car tes blocs et items n’ont pas les mêmes parents.
Donc ici tu appelleras register<tonitem>(tonInstanceDItem, name, oreDicName);
Regarde comment sont faites les listes : tu peux faire une liste de n’importe quel type références (tout ce qui n’est pas primitif).</tonitem></t>
-
Donc si j’ai bien compris, ça permet d’utilisé l’annotation entre <> plutôt que la classe Object ?
-
Y’a pas d’histoire d’annotations, c’est une méthode générique. Ce que tu précises entre ces chevrons sera le type utilisé dans la méthode (quoique, je crois que tu n’es même pas obligé de le préciser).
Donc si le type est extend JItem, il sera considéré comme un Item.
Regarde des tutos sur les méthodes et classes génériques en java (çà existe dans beaucoup de langages).
-
Mouai, j’ai regardé deux trois tuto, et j’ai compris le gros du principe, mais le but m’échappe un peu, j’ai l’impression que ça permet de supplanté la classe object au final ^^’
enfin bon… Ce n’étais que pour optimisé encore plus, le résultat a l’heure actuel fonctionne suffisamment.
Je ne veux pas non plus perdre trop de temps sur l’optimisation alors que le code n’es pas encore finis, et que j’ai encore bon nombre de problème à la con ^^'… Du coup je passe le sujet en Résolu, et je m’y re pencherai plus tard dans l’année quand le mode sera suffisamment avancé^^Merci pour votre aide, et … A toute a l’heure pour un nouveau problème X)
-
Si tu veux vraiment optimiser le code, supprime toute ta librairie : Y’a pleins de choses qui mangent les performances pour rien comme la fonction qui convertit des noms en noms non-localisés. Moi dans mes mods j’utilise un seul nom pour le nom enregistré dans le GameRegistry et unlocalizedName, même si la convention est pas bonne.
-
bha en théorie, les fonctions dans Jfunction ne sont censé être utilise qu’une fois lors de la création du l’objet, donc outre la place en mémoire, les fonctions ne sont pas si gourmande qui ca en processeur (hors c’est souvent cette partie qui pêches)
Après je cherche pas a optimisé le code dans le sens fonctionnement, mais dans le sens codage : plus c’est automatisé, mieux c’est (je cherche avant tous à prendre de l’avance sur le programme de DUT de l’année prochaine X) )