1 : Le composant peut générer des événements text (il répond à la méthode addTextListener
2 : Le listener abonné est bien un TextListener (la méthode addTextListener n'accepte qu'un TextListener en paramètre*/
}}
Schéma de fonctionnement
Les composants et leurs événements
Tous les composants génèrent des événements
Car il dérivent de la classe Component qui génère des événements
Tous les composants ne génèrent pas tous les événements
Un bouton ne génère pas d'événements de type text
Il existe pour les composants élémentaires un événement de sémantique générale appelé ActionEvent, qui représente l'interaction standard avec l'utilisateur
Click sur bouton ==> ActionEvent
DoubleClick sur une liste ==> ActionEvent
Click sur un élément de liste ==> ActionEvent
à la fin d'une saisie dans un TextField ==> ActionEvent
Un adaptateur (Adapter) est une classe qui implante un comportement standard qui permet à l'utilisateur de ne surcharger que les méthodes qui l'intéressent
Adaptateur exemple
Le modèle MVC
Une application se décompose en trois parties
Modèle : données de l'application
Vue : représentation de ses données
Contrôleur : contrôle de l'activation d'une vue en fonction de critères de choix
Exemple : Excel
==> Il existe de nombreuses de manières d'implanter ce modèle
Conception d'une application en Java
Modèle : classe de traitement
Elle définit toutes les méthodes applicatives
Vue : classe graphique de représentation
Elle définit la représentation de l'application
Contrôleur : classe listener
Elle redirige les actions de l'utilisateur sur les classes de traitement
Remarque : le listener et la vue peuvent être contenus dans la même classe
Exemple : Un client graphique ftp
Le pseudo-code
MVC pseudo-code
Programmation multithread
Un thread est un processus en exécution concurrente avec d'autres processus.
Tout objet java s'exécute dans au moins un thread
La programmation multi-thread est indissociable de Java.
Un programme « simple » exécute les threads suivants :
Thread principal
Garbage collector
La file d'événements graphiques
Java est multi-threads
Exécution de tâches en //
Mémoire, Code et Ressources partagés
Economie de ressources
Un thread ~= méthode qui rend immédiatement la main
Exemple événements (IHM, gc)
+ priorités
+ synchronisation
(moniteur, synchronized)
Implantation dépendante du SE
java.lang.Thread (1)
Cette classe permet de déléguer le traitement d'un objet par une nouvelle thread.
2 possibilités : soit hériter de Thread soit implémenter Runnable
class C1 extends Thread
{
public C1() { this.start(); }
public void run() {...}
}
class C2 implements Runnable
{
public C2() {Thread t = new Thread(this); t.start(); }
public void run() {...}
}
Exemple : un compteur
Exemple : Un générateur de cotations
Etat complet
Méthodes des Threads
start()
sleep()
join()
yield()
interrupt()
isAlive()
isInterrupted()
java.lang.Thread (3)
Le mot réservé synchronized permet de synchroniser l'accès à une partie de code où à une méthode.
class Banque {
synchronized void ajouter(int montant) {...}
synchronized void retirer(int montant) {...}
}
class Client implements Runnable {
Banque b;
public Client(Banque b) {
this.b = b;
Thread t = new Thread(this); t.start();
}
public void run() { ... b.ajouter(100); ... b.retirer(10); ...}
}
Banque b = new Banque();
Client c1 = new Client (b); Client c2 = new Client(b);
java.lang.Thread (4)
Chaque objet possède les méthode wait(), notify() et notifyAll()
Collection non ordonnée d'éléments qui peut contenir des doublons. Interface Collection
Ensembles (sets) :
Collection non ordonnée sans doublons d'éléments (un même élément inséré deux fois donne un seul élément). Une sous-classe est l'ensemble ordonné. Interface Set et SortedSet
Listes (lists)
La liste est une collection ordonnée d'éléments (aussi appelée séquence). Les éléments d'une liste sont indexés séquentiellement en démarrant de 0. Les doublons sont autorisés. Interface List
Cartes (maps)
Une carte est une collection non ordonnée de paires clés -> valeurs. Les cartes sont aussi connues comme (fonctions, dictionnaires, tableaux associatifs). Les clés dans une cartes sont uniques. Les cartes peuvent être triées selon les clés. (sortedMap, orderedMap). Interface Map, SortedMap
Schéma
Interface Collection
add(o)
addall(c)
clear()
contains(o)
containsAll(c)
isEmpty()
iterator()
remove(o)
removeAll(c)
retainsAll(c)
size()
Interface Set
Pas de nouvelles méthodes, mais certaines sémantiques changent
Interface list
add(i,o)
add(o)
addall(c)
get()
indexOf(o)
lastIndexOf(o)
listIterator()
listIterator(i)
remove(i)
remove(o)
set(i,o)
subList(i,j)
Interface Map
clear()
containsKey(k)
containsValue(v)
entrySet()
get(k)
isEmpty()
keySet()
put(k, v)
putAll(m)
remove(k)
size()
values()
Implantation des collections
HashSet
TreeSet
ArrayList
LinkedList
Vector
HashMap
TreeMap
HashTable
Quelle classe utiliser ?
TreeSet / HashSet :
Les éléments sont triés par (comparateur/clé de Hash)
add et contains sont en : O(log n) / O(1)
ArrayList / LinkedList
perte de place/pas de perte
perte de performance si la taille max est dépassée
get et set : O(1) / O(n)
Vector : histoire de java
TreeMap / HashMap :
Les éléments sont triés par (comparateur/clé de Hash)
put et get : O(log n)/O(1)
Hashtable : histoire de java
Ordre et Tri
Deux manières de définir un ordre
La classe des objets à trier fournit une implantation de l'interface Comparable
public int compareTo(Object o)
Ordre naturel
On peut utiliser un comparateur externe (classe qui implante l'interface Comparator
public int compare (Object o1, Object o2)
Interface SortedSet
comparator()
first()
headSet(o)
last()
subSet(o1, o2)
tailSet(o)
Interface SortedMap
comparator()
firstKey()
headMap(m)
lastKey()
subMap(k1, k2)
tailMap(k)
Iterateur
Un itérateur permet de parcourir les éléments d'une collection
Type de I/O
IO Streams (Flux E/S) : Un flux est une séquence d'octets. Les E/S de type flux permettent la lecture et l'écriture séquentielle de données. Un flux peut être ouvert soit en lecture soit en écriture
Random Access I/O (E/S direct) : Une ES directe permet la lecture et l'écriture de données de n'importe où dans un fichier. Un fichier à accès direct peut être ouvert en lecture et en écriture
Les flux
Il existe deux familles de flux
Les byte Stream : flux d'octets de n'importe quel type (incluant les String) au format binaire
Les character Stream : flux d'entrée / sortie de type texte, en utilisant les caractéristiques locales.
L'interface des byte streams
read()
read(ba)
read(ba,off,len)
close()
java.io.File(Input|Output)Stream
Ces classes permettent d'accèder en lecture et en écriture à un fichier.
FileInputStream fis = new FileInputStream("source.txt");
byte[] data = new byte[fis.available()];
fis.read(data);
fis.close();
FileOutputStream fos = new FileOutputStream("cible.txt");
fos.write(data);
fos.close();
Problème : si on veut lire des doubles
public static double readDouble(InputStream in)
throws IOException {
byte [] buf=new byte[8];
in.read(buf);
long l=0;
for (int k=0; k<8; k++){
l <<= 8;
l += (((int)buf[k] & 0xFF);
}
return Double.longBitsToDouble(l);
}
Les interfaces DataInput / DataOuput
readBoolean()
readByte()
readChar()
readDouble()
readFloat()
readInt()
readLong()
readShort()
readUTF()
java.io.Data(Input|Output)Stream
Ces classes permettent de lire et d'écrire des types primitifs et des lignes sur des flux.
FileInputStream fis = new FileInputStream("source.txt");
DataInputStream dis = new DataInputStream(fis);
int i = dis.readInt();
double d = dis.readDouble();
String s = dis.readLine();
FileOutputStream fos = new FileOutputStream("cible.txt");
DataOutputStream dos = new DataOutputStream(fos);
dos.writeInt(123);
dos.writeDouble(123.456);
dos.writeChars("Une chaine");
Flux bufferisés
La lecture réelle du flux est réalisée de manière asynchrone
Les données sont lue et mises dans un buffer en mémoire
Flux d'objets
Sérialiser : Ecrire un objet et tous les objets qu'il référence dans un flux
Déserialiser : Refabriquer l'objet
java.io.Object(Input|Output)Stream (1)
Ces classes permettent de lire et d'ecrire des objets, implémentant java.io.serializable, sur des flux.
// Ecriture
FileOutputStream fos = new FileOutputStream("tmp");
ObjectOutput oos = new ObjectOutputStream(fos);
oos.writeObject("Today");
oos.writeObject(new Date());
oos.flush();
// Lecture
FileInputStream fis = new FileInputStream("tmp");
ObjectInputStream ois = new ObjectInputStream(fis);
String today = (String)ois.readObject();
Date date = (Date)ois.readObject();
java.io.Object(Input|Output)Stream (2)
Par défaut, tous les champs sont sérialisés (y compris private)
Cela peut poser des problemes de sécurité
3 solutions :
Ne pas implémenter Serializable
Réécrire les méthodes writeObjet() et readObject()
Le mot clé transcient permet d'indiquer qu'un champs ne doit pas être serialisé.
Possibilité d’avoir des propriété contraintes (vetoable)
Persistance
Sauver son état
Notion de personnalisation
La sérialisation Java est le mécanisme technique de persistance
Éviter qu’un attribut soit sérialisé :
private transient String motDePasse;
Accès à l'environnement externe
Les machines virtuelles Java peuvent accéder au système sous-jacent
L'utilisation de méthodes natives de l'environnement se fait par l'appel de méthodes natives
Les méthodes natives sont des méthodes définies dans un langage autre que java (C ou C++)
Le package java.native donne les méthodes pour ces appels
Une méthode native ne peut pas être abstraite
Jni : Java Native Interface Framework
Cycle de développement
HelloWorld.java
HelloWorld le programme C
Principes de portées des attributs
Les attributs d'un objet (méthodes et variables) possèdent un «modificateur » qui indique la visibilité de l'attribut pour les autres objets
La visibilité de l'attribut peut être spécifié d'une manière intra ou inter objets
Accès par this. ou par obtention d'une référence sur l'objet.
Modificateurs de portée
Il y a 4 modificateurs
public : d'une manière général ouvre l'accès à l'attribut (OK pour méthode, KO pour variable)
protected : l'attribut est visible pour les classes qui héritent de l'attribut et les classes du même package (OK pour attributs et méthodes)
<vide> : l'attribut est visible pour les classes du package mais pas pour les classes qui en héritent dans d'autre package (Développement en package)
private : l'attribut n'est visible que pour la classe (variable interne)
L'encapsulation des membres héritage
L'encapsulation des membres par référence
Interface marqueur (marker)
Une interface de type marqueur est une interface vide dont le rôle est de « marquer » un objet comme possédant certaines caractéristiques
Exemple :
cloneable, serializable
Masquage et Surcharge
Introduction d'un champ ou d'une méthode statique dans une sous-classe qui possède le même nom que la classe parent
Masquage ==> Compilation, Surcharge ==> Execution
==> NE JAMAIS FAIRE DE MASQUAGE !
Forme Canonique d'une classe publique
Définir un constructeur publique sans argument
Surcharger la méthode toString()
Surcharger la méthode equals() et hashCode()
Implanter l'interface Cloneable et surcharger clone()
Si les instances peuvent être sauvegardées (ou transférées), implanter l'interface Serializable et éventuellement surcharger les méthodes readObject() et writeObject()
Equivalence d'objets
La méthode equals() permet de tester l'équivalence entre deux objets (différent de ==)
L'équivalence de base se fait si deux objets ont la même identité (pointeurs sur la même zone).
Il est préférable de comparer leur états et non pas leur identité.
Exemple : deux listes sont égales si elles ont le même nombre d'éléments et les éléments d'une même position sont égaux.
Contrat Equals
Relation d'équivalence :
Réflexive : pour x, x.equals(x) renvoie true
Symétrique : pour x et y, x.equals(y) doit retourner true si et seulement si y.equals(x) renvoie true
Transitive : pour x,y,z, si x.equals(y) renvoie true et y.equals(z) renvoie true alors x.equals(z) doit renvoyer true
Consistante : l'égalité est persistante dans le temps
Non-nullité : Pour tout référence non nulle : x.equals(null) renvoie false
Code de Hash
La méthode hashCode() permet de fournir une valeur de hash pour un objet
Si deux objets sont equals il doivent fournir la même valeur de hash
Cette méthode est utilisée par des classes de gestion de collections (HashMap, HashSet)
Deux objets différents peuvent renvoyer la même valeur de hash
Contrat du Hash
Pour toute invocation sur le même objet le code de hash doit renvoyer le même int
Si deux objets sont égaux par la méthode equals(objets), leurs fonction de hash doit renvoyer le même entier
Deux objets non égaux peuvent renvoyer la même valeur de hash
Clonage d'objets
La méthode clone permet d'obtenir un clone d'un objet (copy constructeur du C++)
Le clone ne doit pas être le même que l'objet initial (c.clone() != c)
Le clone doit être égal à l'objet initial (c.equals(c.clone())
Pour qu'un objet soit clonable, il faut qu'il implante l'interface Cloneable
L'implantation par défaut de clone fait une « copie ombre » et non pas une « copie profonde »
Conversion en chaîne
La méthode toString() permet de fournir une représentation de type chaîne d'un objet
En appelant la méthode System.out.println(o), l'objet présente sa chaîne de caractères.
Sérialisation
La sérialisation (Serialization) est le processus de transformation d'un objet dans un flux d'octets, et la déserialisation le processus inverse.
La sérialisation permet à un objet d'être facilement sauvé sur un fichier ou transféré sur le réseau
Les classes doivent implanter l'interface Serializable et éventuellement surcharger les méthodes readObject() et writeObject()
java.lang.String (1)
La classe String gère des chaînes de caractères (char).
Une String n’est pas modifiable.
Toute modification entraine la création d'une nouvelle String.
Les valeur littérales ("abc") sont transformées en String.
L'opérateur + permet la concaténation de 2 String.
Java.lang.String (2)
String s = "\u00catre ou ne pas \u00catre"; // s = "être ou ne pas être"
int lg = s.length(); // lg = 19
String s = "Java" + "Soft"; // s = "JavaSoft"
String s = (String) new URL("http://server/big.txt").getContent();
char[] data = {'J', 'a', 'v', 'a'};
String name = new String(data);
String s = String.valueOf(2 * 3.14159); // s = "6.28318"
String s = String.valueOf(new Date()); // s = "Sat Jan 18 12:10:36 GMT+0100 1997"
int i = Integer.valueOf("123"); // i = 123
String s = "java";
if (s == "java") {...} // Erreur
if (s.equals("java") {...} // Ok
java.lang.StringBuffer
La classe StringBuffer gère des chaînes de caractères (char) modifiable (setCharAt(), append(), insert())
La méthode toString() convertit une StringBuffer en String (pas de recopie, le même tableau est partagé, jusqu'à modification)