Page d'accueilFindIt !ContactLes threadsAjouts syntaxiques de Java 5.0

Le langage JavaTM

Table des matièresHierarchie des classes

CJava

 Les classes internes

Les classes internes
Les classes anonymes
Autres nouveautés Java 1.1

 

Ce chapitre décrit les ajouts apportés dans le langage Java à partir de Java 1.1, et particulièrement les classes internes (inner classes).

Les classes internes

Syntaxe

Avec Java 1.0, il n'est possible de créer des classes public ou non qu'au niveau le plus haut dans un fichier .java, c'est à dire des classes externes dépendant directement d'un package. Java 1.1 introduit la possibilité de créer des classes internes ou interfaces internes qui sont déclarées à l'intérieur d'une classe ou d'une interface, en plus des méthodes et des champs :

class ClasseExterne
{
  // Déclararation d'une classe interne
  ModificateurClasseInterne class ClasseInterne
  {
    // Corps de ClasseInterne :
    // Déclaration des champs, des méthodes, des constructeurs,...
  }
 
  // Déclaration d'une classe interne dérivant d'une super classe 
  // et implémentant une interface
  ModificateurClasseInterne class ClasseInterne2 extends nomDeSuperClasse 
                                      implements nomInterface //, nomInterface2, ...
  {
    // ...
  }
 
  // Déclararation d'une interface interne
  ModificateurInterfaceInterne interface InterfaceInterne
  {
  }
 
  // Autres déclarations
}

ModificateurClasseInterne est optionnel et peut être un ou plusieurs des mots-clés suivants :

ModificateurInterfaceInterne peut prendre toutes les valeurs que ModificateurClasseInterne, sauf final (abstract est implicite).
Une classe interne non static ne peut pas déclarer des champs et des méthodes static.

De même dans un bloc, il est possible de déclarer des classes internes locales dont la portée est limitée au bloc. Dans ce cas, ModificateurClasseInterne ne peut être prendre comme valeur que final ou abstract.

Une classe interne peut déclarer elle-même d'autres classes internes.

Pour chacune des classes internes déclarées est généré un fichier .class à la compilation. Pour assurer l'unicité du nom de ces fichiers, la syntaxe suivante est utilisée : La classe interne ClasseInterne déclarée à l'intérieur d'une classe externe ClasseExterne, sera stockée dans le fichier ClasseExterne$ClasseInterne.class.
Pour les classes internes déclarées dans un bloc, le nom de fichier comporte en plus un identifiant numérique généré par le compilateur donnant comme nom de fichier par exemple ClasseExterne$1$ClasseInterne.class.

C++

Java 1.1 permet de déclarer des classes internes (inner classes). Les classes internes static correspondent aux classes internes du C++ (nested classes). Par contre les classes internes non static sont un concept inexistant en C++ et permettent aux instances de ces classes de garder implicitement un lien avec l'instance de la classe externe dont elles dépendent.


!

Le mécanisme utilisé par le compilateur Java 1.1 pour générer les classes internes est entièrement compatible avec la Machine Virtuelle Java 1.0.
Donc même si vous faites fonctionner vos applets avec Java 1.0, vous pouvez leur permettre quand même d'utiliser les classes internes en les compilant avec un compilateur Java 1.1 en donnant comme classpath la librairie des classes de Java 1.0.

Utilisation

Bien qu'il ne soit pas obligatoire de s'en servir, les classes internes apportent un plus pour l'organisation et la programmation des classes de votre programme :

Les classes anonymes

Par extension des classes internes locales, vous pouvez déclarer aussi des classes "anonymes" en Java.
C'est un ajout à la syntaxe de l'opérateur new : Après l'instruction new Classe1 (), il est possible d'ajouter un bloc permettant de modifier le comportement de Classe1, en outrepassant telle ou telle méthode de Classe1.
Résultat : un objet d'une classe "anonyme" dérivée de Classe1 est créé, puis un cast implicite de cette classe vers Classe1 est effectué.

SuperClasse objet = new SuperClasse (/* argument1, argument2, ...*/)
  {
    // Méthodes de SuperClasse outrepassées
    // pour modifier le comportement de SuperClasse
  };

Dans la même logique, il est possible de créer une instance d'une classe anonyme implémentant une interface InterfaceX, grâce à l'instruction :

InterfaceX objet2 = new InterfaceX ()
  {
    // Implémentation de toutes les méthodes de InterfaceX
  };

Dans ce cas, le bloc qui suit new InterfaceX () doit implémenter toutes les méthodes de InterfaceX pour qu'il soit possible de créer une instance d'une telle classe.
Comme toute classe interne, une classe anonyme peut déclarer un ensemble de champs et de méthodes d'instances.

Pour chacune des classes anonymes déclarées est généré un fichier .class à la compilation. Pour assurer l'unicité du nom de ces fichiers, le nom de chaque fichier est constitué du nom de la classe externe suivi du symbole $ et d'un identifiant numérique généré par le compilateur, comme par exemple ClasseExterne$1.class.

Bien que les classes anonymes peuvent en apparence obscurcir la lisibilité d'un programme, il existe un ensemble de circonstances où il est intéressant de les utiliser :

Par exemple, il est possible d'encore simplifier l'applet AfficheurDeCalcul, en remplaçant les classes internes Calculateur et Afficheur par des classes anonymes :

import java.applet.Applet;
import java.awt.*;
 
public class AfficheurDeCalcul extends Applet
{
  private Thread    calculateur;
  private Thread    afficheur;
 
  public void start ()
  {
    setBackground (Color.white);
    // Création de deux instances de classes 
    // anonymes implémentant la méthode run ()
    // de la classe Thread
    calculateur = new Thread ()
      {
        public void run ()
        {
          while (isAlive ())
            // calculerCourbe (), méthode de
            // la classe externe AfficheurDeCalcul
            // peut être appelée directement
            calculerCourbe (); 
        }
      };
    afficheur = new Thread ()
      {
        public void run ()
        {
          while (isAlive ())
            // dessinerCourbe (), méthode de
            // la classe externe AfficheurDeCalcul
            // peut être appelée directement
            dessinerCourbe ();
        }
      };
    
    calculateur.start ();
    afficheur.start ();
  }
 
  // ...
  // Les méthodes stop (), calculerCourbe ()
  // dessinerCourbe () et paint ()
  // sont inchangées
}

 

Les classes anonymes permettent de transformer facilement un programme existant pour exécuter un bloc d'instructions dans un thread isolé en ajoutant sur place les quelques instructions suivantes :

Avant

Après
  // ...
 
 
 
  {
    // Bloc d'instructions 
  }
  // ...
  new Thread ()
    {
      public void run ()
      {
        // Bloc d'instructions 
      }
    }.start ();

 

!

Pour éviter toute confusion avec le reste des instructions, utilisez des règles d'écriture et une indentation claires pour l'écriture des classes anonymes.

Autres nouveautés Java 1.1

Initialisations d'instance

En plus des initialisations static, il est possible d'ajouter à une classe des blocs d'initialisations d'instance. Ces blocs d'instructions sont exécutés à la création d'un objet juste après le constructeur de sa super classe et avant tout constructeur de sa classe.
Ces initialisations sont surtout utiles pour les classes anonymes qui ne peuvent pas déclarer de constructeurs.

Sauf pour les classes anonymes, les blocs d'initialisations d'instance d'une classe Classe1 ne peuvent déclencher d'exceptions que si tous les constructeurs de Classe1 déclarent qu'ils sont susceptibles de déclencher ces classe d'exceptions avec la clause throws.

Initialisation de tableaux

Les tableaux peuvent être initialisés à leur création en faisant suivre l'instruction de création du tableau new Classe0 [], par la liste des éléments à stocker, comme dans l'exemple suivant :

class Classe1
{
  // Les deux instructions suivantes sont équivalentes
  int [ ] tab1 = {1, 2};
  int [ ] tab2 = new int [] {1, 2};
 
  void methode1 (String [] tab)
  {
  }
 
  void methode2 ()
  {
    // Possibilité de créer des tableaux, envoyés 
    // directement en paramètre à une méthode
    methode1 (new String [] {"valeur1", "valeur2"});
  }
}

Comme vous pouvez le voir, c'est surtout pratique pour envoyer un tableau en paramètre sans avoir à le déclarer dans une instruction séparée.

Utilisation du mot-clé class

Toute classe ou interface peut être suivie du mot-clé class : ceci produit le même effet que l'utilisation de la méthode forName () de la classe Class.
L'instruction String.class équivalente à Class.forName ("java.lang.String") est bien plus pratique à utiliser car vous n'êtes pas obligé de donner le package complet de la classe String et d'intercepter l'exception ClassNotFoundException que peut déclencher la méthode forName ().

Cette nouvelle syntaxe peut être aussi utilisée pour tous les types primitifs et void, de la manière suivante :

byte.class
short.class
int.class
long.class
float.class
double.class
char.class
boolean.class
 
void.class

Ceci est utilisé en particulier par les classes du package java.lang.reflect pour manipuler tous les types Java (que ce soient des classes ou des types primitifs) sous forme d'un objet de classe Class.

Variables locales et paramètres final

Les variables locales et les paramètres d'une méthode ou d'un constructeur peuvent être déclarés final.

TypeRetour methode1 (final TypeParam1 param1Name /*,... */)
{
  final TypeVariable variableLocale1 = valeur;
   // ...
}

Il n'est pas obligatoire d'initialiser une variable locale final dès sa déclaration, mais par contre il n'est possible de lui assigner qu'une seule fois une valeur.
Tout paramètre ou toute variable locale que vous voulez utiliser dans une classe anonyme doivent être déclarés final. Ceci permet à cette classe anonyme d'utiliser ces variables temporaires sans risque qu'elles soient modifiées ultérieurement.
Par contre, tous les champs d'instance ou de classe existent de façon permanente et peuvent être utilisées dans une classe anonyme qu'elles soient final ou non.

C++

Comme avec const en C/C++, les paramètres d'une méthode peuvent être déclarés constants grâce à final en Java. Mais ceci interdit uniquement à une méthode de modifier la valeur d'un paramètre. Si un paramètre param1 final est une référence sur un objet, il est impossible de modifier param1 mais l'objet désigné par param1 lui peut être modifié.


Page d'accueilFindIt !ContactLes threadsAjouts syntaxiques de Java 5.0Début de la page
© Copyrights 1997-2023 Emmanuel PUYBARET / eTeks
- Tous droits réservés -
Table des matièresHiérarchie des classes