Généralités sur JAVA

Complément du langage JAVA

APPENDICES JAVA

Spécification du langage JAVA

 

1. Structuration d'un Programme JAVA

Un programme source de JAVA est composé d'une ou plusieurs unités de compilation. Chaque unité de compilation ne peut contenir que les éléments suivants :

une déclaration de package (voir Packages),

une série d'importations (voir Packages),

des déclarations de classes (voir Classes),

des déclaration d'interfaces (voir Interfaces).

Cependant, bien que plusieurs classes ou interfaces puissent être contenues dans une unité de compilation, une seule de ces classes et interfaces peut être publique (voir plus loin la définition du modificateur public).

 

Quand un programme JAVA est compilé, il en résulte des byte codes JAVA. Le byte code JAVA est un semi-langage machine qui peut être interprété par le runtime JAVA, et ce, quel que soit la machine sur laquelle il est interprété. Le byte code JAVA est donc indépendant de la machine où il est exécuté. La compilation et l'exécution d'un programme JAVA suivent donc les étapes décrites dans le schéma ci-dessous :

2. Unités Lexicales

Le compilateur JAVA reconnaît cinq types d'unités lexicales : les identifiants, les mots réservés, les littéraux, les opérateurs, et les séparateurs. Les commentaires et les espaces ne sont pas des unités lexicales, mais sont souvent utilisés pour séparer des unités lexicales.

Les programmes JAVA sont écrit à l'aide de jeu de caractères Unicode, ou d'un jeu de caractères qui est ensuite converti en Unicode avant d'être compilé.

2.1. Les Commentaires

Les programmes JAVA reconnaissent trois styles de commentaires:

// text Tous les caractères de // jusqu'à la fin de la ligne sont ignorés.

/* text */ Tous les caractères entre /* et */ sont ignorés.

/** text */ Ces commentaires sont traités d'une manière particulière lorsqu'ils sont placés juste avant une déclaration. Ils ne peuvent d'ailleurs être utilisés nulle part ailleurs dans le code. Ces commentaires seront inclus dans une documentation générée automatiquement comme une description de la déclaration.

2.2. Les Identifiants

Les identifiants ne peuvent commencer que par une lettre, un souligné (" _ "), ou un dollar (" $ "). Les caractères suivants peuvent être les mêmes, ou des chiffres (0-9). Les caractères considérés comme des lettres sont :

les caractères de A à Z,

les caractères de a à z,

tous les caractères du jeu Unicode de numéro supérieur à H00C0.

Quelques exemples :

Garçon et Mj0lner sont des identifiants légaux.

Mko[[paragraph]]jki n'est pas valable à cause du caractère [[paragraph]].

 

2.3. Les Mots Réservés

Les identifiants de la liste suivante sont des mots réservés. Ils ne peuvent absolument pas être utilisés d'une autre manière.

abstract         continue         for  gotoa if    new  null        switch
boolean break    default do       implements       package          synchronized
byte byvaluea    double else      import           private          this
case catch       extends false    instanceof int   protected        threadsafe
char class       final finally    interface long   public return    throw
consta           float            native           short static     transient true
                                                   super            try void while

a. Ces mots ne sont pas très utilisés.

2.4. Les Littéraux

2.4.1. Les Entiers

Les entiers (Integer) peuvent être exprimés en décimal (base 10), en hexadécimal (base 16), ou en octal (base 8). Ces représentations sont les suivantes :

int x=12; /* Représentation décimale : pas de 0 avant le nombre 12 */

int x=0777; /* Représentation octale : un 0 précède le nombre 777. On ne peut utiliser que les chiffres 0 à 7. */

int x=0xDead; /* Représentation hexadécimale : un 0x précède le nombre. On peut utiliser les chiffres de 0 à 9, et les lettres de A à F, et de a à f. */

Les entiers sont soit de type int, soit de type long (voir plus loin).

2.4.2. Les Réels

Les réels peuvent avoir les parties suivantes : une partie entière, un point (" . "), une partie décimale, un exposant, et un suffixe de type. L'exposant est un E (ou un e) suivi d'un entier qui peut être signé. Un réel doit avoir au moins une décimale, et soit une virgule, soit un exposant. Quelques exemples éclaireront plus cela :

3.1415 3.1E12 .1E12 2E12

Le langage JAVA possède deux types de réels : les float (précision simple), et les double (précision double). Il est possible de spécifier le type du réel lors de son écriture :

2.0d ou 2.0D est un réel double.

2.0f ou 2.0F est un réel float.

2.4.3. Les Booléens

Les booléens sont, comme en C, des littéraux qui peuvent prendre seulement deux valeurs : true et false.

2.4.4. Les Caractères

Un littéral caractère est un caractère, ou une série de caractères inclus dans des guillemets simples. Les caractères sont de type char et utilisent le jeu Unicode. Les séries de caractères permettent de représenter les caractères non graphiques. Il s'agit des caractères suivants :

Nom               Série       Représentation
nouvelle ligne    \n \t \b    NL HT BS CR FF
tabulation        \r \f \\    \ ' " 0ddd
backspace         \' \"       0xdd 0xdddd
retour chariot    \ddd \xdd
saut de page      \udddd
anti-slash
guillemet
simple
guillemet
double octal
hexadécimal
caractère
Unicode

2.4.5. Les Chaînes de Caractères

Une chaîne de caractères est composée de 0 à n caractères inclus dans des guillemets doubles. A la différence du langage C, les chaînes de caractères sont des Objets, et forment à ce titre un type à part entière. Une chaîne de caractères n'est pas un tableau de caractères.

2.5. Les Opérateurs et les Séparateurs

Les caractères suivants sont utilisés comme opérateurs ou séparateurs dans le code source :

+ - ! % ^ & * | ~ / > <

( ) { } [ ] ; ? : , . =

Quelques combinaisons de caractères sont aussi utilisées comme opérateurs :

++ -- == <= >= != << >> >>> += -= *=

/= &= |= ^= %= <<= >>= >>>= || &&

Pour plus d'information, voyez la partie Opérateurs.

3. Les Types

Chaque variable et chaque expression a un type. Le type permet de définir les valeurs qui peuvent être prises par la variable, et les actions qui peuvent être effectuées dessus. Le langage JAVA possède un certain nombre de types prédéfinis. Les programmeurs peuvent eux aussi en définir à l'aide des mécanismes de classe et d'interface.

Le langage JAVA possède deux sortes de types : les types simples et les types composites. Les types simples sont atomiques : il s'agit des entiers, réels, booléens, et caractères. Les types composites sont basés sur des types simples. Il existe trois sortes de types composites : les tableaux, les classes et les interfaces.

3.1. Les Types Numériques

3.1.1. Les Entiers

Les entiers sont très similaires à ceux qui existent en C et en C++. Il existe cependant deux exceptions : tous les types d'entiers sont indépendants de la machine où ils sont compilés, et quelques définitions traditionnelles du C ont été modifiées. Les 4 types d'entiers sont signés, et sont les suivants :

         Nom            Représenté sur (en
                               bits)
 byte
short
int
long   8
16
32
64

3.1.2. Les Réels

Il n'existe que deux types de réels en langage JAVA. Il s'agit du type float, représenté sur 32 bits, et du type double représenté sur 64 bits. Un opérateur appliqué à deux float donnera un float comme résultat. Si l'une ou l'autre des opérandes est un double, le résultat sera un double.

3.1.3. Les Caractères

Le seul type caractère qui existe est le type char. Ce type est représenté sur 16 bits, puisque JAVA utilise le jeu de caractères Unicode.

3.2. Les Booléens

Le type booléen est le type boolean. Son utilisation ne diffère pas du langage C. Les deux seules valeurs qu'il peut prendre sont true et false. Il s'agit du type qui est retourné par les opérateurs relationnels (du type <=, !=, ==, ...). Les booléens ne sont pas des entiers, et ils ne peuvent pas être convertis en nombre par un cast.

3.3. Les Tableaux

Les tableaux sont des objets. Tous les objets sont référencés par pointeurs, mais ne peuvent pas être manipulés comme des nombres. Comme tous les objets, les tableaux sont créés en utilisant l'opérateur new.

char s[]=new char[30];

Comme en C, le premier élément d'un tableau est situé à l'index 0. Il n'est pas permis de spécifier la taille du tableau dans la déclaration. Chaque allocation doit donc être explicite. Il faut utiliser l'opérateur new à chaque fois.

JAVA ne permet pas de spécifier plusieurs dimensions à la fois. Il n'est donc pas possible de créer des tableaux multidimensionnels. Par contre, il est possible de créer des tableaux de tableaux :

int exemple1[][]=new int[4][5];

int exemple2[][]=new int[30][];

Comme on le voit dans les exemples, il est possible de ne spécifier qu'une seule dimension lors de l'allocation avec l'opérateur new.

Il est aussi possible de placer les crochets après le type des éléments plutôt qu'après le nom :

int[] exemple;

int fonction(int i)[]; // équivaut à int[] fonction(int i)

Les dépassements d'index sont testés lors de l'exécution par le runtime JAVA. Une erreur de ce type provoquerait l'exception ArrayIndexOutOfBoundsException.

La taille d'un tableau peut être trouvée en utilisant .length :

int a[][]=new int[3][5];

i=a.length; // i=3

j=a[0].length; // j=5

Place des Tableaux dans l'Arborescence des Classes

Les tableaux sont tous des instances de sous-classes de la classe Object. Dans la hiérarchie de classe, la classe Array est située sous la classe Object. Elle possède une seule variable d'instance, length. Pour chaque classe existante, il existe implicitement une sous-classe de Array. La création d'une classe A permet donc d'avoir des tableaux de A.

De plus, lorsqu'une classe A possède une sous-classe B, la hiérarchie est conservée dans les tableaux : B[ ] est sous classe de A[ ]. Le schéma ci-dessous résume bien cela :

Les classes Array ne peuvent pas être sous-classées explicitement.

4. Les Classes

Tous les principaux langages orientés objet contiennent des classes. En langage JAVA, chaque nouvelle classe implémente en fait un nouveau type. Toute nouvelle classe est définie comme sous classe d'une classe déjà existante. Le schéma ci-dessous résume les différents points de vocabulaire concernant les classes:

La superclasse d'une classe et les interfaces (voir le chapitre Interfaces) qu'elle implémente sont indiquées dans la déclaration par les mots réservés extends et implements. La déclaration d'une classe se fait suivant la syntaxe :

[Commentaires][Modificateur] class NomDeClasse [extends SuperClasse]
[implements Interface1[, Interface2]] {
CorpsDeClasse
}

Un exemple est la déclaration d'un point à deux dimensions, puis un à trois dimensions :

public class point2D {
float x,y;
...
}

public class point3D extends point2D implements Dessin {
float z;
...
}

Toutes les classes dépendent d'une seule et même superclasse de base : la classe Object. Toute autre classe qu'Object dérive d'une seule superclasse. Si, dans la déclaration d'une classe, aucune superclasse n'est spécifiée, alors cette classe dérive par défaut de Object. Le langage JAVA ne permet donc pas de faire de l'héritage multiple, au sens classique du terme. Cependant, ce mécanisme est remplacé par le système d'interfaces.

4.1. Le Mécanisme de Cast entre Classes

Comme chaque nouvelle classe définit un nouveau type dans le langage JAVA, il est possible d'appliquer le mécanisme de cast aux classes. Ainsi, si une classe B est une sous-classe de A, il est possible d'utiliser une instance de B comme une instance de A. Cela se nomme widening, et ne nécessite pas de faire un cast explicite. De même, une instance de A peut être utilisée comme une instance de B : il y a conversion de type, et cela se nomme narrowing. Le cast doit, cette fois, être explicite.

Le mécanisme de cast est vérifié lors de l'exécution du programme par le runtime JAVA. Cependant, le cast entre des classes sans lien hiérarchique provoque une erreur de compilation. La syntaxe d'un cast est la suivante :

(NomDeClasse)référence;

Ici, NomDeClasse est le nom de la classe en laquelle l'objet référence doit être converti.

Le mécanisme de cast n'affecte que les références aux objets, et non les objets eux-mêmes. La référence aux variables d'instance est concernée par le cast, notamment en ce qui concerne les variables qui portent le même nom. L'exemple ci-dessous résume bien cette caractéristique :

class ClasseA {
String nom="Classe A";
}
class ClasseB extends ClasseA {
String nom="Classe B";
}
class Test {
void MonTest(){
ClasseB b=new ClasseB();
println(b.nom); // Ici on a Classe B

ClasseA a;
a=(ClasseA)b;
println(a.nom); // Ici on a Classe A
}
}

4.2. Les Méthodes

Les méthodes sont les opérations qui peuvent être effectuées dans les objets ou les classes. Elles sont déclarées dans les classes ou dans les interfaces. Cependant, elles ne peuvent être implémentées que dans les classes. La syntaxe de la déclaration d'une méthode est la suivante :

[Commentaires][Modificateurs] TypeRetourné NomDeMéthode (ListeDeParamètres)
{ CorpsDeLaMéthode }

Les méthodes ont toujours un TypeRetourné, sauf s'il s'agit de constructeurs. Dans ce cas seulement, aucun type n'est spécifié (pas même void). Dans le cas où une autre méthode ne retourne pas d'élément, elle a void pour TypeRetourné. La liste des paramètres s'exprime comme en langage C.

Le langage JAVA est un langage polymorphique. Il est donc possible de faire de la surcharge de nom de méthodes : utiliser un nom de méthode qui existe déjà pour une méthode de la même classe ou d'une superclasse. Il existe deux types de surcharge :

Surcharge "verticale" : déclarer une méthode de même spécification qu'une méthode héritée, mais en faire une spécification différente.

Surcharge "horizontale" : déclarer une méthode qui a le même nom qu'une autre méthode, mais pas la même liste de paramètres.

4.2.1. Les Variables d'Instance

Les variables d'instance sont toutes les variables déclarées dans une classe, en dehors d'une méthode, et qui ne sont pas static (voir plus loin). Les variables d'instance peuvent être initialisées lors de la déclaration. Une variable d'instance non initialisée est automatiquement initialisée à zéro, false ou null selon le type de la variable.

4.2.2. This et Super

A l'intérieur d'une méthode non-statique, la variable this représente l'objet courant, c'est à dire l'objet qui appelle la méthode. Ainsi, lorsqu'une méthode fait référence à l'une des variables d'instance de la classe, un "this." implicite est fait.

La variable super est très similaire à la variable this. La variable this est du type de la classe contenant la méthode exécutant this. La variable super est en tout point identique à this, sauf qu'elle est du type de la super classe.

4.2.3. Initialisation des Variables Locales

Dans une méthode, il convient d'initialiser les variables déclarées localement avant toute utilisation. Une vérification est faite lors de la compilation. Une variable locale qui serait utilisée sans avoir été initialisée provoquerait une erreur de compilation.

4.3. Les Constructeurs

Les constructeurs sont des méthodes spéciales destinées à initialiser les classes. Les caractéristiques d'un constructeur sont les suivantes :

 

ils portent le même nom que la classe dans laquelle ils sont déclarés.

 

ils ne retournent aucun type (pas même void).

 

ils sont automatiquement appelés lors de la création d'un nouvel objet de la classe.

 

ils peuvent être surchargés, mais ne peuvent en aucun cas être appelés explicitement. La surcharge peut être faite en variant le nombre des paramètres, et leur type.

 

Class Exemple {
int x;
float y;

Exemple(){
x=3;
y=2.5;
}
Exemple(int i){
x=i;
y=2.5;
}
Exemple(float j) {
x=3;
y=j;
}
Exemple(int i,float j){
x=i;
y=j;
}
static void Test(){
Exemple e1=new Exemple();
Exemple e2=new Exemple(1);
Exemple e3=new Exemple(1.0);
Exemple e4=new Exemple(1,1.0);
}
}

 

Les variables d'instance de la superclasse sont initialisées, soit dans le constructeur courant, soit en faisant appel à un constructeur de la superclasse dans le constructeur. Si rien n'est spécifié, c'est le constructeur sans paramètres de la superclasse qui est automatiquement appelé. Si au contraire un autre constructeur est appelé, ce doit être la première chose faite dans le constructeur courant. Pour appeler le constructeur d'une superclasse, on utilise la syntaxe suivante :

 

Class B extends A {
B(int i){
// Appel au constructeur de la superclasse
super(2.0);
// Appel à un constructeur de la classe
this("bonjour");
}
...
}

 

 

4.4. L'Opérateur New

 

 

Un objet est une instance d'une classe. Toutes les instances de la classe sont stockées dans une zone mémoire spécifique, de type Garbage Collected.. La déclaration d'une référence à un nouvel objet n'alloue aucune zone mémoire réservée à cet objet. L'allocation de mémoire pour un objet se fait de manière explicite par l'utilisation de l'opérateur new. En plus de l'allocation de mémoire, l'opérateur new permet d'initialiser les variables d'instance, et d'appeler un constructeur de la classe. La syntaxe de l'opérateur new est la même qu'en langage C++.

 

a=new ClasseA();

a=new ClasseA(3,4);

 

Il est aussi possible de spécifier le nom de la classe dans une chaîne de caractères, comme dans l'exemple ci-dessous.

 

a=new ("Classe"+"A");

 

Dans ce cas, le constructeur sans argument est appelé.

 

4.4.1. Garbage Collection

 

S'il est nécessaire d'allouer de la mémoire de manière explicite, la libération de cette même mémoire est faite automatiquement grâce au mécanisme de garbage collection.. Le garbage collector ne libère jamais des objets qui sont encore référencés d'une manière ou d'une autre. Il libère toujours la mémoire des objets qui ne sont plus du tout référencés.

 

4.4.2. Finalisation

 

Le langage JAVA permet de libérer explicitement des ressources détenues par des objets qui ne peuvent pas être accédés par un programme JAVA. Ces ressources peuvent être des descripteurs de fichier, ou des contextes graphiques. En effet ces ressources ne sont pas forcément libérées lors d'un Garbage Collecting. Lorsqu'une méthode du type void finalize() est définie dans une classe, celle-ci est automatiquement appelée un peu après qu'un objet ait été identifié comme inaccessible par le Garbage Collector.

 

 

La méthode finalize peut être invoquée de manière explicite par l'utilisateur. Cependant, le système JAVA ne garanti pas que cette méthode ne sera pas appelée à nouveau après un Garbage Collecting.. La finalisation doit être plutôt considérée comme une optimisation.

 

 

4.5. Méthodes, Variables et Initialiseurs Statiques

 

 

Les méthodes et variables déclarées comme static en langage JAVA sont équivalentes à des méthodes et variables de classe en Smalltalk. Cela signifie qu'elles s'appliquent uniquement aux classes elles-mêmes et non aux instances de cette classe. De la même façon, un bloc de code à l'intérieur de la définition d'une classe peut être déclaré comme static. Il s'agit d'un initialiseur statique.

 

Les variables statiques peuvent, tout comme les variables d'instance, être initialisées lors de leur déclaration. Lorsqu'une classe possède une variable statique, celle-ci n'est définie qu'une fois pour toutes les instances de la classe. Elle leur est commune. Les méthodes et variables statiques sont accédées en les préfixant par le nom de leur classe. Cependant, elles peuvent aussi être accédées en utilisant une instance de la classe.

 

 

class Exemple {
int i; // Variable d'instance
static int j; // Variables statiques
static int arr[] = new int [10];
static { // Initialiseur statique
for (int i=0;i<arr.length;i++) {
arr[i]=i;
}
}
static void setj(int j){ // Méthode statique
Exemple.j=j;
}
static void Test() {
Exemple e=new Exemple;
Exemple.j=3; // accès par la classe
a.j=4; // accès par l'instance
Exemple.setj(3); // accès par la classe
a.setj(4); // accès par l'instance
}
}

 

 

4.5.1. Ordre de Déclaration

 

L'ordre de déclaration des classes, méthodes et variables d'instance n'a pas d'importance. Cependant, des cycles peuvent apparaître si on ne prend pas garde (voir paragraphe suivant). La déclaration suivante est possible :

class A {
void a() {
f.set(42);
}
B f;
}
class B {
void set(long n) {
this.n=n; }
long n; }

4.5.2. Ordre des Initialisations

 

Lorsqu'une classe est chargée en mémoire, les variables statiques sont initialisées, et le code des initialiseurs statiques est exécuté. L'ordre d'initialisation est l'ordre de lecture du programme. Dans l'exemple ci-dessous :

 

class C {
static int a=1;
static {
a++;
b=7;
}
static int b=2;
}

l'ordre des initialisations est le suivant :

a est mis à 1

a est incrémenté, et b est mis à 7

b est mis à 2

Si une référence est faite à une classe B non chargée dans la séquence d'initialisation d'une classe A, alors la classe B est chargée en mémoire avant la fin de l'initialisation de la classe A. Cela signifie que la séquence d'initialisation des variables statiques de la classe B sera totalement effectuée avant la fin de celle de A. Si, dans la séquence d'initialisation de B, une référence est faite à la classe A, un cycle est créé. Cela provoquera lors de l'exécution par le runtime JAVA une exception NoClassDefFoundException.

Deux variables d'instance, ou deux variables statiques, ne peuvent pas avoir de lien de dépendance avant. Par exemple, le bout de source ci-dessous provoquerait une erreur de compilation :

int i=j+2;
int j=4;

Par contre, quoiqu'il arrive, les variables statiques sont toujours chargées avant les variables d'instance. Un bout de source du type de celui qui suit est donc tout à fait légal.

int i=j+2;
static int j=4;

Les méthodes statiques ne peuvent pas utiliser les variables d'instance. Elles ne peuvent utiliser que les méthodes statiques, et les variables statiques.

 

4.6. Modificateurs d'Accès

 

Les modificateurs d'accès permettent aux programmeurs de contrôler l'accès aux variables et aux méthodes qui sont contenues dans la classe. Les trois types de modificateurs d'accès sont :

public : les méthodes, variables, classes et interfaces marquées comme publiques peuvent être accédées de n'importe où par n'importe quel objet.

private : les méthodes privées ne sont accessibles que dans la classe dans laquelle elles ont été déclarées. Ces méthodes sont aussi final (voir plus loin), car elles ne peuvent plus être surchargées en dehors de la classe. De plus, il n'est pas possible de surcharger une méthode publique et de la marquer comme privée.

protected : les méthodes ou variables qui sont protégées ne peuvent être accédées que dans la classe où elles ont été déclarées, ou dans des sous-classes de cette classe.

Les méthodes, variables et classes qui n'ont aucun modificateur d'accès ne sont accessibles qu'à l'intérieur du package dans lequel elles ont été déclarées.

 

4.7. Autres Modificateurs

 

4.7.1. Variables Threadsafe

Une variable d'instance ou statique marquée comme threadsafe ne sera jamais modifiée par deux tâches parallèles en même temps. En langage JAVA, il est en effet possible de gérer le parallélisme, comme on le verra plus tard. Si une variable threadsafe est utilisée par une tâche, elle ne pourra pas être utilisée en même temps par une autre tâche. Cela permet au compilateur d'effectuer des optimisations, et d'utiliser les variables dans des registres.

4.7.2. Variables Transient

 

Une variable transient est utilisée dans des objets persistants. Elles sont traitées de manière spéciale quand des objets de la classe sont déclarés comme persistants.

 

4.7.3. Classes, Méthodes et Variables Finales

 

Le modificateur final permet d'indiquer au compilateur :

Les classes sans héritier,

Les méthodes qui ne peuvent pas être surchargées,

Les variables dont la valeur ne peut pas être changée. Ces dernières se comportent comme des constantes.

L'utilisation du modificateur final permet au compilateur d'effectuer toutes sortes d'optimisations.

 

4.7.4. Méthodes Natives

 

Les méthodes natives sont des méthodes implémentées dans d'autres langages de programmation, dépendants de la machine où ils sont compilés. Il peut s'agir, par exemple, du C. Les méthodes marquées native n'ont pas de corps, seulement une spécification terminée par un point-virgule. Les constructeurs ne peuvent pas être natifs.

Malgré le fait qu'elles soient implémentées dans d'autres langages de programmation, les méthodes natives se comportent de la même manière que les méthodes non-natives. Ainsi, elles peuvent être surchargées.

 

4.7.5. Méthodes Abstraites

 

Les méthodes marquées abstract sont des méthodes qui permettent pour une classe, ou une interface, de spécifier une méthode que des sous-classes devront implémenter. Les méthodes marquées comme abstract doivent être implémentées dans une des sous-classes de la classe où elles ont été déclarées. Les méthodes abstraites ne possèdent pas de corps, et sont simplement la spécification de la méthode terminée par un point-virgule.

Parmi les règles importantes à retenir sur les méthodes abstraites, il faut savoir que des constructeurs ne peuvent pas être abstraits. De même, les méthodes statiques ou privées ne peuvent pas être abstraites. Une méthode qui surcharge une méthode de superclasse ne peut pas être abstraite.

On appelle classes abstraites les classes qui contiennent des méthodes abstraites, et les sous-classes de cette classe qui n'implémentent pas les méthodes abstraites héritées. Il n'est pas possible d'instancier une classe abstraite. De même, l'appel d'une méthode abstraite entraînerait une erreur de compilation.

4.7.6. Méthodes et Blocs Synchronisés

Comme cela a déjà été signalé, il est possible de gérer plusieurs tâches à la fois dans le langage JAVA. Le mot réservé synchronized est un modificateur qui indique que la méthode, ou la partie de code, doit acquérir une permission avant d'être exécutée. Cette permission est nécessaire lorsque plusieurs tâches veulent accéder en même temps à une même ressource. Ces tâches ne doivent pas pouvoir manipuler en même temps ces ressources communes.

Chaque objet et chaque classe a exactement un cadenas qui leur est associé. Lorsqu'une tâche tente d'exécuter une méthode synchronized, elle attend jusqu'à ce que le cadenas de l'objet (ou de la classe, si c'est une méthode statique) soit ouvert. A ce moment là, elle le ferme et exécute son code. Lorsque cela est terminé, le cadenas est rouvert, afin de permettre à d'autre tâches de l'utiliser.

Les blocs synchronisés fonctionnent de la même manière que les méthodes synchronisées. La seule différence, vient du fait que le cadenas utilisé n'est pas celui de la classe, ou de l'objet, dans lequel le bloc est implémenté. Cette fois, l'objet ou la classe dont le cadenas est utilisé est spécifié. Voici la syntaxe ci-dessous :

synchronized (<NomDeClasse ou NomObjet>){
/* Code requérant un accès synchronisé */
}

Une méthode synchronisée, elle, se déclare de la manière suivante :

class Exemple {
synchronized void Test{
...
}
}