Université de Nice Sophia-Antipolis
L3 - Programmation orientée objet

Contrôle de mai 2012 - Durée : 2h.

Seuls documents autorisés : photocopies des transparents distribués en cours. Les énoncés et corrections des TP sont interdits. Éteignez les téléphones portables.

Important : la présentation et la lisibilité du code compteront dans la note finale. Vous êtes autorisé à écrire le code (et seulement le code) avec un crayon à papier si c'est parfaitement lisible (pas de crayon trop clair).

Ajoutez des commentaires quand vous pensez que ça peut être utile au correcteur. Ne mettez pas de commentaires évidents qui n'ajoutent rien à votre code.

Respectez le découpage en questions et l'ordre des questions (vous serez sanctionné sinon). Les numéros des questions devront apparaître clairement sur votre feuille. Vous pouvez répondre à une question même si vous n'avez pas répondu aux questions précédentes mais si vous sautez une question, vous devez l'indiquer clairement et laisser un espace sur votre copie.

Question 1 (6 points)

Vous êtes embauché par la société « Smart Faune » qui écrit des applications Java pour les téléphones mobiles. Vous êtes chargé de la partie qui concerne les répertoires et les contacts. Un contact a un pseudo, un nom, un prénom, et un n° de téléphone. On suppose que les n° de téléphone sont des numéros à 10 chiffres commençant tous par 0. Il ne doit pas être possible d'avoir deux contacts avec des pseudos identiques dans un même répertoire.

  1. Donnez les attributs de la classe Contact (mais ni les accesseurs ni les modificateurs). Justifiez les types choisis pour ces attributs (pourquoi quel type plutôt qu'un autre s'il y a le choix).
  2. Écrivez le constructeur de la classe Contact : un contact sera créé en donnant son pseudo, son nom, son prénom et son n° de téléphone.
  3. Écrivez la méthode permettant de modifier le n° de téléphone d'un contact, et celle qui renvoie son n°.
  4. Une instance de la classe Repertoire contient des contacts : quel sera le type de l'attribut nécessaire pour que le répertoire contienne des contacts ? Écrire une méthode Contact[] chercherContacts(String debutPseudo) qui, étant donné le début d'un pseudo, renvoie les contacts correspondants du répertoire (s'ils existent). Par exemple, pour le début de pseudo « can », elle renverra les contacts « canard » et « canari ».
  5. La société « Smart Faune » est spécialisée dans la commande vocale. Les pseudos des contacts sont des noms d'animaux : il suffit à l'utilisateur d'émettre le cri du pseudo pour appeler le contact (par exemple dire « coin coin » appelera le contact dont le pseudo est « canard »). Vous supposerez qu'il existe déjà une application qui à tout cri d'animal lui fait correspondre une chaîne de caractères, ou lève l'exception CriInconnu. Indiquez comment vous pouvez faire correspondre la chaîne représentant un cri à un nom d'animal. Écrivez la méthode du répertoire Contact chercher (String cri) qui renvoie le contact correspondant au cri passé en paramètre (s'il existe).

Question 2 (4 points)

Vous devez faire des statistiques sur des textes, c'est à dire compter combien de fois un même mot apparaît dans ce texte. Le texte sera une suite de lignes où les mots (une suite de lettres) sont séparés par un espace, sans aucun signe de ponctuation. Vous devez écrire les attributs et les méthodes d'une classe StatsTexte qui répondent aux questions suivantes :

  1. Quelle est la structure de données qui vous permettra d'associer à un mot le nombre de fois qu'il apparaît dans le texte ? Écrivez la méthode void unDePlus (String mot) qui augmente de 1 dans cette structure de données le nombre de fois où le mot apparaît.
  2. Écrivez la méthode void traiterLigne (String ligne) qui augmente le nombre de fois que les mots contenus dans la ligne apparaissent.
  3. Écrivez une méthode void compter (String nomDeFichier) qui compte tous les mots du texte qui se trouvent dans le fichier de nom nomDeFichier. N'oubliez pas les exceptions.
  4. Écrivez les deux versions suivantes d'une méthode void afficher () qui affiche, pour chaque mot du texte, le nombre de fois où il apparaît :
    1. Les mots sont affichés dans un ordre quelconque.
    2. Les mots sont affichés par ordre alphabétique inverse.

Question 3 (2 points)

La classe java.util.Random permet d'obtenir des nombres aléatoires (tirés au hasard). Il existe un constructeur sans paramètre.

Cette classe contient la méthode public int nextInt(int n) qui renvoie un nombre entier compris entre 0 (inclus) et n (non inclus). La méthode lance une java.lang.IllegalArgumentException (classe fille de RuntimeException) si le paramètre est un nombre négatif ou nul.

Écrivez une classe fr.unice.util.Util qui contient une méthode de classe publique "aleatoire(int m, int n)" qui renvoie un nombre entier aléatoire compris entre m (inclus) et n (non inclus). La méthode lance une IllegalArgumentException si n n'est pas strictement plus grand que m. Écrivez le code complet, y compris les importations. Le code ne devra contenir que ce qui est nécessaire à la compilation et au bon fonctionnement de la classe (pensez aux "throws" qui sont obligatoires pour que le code compile par exemple).

Arrangez-vous pour que la classe Util utilise la même instance de Random pour tous les appels de la méthode aleatoire.

Question 4 (2 points)

Voici le code d'une interface graphique :

package fr.unice.controle3.gui;

import java.awt.*;
import javax.swing.*;

public class Main extends JFrame {

  // Zone de texte de 5 lignes et 40 colonnes
  private JTextArea textArea = new JTextArea(5, 40);

  public Main() {
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    this.add(textArea, BorderLayout.CENTER);
    JPanel panelBoutons = new JPanel();
    JButton lancer = new JButton("Lancer");
    final LancerListener lancerListener = new LancerListener();
    lancer.addActionListener(lancerListener);
    panelBoutons.add(lancer);
    JButton stopper = new JButton("Stopper");
    panelBoutons.add(stopper);
    this.add(panelBoutons , BorderLayout.SOUTH);
    this.pack();
    this.setVisible(true);
  }

  public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        construireAfficherGUI();
      }
    });
  }

  private static void construireAfficherGUI() {
    new Main();
  }
  1. Faites un dessin sommaire (mais clair, montrant que vous avez bien compris la disposition des différents composants) de cette interface graphique.
  2. A qui s'adresse le message correspondant à la première ligne du constructeur Main ? Détaillez votre réponse (une ou deux lignes devraient suffire). A quoi sert cette ligne ?

 

Question 5 (4 points)

Lorsque l'utilisateur clique sur le bouton "Lancer" de la question précédente, 2 threads sont lancés en arrière-plan.

Les 2 threads exécutent le code écrit dans une classe fr.unice.controle.Action qui implémente java.lang.Runnable.

Chacun des 2 threads exécute une boucle parcourue un nombre aléatoire de fois ; ce nombre est compris entre 5 (inclus) et 10 (non inclus). Chaque boucle exécute 3 parties :

  1. Code d'initialisation écrit dans la méthode "private void init() { ... }" ;
  2. Code écrit dans la méthode "private int critique() { ... }" qui sera exécutée dans une section critique ;
  3. Code de fin écrit dans la méthode "private void fin() { ... }".

Il est interdit de modifier quoi que ce soit dans le code de ces 3 méthodes. Aucune des 3 méthodes n'est protégée contre les accès concurrents par plusieurs threads ; en particulier la méthode critique ne l'est pas ; c'est donc votre code qui devra créer une section critique qui englobera cette méthode.

Aucune de ces 3 méthodes ne modifie l'interface graphique. Vous pouvez considérer, par exemple, qu'elles font des calculs qui n'ont aucune influence sur l'interface graphique.

La section critique sera protégée contre les accès multiples : si un des 2 threads est en train d'exécuter le code de cette section critique, l'autre thread sera mis en attente.

  1. Écrivez la classe Action en supposant que les méthodes init, critique et fin sont déjà écrites (on ne vous demande pas leur code). Utilisez la méthode aleatoire de la question 1 pour donner le nombre de fois que la boucle est parcourue.
  2. Écrivez la classe LancerListener qui est mentionnée dans le code de la classe Main (voir le début de cette question).

Question 6 (1 point)

Pendant les tests, on voudrait faire afficher si les threads sont en attente ou non pour exécuter la section critique, et, s'ils sont en attente, depuis combien de temps ils le sont.

Pour cela vous utiliserez la méthode

public static long currentTimeMillis()

de la classe java.lang.System.

Voici sa javadoc simplifiée :

public static long currentTimeMillis()
Returns the current time in milliseconds.
Returns:
the difference, measured in milliseconds, between the current time and midnight, January 1, 1970 UTC.

Donnez le code vous allez écrire, et où vous allez l'écrire, pour avoir l'information recherchée. Vous considérerez qu'il n'y a pas d'attente si l'attente est strictement inférieure à 1 milliseconde.

Question 7 (1 point)

Si l'interface graphique est modifiée à la fin de l'exécution de chacun des 2 threads (par exemple, ajout d'une liste déroulante dans l'interface graphique) par l'appel d'un méthode modifGui(), quelle classe allez-vous utiliser pour éviter les problèmes liés aux accès concurrents dans l'interface graphique ?

Décrivez très brièvement les méthodes que vous allez utiliser et ce qui sera exécuté par ces méthodes. Chaque description devra tenir en une ou deux lignes au plus.