Date de première publication : 2018/01/29
Notions : Définition de classes, Manipulations de chaines et de fichiers, JavaFX, conteneurs
Nous allons créer un annuaire non exhaustif des personnes ayant créé un langage de programmation.
Mise en place de quelques classes
- Créer une classe
Personne
qui possède les attributs privés suivants : nom
,prenom
,langage
etannee
: des chaînes de caractères- un attribut de classe entier
compteur
.
Java 8 introduit un nouveau package java.time qui définit une classe Year...
- Initialiser
compteur
dans un bloc spécifique exécuté au chargement de la classe. Ce bloc affichera sur la console ce qu’il fait. - Créer un constructeur sans paramètre qui incrémente
compteur
. Afficher l’action sur la console. Quelle est l'instanciation par défaut des attributs ? - Créer un autre constructeur qui permet d’initialiser tous les attributs d’instance et d'incrémenter
compteur
. Pour ne pas faire de la duplication de code, vous avez deux possibilités : - une méthode privée dédiée (méthode qui marche quel que soit le langage)
- un appel de constructeur à partir d'un constructeur (spécifique au java), méthode que l'on peut aussi utiliser pour pallier l'absence de paramètres par défaut
Si vous choisissez l'appel de constructeur à partir d'un autre constructeur, vous devez choisir quel constructeur appelle l'autre. Pour moi, il est plus logique que le constructeur avec moins d'arguments appelle le constructeur qui initialise tous les paramètres - ce dernier peut être private
si nécessaire.
- Doter la classe
Personne
d’une méthode de classe qui affiche le nombre d’instances déjà créées. - Créer une classe
WhoswhoApplication
avec une méthodemain()
. - Vérifier qu’aucune instance de
Personne
n’a été créée. - Créer une instance de
Personne
. Vérifier que le nombre d’instances de la classePersonne
a bien été mis à jour. - Appeler la méthode
toString()
de l’objet créé. Obtient‐on le résultat attendu ? Pourquoi ?
La méthode toString()
est héritée d’Object
. Son comportement par défaut est de donner le nom de la classe et l'adresse mémoire un code de hachage de l’instance concernée.
- Redéfinir la méthode
toString()
pour que celle‐ci renvoie une chaîne de caractères du typenom:prenom:langage:annee
. On utilisera un objetStringBuffer
ouStringBuilder
pour la générer.
Si vous codez une concaténation de String
, "a"+"b", le compilateur transforme automatiquement avec un StringBuilder
MAIS cela reste une bonne idée de le faire et de savoir faire car dans d'autres situations, le compilateur ne saura pas optimiser.
Gestion de fichiers et de plusieurs instances d’une même classe
Manipulation d'un fichier texte
- Sauvegarder cette chaine de caractères dans un fichier texte. Créer quelques autres instances de
Personne
et les sauvegarder dans le fichier de la même manière. Une méthode se trouve dans la copie des transparents (mais à quelle page ? ;-) ).
On peut par exemple chaîner des objets de type File
, FileOutputStream
puis PrintStream
.
Il faut également gérer les exceptions possibles avec double bloc try/catch ou un try-with-resources si vous le pouvez.
try(R1 r1 = new R1(); R2 r2 = new R2()) {
// code utilisant les ressources
} // fermeture automatique des ressources
catch (Exception e) {
}
On va maintenant s’intéresser à la lecture de ce fichier par une classe Whoswho
, un conteneur d’instances de Personne
.
- Créer une classe
Whoswho
qui aura un attributpersonnes
: une collection dePersonne
. Je vous propose différentes solutions : un tableau de personnesPersonne[]
avec un attribut pour compter le nombre d’éléments ou un vecteur dynamique génériqueVector
, ou bien encoreArrayList
. Cette dernière classe dite legacy (mais indispensable quand on fait du multithreading) peut vous sembler trop veille, vous pouvez utiliser également une liste chaînée. Nous avons déjà cité la classe idoine. - Initialiser
personnes
dans le constructeur de la classeWhoswho
. Est‐ce que cela crée des instances dePersonne
? Pourquoi ?
Cela ne crée pas d’instance car c’est un tableau de références. Créer un tableau d’objets en C++ crée autant d’objets que nécessaire en faisant appel au constructeur par défaut de la classe.
- Ajouter une méthode
lire()
qui prend en paramètre le nom d’un fichier et qui lit le fichier précédent avec les classesFileReader
etBufferedReader
. Chaque ligne sera analysée avec la classeStringTokenizer
(la documentation déconseille son usage désormais), la méthodesplit()
deString
ou une expression régulièrejava.util.regex
.
Sérialisation
- Reprendre le point précédent en essayant cette fois la sérialisation des objets.
- Sérialisation classique intégrée au langage (fichier binaire)
- "Sérialisation" XML avec une bibliothèque comme celle présentée en cours x-stream [lien officiel] [miroir]
L'étape la plus délicate pour la "sérialisation" XML est l'ajout de la bilbilothèque spécifique (sous forme de fichier jar) lors des étapes de compilation/exécutation que ce soit à la main ou dans l'EDI. La méthode est décrite dans la FAQ Eclipse.
Pour la compilation ou l'exécution à la main, il faut "inclure" le fichier jar dans la liste des classes disponibles :
javac -cp xstream.jar:. Classe.java
Voilà le code d'écriture pour une version récente de la bibliothèque :
FileOutputStream fos = null;
XStream xstream = null;
fos = new FileOutputStream(name);
xstream = new XStream(new StaxDriver());
xstream.toXML(objects, fos);
Interface graphique JavaFX
On veut maintenant afficher la classe Whoswho
dans un composant JavaFX comme une TableView
.
- Créer une fenêtre avec une
TableView
vide. - Créer des
TableColumn
pour donner un peu de consistance à la table - Modifier la classe
Personne
pour que les différents champs soient maintenant des propriétés (SimpleStringProperty
) - Stocker les éléments dans une collection comme
FXCollections.observableArrayList
- Lier la collection avec la table :
colonne.setCellValueFactory(
new PropertyValueFactory<Person,String>("nom")
);
Pour compléter, n’hésitez pas à jeter un coup d’œil au tutoriel dédié Oracle.