"Les bases"

Page Home (contact) Retour TPs

Support de cours


Reprenez les classes Livre et TestLivre du TP précédent (les sources dans 2 fichiers séparés).

Contrôle des variables private par les modificateurs

Une variable d'instance private n'est pas modifiable en dehors de la classe. Ajouter un modificateur (un "setter") permet la modification en dehors de la classe tout en contrôlant les valeurs affectées à la variable d'instance.

  1. Ajoutez un prix aux livres (nombre qui peut avoir des décimales, de type Java double) avec 2 méthodes getPrix et setPrix pour obtenir le prix et le modifier. Si un prix passé en paramètre au setter est négatif, le prix n'est pas modifié et un message d'erreur est affiché.
    Ajoutez un constructeur qui prend le prix en paramètre, en plus des autres attributs. Ce constructeur fait appel à un autre pour éviter de dupliquer du code ("this(...)").
    Si le prix d'un livre n'a pas été donné, la description du livre (toString()) devra indiquer "Prix pas encore donné". Attention, un livre peut être gratuit (0 est une valeur possible pour un prix) ; la valeur -1 indiquera que le prix n'a pas encore été donné.
    Testez.
  2. Vous allez modifier la classe Livre pour qu'il ne soit plus possible de modifier le prix d'un livre : un prix ne peut être donné qu'une seule fois et ne peut être modifié ensuite (une tentative pour changer le prix ne fait qu'afficher un message d'erreur).
    Récrivez la méthode setPrix (et autre chose si besoin est). Cette fois-ci vous ajouterez une variable d'instance booléenne prixFixe (pour "prix fixé") qui indiquera si prix a déjà été donné (n'utilisez plus la valeur -1 comme valeur particulière, comme c'était fait à la question précédente).
    Faut-il écrire une méthode "setPrixFixe" pour modifier la variable d'instance booléenne ?
    Ajoutez une méthode "isPrixFixe" qui renvoie vrai si le prix a déjà été fixé.
    Testez en écrivant une méthode main qui essaie de changer le prix d'un livre.

Correction :
1.
Classe Livre
Classe TestLivre
2.
Classe Livre
Classe TestLivre


Comparaison de 2 livres en utilisant une méthode d'instance

Dans la classe Livre écrivez une méthode d'instance compare pour comparer 2 livres sur leur nombre de pages.
compare prend un livre en paramètre et elle renvoie 0 si le livre a le même nombre de pages que l'instance qui reçoit le message, 1 si l'instance courante ("this") a plus de pages que le parametre et -1 sinon.

Pour tester, vous utiliserez un code semblable au suivant :

System.out.print("L'auteur du plus gros livre est ");    
String auteurPlusGrosLivre; 
// Le code pour trouver le livre qui a le plus de pages (entre 2 livres)
// Ecrivez 2 versions : une avec if et l'autre avec switch
. . . 
System.out.println(auteurPlusGrosLivre);

Correction :
Méthode compare de la classe Livre
Classe TestLivre


Comparaison de 2 livres en utilisant une méthode de classe

Dans la classe Livre, écrivez une méthode de classe compare2 pour comparer 2 livres (passés en paramètres) sur leur nombre de pages. Testez.

Correction :
Méthode compare2 de la classe Livre
Classe TestLivre


Délégation (une nouvelle classe Comptable)

Cet exercice montre comment des instances peuvent collaborer pour obtenir le résultat voulu. Pour simplifier, vous vous placerez dans le cas où les prix des livres sont bloqués : le prix d'un livre ne peut être donné qu'une seule fois (dans un constructeur ou dans un modificateur) et ne peut être modifié ensuite.
  1. Créez une classe Comptable qui possède une méthode de signature "void comptabiliser(Livre l)". Une instance de cette classe permettra de calculer le prix total de tous les livres qu'on lui aura passé par la méthode "comptabiliser". Voici comment une instance comptable de cette classe peut être utilisée :

Vous mettrez la classe Comptable dans un fichier à part (pas dans le fichier Livre.java).
Testez votre nouvelle classe dans la méthode main de TestLivre. 2 comptables seront créés. Ils comptabiliseront chacun quelques livres. A la fin, on fera afficher le total des prix ainsi comptabilisés par chacun des 2 comptables.

  1. Vous ne devez pas modifier la classe Comptable pour cette question.
    Pour simplifier l'utilisation de la classe Livre, on veut cacher la classe Comptable aux "clients" de la classe Livre. Un client de la classe Livre est une classe qui utilise la classe Livre.
    Les livres vont faire enregistrer automatiquement leur prix par un comptable (un même comptable pour tous les livres) : appelez directement la méthode comptabiliser depuis la méthode setPrix (et depuis les constructeurs si nécessaire). Pour cela vous devrez utiliser un this explicite. Puisque le comptable doit être le même pour tous les livres (il ne dépend pas d'une instance particulière de Livre), vous allez l'enregistrer dans une variable de la classe Livre de quel type ?
    A tout moment on peut demander (à qui ?) le total des prix comptabilisés. Testez avec ce code.
    Maintenant la classe Livre devient une classe cliente de la classe Comptable ; on peut aussi dire que la classe Livre dépend de la classe Comptable (pour bien fonctionner).

Correction :

Question 1 :
Classe Comptable
Classe TestLivre
Question 2 :
Classe Livre
Classe TestLivre


Nombres complexes (pour les matheux !)

1. Créez une classe Complexe pour représenter des nombres complexes sous leur forme algébrique a + ib.

La classe contient 2 variables d'instance de type double pour représenter la partie réelle et la partie imaginaire.

Ajoutez les méthodes pour

N'implantez pas la soustraction.

Pour l'addition (idem pour la multiplication et l'opposé), la méthode ajouteToi enverra le message suivant à un nombre complexe : "complexe, ajoute-toi ce nombre". Le nombre à qui on envoie le message est donc modifié. La méthode ajouteToi aura le profil suivant :

Complexe ajouteToi(Complexe) ; le paramètre est le nombre que l'on ajoute au nombre à qui on envoie le message ; la méthode retourne la valeur de l'instance courante pour pouvoir enchaîner ; par exemple, z1.ajouteToi(z2).multiplieToiPar(z3) ajoute z2 à z1 et multiplie le résultat par z3.

Vous implanterez aussi une méthode toString() qui retourne la représentation habituelle des nombres complexes : 5.3, 6.0i, 2 + 5.2i, 3.0 - 8.0i (les nombres ne devront pas être de la forme 1 + -2i, mais de la forme 1 - 2i).

2. Dans une classe TestComplexe , commencez par tester la méthode toString() avec les nombres complexes suivants : 0, 2, 2i, -2i, 1 + 2i, 3 - 5i. Avec, par exemple, System.out.println(new Complexe(1, -2)).

Testez ensuite l'addition avec l'addition de (1 + 2i) + (3 - 5i). Le résultat est 4 - 3i.

Pour finir, testez la multiplication avec (1 + 2i) x (3 - 5i). Le résultat est 13 + i. Ca n'est pas ce que vous trouvez ? Voici de l'aide.

3. Tout devrait bien fonctionner maintenant, mais testons un peu plus.

Vérifiez que (1 + i)(1 + i) est bien égal à 2i . Testez en mettant 1 + i dans une variable z et en calculant z.multiplieToiPar(z).

Si ça n'est pas le cas, réfléchissez à la raison. Le fait que z soit passé en paramètre, en plus d'être le destinataire du message peut être la raison de votre problème. Si votre résultat était faux, corrigez le code de multiplieToiPar.

4. Vous ferez ensuite le calcul suivant en utilisant votre classe  (vous devriez trouver -7 -2i) :
z1 = 1 + 2i
z2 = 3 - 5i
z3 = 1 + i
z4 = (z1 - z2) (z3 - 1)

Après le calcul votre programme affichera les valeurs finales de z1, z2, z3 et z4. Essayez de comprendre les valeurs affichées.

Comment faire si on veut aussi afficher à la fin les valeurs initiales de z1, z2 et de z3 ?

5. Faites maintenant le calcul suivant en partant des mêmes valeurs de départ de z1 et z2 :
(z1 - z2) (z1 + z2 -1)
Vous devriez trouver 15 + 27i. Si ça n'est pas ce que vous trouvez, essayez de comprendre pourquoi (on ne vous demande pas d'écrire le bon code ; ne le faites que si vous êtes en avance par rapport à vos camarades).

6. On voit les difficultés si le nombre complexe à qui on envoie un message est modifié à la suite de ce message. Dans la pratique d'autres méthodes seront utilisées, qui ne modifient pas le nombre complexe qui reçoit le message. Ecrivez 2 méthodes add et mul dans la classe Complexe, qui retournent la somme et le produit du nombre complexe à qui on envoie le message, et du nombre complexe passé en argument, mais sans modifier le nombre qui reçoit le message. De même écrivez la méthode oppose() qui retourne l'opposé du nombre à qui on envoie un message, sans modifier le nombre qui reçoit le message. Le profil de add est le suivant :

  • Complexe add(Complexe)
  • En utilisant ces nouvelles méthodes, refaites maintenant le calcul (z1 - z2) (z1 + z2 -1) dans TestComplexe.

    Correction :
    Classe Complexe
    Classe TestComplexe


    Pour ceux qui ont déjà fini :

    Toutes les sections "Pour ceux qui ont déjà fini" des TPs sont optionnelles.

    Quelques calculs, quelques erreurs

    1. Copiez, corrigez, compilez et exécutez la classe suivante. Le programme suivant devrait afficher 3 (ou 3.0).
    public class Division {
      public static void main(String args) {
        int x, y;
        x = 3;
        y = 2;
        double a = x / y;
        double f = a * y;
        System.out.println(f);
      }
    }

    2. Idem pour la classe suivante (la classe doit afficher "1 + 1 = 2", puis 120, c'est-à-dire la valeur de e, puis 36.9) :

    public class Classe2 {
      public static void main(String args) {
        int a = 1;
        int b = 1;
        System.out.println(a + b + " = " + a + b);
        // Interdit de modifier les 3 lignes suivantes !
        byte c = 50;
        byte d = 70;
        byte e;
        // Mais vous pouvez modifier cette ligne...
        e = c + d;
        System.out.println("e= " + e);
        System.out.println(20.1 + 16.8); // Explications ?
    }

    Après avoir fait exécuter cette classe, remplacez 50 par 70 pour la valeur de c. Ne modifiez rien d'autre, compilez et exécutez. Quelle valeur est affichée pour e ?

    3. Utilisez la classe java.lang.Math (cherchez dans la documentation des API) pour faire afficher quelques calculs scientifiques et en particulier racine carrée de 4, cos(pi / 2), etc.

    4. Faites afficher 100 nombres entiers aléatoires compris entre 1 et 10 (bornes comprises). Vous pouvez utiliser Math.random() et Math.floor() pour générer ces nombres aléatoires. Vérifiez par programmation que tous les nombres générés sont bien entiers et bien compris entre 1 et 10. Pour chaque nombre compris entre 1 et 10, faites afficher le pourcentage de tirages de ce nombre ; par exemple si le nombre 5 a été généré 8 fois, faites afficher "5 : 8 %".


    Retour TPs