1. STRUCTURE GENERALE
 
 
ORGANISATION DES FICHIERS
 
 
Fichiers sources
 

Les fichiers sources en Java portent l'extension .java. Contrairement au C++, il n'est pas nécessaire de séparer dans des fichiers différents l'interface (.hpp) et l'implémentation (.cpp). En revanche, dans un fichier source, il ne peut y avoir qu'une seule classe visible de l'extérieur du fichier et c'est celle qui porte le même nom que le fichier. Un exemple, si l'on veut créer la classe Liste, elle doit être écrite dans le fichier Liste.java. Si d'autres classes comme Cellule sont définies dans ce même fichier, elles ne seront visibles que dans le fichier. Le mot-clé public qui désigne une classe visible de l'extérieur ne peut être utilisé que pour la classe Liste. Le fichier Liste.java contiendra par exemple:

public class Liste { ... }
class Cellule { ... }
 
Packages
 

Plusieurs classes peuvent être regroupées pour former un package. En C++, cela peut être fait par l'intermédiaire des namespaces, aucune contrainte n'est faite sur l'organisation physique des fichiers qui composent un package. En Java, le mot-clé package est employé pour indiquer à quel package appartient un fichier. Reprenons l'exemple de Liste.java, voici sa structure lorsqu'il fait partie du package conteneur.

package conteneur;
public class Liste { ... }
class Cellule { ... }

L'organisation physique des fichiers en Java est très importante. Prenons l'exemple suivant d'une arborescence de fichiers.

  • Répertoire maths/

    • Répertoire matrice/

      • Fichier Matrice.java

      • Fichier Vecteur.java

    • Répertoire grandnombre/

Cela signifie que le package maths en contient deux autres, matrice et grandnombre. Le package matrice contient deux classes Matrice et Vecteur. La convention en Java est de nommer les classes avec la première lettre en majuscule et les packages avec la première lettre en minuscule. Pour accéder directement à la classe Matrice, il faut spécifier le chemin complet maths.matrice.Matrice. La commande

import maths.matrice.*;

au début d'un fichier permet d'utiliser n'importe quelle classe de maths.matrice, en l'occurrence Matrice, directement dans ce fichier. Cette commande est équivalente à using namespace en C++.

 
COMPILATION ET EXECUTION
 
 
Machine virtuelle Java et pseudo-code binaire
 

Dans la plupart des langages classiques, la compilation signifie la traduction de code source dans le langage du processeur, i.e. le language machine. Cela signifie que si l'on prend des fichiers binaires (i.e. des fichiers résultants d'une compilation), et qu'on les place sur une machine différente de celle pour laquelle ils ont été compilés, ces fichiers sont totalement inexploitables. La figure suivante illustre les processus de compilation et d'exécution d'un programme C++.

Java a été conçu pour être totalement portable. Au lieu de compiler le code source Java dans un langage machine spécifique (il existe quand même des compilateurs qui peuvent le faire), le code source est compilé dans un pseudo-langage machine, appelé souvent pseudo-code binaire, qu'un interpréteur logiciel, la machine virtuelle Java (Java Virtual Machine, JVM), peut décoder et exécuter. Ainsi, toute machine qui dispose d'une JVM peut exécuter des fichiers binaires Java. La figure suivante illustre les processus de compilation et d'exécution d'un programme Java.

Au cours de leur exécution, les fichiers binaires Java sont interprétés, cela signifie qu'en temps réel, la machine virtuelle Java traduit du code binaire Java en code binaire dédié pour la machine sur laquelle elle s'exécute. Cela implique nécessairement un ralentissement dans l'exécution des programmes, en comparaison avec les programmes C++ par exemple qui sont directement compilés pour la machine. Mais un mécanisme appelé Just In Time (JIT) permet d'optimiser cette phase de traduction du code binaire Java en code binaire dédié, ce qui améliore grandement les performances des programmes Java et les rapproche des performances des compilations dédiées. Les mauvaises performances que l'on rencontre souvent avec les programmes Java proviennent plutôt du fait que l'héritage est trop utilisé, simplement parce que le langage est privé de la notion de patron (ce qui est en train d'être corrigé). En effet, l'héritage, par l'appel à une méthode virtuelle ou par le downcast (conversion d'un objet d'une classe en l'une de ses sous-classes), peut entraîner des ralentissements conséquents.

 
Compiler un code source
 

Voici maintenant la commande qui permet de compiler un programme Java. Considérons le fichier Liste.java, s'il dépend d'autres fichiers Java, le compilateur va se charger automatiquement de les compiler ou de les recompiler si nécessaire. Ainsi, la commande

javac -classpath <classpath> Liste.java

compile le fichier Liste.java et tous les fichiers dont il dépend si nécessaire (i.e. s'ils ont été modifiés ou s'ils n'ont jamais été compilés). Pour trouver ces fichiers, le compilateur regarde dans les répertoires listés par <classpath>. Pour des programmes simples, il suffit de préciser le répertoire courant (i.e. <classpath> = .). Pour éviter de préciser à chaque fois <classpath>, il existe la variable d'environnement CLASSPATH qui peut être initialisée à partir du shell. Il faut noter que les répertoires qui constituent CLASSPATH ou <classpath> doivent être séparés par : (sous Unix) ou ; (sous Windows).

 
Exécuter un pseudo-code binaire
 

La compilation fournit pour chaque fichier .java compilé un fichier avec l'extension .class de même nom. Ce fichier peut être placé sur n'importe quelle machine avec une JVM. Pour l'exécuter, il suffit de taper la commande suivante.

java -classpath <classpath> Liste

Elle ordonne à la JVM d'interpréter le fichier Liste.class. Là aussi, il faut préciser éventuellement le chemin des fichiers dont dépend Liste.class, à l'aide de <classpath>. Nous verrons par la suite que tous les fichiers .class ne peuvent pas être exécutés directement, il faut qu'ils disposent d'une méthode particulière, équivalente de la fonction main en C++.

 
L'interface JNI
 

Pour diverses raisons, un programme implémenté en Java peut être plus lent que son implémentation en C++. L'efficacité peut être un critère important pour un logiciel, notamment ceux dédiés au calcul scientifique. En revanche, Java offre une portabilité intéressante au niveau du graphisme. Même si cela est souvent déconseillé, il est possible de combiner du code C++ avec du code Java. Typiquement, pour une application scientifique, les calculs seront effectués en C++ et l'interface en Java. Le mécanisme qui permet cela est JNI (Java Native Interface), une interface entre Java et C++. Le lecteur intéressé pourra consulter le livre: The Java Native Interface: Programmer's Guide and Specification, Sheng Liang, 1999, Addison-Wesley. Une partie de ce livre est disponible dans le tutoriel Java de Sun Microsystems. JNI permet à Java d'appeler des méthodes dites natives (i.e. fonctions C++ compilées dans un langage machine dédié), il permet également à C++ d'appeler des méthodes des classes Java. La figure suivante illustre sommairement ce mécanisme.

 
 
 
Copyright (c) 1999-2016 - Bruno Bachelet - bruno@nawouak.net - http://www.nawouak.net
La permission est accordée de copier, distribuer et/ou modifier ce document sous les termes de la licence GNU Free Documentation License, Version 1.1 ou toute version ultérieure publiée par la fondation Free Software Foundation. Voir cette licence pour plus de détails (http://www.gnu.org).