Introduction
Tutoriel pour une prise en main rapide de la programmation orientée objet avec Java : classes, méthodes, constructeurs, héritage, polymorphisme, encapsulation…
Les opérateurs et blocs d’instruction du langage Java ainsi que les packages sont également abordés.
L’utilisation de javac pour compiler des classes java et l’exécution des classes avec java est proposée à la fin de l’article avec le classique programme Hello World.
Design orienté objet avec Java
Avec Java, des classes sont créées. les trois composantes essentielles des classes sont :
- la définition d’une classe;
- les membres d’une classe (méthodes et champs);
- les méthodes particulières d’une classe (constructeurs et méthode main()).
Anatomie d’une classe
L’anatomie d’une classe Java peut être schématisée dans la façon suivante :
class circle {
// Liste des champs
// Liste des méthodes
// Constructeurs
// méthode main()
}
Les champs d’une classe
Un champ dans une classe a pour objectif de stocker des informations. Deux types de champs sont implémentables dans une classe Java :
- les champs d’instance;
- les champs statiques;
Les champs d’instance
Ce champ est défini pour une instance. Il peut être initialisé à la déclaration.
double radius = 5;
Cette variable est assimilable aux variables d’instance définies dans une classe PowerBuilder.
static double pi=3.1416;
Ajouter des champs dans la définition d’une classe :
class circle {
// Liste des champs
double radius = 0;
static double pi = 3.1416;
// Liste des méthodes
// Constructeurs
// méthode main()
}
Les champs statiques
Ces champs peuvent être partagés par plusieurs instances d’un même objet. Ce champ est comparable aux variables partagées avec PowerBuilder. Ces derniers champs peuvent être obtenues sans avoir à instancier la classe.
L’encapsulation avec Java
L’encapsulation permet de cacher l’implémentation interne d’un objet à l’utilisateur.
Par ailleurs les objets ne devraient jamais directement modifier les champs d’un autre objet, des méthodes doivent être définies dans une classe pour lire ou modifier effectivement les valeurs de cette dernière classe, ces dernières méthodes doivent évidemment être définies comme publiques pour réaliser ces manipulations.
Propriétés d’accès dans les classes
Portée | Description |
---|---|
Public |
Accessible partout où la classe est accessible |
Protected |
Accessible par les sous-classes uniquement et les classes dans le même package |
Private |
Accessible uniquement par la classe elle-même |
Package |
Accessible par les classes dans le même package (par défaut) |
Bénéfices de l’encapsulation
L’implémentation interne d’une classe ne doit être modifiée qu’en invoquant des méthodes définies dans la classe en question. Les méthodes permettent de gérer les erreurs alors que d’assigner des valeurs à des champs ne le permettent pas.
Exemple de protection d’un champ :
class circle {
// Liste des champs
private double radius = 0;
static double pi = 3.1416;
// Liste des méthodes
// Constructeurs
// méthode main()
}
Définition des méthodes
Les méthodes sont des instructions permettant de manipuler des données dans un objet et de retourner des valeurs. Ces dernières peuvent contenir aucun ou plusieurs arguments.
Les méthodes peuvent éventuellement retourner des valeurs. Lorsque ces
méthodes sont définies avec void
, ces dernières ne retournent alors aucune
valeur.
Syntaxe d’une méthode :
<return type> <Nom méthode> (arg1Type arg1Nom, ...) {
// Corps de la méthode
return <returnvalue>;
}
Exemple :
double getCircumference( ) {
return 2 * radius * PI;
}
Les méthodes statiques
Les méthodes statiques d’une classe n’agissent pas sur une instance particulière et peuvent être utilisées sans avoir à instancier la classe. Ces méthodes peuvent uniquement accéder aux variables statiques de la classe.
static double getCircumference(double radius) { }
Ajout de méthodes à la définition d’une classe :
class Circle {
// liste des champs
private double radius;
static double pi = 3.1416;
// liste des méthodes
public void setRadius(double radius) { }
public double getRadius() { }
public double getCircumference() { }
public static double getCircumference(double radius) { }
// constructeurs
// méthode main()
}
Les constructeurs
Un constructeur est une méthode spéciale pour instancier une classe.
- le constructeur est appelé avec le mot clé
new()
- le constructeur possède le même nom que la classe;
- peut accepter aucun ou plusieurs paramètres;
- ne possède aucune valeur à retourner;
- un constructeur non publique restreint les classes pouvant créer l’objet.
Un constructeur sans arguments est créé par le compilateur si la classe est fournie sans constructeur.
Si la classe possède un constructeur personnalisé, le constructeur sans argument doit être également explicitement créé.
Exemple de constructeurs :
class Circle {
private double radius;
static double pi = 3.1416;
// constructors
public Circle() {
}
public Circle(double r) {
radius = r;
}
// main() method
}
La méthode main()
La méthode main()
est invoquée lorsqu’une application démarre. Cette
dernière n’est pas nécessaire si la classe en question n’est pas le point
d’entrée de l’application. Elle peut être appelée sans créer l’instance.
Cette méthode créé typiquement une instance.
La signature de la méthode main()
est la suivante :
La méthode main()
doit
- être déclarée comme
public
- être une méthode statique
- ne rien retourner :
void
- accepter comme argument un tableau de string
public static void main(String args[ ]) {
Circle c = new Circle( );
}
Instanciation d’une classe
Une classe peut être déclarée, en aucun cas cette dernière est instanciée au cours de la déclaration. Une déclaration ne créé pas une instance, elle créé une référence à un objet de ce type.
La référence est initialement à null
:
Circle myCircle;
L’objet est créé en utilisant le mot clé new
:
myCircle = new Circle();
Les objets nouvellement créés sont alloués dans une zone de la mémoire système connue sous le nom de 'heap'. Tous les objets Java sont obtenus par référence.
Accéder aux membres d’une classe
Les membres d’un objet sont invoqués en utilisant la 'dot notation' :
objet.méthode, objet.propriete
myCircle.getCircumference()
myCircle.pi
Si la référence est null
, une exception de type NullPointerException
est
levée.
Utilisation du pronom this
this
fait référence à l’objet. Dans une méthode qui n’est pas statique, this
fait référence à l’objet sur lequel la méthode agit.
Ce pronom peut être utilisé à la première ligne d’un constructeur pour appeler un autre constructeur.
Collecteur de mémoire
Lorsqu’un objet n’est plus référencé, l’espace occupé par ce dernier est sujet à la prise en charge par le collecteur de mémoire. Les objets ne sont pas explicitement détruits (aucun delete, aucun destructeur).
Il est toutefois possible d’invoquer directement le collecteur de mémoire pour détruire prématurément un objet.
La méthode finalize()
La méthode finalize()
est invoquée implicitement par le collecteur de
mémoire avant la destruction d’un objet.
Le langage Java
Caractéristiques du langage
Java est case-sensitive, ce qui signifie sensible à la casse. Toutes les lignes de commande se terminent par un point virgule ;
Les espaces sont ignorés exceptés ceux dans les chaînes de caractères utilisés dans le code Java.
Commentaires en Java
// comment |
Les caractères depuis // jusqu’à la fin de la ligne sont ignorés. |
/* comment */ |
Les caractères entre /* et */ sont ignorés. |
/** comment */ |
Les caractères entre /** et */ sont ignorés et automatiquement
générés dans la documentation. |
Variables
Une variable est un identifiant donné à un stockage d’une donnée. Trois types de variables sont disponibles :
- variables locales
- variables d’instance
- champs statiques
La déclaration d’une variable locale peut être réalisée à n’importe quel endroit du code source et sa durée de vie est égale à l’exécution du bloc qui la contient.
public class MyClass {
int a;
static int b;
public void myMethod( ) {
int c;
if (condition) {
int d;
} // =====================> d n’est plus disponible
} // =======================> c n’est plus disponible
} // ===========================> a n’est plus disponible
Constantes
Une fois initialisées, les constantes ne peuvent être modifiées. Il est nécessaire d’utiliser le mot clé final pour rendre un champ constant et non modifiable.
Une constante statique peut être utilisée sans avoir à instancier la classe.
class Circle {
static final double pi = 3.1416;
}
Tableaux
Un tableau est une collection ordonnée d’éléments de données primitives ou d’objets. La longueur est définie à la création et ne peut alors être modifiée.
Données de type primitives | Tableaux d’objets |
---|---|
|
|
x.length
permet de connaître la dimension d’un tableau.
Opérateurs
Les opérateurs en Java sont au nombre de 4 :
- opérateurs d’assignation;
- opérateurs arithmétiques;
- opérateurs relationnels;
- opérateurs logiques;
Opérateurs d’assignation
Pour assigner une valeur, le symbole = est utilisé :
validated = true
Opérateurs arithmétiques
Opérateurs arithmétiques classiques :
+ |
Addition | / |
Division |
- |
Soustraction | % |
Reste |
* |
Multiplication |
Opérateurs d’incrémentation et de décrémentation :
i++ <=> i = i+1;
i-- <=> i = i-1;
Raccourcis d’opérateurs :
var op= expression <=> var = var op (expression)
a *= (b+1) <=> a = a *(b+1)
Opérateurs relationnels
> |
Supérieur strictement | < |
Inférieur strictement |
>= |
Supérieur ou égal | <= |
Inférieur ou égal à |
== |
Égal à | != |
Différent de |
Opérateurs logiques
&&
||
! |
And Or Not |
|
Structures de programmation
if else
Syntaxe | Exemple |
---|---|
|
|
|
|
Alternative avec l’opérateur ? | |
|
|
|
|
switch
Syntaxe | Exemple |
---|---|
L’expression switch autorise la sélection multiple.
Cette dernière instruction doit évaluer une
expression retournant une valeur de type int .
case < expression> doit être une expression littérale
ou un champ statique final. break permet de sortir de
la commande switch sans se préoccuper des cas
suivants. |
|
Boucles for loop
Syntaxe | Exemple |
---|---|
counter_init et counter_increment peuvent
être des listes d’expressions séparées par
des virgules. |
|
Boucles indéterminées
Syntaxe | Exemple |
---|---|
Bloc exécuté aucune fois ou plusieurs fois
Bloc exécuté au moins une fois |
|
Commandes identifiées
Les blocs d’instructions peuvent être identifiés par des labels. Ces labels sont typiquement utilisés dans les blocs et les boucles.
Syntaxe | Exemple |
---|---|
|
|
Conversions
Java vérifie la compatibilité au cours de la compilation. Dans le cas où cette compabilité ne peut être vérifiée qu’à l’exécution, des fonctions de casting sont fournies par Java.
Conversions implicites
Une valeur numérique est implicitement convertie en un autre type de valeur numérique à condition que la gamme du nouveau type soit supérieur :
byte > short > int > long > float > double
Plus petit -------------------> Plus grand |
|
Conversions explicites
Lorsque la conversion implicite n’est pas réalisable, une conversion explicite doit être réalisée. Quelques conversions sont en revanche irréalisables (se reporter à la documentation à ce sujet).
Exemples de conversion de types de données :
Valeurs numériques en chaînes de caractères
|
Chaînes de caractères en valeurs numériques
|
Héritage de classes
L’héritage
L’héritage permet à une classe d’hériter des propriétés et des méthodes d’une autre classe. Les méthodes et les champs sont généralisés au niveau d’un ancêtre. Les méthodes particulières sont transcrites dans la classe descendante.
Toutes les classes dérivent implicitement de la classe Object
. La clause
Extends
permet de spécifier un ancêtre intermédiaire. L’héritage multiple n’est
pas autorisé avec Java.
Une sous classe hérite de toutes les méthodes et de toutes les propriétés de la superclasse dont elle dérive.
class Shape {
int x, y;
public void setX(int xpos) { x = xpos; }
public void setY(int ypos) { y = ypos; }
}
class Rectangle extends Shape {
int width, height;
public void setWidth(int w) { width = w; }
public void setHeight(int h) { height = h; }
}
Les classes abstraites
Ces classes définissent une partie de l’implémentation et ne peuvent être instanciées. Les classes abstraites peuvent posséder des méthodes concrètes réutilisables dans les descendants.
public abstract class Shape {
public abstract void draw();
}
public class Rectangle extends Shape {
public void draw( ) {
// programme
}
}
L’opérateur instanceof
L’opérateur instanceof
est utilisé pour déterminer si un objet est d’une
classe donnée.
if (shape instanceof Circle) {
Circle circle = (Circle) shape;
// programme
}
Polymorphisme et redirection des méthodes
Les méthodes dans une classe peuvent avoir le même nom mais des arguments différents. Lorsque la méthode est invoquée, le compilateur vérifie les arguments et les codes de retour pour invoquer la méthode appropriée.
La signature d’une méthode consiste à donner un nom à une méthode ainsi que des arguments.
class Account {
public void deposit(double amt) {
this.deposit(amt, "USD");
}
public void deposit(double amt, String currency) {
// process deposit
}
}
Surcharge des méthodes
La surcharge d’une méthode permet de remplacer l’implémentation d’une méthode dans l’ancêtre au niveau du descendant.
La signature et le type de retour sont les mêmes que ceux définis au niveau de la classe ancêtre.
Le niveau d’accès doit être le même ou fournir plus d’accès (une fonction protégée ne peut être définie comme privée au niveau de la classe descendante).
Seules les méthodes non statiques peuvent être surchargées.
Le mot clé super
est utilisé pour invoquer une méthode implémentée au niveau
de l’ancêtre. Il fait référence à l’ancêtre direct dans l’arborescence de
l’héritage. Ce mot clé est disponible pour toutes les méthodes non statiques
d’une classe étendue.
public class Employee {
public int getHolidays( ) {
return 20;
}
}
public class Manager extends Employee {
public int getHolidays( ) {
return super.getHolidays( ) + 5;
}
}
Les constructeurs dans les classes étendues
Le constructeur d’une classe étendue doit invoquer le constructeur de la superclasse.
Explicitement en utilisant le mot clé super()
à la première ligne.
Implicitement, si le constructeur de la superclasse n’est pas invoqué explicitement, le constructeur de la superclasse sans arguments est automatiquement invoqué : une erreur d’exécution en résulte si le constructeur sans arguments n’est pas défini au niveau de la superclasse.
class Shape {
int left, top;
Shape(int x, int y) {
left = x;
top = y;
}
}
class Rectangle extends Shape {
int width, height;
Rectangle(int x, int y, int w, int h) {
super(x,y);
width = w;
height = h;
}
}
Lorsqu’une instance d’une classe est créée : le processus suivant est déclenché
- Les valeurs par défaut des champs sont initialisées.
- Le constructeur de la classe est invoqué.
- Le constructeur de la superclasse est invoqué.
- Les champs de la superclasse sont initialisés.
- Le constructeur de la superclasse est exécuté.
- Les champs de la classe sont initialisés.
- Le constructeur de la classe est exécuté.
Limitation de l’héritage en utilisant le mot clé final
Cette particularité peut être utilisée :
- au niveau de la classe pour empêcher l’héritage à partir d’une classe
- au niveau d’une méthode pour empêcher la surcharge d’une méthode
Les classes finales
Un héritage à partir d’une classe finale ne peut être réalisé et les méthodes sont implicitement finales.
final class Password {
public boolean validate( ) {
// validate password
}
}
Les méthodes finales
Ces méthodes ne peuvent être surchargées.
class Password {
final public boolean validate() {
// validate password
}
}
Packages Java
Définition d’un package
Un package est une collection de classes et d’interfaces interdépendantes. Le groupement par packages a deux objectifs majeurs :
- éviter les conflits de noms;
- gérer les niveaux d’accès aux classes;
Hiérarchie des packages
Les packages java standards sont donnés ci-dessous :
java.lang |
java.applet |
java.sql |
java.awt |
java.util |
java.text |
java.io |
java.rmi |
|
java.net |
java.security |
Les noms des packages sont hiérarchiques : java.awt.event
Les classes doivent être stockées dans un sous répertoire qui correspond
exactement au nom du package : une classe appartenant au package donné
ci-dessus doit être stocké dans le répertoire /java/awt/event
.
Les sous répertoires des packages peuvent être stockés n’importe ou dans le système de fichiers.
Variable d’environnement CLASSPATH
La variable d’environnement CLASSPATH est utilisée pour la recherche des packages.
SET CLASSPATH=.;c:\jdk\lib;c:\Program Files\java
Cette variable d’environnement peut être initialisée dans une commande bat.
Incorporation d’une classe dans un package
Afin d’incorporer une classe dans un package, il convient d’utiliser la déclaration package dans le fichier source puis de stocker la classe dans un répertoire qui correspond avec le nom du package. |
|
Accessibilité des classes
Par défaut, une classe est accessible uniquement par les classes du même package. Cette dernière classe doit être déclarée comme publique pour pouvoir être accessible par les classes des autres packages. |
|
Référencement des packages dans les classes
Référencement en utilisant explicitement les noms des classes | Référencement avec les commandes import :
|
|
|
Recherche des packages :
|
Fichiers zip
La variable d’environnement CLASSPATH
peut être également utilisée pour
rechercher les packages dans des fichiers zip
SET CLASSPATH=.;c:\jdk\lib\classes.zip;c:\mylibs
La structure interne des répertoires dans le fichier Zip est identique à celle des packages libres.
Compilation et exécution (JDK, javac, java)
Pour démonstration, le programme helloworld.java
ci-dessous va être compilé
:
helloworld.java
class helloworld {
public static void main (String[] args){
System.out.println("Hello World");
}
}
Ce programme basique affiche à la console "Hello World".
Les classes Java sont compilées avec la distribution Java Developer’s Toolkit (JDK) téléchargeable gratuitement, et non la distribution JRE (Java RunTime Environment).
Le binaire javac
dans le répertoire %JAVA_SDK_HOME%\bin
compile un code
source .java
en fichier compilé avec l’extension .class
.
javac helloworld.java
La commande ci-dessus génère un fichier helloworld.class
, fichier compilé
exécutable avec le binaire java
.
javac
accepte de très nombreux arguments, notamment l’argument -cp
permettant de modifier la variable CLASSPATH
au moment de la compilation pour
la recherche des packages et classes : javac -cp <path>
Le programme est alors exécutable avec java
:
java helloworld
Hello World
Comme pour javac
, java
accepte également l’argument -cp
pour modifier la
variable CLASSPATH
afin d’y ajouter des archives java zip/jar.