Developpez.com - Java
X

Choisissez d'abord la catégorieensuite la rubrique :

 

Développons en Java   2.10  
Copyright (C) 1999-2016 Jean-Michel DOUDOUX    (date de publication : 19/03/2016)

[ Précédent ] [ Sommaire ] [ Suivant ] [Télécharger ]      [Accueil ]

 

2. Les notions et techniques de base en Java

 

chapitre   2

 

Niveau : niveau 1 Fondamental 

 

Ce chapitre présente quelques concepts de base utilisés en Java relatifs à la compilation et l'exécution d'applications, notamment, les notions de classpath, de packages et d'archives de déploiement jar.

Ce chapitre contient plusieurs sections :

 

2.1. Les concepts de base

La plate-forme Java utilise quelques notions de base lors de sa mise en oeuvre, notamment :

 

2.1.1. La compilation et l'exécution

Un programme Java est composé d'un ou plus généralement plusieurs fichiers source. N'importe quel éditeur de texte peut être utilisé pour éditer un fichier source Java.

Ces fichiers source possèdent l'extension .java. Ils peuvent contenir une ou plusieurs classes ou interfaces mais il ne peut y avoir qu'une seule classe ou interface déclarée publique par fichier. Le nom de ce fichier source doit obligatoirement correspondre à la casse près au nom de cette entité publique suivi de l'extension .java

Il est nécessaire de compiler le source pour le transformer en J-code ou bytecode Java qui sera lui exécuté par la machine virtuelle. Pour être compilé, le programme doit être enregistré au format de caractères Unicode : une conversion automatique est faite par le JDK si nécessaire.

Un compilateur Java, par exemple l'outil javac fourni avec le JDK est utilisé pour compiler chaque fichier source en fichier de classe possédant l'extension .class. Cette compilation génère pour chaque fichier source un ou plusieurs fichiers .class qui contiennent du bytecode.

Etapes de compilation

Exemple :
public class MaClasse {

  public static void main(String[] args) {
    System.out.println("Bonjour");
  }
}
Résultat :
C:\TEMP>javac MaClasse.java

C:\TEMP>dir MaClas*
 Volume in drive C has no label.
 Volume Serial Number is 1E06-2R43

 Directory of C:\TEMP

31/07/2007  13:34               417 MaClasse.class
31/07/2007  13:34               117 MaClasse.java

Le compilateur génère autant de fichiers .class que de classes et interfaces définies dans chaque fichier source.

Exemple :
public class MaClasse {

  public static void main(String[] args) {
    System.out.println("Bonjour");
  }
}

class MonAutreClasse {

  public static void afficher(String message) {
    System.out.println(message);
  }
}
Résultat :
C:\TEMP>dir *.class
 Volume in drive C has no label.
 Volume Serial Number is 1E06-2R43

 Directory of C:\TEMP

31/07/2007  13:40               417 MaClasse.class
31/07/2007  13:40               388 MonAutreClasse.class

Pour exécuter une application, la classe servant de point d'entrée doit obligatoirement contenir une méthode ayant la signature public static void main(String[] args). Il est alors possible de fournir cette classe à la JVM qui va charger le ou les fichiers .class utiles à l'application et exécuter le code.

Exemple :
C:\TEMP>java MaClasse
Bonjour

Pour les classes anonymes, le compilateur génère un nom de fichier constitué du nom de la classe englobante suffixé par $ et un numéro séquentiel.

Exemple :
import javax.swing.JFrame;
import java.awt.event.*;

public class MonApplication {

  public static void main(String[] args) {
    MaFenetre f = new MaFenetre();
    f.afficher();
  }
}

class MaFenetre {

  JFrame mainFrame = null;

  public MaFenetre() {

    mainFrame = new JFrame();
    mainFrame.setTitle("Mon application");

    mainFrame.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent ev) {
        System.exit(0);
      }
    });

    mainFrame.setSize(320, 240);
  }

  public void afficher() {
    mainFrame.setVisible(true);
  }
}
Résultat :
C:\TEMP>javac MonApplication.java

C:\TEMP>dir *.class
 Volume in drive C has no label.
 Volume Serial Number is 1E06-2R43

 Directory of C:\TEMP

31/07/2007  13:50               494 MaFenetre$1.class
31/07/2007  13:50               687 MaFenetre.class
31/07/2007  13:50               334 MonApplication.class

Une classe anonyme peut elle-même définir une classe : dans ce cas le nom du fichier de classe sera celui de la classe anonyme suffixé par le caractère $ et le nom de la classe

Exemple :
import javax.swing.JFrame;
import java.awt.event.*;

public class MonApplication {

  public static void main(String[] args) {
    MaFenetre f = new MaFenetre();
    f.afficher();
  }
}

class MaFenetre {

  JFrame mainFrame = null;

  public MaFenetre() {

    mainFrame = new JFrame();
    mainFrame.setTitle("Mon application");

    mainFrame.addWindowListener(new WindowAdapter() {
      
      class MonAutreClasse {

        public void afficher(String message) {
          System.out.println(message);
        }
        
      }
      
      public void windowClosing(WindowEvent ev) {
        System.exit(0);
      }
    });

    mainFrame.setSize(320, 240);
  }

  public void afficher() {
    mainFrame.setVisible(true);
  }
}
Résultat :
C:\TEMP>javac MonApplication.java

C:\TEMP>dir *.class
 Volume in drive C has no label.
 Volume Serial Number is 1E06-2R43

 Directory of C:\TEMP

31/07/2007  13:53               549 MaFenetre$1$MonAutreClasse.class
31/07/2007  13:53               555 MaFenetre$1.class
31/07/2007  13:53               687 MaFenetre.class
31/07/2007  13:53               334 MonApplication.class

 

2.1.2. Les packages

Les fichiers sources peuvent être organisés en packages. Les packages définissent une hiérarchie de noms, chaque nom étant séparé par le caractère point. Le nom d'un package est lié à une arborescence de sous-répertoires correspondant à ce nom.

Ceci permet de structurer les sources d'une application car une application peut rapidement contenir plusieurs centaines voire milliers de fichiers source. Les packages permettent aussi d'assurer l'unicité d'une classe grâce à son nom pleinement qualifié (nom du package suivi du caractère «.» suivi du nom de la classe).

L'API Java est organisée en packages répartis en trois grands ensembles :

Les principaux packages standards de Java 6 sont :

java.applet

Création d'applets

java.awt

Création d'interfaces graphiques avec AWT

java.io

Accès aux flux entrants et sortants

java.lang

Classes et interfaces fondamentales

java.math

Opérations mathématiques

java.net

Accès aux réseaux

java.nio

API NIO

java.rmi

API RMI (invocation de méthodes distantes)

java.security

Mise en oeuvre de fonctionnalités concernant la sécurité

java.sql

API JDBC (accès aux bases de données)

java.util

Utilitaires (collections, internationalisation, logging, expressions régulières,...).


Les principaux packages d'extensions de Java 6 sont :

javax.crypto

Cryptographie

javax.jws

Services web

javax.management

API JMX

javax.naming

API JNDI (Accès aux annuaires)

javax.rmi

RMI-IIOP

javax.script

API Scripting

javax.security

Authentification et habilitations

javax.swing

API Swing pour le développement d'interfaces graphiques

javax.tools

Api pour l'accès à certains outils comme le compilateur par exemple

javax.xml.bind

API JAXB pour la mapping objet/XML

javax.xml.soap

Création de messages SOAP

javax.xml.stream

API StAX (traitement de documents XML)

javax.xml.transform

Transformation de documents XML

javax.xml.validation

Validation de documents XML

javax.xml.ws

API JAX-WS (service web)


Les principaux packages tiers de Java 6 sont :

org.omg.CORBA

Mise en oeuvre de CORBA

org.w3c.dom

Traitement de documents XML avec DOM

org.xml.sax

Traitement de documents XML avec SAX


Le package est précisé dans le fichier source grâce à l'instruction package. Le fichier doit donc, dans ce cas, être stocké dans une arborescence de répertoires qui correspond au nom du package.

Exemple :
package com.jmdoudoux.test;

public class MaCLasseTest {

  public static void main() {
      System.out.println("Bonjour");
  }

}

Si les sources de l'application sont dans le répertoire C:\Documents and Settings\jm\workspace\Tests, alors le fichier MaCLasseTest.java doit être dans le répertoire C:\Documents and Settings\jm\workspace\Tests\com\jmdoudoux\test.

Si aucun package n'est précisé, alors c'est le package par défaut (correspondant au répertoire courant) qui est utilisé. Ce n'est pas une bonne pratique d'utiliser le package par défaut sauf pour des tests.

Dans le code source, pour éviter d'avoir à utiliser les noms pleinement qualifiés des classes, il est possible d'utiliser l'instruction import suivi d'un nom de package suivi d'un caractère «.» et du nom d'une classe ou du caractère «*»

Exemple :
import javax.swing.JFrame;
import java.awt.event.*;

Remarque : par défaut le package java.lang est toujours importé par le compilateur.

 

2.1.3. Le déploiement sous la forme d'un jar

Il est possible de créer une enveloppe qui va contenir tous les fichiers d'une application Java ou une portion de cette application dans un fichier .jar (Java archive). Ceci inclus : l'arborescence des packages, les fichiers .class, les fichiers de ressources (images, configuration, ...), ... Un fichier .jar est physiquement une archive de type Zip qui contient tous ces éléments.

L'outil jar fourni avec le jdk permet de manipuler les fichiers jar.

Exemple :
C:\TEMP>jar cvf MonApplication.jar *.class
manifest ajoutÚ
ajout : MaFenetre$1$MonAutreClasse.class (entrÚe = 549) (sortie = 361) (34% comp
ressÚs)
ajout : MaFenetre$1.class (entrÚe = 555) (sortie = 368) (33% compressÚs)
ajout : MaFenetre.class (entrÚe = 687) (sortie = 467) (32% compressÚs)
ajout : MonApplication.class (entrÚe = 334) (sortie = 251) (24% compressÚs)

Le fichier .jar peut alors être diffusé et exécuté s'il contient au moins une classe avec une méthode main().

Exemple : déplacement du jar pour être sûre qu'il n'utilise pas de classe du répertoire et exécution
C:\TEMP>copy MonApplication.jar ..
        1 file(s) copied.

C:\TEMP>cd ..

C:\>java -cp MonApplication.jar MonApplication

Remarque : un fichier .jar peut contenir plusieurs packages.

Le fichier jar peut inclure un fichier manifest qui permet de préciser des informations d'exécution sur le fichier jar (classe principale à exécuter, classpath, ...) : ceci permet d'exécuter directement l'application en double-cliquant sur le fichier .jar.

 

2.1.4. Le classpath

A l'exécution, la JVM et les outils du JDK recherchent les classes requises dans :

Important : il n'est pas recommandé d'ajouter des classes ou des bibliothèques dans les sous-répertoires du JDK.

La notion de classpath est importante car elle est toujours utilisée quel que soit l'emploi qui est fait de Java (ligne de commandes, IDE, script Ant, ...). Le classpath est sûrement la notion de base qui pose le plus de problèmes aux développeurs inexpérimentés en Java mais sa compréhension est absolument nécessaire.

Le classpath permet de préciser au compilateur et à la JVM où ils peuvent trouver les classes dont ils ont besoin pour la compilation et l'exécution d'une application. C'est un ensemble de chemins vers des répertoires ou des fichiers .jar dans lequel l'environnement d'exécution Java recherche les classes (celles de l'application mais aussi celles de tiers) et éventuellement des fichiers de ressources utiles à l'exécution de l'application. Ces classes ne concernent pas celles fournies par l'environnement d'exécution incluses dans le fichier rt.jar qui est implicitement utilisé par l'environnement.

Le classpath est constitué de chemins vers des répertoires et/ou des archives sous la forme de fichiers .jar ou .zip. Chaque élément du classpath peut donc être :

Les éléments du classpath qui ne sont pas des répertoires ou des fichiers .jar ou .zip sont ignorés.

Ces chemins peuvent être absolus ou relatifs. Chaque chemin est séparé par un caractère spécifique au système d'exploitation utilisé : point-virgule sous Windows et deux-points sous Unix par exemple.

Exemple sous Windows :
.;C:\java\tests\bin;C:\java\lib\log4j-1.2.11.jar;"C:\Program Files\tests\tests.jar" 

Dans cet exemple, le classpath est composé de quatre entités :

Remarque : sous Windows, il est possible d'utiliser le caractère / ou \ comme séparateur d'arborescence de répertoires.

Par défaut, si aucun classpath n'est défini, le classpath est composé uniquement du répertoire courant. Une redéfinition du classpath (avec l'option -classpath ou -cp ou la variable d'environnement système CLASSPATH) inhibe cette valeur par défaut.

La recherche d'une classe se fait dans l'ordre des différents chemins du classpath : cet ordre est donc important surtout si une bibliothèque est précisée dans deux chemins. Dans ce cas, c'est le premier trouvé dans l'ordre précisé qui sera utilisé, ce qui peut être à l'origine de problèmes.

Le classpath peut être défini à plusieurs niveaux :

  1. Au niveau global : il faut utiliser la variable d'environnement système CLASSPATH


Exemple sous Windows

Il faut utiliser la commande set pour définir la variable d'environnement CLASSPATH. Le séparateur entre chaque élément du classpath est le caractère point-virgule. Il ne faut pas mettre d'espace de part et d'autre du signe égal.

Exemple :
set CLASSPATH=C:\java\classes;C:\java\lib;C:\java\lib\mysql.jar;.

Sous Windows 9x : il est possible d'ajouter une ligne définissant la variable d'environnement dans le fichier autoexec.bat :

Exemple :
set CLASSPATH=.;c:\java\lib\mysql.jar;%CLASSPATH% 

Sous Windows NT/2000/XP : il faut lancer l'application démarrer/paramètre/panneau de configuration/système, ouvrir l'onglet "avancé" et cliquer sur le bouton "Variables d'environnement". Il faut ajouter ou modifier la variable CLASSPATH avec comme valeur les différents éléments du classpath séparés chacun par un caractère point virgule.

Exemple sous Unix (interpréteur bash) :

Exemple :
CLASSPATH=.:./lib/log4j-1.2.11.jar
export CLASSPATH;
  1. Au niveau spécifique : en utilisant l'option -classpath ou -cp du compilateur javac et de la machine virtuelle
  2. Au niveau d'un script de lancement : cela permet de définir la variable d'environnement CLASSPATH uniquement pour le contexte d'exécution du script

L'utilisation de la variable système CLASSPATH est pratique car elle évite d'avoir à définir le classpath pour compiler ou exécuter mais c'est une mauvaise pratique car cela peut engendrer des problèmes :

Si la JVM ou le compilateur n'arrive pas à trouver une classe dans le classpath, une exception de type java.lang.ClassNotFoundException à la compilation ou java.lang.NoClassDefFoundError à l'exécution est levée.

Exemple :
package com.jmdoudoux.test;

public class MaCLasseTest {

  public static void main() {
      System.out.println("Bonjour");
  }

}

Le fichier MaCLassTest.class issu de la compilation est stocké dans le répertoire C:\Documents and Settings\jm\workspace\Tests\com\jmdoudoux\test

En débutant en Java, il est fréquent de se placer dans le répertoire qui contient le fichier .class et de lancer la JVM.

Exemple :
C:\Documents and Settings\jmd\workspace\Tests\com\jmdoudoux\test>java MaCLasseTe
st
Exception in thread "main" java.lang.NoClassDefFoundError: MaCLasseTest (wrong n
ame: com/jmdoudoux/test/MaCLasseTest)
        at java.lang.ClassLoader.defineClass1(Native Method)
        at java.lang.ClassLoader.defineClass(Unknown Source)
        at java.security.SecureClassLoader.defineClass(Unknown Source)
        at java.net.URLClassLoader.defineClass(Unknown Source)
        at java.net.URLClassLoader.access$000(Unknown Source)
        at java.net.URLClassLoader$1.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClassInternal(Unknown Source)

Cela ne fonctionne pas car la JVM cherche à partir du répertoire courant (défini dans le classpath par défaut) une classe qui soit définie dans le package par défaut (aucun nom de package précisé). Hors dans l'exemple, la classe est définie dans le package com.jmdoudoux.test.

Une autre erreur assez fréquente est de se déplacer dans le répertoire qui contient le premier répertoire du package

Exemple :
C:\Documents and Settings\jm\workspace\Tests\com\jmdoudoux\test>cd ../../..

C:\Documents and Settings\jm\workspace\Tests>java MaCLasseTest
Exception in thread "main" java.lang.NoClassDefFoundError: MaCLasseTest

Dans ce cas, cela ne fonctionne pas car le nom de la classe n'est pas pleinement qualifié

Exemple :
C:\Documents and Settings\jmd\workspace\Tests>java com.jmdoudoux.test.MaCL
asseTest
Bonjour

En précisant le nom pleinement qualifié de la classe, l'application est exécutée.

Si le classpath est redéfini, il ne faut pas oublier d'ajouter le répertoire courant au besoin en utilisant le caractère point. Cette pratique n'est cependant pas recommandée.

Exemple :
C:\Documents and Settings\jmd\workspace\Tests>java -cp test.jar com.jmdoudoux.te
st.MaCLasseTest
Exception in thread "main" java.lang.NoClassDefFoundError: com/jmdoudoux/test/Ma
CLasseTest

C:\Documents and Settings\jmd\workspace\Tests>java -cp test.jar;. com.jmdoudoux.
test.MaCLasseTest
Bonjour

Les IDE fournissent tous des facilités pour gérer le classpath. Cependant en débutant, il est préférable d'utiliser les outils en ligne de commande pour bien comprendre le fonctionnement du classpath.

 

2.1.4.1. La définition du classpath pour exécuter une application

Dans cette section, une application est contenue dans le répertoire c:\java\tests. Elle est composée de la classe com.jmdoudoux.test.MaClasse.java.

Exemple :
package com.jmdoudoux.test;

public class MaClasse {

  public static void main(
      String[] args) {
    System.out.println("Bonjour");
  }

}

La structure des répertoires et fichiers de l'application est la suivante :

Pour compiler la classe MaClasse, il faut utiliser la commande :

Exemple :
C:\java\tests>javac com/jmdoudoux/test/MaClasse.java

Le fichier MaClasse.class est créé

Pour exécuter la classe, il faut utiliser la commande

Exemple :
C:\java\tests>java com.jmdoudoux.test.MaClasse
Bonjour

Remarque : il est inutile de spécifier le classpath puisque celui-ci n'est composé que du répertoire courant qui correspond au classpath par défaut.

Il est cependant possible de le préciser explicitement

Exemple :
C:\java\tests>java -cp . com.jmdoudoux.test.MaClasse
Bonjour

C:\java\tests>java -cp c:/java/tests com.jmdoudoux.test.MaClasse
Bonjour

 

2.1.4.2. La définition du classpath pour exécuter une application avec la variable CLASSPATH

Il est possible de définir le classpath en utilisant la variable d'environnement système CLASSPATH.

Exemple : le fichier run.bat
@echo off
set CLASSPATH=c:/java/tests
javac com/jmdoudoux/test/MaClasse.java
java com.jmdoudoux.test.MaClasse

Ce script redéfinit la variable CLASSPATH, exécute le compilateur javac et l'interpréteur java pour exécuter la classe. Ces deux commandes utilisent la variable CLASSPATH.

Exemple :
C:\java\tests>run.bat
Bonjour

 

2.1.4.3. La définition du classpath pour exécuter une application utilisant une ou plusieurs bibliothèques

L'exemple de cette section va utiliser la bibliothèque log4j.

Exemple :
package com.jmdoudoux.test;

import org.apache.log4j.*;

public class MaClasse {
  static Logger logger = Logger.getLogger(MaClasse.class);

  public static void main(
      String[] args) {
    PropertyConfigurator.configure("log4j.properties");

    logger.info("Bonjour");
  }

}

Le fichier jar de log4j est stocké dans le sous-répertoire lib. Le fichier de configuration log4.properties est dans le répertoire principal de l'application puisqu'il est inclus dans le classpath

Il est nécessaire de préciser dans le classpath le répertoire tests et le fichier jar de log4j.

Exemple :
C:\java\tests>javac -cp c:/java/tests;c:/java/tests/lib/log4j-1.2.11.jar com/jmd
oudoux/test/MaClasse.java
C:\java\tests>java -cp c:/java/tests;c:/java/tests/lib/log4j-1.2.11.jar com.jmdo
udoux.test.MaClasse
[main] INFO com.jmdoudoux.test.MaClasse - Bonjour

Il est aussi possible d'utiliser la variable d'environnement système classpath.

 

2.1.4.4. La définition du classpath pour exécuter une application packagée en jar

Il est possible de préciser les bibliothèques requises dans le fichier manifest du fichier jar.

La propriété JAR-class-path va étendre le classpath mais uniquement pour les classes chargées à partir du jar. Les classes incluses dans le JAR-class-path sont chargées comme si elles étaient incluses dans le jar.

Exemple : le fichier manifest.mf
Main-Class: com.jmdoudoux.test.MaClasse
Class-Path: lib/log4j-1.2.11.jar

La clé Class-Path permet de définir le classpath utilisé lors de l'exécution.

Remarques importantes : Il faut obligatoirement que le fichier manifest se termine par une ligne vide. Pour préciser plusieurs entités dans le classpath, il faut les séparer par un caractère espace.

La structure des répertoires et des fichiers est la suivante :

Pour créer l'archive jar, il faut utiliser l'outil jar en précisant les options de création, le nom du fichier .jar, le fichier manifest et les entités à inclure dans le fichier jar.

Exemple :
C:\java\tests>jar cfm tests.jar manifest.mf com log4j.properties

Le fichier jar est créé

L'archive jar ne contient pas le sous-répertoire lib, donc il n'inclut pas la bibliothèque requise.

Pour exécuter l'application, il suffit d'utiliser l'interpréteur java avec l'option -jar

Exemple :
C:\java\tests>java -jar tests.jar
[main] INFO com.jmdoudoux.test.MaClasse - Bonjour

Attention : les entités précisées dans le classpath du fichier manifest doivent exister pour permettre l'exécution de l'application.

Exemple :
C:\java\tests>rename lib libx

C:\java\tests>java -jar tests.jar
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/log4j/Logg
er
        at com.jmdoudoux.test.MaClasse.<clinit>(MaClasse.java:6)
Caused by: java.lang.ClassNotFoundException: org.apache.log4j.Logger
        at java.net.URLClassLoader$1.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClassInternal(Unknown Source)
        ... 1 more

 

2.2. L'exécution d'une applet

Il suffit de créer une page HTML pouvant être très simple :

Exemple :
<HTML>
<TITLE> test applet Java </TITLE>
<BODY>
<APPLET code="NomFichier.class" width="270" height="200">
</APPLET>
</BODY>
</HTML>

Il faut ensuite visualiser la page créée dans l'appletviewer ou dans un navigateur 32 bits compatible avec la version de Java dans laquelle l'applet est écrite.

 

 


[ Précédent ] [ Sommaire ] [ Suivant ] [Télécharger ]      [Accueil ]

72 commentaires Donner une note à l'article (5)

 

Copyright (C) 1999-2016 Jean-Michel DOUDOUX. Vous pouvez copier, redistribuer et/ou modifier ce document selon les termes de la Licence de Documentation Libre GNU, Version 1.1 ou toute autre version ultérieure publiée par la Free Software Foundation; les Sections Invariantes étant constitués du chapitre Préambule, aucun Texte de Première de Couverture, et aucun Texte de Quatrième de Couverture. Une copie de la licence est incluse dans la section GNU FreeDocumentation Licence. La version la plus récente de cette licence est disponible à l'adresse : GNU Free Documentation Licence.

Responsables bénévoles de la rubrique Java : Mickael Baron - Robin56 -