Le langage JAVA - IPNL
Le langage JAVA - IPNL
Le langage JAVA - IPNL
Create successful ePaper yourself
Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.
<strong>Le</strong> <strong>langage</strong> <strong>JAVA</strong><br />
G. Baulieu Institut de Physique Nucléaire de Lyon – Septembre 2009
Quelques acronymes<br />
●<br />
●<br />
●<br />
●<br />
●<br />
JDK : Java Development Kit<br />
SDK : Software Development Kit<br />
J2SE : Java 2 Standard Edition<br />
JRE : Java Runtime Environment<br />
API : Application Programming Interface
Points forts<br />
●<br />
●<br />
●<br />
●<br />
●<br />
Simplicité : syntaxe ~C++ simplifié (pointeurs,<br />
fichiers d'entête, surcharge des opérateurs...)<br />
Orienté objet<br />
Fiabilité : gestion de la mémoire, compilateur<br />
puissant<br />
Portabilité : executable sur plusieurs systèmes<br />
Bibliothèque importante et documentée
Naissance de Java<br />
Java est un <strong>langage</strong> très récent...<br />
● 1991 : Projet Green (P. Naughton/J. Gosling – Sun)<br />
Langage Oak<br />
● 1996 : Java 1.0 – Premiere version officielle<br />
● 2004 : JDK 1.5 "Java 5.0"<br />
● 2006 : JDK 1.6 "Java 6.0"
La machine virtuelle<br />
Code source<br />
Compilation<br />
Bytecode (pseudocode)<br />
Indépendant du<br />
système<br />
Interprétation<br />
Machine Virtuelle<br />
Génération<br />
Dépendant du<br />
système<br />
Langage machine
Notions fondamentales<br />
1. Premiers pas<br />
1. Structure d'un programme<br />
2. Compilation / Execution<br />
3. Localisation des classes<br />
2. Types de données<br />
3. Déclaration de variables<br />
4. <strong>Le</strong>s tableaux<br />
5. <strong>Le</strong>s opérateurs<br />
7. <strong>Le</strong>s structures de contrôle<br />
1. Conditions (IF)<br />
2. Boucles (FOR, WHILE, DO...WHILE)<br />
3. SWITCH<br />
4. Interruption de boucle<br />
8. <strong>Le</strong>s méthodes<br />
1. Généralités<br />
2. La méthode "main"<br />
6. <strong>Le</strong>s conversions de type
1.1 Structure d'un programme<br />
Fichier PremiereClasse.java<br />
/*<br />
Premier exemple de programme<br />
*/<br />
public class PremiereClasse<br />
{<br />
// Fonction principale<br />
public static void main(String[] args)<br />
{<br />
System.out.println("Premier programme!");<br />
}<br />
}<br />
Commentaires<br />
entre /* et */<br />
ou ligne précédée de //<br />
Déclaration de<br />
la classe<br />
Fonction<br />
principale
1.2 Compilation d'un programme<br />
●<br />
<strong>Le</strong> fichier doit porter le nom de la classe<br />
Dans notre exemple : PremiereClasse.java<br />
● Compilation :<br />
$ javac PremiereClasse.java<br />
Génère un fichier PremiereClasse.class<br />
● Execution :<br />
$ java PremiereClasse
1.3 Localisation des classes<br />
●<br />
●<br />
Par défaut : uniquement le répertoire courant<br />
Ajout de répertoires<br />
– Par l'option classpath :<br />
$ java classpath ./classes/ PremiereClasse<br />
– Par la variable d'environnement CLASSPATH :<br />
$ export CLASSPATH=./classes/<br />
$ java PremiereClasse
2. Types de données<br />
●<br />
●<br />
Java est un <strong>langage</strong> fortement typé<br />
8 types primitifs:<br />
– Entiers<br />
byte 8 bits -128 à 127<br />
short 16 bits -32 768 à 32 767<br />
int 32 bits -2 147 483 648 à 2 147 483 647<br />
-9 223 372 036 854 775 808<br />
long 64 bits à<br />
9 223 372 036 854 775 807
2. Types de données (2)<br />
– Virgule flottante<br />
float 32 bits 6 décimales significatives<br />
double 64 bits 15 chiffres significatifs<br />
– <strong>Le</strong> type char (16 bits)<br />
Une unité de code UTF16<br />
– <strong>Le</strong> type boolean (1 bit)<br />
Deux valeurs : true et false<br />
Il n'existe pas de type chaîne de caractères. On utilisera la<br />
classe String.
3. Déclaration de variable<br />
●<br />
Indication du type suivi du nom de la variable:<br />
●<br />
●<br />
int compteur;<br />
double aire;<br />
La variable doit ensuite être initialisée:<br />
compteur = 0;<br />
aire = 3.54;<br />
On peut déclarer et initialiser une variable dans la même<br />
instruction:<br />
int compteur = 0;<br />
● <strong>Le</strong> mot clé final permet de déclarer une constante :<br />
final int COMPTEUR = 0;
4. <strong>Le</strong>s tableaux<br />
●<br />
●<br />
Structure permettant de stocker une série de valeurs du même type.<br />
Déclaration et initialisation:<br />
int[] tab;<br />
tab = new int[10];<br />
> déclare la variable tab et lui alloue l'espace mémoire pour 10<br />
valeurs de type int.<br />
Remarque : "int tab[]" est également valable.<br />
●<br />
Affectation:<br />
tab[5] = 3;<br />
> Affecte la valeur 3 à la sixième case du tableau (l'indice commence à 0!).
4. <strong>Le</strong>s tableaux (2)<br />
● <strong>Le</strong>cture :<br />
int i = tab[5];<br />
> La variable i contient la valeur de la sixième case du<br />
tableau.<br />
●<br />
Raccourci:<br />
int[] tab = {3,24,5,3,6,54,7,1,6,45};<br />
> Déclare, initialise et affecte les valeurs au tableau tab.
4. <strong>Le</strong>s tableaux (3)<br />
●<br />
Taille du tableau:<br />
int taille = tab.length;<br />
●<br />
Copie d'un tableau :<br />
– Copie de la variable :<br />
int[] secondArray = tab;<br />
secondArray[0] = 33;//tab[0] vaut 33!!!<br />
– Utilisation de la fonction arraycopy(from,fromIdx,to, toIdx, count)<br />
int[] secondArray = new int[5];<br />
System.arraycopy(tab, 0, secondArray, 0, 5);//copie les 5 premiers<br />
éléments de tab dans secondArray – attention à la taille de<br />
secondArray!<br />
●<br />
Tri d'un tableau :<br />
int[] tab = {3,24,5,3,6,54,7,1,6,45};<br />
java.util.Arrays.sort(tab);//tab contient maintenant<br />
{1,3,3,5,6,6,7,24,45,54}
5. Opérateurs<br />
● Affectation : =<br />
● Addition, soustraction et multiplication : +, , *<br />
● Division : /<br />
– Si appelé avec 2 entiers : division entière<br />
– Sinon division en virgule flottante<br />
●<br />
On peut combiner opérateurs arithmétiques et opérateurs<br />
d'affectation : +=, =, *= ...<br />
int n = 2;<br />
n += 3; // n vaut 5
5. Opérateurs (2)<br />
● Incrémentation, décrémentation : ++,int<br />
m = 1;<br />
m++; //m vaut 2<br />
int n = 2;<br />
int a = 2 * ++m; //a vaut 6, m vaut 3<br />
int b = 2 * n++; //b vaut 4, n vaut 3<br />
● Opérateurs relationnels : ==, !=, >, =,
6. Conversions<br />
●<br />
●<br />
Si besoin, les valeurs peuvent être converties<br />
automatiquement :<br />
int i = 123;<br />
long l = i;<br />
Attention : dans certains cas cela peut entraîner une perte<br />
de précision:<br />
– int vers float<br />
– long vers float<br />
– long vers double
6. Conversions (2)<br />
● On peut faire une conversion explicite :<br />
double d = 4.321;<br />
int i = (int)d; // i vaut 4<br />
Autre exemple :<br />
int i=3;<br />
double d1 = 5/i; // d1 vaut 1.0 !<br />
double d2 = 5/(double)i; // d2 vaut 1.6667
7.1 Conditions IF<br />
●<br />
Syntaxe de l'instruction conditionnelle:<br />
if (condition) instruction<br />
– La condition est une expression booléenne, indiquée entre<br />
parenthèses.<br />
– L'instruction peut être unique, ou on peut en placer plusieurs dans<br />
un bloc d'instructions (instructions entre accolades).<br />
●<br />
Exemples<br />
if(x
7.1 Conditions(2) ELSE<br />
●<br />
●<br />
●<br />
Instruction else:<br />
if (condition) instruction1 else instruction2<br />
if(x
7.2 <strong>Le</strong>s boucles FOR<br />
●<br />
Boucle gérée par un compteur:<br />
for(initialisation;test;mise à jour)<br />
instruction(s);<br />
● Exemple :<br />
for (int i=0;i Affiche les valeurs de i de 0 à 9.
7.2 <strong>Le</strong>s boucles (2) – FOR EACH<br />
●<br />
●<br />
Simplification pour les tableaux et collections<br />
Version classique ('tab' est un tableau de doubles):<br />
for (int i=0;i
7.2 <strong>Le</strong>s boucles (3) WHILE<br />
●<br />
Boucle tant que la condition est vraie.<br />
while(condition)<br />
instruction(s);<br />
● Exemple :<br />
while(nbSucre
7.2 <strong>Le</strong>s boucles (4) DO...WHILE<br />
●<br />
Répète l'instruction jusqu'à ce que la condition soit vraie.<br />
do<br />
instuction(s);<br />
while(condition);<br />
<strong>Le</strong>s instructions sont exécutées au moins une fois.<br />
●<br />
Exemple<br />
do{<br />
}<br />
System.out.println("Saisir une valeur positive : ");<br />
//affectation d'une valeur saisie par l'utilisateur<br />
dans la variable double "reponse"<br />
while(reponse
7.3 L'instruction SWITCH<br />
●<br />
Permet de gérer les différentes valeurs prisent par une<br />
variable entière.<br />
● Syntaxe :<br />
switch(variable){<br />
case 1:<br />
}<br />
...<br />
break;<br />
case 2:<br />
...<br />
break;<br />
default:<br />
...<br />
break;
7.4 Interruption de boucle<br />
●<br />
L'instruction break permet de sortir immédiatement d'une<br />
boucle.<br />
●<br />
L'instruction continue court circuite la fin de boucle.<br />
while(true){<br />
...<br />
if(stop)<br />
}<br />
break;<br />
...<br />
if(shortcut)<br />
continue;<br />
...
7.4 Interruption de boucle (2)<br />
●<br />
On peut également sortir de boucles imbriquées en utilisant<br />
un label:<br />
label_name:<br />
while(...){<br />
...<br />
while(...){<br />
}<br />
}<br />
if(stop)<br />
break label_name; // sort des boucles<br />
...<br />
... à utiliser avec parcimonie...
8.1 <strong>Le</strong>s méthodes<br />
●<br />
Une méthode est une suite d'instructions permettant de<br />
réaliser des traitements sur les données.<br />
● Déclaration :<br />
type_de_retour Nom(liste d'arguments){<br />
Corps_de_la_méthode<br />
return valeur_de_retour<br />
}<br />
int addition(int a, int b){<br />
int resultat = a+b;<br />
return resultat;<br />
}<br />
Si la méthode ne retourne rien, on utilise le type de retour void.<br />
● Appel de la méthode :<br />
int somme = addition(3,5);//somme vaut 8 après l'appel
8.2 La méthode main<br />
●<br />
●<br />
●<br />
Point d'entrée dans le programme (obligatoire!)<br />
Prototype:<br />
public static void main(String[] args)<br />
{<br />
...<br />
}<br />
<strong>Le</strong> tableau args contient les arguments passés dans la ligne de<br />
commande :<br />
1er argument : args[0]<br />
2ème argument : args[1] ...
Programmation orientée objet<br />
1. Introduction<br />
1. Vocabulaire<br />
2. Exemple : la classe Color<br />
3. Utilisation des paquetages<br />
4. La classe String<br />
3. Ajouter une classe dans un paquetage<br />
4. Documenter le code : <strong>JAVA</strong>DOC<br />
5. <strong>Le</strong>s fichiers JAR<br />
6. Un outil de construction : ANT<br />
5. <strong>Le</strong>s classes Integer, Double...<br />
2. Création d'une classe<br />
1. <strong>Le</strong>s champs<br />
2. <strong>Le</strong>s constructeurs<br />
3. Libération de la mémoire<br />
4. <strong>Le</strong>s méthodes<br />
5. <strong>Le</strong> mot clé this<br />
6. L'instruction static
1. Introduction<br />
●<br />
●<br />
Décomposer le programme en modules indépendants : les<br />
objets.<br />
Chaque objet contient sa structure de données (les<br />
champs) et les traitements possibles sur ces données (les<br />
méthodes).<br />
Modifier la structure des données ou<br />
le traitement de cellesci ne modifie<br />
pas le programme général.
1.1 Vocabulaire<br />
●<br />
●<br />
●<br />
Une classe contient la description des données d'un objet<br />
ainsi que les traitements pouvant être effectués sur celuici<br />
(= le moule).<br />
On peut ensuite créer une ou plusieurs "instance(s) de la<br />
classe" (= les biscuits).<br />
<strong>Le</strong>s données de l'objet ne seront pas accessibles à<br />
l'utilisateur : c'est l'encapsulation.<br />
Si les données de l'objet sont incohérentes, l'erreur est<br />
obligatoirement dans la classe! Nul besoin d'aller chercher<br />
partout dans le programme...
1.2 Exemple : la classe Color<br />
●<br />
L'API java met à notre disposition la classe java.awt.Color<br />
● Création d'une instance de la classe :<br />
java.awt.Color maCouleur = new java.awt.Color(255,255,255);//Création<br />
d'une instance contenant la couleur blanche
1.3 Interlude : <strong>Le</strong>s paquetages<br />
● But :<br />
– Structurer les classes<br />
– Faciliter la recherche d'une classe<br />
– Eviter les confusions entre classes de même nom<br />
– Modifier la visibilité d'une classe
1.3 L'instruction import<br />
●<br />
Permet de créer un raccourci pour faire référence aux<br />
classes d'un paquetage:<br />
import java.awt.Color;<br />
class [...]{<br />
[...]<br />
Color maCouleur = new Color(255,255,255);<br />
● On peut également utiliser :<br />
import java.awt.*;<br />
...pour pouvoir accéder à toutes les classes du paquetage<br />
java.awt.
1.2 Exemple : la classe Color(2)<br />
●<br />
On peut créer différentes instances de la même classe:<br />
Color blanc = new Color(255,255,255);<br />
Color rouge = new Color(255,0,0);<br />
<strong>Le</strong>s 2 objets ont une existence propre!<br />
●<br />
On peut appeler différentes méthodes sur les objets:<br />
int valeurRouge = rouge.getRed(); // valeurRouge vaut 255<br />
Appel de la méthode getRed() appartenant à la classe Color<br />
sur l'objet 'rouge'.
1.2 Exemple : la classe Color(3)<br />
● <strong>Le</strong> programme suivant :<br />
Color rouge = new Color(255,0,0);<br />
System.out.println(rouge);<br />
Color rougeSombre = rouge.darker();<br />
System.out.println(rougeSombre);<br />
● Affiche :<br />
java.awt.Color[r=255,g=0,b=0]<br />
java.awt.Color[r=178,g=0,b=0]<br />
●<br />
Comment connaître les méthodes d'une classe?<br />
Grâce à la documentation de la classe!<br />
http://java.sun.com/j2se/1.5.0/docs/api/
1.2 Exemple : la classe Color(4)
1.4 La classe String<br />
● Déclaration :<br />
String vide = new String(""); // ou String vide = "";<br />
String exemple = "Chaine de caractères";<br />
● Longueur :<br />
int taille = exemple.length();<br />
● Concaténation :<br />
String nouvelleChaine = "Exemple d'une "+exemple;<br />
● Sous chaines :<br />
String petiteChaine = exemple.substring(0,7);<br />
● Egalité :<br />
boolean sontEgales = exemple.equals("test");
1.5 Classes Integer, Double...<br />
Il est parfois utile de pouvoir utiliser les types de base comme des<br />
objets. L'API Java dispose de classes wrapper:<br />
Integer objectInt = new Integer(5);<br />
La conversion est faite automatiquement :<br />
int i = objectInt; //equivalent à objectInt.intValue()<br />
Ces classes permettent aussi la conversion de chaines de<br />
caractères :<br />
int i = Integer.parseInt(“234”);
2. Création d'une classe<br />
● Une classe est composée :<br />
● De champs : données propres à l'objet.<br />
● De constructeurs : méthodes permettant d'instancier un<br />
objet (création de l'objet).<br />
● De methodes : services offerts par la classe pour<br />
manipuler l'objet.
2.1 <strong>Le</strong>s champs de la classe<br />
●<br />
Ce sont les données qui seront contenues dans une<br />
instance de la classe.<br />
●<br />
Déclaration:<br />
class Personne{<br />
private String nom;<br />
private String prenom;<br />
...<br />
}
2.1 <strong>Le</strong>s champs de la classe (2)<br />
Portée des champs :<br />
●<br />
private indique que le champ n'est accessible que de l'intérieur<br />
de la classe (encapsulation).<br />
On pourrait (mais on ne le veut probablement pas!) déclarer les<br />
champs:<br />
●<br />
●<br />
public : toujours visible par tous.<br />
protected : visible pour le paquetage et les classes filles (voire<br />
héritage).<br />
<strong>Le</strong>s méthodes de la classe utilisent les mêmes modificateurs de<br />
visibilité.
2.1 <strong>Le</strong>s champs de la classe (3)<br />
●<br />
Initialisation explicite<br />
On peut initialiser les champs de la classe au moment de la déclaration :<br />
class Personne{<br />
private String nom = "";<br />
private String prenom = "";<br />
...<br />
}<br />
Cette affectation est effectuée avant l'appel du constructeur.
2.2 <strong>Le</strong>s constructeurs<br />
●<br />
Méthode permettant d'instancier un objet.<br />
●<br />
<strong>Le</strong> constructeur alloue la mémoire pour les champs de<br />
l'objet et les initialise.<br />
●<br />
●<br />
<strong>Le</strong> constructeur est une méthode ayant le même nom que la<br />
classe :<br />
public Personne(){<br />
nom = "X";<br />
prenom = "Toto";<br />
}<br />
Cette méthode est appelée lors de l'instruction:<br />
Personne p = new Personne();
2.2 <strong>Le</strong>s constructeurs (2)<br />
●<br />
Si aucun constructeur n'est défini, java crée un constructeur<br />
par défaut (sans argument). Ce constructeur initialise les<br />
champs de la classe :<br />
– numérique : 0<br />
– booléen : false<br />
– classe : null (inexistant)<br />
Pour des raisons de lisibilité, il est préférable d'écrire<br />
explicitement un constructeur.
2.2 <strong>Le</strong>s constructeurs (3)<br />
●<br />
On peut définir plusieurs constructeurs pour une même classe<br />
(surcharge):<br />
public Personne(){<br />
nom = "X";<br />
prenom = "Toto";<br />
}<br />
public Personne(String n, String p){<br />
nom = n;<br />
prenom = p;<br />
}<br />
● Appel :<br />
Personne p1 = new Personne();// Toto X<br />
Personne p2 = new Personne("Dupont", "Jean");// Jean Dupont
2.3 Libération de la mémoire<br />
●<br />
●<br />
La libération de la mémoire est effectuée par java par<br />
l'intermédiaire du ramassemiettes (garbage collector).<br />
Il n'y a donc pas de destructeurs.<br />
●<br />
Si une ressource doit absolument être libérée il faut<br />
explicitement appeler une méthode écrite dans ce but.
2.4 <strong>Le</strong>s méthodes de la classe<br />
●<br />
Fournissent des fonctionnalités à la classe.<br />
●<br />
<strong>Le</strong>s méthodes seront appelées par une instance de la<br />
classe :<br />
Personne p = new Personne();<br />
String nom = p.getNom();<br />
● Implémentation :<br />
public String getNom(){<br />
return nom;<br />
}
2.4 <strong>Le</strong>s méthodes de la classe (2)<br />
<strong>Le</strong>s méthodes d'une classe ont accès aux champs privés de la<br />
classe et peuvent donc les modifier.<br />
public void setNom(String n){<br />
}<br />
nom = n;<br />
Personne p = new Personne();<br />
p.setNom("Dupont");//impossible si setNom etait private !<br />
Rappel : une méthode peut être définie comme public, private ou<br />
protected<br />
Implémenter la méthode String toString() permet d'afficher l'objet avec<br />
System.out.println();<br />
Implémenter la méthode Object clone() permet de renvoyer une copie de<br />
l'objet.
2.5 <strong>Le</strong> mot clé this<br />
Fait référence à l'instance courante de la classe:<br />
void setNom(String nom){<br />
}<br />
this.nom = nom;<br />
Il peut également être utilisé pour appeler un constructeur<br />
depuis un autre constructeur :<br />
public Personne(){<br />
}<br />
this("Dupuis", "Paul"); // Premiere instruction!!<br />
// <strong>Le</strong> constructeur Personne(String, String) est appelé
2.6 L'instruction static<br />
●<br />
●<br />
●<br />
Permet de définir des variables et méthodes de classe.<br />
Une variable statique est commune à toutes les instances de la<br />
classe.<br />
Une méthode (ou une variable) statique peut être appelée sans<br />
instance, avec le nom de la classe :<br />
double r = Math.sqrt(81);// appel de la méthode statique sqrt()<br />
de la classe Math.<br />
●<br />
Une méthode statique ne peut accéder qu'aux champs<br />
statiques de la classe.
3. Ajouter une classe dans un<br />
paquetage<br />
● Syntaxe :<br />
package Formation.Java.Exemples;<br />
class MaClasse{...}<br />
La classe MaClasse se trouve dans le paquetage<br />
"Formation.java.Exemples" : le fichier MaClasse.class devra donc se<br />
trouver dans le répertoire :<br />
[...]/Formation/Java/Exemples/
4. Documenter le code : Javadoc<br />
●<br />
●<br />
Outil permettant de générer de la documentation à partir du<br />
code source.<br />
Nécessite des commentaires dans le code:<br />
Commentaires situés entre /** et */<br />
●<br />
Documentation d'une classe:<br />
/** Commentaire décrivant la classe.<br />
@version 1.0<br />
@author Jules Dupont<br />
*/<br />
public class MaClasse {...}
4. Javadoc (2)<br />
●<br />
Documentation d'un méthode:<br />
/** Commentaire décrivant la méthode.<br />
@param a Description de l'argument a<br />
@param b Description de l'argument b<br />
@return <strong>Le</strong> résultat de la méthode<br />
*/<br />
public int addition(int a, int b){...}<br />
●<br />
Génération:<br />
% javadoc author version d ./doc/ MaClasse.java
4. Javadoc (3)<br />
http://java.sun.com/j2se/javadoc/
5. Créer une archive : les<br />
fichiers JAR<br />
●<br />
●<br />
●<br />
Java ARchive<br />
Permet de stocker tous les fichiers (.class, images, sons...)<br />
dans un seul fichier.<br />
Peut être compressé.<br />
● Création de l'archive :<br />
% jar cf NomArchive.jar Fichiers
5. <strong>Le</strong>s fichiers JAR (2)<br />
●<br />
On peut ajouter un fichier MANIFEST.MF qui contient des<br />
informations sur l'archive :<br />
ManifestVersion: 1.0<br />
MainClass: Formation/MaClasse<br />
●<br />
Création de l'archive:<br />
% jar cfm NomArchive.jar MANIFEST.MF Fichiers<br />
● On peut alors lancer le programme par la commande :<br />
% java jar NomArchive.jar
6. Un outils de construction :<br />
ANT<br />
●<br />
●<br />
●<br />
Il est fastidieux de devoir taper de longues commandes à<br />
chaque modification.<br />
Dans un projet conséquent, il peut y avoir plusieurs<br />
commandes à exécuter pour compiler, créer des archives,<br />
générer la documentation, créer une distribution...<br />
ANT (~make) permet de simplifier ces procédures en<br />
définissant des taches pouvant dépendre les une des<br />
autres.
6. Un outils de construction :<br />
ANT (2)<br />
– On défini des taches dans le fichier build.xml :<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
– On peut ensuite exécuter une tache avec la commande :<br />
% ant nom_de_la_tache<br />
Exemple : % ant compile
L'héritage<br />
1. Introduction<br />
1. Concept<br />
2. Exemple<br />
2. Syntaxe<br />
6. <strong>Le</strong>s interfaces<br />
1. Utilisation<br />
2. Création<br />
7. <strong>Le</strong> clonage<br />
1. <strong>Le</strong> mot clé extends<br />
2. <strong>Le</strong>s constructeurs<br />
3. <strong>Le</strong>s méthodes<br />
4. Interdire l'héritage<br />
3. <strong>Le</strong> polymorphisme<br />
4. Classes et méthodes abstraites<br />
5. La classe Object
1.1 Concept<br />
●<br />
●<br />
●<br />
L'idée est de pouvoir créer de nouvelles classes à partir de<br />
classes existantes.<br />
Exprime la relation "est un". Par exemple, un lion est un<br />
animal : la classe 'Lion' peut donc hériter de la classe<br />
'Animal'. Elle dispose ainsi automatiquement de toutes les<br />
données et services de la classe 'Animal'.<br />
La classe 'Animal' est appelée classe mère ou superclasse<br />
et la classe 'Lion' classe fille ou sousclasse.
1.2 Exemple<br />
<strong>Le</strong> lion et l'oiseau sont des animaux : ils ont une taille, une couleur,<br />
peuvent manger et dormir.<br />
Seul le lion peut rugir et seul l'oiseau peut voler.<br />
On peut ajouter des champs spécifiques à la classe fille.
1.2 Exemple (2)<br />
● La classe Animal :<br />
import java.awt.Color;<br />
class Animal{<br />
private Color couleur;<br />
private int taille;<br />
public Animal(){...}<br />
public Animal(Color c, int t){...}<br />
}<br />
public void Manger(){...}<br />
public void Dormir(){...}<br />
public Color getCouleur(){...}<br />
public int getTaille(){...}
2.1 <strong>Le</strong> mot clé extends<br />
● On utilise le mot clé extends pour marquer l'héritage :<br />
class Lion extends Animal{<br />
private Color couleurCriniere;<br />
}<br />
public void Rugir(){...}<br />
public void setCouleurCriniere(Color c){...}<br />
public Color getCouleurCriniere(){...}<br />
● Utilisation :<br />
Lion leo = new Lion();<br />
leo.Rugir();<br />
leo.Dormir();<br />
On ne peut hériter que d'une seule classe!
2.2 <strong>Le</strong>s constructeurs<br />
● Constructeur par défaut :<br />
public Lion(){<br />
}<br />
super();<br />
couleurCriniere = new Color(125, 125, 125);<br />
<strong>Le</strong> mot clé super permet d'appeler un constructeur de la classe mère.<br />
● Autre constructeur :<br />
public Lion(Color c, int t, Color criniere){<br />
}<br />
super(c, t);<br />
couleurCriniere = new Color(criniere.getRed(), criniere.getGreen(),<br />
criniere.getBlue());<br />
L'appel au constructeur de la classe mère est toujours la première instruction du<br />
constructeur de la classe fille.
2.3 <strong>Le</strong>s méthodes<br />
●<br />
La classe fille hérite de toutes les méthodes de la classe mère. Par<br />
exemple si la classe Animal contient la méthode :<br />
public String toString(){<br />
}<br />
return "Je mesure "+taille+" cm et je suis de couleur "+couleur;<br />
On peut alors automatiquement écrire :<br />
String description = leo.toString(); // leo est une instance de Lion<br />
Je mesure X cm et je suis de couleur [color]"<br />
Ceci permet de réduire la taille du code à écrire... ou à corriger!<br />
Cependant on peut souhaiter spécialiser la méthode.
2.3 <strong>Le</strong>s méthodes (2) :<br />
Spécialisation<br />
●<br />
On peut redéfinir une méthode existante de la classe mère pour mieux<br />
l'adapter à la classe fille :<br />
public String toString(){<br />
}<br />
String description = "Je suis un lion avec une criniere<br />
"+CouleurCriniere+"\n";<br />
return description+super.toString();<br />
<strong>Le</strong> résultat de la méthode toString() de la classe Lion est alors différent de<br />
celui de la classe Animal :<br />
String description = leo.toString(); // leo est une instance de Lion<br />
"Je suis un lion avec une criniere [color]<br />
Je mesure X cm et je suis de couleur [color]"
2.4 Interdire l'heritage<br />
●<br />
Il est possible d'interdire à tout autre programmeur d'hériter de votre<br />
classe : on utilise alors le mot clé final.<br />
final class Lion extends Animal{...}<br />
... Il est maintenant impossible de créer une classe héritant de Lion.<br />
●<br />
De la même façon, on peut empêcher la redéfinition d'une méthode par<br />
les classe filles :<br />
public final String toString(){...} // Dans la classe mère<br />
Il est maintenant impossible aux classes filles de redéfinir la méthode<br />
toString().
3 <strong>Le</strong> polymorphisme<br />
L'héritage exprime la relation "est un". Dans notre exemple, un lion est<br />
un animal tout comme un oiseau l'est également. Il est donc logique de<br />
pouvoir écrire :<br />
Animal albert = new Lion();<br />
Animal gustave = new Oiseau();<br />
On peut ensuite appeler n'importe quelle méthode définie dans la classe<br />
Animal :<br />
System.out.println(albert.toString());<br />
System.out.println(gustave.toString());<br />
Dans ce cas, le compilateur va créer une liaison dynamique permettant<br />
de choisir la méthode au moment de l'execution :<br />
System.out.println(albert.toString()); // méthode Lion.toString()<br />
System.out.println(gustave.toString()); // méthode Oiseau.toString()
3 <strong>Le</strong> polymorphisme (2)<br />
On peut naturellement définir un tableau :<br />
Animal[] animaux = new Animal[2];<br />
animaux[0] = new Lion();<br />
animaux[1] = new Oiseau();<br />
et afficher le contenu de ce tableau :<br />
for(Animal a : animaux){<br />
System.out.println(a); // méthode toString()<br />
}<br />
"Je suis un lion avec une criniere [color]<br />
Je mesure X cm et je suis de couleur [color]<br />
Je suis un oiseau<br />
Je mesure X cm et je suis de couleur [color]"
3 <strong>Le</strong> polymorphisme (3)<br />
Ayant un tableau d'objets 'Animal', on ne peut appeler que les méthodes<br />
de la classe Animal :<br />
animaux[0].Dormir(); // OK<br />
animaux[0].Rugir(); // NON!! N'existe pas dans la classe Animal!<br />
Si on veux pouvoir utiliser toutes les fonctionalités de la classe, on doit<br />
effectuer un transtypage :<br />
((Lion)animaux[0]).Rugir(); // Compilation OK<br />
Par contre rien ne prouve que animaux[0] soit une instance de Lion. On<br />
peut donc avoir une erreur à l'execution! Pour l'éviter :<br />
if(animaux[O] instanceof Lion)<br />
((Lion)animaux[0]).Rugir(); // Uniquement si on a un Lion !
Classes abstraites<br />
4 Classes et méthodes<br />
abstraites<br />
A mesure que l'on élabore la hiérarchie des classes, certaines peuvent<br />
ne plus décrire des objets réels. Pour notre exemple, la classe 'Animal'<br />
correspond elle à un objet utile, ou simplement à un concept abstrait?<br />
Il est possible de déclarer une classe comme "abstraite", ceci aura 2<br />
conséquences :<br />
● Il n'est plus possible de créer une instance de la classe.<br />
● La classe peut comporter des méthodes abstraites.<br />
Méthodes abstraites<br />
Une méthode abstraite est déclarée dans la classe mère mais n'est<br />
implémentée que dans les classes filles.
4 Classes et méthodes<br />
Déclaration d'une classe abstraite :<br />
abstract class Animal{...}<br />
abstraites (2)<br />
Déclaration d'une méthode abstraite :<br />
public abstract String toString(); // pas d'implémentation<br />
Conséquence : toutes les classes héritant de Animal, si elles ne sont pas<br />
abstraites ellesmême, doivent implémenter la méthode toString().
5 La classe Object<br />
Si une classe n'hérite pas explicitement d'une autre, alors elle<br />
hérite de la classe Object.<br />
Par conséquent, toutes les classes java héritent directement<br />
ou indirectement de la classe Object.<br />
Il est donc toujours possible d'écrire :<br />
Object o = new NomDeLaClasse(...);
5 La classe Object (2)<br />
La classe Object propose différentes méthodes dont vont<br />
hériter toutes les classes java:<br />
– String toString() : retourne une description de la<br />
classe.<br />
– boolean equals() : comparaison de deux objets<br />
– Object clone() : retourne une copie de l'objet<br />
Ces méthodes doivent souvent être redéfinies au niveau de la<br />
classe pour être pertinentes.<br />
Voire la documentation de la classe Object pour la liste complète des méthodes...
6.1 <strong>Le</strong>s interfaces Utilisation<br />
Une interface est un ensemble de règles auxquelles doit se<br />
conformer une classe. C'est une sorte de cahier des charges.<br />
Exemple : La méthode sort() de la classe Arrays permet de<br />
trier un tableau d'objets.<br />
Condition : les objets doivent provenir d'une classe qui<br />
implémente l'interface Comparable :<br />
public interface Comparable<br />
{<br />
}<br />
int compareTo(T other);
6.1 <strong>Le</strong>s interfaces – Utilisation<br />
(2)<br />
Modifons la classe Animal pour implementer l'interface Comparable :<br />
class Animal implements Comparable{// on peut implémenter plusieurs interfaces<br />
[...]<br />
public int compareTo(Animal other){<br />
}<br />
}<br />
if (taille>other.taille) return 1;<br />
if (taille
6.1 <strong>Le</strong>s interfaces – Utilisation<br />
(3)<br />
Quelques propriétés des interfaces :<br />
– Elles ne peuvent pas contenir de champs, mais elles peuvent<br />
contenir des constantes<br />
– Elles ne peuvent pas être instanciées<br />
– On peut cependant déclarer des variables interfaces (ces variables<br />
références des objets de classes implémentant l'interface)<br />
– Une interface peut hériter d'une autre interface<br />
– Une classe peut implémenter plusieurs interfaces
6.2 <strong>Le</strong>s interfaces – Création<br />
Ecrire une interface est très simple, il suffit de lui donner un nom et<br />
d'énumérer les méthodes.<br />
Par exemple, nous pouvons créer une interface Dessinable qui garantit<br />
que les classes l'implémentant auront une méthode public void<br />
Dessine(Graphics g) :<br />
public interface Dessinable {<br />
}<br />
public void Dessine(Graphics g);<br />
Comme pour une classe, ce code devra être placé dans un fichier nommé<br />
Dessinable.java.
7 <strong>Le</strong> clonage<br />
<strong>Le</strong> clonage permet d'obtenir une copie en profondeur d'un objet par<br />
un appel à la méthode clone().<br />
Cependant cette méthode est protected dans la classe Object!<br />
Il faut donc la redéfinir dans la classe fille :<br />
public Object clone() throws CloneNotSupportedException{<br />
Personne p = (Personne)super.clone();<br />
p.birthday = (Date)this.birthday.clone();<br />
return p;<br />
}
7 <strong>Le</strong> clonage (2)<br />
Afin d'éviter une erreur lors du clonage (une classe fille qui ne<br />
redéfinit pas correctement la méthode clone()), il est impératif<br />
d'implémenter l'interface Cloneable pour indiquer que notre classe<br />
gère le clonage. C'est une interface de balisage (elle ne contient<br />
aucune méthode).<br />
class Personne implements Cloneable{<br />
...<br />
}<br />
Tout appel à la méthode clone() à partir d'une classe<br />
n'implémentant pas Cloneable générera une exception<br />
CloneNotSupportedException.
Gestion des exceptions<br />
1.Envoi d'une exception<br />
2.Réception d'une exception<br />
3.<strong>Le</strong> mot clé finally<br />
4.Créer ses propres exceptions
1. Envoi d'une exception<br />
Si une méthode rencontre une situation qu'elle ne sait pas gérer,<br />
elle peut envoyer une exception.<br />
public void openFile(String name) throws<br />
FileNotFoundException{<br />
}<br />
[...le fichier n'existe pas]<br />
throw new FileNotFoundException();<br />
[...]<br />
Lors de l'envoi d'une exception, on sort de la méthode<br />
immédiatement. Celleci ne retourne pas de valeur.
2. Réception d'une exception<br />
La méthode pouvant envoyer une exception doit être appelée à<br />
l'interieur d'un bloc try...catch:<br />
try{<br />
}<br />
...<br />
openFile(fileName);<br />
...<br />
catch(FileNotFoundException e){<br />
}<br />
System.out.println(“Aucun fichier trouvé!”);<br />
Si exception<br />
On peut enchaîner plusieurs blocs catch pour gérer plusieurs types<br />
d'exception.
3. <strong>Le</strong> mot clé finally<br />
On peut également utiliser un block finally qui sera executé qu'une<br />
exception soit levée ou non :<br />
try{<br />
}<br />
openFile(fileName);<br />
catch(FileNotFoundException e){...}<br />
catch(...){...}<br />
finally{...}<br />
<strong>Le</strong> bloc finally est exécuté :<br />
– soit après le bloc try si aucune exception n'est envoyée<br />
– soit après l'un des blocs catch si une exception a été envoyée.<br />
– même si une instruction return a été rencontrée.
4. Créer ses propres exceptions<br />
Pour créer une nouvelle classe pouvant être utilisée comme<br />
exception, il suffit d'hériter de la classe Exception ou d'une de ses<br />
classes filles:<br />
public class MyException extends Exception {<br />
}<br />
public MyException(){}<br />
public MyException(String message) {<br />
}<br />
super(message);<br />
On pourra maintenant utiliser la classe MyException de la même facon<br />
que la classe FileNotFoundException.<br />
<strong>Le</strong> compilateur force le traitement des exceptions sauf pour les<br />
RuntimeException.
Introduction aux interfaces<br />
graphiques<br />
1. AWT et Swing<br />
2. <strong>Le</strong>s classes de base<br />
1. Créer une fenêre : JFrame<br />
2. Ajouter un contenu : JPanel<br />
3. JLabel<br />
4. JTextField<br />
5. JButton<br />
6. Autres composants<br />
3. Gestion des événements<br />
1. Créer un écouteur<br />
2. Classes internes<br />
3. Lier un composant à un écouteur<br />
4. Interfaces listener utiles
1. AWT et Swing<br />
●<br />
Abstract Window Toolkit (AWT) : première bibliothèque graphique<br />
de Java<br />
Appel des fonctions natives du système d'exploitation<br />
La bibliothèque AWT est contenue dans la package java.awt.*<br />
●<br />
Swing : Standard depuis Java 2<br />
Dessine tous les composants dans une fenêtre<br />
La bibliothèque Swing est contenue dans la package javax.Swing.*
2.1 Créer une fenêtre : JFrame<br />
La classe JFrame permet de créer une fenêtre graphique :<br />
import javax.swing.*;<br />
public class MyFrame extends JFrame {<br />
public static final int HEIGHT = 250;<br />
public static final int WIDTH = 300;<br />
public MyFrame(String title){<br />
super(title);//constructeur de JFrame<br />
setSize(WIDTH, HEIGHT);<br />
}}<br />
public class Launcher{<br />
public static void main(String args[]){<br />
}}<br />
MyFrame mf = new MyFrame("Nom de la fenetre");<br />
mf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);<br />
mf.setVisible(true);
2.1 Créer une fenêtre : JFrame<br />
(2)<br />
JFrame : fonctions utiles<br />
– setTitle(String t) : donne un titre à la fenêtre.<br />
– setSize(int w, int h) : stipule la taille de la fenêtre en pixels.<br />
– setLocation(int x, int y) : stipule l'emplacement de la fenêtre.<br />
– setDefaultCloseOperation(constante) : comportement du<br />
programme lors de la fermeture de la fenêtre.<br />
– setVisible(boolean b) : affiche ou cache la fenêtre.<br />
– getContentPane() : retourne la couche "contenu" de la<br />
fenêtre.
2.2 Ajouter un contenu : JPanel<br />
Un JPanel est un composant sur lequel on peut dessiner et qui peut egalement<br />
contenir d'autres composants. Pour déssiner sur un JPanel, il faut surcharger la<br />
méthode void paintComponent(Graphics g).<br />
import javax.swing.*;import java.awt.*;<br />
public class MyPanel extends JPanel {<br />
public void paintComponent(Graphics g){<br />
}}<br />
super.paintComponent(g);<br />
g.fillRect(20,20,25,50);<br />
public class Launcher{<br />
public static void main(String args[]){<br />
}}<br />
MyFrame mf = new MyFrame("Nom de la fenetre");<br />
mf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);<br />
mf.getContentPane().add(new MyPanel());<br />
mf.setVisible(true);
2.2 Ajouter un contenu : JPanel<br />
(2)<br />
Pour ajouter d'autres composants dans un JPanel, on lui affecte un<br />
gestionnaire de mise en forme. On dispose de plusieurs<br />
gestionnaires possibles :<br />
– FlowLayout (défaut de JPanel) : Tous les composants sont ajoutés<br />
horizontalement jusqu'à ce qu'il n'y ait plus de place sur la ligne, on<br />
commence alors une nouvelle ligne.<br />
– BorderLayout (défaut de JFrame) : L'espace est divisé en 5 zones<br />
(Nord, Sud, Est, Ouest, Centre) et on doit affecter les composants à<br />
l'une de ces zones.<br />
– GridLayout : On divise l'espace en lignes et colonnes, un composant<br />
est affecté à la case (x,y).<br />
– GridBagLayout : Similaire à GridLayout, mais les cases peuvent<br />
avoir des tailles différentes.<br />
http://java.sun.com/docs/books/tutorial/uiswing/layout/using.html
2.3 JLabel<br />
Un JLabel est un composant permettant d'afficher du texte qui ne pourra pas<br />
être modifié par l'utilisateur.<br />
import javax.swing.*;<br />
import java.awt.*:<br />
public class MyInterface{<br />
private JLabel titre;<br />
public MyInterface(){<br />
}}<br />
MyFrame mf = new MyFrame("Nom de la fenetre");<br />
mf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);<br />
JPanel j = new JPanel();<br />
j.setLayout(new BorderLayout());//definition du gestionnaire<br />
titre = new JLabel("Un titre pour la fenetre", JLabel.CENTER);<br />
j.add(titre, BorderLayout.NORTH);<br />
mf.getContentPane().add(j);<br />
mf.setVisible(true);
2.4 JTextField<br />
Un JTextField est un composant permettant à l'utilisateur de saisir du texte.<br />
public class MyInterface{<br />
private JLabel titre;<br />
private JTextField text;<br />
public MyInterface{<br />
MyFrame mf = new MyFrame("Nom de la fenetre");<br />
JPanel mainPanel = new JPanel();<br />
mainPanel.setLayout(new BorderLayout());//definition du gestionnaire<br />
titre = new JLabel("Saisir puis valider : ", JLabel.CENTER);<br />
text = new JTextField(10);<br />
JPanel saisiePanel = new JPanel();<br />
saisiePanel.add(titre);<br />
saisiePanel.add(text);<br />
mainPanel.add(saisiePanel, BorderLayout.NORTH);<br />
mf.getContentPane().add(mainPanel);<br />
mf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);<br />
mf.setVisible(true);<br />
}}
2.5 JButton<br />
Un JButton permet d'afficher un bouton sur lequel l'utilisateur pourra cliquer.<br />
private JLabel titre;<br />
private JTextField text;<br />
private JButton bouton;<br />
public MyInterface{<br />
}<br />
MyFrame mf = new MyFrame("Nom de la fenetre");<br />
JPanel mainPanel = new JPanel();<br />
mainPanel.setLayout(new BorderLayout());//definition du gestionnaire<br />
titre = new JLabel("Saisir puis valider : ", JLabel.CENTER);<br />
text = new JTextField(10);<br />
bouton = new JButton("Quitter");<br />
JPanel saisiePanel = new JPanel();<br />
saisiePanel.add(titre);<br />
saisiePanel.add(text);<br />
mainPanel.add(saisiePanel, BorderLayout.NORTH);<br />
mainPanel.add(bouton, BorderLayout.SOUTH);<br />
mf.getContentPane().add(mainPanel);<br />
mf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);<br />
mf.setVisible(true);
2.6 Autres composants<br />
Il existe beaucoup d'autres composants graphiques. Entre autres :<br />
– JComboBox : Composant affichant une liste.<br />
– JRadioButton : Sélection d'une seule valeur parmi plusieurs boutons.<br />
– JCheckBox : Composant pouvant prendre les valeurs vrai/faux.<br />
– JTree : Permet d'afficher une arborescence.<br />
– JProgressBar : Affiche la progression d'une action.<br />
– JTabbedPane : Permet de passer d'un panneau à un autre en<br />
utilisant des onglets.<br />
Tous les composants graphiques héritent de javax.swing.JComponent.<br />
http://java.sun.com/j2se/1.5.0/docs/api/javax/swing/JComponent.html
3. Gestion des événements<br />
Une fois les composants graphiques mis en place, il faut pouvoir<br />
récupérer les actions de l'utilisateur.<br />
Composant<br />
graphique<br />
objet événement<br />
objet<br />
événement<br />
objet<br />
événement<br />
Ecouteur 1 Ecouteur 2 Ecouteur N<br />
...<br />
Il faut donc :<br />
– Créer un/des écouteur(s)<br />
– Référencer les écouteurs au niveau des composants
3.1 Créer un écouteur<br />
<strong>Le</strong> rôle de l'écouteur est d'attendre qu'un événement lui soit envoyé.<br />
Il analyse cet événement et execute le code adéquate.<br />
Pour créer un écouteur, il suffit d'implémenter une interface, par<br />
exemple ActionListener :<br />
class MyListener implements ActionListener{<br />
public void actionPerformed(ActionEvent e){<br />
}<br />
}<br />
Lorsqu'un événement est reçu, la méthode actionPerformed est<br />
executée.
3.2 Classes internes<br />
<strong>Le</strong>s classes écouteurs sont spécifiques à l'interface développée.<br />
Elles sont souvent placées à l'intérieur de la classe décrivant<br />
l'interface graphique. Ce sont alors des classes internes.<br />
<strong>Le</strong>s classe internes :<br />
– ont accès aux champs de la classe conteneur<br />
– sont invisibles à l'extérieur de la classe conteneur
3.2 Classes internes (2)<br />
public class MyInterface{<br />
private JTextField text;<br />
private JLabel titre;<br />
private JButton bouton;<br />
public MyInterface(){ ... }<br />
class MyListener implements ActionListener{<br />
public void actionPerformed(ActionEvent e){<br />
if(e.getSource()==text){<br />
System.out.println(text.getText());<br />
}<br />
if(e.getSource()==bouton){<br />
System.out.println("Je quitte!!");<br />
System.exit(0);<br />
}<br />
}<br />
}}
3.3 Lier un composant à un<br />
écouteur<br />
Il nous faut maintenant créer une instance de notre classe écouteur:<br />
public MyInterface{ ...<br />
...}<br />
MyListener listener = new MyListener();<br />
Et indiquer à nos composants qu'ils doivent envoyer les<br />
événements à ce listener :<br />
public MyInterface{ ...<br />
...}<br />
MyListener listener = new MyListener();<br />
bouton.addActionListener(listener);<br />
text.addActionListener(listener);
3.4 Interfaces listener utiles<br />
●<br />
ActionListener : Touche entrée et boutons<br />
● public void actionPerformed(ActionEvent e)<br />
●<br />
KeyListener : Evénements clavier<br />
● public void keyPressed(KeyEvent e)<br />
● public void keyReleased(KeyEvent e)<br />
● public void keyTyped(KeyEvent e)<br />
●<br />
MouseListener : Clics et positionnement de la souris<br />
● public void mouseClicked(MouseEvent e)<br />
● public void mouseEntered(MouseEvent e)<br />
● public void mouseExited(MouseEvent e)<br />
● public void mousePressed(MouseEvent e)<br />
● public void mouseReleased(MouseEvent e)
3.4 Interfaces listener utiles (2)<br />
●<br />
MouseMotionListener : Mouvements de la souris<br />
● public void mouseDragged(MouseEvent e)<br />
● public void mouseMoved(MouseEvent e)<br />
Il existe bien d'autres interfaces écouteur. Toutes héritent de l'interface<br />
EventListener<br />
(http://java.sun.com/j2se/1.5.0/docs/api/java/util/EventListener.html).
Pour aller plus loin...<br />
●<br />
<strong>Le</strong> site officiel de Sun contient énormément d'informations :<br />
documentation de l'API, exemples, tutoriaux...<br />
– http://java.sun.com/j2se/1.5.0/docs/<br />
●<br />
De nombreux sites Internet proposent des exemples de code en<br />
Java, un simple moteur de recherche permet souvent de trouver<br />
des informations pertinentes.<br />
●<br />
Au coeur de Java 2 (Hortsmann & Cornell), CampusPress<br />
●<br />
Java Cookbook (Darwin), O'Reilly