Les classes internes


Le JDK 1.1 apporte de nombreuses modifications au niveau des bibliothèques de classes, mais l'ajout des classes internes constitue la seule modification majeure du langage.


Tout d'abord, définissons une classe interne :

Une classe interne est une classe définie à l'intérieur d'une autre classe.

Par exemple :

public class Avion {
	public class Pilote {
		// code de la classe Pilote
	}
}

Une classe interne peut être définie comme membre d'une classe comme dans l'exemple ci-dessus, ou à l'intérieur d'une méthode.
Elle possède les mêmes attributs de visibilité qu'une variable ou une méthode (public, private, etc).

Pour accèder à une classe interne, il faut utiliser un nom de classe complet, c'est à dire dans l'exemple précédent :

Avion.Pilote.uneMethodeDePilote();

Une classe interne a un accès complet sur tous les attributs des ses classes englobantes.

Attention, si on définit une classe à l'intérieur d'une méthode, et que cette classe crée un objet de cette classe, cet objet ne disparaitra pas avec la fin de la méthode.

Par exemple :

import java.util.*;

interface Personne {
	public String identite();
}

public class Avion {
	Personne[] listePilotes = new Personne[3] ;
	int nbrePilotes=0;
	public Personne creePilote() { 
		final String nomParDefaut = new String("Guynemer");
		class Pilote implements Personne { 
			private String nom ;
			private String prenom ;
			private Date dateNaissance ;
			Pilote(String unNom, String unPrenom, Date uneDate) { // le constructeur
				nom = nomParDefaut ;
				prenom = unPrenom ;
				dateNaissance = uneDate ;
				if (nbrePilotes < 3) 
					listePilotes[nbrePilotes++] = this ; // il y a un pilote de plus
			}
			public String identite() {
				return nom+ prenom + dateNaissance.toString() ;
			}
		} // fin de la classe Pilote
		return new Pilote("St-Exupery","Antoine",new Date(1905,3,5));
	} // fin de la méthode creePilote
}

Il est aussi possible de définir des classes anonymes. En voici un exemple d'utilisation :

import java.util.Date;

interface Personne {
	public String identite();
}

public class Avion2 {
	public static void main(String args[]) {
		System.out.println(yatilUnPiloteDansLAvion(new Avion2()));
	}
	public Personne creePilote() { // Ceci est une méthode de la classe Avion
		// Notre classe est maintenant anonyme
		// La seule chose que l'on sait c'est qu'elle respecte l'interface Personne
		return new Personne() { 
			private String nom = "Antoine";
			private String prenom = "St-Exupery";
			private Date dateNaissance  = new Date(3,5,1905);
			public String identite() {
				return nom+ prenom + dateNaissance.toString() ;
			}
		}; // fin de la classe Anonyme. notons le point-virgule, obligatoire.
		
	} // fin de la méthode creePilote
	
	public static String yatilUnPiloteDansLAvion(Avion2 monAvion) {
		Personne unPilote = monAvion.creePilote(); 
		// l'appel à creePilote instancie un objet respectant l'interface Personne.
		// Il est donc maintenant possible de lui demander de décliner son identité :
		return unPilote.identite();
	}

}	

Voyons maintenant une application des classes internes.

Supposons que vous ayez une classe Moteur :

class Moteur {
	public void demarre() {
		// le moteur tourne
	}
}

Vous disposez aussi d'une classe Voiture que vous voulez rendre "threadisable". Ceci se ferait ainsi :

public class Voiture implements Runnable {
	private Moteur monMoteur ;
	public void run() {
			monMoteur.demarre(); // le moteur tourne
	} 
	Thread t = new Thread(r,"monMoteur");
	Voiture(Moteur unMoteur) {
		monMoteur = unMoteur ;
		t.start();
	}
}

Mais il se peut que vous ayez déjà une classe Voiture utilisée par d'autres classes et que vous ne puissiez pas changer sa signature. Les classes internes permettent de résoudre le problème :

public class Voiture {
	private Moteur monMoteur ;
	Runnable r = new Runnable() { 
		public void run() {
			monMoteur.demarre(); // le moteur tourne
		} 
	}; // notez le point-virgule, obligatoire.
	Thread t = new Thread(this,"monMoteur");
	Voiture(Moteur unMoteur) {
		monMoteur = unMoteur ;
		t.start();
	}
}

Maintenant, vous êtes prêt à attaquer la nouvelle gestion évènementielle dans le JDK 1.1 :
La gestion des évènements