:: Enseignements :: Master :: M1 :: 2007-2008 :: Java Avancé ::
[LOGO]

Quelques notes pour le TD3


Interface

Une interface définit un type sans code. On utlise le mot-clé interface . Une interface déclare des méthodes sans indiquer le code (implantation) de celles-ci; on dit alors que les méthodes sont abstraites. Il n'est pas possible d'instantier une interface car celle-ci ne définit pas le code de ses méthodes.

Implanter une Interface

Implanter une interface consiste à déclarer un classe qui fournira le code pour l'ensemble des méthodes abstraites, on utilise le mot-clé implements . Le compilateur vérifie que toutes les méthodes de l'interface sont implantées par la classe.

Les méthodes déclarées dans une interface sont obligatoirement abstraite ( abstract ) et publique ( public ). Les champs déclarés dans une intreface sont obligatoirement constant ( final ), publique ( public ) et statique ( static ).

Classe abstraite

Il est possible de définir en Java des classes ayant des méthodes abstraites! Une classe abstraite est une classe partiellement implantée donc non instantiable. Une classe abstraite peut s'intercaler dans l'arbre d'héritage entre l'interface et les classes concrètes.

L'intérêt des classes abstraites est de permettre de partager du code commun à des sous-classes. Le code commun peut supposer la présence de certaines méthodes (donc abstraites).

Classe interne

Il existe quatre types de classe interne:
  • les classes internes simples ( inner class ), définies au niveau des classes,
  • les classes internes statiques,
  • les classes locales (ou dites de méthode), définies au niveau des méthodes,
  • les classes internes anonymes, définies au niveau d'une instance.
Les classes internes simples sont définies au sein des classes. Elles constituent des membres à part entière des classes d'inclusions au même titre que des variables ou des méthodes.

    class ClasseParente {
      ...
      modificateur class ClasseInterne {
        // instructions...
      }
      ...
    }
Une classe interne peut être déclarée avec n'importe lequel des modificateurs d'accès et les modificateurs spéciaux abstract , final ou static . Les classes possèdant le modificateur static deviennent des classes internes statiques.

Les classes internes ne doivent pas déclarer de membres statiques, hormis s'ils comportent le modificateur final , dans le cas contraire, une erreur de compilation se produit.

Toutefois, les membres statiques de la classe externe peuvent être hérités sans problème par la classe interne. Les classes imbriquées sont capables d'accéder à toutes les variables et méthodes de la classe parente, y compris celles déclarées avec un modificateur private .

Cette notation particulière spécifie que l'objet créé est une instance de la classe interne associée à l'objet résultant de l'instanciation d'une classe de plus haut niveau.

L'instanciation de la classe interne passe obligatoirement par une instance préalable de la classe d'inclusion. La classe parente est d'abord instanciée, puis c'est au tour de la classe interne de l'être par l'intermédiaire de l'objet résultant de la première instance.

    ClassParente obj_out = new ClasseParente();
    ClasseInterne obj_in = obj_out.new ClasseInterne();
    // est équivalent à
    ClasseInterne obj_in = (new ClassParente()).new ClasseInterne();
La référence d'objet this désigne une instance de la classe parente.

Le mot-clé this permet d'accéder à un membre de la classe en cours, c'est-pourquoi this.variable accède au membre de la classe interne et ClasseParente.this.variable à celui de la classe parente spécifiée.

Les classes internes statiques peuvent accéder à l'ensemble des membres statiques de leur classe parente, à l'instar des méthodes de classe. Il n'est pas nécessaire de créer une instance de la classe parente pour pouvoir instancier la classe intérieure statique contrairement aux classes internes simples. Il est possible de créer une instance d'une classe interne par l'instruction suivante : new ClasseParente.ClasseInterne()

Les méthodes d'une classe interne statique peuvent être accédées dans la classe parente de la même façon que les classes internes simples, c'est-à-dire, suite à l'instanciation de leur propre classe.

Une classe locale (ou de méthode) est définie à l'intérieur d'une méthode, et agît librement et essentiellement au sein de cette dernière.

modificateur class UneClasse {
	modificateur type_retour uneMethode([Liste de paramètres]){
   		class UneClasseLocale {
   	   	// instructions...
   		}
	}
}
Les données membres d'une classe externe peuvent être accédés par la classe locale.

class ClasseExterne {
	int x = 10;
	int y = 12;
	int z = x + y;
	void addition(){
	   class ClasseLocale {
	      boolean verification(){
	      if(x + y == z)
	         return true;
	      else
	         return false;
	      }
	   }

	   ClasseLocale obj_in = new ClasseLocale();
	   if(obj_in.verification()){
	      x = x + y;
	      System.out.println("La classe interne a bien accédé aux "
	                        + "membres de la classe extérieure.n"
	                        + "x = " + x + "ny = " + y + "nz = " + z);
	   }
	   else 
	      System.out.println("Erreur !");

	   }
	}
	public static void main(String[] args){
	   ClasseExterne obj_out = new ClasseExterne();
	   obj_out.addition();
	}
}
Seules les variables locales et les paramètres de la méthode d'inclusion, déclarées avec le modificateur final, peuvent être exploitées par les classes internes locales, sinon une erreur se produit lors de la compilation. De plus, ces variables doivent être impérativement assignées avant leur emploi dans la classe locale.

class ClasseExterne {
	int x = 10;
	int y = 12;
	// Paramètre constant utilisable par la classe locale
	ClasseExterne(final int p){
	   // Constante utilisable par la classe locale
	   final int a = 20;
	   // Variable inutilisable par la classe locale
	   int b = 44;
	   class ClasseLocale {
	      boolean verification(){
	      if(x + y == a + p)
	         return true;
	      else
	         return false;
	      }
	   }

	   ClasseLocale obj_in = new ClasseLocale();
	      if(obj_in.verification()){
	      x = x + y;
	      System.out.println("La classe interne a bien accédé aux "
	                        + "membres de la classe extérieure.n"
	                        + "x = " + x + "ny = " + y + "na = " + a);
	      }
	      else 
	      System.out.println("Erreur !");
	}
	public static void main(String[] args){
   	ClasseExterne obj_out = new ClasseExterne(2);
	}
}
Les classes anonymes ( anonymous classes ) sont déclarées immédiatement après l'expression d'instanciation d'une classe, permettant directement d'étendre ou d'implémenter respectivement la classe ou l'interface instanciée.

new Classe([Liste d'arguments]) {
	// Instructions de la classe anonyme...
};

new Interface() {
	// Instructions de la classe anonyme...
};
La déclaration d'une classe anonyme doit être toujours suivie d'un point virgule immédiatement après son accolade fermante, sans quoi une erreur de compilation serait générée.

Les classes anonymes obéissent aux mêmes restrictions que les classes locales et de plus, ne peuvent ni être abstraites (abstract) ni être statiques (static). Par contre, elles portent toujours implicitement le modificateur final.

En fait, aucun modificateur n'est permis dans une déclaration de classe anonyme.

Dans le cas d'une extension, la classe anonyme doit outrepasser une à plusieurs des méthodes de la classe à instancier. La surcharge et la définition d'une nouvelle méthode ne sont pas permis sinon elles provoqueraient une erreur de compilation.

Dans le cas d'une implémentation, la classe anonyme doit définir chacune des méthodes abstraites de l'interface à instancier, sinon une erreur de compilation se produira.

La classe A peut accéder à tous les champs et toutes les méthodes des calsses C et D. En revanche, il ne peut accéder qu'aux champs et méthodes des classes B et E qui existent dans la délcaration de la classe que B ou E implémentent ou étendent. De plus, la visibilité de la classe F est limitée à la méthode qui l'a contient.

Les classes internes B,C,E,F peuvent accéder à tous les champs et toutes les méthodes de la classe A. La classe D ne peut accéder qu'au champs et méthodes statiques de la classe A.

Finalement, l'accès par des classes anonymes ou de méthode, à des variables locales à une méthode n'est possible que si ces dernières sont déclarées comme final .