Programmation Objet - Java IUT Limoges L.U.P Michel Vergnaud 2004-2005
Qu'est-ce que Java ? Un langage de programmation à objets Une architecture de MachineVirtuelle Un ensemble d'API variées (Application Programming Interface) Un ensemble d'outils (le JDK)
Historique Origines dans les années 1990, chez Sun Microsystems. Au départ, projet d'environnement indépendant du matériel pouvant permettre la programmation d'appareils variés : téléviseurs, magnétoscopes, … Première réalisation en 1992 par James Grosling ingénieur, d’abord appelée Oak. Echec. Puis renommé Java en 1995, visant les applications pour Internet, par Bill Joy. Machine virtuelle et compilateur sont distribués gratuitement. Gros succès, y compris pour des applications indépendantes d’Internet.
Présentation - 1 Langage portable : un programme une fois compilé fonctionnera aussi bien sous des stations Unix, que sous Windows ou autre, sans aucune modification. Le code source Java est compilé non pas pour un processeur donné, mais pour une machine virtuelle (c'est-à-dire qui n'a pas d'existence physique), la JVM (Java Virtual Machine). Le code résultant est nommé ByteCode. Lors de l'exécution le ByteCode est transformé en un code machine compréhensible par le processeur de la machine réelle. Java est donc aussi un langage interprété. L'interprète de la JVM est très élaboré pour être le plus rapide possible; il inclut un JIT (Just In Time Compiler) de façon à faire la traduction bytecode->code natif seulement lorsque c’est nécessaire (première instanciation d’une classe, boucles...).
Présentation - 2 Java est un vrai langage de programmation, conçu selon « l’état de l’art » en la matière, tout en supprimant ce qui s'est avéré être des erreurs des langages plus anciens. C’est est un langage à objets : L ’élément de base du langage est l ’objet, instance d ’une classe. Tous les éléments du langage sont des classes, sauf les types primitifs (int, float, double, char). Pas de fonctions autonomes, seulement des méthodes de classes. La gestion de la mémoire n'est plus à la charge du programmeur : la libération de la mémoire est automatique (Garbage collector, ramasse-miettes). Il n’y a ni pré-processeur ni macro-instructions. C’est est un langage réputé robuste et sûr.
Les identificateurs Java Un identificateur est un nom qui identifie de façon unique une variable, une méthode ou une classe. Un identificateur doit commencer par une lettre, un trait de soulignement ( _ ) ou un signe dollar ($), pas par un chiffre. Un identificateur peut contenir des chiffres, mais pas d'espace, tabulation, retour chariot ... Les identificateurs différencient les minuscules et les majuscules. Les mots clés de Java ne peuvent pas servir d’identificateurs
Les identificateurs Java : conventions Non obligatoires, mais facilitent la lisibilité. Les noms de classes commencent par une majuscule. Si le nom est composé de plusieurs mots, chacun commence par une majuscule. Ex. Rectangle, RectanglePlein, ... Les nom de méthodes et de variables commencent par une minuscule. Si le nom est composé de plusieurs mots, chacun commence par une majuscule. Ex. définirLargeur, rayon, produitScalaire, ...
Les mots-clés Java Empruntés à C / C++ Toujours en minuscules. • Mots clés de déclaration des données (boolean, float, int, ...) • Mots clés de boucle (continue, while, for, ...) • Mots clés conditionnels (if, else, switch, ...) • Mots clés d’exception (try, throw, catch, ...) • Mots clés de classes (class, extends, implements, ...) • Mots clés de modification et d’accès (private, public, ...) • Mots clés divers (true, false, null, super, this, ... )
Les instructions Java Séparées par le caractère ; (point-virgule) Peuvent être écrites sur plusieurs lignes Le caractère \ (barre oblique inversée) est utilisé pour écrire une chaîne de caractères sur plusieurs lignes. Ex. y = 10 * x ; b = (b1 && b2 ) || (b3 && b4 ) ;
Blocs de code Délimités par des accolades { } Ex. public void start() if (thread == null) thread = new Thread(this); } thread.start();
Commentaires Délimités par /* et */ Ex. Sur une fin de ligne, après // Ceci est un commentaire sur plusieurs lignes */ Sur une fin de ligne, après // // Ceci est un commentaire Délimités par /** et */ : utilisés par l’outil javadoc du JDK pour générer automatiquement une documentation /** Méthode renvoyant l'aire du rectangle
Une application Java Première application « Bonjour » Très proche des langages C et C++ Première application « Bonjour » Fichier « Bonjour.java » /* ------------------------------------------------ Ce programme se contente d'afficher le message "Bonjour tout le monde !" ------------------------------------------------- */ public class Bonjour { // Définition de la méthode statique main static public void main(String args[]) System.out.println("Bonjour tout le monde !"); } Le nom du fichier doit être le même que le mot suivant le mot-clé class (ici : Bonjour) Le fichier doit être compilé par la ligne de commande javac Bonjour.java Un fichier « Bonjour.class » est créé Pour exécuter l ’application, commande java Bonjour
Types et variables Déclarer une variable : Exemples type nom ; ou type nom = valeur_initiale; Exemples int n ; // Déclaration de la variable de nom n et de type entier double x ; // Déclaration de la variable de nom x et de type réel en double précision int m = 0; // ... Valeur initiale 0 double x = 100.0; // ... Valeur initiale 100.0 Les noms sont différents selon la casse (majuscules - minuscules) : x est différent de X Ne pas oublier le point-virgule en fin de déclaration Déclarer une constante : mot-clé final final double PI = 3.14159 ; La valeur de PI ne pourra pas être modifiée. L'écriture PI = 0.0 ; sera refusée à la compilation.
Portée (visibilité) Variables globales : visibles partout dans le programme. Leur utilisation est à éviter Variables locales : Variables visibles uniquement dans le bloc de code où elles sont déclarées. class DémoPortée { int x =0; void méthode1() int y = 0; y = x; //correct } void méthode2() int z = 1; z = x; //correct z = y; //incorrect: y n'est pas visible, déclarée dans un autre bloc
Types primitifs Java Les types numériques entiers byte, short, int, long Les types numériques réels float, double Type boolean : deux valeurs : true, false. Type caractère char : toutes les valeurs ASCII ou unicode ex. char c = ‘z’; char nl = ‘\n’ char uc = ‘\u0521’;
Types primitifs Java 2 Le transtypage (cast) est implicite s ’il n ’y a pas perte de données. int a = 4 ; double x = 2.5 ; double y = a; // ok, y = 4.0 int b = 1.5 ; // erreur à la compilation int c = a * (int)x ; // ok, c = 8 int n = 3; if (n > ‘A') { . . . } Ici la valeur ‘a ’ est convertie en entier (65, valeur ASCII de la lettre a ) avant d’être comparée à la valeur de n .
Classes et objets En programmation structurée non objet : les données (variables) et les opérations associées (fonctions) sont séparées. En programmation objet : les données et les opérations sont réunies dans une même entité. Dans Java, il n’y a pas de constantes, variables ou fonctions autonomes, contrairement au C++ qui autorise une programmation non-objet. La création d’un objet à partir d’une classe est appelé instanciation. Une classe définit un ensemble d ’objets utilisables. Un objet utilisable est une instance d ’une classe
Attributs et méthodes L'unité de base d'un programme écrit dans un langage orienté objet, est la classe Une classe contient : des données ou attributs ou champs Un attribut possède un type. A tout moment, il a une valeur. L'ensemble des valeurs des attributs de l'objet détermine l'état courant de l'objet. des actions pouvant être effectuées sur les attributs, nommées méthodes Les méthodes peuvent renvoyer une valeur (fonctions) ou non (procédures) La valeur des attributs ne devrait être modifiée que par les méthodes de l ’objet.
Programmation objet en Java - 1 La définition d'une classe se fait par le mot-clé class public class UneClasse { } La création d'un objet (instanciation) se fait en deux temps : Déclaration d'une référence UneClasse unObjet ; Création de l'objet par l'opérateur new : unObjet = new UneClasse(); Avant l'instanciation, une référence a pour valeur null La destruction de l'objet (libération des ressources allouées par new) est automatique dès que l’objet n'est plus référencé.
Programmation objet en Java - 2 Exemple On définit une classe « Cercle » dans un fichier « Cercle.java » public class Cercle { // Définition des attributs double xCentre; double yCentre; double rayon; } Cette classe ne contient que des attributs, pas de méthodes. Pour utiliser un objet de type Cercle, il faut instancier cet objet : Cercle unCercle; unCercle = new Cercle(); On peut accèder aux champs de l'objet par la notation pointée : unCercle.xCentre = 2.0; unCercle.yCentre = 3.0; unCercle.rayon = 10.0;
Méthodes : constructeur Un constructeur est une méthode automatiquement appelée lors de l'instanciation de l'objet Elle a le même nom que la classe. On ne précise pas le type de donnée retourné. Elle sert typiquement à initialiser les champs de l'objet. public class Cercle { // Constructeur Cercle() xCentre = 0.0; yCentre = 0.0; rayon = 1.0; } // Définition des attributs double xCentre; double yCentre; double rayon;
Plusieurs constructeurs Une classe peut posséder plusieurs constructeurs qui diffèrent par leurs arguments. Un seul des constructeurs est appelé lors de la construction de l'objet public class Cercle { // Constructeur par défaut Cercle() xCentre = 0.0; yCentre = 0.0; rayon = 1.0; } // Constructeur avec trois arguments Cercle(double x, double y, double r) xCentre = x; yCentre = y; rayon = r; // Définition des attributs double xCentre; double yCentre; double rayon;
Méthodes : exemples public class Cercle { // Constructeurs . . . // Déplacer le cercle void déplacer(double dx, double dy) xCentre = xCentre + dx; yCentre = yCentre + dy; } // Calculer l'aire du cercle double aire() return rayon * rayon * 3.14159; // Définition des attributs double xCentre; double yCentre; double rayon;
Créer et utiliser des objets public class UneApplication { static public void main(String args[]) Cercle c1; // déclaration d'une référence sur un objet de classe Cercle Cercle c2; // idem c1 = new Cercle(); // création de l'objet référencé par c1 c2 = new Cercle(12.0, 5.0, 2.5); // création de l'objet référencé par c2 System.out.println("Premier cercle"); System.out.print(" x = "); System.out.print(c1.xCentre); System.out.print(" y = "); System.out.print(c1.yCentre); System.out.print(" rayon = "); System.out.print(c1.rayon); System.out.println("\n"); System.out.println("Second cercle "); System.out.print(" x = " + c2.xCentre); System.out.print(" y = " + c2.yCentre); System.out.println(" rayon = " + c2.rayon); c2.déplacer(8.0,15.0); }
Exemples : classes Double et Integer Ces classes ont pour champ une valeur de type double pour Double et int pour Integer et proposent des méthodes permettant d'utiliser ces valeurs. Double 2 constructeurs : Double(double value) Double(String s) Quelques méthodes : //Returns the double value of this Double. double doubleValue() // Compares two Doubles numerically. int compareTo(Double anotherDouble) Integer Integer(int value) Integer(String s) int intValue() int compareTo(Integer anotherInteger)
Tableaux En Java, (pas en C / C++) les tableaux sont des objets Déclaration de tableaux ex. int[ ] unTableau; // un tableau d ’entiers int unTableau[ ]; // idem int unTableau[ ] [ ]; // un tableau d’entiers à 2 dimensions La définition des dimensions d ’un tableau se fait au moment de l ’instanciation (création de l'objet) avec l ’opérateur new. ex. int[ ] unTableau; // Déclaration unTableau = new int[100]; // Instanciation avec 100 éléments Accès aux éléments d'un tableau par l'opérateur [ ] unTableau [0] = 140; // affecte 140 au premier élément du tableau n = unTableau [0] // affecte à n la valeur du premier élément du tableau Dimension d'un tableau int nb_elem = unTableau.length; // nb_elem = 100
Arguments de la ligne de commande public class UneApplication { static public void main(String args[]) // args fait référence au tableau d'arguments // passés en ligne de commande // On peut connaître le nombre d'arguments : int nbArgs = args.length; // et utiliser ces arguments for(int i=0; i < nbArgs; i++) System.out.println("Argument " + i + " : " + args[i] ); }
Encapsulation des données - 1 L'accès aux champs de l'objet peut être interdit par le mot-clé private. Seules les méthodes membres de la classe pourront alors accéder aux champs. public class Cercle { // Constructeurs Cercle() xCentre = 0.0; yCentre = 0.0; rayon = 1.0; } . . . // Définition des attributs private double xCentre ; private double yCentre ; private double rayon;
Encapsulation des données - 2 Les lignes suivantes sont alors erronées : Cercle c = new Cercle(); System.out.println(c.rayon):// Le champ rayon est déclaré private c.rayon = 3.5; // on ne peut pas connaître sa valeur // ni la modifier depuis l'extérieur L'accès aux champs private ne peut se faire que par l'intermédiaire de méthodes membres, par exemple : class Cercle { . . . double getRayon() { return rayon; } void setRayon(double r) if (r > 0.0) rayon = r; . . . On peut ainsi définir des données "en lecture seule" ou n'autoriser la modification des données qu'à certaines conditions.
Encapsulation des données - 3 Exemple : On veut représenter un article dans un magasin. Un article est défini par sa désignation, qui ne peut pas varier, et son prix, qui peut changer. public class Article { Article(String d, double p) désignation = d; prix = p; } public String getDésignation() {return désignation ;} public double getPrix() {return prix ;} public void modifPrix(double pourCent) prix = prix * (1.0 + pourCent / 100.0); // Champs privés private String désignation ; private double prix;
Héritage - 1 On veut définir un "disque" c'est-à-dire un cercle ayant une couleur de remplissage. Un disque est défini par - les coordonnées x et y de son centre // Comme un cercle - son rayon // Comme un cercle - sa couleur On veut pouvoir - le créer à partir de ses coordonnées et son rayon // Comme un cercle - le déplacer // Comme un cercle - connaître sa couleur L'héritage permet de réutiliser la définition de la classe Cercle en se contentant d'y ajouter l'attribut de couleur et les méthodes associées. La classe Disque hérite ou est dérivée ou est sous-classe de la classe Cercle. La classe Cercle est parente ou classe de base ou superclasse de la classe Disque .
Héritage - 2 Cercle Disque import java.awt.Color; // package pour la classe // Color public class Disque extends Cercle { // Constructeurs Disque () // Appel au constructeur de la superclasse // Cet appel doit être fait en premiere ligne super(); couleur = Color.black; } Disque (double x, double y, double r) super(x, y, r); Disque (double x, double y, double r, Color c) couleur = c; public Color getCouleur(){ return couleur;} // Définition des attributs private Color couleur; Cercle Disque
Héritage : accès aux champs et méthodes Une classe dérivée peut accéder à tous les champs et méthodes public ou protected de sa classe parente, mais pas aux champs private. public class Disque extends Cercle { . . . void test() double r = rayon; // rayon est déclaré private // dans la classe parente Cercle double r = getRayon(); // correct }
Héritage et références Une référence sur une classe peut référencer un objet d'une classe dérivée. Elle ne peut pas référencer un objet d'une classe parente. Cercle c1; Cercle c2; Disque d1; Disque d2; c1 = new Cercle(12.0, 5.0, 40.0); c2 = new Disque(6.0, 5.0, 20.0); d1 = new Cercle(12.0, 5.0, 40.0); // erreur System.out.print(c2.getCouleur() ); // erreur UneApplication2.java:14: incompatible types found : Cercle required: Disque d1 = new Cercle(12.0, 5.0, 40.0); UneApplication2.java:17: cannot resolve symbol symbol : method getCouleur () location: class Cercleur() );
Héritage : généralités Une classe ne peut hériter (extends) que d'une seule classe. Si une classe C est déclarée final, on ne peut pas définir de classe dérivée de C. Toutes les classes dérivent de java.lang.Object . L'opérateur instanceof permet de déterminer la classe d'une instance. Cercle c1, c2; c1 = new Cercle(1.0, 1.0, 4.0); System.out.println(c1 instanceOf Cercle); // affiche true System.out.println(c1 instanceOf Disque); // affiche false c2 = new Disque(1.0, 1.0, 4.0); System.out.println(c2 instanceOf Cercle); // affiche true System.out.println(c2 instanceOf Disque); // affiche true
Polymorphisme - 1 class Cercle { . . . public void dessiner(Graphics g) // on dessine le cercle... } class Disque extends Cercle // on dessine le disque... Cercle c1 = new Cercle(. . .); Disque d1 = new Disque(. . .); c1.dessiner(g); // les « bonnes » méthodes sont appelées d1.dessiner(g);
Polymorphisme - 2 Soit la hiérarchie de classes suivante class Employé { . . . public int ancienneté() { . . .} public void augmenterSalaire(double pourCent) salaire *= 1.0 + pourCent / 100.0; } private double salaire; Employé Manager Secrétaire
Polymorphisme - 3 class Manager extends Employé { public void augmenterSalaire(double pourCent) double bonus = 0.5 * ancienneté(); super.augmenterSalaire(pourCent + bonus); } // Tout le personnel est conservé dans un tableau : Employé[] personnel = new Employé[100]; personnel[0] = new Secrétaire(. . .); personnel[1] = new Manager(. . .); // on augmente les salaires de 2% personnel[0].augmenterSalaire(2.0); personnel[1].augmenterSalaire(2.0); // le manager a eu son bonus !
La classe Vector Tableau « à taille variable » Contient uniquement des références sur des objets de classe « Object » On doit donc transtyper ces références pour les utiliser. int size() // nombre d’éléments du vecteur. add(Object o) // ajoute un élément au vecteur. remove(int index) // supprime l’élément à la position index Object elementAt(int index) // l’élément à la position index import java.util.Vector; Vector personnel = new Vector(); Manager m = new Manager(...); personnel.add( m ); personnel.add ( new Secrétaire(…) ); for(int i = 0; i < personnel.size(); i++) { Employé e = (Employé)personnel.elementAt(i); e.augmenterSalaire(5.0); }
La classe Object Rayon : 40.0 x : 12.0 y : 5.0 Classe de base de toutes les classes. Contient des méthodes généralement redéfinies dans les classes dérivées. Exemple : public String toString() retourne une représentation lisible de l’objet sous forme de chaîne de caractère, et est appelée par System.out.print Exemple class Cercle { . . . return " Rayon : " + rayon + " x : " + xCentre + " y : " + yCentre ; } Cercle c = new Cercle(12.0, 5.0, 40.0); System.out.println(c); Rayon : 40.0 x : 12.0 y : 5.0
Modificateurs d'accès Accès depuis l’intérieur du paquet d’une classe Modificateur d’accès Héritage Accessible Par défaut Oui Oui Public Oui Oui Protected Oui Oui Private Non Non Accès depuis l’extérieur du paquet d’une classe Par défaut Non Non Protected Oui Non
Classes abstraites - 1 Une classe est dite abstraite si une de ses méthode au moins n'est pas implémentée (méthode abstraite). Une classe abstraite ne peut pas être instanciée. Une classe dérivée d'une classe abstraite doit implémenter toutes les méthodes abstraites pour pouvoir être instanciée. abstract public class ObjetGéométrique { . . . // Calcul de l'aire abstract public double aire(); // Calcul du périmètre abstract public double perimetre(); } ObjetGéométrique unObjet; unObjet = new ObjetGéométrique(. . .);
Classes abstraites - 2 abstract class Employé { . . . abstract public void augmenterSalaire(double pourCent); protected double salaire; } class Manager extends Employé public void augmenterSalaire(double pourCent) double bonus = 0.5 * ancienneté(); salaire = salaire * (1 + (pourCent + bonus)/100.0); class Secrétaire extends Employé
Interfaces - 1 Une classe ne peut hériter (extends) que d'une seule classe. L'héritage multiple est interdit. Il est remplacé par l'utilisation d'interfaces. Une interface est une déclaration de classe qui contient des déclarations de méthodes, mais pas d’implémentation. Exemple : On veut pouvoir comparer des objets de classe Rectangle par leur aire. On définit une interface Comparable : public interface Comparable { public boolean isGreaterThan ( Object b); public boolean isSmallerThan ( Object b); } Cette interface pourra être utilisée par d’autres classes héritant de Object, c’est-à-dire toutes les classes…
Interfaces - 2 On indique que la classe Rectangle implémente cette interface : public class Rectangle implements Comparable Il faut maintenant implémenter toutes les méthodes de l'interface Comparable dans la classe Rectangle { Rectangle (…) public boolean isGreaterThan ( Object b) Rectangle R = (Rectangle)b; return aire() > R.aire(); } public boolean isSmallerThan ( Object b) return aire() < R.aire();
Champs et méthodes statiques Les membres statiques (champs ou méthodes) d'une classe sont définis et peuvent être utilisés sans instanciation d'objet. On y accède par le nom de la classe suivi d'un point. Exemples : Color.blue est un champ statique de la classe Color défini par public static final Color blue Double.MAX_VALUE est un champ statique de la classe Double défini par public static final double MAX_VALUE Double.parseDouble est une méthode statique de la classe Double définie par public static double parseDouble(String s) que l'on peut être utiliser sans instance : double valeur = Double.parseDouble( "123.45" ); Les méthodes statiques ne peuvent pas accéder aux champs et méthodes non statiques d'un objet.
Méthode statique main - 1 class Test { int n; public static void main(String[] args) n = 10; } Test.java:6: non-static variable n cannot be referenced from a static context n = 10; ^ 1 error
Méthode statique main – 2 class Test { int n; public Test() n = 10; } public static void main(String[] args) new Test();
Chaînes de caractères En Java, (pas en C / C++) les chaînes sont des objets Elles sont stockées dans des objets de classe String. String s; // déclaration s = "Bonjour"; // instanciation // ou s = new String("Bonjour"); // instanciation Longueur d'une chaîne : int n = s.length(); // n vaut 7 Caractère à une position donnée d'une chaîne : char unCar = s.charAt(3); // unCar vaut 'j' On ne peut pas modifier le contenu d'un objet String. Pour cela, utiliser la classe StringBuffer.
Egalité des objets Égalité de deux objets ou de leurs valeurs String ch1 = "Azerty"; // un objet de classe String String ch2 = "Azerty"; // un autre objet de classe String System.out.println(ch1 == ch2); // Affiche false : les 2 objets // sont distincts System.out.println(ch1.equals(ch2) ); // Affiche true : les deux // objets ont la même valeur ch2 = ch1; // ch1 et ch2 sont "le même objet" System.out.println(ch1 == ch2); // Affiche true ch2 = new String(ch1); // on re-crée ch2 System.out.println(ch1 == ch2); // Affiche false System.out.println(ch1.equals(ch2) ); // Affiche true
Exceptions - 1 Deux grands types d'erreurs : erreurs de progammation détectables à la compilation Le programme ne peut pas être exécuté. D'autres erreurs sont détectées au moment du lancement de l'application à l'appel de la machine virtuelle par java.exe. L'exécution s'arrête immédiatement. erreurs à l'exécution (bugs) Exemples : lecture / écriture en dehors des limites d'un tableau écriture sur un disque plein . . . A ce moment une exception est générée. Java permet de gérer les exceptions, c'est-à-dire de spécifier ce que le programme doit faire à l'apparition d'une exception. Si une exception survient est n'est pas gérée, le programme "plante".
Exceptions - 2 Syntaxe try - catch { // bloc susceptible de provoquer une exception } catch (Exception e) // traitement à effectuer si une exception est générée // par exemple System.out.println( e ); L'exception e est un objet instance d'une classe dérivée de la classe de base Throwable ou de la sous-classe Exception. Error Throwable IOException Exception RuntimeException
Exceptions - exemple : saisie d’un entier int saisieEntier() { byte ch[] = new byte[256]; int longueur = 0; try longueur = System.in.read(ch); } catch(java.io.IOException e) System.out.println(e); String str = new String(ch, 0, longueur-2); int n; n = Integer.parseInt(str); catch(NumberFormatException e) n = -1; return n;
Exceptions - 3 Les exceptions dérivées de Error découlent d'erreurs internes ou de manque de ressources, assez rares. Le seul traitement possible consiste à informer l'utilisateur et à fermer le programme "proprement". Une exception dérivée de RuntimeException est provoquées par une erreur de programmation : mauvais typage accès à un tableau en dehors des limites emploi d'une référence null Les autres exceptions sont provoquées par une cause externe au programme : lire au-delà de la fin d'un fichier accéder à une URL incorrecte utiliser un nom de classe inexistante dans la recherche d'un objet Une fois lancée, une exception est soit traitée (catch, soit propagée. Elle se propage en remontant vers les méthodes appelantes jusqu’à ce qu’elle soit traitée. Si elle ne l’est pas, le programme s’arrête.
Exceptions - 4 Signaler la possibilité de propagation d'une exception dans l'en-tête d'une méthode (throws) si cette exception n'est pas traitée dans la méthode. public void uneMéthode() throws UneException { ... } public void uneMéthode() throws UneException, UneAutreException, ... Ex. class Animation { public Image loadImage(String s) throws IOException ... On ne doit pas signaler les exceptions héritant de RuntimeException ou de Error (exceptions hors contrôle). Les exceptions héritant de RuntimeException peuvent être évitées. Toutes les autres exceptions sont dites sous contrôle.
Exceptions - 5 Générer volontairement une exception : throw ou if(t == null) throw new NullPointerException(); ou { NullPointerException e = new NullPointerException("t est null !"); throw e; } Créer ses propres classes d'exception Utile si aucune des classes existantes ne correspond de façon adéquate au problème rencontré. class FileFormatException extends IOException public FileFormatException (){}; public FileFormatException (String msg) super(msg);
Exceptions – 6 Lancer l'exception définie : String readData(BufferedReader in) throws FileFormatException { ... while(...) if(ch == -1) if (n < len) FileFormatException e = new (FileFormatException("Format incorrect"); throw e; }
Classe File - 1 Ne pas confondre avec la structure FILE du c !! Cette classe fournit une représentation abstraite des fichiers physiques et des répertoires. Cette représentation est indépendante du système d'exploitation. Ex : File f = new File("./donnees.dat"); System.out.println(f.getPath()); // .\donnees.dat System.out.println(f.getAbsolutePath()); // C:\Iut\Lup2001-2002\TD4\donnees.dat System.out.println("Accessible en lecture : " + f.canRead()); // Accessible en lecture : true System.out.println("Accessible en ecriture : " + f.canWrite()); // Accessible en ecriture : true System.out.println("Longueur : " + f.length()); // Longueur : 12
Classe File - 2 Lister les fichiers d'un répertoire avec l'heure de leur dernière modification : File dir = new File("."); File[] files = dir.listFiles(); int nbFiles = files.length; for (int i=0; i< nbFiles; i++) { System.out.print(files[i].getPath()); Time t = new Time(files[i].lastModified()); System.out.print(" " + t.toString() ); if(files[i].isDirectory() ) System.out.print(" Dossier"); else System.out.print(" Fichier"); }
Classe File – 3 Lister les fichiers d'un répertoire ayant une extension donnée : // On définit une classe implémentant FileFilter // Cette interface ne possède qu'une méthode définie ainsi : // public boolean accept(File pathname) class DatFilter implements FileFilter { public boolean accept(File pathname) return pathname.getPath().endsWith(".dat"); } // On utilise un objet de cette classe en paramètre de listFiles File dir = new File("."); DatFilter filter = new DatFilter(); File[] datFiles = dir.listFiles(filter); int nbFiles = datFiles.length; for (int i=0; i< nbFiles; i++) System.out.println(datFiles[i].getPath()); // Ou plus simplement, avec une instance anonyme de DatFilter File[] datFiles = dir.listFiles(new DatFilter() ); . . .
Entrées-sorties : package io Il prend en charge la lecture et l’écriture de données sur différentes unités. Les classes de ce package sont réparties en plusieurs packages : classe File. classes de flux d’entrée classes de flux de sortie La classe File donne un ensemble de méthodes faciles pour manipuler les fichiers et répertoires. L'utilisation des flux est rendue plus complexe par le grand nombre de classes fournies.
Flux d'entrée - sortie - 1 Les classes FileInputStream et FileOutputStream. Fournissent des flux associés à un fichier sur disque. Ex FileInputStream ficEntree = new FileInputStream ("employes.dat"); On peut aussi employer un objet de classe File pour créer un objet FileInputStream : File f = new File ("employes.dat"); FileInputStream fic = new FileInputStream (f); Ces classes fournissent des méthodes read()(pour FileInputStream ) et write() (pour FileOutputStream) qui lisent ou écrivent des octets (flux binaires). Elles servent de classes de base pour d'autres classes de manipulation de flux.
Flux d'entrée - sortie - 2 Les classes DataInputStream et DataOutputStream permettent de lire et d'écrire des données formatées : float, double, int, String, char, boolean, … On construit un objet de ces classes à partir d'un objet InputStream ou FileInputStream, OutputStream ou FileOutputStream ex. : écriture de données File f = new File ("donnees.dat"); FileOutputStream outputStream = new FileOutputStream (f); DataOutputStream dataStream = new DataOutputStream(outputStream); int n = 10; dataStream. writeInt(n); double x = 12.5; dataStream. writeDouble(x); dataStream.close(); lecture des données FileInputStream inputStream = new FileInputStream (f); DataInputStream dataStream = new DataInputStream(inputStream); in n = dataStream. readInt(); double x = dataStream. readDouble();
Fichiers textes Utiliser des classes dérivées de Writer et Reader qui gèrent l'encodage des caractères, par ex BufferedReader et BufferedWriter ex Lire un fichier texte : try { FileReader f = new FileReader("essai.txt"); BufferedReader ficEntree = new BufferedReader (f); String temp; while( (temp = ficEntree.readLine() ) != null) System.out.println(temp); } catch(FileNotFoundException e) System.out.println("Erreur de fichier"); catch(IOException e) System.out.println("Erreur de lecture");
Persistance des objets - 1 Les objets peuvent être déclarés sérialisables. La sérialisation consiste à sauvegarder dans un fichier l'état courant de l'objet. Cet état peut ensuite être retrouvé par la désérialisation. //Un carré horizontal public class Carre implements Serializable { // Constructeurs Carre() this(0.0, 0.0, 1.0) ; } . . . private double x; private double y; private double cote;
Persistance des objets - 2 import java.io.*; class TestSerialW { public static void main(String[] args) // On crée un carré Carre C1 = new Carre(1.0, 10.0, 5.0); // On le sérialise dans un fichier "carre.txt" try FileOutputStream f = new FileOutputStream(" carre.txt"); ObjectOutputStream out = new ObjectOutputStream(f); out.writeObject(C1); out.close(); } catch(FileNotFoundException e) System.out.println("Erreur a l'ouverture du fichier"); catch(IOException e) System.out.println("Erreur en ecriture");
Persistance des objets - 3 import java.io.*; class TestSerialR { public static void main(String[] args) // On retrouve le carre sauvegarde try FileInputStream f = new FileInputStream("care.txt"); ObjectInputStream input = new ObjectInputStream(f); Carre C1 = (Carre)input.readObject(); input.close(); System.out.println("C1 : cote " + C1.getCote() ); System.out.println("C1 : aire " + C1.getAire() ); } catch(FileNotFoundException e) System.out.println("Erreur a l'ouverture du fichier"); catch(IOException e) System.out.println("Erreur en lecture"); catch(ClassNotFoundException e) System.out.println("La classe Carre n'existe pas");
Persistance des objets – 4 Les champs déclarés transcient ne seront pas sauvegardés lors de la sérialisation. Utile pour ne pas sauvegarder des champs contenant des données temporaires ne concernant pas l'état de l'objet. Si l'on sérialise un objet, tous les objets référencés par les champs de cet objet sont également sérialisés,s’ils implémentent l’interface Serializable. Notamment, si l'on sérialise un objet de classe Vector, tous les objets référencés par les éléments de cet objet sont sérialisés ,s’ils implémentent l’interface Serializable.
Composants d'interface utilisateur graphique (GUI) 1 Bibliothèques Awt et Swing Procédures communes pour l'utilisation de ces clases : Créer un cadre Créer des composants dans ce cadre Mettre en page ces composants Écrire des méthodes réagissant aux actions de l'utilisateur AWT (Abstract Windowing Toolkit) : première bibliothèque, depuis Java 1. Peu de composants Complétée par Swing depuis Java 2
Composants d'interface utilisateur graphique (GUI) 2 Principaux composants : awt swing Boutons Button JButton Labels Label JLabel Case à cocher Checkbox JCheckBox Groupe de boutons radio CheckboxGroup ButtonGroup Listes déroulantes List JList, JComboBox Zones de texte TextField JTextField Zones de texte multi-lignes TextArea JTextArea Ascenseurs ScrollBar JScrollBar etc...
Composants d'interface utilisateur graphique (GUI) 3 Conteneurs Cadres dans lesquels sont placés les composants. Ex JPanel : panneau, volet d'affichage JFrame : JPanel avec barre de menu JDialog : boîte de dialogue JScrollPane : fenêtre avec ascenseurs JTabbedPane : fenêtre à onglets
Composants d'interface utilisateur graphique (GUI) 4
Disposition des composants (layout) - 1 On peut définir la disposition géométrique des composants dans un conteneur. Par défaut : FlowLayout //BorderLayout : conteneur.setLayout(new BorderLayout()); conteneur.add(new JButton("North") , BorderLayout.NORTH); conteneur.add(new JButton("Center") , BorderLayout.CENTER); . . .
Disposition des composants (layout) - 2 GridLayout : conteneur.setLayout(new GridLayout(3,2) ); for(int i=1; i< =6; i++) conteneur.add(new JButton(""+i));
Disposition des composants (layout) - 3 GridBagLayout et GridBagConstraints Chaque composant est associé à une instance de GridBagConstraints qui indique la disposition du composant dans la grille. On peut ainsi disposer les composants librement.
Gestion d'évènements 1 Les gestionnaires (écouteurs) d'évènements permettent d'intercepter les actions des utilisateurs et d'assigner au programme un comportement adapté en réponse. Démarche Définir l'objet sur lequel on veut gérer les évènements (ex JPanel) Définir une classe (1) implémentant une interface gestionnaire d'évènements (ex MouseListener) (2) ou héritant d'une classe gestionnaire d'événement (ex MouseAdapter) Surcharger toutes (1) ou certaines(2) méthodes de cette classe. Associer l'objet (JPanel) à l'écouteur d'évènements (ex addMouseListener() )
Gestion d'évènements 2 // Définir le gestionnaire d'évènements class MyMouseAdapter extends MouseAdapter { public void mouseClicked(MouseEvent e) // le code défini ici sera exécuté lors d'un clic } // Panel sur lequel on veut gérer les clics souris class UnPanel extends JPanel UnPanel () // associer à l'écouteur d'évènements addMouseListener(new MyMouseAdapter()); . . .
Gestion d'évènements 3 // Même chose en utilisant une classe anonyme // Panel sur lequel on veut gérer les clics souris class UnPanel extends JPanel { UnPanel () // associer à l'écouteur d'évènements addMouseListener(new MouseAdapter() public void mouseClicked(MouseEvent e) // le code défini ici sera exécuté // lors d'un clic } } ); . . .
Gestion d'évènements 4 // L'objet peut être son propre écouteur d'évènement // Panel sur lequel on veut gérer les clics souris class UnPanel extends JPanel implements MouseListener { UnPanel () // associer à l'écouteur d'évènements : l'objet lui-même addMouseListener(new MouseAdapter(this) ); } // Surcharger toutes les méthodes de l'interface public void mouseClicked(MouseEvent e) // le code défini ici sera exécuté lors d'un clic public void mousePressed (MouseEvent e) {} public void mouseReleased(MouseEvent e) . . .
Une application Swing JFrame JPanel JButton JLabel Cet exemple d'application swing comprend : Une fenêtre principale, de classe JFrame Un "panneau" de classe JPanel Un bouton JButton Une zone d'affichage JLabel JFrame JPanel JButton JLabel
Code de l’application import java.awt.*; import javax.swing.*; class Exemple { Exemple() mainFrame = new JFrame("Exemple d'application"); mainPanel = new JPanel(); bouton = new JButton("Bouton Swing"); label = new JLabel("Nombre de clics : 0"); mainPanel.setLayout(new GridLayout(2,1)); mainPanel.add(bouton); mainPanel.add(label); mainFrame.getContentPane().add(mainPanel); mainFrame.setSize(300,200); mainFrame.show(); } public static void main(String args[]) new Exemple(); private JFrame mainFrame; private JPanel mainPanel; private JButton bouton; private JLabel label;
Code de l’application - 2 // L’application doit se terminer si on ferme la fenêtre // principale . . . import java.awt.event.*; mainFrame = new JFrame("Exemple d'application"); mainFrame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) System.exit(0); } });
Code de l’application - 3 // Gestion des actions sur le bouton bouton = new JButton("Bouton Swing"); bouton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) nbClics++; label.setText(prefix + nbClics); } }); . . . private final String prefix = "Nombre de clics : "; private int nbClics = 0;
Dessiner dans un JPanel Toutes les instructions graphique doivent être appelées dans la méthode protected void paintComponent(Graphics g) Cette méthode est applelée automatiquement quand le widget doit être affiché. Elle doit être redéfinie dans une classe dérivée de JPanel. On utilise le paramètre g de classe Graphics (cf. doc); Exemple : class unPanel extends JPanel { super.paintComponent(g); g.drawLine( 10,10, 200, 100); } On peut provoquer explicitement le réaffichage du panneau en appelant sa méthode repaint();
Utiliser la souris Utiliser la classe Mouse Adapter addMouseListener ( new MouseAdapter() { public void mouseClicked(MouseEvent e) // e.getX() et e.getY() donnent les // coordonnées du curseur au moment du clic . . . } );
Threads - généralités Un programme peut être divisé en plusieurs tâches qui semblent s’exécuter simultanément. Chacune de ces tâches est une thread. Un processus est un programme en cours d’exécution, avec son propre espace d’adressage. Un système d’exploitation multi-tâches autorise plusieurs processus à s’exécuter « simultanément » en partageant les cycles CPU entre eux. Un processus peut contenir plusieurs threads, qui utilisent le même espace d’adressage. Le multithreading s’impose lorsqu’un programme doit exécuter une procédure longue et gourmande en CPU (ex calcul mathématique intensif, ou animation graphique) tout en laissant la main à l’utilisateur qui doit pouvoir interrompre le calcul ou l’animation, ou en modifier le comportement. On peut ainsi conserver à un programme une interface utilisateur réactive : une thread s’occupe du calcul, de l’animation… une autre gère les évènements d’interface utilisateur Tout programme comprend au moins une thread (thread principale).
Threads en Java : méthode 1 Définir une classe héritant de la classe Thread Surcharger la méthode run() de cette classe Instancier un objet de cette classe Appeler la méthode start() de cet objet. class PrimeThread extends Thread { long minPrime; PrimeThread(long minPrime) this.minPrime = minPrime; } public void run() // compute primes larger than minPrime . . . . . . PrimeThread p = new PrimeThread(143); p.start();
Threads en Java : méthode 2 Définir une classe implémentant l’interface Runnable Implémenter la méthode run() de cette classe Instancier un objet de cette classe. Instancier la classe Thread avec cet objet en argument du constructeur Appeler la méthode start() de ce dernier objet. class PrimeRun implements Runnable { long minPrime; PrimeRun(long minPrime) this.minPrime = minPrime; } public void run() // compute primes larger than minPrime . . . . . . PrimeRun p = new PrimeRun(143); new Thread(p).start();
Priorité et noms des threads en Java On peut fixer la priorité de chaque thread par la méthode setPriority Valeurs possibles (constantes définies dans Thread) : MAX_PRIORITY MIN_PRIORITY NORM_PRIORITY Chaque thread a un nom qui permet de l’identifier. Ce nom peut être passé en paramètre du constructeur. uneThread = new Thread ( "Thread 1"); Il peut être retrouvé par la méthode getName();
Exemple 1 : thread class MyThread extends Thread { MyThread(String name) super(name); } public void run() while(true) System.out.println("Je suis" + getName());
Exemple 1 : application public class essai { public static void main(String args[]) new essai(); } public essai() thread1 = new MyThread("Un"); thread2 = new MyThread("------deux"); thread3 = new MyThread("---------------trois"); thread1.start(); thread2.start(); thread3.start(); private MyThread thread1; private MyThread thread2; private MyThread thread3;
Contrôler l’exécution : sleep //public static void sleep(long millis) throws InterruptedException class MyThreadS extends Thread { MyThreadS(String name, int tempo) super(name); this.tempo = tempo; } public void run() while(true) System.out.println("Je suis " + getName()); try sleep(tempo); catch(InterruptedException e){}; private int tempo = 0;
Exemple : chronomètre Construction de l’interface : Un objet JFrame Un objet JPanel principal, associé à une instance de BorderLayout Un objet JPanel contenant les trois boutons (au Nord) Un objet JPanel pour l’affichage du temps (au Centre) Un champ privé t contient la valeur à afficher et est incrémentée dans une boucle infinie. La méthode paintComponent de JPanel réalise l’affichage. La boucle infinie s’exécute dans un objet Thread. La thread principale gère les actions sur les boutons.
Chronomètre : affichage class ClockPanel extends JPanel { // Fixer la valeur à afficher public void setT(double t) this.t = t; } // Réaliser l’affichage public void paintComponent(Graphics g) Font font = new Font("Helvetica", Font.BOLD, 60); g.setFont(font); g.drawString(""+t, 150, 100); private double t ;
Chronomètre : thread d’animation class ClockThread extends Thread { public void run() while(onContinue) clockPanel.setT(t); try sleep(1000); } catch(InterruptedException e){} mainPanel.repaint(); t = t + 1; . . . private boolean onContinue = true; private double t = 0.0;
Chronomètre : démarrer - arrêter class ClockThread extends Thread { . . . public void demarre() start(); } public void arrete() onContinue = false;
Chronomètre : démarrer - arrêter public class Clock { public Clock() . . . boutonStart.addActionListener(new ActionListener() public void actionPerformed(ActionEvent e) clockThread = new ClockThread(); clockThread.demarre(); } }); boutonSop.addActionListener(new ActionListener() if(clockThread != null) clockThread.arrete(); private ClockThread clockThread;
Chronomètre : interrompre - reprendre public void run() { while(onContinue) . . . // affichage synchronized(this) while(estSuspendue) try wait(); } catch(InterruptedException e){} . . . public void pause() estSuspendue = ! estSuspendue; if ( ! estSuspendue) notify(); private boolean estSuspendue = false;
Chronomètre : wait - notify L’instruction wait de la classe Object interrompt l’exécution de la thread courante jusqu’à l’appel de l’instruction notify par une autre thread . Un bloc déclaré synchronized ne peut être exécuté que par une thread à la fois (exclusion mutuelle). Losqu’une thread exécute un bloc synchronized , ce bloc est verouillé et ne peut donc pas être exécuté par une autre thread, jusqu’à ce que la première exécution se termine.
APPLETS
Applets : généralités Applet : application s'exécutant dans une page HTML Le ByteCode (fichiers .class) est téléchargé depuis un serveur. L'exécution est effectuée par la machine virtuelle du navigateur ou par l'utilitaire appletviewer du JDK.
Applets : restrictions Droits d'un programme Java s'exécutant dans un navigateur Web ou dans appletviewer Nav. appletviewer Lire les fichiers locaux Non Oui Écrire dans les fichiers locaux Non Oui Lire des informations sur les fichiers Non Oui Supprimer un fichier Non Non Lancer un autre programme Non Oui Lire la propriété user.name Non Oui Sortir de l'applet par exit() Non Oui Créer une fenêtre popup Oui ( message) Oui
Insertion dans une page Html Balise APPLET </html> </body> <APPLET CODE='HelloWorld.class' WIDTH=100 HEIGHT=100> </APPLET> Balise OBJECT <OBJECT CLASSID="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93" WIDTH=100 HEIGHT=100> <param NAME = CODE VALUE = HelloWorld.class > </OBJECT> 35 attributs. Voir documentation...
Passer des informations à une applet Balise PARAM </html> </body> <OBJECT CLASSID="HelloWorld.class" WIDTH=200 HEIGHT=100 PARAM NAME=font VALUE="Helvetica" PARAM NAME=size VALUE="48"> </OBJECT> Les paramètres sont toujours passés sous forme de chaînes. Un transtypage peut être nécessaire dans le code de l'applet : public class UneApplet extends Japplet { public void init() String fontName = getParameter(font); int fontSize = Interger.parseInt(getParameter(size)); . . . }
Gérer le chargement de l'applet <OBJECT CLASSID="HelloWorld.class" WIDTH=100 HEIGHT=100 CODEBASE="/classes/" <!-- Ligne affichée pendant le chargement de l'applet --> STANDBY = "Merci de patienter…" > <!-- Le code suivant est exécuté si l'applet n'a pas été lancée correctement, par ex. si le navigateur est incompatible avec Java --> Échec du chargement de l'applet </OBJECT>
Fichiers Jar Les différents fichiers .class, .gif, etc… constituant l'applet peuvent être réunis et compressés dans un seul fichier .jar (Java Archive). Raccourcir la durée du chargement initial au démarrage de l'applet Supprimer le chargement d'autres fichiers pendant l'exécution. jar.exe fait partie du jdk. Créer un fichier jar : jar cf FileName.jar Fichier1 Fichier2 . . . Le fichier HTML fera référence au fichier .jar <OBJECT CLASSID="HelloWorld.class" ARCHIVE = "Filename.jar" WIDTH=200 HEIGHT=100 PARAM NAME=font VALUE="Helvetica" PARAM NAME=size VALUE="48"> </OBJECT>
Structure d'une applet Pas de méthode main(). public class HelloWorld extends java.applet.Applet { public void init() // Appelée 1 fois. Similaire à un constructeur } public void start() // Appelée à chaque chargement de la page public void stop() // Appelée lorsque l'utilisateur quitte { // la page public void destroy() // Appelée à l'arrêt du navigateur ou public class HelloWorld extends Japplet {…} // Java 2 Pas de méthode main().
Application -> applet Créer une page HTML pour charger l'applet Supprimer la méthode main() de l'application Remplacer la classe JFrame par la classe JApplet. Cette classe doit être publique. Supprimer l'appel à setSize() : la taille de l'applet est donnée dans la page HTML par les paramètres WIDTH et HEIGHT Supprimer l'appel à WindowListener. Une applet ne peut pas être explicitement fermée. Recopier le code placé dans le constructeur de l'application vers la méthode init() de l'applet, si ce code contient des appels à getParameter().
Passer des informations au navigateur Interface AppletContext La méthode getAppletContext() de la classe Applet (dont hérite JApplet) renvoie un objet implémentant cette interface. On peut : demander au navigateur d'afficher des informations dans la barre d'état (status bar). Méthode showStatus(String msg) demander au navigateur d'afficher un document (page Web ou autre) dans la même page, dans une nouvelle page, ou dans un autre cadre. Méthode showDocument(URL url) communiquer avec d'autres applets présentes sur la même page et provenant du même CODEBASE. Pour cela chaque applet doit avoir un nom, donné par la balise NAME dans le fichier HTML. Méthode getApplet(String name) charger des fichiers images et sons. Méthodes getImage(URL url) , getAudioClip(URL url)
MULTIMEDIA
URLs Les ressources images ou sons sont généralement décrites par une URL. La classe java URL permet de manipuler ler URLs… URL u = new URL("http://www.unilim.fr/index.html"); (URL absolue) Ou URL data = new URL(u, "images/duke.gif"); (URL relative) Syntaxe d’un constructeur : public URL(String spec) throws MalformedURLException -> Il faut gérer l’exception MalformedURLException
Graphisme dans une applet Afficher une image ( GIF, JPEG ou PNG ) Utiliser les méthodes getImage de Applet et drawImage de Graphics. Image img = getImage( getCodeBase(), "img.gif" ); g.drawImage(img, 0, 0, this); drawImage posséde de nombreuses variantes ; cf doc… Les fichiers images doivent se trouver sur le même serveur que l’applet.
Graphisme dans une application Utiliser la classe Toolkit Toolkit.getDefaultToolkit().getImage(name);
Traitement d’images 1 Classe Graphics public abstract boolean drawImage(Image img, int x, int y, ImageObserver observer) affiche l’image sans modification d’échelle : peut donc afficher soit l’image entière, soit une partie seulement.
Traitement d’images 2 public abstract boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) modifie l’échelle de l’image pour qu’elle s’affiche entièrement dans le rectangle spécifié.
Traitement d’images 3 public abstract boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer) modifie l’échelle de l’image pour qu’elle s’affiche entièrement dans le rectangle spécifié et affiche les pixels transparents dans la couleur spécifiée.
Traitement d’images 4 public abstract boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer) Affiche la portion d’image définie par sx1...sy2 (source) dans le rectangle défini par dx1...dy2 (destination), en modifiant l’échelle.
Traitement d’images 5 Classes Graphics2D et BufferedImage Graphics2D hérite de Graphics et propose des méthodes élaborées de transformations géométriques, gestion des couleurs et affichage du texte. C’est une classe abstraite qui ne peut pas être instanciée directement. On doit obtenir une instance à partir d’un objet déjà existant, par exemple une instance de BufferedImage.
Traitement d’images 6 Ex. rotation d’une image public void paintComponent(Graphics g) { . . . img = getImage( getCodeBase(), "duke.gif" ); buffimg = new BufferedImage(getWidth(), getHeight(),BufferedImage.TYPE_3BYTE_BGR ); Graphics2D g2 = buffimg.createGraphics(); g2.rotate(Math.PI/4, getWidth() /2, getHeight()/2 ); g2.drawImage(img, 0, 0, getWidth(), getHeight(), Color.yellow, this); g.drawImage(buffimg, 0, 0, getWidth(), getHeight(),this); }
Exemple
Exemple : code 1 /** * @version 1.20 23 Jun 1998 * @author Cay Horstmann */ import java.awt.*; import java.awt.event.*; import javax.swing.*; class ImagePanel extends JPanel { public ImagePanel() { image = Toolkit.getDefaultToolkit().getImage ("blue-ball.gif"); MediaTracker tracker = new MediaTracker(this); tracker.addImage(image, 0); try { tracker.waitForID(0); } catch (InterruptedException e) {} }
Exemple : code 2 public void paintComponent(Graphics g) { super.paintComponent(g); Dimension d = getSize(); int clientWidth = d.width; int clientHeight = d.height; int imageWidth = image.getWidth(this); int imageHeight = image.getHeight(this); g.drawImage(image, 0, 0, this); for (int i = 0; i * imageWidth <= clientWidth; i++) for (int j = 0; j * imageHeight <= clientHeight; j++) if (i + j > 0) g.copyArea(0, 0, imageWidth, imageHeight, i * imageWidth, j * imageHeight); } private Image image;
Exemple : code 3 class ImageFrame extends JFrame { public ImageFrame() { setTitle("ImageTest"); setSize(300, 200); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } } ); Container contentPane = getContentPane(); contentPane.add(new ImagePanel()); public class ImageTest { public static void main(String[] args) { JFrame frame = new ImageFrame(); frame.show();
Fichiers audio Les formats wav, au, aiff sont supportés. Utiliser la méthode play de la classe Applet : play(getCodeBase(), "son.au"); ou la classe AudioClip : AudioClip clip = getAudioClip(getCodeBase()"son.au"); clip.play(); clip.stop() clip.loop(); Appeler clip.stop dans la méthode stop de l’applet.
Fichiers midi Utiliser les classes du package javax.sound.midi Interfaces ControllerEventListener MetaEventListener MidiChannel MidiDevice Receiver Sequencer Soundbank Synthesizer Transmitter Classes Instrument MetaMessage MidiDevice.Info MidiEvent MidiFileFormat MidiMessage MidiSystem Patch Sequence Sequencer.SyncMode ShortMessage SoundbankResource SysexMessage Track VoiceStatus Exceptions InvalidMidiDataException MidiUnavailableException
Fichiers MPEG
Fichiers MPEG
Fichiers MPEG
Distribution d’applications Fichiers jar ou zip Les fichiers .class, .gif, .jpeg, etc… nécessaire à une application peuvent être rassemblés et compressés dans un fichier unique .jar ou .zip L’application sera alors lancée par java -jar NomFichier.zip ou java -jar NomFichier.jar Une archive peut ête créée avec l’utilitaire jar.exe du jdk Options de jar : c : crée une nouvelle archive et y place des fichiers t : affiche le contenu de l’archive f : indique le nom du fichier à créer v : sortie de message détaillée (verbose) m : ajoute un fichier manifest à l’archive
Distribution d’applications - 2 Manifest Un fichier Manifest.mf (par défaut) contient la description du contenu de l’archive, ainsi qu le chemin d’éventuels autres fichiers. Ex : Manifest-Version: 1.0 Main-Class: Source.Main.ClassePrincipale Class-Path: AutreArchive.jar Mise à jour sans recompilation Une mise à jour peut se faire simplement par l’actualisation de quelques fichiers .class, sans modifier les autres fichiers.
Environnements de développement : IDE JCreator Forte ou NetBeans de Sun Environnement complet, écrit en Java Permet d’écrire et déboguer en Java, Html, Xml, Jsp, C++, … Fonctionne sur toutes les plate-formes Disponible gratuitement avec le code source. http://www.netbeans.org
Servlets Une servlet est un programme qui s'éxécute côté serveur Elle reçoit une requête du client, elle effectue des traitements et renvoie le résultat, généralement sous forme de page HTML La servlet se positionne dans une architecture Client/Serveur trois tiers dans le tiers du milieu entre le client léger chargé de l'affichage et la source de données. Pour développer des servlets avec le JDK standard édition, il faut utiliser le Java Server Development Kit (JSDK) qui est une extension du JDK. Les programmes ou script CGI ( Common Gateway Interface) sont aussi utilisés pour générer des pages HTML dynamiques. Il existe plusieurs avantages à utiliser des servlets plutôt que des CGI : la portabilité offerte par Java la servlet reste en mémoire une fois instanciée ce qui permet de garder des ressources systèmes et gagner le temps de l'initialisation. Un CGI est chargé en mémoire à chaque requête, ce qui réduit les performances. les servlets possède les avantages de toutes les classes écrites en java
JDBC Java DataBase Connectivity pour l'accès aux bases de données à l'aide de Java. Ensembles de classes permettant de développer des applications capables de se connecter à des serveurs de base de données. JDBC a été conçu, comme Java, pour être indépendant de la plate-forme sur laquelle il est utilisé, c'est pourquoi il est basé sur SQL (Structured Query Language). Le package contenant les différentes classes exploitées par JDBC est java.sql. On distingue trois étapes permettant de travailler sur une base de données : Etablissement de la connexion avec la base de données. Envoi de la requête SQL à cette base. Traitement du résultat de cette requête.
RMI Remote Method Invocation : mécanisme qui permet d'appeler, dans un programme Java, une méthode se trouvant sur une machine distante et ce, de façon totalement transparente. On construit l'application comme si la méthode était localement disponible, en lui passant des arguments si besoin est. Ensuite, quand on exécute l'application, il va y avoir transmission de l'appel de la méthode à un serveur distant qui aura pour but d'exécuter cette méthode et de renvoyer le résultat de l'exécution à l'application demandeuse. Un tel système permet de centraliser certains développements et d'exécuter des calculs, opération parfois coûteuse en ressources, sur une machine distante. RMI masque la présence d'un réseau si bien que le programmeur n'a pas à connaître la moindre notion de programmation réseau. package java.rmi
Javadoc Javadoc Permet de générer des documentations normalisées Analyse les commentaires de type /** */ dans les classes et les méthodes. Ces commentaires peuvent contenir : du texte simple Des balises HTML de mise en forme Des tags spéciaux à javadoc, commençant par @
Javadoc : tags @author @version @params @see (see also) @link @since @return Syntaxe de la commande : Javadoc [options][nomsClasses…][nomspackages] Options : -d répertoire -public –protected –private –package -author –version -sourcepath
JNI Java Native Interface Les performances d'un programme Java ne seront jamais celles d'un code C++ optimisé savamment. Si pour une application donnée, pour certaines parties critiques, le temps d'exécution est crucial, vous pouvez les coder en C++. Pour les autres parties de l'application, vous pouvez utiliser le langage Java (interfaces graphiques notamment, ...). L’application n'est alors plus réellement portable. Ex : public class HelloWorld { static { System.loadLibrary("HelloWorld"); } public static native void printCpp(); public static void main(String args[]) System.out.print("Hello "); HelloWorld.printCpp(); }
JNI Ex : public class HelloWorld { // HelloWorld.dll (sous Windows) // libHelloWorld.so (sous Unix) static { System.loadLibrary("HelloWorld"); } // Déclaration de la méthode statique écrite en C++ public static native void printCpp(); public static void main(String args[]) System.out.print("Hello "); HelloWorld.printCpp(); } On peut échanger des données entre le code Java et le code C++.
Java vs C++ http://verify.stanford.edu/uli/java_cpp.html
Java vs C++ http://www.cs.colostate.edu/~cs154/PerfComp/
Java vs C++ http://www. javaworld
Java vs C++ http://www.cs.colostate.edu/~cs154/PerfComp/ Java has many advantages, but it also has a large disadvantage. Java performs many times slower than C++, especially when it comes to I/O operations. Modern day computers are very fast and the speed difference may often translate to waiting for 8 milliseconds for Java as opposed to 1 millisecond for C++. Java may be much slower, but, from the users perspective, there is relatively little difference. The advantages to Java outweigh its disadvantages in most cases. The ease of development, reusability and portability make Java well worth the time to learn.
Opérateurs - 1 Opérateurs numériques + - * / s ’appliquent sur des variables de n ’importe quel type numérique. Règles de priorité classiques. Attention : l ’opérateur + réalise aussi la concaténation de deux chaînes de caractères. Ex. System.out.println( "a = " + a + " ; b = " + b); affichera : a = 4 ; b = 8
Opérateurs - 2 Opérateurs unaires d ’incrémentation - décrémentation int a = 10; system.out.println(a); // affiche 10 a++; system.out.println(a); // affiche 11 a-- system.out.println(a++); // affiche 10 system.out.println(++a); // affiche 12
Expressions booléennes opérateur binaire ET : && opérateur binaire OU : || opérateur unaire NON : ! boolean b1 = true; boolean b2 = false; boolean b3 = true; boolean b4 = b1 || b2 || b3; // b4 vaut true boolean b5 = b1 && b2 && b3; // b5 vaut false boolean b6 = !(b1 && b2 && b3); // b6 vaut true boolean b7 = (b1 && b2) || b3; // b7 vaut true boolean b8 = (b1 || b2) && b3; // b8 vaut true // ----------------------------------------------- int a = 10; int b = 12; boolean sontEgaux = (a == b) ; // sontEgaux vaut false boolean sontDiff = (a < b || b > a) ; // sontDiff vaut true
Affectation L'opérateur d'affectation est noté = Ne pas le confondre avec l'opérateur de comparaison == Lors d'une affectation, la valeur de l'expression à droite du signe = est d'abord calculée, puis placée dans la variable située à gauche de l'opérateur. L'affectation est elle-même une expression qui retourne la valeur calculée. Ex. int a, b ; a = 5 + 5; // affectation; a vaut 10 b = a + 10; // affectation; b vaut 15 a = a + b ; // affectation; a vaut 25 System.out.println (b); // affiche 15 System.out.println (b + 5); // affiche 20 System.out.println (b = a); // affiche 25 System.out.println (b); // affiche 25
Affectations - 2 Ex. int a, b ; a = 2; // a vaut 2 Les opérateurs += -= *= /= calculent la valeur de droite par rapport à la valeur actuelle de la variable. Ex. int a, b ; a = 2; // a vaut 2 b = 10; // b vaut 10 a += b; // identique à a = a + b ; a vaut 12 a += a; // identique à a = a + a ; a vaut 24 b -= a; // identique à b = b - a ; b vaut -12 a %= b; // identique à a = a % b; a &= b; // identique à a = a & b; a |= b; // identique à a = a | b; a ^= b; // identique à a = a ^ b;
Structures de contrôle - 1 Instruction conditionnelle if if (condition) { bloc1 } [else { bloc2 }] public class Essai { static public void main(String args[]) // On récupère le nombres de paramètres // saisis sur la ligne de commande // c.à.d. le nombre d'éléments du tableau args int nbParam = args.length; if (nbParam < 1) System.out.println("Entrez un paramètre"); } else System.out.println(args[0]);
Structures de contrôle - 2 Boucle for for (instruction1 ; expression; instruction2) { bloc } // Afficher les nombres de 0 à 9 for(int i=0; i < 10; i++) { System.out.println("i vaut : " + i); } // initialiser et afficher les éléments d'un tableau : int [] tab = new int[10]; int i; for( i = 0; i < 10; i++) tab[ i ] = i * 5; System.out.println(tab[ i ]); Boucle while while (condition) { bloc } i = 0; while (i < 10) { tab[ i ] = i * 5; System.out.println(tab[ i ]); i = i+1; } Boucle do while do { bloc } while (condition); i = 0; do { tab[ i ] = i * 5; System.out.println(tab[ i ]); i = i+1; } while (i < 10);
Structures de contrôle - 3 Sélection multiple : instruction switch // On lit un nombre du clavier int choix = Console.readInt("Donnez votre choix, de 1 à 4 : "); switch (choix) { case 1 : { bloc d'instructions 1} break; case 2 : { bloc d'instructions 1} case 3 : { bloc d'instructions 1} case 4 : { bloc d'instructions 1} default : System.out.println(" Choix invalide…"); } La variable de sélection ( ici, choix ) doit être d'une type entier ou char
Structures de contrôle - 4 L'instruction break n'est pas obligatoire switch (c) // c est un caractère { case '1': case '3': case '5': case '7': case '9': System.out.println(‘c’ + " est un chiffre impair"); break; case '0': case '2': case '4': case '6': case '8': System.out.println(‘c’ + " est un chiffre pair"); default : System.out.println(‘c’ + " n ’est pas un chiffre"); } Ceci permet de compenser l'absence d'intervalles pour la variable de sélection.
Exemple : utiliser une classe La classe Double "encapsule" le type primitif double et fournit diverses méthodes. Construire un objet de type Double à partir d'une variable de type double: Double D1 = new Double(12.5); Construire un objet de type Double à partir d'une variable de type String: Double D2 = new Double("12.5"); Récupérer la valeur de type double d'un objet Double : double x = D1.doubleValue(); On peut utiliser directement certaines méthodes de la classe Double, sans instancier d'objet (méthodes statiques) : par ex. convertir directement une chaîne (String) en réel (double) : String chaine = "123.45"; double x = Double.parseDouble( chaine ); // valeur de x : 123.45 De même on peut utiliser la classe Integer qui encapsule le type primitif int : String chaine = "123"; int n = Integer.parseInt( chaine ); // valeur de n : 123 Une classe est dite abstraite si une de ses méthode au moins n'est pas implémentée (méthode abstraite). Une classe abstraite ne peut pas être instanciée. Une classe dérivée d'une classe abstraite doit implémenter toutes les méthodes abstraites pour pouvoir être instanciée. abstract public class ObjetGéométrique { . . . // Calcul de l'aire abstract public double aire(); // Calcul du périmètre abstract public double perimetre(); } ObjetGéométrique unObjet; unObjet = new ObjetGéométrique(. . .);
Surcharge de méthodes Même nom, arguments de nombre ou types différents public class Cercle { // Constructeurs Cercle() this(0.0, 0.0, 1.0); } Cercle(double x, double y, double r) xCentre = x; yCentre = y; if(r > 0.0) rayon = r; else rayon = 1.0; // Définition des méthodes void setCentre(double x, double y) { xCentre = x; yCentre = y; } void setCentre(Point2D c) xCentre = c.getX(); yCentre = c.getY(); . . .
Héritage : exemple - 1 Définition d'une classe décrivant une ellipse : public class Ellipse { // Consructeurs Ellipse() this(0.0, 0.0, 1.0, 1.0); } Ellipse(double x, double y, double r1, double r2) rayon1 = r1; rayon2 = r2; xCentre = x; yCentre = y; // Méthodes void setRayon1() { . . . } void setRayon2() double getRayon1() . . . double aire() return . . . // Attributs protected double xCentre; protected double yCentre; protected double rayon1; protected double rayon2; }
Héritage : exemple - 2 Ellipse Cercle Un cercle est un cas particulier d'ellipse (rayon1 = rayon2). On peut dire : un cercle "est une sorte" d'ellipse la classe Cercle hérite de la classe Ellipse la classe Cercle est dérivée de la classe Ellipse la classe Ellipse est parent de la classe Cercle Ellipse Cercle // Méthodes void setRayon(double r) { if( r >= 0) rayon1 = r; } double getRayon() return rayon1; // Pas d'attributs // on utilise ceux de la classe // de base déclarés protected La classe Cercle devient : public class Cercle extends Ellipse { // Constructeurs // Appel des constructeurs de la classe Ellipse Cercle(double x, double y, double r) super(x, y, r, r); } Cercle() // super() cet appel est implicite
Héritage : exemple - 3 // On crée un cercle et une ellipse Cercle unCercle(); unCercle = new Cercle(1.0, 1.0, 4.0); Ellipse uneEllipse(); uneEllipse = new Ellipse (5.0, 5.0, 4.0, 3.0); // On calcule les aires des deux objets : double aC = unCercle.aire(); // la méthode aire de la classe Cercle est appelée double aE = uneEllipse .aire(); // la méthode aire de la classe Ellipse est appelée Une classe ne peut hériter (extends) que d'une seule classe. Une référence d'une classe C peut contenir des instances de C ou des classes dérivées de C. Ellipse uneEllipse(); uneEllipse = new Cercle (5.0, 5.0, 4.0); // correct Cercle unCercle(); unCercle = new Ellipse (5.0, 5.0, 4.0, 3.0); // incorrect Les classes final ne peuvent pas être redéfinies dans les sous-classes. Toutes les classes dérivent de java.lang.Object . L'opérateur instanceof permet de déterminer la classe d'une instance. unCercle = new Cercle(1.0, 1.0, 4.0); System.out.println(unCercle instanceOf Cercle); // affiche true
Interfaces - 3 On définit l'interface Vehicule (fichier Vehicule.java) public interface Véhicule { public int nbRoues(); public String énergie(); public double vMax(); public void ajouterKm(int nbKm); public int getDistanceParcourue(); } et la classe abstraite Voiture qui l'implémente en partie (fichier Voiture.java) public abstract class Voiture implements Vehicule public int nbRoues(){return 4;} public void ajouterKm(int nbKm){ km = km + nbkm;} public int getDistanceParcourue(){return km;} protected int km; enfin la classe R5D (fichier R5D.java) public class R5D extends Voiture implements Vehicule public String énergie(){return "Gazole";} public double vMax(){return 125.0;}
Classes internes Une classe interne est une classe définie à l'intérieur d'une autre classe. Un objet d'une classe interne peut accéder à toutes les données, même privées, de l'objet qui l'a créé. Les classes internes peuvent être cachées aux autres classe d'un même package. Elles sont souvent utilisées pour décrire des gestionnaires d'évènements. public class Avion { . . . public class Pilote public Pilote(); public String getNom() { return nom;} public int heuresDeVol() { . . .} } public Avion(){ . . . } public Pilote getPilote() { return lePilote; } private Pilote lePilote;
Les packages standards de l ’API lang : classes liées au langages : opérations et types de base awt (abstract Window Toolkit) : méthodes d'accès à toutes les ressources graphiques de la machine. io : opérations d'entrées/sorties. applet : pour la réalisation d’applets (application pouvant s'exécuter dans un navigateur Internet. beans : pour la programmation orientée composants. sql : accès aux bases de données. rmi (Remote Method Ivocation) : pour mettre en place des applications réparties. util : divers utilitaires ...
Packages Utilisation des packages : mot-clé import import java.awt.*; Déclaration des packages . Par exemple, pour créer un package appelé monpackage, placer le mot-clé package au début du fichier : package monpackage; public class Bonjour { . . . } Les fichiers constituant ce package doivent être placés dans un sous-répertoire nommé comme le package (ici, monpackage). Maintenant, n’importe quel autre programme peut, pour accéder aux classes déclarées dans monpackage, utiliser : import monpackage.*;
Classes internes anonymes La classe DatFilter de l'exemple précédent n'est utilisée qu'une fois. On peut éviter la définition indépendante de cette classe en la définissant directement au moment de l'instancier, sans lui donner de nom : File dir = new File("."); File[] datFiles = dir.listFiles(new FileFilter() { public boolean accept(File pathname) return pathname.getPath().endsWith(".dat"); } }); int nbFiles = datFiles.length; . . .