PROJET PROGRAMMATION ORIENTÉE OBJET (POO) Université Antonine 2010 - 2011 Plan détaillé Initiation Java Interfaces Graphiques ◦ Awt ◦ Swing Evénements ◦ ActionListener ◦ MouseListener ◦ Etc. Rappel sur les notions de POO Application Client - Serveur ◦ Base de données Threading et Gestion du Graphisme Plan détaillé Initiation C# Interface Graphique Manipulation Fichiers ◦ Editeur de Texte Réseaux et Sockets ◦ Serveur Chat Connaissances Acquises Elaborer une bonne démarche scientifique nécessaire pour le développement d’une application Intégrer les interfaces de programmation nécessaires à l’application en question. Développer des applications dotées d’interfaces graphiques et/ou de communication (client/serveur). Connaissances Requises Des notions de bases en ◦ Algorithmique L3G ◦ Algorithme OO INITIATION JAVA Introduction Java Orienté objet ◦ Java ne permet d'utiliser que des objets (hors les types de base) Sûr ◦ Seul le bytecode est transmis, et «vérifié» par l’interpréteur Le code source est préservé 7 Caractéristiques du langage Java Simple ◦ Apprentissage facile faible nombre de mots-clés simplifications des fonctionnalités essentielles ◦ Développeurs opérationnels rapidement Familier ◦ Syntaxe proche de celle de C/C++ 8 Caractéristiques du langage Java Fiable ◦ Gestion automatique de la mémoire (ramasse-miette ou "garbage collector") ◦ Gestion des exceptions ◦ Sources d'erreurs limitées typage fort, (le type est imposé) pas d'héritage multiple, pas de manipulations de pointeurs, etc. ◦ Vérifications faites par le compilateur facilitant une plus grande rigueur du code Vérification des types, des constructeurs des classes, … 9 Java, un langage Interprété Java est un langage interprété ◦ La compilation d'un programme Java crée du pseudo-code portable : le "byte-code" ◦ Sur n'importe quelle plate-forme, une machine virtuelle Java peut interpréter le pseudo-code afin qu'il soit exécuté Les machines virtuelles Java peuvent être ◦ des interpréteurs de byte-code indépendants (pour exécuter les programmes Java) ◦ contenues au sein d'un navigateur (pour exécuter des applets Java) 10 langage Compilé Fichier C (.c) Compilateur C Code executable 11 langage interprété Fichier Java (.java) Compilateur Javac bytecode(.class) Machine Virtuelle java Code executable 12 L’API de Java Java fournit de nombreuses librairies de classes remplissant des fonctionnalités très diverses : c'est l'API Java Ces classes sont regroupées, par catégories, en paquetages (ou "packages") ◦ ◦ ◦ ◦ Swing Java2D Java3D JAAS (Java Authentication and Authorization Service) Java Security Framework ◦ Etc. 13 INTERFACE GRAPHIQUE EN JAVA APIs correspondantes AWT ◦ Utilise des composants du systèmes Swing (Sun Microsystems) ◦ Composants entièrement dessinés en Java SWT (Standard Widget Toolkit) ◦ ◦ ◦ ◦ Initialement développée par IBM Maintenu par Eclipse foundation Une librairie graphique Utilise les composants du système d’exploitation( comme le dll WinApi,..) ◦ Elle est plus riche que AWT/Swing SWING Les Fenêtres JWindow ◦ Conteneur que vous pouvez afficher sur votre écran Jframe ◦ Fenêtre destinée à être la fenêtre principale de votre application JDialog ◦ Fenêtre destinée aux boîtes de dialogue Lancer un message d’avertissement Entrer les données Note the JoptionPane example(JavaApplication1/JButton7) . showConfirmDialog . showMessageDialog . showInputDialog . showOptionDialog JFrame import javax.swing.JFrame; public class SimpleFenetre extends JFrame{ public SimpleFenetre(){ super(); build();//On initialise notre fenêtre } private void build(){ setTitle("Ma première fenêtre"); //On donne un titre à l'application setSize(320,240); //On donne une taille à notre fenêtre setLocationRelativeTo(null); //On centre la fenêtre sur l'écran setResizable(false); //On interdit la redimensionnement de la fenêtre setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //On dit à l'application de se fermer lors du clic sur la croix } } Les Fenêtres JDialog ◦ Fenêtre destinée aux boîtes de dialogue . showConfirmDialog int rep=jOptionPane1.showConfirmDialog(this, "Cont O/N:Presss Escape or Close for Cancel", "My_title", jOptionPane1.CLOSED_OPTION); //0 si OK, -1 si ESCAPE or CLOSE System.out.println("reponse="+rep); Les Fenêtres JDialog ◦ Fenêtre destinée aux boîtes de dialogue . showMessageDialog jOptionPane1.showMessageDialog(this, "Eggs are not supposed to be green.", "Inane warning", jOptionPane1.WARNING_MESSAGE); Les Fenêtres JDialog ◦ Fenêtre destinée aux boîtes de dialogue . showOptionDialog Object[] options = {"Yes, please", "No, thanks", "No eggs, no ham!"}; int n = jOptionPane1.showOptionDialog(this, "Would you like some green eggs to go « + "with that ham?", "A Silly Question", jOptionPane1.YES_NO_CANCEL_OPTION, jOptionPane1.QUESTION_MESSAGE, null, options, options[2]); System.out.println("n=" + n + "!"); Les Fenêtres JDialog ◦ Fenêtre destinée aux boîtes de dialogue . showInputDialog Object[] possibilities = {"ham", "spam", "yam"}; //possibilities=null; String s = (String)jOptionPane1.showInputDialog( this, "Complete the sentence:\n« + "\"Green eggs and...\"", "Customized Dialog", jOptionPane1.WARNING_MESSAGE, null, possibilities, "ham"); //If a string was returned if ((s != null) && (s.length() > 0)) { System.out.println("Green eggs and... " + s + "!");} Positionnement des composants Les Layouts ◦ ◦ ◦ ◦ ◦ ◦ BorderLayout GridLayout FlowLayout CardLayout Boxlayout Etc. BorderLayout Divise ses composants en 5 régions : nord, sud, ouest, est, et centre. "nord" et "sud" occupent toute la largeur de la partie réservée à nord ou sud, "ouest" et "est" occupent toute la hauteur qui reste de la partie réservée à ouest et est, Centre" occupe la place restante. BorderLayout Demo: JavaApplication1\NewJFrame1 BorderLayout main_layout=new BorderLayout(5,5); this.setLayout(main_layout); (this=mainFrame) Panel p1=new Panel(); this.add(p1, BorderLayout._____) north, center, south, west, east) p1.setLayout( A layout for p1) GridLayout ◦ Composants sur une grille, ligne par ligne (dans l'ordre d'adjonction), ◦ Les cellules ont la même taille, ◦ à la retaille, les cellules se taillent, ◦ hgap et vgap sont nuls par défaut. ◦ Demo:JavaApplication1\NewJFrame FrameGridLayout 5 lignes 0 colonne Jpanels dans Jframe Jpanels GridLayout 2 lignes 0 colonne GridLayout(int lignes, int cols, int hgap, int vgap) GridLayout(int lignes, int cols) FlowLayout FlowLayout est le gestionnaire par défaut des Panel. Affiche les composants de la gauche vers la droite, et passe à la ligne s'il n'y a plus de place. FlowLayout(int align, int hgap, int vgap) FlowLayout(int align) FlowLayout() e.g. FlowLayout fl=new FlowLayout(FlowLayout.center,0,2) FlowLayout CardLayout CardLayout BoxLayout BoxLayout BoxLayout BoxLayout BoxLayout BoxLayout public class Frame1 extends JFrame{ public Frame1() { super(); this.setTitle("Ma premiere application"); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setLocationRelativeTo(null); BorderLayout bLayout= new BorderLayout(); this.getContentPane().setLayout(bLayout); JPanel buttonsPanel = new JPanel(); JPanel textPanel = new JPanel(); JLabel label = new JLabel("Nom: "); JTextField textField = new JTextField(20); JButton btok = new JButton("ok"); textPanel.add(label); textPanel.add(textField); buttonsPanel.add(btok); this.getContentPane().add(buttonsPanel, BorderLayout.SOUTH); this.getContentPane().add(textPanel, BorderLayout.CENTER); this.pack(); this.setVisible(true); } } La méthode main public static void main (String args[]) { Frame1 frame = new Frame1(); } Exercice Développez le code qui permet d’afficher la fenêtre suivante JAVA ET EVÉNEMENTS Que se passe-t-il lors d'un clic ? En java, un clic génère un événement (Un objet) import javax.swing.*; public class FenetreAvecBouton extends JFrame { private JButton unBouton; private Jpanel pane = new JPanel (); public FenetreAvecBouton (){ JButton unBouton = new JButton("Quitter"); pane.add (unBouton); setContentPane(pane); //or this.getContentPane().add(pane); } public static void main (String args []) { new FenetreAvecBouton().setVisible (true); } } Events Create the Listener: Objects of this class are public class GoHandler GoHandlers but also implements ActionListener ActionListeners { ... public void actionPerformed (ActionEvent e) { ... This method is called } automatically when the } button is clicked ... JButton go = new JButton (“Go”); go.addActionListener (new GoHandler ()); Register the Listener:This method expects an ActionListener object (GoHandler) 1643 Events L'objet événement de Java est un objet de type EventObject Tout objet de type EventObject a un attribut source qui peut être récupéré en utilisant la fonction getSource() de la class EventObject Hiérarchie des événements Qui crée ce type d'objet ? Un Thread (comme le EventDispatchingThread) dans JVM permet de récupérer les interactions de l’utilisateur avec l’application Si on clique sur un composant, ce thread crée un événement relatif à l’action réalisée en utilisant le composant comme source de l’événement Ensuite il appel le « handler » correspondant à ce composant Cependant, on ne crée pas les événements: on se contente de les gérer Explication additionnelle Qui crée ce type d'objet ? La gestion des événements Pour pouvoir gérer les événements, il faut les écouter Tout le principe de la programmation événementielle repose sur la définition des événements et des objets qui les écoutent Catégories des événements Pour chaque catégorie d’événements, il existe une interface qui doit être respectée par toute classe souhaitant recevoir cette catégorie événements. ◦ Cette interface exige que toutes les méthodes soient définies. ◦ Ces méthodes sont appelées lorsque des événements particuliers surviennent. Catégories des événements Qu’est ce qu’un écouteur Le diapo précédent indique que à chaque catégorie une interface est associée Un écouteur est un objet destiné à recevoir et à gérer une catégorie d’ événement générés par le système N'importe quel objet peut devenir un écouteur du moment qu’il implémente les méthodes définies dans l'interface. Ecouteurs Par défaut, un écouteur ne récupère pas tous les événements produits par le système Il n'écoute que les objets qu'on lui dit d'écouter ! Donc, Il doit être associé à un objet qui génère des événements Ainsi, les objets qui génèrent des événements possèdent des méthodes qui permettent de leur associer des écouteurs Ajout d’écouteurs Pour ajouter un écouteur à un composant : ◦ addActionListener JButton, JCheckBox, JComboBox, JTextField et JRadioButton. ◦ addAdjustementListener JScrollBar ◦ addFocusListener tous les composants. ◦ addItemListener JCheckBox, JRadioButton et JComboBox. ◦ addKeyListener JTextField ,… saisie de texte au clavier. ◦ addMouseListener, addMouseMotionListener tous les composants. Résumé Une même catégorie peut être utilisée avec plusieurs objet, et un objet peut avoir plusieurs catégories Les méthodes de l’interface correspondent aux différents événements supportés par cette catégorie Le nom de la catégorie d’un événement est généralement utilisé avec ◦ L’interface de l’écouteur du l’objet ◦ Les méthodes de l’écouteur et leur événement passé en paramètre ◦ La méthode de l’objet utilisée pour ajouter l’ écouteur à cet objet Par exemple à la catégorie d’ événement Action correspond ◦ L’interface ActionListener ◦ La méthode ActionPerformed et l’ événement ActionEvent en paramètre ◦ La méthode addActionListener Résumé Le eventdispatcher contrôle les événements amorcés à partir de l’interface graphique Les correspond à leurs objets sources Il Crée les événements catégories correspondants Si des écouteurs sont déclarés pour ces evenements et enregistrés avec les objets sources alors le eventdiapatcher appelle les méthodes correspondantes de l’écouteur tout en lui passant l’événement catégorie afin de répondre à l’événement import javax.swing.*; import java.awt.event.*; public class FenetreAvecBouton extends JFrame implements ActionListener { private JButton unBouton; public FenetreAvecBouton (){ Jpanel pane = new JPanel (); JButton unBouton = new JButton("Quitter"); pane.add (unBouton); setContentPane(pane); } public void actionPerformed (ActionEvent e) { System.exit (0); } … } import javax.swing.*; import java.awt.event.*; public class FenetreAvecBouton extends JFrame implements ActionListener { private JButton unBouton; public FenetreAvecBouton (){ Jpanel pane = new JPanel (); JButton unBouton = new JButton("Quitter"); pane.add (unBouton); unBouton.addActionListener(this); setContentPane(pane); } public void actionPerformed (ActionEvent e) { System.exit (0); } … } Le code présenté précédemment est déconseillé Correction Il s’agit en effet de séparer les interfaces graphiques des événements récepteurs import javax.swing.*; import java.awt.event.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JOptionPane; public class MonEvent implements ActionListener { public void actionPerformed(ActionEvent e) { JOptionPane.showMessageDialog(null, "Test "); } } public class FenetreAvecBouton extends JFrame { MonEvent event = new MonEvent(); private JButton unBouton; public FenetreAvecBouton (){ Jpanel pane = new JPanel (); JButton unBouton = new JButton("Quitter"); pane.add (unBouton); unBouton.addActionListener(event); setContentPane(pane); } … } import javax.swing.*; import java.awt.event.*; Ou encore… public class FenetreAvecBouton extends JFrame { MonEvent event = new MonEvent(); private JButton unBouton; public FenetreAvecBouton (){ Jpanel pane = new JPanel (); JButton unBouton = new JButton("Quitter"); pane.add (unBouton); unBouton.addActionListener(event); setContentPane(pane); } class MonEvent implements ActionListener { public void actionPerformed(ActionEvent e) { getContentPane().setBackground(Color.red); } } } Inner Class A la possibilité d’accéder aux attributs de la classe principale Ou encore… import javax.swing.*; import java.awt.event.*; public class FenetreAvecBouton extends JFrame { private JButton unBouton; public FenetreAvecBouton (){ Jpanel pane = new JPanel (); JButton unBouton = new JButton("Quitter"); pane.add (unBouton); unBouton.addActionListener(event); setContentPane(pane); } ActionListener event= new ActionListener { public void actionPerformed(ActionEvent e) { getContentPane().setBackground(Color.red); } } } Exercice Comment faire un écouteur pour 2 objets Solution import javax.swing.*; import java.awt.event.*; public class FenetreAvecDeuxBouton extends JFrame { MonEvent event = new MonEvent(); private JButton btOk = new JButton(" ok" ); private JButton btCancel = new Jbutton("Cancel"); public FenetreAvecDeuxBouton (){ Jpanel pane = new JPanel (); pane.add (btOk ); pane.add (btCancel); btOK.addActionListener(event); btCancel.addActionListener(event); setContentPane(pane); } … } Solution import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JOptionPane; public class MonEvent implements ActionListener { public void actionPerformed(ActionEvent e) { JButton b = (JButton)e.getSource(); if(e.getActionCommand().equals("ok")){ … } else if(e.getActionCommand().equals("Cancel")) { …. } } } Les événements souris interface MouseListener{ void mouseClicked(MouseEvent e); void mouseEntered(MouseEvent e); void mouseExited(MouseEvent e); void mousePressed(MouseEvent e); void mouseReleased(MouseEvent e); } Quelques fonctions intéressantes de MouseEvent: Point getPoint() Retourne les coordonnées de la souris lors de la génération de l'événement. int getX() Retourne la coordonnée en X de la souris lors de la génération de l'événement. int getY() Retourne la coordonnée en Y de la souris lors de la génération de l'événement. Exemple import java.awt.event.MouseEvent; import java.awt.event.MouseListener; public class MonMouseListener implements MouseListener{ public void mouseClicked(MouseEvent e) { System.out.println("X: "+e.getX()+" Y: "+e.getY()); } public void mousePressed(MouseEvent e) { } public void mouseReleased(MouseEvent e) { } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { } } Exercise Demo: JavaApplication1 Développez une application qui permet de récupérer et afficher les coordonnées de la souris en passant en dessus d’une fenêtre INITIATION POO EN JAVA Pour commencer… Se poser les bonnes questions ◦ Quelles sont les objets qui interviennent dans le problème? ◦ Quelles sont les données, les objets, que le programme va manipuler? ◦ Quelles vont être les relations entre ces objets? Quelles sont les opérations que je vais pouvoir effectuer sur ces objets? 69 Concevoir un modèle UML Avant de construire un bâtiment il nous faut le plan En programmation objet il faut élaborer le schéma UML avant de commencer le codage QUELQUES DÉFINITIONS… Objets Un objet représente un concept, une idée ou toute entité du monde physique Un objet est une structure qui regroupe des données (attributs) et les moyens de traiter ces données (des fonctions que l'on appelle "méthodes" en POO) ◦ Un fichier est un objet. cet objet existe, on peut l'utiliser ◦ La voiture est un objet ◦ Un conducteur est un objet ◦ Un gâteau est un objet Caractéristiques d’un objet… Les caractéristiques qui représentent un objet ◦ Une voiture est caractérisée par une couleur, un type, marque, un numéro de châssis, un moteur, vitesse, etc. ◦ Un conducteur a un nom, sexe, nationalité, etc. ◦ Un gâteau a un type (forêt noire, forêt blanche, etc.), poids, etc. Classes… Une classe est un modèle de données ◦ famille d'objets, ou encore moule à objets ◦ tous les objets d’une même classe partagent les mêmes attributs et les mêmes méthodes Une instance de la classe voiture serait par exemple un objet de ◦ ◦ ◦ ◦ marque "Renault", modèle "Clio", couleur "rouge" vitesse 0 Classes… le mot clé class permet de déclarer une classe d'objet. UML Java Nom de la classe Attributs de la classe Méthodes de la classe public class Voiture { //code de la classe } Attributs d’une classe Les attributs d'une classe sont des variables (ou des constantes) décrivant les caractéristiques de l'objet Elles composent le type Elles caractérisent l'objet Variables d’une classe UML Java Type texte Type entier public class Voiture { private String marque = "bmw"; private int vitesse= 10; } Types: texte, entier, réel, booléen, etc. Méthodes d’une classe Représentent les moyens de traiter les attributs et les données d’un objet Elles peuvent posséder des paramètres. Elles peuvent éventuellement renvoyer une valeur public [or private] returnType methodName (type1 name1, ..., typeN nameN) { ... } Méthodes d’une classe Par exemple, si on souhaite arrêter une voiture en marche, il suffit d’utiliser une méthode freiner() qui permet d’associer à l’attribut vitesse la valeur 0 UML class Voiture { private String marque = "bmw"; private int vitesse= 10; public int freiner() { this .vitesse = 0; return this.vitesse; Retourne une variable de type entier } } Méthodes d’une classe Passage de paramètres à une fonction double u = 3, v = -4; ... Polynomial p = new Polynomial (1.0, -(u + v), u * v); double y = p.getValue (2 * v - u); public class Polynomial { public Polynomial (double a, double b, double c) { ... } public double getValue (double x) { ... } ... Méthodes d’une classe Passage de paramètres à une fonction ◦ Les données de types primitives sont toujours passées par valeur double x = 3.0; double y = p.getValue ( x ); x: 3.0 public class Polynomial { copy ... public double getValue (double u) { double v; u acts like a ... local variable } in getValue } copy u: 3.0 Méthodes d’une classe Passage de paramètres à une fonction ◦ Les objets sont toujours passées par référence Fraction f1 = new Fraction (1, 2); Fraction f2 = new Fraction (5, 17); public class Fraction { ... Fraction f3 = f1.add (f2); refers to A Fraction object: num = 5 denom = 17 public Fraction add (Fraction f) { ... } refers to the } same object Méthodes d’une classe Une méthode peut avoir plusieurs instruction return public someType myMethod (...) { ... if (...) return <expression1>; else if (...) return <expression2>; ... return <expression3>; } Méthodes d’une classe Une méthode booléenne peut retourner true/false ou bien le résultat d’une expression booléenne public boolean myMethod (...) { ... if (...) return true; ... return n % 2 == 0; } Méthodes d’une classe Une méthode de type void peut utiliser l’instruction return pour quitter la méthode public void myMethod (...) { ... if (...) return; ... No need for a } redundant return at the end Constructeur d’une classe Le rôle du constructeur est de déclarer et de permettre d'initialiser les données membres de la classe Le constructeur est appelé automatiquement quand on crée un objet. Un constructeur se définit comme une méthode standard, mais ne renvoie aucune valeur. Tous les noms des constructeurs ont le même nom de la classe Si une classe possède plusieurs constructeurs, ces derniers doivent avoir différent nombre et/ou différent types de paramètres Java affecte par défaut à une classe ayant aucun constructeur, le constructeur vide. Constructeur d’une classe Java UML class Voiture { private String marque = ""; private int vitesse= 0; public Voiture(String m, int v) { this.vitesse=v; this.marque = m; } … } Constructeur d’une classe Les constructeurs d’une même classe peuvent appeler l’un l’autre en utilisant le verbe « this » class Voiture { private String marque = ""; private int vitesse= 0; public Voiture(String m, int v) { this(100); } public Voiture(int v) { vitesse=v; } … } Constructeur d’une classe Les constructeurs sont invoqués en utilisant l’operateur new Fraction Fraction Fraction Fraction f1 = new Fraction ( ); f2 = new Fraction (5); f3 = new Fraction (4, 6); f4 = new Fraction (f3); public class Fraction { public Fraction (int n) { num = n; denom = 1; } ... Etude de Cas (A faire…) Elaborer en UML et Java la classe qui représente les gâteaux Attributs ◦ poids ◦ type ◦ bon 2 Constructeurs ◦ Premier, sert à initialiser les attributs à Poids: 100 type: forêt noire bon: TRUE ◦ Second; prend trois paramètres pour charger les attributs Poids type bon Méthodes ◦ BienPreparé retourne la valeur de l’attribut bon ◦ ModifieType Prend le nouveau type en paramètre et modifie la valeur de l’attribut type Solution Java class Gateau { private String type= ""; private int poids= 0; private boolean bon=true; UML public Gateau() { this.poids=100; this.type= forêt noire; this.bon= bon ; } public Gateau(String type, boolean bon, int poids) { this.poids=poids; this.type=type; this.bon= bon ; } public boolean bienPreparé() { return this .bon; } public void modifiéType ( String nouveauType) { this.type = nouveauType; } } Instanciation Créer un objet se fait en "instanciant" une classe. Quand on instancie une classe, on crée une version de l'objet ayant des caractéristiques propres Instanciation Fraction f1 = new Fraction(3,7); Fraction f2 = f1; f1 A Fraction object: f2 num = 3 denom = 7 Refere au meme objet Fraction f1 = new Fraction(3,7); Fraction f2 = new Fraction(3,7); f1 A Fraction object: num = 3 denom = 7 f2 A Fraction object: num = 3 denom = 7 993 Visibilité de données publique: les fonctions de toutes les classes peuvent accéder aux données ou aux méthodes d'une classe définie avec le niveau de visibilité public. Il s'agit du plus bas niveau de protection des données protégée: l'accès aux données est réservé aux fonctions des classes héritières, c'est-à-dire par les fonctions membres de la classe ainsi que des classes dérivées privée: l'accès aux données est limité aux méthodes de la classe elle-même. Il s'agit du niveau de protection des données le plus élevé Encapsulation Les attributs et les méthodes d'un objet qui constituent sa structure interne ne sont en général pas accessibles aux autres objets, c'est le principe de l'encapsulation Par exemple, pour pouvoir modifier la couleur d'une voiture, il faudra lui ajouter une méthode publique, changerCouleur, qui s'occupera de changer la valeur de son attribut couleur Les autres objets n'ont ainsi plus besoin de savoir comment changer la couleur de la voiture, ils se contentent d'appeler la méthode changerCouleur Encapsulation public class MyClass { // Private fields: private <sometype> myField; ... // Constructors: public MyClass (...) { ... } ... // Public methods: public <sometype> myMethod (...) { ... } ... // Private methods: private <sometype> myMethod (...) { ... } ... } Public interface: public constructors and methods Encapsulation: Exemple On souhaite incrémenter l’attribut useCount d’une manière sécurisée Accès statique: Attribut statique Un attribut statique est partagée à travers tous les objets de la même classe ◦ Si vous avez à utiliser une même variable à travers plusieurs objets, vous pouvez la déclarer statique class Voiture { public static int roues = 4; … } Voiture v1=new Voiture() v1.roues=4 Voiture v2=new Voiture() //4 System.out.println(v2.roues); V2.roues=10; Voiture v3=new Voiture(); //10 System.out.println(v3.roues); Accès statiques: Attribut statique On peut l’appeler directement via la classe sans instanciation Exemple Voiture.roues=4 Voiture v2=new Voiture() //4 System.out.println(v2.roues); Voiture.roues=14 Voiture v3=new Voiture(); //14 System.out.println(v3.roues); //14 System.out.println(v2.roues); Accès statiques: Méthode statique Les méthodes statiques manipulent seulement les attributs statiques de leur classe Les méthodes statiques ne peuvent plus manipuler les attributs non statiques, et, ne peuvent appeler que des méthodes statiques Sont appelées sans instanciation ◦ Exemple d’appelle des méthodes statiques double x = Math.random(); double y = Math.sqrt (x); System.exit(); Accès statiques: Méthode statique Un autre exemple public class MyClass { public static final int statConst; private static int statVar; private int instVar; ... public static int statMethod(...) { statVar = statConst; OK statMethod2(...); instVar = ...; instMethod(...); } Errors! Static method Accès statiques: Remarque Pas besoin de créer une instance sur une classe ayant tous ses attributs et/ou méthodes statiques Les classes Math et System sont des exemples double x = Math.random(); double y = Math.sqrt (x); System.exit(); Méthode non statique Pour accéder aux méthodes non statiques il est nécessaire de créer une instance sur la classe Les méthodes non statiques peuvent accéder aux attributs et méthodes statiques et non statiques A faire… Elaborer une classe Forme Créez deux instances différentes de la classe forme et comparez les en utilisant la méthode comparerForme Héritage Souvent, vous aurez besoin d'une classe avec des méthodes et fonctions similaires à une autre classe Il est bon de définir des classes génériques, qui pourront être réutilisées et adaptées à tous vos projets Pour faciliter cela, une classe peut être une extension d'une autre classe. Héritage La classe dérivée hérite alors toutes les méthodes et variables de la classe parent La classe dérivée que nous appelons fille peut définir ses propres fonctions et variables, qui s'ajouteront Une classe ne peut hériter que d'une seule autre classe, et l'héritage multiple n'est pas supporté Les héritages se font avec le mot clé ' extends '. Héritage Le principe d’héritage permet la réutilisabilité et l'adaptabilité des objets ◦ Classes filles qui héritent des caractéristiques (attributs et méthodes) d'une classe mère ◦ Les classes filles peuvent également définir leurs propres caractéristiques. Le principe d’héritage réduit la duplication d’un même code tout en l’écrivant dans la classe mère Héritage UML Lien d’héritage Héritage Java UML class Vehicule { protected String marque = ""; public void avance() { //code qui fait avancer le véhicule } public void freine() { //code qui fait freiner le véhicule } } Héritage Java UML class Voiture extends Vehicule { private int porte=4; public int nbrPortes() { //retourne nbrPortes } } la classe voiture possède un attribut marque par héritage, un attribut porte, une méthode freine et une méthode avance par héritage et une méthode nbrPortes() Héritage java UML class Camion extends Vehicule { private int Remorque=40; public int volumeRemorque() { //retourne volumeRemroque } } la classe Camion possède un attribut Remorque et une méthode volumeRemorque, ainsi qu’ un attribut marque, une méthode freine et une méthode avance par héritage Etude de Cas Elaborez les classes suivantes Héritage Redéfinition de méthode Les méthodes hérités peuvent être réécrites dans la classe fille class Vehicule { protected String marque = ""; public void avance() { //code qui fait avancer le véhicule } public void freine() { //code qui fait freiner le véhicule } } class Voiture extends Vehicule { public void avance() { //code qui fait avancer la voiture } public void freine() { //code qui fait freiner la voiture } } Contrôle d’accès héritage Les accès aux attributs et méthodes sont redéfinissables dans les classes filles pourvu que la directive soit identique ou plus large ◦ Une méthode protégée peut être redéfinie comme protégée ou publique dans une classe fille. ◦ Une méthode publique ne peut être que publique dans une classe fille. Contrôle d’accès héritage Appel des constructeurs d’une super classe En utilisant super, et ceci seulement à partir d’un constructeur Biped Walker public class Walker extends Biped { // Constructor public Walker(int x, int y, Image leftPic, Image rightPic) { Calls Biped’s super(x, y, leftPic, rightPic); constructor ... } The number / types of parameters passed to } super must match parameters of one of the If present, must be the first statement superclass’s constructors. Contrôle d’accès héritage Appel des constructeurs d’une super classe ◦ Il est conseillable d’ajouter toujours un constructeur vide dans les classes et ceci afin d’éviter des erreurs de compilation en cas d’ héritage ◦ Par exemple l’écriture suivante est erronée et peut generer l’ erreur suivante: syntax error: cannot find symbol : constructor ... public class NewClass { public NewClass(int a) { } void f0() { } } public class NewClass2 extends NewClass { void f1() { System.out.println("hello") } } Contrôle d’accès héritage Appel des constructeurs d’une super classe ◦ Alors elle sera juste en ajoutant le constructeur par défaut à NewClass1 public class NewClass1 { public class NewClass2 extends NewClass 1 { public NewClass() { } } public NewClass1(int a) { } void f0() { } } void f1() { System.out.println("hello") } Contrôle d’accès héritage Appel des constructeurs d’une super classe Conclusion: ◦ Pour bien faire fonctionner le code en présence de plusieurs constructeurs dans une hiérarchie de classes, essayer toujours de mentionner explicitement le constructeur par défaut (sans argument) dans l’hiérarchie. Contrôle d’accès héritage Appel des méthodes de la classe supérieur Walker CharlieChaplin public class CharlieChaplin extends Walker { ... public void nextStep () { turnFeetIn(); Calls Walker’s super.nextStep(); nextStep turnFeetOut(); } ... super.someMethod refers to someMethod in } the nearest class, up the inheritance line, where someMethod is defined. Contrôle d’accès héritage Les appels super sont fréquemment utilisés dans les sous classes d’un classe librairie. public class Canvas extends JPanel { ... public void paintComponent (Graphics g) { super.paintComponent (g); ... } ... Contrôle d’accès héritage En Java toutes les classes étendent par défaut la classe Object, une classe concrète et non plus abstraite public class Object { public String toString {...} public boolean equals (Object other) {... } public int hashCode() { ... } // a few other methods ... } POLYMORPHISME Polymorphisme Polymorphisme vient du grec et signifie "multiforme " Il y a 3 types de polymorphisme en POO ◦ Polymorphisme de classe ◦ Polymorphisme d’héritage ◦ Polymorphisme paramétrique Polymorphisme de classe Une donnée membre ou une méthode de deux classes différentes peuvent avoir le même nom, et le langage saura faire la différence. class A { public void lire(String fichier_texte) { // lit le fichier texte } } class B { public void lire(String chaine_sql) { // fait une requête SQL dans la base } } Polymorphisme d’héritage Une même donnée ou une même méthode peut être redéfinie dans une classe dérivée Ca sera cette donnée ou méthode que l’objet instancié de la classe dérivée utilisera Exemple class Personne { private String prenom; private String nom; public Personne(String prenom, String nom) { this.prenom = prenom; this.nom = nom; } Héritage public String info() { return this.prenom +” “this.nom; } } class Pirate extends Personne { private String bateau; Public Pirate(String prenom, String Redéfinition nom){super(prenom, nom);} public String info() { return "pirate “+this.prenom + “ ”+this.nom; }} Polymorphisme paramétrique Il permet de définir plusieurs constructeurs/méthodes qui diffèrent en fonction du type et/ou du nombre d’arguments Polymorphisme paramétrique class A { private String nom; public A() { this.nom= « JaneDoe » } public A(String nom, String prenom) { this.nom= nom; this.prenom; } } Polymorphisme Poly. D’héritage: exemple Les méthodes de la classe Biper sont redéfinies dans les sous classes Biped Walker The actual parameter passed to this method can be a Walker, a Hopper, etc. any subclass of Biped. public void moveAcross (Biped creature, int distance) { creature.firstStep(); while (creature.distanceTraveled () < distance) creature.nextStep(); creature.stop(); } Correct methods will be called automatically for any specific type of creature: Walker’s methods for Walker, Hopper’s for Hopper, etc. ABSTRACT … Méthodes abstraites Une méthode abstraite ne doit pas avoir d’implémentation Elle est indiquée avec le mot-clé abstract. public abstract int périmètre(); Classe abstraite Une classe contenant une ou plusieurs méthodes abstraites doit être elle-même déclarée abstraite Ne peut être instanciée : c’est à dire qu’on ne peut pas créer d’objet basé sur une classe abstraite Noter qu’une classe abstraite peut contenir des méthodes avec leur code abstract class Forme { … } public abstract class Biped { ... public abstract void firstStep(); public abstract void nextStep(); public abstract void stop(); ... public void draw(Graphics g) { ... } } Classe abstraite Elle peut servir de classe de base à d’autres classes qui la étend (extends) Ces sous-classes devront implémenter toutes les méthodes abstraites de la superclasse Sinon il faut déclarer ces classes abstraites ◦ On forme alors une hiérarchie de classes abstraites En utilisant l’abstraction, un compilateur peut détecter des erreurs additionnelles Elle est utilisée de la même manière dans le Polymorphisme Elle peut contenir des constructeurs qui peuvent être appelés par les sous classes Préférable d’avoir un constructeur vide Exemple Italic = Abstract Développez l’exemple ci-dessus INTERFACE Interface Spécifie quelles méthodes et variables une classe peut implémenter, sans avoir à définir comment ces méthodes seront gérées Non instanciable Seules les signatures des méthodes d’une interface sont déclarées (pas d’implémentation) Toutes les méthodes de l'interface doivent être implémentées Les classes peuvent implémenter plus d'une interface en séparant chaque interface par une virgule Interface Une Interface est similaire à une classe abstraite mais pas d’attributs et de constructeurs, ainsi que toutes ses méthodes sont abstraites par défaut. Une classe qui implémente une interface doit fournir toutes les méthodes de l’interface. Une Interface peut être définit comme suit: ◦ interface InterfaceName { constant definitions method declarations (without implementations) } Exemples: Interface Mais public static final pour les constantes ainsi que public pour les méthodes sont considérés par défaut, alors l’exemple précédent peut être écrit comme suit: Interface interface peutAvancer { public void avancer(); public void freiner(); } interface peutTourner { public void tourneGauche(); Méthodes sans code public void tourneDroite(); } Interface public interface Dance { DanceStep getStep (int i); int getTempo (); int getBeat (int i); } public class Waltz implements Dance { // Methods: public DanceStep getStep (int i) { ... } public int getTempo () { return 750; } public int getBeat (int i) { ... } } L’ecriture suivante est possible: Dance d = new Waltz( ); Interface Alors Le polymorphisme peut être géré par les interfaces public interface Edible { String getFoodGroup(); int getCaloriesPerServing(); } public class Pancake implements Edible { ... } public class Breakfast Polymorphism: { the correct private int myTotalCalories = 0; method is called ... for any specific public void eat (Edible obj, int servings) type of Edible, { e.g., a Pancake myTotalCalories += obj.getCaloriesPerServing () * servings; } } Abstract VS interface Aucun code n’est présent dans une interface ◦ Une interface est donc une classe abstraite qui ne contiendrait que des méthodes abstraites ◦ Une classe ne peut dériver que d’une classe abstraite mais peut implémenter plusieurs interfaces Mot clé Final Une méthode ou une classe est finale, si elle est précédée du mot-clé final Elle ne peuvent plus redéfinit et hérité respectivement Redéfinition class BaseClass { public void test() { System.out.println("test() appelé "); } final public void moreTesting() { System.out.println("moreTesting() appelé"); } } class ChildClass extends BaseClass { public void moreTesting() { System.out.println("moreTesting() appelé dans Child Class"); } } Fatal error: Cannot override final method BaseClass::moreTesting() TD POO Etude de cas 1 On souhaite simuler une gestion de location de véhicules. ◦ Un véhicule est caractérisé par un numéro d'immatriculation, un kilométrage, un modèle et une marque. (Classe abstraite) ◦ Fonction: avancer, reculer, toString. ◦ Parmi les véhicules on distingue les véhicules utilitaires les voitures Les motos ◦ Client (Caractérisé par son nom, prénom, date de naissance) qui loue un véhicule et le conduit UML Etude de cas 2 Modifiez l’étude de cas précédent afin d’ajouter ◦ L’attribut nbPersonnes à la classe Moto ◦ L’attribut nbPortes à la classe Voiture ◦ L’attribut poids à la classe Utilitaire Les attributs doivent être initialisés par le constructeur Redéfinissez la méthode toString dans chaque classe afin d’afficher les détails correspondants Etude de cas 3 Ajoutez la classe VoitureDeSport qui étend la classe Voiture Une voiture de sport a deux portes par défaut Faites les modifications nécessaires en fonction du diagramme ci-dessous JAVA ET LES BASES DE DONNÉES Introduction En java, l’api JDBC (Java DataBase Connectivity) permet de gérer les connexions à une base de données. En réalité, JDBC permet aux programmeurs Java d’écrire un code indépendant de la base de données et du moyen de connexion utilisé JDBC ? Un package (java.sql.*) contenant ◦ un ensemble de classes et d’interfaces pour écrire des requêtes destinées aux SGBD (SQL) Il sert a ◦ Créer des connexions à une base distante ◦ Gérer la création et l'exécution de requêtes SQL ◦ Récupérer et traiter les résultats JDBC General Architecture Interfaces JDBC 8 interfaces : ◦ Connection (created from the DriverManager) ◦ Statement,CallableStatement, PreparedStatement (created from the connection) ◦ ResultSet Created from the statements ◦ DatabaseMetaData, ResultSetMetaData ◦ Driver Interface OJDBC ◦ OraclePreparedStatement, OracleResultSet ◦ … Procédure d’une connexion à une base de données Importer le package java.sql Enregistrer le driver JDBC Etablir la connexion au SGBD Créer une requête (ou instruction SQL) Exécuter la requête Traiter les données retournées Fermer la connexion 1 - Enregistrer un pilote Pour qu'un driver soit disponible, il faut charger sa classe en mémoire en utilisant: ◦ Class.forName("driverName") Class.forName("oracle.jdbc.driver.OracleDriver"); ◦ DriverManager.registerDriver(instance de driver); DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver()) 1- Enregistrer un pilote(exemples) Access database ◦ Class.forName(“sun.jdbc.odbc.JdbcOdbcDrive r"); Microsoft SQL Server ◦ Class.forName(“com.microsoft.sqlserver.jdbc. SQLServerDriver"); Mysql ◦ Class.forName(“com.mysql.jdbc.Driver"); 2 – Etablir une connexion On utilise la méthode getConnection() de DriverManager 3 arguments : ◦ l’URL de la base de données ◦ le nom de l’utilisateur de la base ◦ son mot de passe Connection conn = DriverManager.getConnection(url, user, password); 2 – Etablir une connexion le DriverManager essaye tous les drivers enregistrés (chargés en mémoire avec Class.forName()) jusqu’à ce qu’il trouve un driver qui lui fournisse une connexion Le chemin de la base depend de la base en question URL="jdbc:oracle:thin:@computer_name:1521:oracleinstance” 2 – Etablir une connexion MS Access ◦ String chemin= "jdbc:odbc:Driver={Microsoft Access Driver (*.mdb)};DBQ= c:\\XmlDB "; Microsoft SQL Server ◦ String chemin= "jdbc:sqlserver://Computername;" + databaseName=DBname;user=usename;password=passn ame"; Mysql ◦ String chemin= "jdbc:mysql://Computername:port/dbname"; 3- Creation d’un Statement Statement: permet d’exécuter requêtes SQL 3 types de Statement : ◦ Statement : requêtes statiques simples ◦ PreparedStatement : requêtes dynamiques précompilées (avec paramètres d’entrée/sortie) ◦ CallableStatement : procédures stockées des 3- Creation d’un Statement La création d’un statement s’effectue a partir de l’instance de connexion déjà créée Statement req1 = conn.createStatement(); PreparedStatement req2 = conn.prepareStatement(str); CallableStatement req3 = conn.prepareCall(str); Str est une requête SQL 4- Execution de la requête 3 types d’exécution pour le statement ◦ Consultation (requêtes de type SELECT) executeQuery() : retourne un ResultSet (n-uplets résultants) ◦ Modification (requêtes de type INSERT, UPDATE, DELETE, CREATE TABLE, DROP TABLE) executeUpdate() : retourne un entier (nombre de nuplets traités) ◦ Exécuter des requêtes qlq, procédures stockées, retour de plusieurs ensemble de résultats (plusieurs ResultSet) execute() 5 - Traiter le résultat ResultSet de executeQuery() ◦ executeQuery() renvoie une instance de ResultSet qui permet d’accéder aux champs des n-uplets sélectionnés ◦ seules les données demandées sont transférées en mémoire par le driver JDBC ◦ il faut donc les lire "manuellement" et les stocker dans des variables pour un usage ultérieur Exemple public void connect (String host, String user, String pass) { //enregistrer le pilote DriverManager.registerDriver(new oracle.jdbc.OracleDriver()); //creer la connexion Connection conn = DriverManager.getConnection( "jdbc:oracle:thin:@ " +host +" :1521:nomdb", user, pass); //creer un Statement Statement stmt = conn.createStatement(); //execution de la requete ResultSet res = stmt.executeQuery(“Select nom, prenom from user”); … } 5 - Traiter le résultat Méthode next() de ResultSet ◦ retourne false si dernier tuple lu, true sinon ◦ un appel fait avancer le curseur sur le tuple suivant ◦ au départ, le curseur est positionné avant le premier tuple ◦ exécuter next() au moins une fois pour avoir le premier 5 - Traiter le résultat Ou encore ◦ on peut parcourir le ResultSet d’avant en arrière : next() vs. previous() ◦ en déplacement absolu : aller à la n-ième ligne absolute(int row), first(), last(), ... ◦ en déplacement relatif : aller à la n-ième ligne à partir de la position courante du curseur, … relative(int row), afterLast(), beforeFirst(), ... Exemple { //enregistrer le pilote DriverManager.registerDriver(new oracle.jdbc.OracleDriver()); //creer la connexion Connection conn = DriverManager.getConnection( "jdbc:oracle:thin:@ " +host +" :1521:nomdb", user, pass); //creer un Statement Statement stmt = conn.createStatement(); //execution de la requete ResultSet res = stmt.executeQuery(“Select nom, prenom from user”); while (res.next()){ System.out.println(res.getString(1)+” ”+res.getString(2)); } } Type SQL vs. Type Java Le driver JDBC traduit le type JDBC retourné par le SGBD en un type Java correspondant le XXX de getXXX() est le nom du type Java correspondant au type JDBC attendu chaque driver a des correspondances entre les types SQL du SGBD et les types JDBC Type SQL vs. Type Java Type BDD Type Java NUMERIC, DECIMAL getBigDecimal() TINYINT getByte() DATE getDate() REAL getFloat() INTEGER getInt() DOUBLE, FLOAT getDouble() TIME getTime() CHAR,VARCHAR getString() … … Exemple – Scrollable Result Set Pour utiliser absolute et relative il faut que le resultset soit ResultSet.TYPE_SCROLL_SENSITIVE : Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); String query = “select students from class where type=‘not sleeping’ “; ResultSet rs = stmt.executeQuery( query ); … rs.previous(); / / go back in the RS (not possible in JDBC 1…) rs.relative(-5); / / go 5 records back rs.relative(7); / / go 7 records forward rs.absolute(100); / / go to 100th record … 171 Exemple – Updatable ResultSet … Statement stmt = con.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE); String query = " select students, grade from class where type=‘really listening this presentation’ “; ResultSet rs = stmt.executeQuery( query ); … while ( rs.next() ) { int grade = rs.getInt(“grade”); rs.updateInt(“grade”, grade+10); rs.updateRow(); } 172 Exemple – Delete/Update using Statement Statement stmt = conn.createStatement(); String deleteStr = "DELETE FROM Member " + "WHERE Lower(Name) = 'harry potter'"; ◦ int delnum = stmt.executeUpdate(deleteStr); String createLehigh = "Create table Lehigh " + "(SSN Integer not null, Name VARCHAR2(32), " + "Marks Integer)"; ◦ stmt.executeUpdate(createLehigh); String insertLehigh = "Insert into Lehigh values“ + "(123456789,abc,100)"; ◦ stmt.executeUpdate(insertLehigh); 173 6 – Fermeture de la connexion resultset.close() statement.close() conn.close(); Encore – Les requêtes préparées La méthode prepareStatement() de l’objet Connection crée un PreparedStatement : PreparedStatement ps = conn.prepareStatement("SELECT * FROM Clients WHERE name = ? "); •les paramètres sont spécifiés par un "?" •ils sont ensuite instanciés par les méthodes setInt(), setString(), setDate()… •ces méthodes nécessitent 2 arguments (setInt(n, valeur)) •le premier (int) indique le numéro relatif de l’argument dans la requête •le second indique la valeur à positionner •setNull(n,type) positionne le paramètre à NULL (SQL) Exemple – PreparedStatement PreparedStatement ps = conn.prepareStatement(“Select uid from user where username = ? and password = ?"); … Variable locale ps.setString(1, user); Variable locale ps.setString(2, pass); ResultSet res = ps.executeQuery(); } Exemple – PreparedStatement String queryStr = "SELECT * FROM Items " + "WHERE Name = ? and Cost < ?"; PreparedStatement pstmt = conn.prepareStatement(queryStr); pstmt.setString(1, "t-shirt"); pstmt.setInt(2, 1000); ResultSet rs = pstmt.executeQuery(); Exemple – PreparedStatement String deleteStr = “DELETE FROM Items " + "WHERE Name = ? and Cost > ?"; PreparedStatement pstmt = conn.prepareStatement(deleteStr); pstmt.setString(1, "t-shirt"); pstmt.setInt(2, 1000); int delnum = pstmt.executeUpdate(); Exemple – PreparedStatement Are these the same? What do they do? String val = "abc"; PreparedStatement pstmt = conn.prepareStatement("select * from R where A=?"); pstmt.setString(1, val); ResultSet rs = pstmt.executeQuery(); String val = "abc"; Statement stmt = conn.createStatement( ); ResultSet rs = stmt.executeQuery("select * from R where A=" + val); 179 Exercice Développez un module d’authentification qui permet d’authentifier des utilisateurs. A noter que les informations des utilisateurs sont stockées dans une table users dans la base de données oracle JAVA ET LES THREADS Introduction En java, il est possible de simuler l'exécution de plusieurs taches dans un même programme en même temps . C'est le multithreading. L'exécution de chaque tache est alors appelé un thread. Thread Un thread n’est pas un vrai objet Un thread est un flot de contrôle Un thread est une série d’instructions à exécuter Creation des Threads En Java, il existe deux méthodes pour créer des threads. ◦ Etendre la classe Thread ◦ Implémenter l’interface Runnable Etendre la classe Thread public class MonThread extends Thread { public void run () { // ici se trouve la description // du comportement du thread } public static void main ( String [] args ) { MonThread t1 = new MonThread (); t1. start (); } Implementer l’interface Runnable public class Tache implements Runnable { public void run () { // ici se trouve la description // du comportement du thread } public static void main ( String [] args ) { // on crée une tache pour un thread : Tache job = new Tache (); //Runnable job=new Tache(); Thread t1 = new Thread (job ); : t1. start (); } Les méthodes d’un Thread void start() ◦ Démarre le thread – appelle la méthode run() du thread ◦ Elle est appelée une seule fois void run() ◦ Contient les taches à exécuter par le thread void stop() ◦ Arrête le Thread ◦ A ne pas utiliser ◦ Il suffit d’arrêter le thread manuellement Par code (sortir de la fonction run()) Utilisation de la méthode interrupt(); Exemple public static void main ( String [ ] args ) { // étape 1 Runnable r = new MaTache (); Thread t = new Thread (r); t. start (); // étape 2 : une nouvelle pile est créée Chat c = new Chat (); c.start(); } Les méthodes d’un Thread void yield() ◦ Permet l’arrêt momentané du thread et sa rejointure à la queue ◦ Le/Les thread/s qui sont dans la queue et de même priorité seront exécutés void sleep(int m) ou sleep(int m, int n) ◦ Fais endormir le thread Exemple – yield() class YieldThread extends Thread { public void run() { for ( int count = 0; count < 4; count++) { System.out.println( count + "From: " + getName() ); yield(); } } } class TestYield { public static void main( String[] args ) { YieldThread first = new YieldThread(); YieldThread second = new YieldThread(); first.start(); second.start(); System.out.println( "End" ); } } Résultat End 0From: Thread-0 0From: Thread-1 1From: Thread-0 1From: Thread-1 2From: Thread-0 2From: Thread-1 3From: Thread-0 3From: Thread-1 Cycle de vie d’un thread 1. 2. 3. Le thread est nouveau. L'objet est créé mais il n'y a pas encore de file d'exécution. Thread t = new Thread (r); Le thread est exécutable. Quand vous lancez le thread, une pile est créée. Le thread attend dans la file pour que la JVM le choisisse afin de s'exécuter. t. start () ; le thread est en cours d'exécution. C'est le thread qui s'exécute, le seul. C'est l'ordonnanceur de la JVM qui décide quel thread va s'exécuter à un moment donné. Quand un thread s'exécute les autres sont en attente. A tout moment l'ordonnanceur peut arrêter l'exécution du thread (il retourne alors dans l'état Active) et en choisir un autre. Cycle de vie d’un thread new start() Active in the queue sleep(500) wake up JVM Born suspend() resume() Runnable Stop/Interrupt() wait Blocked notify Stop/Interrupt() Dead Waiting for a monitor block on I/O Acquire monitor I/O available Quel est le resultat de ce programme ? public class MaTache implements Runnable { public void run () { for ( int i = 0; i < 30; i++) { String nom = Thread . currentThread (). getName (); System .out. println (nom + "est en cours d'exécution "); } } public static void main ( String [] args ) { Runnable tache = new MaTache (); Thread a = new Thread ( tache ); a. setName (" Caroline "); Thread b = new Thread ( tache ); b. setName (" Cedric "); System.out.println("wawawawa"); a. start (); b. start (); System.out.println("laaaaaaaa"); } } Cedric est en cours d'exécution Caroline est en cours d'exécution Caroline est en cours d'exécution Caroline est en cours d'exécution Caroline est en cours d'exécution Caroline est en cours d'exécution Caroline est en cours d'exécution Caroline est en cours d'exécution Caroline est en cours d'exécution Cedric est en cours d'exécution Cedric est en cours d'exécution Caroline est en cours d'exécution Caroline est en cours d'exécution Caroline est en cours d'exécution Caroline est en cours d'exécution Caroline est en cours d'exécution Caroline est en cours d'exécution Cedric est en cours d'exécution Cedric est en cours d'exécution Cedric est en cours d'exécution Cedric est en cours d'exécution … Problème d’accès concurrent les Threads partagent les mêmes ressources (mémoire, écran, les attributs et méthodes d’un même object partagé, etc.) Dans certaines situations, il est nécessaire d’obtenir un résultat cohérent Exemple ◦ Garantir des opérations de débits et crédits synchronisées qui peuvent être interprétées, par des opérations de lectures, comme cohérentes à tout instant Transaction bancaire Reservation billets d’avion Dans certaines situations, il est nécessaire de bloquer l’ accès concurrent à un même attribut ou méthode ◦ Cas où deux thread traitent un même objet Problème d’accès concurrent L’utilisation des Threads implique de nombreux problèmes ! ◦ Accès concurrent à certains conteneurs de données (et leurs modifications) ! ◦ Protection de certaines sections pour éviter des interblocages Par exemple lorsque deux threads essayent de verrouiller alternativement deux fonctions synchronisées de deux instances différentes d’un même classe Synchronization Une solution pour résoudre à l’accès concurrent synchronized public void maMethode { // Cette méthode ne peut être exécutée de manière concurrente ... } Attention aux méthodes statiques qui sont associées aux classes. Synchroniser de telles méthodes revient a bloquer l'accès à toute la classe Les écritures suivantes sont Equivalentes public synchronized void a() { //… some code … } public void a() { synchronized (this) { //… some code … } } 198 Synchronization public class MaTache implements Runnable { public void run () { synchronized (this){ for ( int i = 0; i < 30; i++) { String nom = Thread . currentThread (). getName (); System .out. println (nom + "est en cours d'exécution "); } } } Resultat … Caroline est en cours d'exécution Caroline est en cours d'exécution Caroline est en cours d'exécution Caroline est en cours d'exécution Caroline est en cours d'exécution Caroline est en cours d'exécution Cedric est en cours d'exécution Cedric est en cours d'exécution Cedric est en cours d'exécution Cedric est en cours d'exécution Cedric est en cours d'exécution Cedric est en cours d'exécution Cedric est en cours d'exécution … Les methodes wait() et notify() wait() ◦ S’exécute dans un bloc synchronized ◦ Met le thread en exécution en attente(bloquee) jusqu’à ce qu’un autre thread crée sur le même objet exécute la méthode notify() ou notifyAll() ◦ Libère le monitor de l’objet/fonction courant(e) ◦ Wait est similaire à yield sauf que wait attend l’ exécution de notify pour remettre le thread dans la queue, l’ ordonnanceur le choisit, et le thread essaye d’acquérir le monitor pour verrouiller l’objet/la fonction. public class CubbyHole { private int contents; private boolean available = false; public synchronized void get() { if (available == false) { try { wait(); } catch (InterruptedException e) { } } available = false; System.out.println( “consume " + contents); notifyAll(); } public synchronized void put(int value) { if (available == true) { try { wait(); } catch (InterruptedException e) { } } contents = value; available = true; System.out.println( “produce: " + contents); notifyAll(); } } Applications Exemple 1 PrintThread1 a = new PrintThread1("*"); PrintThread1 b = new PrintThread1("-"); a.start(); b.start(); Applications Exemple 1 suite class PrintThread1 extends Thread { String name; public PrintThread1(String name) { this.name = name; } public void run() { for (int i=1; i<100 ; i++) { try { sleep((long)(Math.random() * 100)); } catch (InterruptedException ie) { } System.out.println(name); } } } Applications Applications Exemple 2 bankAccount b=new bankAccount(); setBalance b1=new setBalance(b,100,50); b1.start(); setBalance b2=new setBalance(b,200,100); b2.start(); setBalance b3=new setBalance(b,300,150); b3.start(); Applications Exemple 2 class bankAccount { private float debit=1000; private float credit=500; public synchronized void deposit(float amount){ debit += amount; System.out.println("db="+debit); } public synchronized void withdraw(float amount){ credit -= amount; System.out.println("cr="+credit); } } Applications Exemple 2 class setBalance extends Thread { bankAccount ba; int dp; int wd; public setBalance(bankAccount banka, int dp, int wd){ this.ba = banka; this.dp=dp; this.wd=wd; } public void run() { ba.deposit(this.dp); ba.withdraw(this.wd); } } Applications Avec synchronization db=1100.0 cr=450.0 db=1300.0 cr=350.0 db=1600.0 cr=200.0 Sans synchronization db=1100.0 cr=450.0 db=1300.0 db=1600.0 cr=300.0 cr=200.0 Avec une possibilité d’accès concurrent à une même méthode par deux thread db=1300.0 (1300) db=1600.0 (1400) Applications Exemple 3 incr c1=new incr(5); incr c2=new incr(5); c1.start(); c2.start(); Applications Exemple 3 class incr extends Thread { int n; int i=0; public incr(int k){ this.n = k; } public void run() { while (i<=n) { System.out.println(Thread.currentThread().getName()+ "i="+i); i++; try { sleep(100); } catch (InterruptedException ex) { Logger.getLogger(incr.class.getName()).log(Level.SEVERE, null, ex); } } } } Applications Compléter la notion de producteur et consommateur en utilisant la classe CubbyHole On suppose ◦ Que la fonction put() est le producteur, et que la fonction get() est le consommateur ◦ Qu’on souhaite produire et consommer 10 espèces ◦ La sortie peut être comme suit: Produce : 0 Consume: 0 Produce : 1 Consume: 1 Produce : 3 Consume: 3 … Une Introduction C SHARP Introduction Interagissant simplement avec les DB Essentiellement OO Lisible en XML et optant pour les services Web Langages .Net Tous les langages doivent se conformer au CTS(Common Type System). ◦ Tout est objet ◦ C# est très fortement typé. Plus riche que Java. ◦ Décrit les classes(visibilite, type, constructeur,…), interfaces, delegates, arrays, pointers, events, data types … ◦ Décrit deux systèmes de typage: par valeur ou par référence ◦ Assure une interopérabilité avec les autres langages Types natives définis par le CTS et communs à tous les langages .Net ◦ Type existant (int) ou type crée (enum, classe,…) ◦ Les pointeurs sont possibles mais très rarement utilisés Langages .Net Le CLS(Common Langage Specification) est une couche qui décrit largement les règles d’interopérabilité Les programmes doivent respecter un ensemble de règles pour permettre l’intégration des langages ◦ Un composant créé par un langage respectant CLS peut être utilisé par un autre langage respectant CLS Les règles définies par le standard CLS obéissent aux règles imposer par le CTS Langages .Net Les programmes sont exécutés dans le CLR(Common Langage Runtime) = machine virtuelle (à la Java): gestion sécurité et gestion mémoire. De nombreuses librairies .Net: I/O, String, Securité, Network, thread, Collections, XML + Services Web, SQL, GUI (Windows Forms). Langages .Net Plateforme .Net COMPARAISON ENTRE JAVA ET C# Java C# import java.util.ArrayList; using System.Collections; LES LIBRAIRIES Java C# System.out.println("hello world"); Console.WriteLine("hello world"); Sortie Java C# Non pas de pointeurs Existent mais rarement utilises Pointeurs Java C# Boolean ◦ boolean ◦ Bool, Boolean Entiers signés ◦ Tous les types primitifs sont signés String Boolean Entiers signés et non signés ◦ int, uint, long, ulong, etc. String, string Types Java C# Comparaison des Strings ◦ Operateur equals() ◦ Soit == soit Equals () Conversion String a Integer ◦ Integer.parseInt("3"); Passage par valeur Comparaison des Strings Conversion String a Integer ◦ int.Parse("3"); Passage par valeur et par adresse (mot clé ref ) Types Java C# for (int i : someArray) { } foreach (int i in someArray) {} Boucle foreach Java C# Heritage simple et pas d’heritage multiple ◦ class Dog extends Animal implements Comparable Mot clé super Heritage simple et pas d’heritage multiple ◦ class Dog : Animal, IComparable Mot clé base Heritage Les propriétés en C# Une propriété est un membre d'une classe permettant d'accéder ou de modifier les caractéristiques d'un objet Une propriété comprend un accesseur get qui permet de retourner une valeur et un accesseur set qui permet de modifier une valeur. Exemple class User { private int age; public int Age { get { return age; } set { age = value; } } } class Test { private User user; public Test () { user = new User(); // Set user.Age = 25; // Get int age = user.Age; // Set user.Age += 1; } } Héritage class Etudiant: Personne { public Etudiant(String nom, int age):base(nom, age) {…} } Les Tableaux String [] noms = new String[4]; int[] ia= new int[4]; String [] noms = {«John», «Denise», «Pierre», «Paul»}; int[] ia= {1, 2, 5, 7, 9, 2, 3}; noms[3] = «Isabelle»; nom.Length; Homme [] lesHommes= new Homme[]; lesHommes[0] = new Homme(); int[,] V= new int[3,3]; ◦ En JAVA: int[][] V= new int[3][3]; int[,] = {{1,1},{3,2},{4,5}}; ◦ En JAVA: int[][] v={{1,1},{3,2},{4,5}}; Exemple using System; using System.Collections; public class TestForeach { public static void Main() { ArrayList list = new ArrayList(); list.Add("John"); list.Add("Paul"); list.Add("Frank"); list.Add("Pierre"); foreach(String p in list) { Console.WriteLine(p); } } } La classe Array de System String [] s = {“ John “ ,“ Denise “, “ Pierre “, “ Paul “}; Array.Sort(s); ◦ // cela donnera 2. ◦ Int pos = Array.BinarySearch(s, “Paul”); Array.Reverse(s); MANIPULATIONS DES FICHIERS Introduction Pour manipuler des fichiers en C# il s’agit d’utiliser la classe File de System.IO Plusieurs autres méthodes peuvent être utilisées . On en examinera une dans le TP Cette classe permet d’effectuer les opérations courantes telles que la copie, le déplacement, l'attribution de nouveau nom, la création, l'ouverture, la suppression et l'ajout de fichiers Exemple – Ecriture string path = @"c:\temp\MyTest.txt"; if (!File.Exists(path)) { // Create a file to write to. using (StreamWriter sw = File.CreateText(path)) { sw.WriteLine("Hello"); sw.WriteLine("And"); sw.WriteLine("Welcome"); } } Exemple – Lecture // Open the file to read from. using (StreamReader sr = File.OpenText(path)) { string s = ""; while ((s = sr.ReadLine()) != null) { Console.WriteLine(s); } } PROGRAMMATION RÉSEAU ET C# Introduction La programmation réseau repose sur les sockets Sockets ◦ Une norme de communication sur réseau ◦ Permettent à deux applications de communiquer a l’aide d’UN PROTOCOLE TCP UDP Architecture Ports Proc2 Proc1 A Adresse IP1 Internet Proc3 Proc4 Proc5 B Adresse IP2 Un port et un IP forment un ‘EndPoint’ Creation d’un objet Endpoint Utiliser les fonctions suivantes pour récupérer l’adresse IP et le nom de la machine locale Dns.Resolve() and Dns.GetHostName() IPHostEntry.AddressList==> la liste de tous les adresses IP sur cette machine IPHostEntry hostEntry = Dns.Resolve(Dns.GetHostName()); IPEndPoint endPoint = new IPEndPoint(hostEntry.AddressList[0], 11000); //Ou bien puisque “Dns.Resolve is obsoleted” string hostName = System.Net.Dns.GetHostName(); IPHostEntry myself = Dns.GetHostEntry(hostName); IPEndPoint endPoint = new IPEndPoint(myself.AddressList[0], 11000); Utiliser les ports > 1023 Creation TCP Socket using System.Net; using System.Net.Sockets; using System.Text; Socket serveur = new Socket(AddressFamily.InterNetwork, SocketType. Stream, ProtocolType.Tcp); InterNetwork: Reseaux IP .Stream ou .Dgram TCP Sockets Serveur Client Creation d’un socket TCP Creation d’un socket TCP Ecouter et attendre les connexions du client Etablir la connexion Créer un socket du nœud distant Lire et envoyer les données Fermeture socket Lire et envoyer des données Femeture socket Mettre un Socket en mode d’écoute Une fois le socket serveur est créé, il faut le relier à un endPoint serveur.Bind(endPoint); Pour mettre le socket en mode d’écoute il suffit d’appeler la méthode listen de la classe socket. Le nombre indique le nombre de connections dans la file serveur.Listen(number); Création Socket du nœud distant Utiliser Accept pour accepter une connection de la file, et retourne un socket représentant le client distant //création du socket qui représente le nœud distant //coté serveur Socket client= serveur.Accept(); Lecture des données La fonction Receive () bloquera l’application serveur jusqu’à la réception des informations byte[] bytes = new byte[1024]; int bytesRec = client.Receive(bytes); if (bytesRec == 0) break; (ou bien autre action) Console.WriteLine(Encoding.ASCII.GetString(bytes, 0, bytesRec)); Envoyer des données La fonction send() bloquera l’application jusqu’à l’envoie des informations byte[] msg = Encoding.ASCII.GetBytes("This is a test"); Console.WriteLine("Sending data."); client.Send(msg); Ici le serveur repond au client Fermeture du Socket serveur.Close();