Calculez la complexité en temps relativement à n, du code C1 et C2, sachant que
la création d'un objet coûte 10ms, l'addition d'entiers 0.5ms, la comparaison d'entiers
0.1ms, l'accès à un élément d'un tableau 0.1ms, l'appel de la méthode append 3ms.
Note : L'appel de
+sur une chaîne de caractère crée unStringBufferet va appeler sa méthodeappend.
String ch = new String(); // | 10ms int n = tab.length; // Balec for (int i = 0; i < n; i++) // | Pour `i < n` : (n+1) * 0,1ms // | Pour `i++` : n * 0,5ms // Le tout multiplié par n ici ch += new String(tab[i]) + ","; // | Pour `new String()` : 10ms // | Pour `tab[i]` : 0,1ms // | Pour `ch +=` : 10ms + 3ms // | Pour `+ ","` : 10ms + 3ms System.out.println("tab = " + ch); // | Pour `"tab =" + ch` : 10ms + 3ms
On a donc une complexité temporelle
StringBuffer sb = new StringBuffer(); // | Pour `new StringBuffer()` : 10ms String sep = new String(", "); // | Pour `new String()` : 10ms int n = tab.length; // Balec for (int i = 0; i < n; i++) // | Pour `i < n` : (n + 1) * 0,1ms // | Pour `i++` : n * 0,5ms // Le tout multiplié par n ici sb.append(new String(tab[i])) // | Pour `.append` : 2 * 3ms .append(sep); // | Pour `new String()` : 10ms // | Pour `tab[i]` : 0,1ms System.out.println("tab = " + ch); // | Pour `"tab =" + ch` : 10ms + 3ms
On a donc en complexité temporelle :
Pourquoi l'utilisation de la classe Vector est-elle plus lente que celle de
la classe ArrayList ?
L'utilisation de la classe Vector est plus lente car la JVM va synchroniser les
accès à la classe Vector mais ne va pas le faire pour les instances de la classe
ArrayList. Ceci permet de faire de la programmation multi-threads avec Vector.
Dans la programmation par processus, le code suivant permet à plusieurs processus
de stocker un objet dans un tableau tampon. Que se passe-t-il si un processus appelle
ce code alors qu'un processus est déjà entré dedans (et qu'il est à la ligne
nbObjetsCourants++) ?
public synchronized void depose(Object obj) { while (nbObjetsCourant == (taille - 1)) { try { wait(); } catch (InterruptedException e) { } } try { tampon[nbObjetsCourant] = obj; } catch (Exception e) { System.out.println(e); } nbObjetsCourant++; produits++; notify(); }
Le fait que la définition de la méthode ait le mot clé synchronized permet
d'indiquer à la JVM que cette méthode est susceptible d'être appelée par plusieurs
threads. L'appel à notify permet d'indiquer à Java qu'un autre processus peut
appeler cette méthode.
De ce fait, si un autre processus appel cette méthode alors qu'un autre processus
est à l'instruction nbObjectCourants++, ce processus va se bloquer jusqu'à ce que
notify soit appelé.
Que se passe-t-il si un processus entre dans la méthode et que nbObjetsCourant est au maxime (== taille - 1)?
Dans ce cas, l'appel de cette méthode va bloquer le processus puisque la condition
du while sera évaluée a true et qu'il y aura un appel à wait.
Quel est le principe du garbage collector (ramasse miettes) ?
Le principe du garbage collector est de libérer l'espace mémoire occupé par les objets qui ne sont plus utilisés dans le programme.
Quel est le principe de JavaFX pour la création d'applications graphiques ?
Le principe de JavaFX est de créer des applications graphiques en manipulant des
objets qui représentent des formes (ligne, cercle, etc.). Une application JavaFX
hérite de la classe javafx.application.Application et sa méthode start permet
d'accéder à une scène principale (Stage) pour dessiner les éléments. À cette scène
est associé une ou plusieurs scène possèdant une troupe d'objets qui gardent en
mémoire les éléments dessinés sur cette scène.
Créer une classe représentant une Plage.
Un object Page est composé d'un nom, de deux coordonées GPS réelles (gpsx,
gpsy) et d'un numéro unique d'instance (no). La classe possède un membre de
classe indiquant le nombre d'instances créées.
Le constructeur par défaut de Page initiliase les coordonnées à 0.
Vous écrirez également un constructeur qui prend en paramètre son nom et
ses coordonées. Surcharger la méthode toString pour retourner une représentation
d'un objet Plage par son nom, ses coordonées et son numéro d'instance.
class Plage { static int nbInstances = 0; protected double gpsx; protected double gpsy; protected String nom; protected int no; /** * Constructeur par défaut. */ Plage() { this.gpsx = 0; this.gpsy = 0; this.no = this.nbInstances; this.nbInstances++; } /** * Constructeur avec paramètres */ Plage(String nom, double gpsx, double gpsy) { this.nom = nom; this.gpsx = gpsx; this.gpsy = gpsy; this.no = this.nbInstances; this.nbInstances++; } /** * Surchage de la méthode `toString` */ public String toString() { return "Plage " + this.nom + "(n°" + this.no + ", " + "cordonnées : x = " + this.gpsx + ", y = " + this.gpsy + ")."; } }
Créer une classe PlageSurveillee qui étend Plage. Un objet PlageSurveillee
possède en plus une variable de type Categorie. Le type Categorie est une
énumration à définir, contenant les constantes FAMILLE, SURFEURS et
NATURISTES. Le constructeur par défaut de PlageSurveillee initialise la
catégorie cat à FAMILLE. Un constructeur de PlageSurveillee prenant en
paramètre le nom et la valeur de sa catégorie qui doit être définie. Il doit
utiliser un constructeur de la classe mère.
Rédéfinir la méthode toString pour cette classe pour retourner une
représentation avec son nom, ses coordonnées, son numéro d'instance et sa catégorie.
public enum Categorie { FAMILLE("familles"), SURFEURS("surfeurs"), NATURISTES("naturistes"); protected String texte; Categorie(String texte) { this.texte = texte; } public String toString() { return texte; } } class PlageSurveillee extends Plage { protected Categorie cat; /** * Constructeur par défaut. */ PlageSurveillee() { super(); this.cat = Categorie.FAMILLE; } /** * Constructeur avec paramètres */ PlageSurveillee(String nom, double gpsx, double gpsy, String categorie) { super(nom, gpsx, gpsy); try { this.cat = Categorie.valueOf(categorie); } catch (IllegalArgumentException e) { System.out.println("La catégorie spécifiée n'existe pas"); } } /** * Surchage de la méthode `toString` */ public String toString() { return "Plage " + this.nom + " pour " + this.cat + "(n°" + this.no + ", " + "cordonnées : x = " + this.gpsx + ", y = " + this.gpsy + ")."; } }
Soit le code suivant :
ArrayList<Plage> lesPlages = new ArrayList<>(); lesPlages.add(new Plage("l'Anse de la Baie", 49.13, 6.66)); lesPlages.add(new Plage("La baie de l'Anse", 42.53, 3.08)); ArrayList<PlageSurveillee> lesSurveillees = new ArrayList<>(); lesSurveillees.add(new PlageSurveillee("Santissu", 42.23, 6.66, Categorie.NATURISTES)); lesSurveillees.add(new Plage("ValenciennesPlage", 50.34, 3.5)); for (Plage p : lesPlages) System.out.println(p); for (PlageSurveillee ps : lesSurveillees) System.out.println(ps); lesPlages.add(new PlageSurveillee("Les Rouleaux", 43.95, -1.36, Categorie.SURFEUR));
Quelle(s) ligne(s) déclenche(nt) une erreur, pourquoi ? Proposez une correction.
La ligne suivant va lever une exception car le type que peut contenir l'ArrayList ne correspond pas à celui que l'on essaie d'insérer :
lesSurveillees.add(new Plage("ValenciennesPlage", 50.34, 3.5));
La solution consiste donc à utiliser un wildcard pour spécifier que cette
ArrayList peut accepter des éléments de type Plage ou des classes filles. Il
faut ensuite changer la boucle for pour refléter ceci :
ArrayList<Plage> lesPlages = new ArrayList<>(); lesPlages.add(new Plage("l'Anse de la Baie", 49.13, 6.66)); lesPlages.add(new Plage("La baie de l'Anse", 42.53, 3.08)); ArrayList<? super Plage> lesSurveillees = new ArrayList<>(); lesSurveillees.add(new PlageSurveillee("Santissu", 42.23, 6.66, Categorie.NATURISTES)); lesSurveillees.add(new Plage("ValenciennesPlage", 50.34, 3.5)); for (Plage p : lesPlages) System.out.println(p); for (Object ps : lesSurveillees) System.out.println((PlageSurveillee)ps); lesPlages.add(new PlageSurveillee("Les Rouleaux", 43.95, -1.36, Categorie.SURFEUR));
Afin de pouvoir trier les collections d'objets de type Plage et d'objets de
type PlageSurveillee, ces classes doivent implémenter l'interface Comparable.
Réécrivez l'entête de ces classes et écrivez la fonction int compareTo(Object o)
nécessaire dans ces deux classes pour que le tri de Plage se fasse par nom en
ordre alphabétique et que le tri de PlageSurveillee se fasse par catégorie
puis par nom.
Aucune méthode de tri n'est demandée, la méthode Collection.sort(liste) de Java effectue ce tri.
Pour la réécriture des entêtes :
class Plage implements Comparable { class PlageSurveillee extends Plage implements Comparable {
Rappel : Fonctionnement de
compareTo
Pour l'implémentation des méthodes int compareTo(Object o) :
// Dans la classe Plage public int compareTo(Object o) { return this.nom.compareTo(((Plage)o).nom); } // Dans la classe PlageSurveillee public int compareTo(Object o) { PlageSurveillee autre = (PlageSurveillee)o; int resultat = this.cat.texte.compareTo(autre.cat.texte); // Si deux éléments sont de la même catégorie, on les // classe par nom. if (resultat == 0) return this.nom.compareTo(autre.nom); else return resultat; }
Collections.sort(lesPlages); Collections.sort(lesSurveillees);
Utilisez la notation lambda pour trier une liste de Plage par nom en ordre
alphabétique inverse, en utilisant la fonction Collections.sort(liste, comparateur) :
Note : Il y a une erreur dans le code de l'énoncé ;
Collections.sortne renvoie rien et modifie directement la liste donnée en paramètre. Le code original de l'énoncé était :ArrayList<Plage> plagesTriees = Collections.sort(lesPlages); ArrayList<PlageSurveillee> surveilleesTriees = Collections.sort(lesSurveillees);
En utilisant la notation lambda on a donc :
// Il suffit de reprendre le code des méthodes compareTo mais ici // on n'a pas accès au `this` mais à deux éléments à comparer. Collections.sort(lesPlages, (p1, p2) -> { return p1.nom.compareTo(p2.nom); }); Collections.sort(lesSurveillees, (ps1, ps2) -> { int resultat = ps1.cat.texte.compareTo(ps2.cat.texte); // Si deux éléments sont de la même catégorie, on les // classe par nom. if (resultat == 0) return ps1.nom.compareTo(ps2.nom); else return resultat; });