
|
|
|
|
Chapitre bonus!!Haa (ouf) maintenant que je vous ai expliqué l'essentiel de la POO dan un chapitre qui n'est pas un plan de mon cours, ce chapitre contiendra entre autre les listes, les exceptions, comment lire et écrire dans un fichier, etc... Ce chapitre est consacré donc à des choses plus spécifiques liées à la POO, je vous conseille de le lire quand même car on aura besoin de repêcher des choses de ce chapitre, notamment si vous voulez sauvegardez vos parties lorsque vous créez vos jeux!
Sommaire du chapitre :
![]() Les listes, collectionneuses d'objetsChapitre complémentaire mais utile!D'abord, une liste c'est quoi ? En fait, ce sont simplement des objets qui permettent d'en stocker des autres de n'importe quel type! Une liste peut même en contenir une autre. Il n'est pas nécessaire de préciser le type, ni la taille d'une liste, pas comme pour les tableaux, mais dans certaines mesure, il sera plus prudent de typer une ArrayList pour qu'elle n'accepte pas n'importe quel type d'objets! (voir le chapitre sur la généricité) Le dernier élément d'une liste est toujours null, et à chaque fois que l'on ajoute un objet à une liste, il contient aussi une adresse vers l'élément suivant, donc on a pas besoin de connaitre la taille des listes! Par défaut, la taille d'une liste est de 5, et sa capacité de 10. Il existe plusieurs types de listes! Quand je vous parlerai des framework, on verra que il y a une multitudes de classes qui permettent de gérer différent type de listes. Bon, je vais commencer par vous présenter la classe LinkedList : Les LinkedListCe sont des listes ou chaque élément contient une référence sur l'élément suivant. Le dernière élément d'une liste vaut toujours null! C'est à ça que l'on reconnait la fin de la liste. Le première élément de la liste commence à zéro comme pour les tableaux! Alors comme une LinkedList est une classe non abstraite, on devra en créer une comme ceci avant d'y stocker nos objets. Mais au tout début, il faudra importer le package java.util qui contient toutes les classes permettant de collectionner des objets. La méthode pour ajouté un élément à une liste c'est add On peut aussi en effacer un avec la méthode remove. Il y a aussi la méthode size qui renvoie le nombre d'éléments stockés dans la liste. (la taille de la liste donc) Je vous met un code comme exemple. Code : Java import java.util.LinkedList La méthode get permet de récupérer un élément d'une liste. Il y a d'autres méthodes comme removeAll qui supprime tout les éléments d'une liste! L'interface IteratorElle a été créée dans la version récente de Java pour parcourir facilement une Liste! Donc on peut utiliser cette interface pour afficher tout les éléments de notre liste! Code : Java ListIterator liIterator = liste.listIterator (); Oui je sais que c'est un peu spécial comme code car il y a pas de "new", mais retenez simplement que la méthode listIterator de la classe LinkedList crée une instance de l'interface ListIterator, sur notre liste. La méthode hasNext renvoye true ou false, true si l'élément suivant n'est pas null, false si l'élément suivant est null. On peut aussi parcourir la liste à partir de la fin grâce à la méthode hasPrevious () Maintenant Je vais vous montrer comment on parcours la liste, c'est beaucoup plus simple, ici il faut utiliser juste un while! Code : Java while (liIterator.hasnext ()) Vous vous rappelez de la méthode next ? La méthode nextBah cette méthode renvoye n'importe quel type d'objet, elle renvoie tout simplement un objet de type Object! Les ArrayListInconvénients des LinkedList : C'est qu'elles sont lourdes car chaque éléments contient une référence vers son suivant, il faudra là utiliser donc (si vous voulez créer une multitudes d'objets) un objet de type ArrayList! Les méthodes et la manière de les utiliser est la même que pour les LinkedList. La je vais importer la classe Iterator qui est dans java.util Code : Java import java.util.ArrayList; Les liste de type HashTableVous pouvez stocker aussi vos objets au moyen d'une clé associé à une valeur! La clef est un entier et est unique! Par contre la valeur peut être associée à plusieurs clés C'est une catégorie particulière d'objet appelés des Maps. Pour parcourir la liste, ce n'est plus l'interface Iterator qui le fait, mais l'interface Enumeration! Exemple : Code : Java import java.util.HashTable; Les listes restrictivesCe sont des listes qui n'acceptent pas deux fois la même valeur, par exemple une liste ayant deux fois la valeur null n'est pas accepée! C'est utile si vous ne voulez pas avoir des éléments vides dans votre liste ou tout simplement deux fois le même! Pour la parcourir, on peut aussi utiliser un objet de type Iterator, mais, ici, je vais vous montrer une manière rapide en mettant votre liste dans tableau puis l'afficher, vous verrez c'est vraiment simpliste le code! L'objet qui permet de faire ces listes spéciale c'est les HashSet (un Set est une collection d'objet bien précis) comme on dit un set de cuisine! Il y a des set plus restrictifs que d'autres. Voilà comment on procède pour les listes de type HashSet donc : Code : Java import java.util.HashSet; Quoi, qu'est ce que c'est que ça dans le for ?!? D'abord sachez que la méthode toArray converti note liste en un tableau d'objets. Puis renvoie ce tableau de type Object dans celui que j'ai appelé là objects. L'instruction for (Object o : objects) maintenant. Ca, c'est une manière ultra compacte pour écrire tout ceci : Code : Java for (int i = 0; i < objects.length; i++) C'est une manière plus rapide de l'écrire, vous n'êtes pas obligé de la retenir si ça vous perturbe. Ceux qui connaissent la boucle for ... each..., bah cela permet de la remplacer. Sachez simplement que dans le for, je crée un nouvel objet o qui contient notre tableau d'objets et pour chaque élément de ce tableau, j'affiche les élément un par un automatiquement. Exemple de l'utilisation de listes Reprenez la classe DataBase du projet people et examiner là. Vous avez là un bel exemple d'utilisation d'une ArrayList! Comme pour les tableaux à plusieurs dimension, il est possible d'imbriqué une liste dans une autre, de la même façon que l'on met un tableau dans un autre, si vous vous souvenez du chapitre sur les tableaux. [attention]Ce chapitre est incomplets mais suffisants pour la suite, je vous parlerai du framework collection et tout plus loin lorsque on en aura besoin. Je vous parlerai aussi de la comparaison ente objets, du tri, et quelques méthodes, etc... [/attention] La Gestion des erreurs en Java (Les exceptions)Notion d'exception en JavaC'est en fait une manière qu'utilise le langage Java afin de gérer les erreurs qui peuvent se produisent lors de l'exécution d'un programme Java. (exemple d'erreurs : une division par zéro, essayer d'afficher un élément d'un tableau dont l'indexe est un nombre négatif ou fractionnaire, invoquer une méthode sur un objet qui vaut null c'est à dire qui est déclaré mais qui n'est pas initialisé, etc...) La classe ExceptionC'est cette classe là qui est chargée de gérer les erreurs qui peuvent être produites, elle a un bon nombre de sous classes : ArithmeticException, ArrayIndexOutOfBoundsException, NullPointerException, etc... Quelques méthodes de cette classe : Il y a la méthode getMessage, elle renvoie (sur un objet de type Exception) le type d'erreur générée. Il y a aussi la méthode printStackTrace qui est intéressante, elle nous indique ou est levée l'erreur dans le programme. (Le numéro de la ou des lignes qui posent problème) Lever une Exception et savoir laquelle c'est et ou c'est : Pour savoir laquelle est levée, il suffit de faire une erreur dans votre main comme ceci : Code : Java public class Test { Essayer de l'exécuter en cliquant droit sur la classe Test, puis cliquer sur static void main, laisser le tableau d'argument vide, donc laisser les {} et cliquer sur ok, et là dans le terminal (du dessous) normalement vous avez un message écrit en rouge du style : ArrayIndexOutOfBoundsException: -1 at Test.main (Test.java:6) Capturer les erreurs potentiellesIl y a moyen en Java, de capturer les erreurs qui peuvent être réalisées lors de l'exécution de votre programme. On a vu la que notre erreur est de type ArrayIndexOutOfBoundsException, il faudra donc capturer une erreur de ce type là. Alors pour celà le Java utilise le fameux bloc try{...} catch{...} Dans le bloc try, on aura tout simplement notre code de base à exécuter, et dans le bloc catch il y aura un paramètre à indiquer, le type d'erreur envisagée. Ensuite il restera à marquer dans le bloc catch ce que l'on fait lorsque le programme génère un erreur! Exemple avec le bloc try catch : Code : Java public class Test Et oui, vous pouvez continuer à faire tourner votre programme même lorsqu'il y a une erreur!! On peut même utiliser notre objet e du bloc catch et lui demander quel est l'erreur et ou elle se trouve comme ceci : Code : Java catch (ArrayIndexOutOfBoundsException e) { Pas mettre de System.out.println(e.printStackTrace ()); Cette méthode affiche l'erreur automatiquement dans un terminal spécial réservé pour! (donc pas dans le même terminal ou s'affiche vos textes avec System.out.println!) Capturer plusieurs erreursBah c'est pas compliqué, en fait, il suffit de rajouter plusieurs blocs catch à la suite comme ceci : Code : Java catch (ArrayIndexOutOfBoundsException e) {...} Ou même vous pouvez les imbriquer mais là il faudra que la première exception puisse en engendrer une autre, faîtes attention qu'il faut absolument que la première exception soit engendrée pour que la deuxième puisse être engendrée! Code : Java catch(Exception e) { Récapitulatif de ce que fait le bloc try et catch. Le bloc try tente d'exécuter les instructions qui se trouvent dedans. S'il n'y arrive pas, il fait appel automatiquement au bloc catch, on dit qu'une Exception est levée! Si le type d'exception se trouve dans le bloc catch, ce bloc est exécuté sinon c'est un message par défaut qui est affiché en rouge dans votre fenêtre. Certaines manipulations notamment celle que l'on verra lorsqu'on apprendra à lire et écrire dans des fichiers, devront obligatoirement implémenter le bloc try catch! Pour les exceptions que je vous ai montrer ci dessus on est pas obligé de mettre un bloc try catch car la machine virtuelle le fait déjà pour nous, c'est ça qui nous a permit de voir quel type d'excpetion est renvoyée dans ce cas là, au pire si vous ne connaissez pas le type d'exception, utiliser tout simplement la classe Exception qui est la super classe de toutes les autres. Le mot clef finallyIL se met après le bloc ou les blocs catch. Le bloc finally sert lorsqu'on doit exécuter des instructions, que le programme gère une erreur ou pas. Donc ce bloc sera toujours exécuté quoi qu'il arrive! Code : Java finally { Convention pour les classes gérant les exceptionsToutes vos classes que vous ferez et gérant des excpetions que vous personnaliserai devront se terminer par Exception! Toutes ces classes devront hériter de la classe Exception! Créer vos Exceptions personnalisées!Vous pouvez créer vos propres classes pour gérer vos propres Exceptions, pour celà il y a deux nouveaux mots clefs à retenir, ils se ressemblent fort, attention de ne pas les confondres! Le mot clef throws Il peut se placer avant n'importe quel bloc d'instruction, que ce soit avant le bloc d'instruction d'une classe, d'un if, d'une méthode, d'une boucle, ... Ce mot clé est suivit du nom de la classe ou des classes qui afficheront les erreurs. Le mot clé throw pas confondre avec throws! Ce mot clef permet de jeter un nouvel objet de la classe qui gère vos Exception qui est placée après le mot clé throws. Après ce mot clef throw il faudra créer une instance de la classe placée après votre mot clé throws. Exemple d'utilisation de ces deux mot clef. Code : Java public class Arithmetic { Ne jeter que des objets de la classe Exception ou de celles qui en hérite. Je vois déjà des petits malins (comme David par exemple) qui vont tenter de jeter des autres objets que des exceptions. Essayer si ça vous amuse.^^ Faire ses classes d'excpetions personnalisées :Ce sera (par convention) une classe qui héritera de la classe Excpetion (ainsi on pourra réutiliser les méthodes (getMessage() , printStackTrace (), etc...) de la classe Exception! Bon je vais pas m'amuser à créer des méthodes dans ma classe personnalisée, je vais juste faire un constructeur dans lequel je vais faire un System.out.println pour afficher le message d'erreur. Voici donc comment créer vos classe pour vos exceptions personnalisées : Code : Java public class PersonnaliseeExcpetion { Alors je vais vous montrer un exemple avec une classe Ville que j'ai trouvé sur le net et qui est pas mal! (j'ai trouvé des exemples vraiment pas mal sur le net, et j'essayerai d'encore en trouver et d'en mettre plein!) Je comptes d'ailleur faire par la suite dans les annexes une partie Exemple, spécialisée avec des exemples que je trouves sur le net pour que la POO ne vous pose plus de problèmes. Alors voici l'exemple : Je veux pouvoir créer des villes, avec comme variables leurs nom, et leurs nombre d'habitants. Alors pour ça je vais créer quatre classes, une pour instancier des objets de type Ville, une pour gérer les erreurs si l'on encode un nombre d'habitants négatifs, une pour les erreurs si le nom de la ville fait moins de trois caractères, et une autre qui contiendra le main pour tester mes exceptions personnalisées. Je vais commencer à mettre le code de la classe Ville, et faire la classe avec le main sans tenir compte des exceptions, et ensuite, je rajouterai le code nécessaire pour que vous puissiez bien voir comment que ça marche! Alors voici la classe Ville que j'ai faîtes : Code : Java /** La classe Test avec le main : Code : Java public class Test Maintenant il faut que je crée deux nouvelles classes qui géreront les erreurs, je vais les appeler NbHabExcpetion et NomVilleExcpetion. Voici ces deux classes qui sont vraiment pas difficile à faire! Code : Java /** La deuxième : Code : Java /** Maintenant dans notre classe Ville, il faut tester dans le constructeur si le nombre d'habitants est négatif, et si c'est le cas renvoyé l'erreur, idem pour le nombre de caractères pour le nom de la ville (on peut bien évidement mettre plusieurs classes de type Exception après le throws comme ceci : Code : Java public Ville (String nom, int nbHabitants) throws NbHabEception, NomVilleException {} Voici le code de ma classe ville jetant donc ces deux exceptions : Code : Java /** Maintenant il nous reste plus qu'à rajouter le bloc try {} catch dans notre classe Test pour tester notre code! Code : Java public class Test Vous voyez donc que notre programme a capturé l'erreur que j'ai faîtes. Essayer aussi ceci : Code : Java public class Test Dès que il y a une erreur, le bloc try s'arrête. On peut aussi réutiliser les méthodes de la superClasse Exception avec nos classe d'exceptions personnalisées. (voir chapitre précédant sur l'héritage) Veuillez à bien mettre vos bloc catch dans l'ordre, les exceptions plus spécifiques d'abord ensuite les exceptions plus génrique! Ca, ça ne marchera pas : Code : Java catch (Exception e) {} Car ArithmeticExcption est moins générique que Exception!! Et comme elle est moins générique, elle doit être capturée en premier! Voila j'ai enfin fini, on peut passer maintenant au chapitre suivant : la généricité. Courage il reste plus que trois chapitres barbants après on pourra faire des choses beaucoup plus agréable!! Remarque : autre maniè de traite les exceptions : Les classes personnalisées. Code : Java public class NbHabException extends Exception Code : Java public class NomVilleException extends Exception Là je traite les exceptions dans le constructeur de la classe Ville. Code : Java public class Ville Et le main : Code : Java public class Test La généricité.Introduisons le problème.Imaginons que nous devons créer une classe qui pourra utiliser ses méthodes sur des objets de n'importe quel type (aussi bien des entiers, que des chaînes de caractères) Donc, lors de l'utlisation de votre classe, vous ne savez pas quels type d'objets vous devrez créer! (et je ne le vous direz pas) Bah c'est un bon exercice ça, essayer un peu de faire une classe qui permet de créer n'importe quel type de variable. MMmmm..., avec tout ce que je vous ai appris jusque ici, vous auriez du penser à ceci : Code : Java public class Solo { Maintenant essayons de l'utiliser ce code : Code : Java public class Test { Remarquer que vous devez faire un cast pour mettre votre objet de type Object dans une variable de type int qui est plus spécifique. (un int ne peut faire ce tout ce que peut faire un objet, donc le compilateur n'accepte pas et il faut lui préciser que vous ne faîtes pas de bêtises!) Il faut donc appliquer le casting explicite comme je vous l'ai montré dans l'héritage. Les inconvénients de ce codeL'inconvénient est que vous devriez créer à chaque fois un nouvel objet de type Object pour chaque variable que vous voudriez créer, on serait tenté de créer une classe Solo pour chaque objets. (int, String, etc...) Java à pensé à vous!Là, le Java à pensé à vous, il a créer un type de variable bien particulier appelé les paramètres génériques! Il faut juste ne pas confondre variable et paramètre générique. Celle ci sont définie juste après le nom de votre classe, entre des "< >". (chevrons) Vous avez juste à indiquer le nom de votre variable générique en tappant une lettre majuscule. La création de paramètres génériques se fait comme ceci : Code : Java public class Solo<T> { Et dans la classe même, on remplace le type Object par le paramètre générique inconnito! (T ici) Code : Java public class Solo<T> { Et ça change quoi dans l'utilisation ? Ca change ceci : Au lieu de se casser à écrire tout ceci (en plus il faut faire un cast) : Code : Java Object o = new Objet (12); Il suffit d'écrire ceci : Code : Java Solo<Integer> solo = new Solo<Integer>(12); Et oui, c'est déjà plus simple non et ça nous permet de réutiliser du code! Le truc c'est qu'il ne faut pas oublier de rajouter le type de l'objet entre les <> lorsqu'on le crée. D'ailleurs cliquer droit sur votre classe Solo et faîtes new Solo, vous verrez que il vous demande avant, le type de votre Objet et ensuite seulement sa valeur! Sachez que chaque type de variable primitive à une classe correspondante pour pouvoir utiliser la généricité! Type primitifs des variables et classe correspondantes pour ces types : byte => Byte short => Short int => Integer long => Long float => Float double => Double char => Character boolean => Boolean donc : Code : Java int nombre = 10; Reviens au même que d'écrire ceci : Code : Java nombre = new Integer (12); Oui, il n'y a plus de casting à faire, mais là je ne pourrez plus mettre que des int dans mon objet solo! Encore une fois là, Java à pensé à vous. Le willcard "?"C'est quoi ça. Bah on va simplement dire à notre classe Solo qu'on pourra lui instancier n'importe quel type d'objets! comme ceci : Code : Java Solo<?> solo = new Solo<Integer>(12); Super pratique non ? Cela permet de réutiliser le code de notre classe Solo sur n'importe quel type d'objet, et oui, le Java à beaucoup d'avantages en ce qui concerne la réutilisation de code! Plus loin encore, une classe Duo!Vous pouvez bien sûr créer plusieurs paramètres génériques! Il suffit de les séparer par une virgule comme ceci : Code : Java public class Duo<T, S> Maintenant il suffit d'écrire le code à l'intérieur de la classe comme ceci : Code : Java /** Et notre main : Code : Java import java.util.ArrayList; La généricité et les collectionsOn peut bien évidement créer des listes d'objets tout en utilisant la généricité. Exemple : Code : Java Solo<Integer> listeSolo = new ArrayList (); Ceci à pour avantage de garantir que votre liste ne pourra contenir que des objets de type Integer! La généricité permet de garantir donc la sécurité pour vos liste d'objets! Votre liste ne pourra plus contenir n'importe quoi comme je vosu l'ai montrer dans le chapitre sur les listes!! La généricité et l'héritageC'est un des points les plus dur à comprendre car il contredit la notion d'héritage : Vous ne pouvez pas mettre une liste d'objets plus spécifique dans une liste d'objets plus généraux! Pour exemple, une liste d'objets de type Circle ne peut pas être mise dans une liste d'objets de type Point!! Donc ceci : Code : Java Solo<Circle> listeCircle = new ArrayList (); Quoi, alors ça veut dire que un cercle n'est plus un point, je comprends plus là! Si, mais imaginez que vous puissiez affecter une liste de cercles à une liste de points, bah là ça n'ira plus car vous pourriez sans soucis rajouter des cercles dans votre liste qui est déclarée de type Point je rapelle! Et donc vous ne pourrez pas afficher les cercles que vous aurez ajouter! Ca va à l'encontre de ceci : Solo<Point> car Solo<Point> n'hérite pas de Solo<Circle>! Pour lui dire d'accepter de rajouter des cercles dans notre liste de type Point, il faut rajouter le mot clef extends suivit du nom de la superClasse Point comme ceci : (je vais utiliser le willcard car la superClasse peut très bien avoir plusieurs sous classes et on ne sais pas quels objets de quel sous classe on va mettre dans notre liste) Solo<? extends Point> liste = new Arraylist(); La on lui dit que les objets dans la liste pourront être de type Point ou du type de l'une de ses sous classes. NB : On écrit exactement la même chose pour les interfaces qui sont je rappelle des superClasses contenant que des méthodes abstraite. (que des prototypes de méthodes si vous voulez ou aussi des constantes) Exemple avec une interface : Code : Java Solo <? extends interface1> solo = new ArrayList (); Les méthodes génériquesElle découlent en réalité des classes avec des paramètres génériques, les méthodes générique permettent de faire donc des opérations sur les paramètres génériques! Les paramètres génériques sont passé à une méthode avant le type de retour de celle-ci! Exemple d'une méthode générique! Je veut faire une classe qui créer n'importe quelle paire d'objets et je veux afficher ce couple d'objets à partir d'un paramètre générique. Bah il suffira de faire comme ça : Code : Java public static <T> void afficher (Paire<T> paire) { Le paramètre générique s'insère donc avant le type de retour de la méthode. On pourrait aussi créer une méthode qui renvoie un objet de type Paire<T>, cela ne pose pas problème, il faut juste remplacer void pas Paire<T>! Pas nécessaire de créer deux paramètre génériques, car les deux objets issus du couple devront être de même type, il suffit juste de redéclarer un 2ème paramètre générique avec le même nom comme ceci : Code : Java private T premier; Nah, ce chapitre (à part les derniers point) est pas très difficile à comprendre, je vais passez au chapitre suivant très important car la réflexibilité vous permettra d'interroger vos objets! (connaître sa classe, ses méthodes, ses interféces implémentée, sa classe mère, et même pouvoir instancier dynamiquement une variable d'instance sans utiliser le mot clef new, ce qui vous sera utile dans certains cas) Je vous mettrez des exemple de classes ou on utilise ce principe dès que je pourrai pour que ce soit plus claire. Ceci est équivalent à l'utilisation de template en c++! La réflexibilitéCréation de classe et réflexibilitéAlors vous vous demander ce que c'est la réflexibilité ? Bah pour faire simple je vais vous dire ceci : la réflexibilité est le sens inverse si vous voulez au fait de créer des classes. La réflexibilité permet de récupérer vos classes et des informations sur vos classes! Les objets de type classe d'objetsJ'ai mis ce chapitre à la fin pour pas que vous confondiez les méthodes, classes, etc..., avec les objets de type classe! Création d'une classe et instanciation des objets: public class MaCLasse { Un objet de type classe est automatiquement créé!! Réflexiblité : Class maClasse = objetDeMaClasse.getClass(); ou Class maClasse = maClass.class; Vous voyez en faîtes que l'ont fait un peu l'inverse. La méthode getClass() de la Classe Object permet donc de récupérer des informations sur la classe de notre objet. Elle renvoye donc notre fameux objet créé de type classe. Les méthodes de la classe ClassgetName() : Permet de récupérer le nom de la classe : maCLasse.getName(); maClasse.getSuperclass() : permet de récupérer la superClasse de la classe. class[] mesInterfaces = maClasse.getInterfaces(); Permet de récupérer les interaces implémentées dans une classe. Les sous classes de la classe ClassVous devez les importer! Elles se trouvent dans le package java.lang.reflect. Je vais mettre les objets de ces classes dans un tableau de type Class, ça marchera car Class est leur superClasse. (covariance des variables) La classe Constructor : Elle contient tout les constructeurs de vos classes. class[] construct = maClasse.getConstructor(); La classe Method : Elle contient toutes les méthodes de votre classe, voici comment les récupérer. Class[] mesMethodes = maClasse.getMethods(); La méthode getParametersTypes() Elle permet de récupérer les types des arguments de vos méthodes : Class[] maMéthode.getParameterTypes(); La classe Field Elle permet de récupérer les variables déclarées dans votre classe (statique ou non) ( Class[] lesChamps = maClasse.getFields(); Un gros exemple pour récapituler tout çaPrenons comme classe, la classe String, je veux tout savoir sur elle! Code : Java import java.lang.reflect.*; |