Java Avancé
Stéphane Frénot
Télécommunication Services et Usages
stephane.frenot@insa-lyon.fr
Rappels
• Ces mots doivent vous dire quelque chose :
– paquetage, classpath, encapsulation, interface, super, composition, compilation, machine
virtuelle, membre, attribut, méthode, public,
class, protected, this, héritage, abstraction,
virtuelle, static, main, final, block, opérateur,
constructeur, new, classe, message
Plan
• Interfaces graphiques
• Programmation multi-threads
• Applettes
• Collections
• Flux
• Beans
• JNI
• Compléments
Les interfaces graphiques
Les composants
Généralités
• AWT comporte :
– des composants graphiques (widgets)
• Ils représentent les éléments de l'interface utilisateurs
• javax.swing / java.awt
– des classes de gestion des composants (LayoutManager)
• Elles fournissent des classes de gestion des positions
– un mécanisme de gestion d'événements (java.awt.events)
• Elles fournissent l'interaction avec l'utilisateur
– des mécanismes de représentation graphique
• Color, Font, Graphics, Point, Rectangle, Image, Icon...
Historique
• jdk1.0
– AWT
– Evénements de type bulle
• jdk1.1
– AWT
– Evénements de type Modèle Vue Contrôleur
• jdk1.2
– Swing
– Evénements de type Modèle Vue Contrôleur
AWT
• Objectif :
– interface utilisateur dépendant de la plateforme d'exécution
• X11, Win32, MacOs
• Principes :
– Les composants graphiques java, sont
décomposés en deux parties : Le composant et
son pair(peer) de la plateforme d'execution
AWT le composant et son peer
• Les composants reposent sur les composants natifs de la plateforme
• Les applications conservent le « look and feel » de la plateforme cible
Button ButtonPeer MFC_Button
SWING
• L'approche swing est apparue avec les machines plus puissantes
• Les composants sont écrits entièrement en java
• La bibliothèque des objets graphiques a été largement élargie
– Composants complexes
– Possibilité de mettre en place différents « look and feel »
• Principalement une avancée graphique
Composants graphiques (swing)
• Les widgets
– JLabel (*) – JButton (*) – JToggleButton – JCheckbox (*) – JRadioButton (*) – ButtonGroup (*) – JComboBox (*) – JList (*)
– JTextField (*) – JTextArea (*) – JScrollBar (*) – JMenuBar (*) – JPopupMenu
Les containers
JWindow JFrame JDialog
JFileDialog JPanel
Applet JTabbedPane JScrollPane
•Tous les composants graphiques sont reliés par des relations
container/contenu
Tous les widgets swing
Organisation d’un écran
• Composition d’objets graphique dans des containers
• 1-déclaration du container
• 2-insertion des composants dans le container
• 1) Déclaration du composant
• 2) Insertion du composant dans son container
1) JFrame maFenetre=new JFrame("Fenetre");
21) JButton b=new JButton("Bonjour");
22) maFenetre.add(b);
...
maFenetre
b
Button
Frame UneClasse
1
21 22
• Remarque : Un container peut être inséré dans un autre container
Exemple
Exemple
tfPanel chPanel lstPanel
cbPanel rbPanel btPanel MenuBar
Label
Checkbox
Button
TextField Choice
List
Exemple
// Text Field Panel
Panel tfPanel = new Panel();
label = new
Label("TextField");
tfPanel.add(label);
textField = new TextField(15);
tfPanel.add(textField);
// Choice Panel
Panel chPanel = new Panel();
label = new Label("Choice");
chPanel.add(label);
choice = new Choice();
choice.addItem("Solaris");
choice.addItem("Linux");
// List Panel
Panel listPanel = new Panel();
label = new Label("List");
listPanel.add(label);
list = new List();
list.addItem("Solaris");
list.addItem("Linux");
list.addItem("Aix");
listPanel.add(list);
// Checkbox Panel
Panel cbPanel = new Panel();
cbSolaris = new Checkbox("Solaris");
cbPanel.add(cbSolaris);
cbLinux = new Checkbox("Linux");
cbPanel.add(cbLinux);
cbAix = new Checkbox("Aix");
cbPanel.add(cbAix);
Exemple
// RadioButton Panel
Panel rbPanel = new Panel();
rbGroup = new CheckboxGroup();
rbSolaris = new Checkbox("Solaris");
rbSolaris.setCheckboxGroup(rbGroup);
rbPanel.add(rbSolaris);
rbLinux = new Checkbox("Linux");
rbLinux.setCheckboxGroup(rbGroup);
rbPanel.add(rbLinux);
rbAix = new Checkbox("Aix");
rbAix.setCheckboxGroup(rbGroup);
rbPanel.add(rbAix);
rbGroup.setSelectedCheckbox(rbSolaris);
// Insertion dans la Frame Frame laFenetre=new Frame();
laFenetre.add(tfPanel);
laFenetre.add(chPanel);
laFenetre.add(listPanel);
laFenetre.add(cbPanel);
laFenetre.add(rbPanel);
laFenetre.setSize(100,200);
laFenetre.setVisible(true);
• Qu'est ce qu'il manque ?
Les gestionnaires de position
• Politique de placement
• 1 container = 1 gestionnaire
• Gestionnaires standard
Les gestionnaires de position
Layout-Manager
• java.awt.FlowLayout one
threetwo
four five
Frame tmp=new Frame(new FlowLayout());
tmp.add(new Button("one"));
tmp.add(new Button("two"));
tmp.add(new Button("three"));
tmp.add(new Button("four"));
tmp.add(new Button("five"));
Layout-Manager
• java.awt.BorderLayout North
South
West Center East
Frame tmp=new Frame(new BorderLayout());
tmp.add(new Button("North", BorderLayout.NORTH));
tmp.add(new Button("West"), BorderLayout.WEST);
tmp.add(new Button("Center") BorderLayout.CENTER);
tmp.add(new Button("East") BorderLayout.EAST);
tmp.add(new Button("South") BorderLayout.SOUTH);
Layout-Manager
• java.awt.GridLayout one
two
four five
three
six
Frame tmp=new Frame(new GridLayout(3,2));
tmp.add(new Button("one"), 0,0 );
tmp.add(new Button("two"), 1,0);
tmp.add(new Button("three"),2,0);
tmp.add(new Button("four"),1,0);
tmp.add(new Button("five"),1,1);
tmp.add(new Button("six"),1,2);
Layout Manager : UML
L a y o u t M a n a g e r
L a y o u t M a n a g e r 2 C o n t a i n e r
B o r d e r L a y o u t
C a r d L a y o u t
F l o w L a y o u t
G r i d B a g L a y o u t
Layout Manager
• D'autres gestionnaires
– GridBagLayout, CardLayout
• Intérêts
• Avantages
• Inconvénients
Les Interfaces graphiques
Les interactions
Principes de communication
• Comment font deux objets pour communiquer ?
• Y-a-t'il d'autres moyens de communication ?
La propagation des événements
L ’utilisateur réalise une action
Des événements sont alors générés
La Machine Virtuelle reçoit
tous les événements
Seuls les événements écoutés sont transmis
Source de Événements Écouteurs
Les acteurs
• Le Composant :
– Indique les événements qu'il peut générer.
– Button : MouseEvent, ActionEvent, ComponentEvent…
• L'événement :
– Indique l'action que l'utilisateur a générée.
– Ex : MouseEvent
• Le listener :
– Il indique le traitement à faire sur une catégorie d'événements
– MouseListener, ActionListener…
Exemple traitement d'une saisie de texte
1) Définition du composant de saisie de texte 2) Définition du listener qui va traiter le texte
saisi
3) Abonnement du listener sur le composant
U n e F e n ê t r e
L a b e l :
1) Définition de la fenêtre
public class FrameExample extends JFrame { Label leLabel;
TextField leTextField;
public FrameExample(String title) { super(title);
setLayout(new GridLayout(2,1));
leLabel=new Label("Label");
this.add(leLabel, 1,0 );
leTextField=new TextField();
this.add(new TextField());
// A suivre }
}
2) Définition du listener
public class MonTextListener implements TextListener { Frame src;
public MonTextListener (Frame src){
this.src=src;
}
public void textValueChanged(java.awt.event.TextEvent e){
src.leLabel.setText("Nouveau texte");
} }
• Le comportement de type TextListener impose que l'objet de cette classe réponde à l'invocation textValueChanged(TextEvent x)
• Pour traiter une classe d'événement le listener doit répondre à un
certain nombre de méthodes, qui seront automatiquement
2) Exemple de listener
• FocusListener
– focusGained, focusLost
• WindowListener
– windowOpened, windowActivated, windowDeActivated, windowInconified, windowDeIconified, windowClosed, windowClosing
• …
==> Pour connaître les méthodes à implanter en fonction de
l'événement que l'on veut traiter, il faut lire la documentation de
l'interface
3) Abonnement du listener
public class FrameExample extends Frame { Label leLabel;
TextField leTextField;
public FrameExample(String title) { super(title);
setLayout(new GridLayout(2,1));
leLabel=new Label("Label");
this.add(leLabel, 1,0 );
leTextField=new TextField();
this.add(new TextField());
MonTextListener unListener=new MonTextListener(this);
leTextField.addTextListener(unListener);
/* Le compilateur vérifie que :
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
Bouton1
Bouton2 Bouton3 actions
Liste
Event Listener1
Listener1 Listener1
Bouton1.addEventListenr(listener1 )
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
• <Return> à la fin d'une saisie dans un TextField ==> ActionEvent
j a v a . a w t . e v e n t
C o m p o n e n t A d a p t e r
C o n t a i n e r A d a p t e r A c t i o n L i s t e n e r
A d j u s t m e n t L i s t e n e r C o m p o n e n t L i s t e n e r
C o n t a i n e r L i s t e n e r
F o c u s L i s t e n e r
F o c u s A d a p t e r K e y L i s t e n e r
K e y A d a p t e r M o u s e L i s t e n e r
M o u s e M o t i o n L i s t e n e r M o u s e A d a p t e r
M o u s e M o t i o n A d a p t e r W i n d o w L i s t e n e r
W i n d o w A d a p t e r I t e m L i s t e n e r
T e x t L i s t e n e r
A c t i o n E v e n t A d u j s t m e n t E v e n t C o m p o n e n t E v e n t
C o n t a i n e r E v e n t
F o c u s E v e n t I n p u t E v e n t K e y E v e n t
M o u s e E v e n t
P a i n t E v e n t
W i n d o w E v e n t
I t e m E v e n t T e x t E v e n t
A A A
A
A
A
A
j a v a . u t i l . E v e n t L i s t e n e r j a v a . u t i l . E v e n t O b j e c t
j a v a . a w t . A W T E v e n t
A
A
A
A
S
Patterns d'écriture
• Pour un événement de classe Machin
– L'événement : MachinEvent
– L'interface listener : MachinListener – La méthode d'abonnement :
• public void addMachinListener(MachinListener e);
– Un adaptateur : MachinAdapter
Action Event exemple
public class MonActionListener implements ActionListener { public void actionPerformed(java.awt.event.ActionEvent e){
System.out.println("L'action est faite");
} }
public class MaFen2 extends Frame { public MaFen2 () {
MonActionListener unListener=new MonActionListener();
Button unBouton=new Button("Cliquez-moi !");
this.add(unBouton);
unBouton.addActionListener(unListener);
TextField unTextField=new TextField();
unTextField.addActionListener(unListener);
} }
Problèmes ????
Simplification du code
• Un listener est une interface de comportement.
• Cette interface peut être implantée par
n'importe quel objet y compris la classe de définition de l'interface utilisateur
U n e F e n ê t r e
b o u t o n 1 b o u t o n 2 b o u t o n 3 b o u t o n 4
Exemple la fenêtre est son propre listener
public class MaFen2 extends Frame implements ActionListener { public MaFen2 () {
Button b1=new Button(« 1 »);
Button b2=new Button(« 1 »);
Button b3=new Button(« 1 »);
Button b4=new Button(« 1 »);
this.add(b1); this.add(b2); this.add(b3); this.add(b4)
b1.addActionListener(this);
b2.addActionListener(this);
b3.addActionListener(this);
b4.addActionListener(this);
}
public void actionPerformed(java.awt.event.ActionEvent e){
if (e.getSource()==b1){label.setText("1");}
else if (e.getSource()==b2){label.setText("2");}
else if (e.getSource()==b3){label.setText("3");}
else if (e.getSource()==b4){label.setText("4");}}}
La classe peut avoir une innerclasse listener
public class MaFen2 extends Frame {
protected class PrivListener implement ActionEvent{
public void actionPerformed(java.awt.event.ActionEvent e){
/* Idem à l'exemple précédent */
} }
public MaFen2 (){
PrivListener monListener=new PrivListener();
Button b1=new Button(« 1 »);
/* Idem à l'exemple précédent */
this.add(b1); this.add(b2); this.add(b3); this.add(b4)
b1.addActionListener(monListener);
b2.addActionListener(monListener);
b3.addActionListener(monListener);
b4.addActionListener(monListener);
}}
Equilibre
public class MaFen2 extends Frame {
protected class PrivListenerB1 implement ActionEvent{
public void actionPerformed(java.awt.event.ActionEvent e){
label.setText("1");}}
protected class PrivListenerB2 implement ActionEvent{
public void actionPerformed(java.awt.event.ActionEvent e){
label.setText("2");}}
protected class PrivListenerB3 implement ActionEvent{
public void actionPerformed(java.awt.event.ActionEvent e){
label.setText("3");}}
protected class PrivListenerB4 implement ActionEvent{
public void actionPerformed(java.awt.event.ActionEvent e){
label.setText("4");}}
public MaFen2 (){
Button b1=new Button(« 1 »);
/* Idem à l'exemple précédent */
this.add(b1); this.add(b2); this.add(b3); this.add(b4) b1.addActionListener(new PrivListenerB1());
b2.addActionListener(new PrivListenerB2());
b3.addActionListener(new PrivListenerB3());
b4.addActionListener(new PrivListenerB4());
}}
Utilisation des adaptateur
• 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
public class MaFen2 extends Frame { protected class PrivListener implement WindowListener{
public void windowOpened (WindowEvent e){}
public void windowActivated (WindowEvent e){}
public void windowDeActivated (WindowEvent e){}
public void windowInconified (WindowEvent e){}
public void windowDeIconified (WindowEvent e){}
public void windowClosed (WindowEvent e){}
public void windowClosing (WindowEvent e) {System.exit(0);}
}
public MaFen2 (){
PrivListener monListener=
new PrivListener();
this.addWindowListener(this);}
}
public class MaFen2 extends Frame {
protected class PrivListener extends WindowAdapteur{
public void windowClosing (WindowEvent e)
{System.exit(0);}
}
public MaFen2 (){
PrivListener monListener=new PrivListener();
this.addWindowListener(this);
}
}
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
FtpClass connect get
put
FtpGraph
FtpListener
U n e F e n ê t r e
= = > g e t t o t o . m p 3
C o n n e c t G e t P u t
Le pseudo-code
public class MonFtp { public MaFen2{
FtpGraph laFenetre=new FtpGraph(this);
laFenetre.setVisible(true);
}
public static void main(String [] x){
MonFtp unFtp=new MonFtp();
}
public void connect() throws Exception {...}
public void get() throws Exception {...}
public void put() throws Exception {...}
}
public class GraphFtp extends Frame implements ActionListener {
public GraphFtp (MonFtp modele) { this.modele=modele;
// Création de l'interface b1.addActionListener(this);
...
}
public void actionPerformed(ActionEvent e) {
if (e.getSource()==b1){
modele.connect();
} }
}
Si on veut traiter également la saisie clavier, on ne modifie que le
le listener/interface
MVC pseudo-code
public class GraphFtp extends Frame
implements ActionListener, TextListener { public GraphFtp (MonFtp modele) {
this.modele=modele;
// Création de l'interface b1.addActionListener(this);
t1.addTextListener(this);
...
}
public void actionPerformed(ActionEvent e) {...
}
public void textValueChanged(TextEvent e)
if (e.getSource().getText()=="connect"){
modele.connect();
//ou this.actionPerformed(new ActionEvent(b1,0,""));
}
Programmation multi-threads
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
Nouveau- Né
Blockée
Runnable
Morte
Running new()
stop()
resume()
yield()
stop() stop()
start() notify()
suspend() sleep()
wait()
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
class Compteur extends Thread { protected int count;
protected int inc;
protected int delay
public Compteur(int init, int inc, int delay){
this.count=init;
this.inc=inc;
this.delay=delay;
}
public void run(){
try{
for(;;){
System.out.println(count + " ");
count +=inc;
sleep(delay);
}
catch(InterruptedException e){}
}
public static void main(String [] args){
new Compteur(0,1,33).start();
new Compteur(0,-1,100).start();
} }
Exemple : Un générateur de cotations
class Cotation implements Runnable { protected int value;
public cotation(int init){
this.value=init;
}
public void run(){
try{
for(;;){
System.out.println(value);
value+=(Math.random() -0.4) * (10.0 * Math.random());
Thread.sleep(100);
}
catch(InterruptedException e){}
}
public static void main(String [] args){
new Thread(new Cotation(100)).start();
} }
Etat complet
A l i v e
b l o c k e d R u n n a b l e
w a i t t o b e n o t i f i e d
w a i t f o r t a r g e t t o f i n i s h
S l e e p i n g
N o t I n t e r r u p t e d
I n t e r r u p t e d
n e w
D e a d s t a r t ( )
i n t e r r u p t ( ) w a i t ( )
n o t i f y ( ) n o t i f y A l l ( ) j o i n ( )
T a r g e t f i n i s h s l e e p ( )
T i m e o u t
i n t e r r u p t / t h r o w s I n t e r r u p t e d E x c e p t i o n y i e l d ( )
r e t o u r d u r u n
Méthodes des Threads
start() sleep() join() yield()
interrupt()
isAlive()
isInterrupted()
Le thread doit être dans l'état « new » et se retrouve dans l'état
« alive »
Le thread doit être dans l'état « runnable ». Le thread entre en état « blocked » pendant une durée définie
Le thread doit être dans l'état « runnable ». Le thread est placé dans l'état « blocked » et attend la fin d'un autre thread. Il est alors réactivé
Indique qu'un autre thread peut reprendre la main. Le thread reste « runnable »
Si le thead est « runnable » un flag interrupted est positionné.
Si il est dans l'état « blocked » il est réveillé et une InterruptedException est levée
Indique que le thread est dans l'état Alive
Indique que le thread a l'état interrupted positionné
java.lang.Thread (3)
• Le mot réservé
synchronizedpermet 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()
• Dans une partie synchronized d'un objet O :
– wait() relache le verrou et se met en attente.
– notify() reveille un thread en attente (fifo)
– notifyAll() reveille tous les threads en attente
class MyThing {
synchronized void waiterMethod() {...; wait(); ...}
synchronized void notifyMethod() {...; notify(); ...}
synchronized void anOtherMethod() {...}
}
java.lang.Thread (5)
• Scheduling et priorité :
– Le scheduling est en partie dépendant des implémentations
– setPriority() permet de fixer la priorité d'un thread
– Pour 2 threads de même priorité, par défaut : round robin – T1 cède la place a T2 quand sleep() , wait() , bloque sur un
synchronized , yield() , stop()
– Certaines JVM implémentent un time slicing (Win32,
IE, ...)
Les Applets
java.applet.*
Object
AppletStub
AppletContext
Component Container Panel Applet
java.awt
java.applet.Applet (1)
• Une applet est une classe compilée héritant de
java.applet.Applet
• Elle est diffusée par un serveur web dans une page HTML
<APPLET code='TiffViewer.class' width=50 height=50>
<PARAM name='imagesource' value='mon_image.tiff'>
</APPLET>
• Elle est téléchargée puis exécutée par le browser.
• Elle est soumise au Security Manager du browser :
– pas d'accès en lecture ni en écriture sur le disque du browser.
– connexion réseau uniquement sur le serveur d'origine.
– pas de chargement de librairie native.
– pas de lancement de processus, ...
java.applet.Applet (2)
• Structure d'une applet
public class MyApplet extends java.applet.Applet {
public void init() {...}
public void start() {...}
public void paint(java.awt.graphics g) {...}
public void stop() {...}
public void destroy() {...}
}
Cycle de vie de l'Applet
i n i t
s t a r t
s t o p
d e s t r o y c h a r g e m e n t d e l 'a p p l e t
S o r t i e d e l a p a g e
V i s i t e d e l a p a g e
s u p p r i m e r l a p a g e
init() start() stop() destroy()
Initialise l'applet Active l'applet Désactive l'applet Détruit l'applet
Quand l'applet est initialement chargée
Quand on entre dans la page Web qui contient l'applet Quand on quitte la page Web qui contient l'applet Quand la page Web qui contient l'applet est
supprimée
java.applet.Applet (3)
• Diffusion de l'applet
<HTML>
<BODY>
<OBJECT code="MyApplet"
codebase="http://falconet.inria.fr/~dedieu/applets/"
width=300 height=200>
<PARAM name="message" value="Hello World">
</OBJECT>
</BODY>
</HTML>
Exemple de code simple
import java.awt.*;
import java.applet.Applet;
public class HelloFromVenus extends Applet { public void paint(Graphics g){
Dimension d=getSize();
g.setColor(Color.Black);
g.fillRect(0,0,d.width,d.height);
g.setFont(new Font("Sans-serif", Font.BOLD, 24));
g.setColor(new Color(255,215,0));
g.drawString("Hello from Venus", 40, 25);
g.drawImage(getImage(getCodeBase(), "venus.gif"), 20, 60, this);
}
}
Utilisation dans un jar
• jar cvf Hello.jar HelloFromVenus.class Venus.gif
<applet code="HelloFromVenus.class » archive="Hello.jar"
width=300 height=350>
</applet>
Applet dynamique
• Une applet qui change sa représentation dynamiquement doit être un thread
• Comme la classe de base hérite déjà
d'applet il faut qu'elle implante Runnable
• Exemple : une horloge
Horloge
import java.awt.*;
import java.util.Calendar;
public class DigitalClock extends java.applet.Applet implements Runnable {
protected Thread clockThread=null;
protected Font font=new Font("Monospaced", Font.BOLD, 48);
protected Color color=Color.green;
public void start(){
if (clockThread==null){
clockThread=new Thread(this);
clockThread.start();
} }
public void stop(){
clockThread=null;
}
Horloge
public void run(){
while (Thread.currentThread()==clockThread){
repaint();
try{
Thread.currentThread().sleep(1000);
}catch(InterruptedException e){}
}
}public void paint(Graphics g){
Calendar calendar=new Calendar.getInstance();
int hour=calendar.get(Calendar.HOUR_OF_DAY);
int minutes=calendar.get(Calendar.MINUTES);
int second=calendar.get(Calendar.SECOND);
g.setFont(font);
Pourquoi init ?
Idiom : Applet Dynamique
• Catégorie : Implantation de comportement
• Objectif : Permettre à une applet de mettre à jour continuellement son apparence sans
intervention extérieure
• Alias : Active applet
• Application : Utiliser cet idiom pour animer
un process dynamique
Description de l'idiom
public class AnimationApplet extends java.applet.Applet implements Runnable {
Thread mainThread=null;
int delay;
public void start(){
if(mainThread==null){
mainThread=new Thread(this);
mainThread.start();
} }
public void stop(){
mainThread=null;
}
public void run(){
while(Thread.currentThread==mainThread={
repaint();
try{
Thread.currentThread().sleep(delay);
}catch(InterruptedException e){}}}
public void paint(){
(dessine l'applet);
}
(autres méthodes) }
Applet dynamique : ScrollText
import java.awt.*;
import java.util.Calendar;
public class ScrollingBanner extends java.applet.Applet implements Runnable {
protected Thread bannerThread=null;
protected String text;
protected Font font=new Font("Monospaced", Font.BOLD, 48);
protected int x,y;
protected int delay=100;
protected offset=1;
protected Dimension d;
public void start(){
if (bannerThread==null){
bannerThread=new Thread(this);
bannerThread.start();}
Applet dynamique suite
public void init(){
String att=getParameter("delay");
if (att!=null){delay=Integer.parseInt(att);}
att=getParameter("text");
if(att!=null){text=att;}else{text="coucou";) d.getSize();
x=d.width;
y=font.getSize();
}
public void paint(Graphics g){
g.setFont(font); FontMetrics fm=g.getFontMetrics();
int length=fm.stringWidth(text);
x-=offset;
if(x < -length){x=d.width;}
g.setColor(Color.black);
g.fillRect(0,0,d.width,d.height);
g.setColor(Color.green);
g.drawString(text, x, y);
}
Problème de scintillement : fliquering
• Appels :
run
repaint update
-nettoyage du font en le remplissant avec la couleur standard de font
-positionne la couleur du stylo pour l'avant plan -appel la méthode paint
paint
- rempli à nouveau le fond avec la nouvelle couleur - dessine
• Double buffering
– on détourne update pour qu'elle prépare une image hors écran
sur laquelle le dessin se fait
Double-buffering
public class ScrollingBanner2 extends ScrollingBanner { protected Image image;
protected Graphics offscreen;
public void update(Graphics g){
// Création de l'image hors écran if(image==null){
image=createImage(d.width, d.height);
offscreen=image.getGraphics();
}
super.paint(offscreen);
g.drawImage(image, 0, 0, this);
}
java.applet.Applet (4)
• Quelques methodes :
String msg = this.getParameter("message");
this.showStatus("Applet en cours");
Image img = this.getImage(new
URL("http://falconet/image.gif"));
AppletContext ctxt = this.getAppletContext();
ctxt.showDocument(new URL("http://falconet/page.html"),
"frame");
Les Collections Java
Collection abstraites
• Sacs (bags)
– 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
C o l l e c t i o n
S e t L i s t
S o r t e d S e t
S o r t e d M a p M a p
Interface Collection
add(o) addall(c) clear()
contains(o) containsAll(c) isEmpty()
iterator() remove(o) removeAll(c) retainsAll(c) size()
Ajoute un nouvel élément o à la collection
Ajoute tous les éléments de la collection c à cette collection Retire tous les éléments de la collection
Retourne true si la collection contient un élement égal à o Retourne true si tous les éléments de c sont dans la
collection
Retourne true si la collection ne contient pas d'éléments Retourne un itérateur sur la collection
Retire un élément qui égal o s'il existe
Retire tous les éléments qui sont présents dans c
Ne conserve que les éléments qui sont dans c
Retourne le nombre d'éléments de la collection
Interface Set
• Pas de nouvelles méthodes, mais certaines sémantiques changent
add(o) addall(c)
Ajoute l'élément o s'il n'existe pas déjà
Ajoute tous les éléments s'ils n'existent pas déjà
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)
Insère l'élément o à la ième position dans la liste Ajoute l'élément à la fin de la liste
Insère tous les éléments à la fin de la liste, selon l'ordre définit par l'itérateur de c Retourne l'élément à la ième position
Retourne l'index de la première occurrence de o ou -1 si l'élément n'est pas dans la liste
Retourne l'index de la dernière occurrence de o ou -1 si l'élément n'est pas dans la liste
Retourne un itérateur de liste
Retourne un itérateur positionné sur le ième élément Retire l'élément à la ième position et le renvoie Retire la première occurrence de l'élément o
Remplace l'élément à la position i par l'élément o et renvoie l'ancien
Renvoie une sous-liste à partir de i inclus jusqu ’à j exclu
Interface Map
clear()
containsKey(k) containsValue(v) entrySet()
get(k) isEmpty() keySet() put(k, v) putAll(m) remove(k) size() values()
Retire tous les mapping de la carte
Retourne true si la carte contient un mapping pour la clé k Retourne true si la carte contient une ou plusieur clé pour v Retourne un ensemble des mapping de la cette carte
Retourne la valeur mappée par la clé k
Retourne true si la collection ne contient pas de mapping Retourne un ensemble des clés de la carte
Associe la valeur v à la clé k
Copie tous les mapping de la map m Retire le mapping de la clé k
Retourne le nombre de paires clé-valeur de la carte
Retourne une Collection des valeurs contenues dans la carte
Implantation des collections
HashSet TreeSet ArrayList LinkedList Vector
HashMap TreeMap HashTable
Set
SortedSet List
List List Map
SortedMap Map
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)
Retourne le comparateur utilisé pour cet ensemble trié ou null si l'ordre naturel est utilisé
Retourne le premier élément de l'ensemble trié
Retourne un ensemble dont les éléments sont strictement inférieurs à o
Retourne le dernier élément de l'ensemble
Retourne un sous-ensemble compris entre o1 inclus et o2 exclus Retourne un ensemble dont les éléments sont égaux ou supérieurs
à o
Interface SortedMap
comparator() firstKey() headMap(m) lastKey()
subMap(k1, k2) tailMap(k)
Retourne le comparateur utilisé pour cette carte triée ou null si l'ordre naturel est utilisé
Retourne la première clé de la carte triée
Retourne une carte dont les éléments sont strictement inférieurs à la clé k
Retourne le dernier élément de la carte
Retourne une sous-carte comprise entre k1 inclus et k2 exclus
Retourne une carte dont les éléments sont égaux ou supérieurs à k
Iterateur
• Un itérateur permet de parcourir les éléments d'une collection
Liste maListe=new Liste();
//… Insertion des éléments
Iterator iter1=maListe.iterator();
for (;iter1.hasNext();){
Paquet p1=(Paquet)iter1.next();
Iterator iter2=list.iterator(),;
for (;iter2.hasNext();){
Paquet p2=(Paquet)iter2.next();
if (p2.isSameStack(p1)){
System.out.println(p1+" appartient à la même pile que "+p2);
} }
}
IO FrameWork
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()
Lecture/Ecriture d’un octet Lecture/Ecriture d'un tableau Lecture/Ecriture d'un segment Fermeture du flux
write(b) write(ba)
write(ba,off,len) close()
I n p u t S t r e a m O u t p u t S t r e a m
F i l e I n p u t S t r e a m F i l e O u t p u t S t r e a m
FileInputStream(filename)throws IOException FileOutputStream(filename) throws IOException
FileOutputStream(filename, append) throws IOException
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()
writeBoolean() writeByte() writeChar() writeDouble() writeFloat() writeInt() writeLong() writeShort() writeUTF()
I n p u t S t r e a m
F i le I n p u t S t r e a m F i l t e r I n p u t S t r e a m
D a t a I n p u t S t r e a m
D a t a I n p u t
O u t p u t S t r e a m
F i l e O u t p u t S t r e a m F i l t e r O u t p u t S t r e a m D a t a O u t p u t
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
I n p u t S t r e a m
F i l e I n p u t S t r e a m F i l t e r I n p u t S t r e a m
D a t a I n p u t S t r e a m
D a t a I n p u t
B u f f e r e d I n p u t S t r e a m
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
I n p u t S t r e a m
F i l e I n p u t S t r e a m O b j e c t I n p u t S t r e a m
D a t a I n p u t
O b j e c t I n p u t
readObject()
writeObject()
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é.
Design pattern
• La fonction de base est fournie par les Stream IO
• Il y a plein de fonctionnalités qui s'ajoutent à la fonction de base :
– Data, Object, Buffer, Compression, Encryption…
• Pour mettre en œuvre ces différents ajouts et
combinaisons on peut spécialiser autant de fois les classes ou…
• Utiliser le design pattern décorateur (ou filtreur)
– new Decorateur2(new Decorateur1(inputStream))
Les flux caractères
• Les caractères java sont en Unicode (2octets)
• L'écriture de caractère est fonction des paramètres locaux de la machine
– ISO-8859-1 ==> ASCII (codage sur 1 octet)
– GB-2312 ==> Ideogrammes chinois + caractères latins – java.util.Locale.setDefaults(java.util.Locale.ENGLISH)
• Les flux octets sont indépendants de la locale, les flux
caractères sont dépendants
Schéma de classes
R e a d e r
I n p u t S t r e a m R e a d e r B u f f e r e d R e a d e r I n p u t S t r e a m
F i l e R e a d e r
W r i t e r
O u t p u t S t r e a m R e a d e r B u f f e r e d W r i t e r
O u t p u t S t r e a m P r i n t W r i t e r