
FAQ JavaConsultez toutes les FAQ
Nombre d'auteurs : 53, nombre de questions : 231, dernière mise à jour : 7 juin 2009
Sommaire→Concepts fondamentaux- Qu'est-ce que Java ?
- Que sont le JRE, le JDK et le SDK ?
- Comment installer le JDK ?
- Où puis-je trouver le jre/jdk pour Mac ?
- Quelle sont les différences entre application, applet et servlet ?
- Où peut-on trouver les sources des classes de l'API de Sun ?
- Qu'est-ce que Java Web Start ?
- Comment connaître la version de la JVM installée ?
- Quelles sont les convention de nommage en Java ?
- Qu'est ce qu'un décompilateur ?
- Qu'est qu'un obfuscateur ?
- Qu'est-ce que le PATH ?
- Qu'est-ce que le CLASSPATH ?
- Comment modifier le CLASSPATH ?
- Qu'est-ce que le BOOTCLASSPATH ?
- Quelle est la taille maximum du code d'une méthode ?
- Quels sont les différents modes d'invocation de méthode ?
- [Java 5.0] Comment spécifier qu'un paramètre doit implémenter plusieurs interfaces ?
- Qu'est-ce que la compatibilité ascendante ? Est-elle toujours respectée ?
2.1. Les mots-clés
(17)
- Quels sont les différents mot-clés du langage Java ?
- Que signifient les mots-clés public, private et protected ?
- Que signifie le mot-clé static ?
- Que signifie le mot-clé final ?
- Que signifient les mots-clés this et super ?
- Que signifie le mot-clé strictfp ?
- Que signifie le mot-clé transient ?
- Que signifie le mot-clé volatile ?
- Et le goto en Java ?
- Comment utiliser les mots-clés break et continue ?
- Pourquoi mon switch ne veut-il pas compiler ?
- [Java 5.0] Comment fonctionne l'ellipse (nombre d'arguments variable) ?
- [Java 5.0] Comment fonctionne la boucle for étendu ?
- [Java 5.0] Comment parcourir un tableau à 2 dimensions avec un for étendu ?
- [Java 5.0] Qu'est-ce que l'import static ?
- Quelle est la différence entre 'import' et 'import static' ?
- Qu'est-ce que l'opérateur ternaire?
2.2. Les notions
(17)
- Qu'est-ce que l'héritage ?
- Qu'est ce qu'une classe abstraite ?
- Qu'est-ce qu'une classe interne ?
- Quels sont les différents types de classes internes (nested classes) ?
- Qu'est ce qu'une interface ?
- Qu'est ce qu'une méthode 'deprecated' ?
- Qu'est-ce que la sérialisation ?
- Quelles sont les règles à respecter pour redéfinir/implémenter une méthode ?
- C'est quoi la surcharge (ou encore overload)des méthodes ?
- Comment cloner un objet ?
- [Java 5.0] Qu'est-ce que les Generics (types paramétrés) ?
- [Java 5.0] Qu'est-ce que l'auto-boxing / auto-unboxing ?
- [Java 5.0] Qu'est-ce qu'une annotation ?
- [Java 5.0] Qu'est-ce qu'une enum (type énuméré) ?
- Qu'est-ce qu'une constante ?
- Qu'est-ce qu'un membre 'synthetic' ?
- [Java 5.0] Qu'est-ce qu'une méthode 'bridge' ?
Java est un langage orienté objet développé par la société Sun. La syntaxe générale est très proche de celle du C, mais Java n'est pas une surcouche du C et la syntaxe est beaucoup plus claire que celle du C++.
Cette liste n'est pas exhaustive et est donnée à titre d'exemple.
Windows
Télécharger le JDK
Rendez-vous à cette page pour trouver les dernières versions disponibles.
Téléchargez celui intitulé "JDK 6 Update 5" (en date de cette FAQ). Il contient également le JRE de la même version (donc inutile de télécharger le JDK ET le JRE). Ce téléchargement conviendra à toute utilisation standard de Java : applet, application Desktop, application console.
Installer
Suivez les étapes d'installation. Je vous conseillerais sous Windows d'installer le JDK dans un répertoire C:\Java\jdk_1.6.0_05 (1.6.0_05 pouvant changer selon la version). Idem pour le JRE dans C:\Java\jre_1.6.0_05 . Ceci par commodité et d'éviter ainsi l'utilisation du classique "Program Files" pouvant être pénible à l'utilisation à cause de l'espace.
Il va falloir ensuite positionner la variable d'environnement PATH afin de pouvoir exécuter les programmes du JDK de n'importe où (javac, etc.) :
- Ouvrez les propriétés du "Poste de travail" ("clic-droit/propriétés" sur l'icône OU "Panneau de configuration/Système").
- Allez dans l'onglet "Avancé" puis cliquez sur le bouton "Variables d'environnement".
- Créez une nouvelle variable utilisateur en cliquant sur le bouton "Nouveau".
- Donnez le nom "Path" et comme valeur le chemin vers le répertoire bin de votre installation du JDK (n'oubliez pas le répertoire "bin").
- Validez ces modifications en cliquant sur le bouton "OK".
- Pour tester votre installation, lancez un terminal : Démarrer/Exécuter puis "cmd"
- Tapez "javac -version", vous devriez avoir ce genre de résultat : "javac 1.6.0_05".
Linux (via apt-get ou synaptic)
Pour télécharger, installer et configurer le JDK, il vous suffit d'installer les derniers paquets proposés dans les dépôts de votre distribution.
Sous Ubuntu par exemple j'ai les paquets sun-java6-jdk, sun-java6-jre et sun-java6-source (sans oublier les dépendances proposées automatiquement). Le 3e, sun-java6-source, permet d'installer le src.zip du JDK contenant les sources. Livré séparément il permet d'avoir une autocomplétion détaillée dans les IDE modernes (à moins que vous ne connaissiez l'API par coeur).
Et voilà ! Vous pouvez compiler du code Java !
Contrairement aux autres plateformes, il n'est pas distribué par Sun mais par Apple. Il est possible de le télécharger sur le site suivant:
http://www.apple.com/macosx/features/java
Remarque: La dernière version disponible au moment de l'écriture de cette question est la 5.0.
Il faut noter qu'il est aussi possible de télécharger le JDK 6 pour les développeurs ici.
JavaWebStart est l'implémentation de référence par Sun de la spécification JNLP (JavaNetworkLaunchingProtocol) qui définit un mécanisme d'installation et de mise à jour supportant des fonctionnalités évoluées grâce à HTTP et XML.
L'idée de JWS est de "mimer" le comportement d'une applet pour une application Java. Un serveur héberge l'application ; le client Web Start se connecte au serveur, télécharge l'application et l'exécute. Les règles de sécurité sont semblables à celles des applets.
L'intérêt principal est la facilité de déploiement des applications. Lors d'une mise à jour, seul le serveur est à modifier, les clients téléchargeront la nouvelle application au prochain démarrage. Ce système est très intéressant pour les grosses entreprises qui ne peuvent pas se permettre d'aller mettre à jour une application sur les milliers de postes de leurs collaborateurs.
- Fonctionnement en mode déconnecté.
- Exécution externe au browser -> intégration facile & large support.
- Mise à jour incrémentale et modulaire des applications.
- Support d'un exécution sécurisée dans un environnement de type sandbox.
- Certains services avancés accessibles sans certificat (ouverture d'un flux fichier, sauvegarde d'un flux fichier, mécanisme de persistance entre sessions, impression, téléchargement de ressources, ...).
- Migration facile depuis une application Java standard.
Lien : http://www.up2go.net/
java -version
String version = System.getProperty("java.vm.version");
Retourne le numéro de version complet de la JVM. Ce numéro peut comporter des informations spécifique. Par exemple : "1.5.0_06-b05"
String version = System.getProperty("java.version");
Retourne le numéro de version exacte, y compris les éventuelles updates, mais sans informations spécifiques. Par exemple : "1.5.0_06"
String version = System.getProperty("java.specification.version");
Retourne le numéro de version des spécifications, c'est à dire le numéro de version sans les versions de mises à jours. Par exemple : "1.5"
public int maVariableEntiere;
Note : Une variable peut commencer par le caractère '_' ou '$', mais c'est fortement déconseillé par SUN.
public final static int MA_CONSTANTE
public class MaClasse
com.developpez.javaorg.w3c.domorg.xml.sax
Un décompilateur est un outil permettant de récupérer le code source d'une classe ou d'un ensemble de classes à partir d'un byte code. Sans aller aussi loin, des outils proposent tout simplement l'analyse d'une classe en affichant ses principales caractéristiques.
C'est le cas de javap, disponible dans le SDK.
E:\>javap java.lang.Object
Compiled from "Object.java"
public class java.lang.Object{
public native int hashCode();
static {};
public java.lang.Object();
protected void finalize();
throws java/lang/Throwable
public final native void notify();
public final native void notifyAll();
public final void wait();
throws java/lang/InterruptedException
public final native void wait(long);
throws java/lang/InterruptedException
public final void wait(long,int);
throws java/lang/InterruptedException
public final native java.lang.Class getClass();
protected native java.lang.Object clone();
throws java/lang/CloneNotSupportedException
public boolean equals(java.lang.Object);
public java.lang.String toString();
}
Pour plus d'informations sur la commande javap :
javap -help
Lien : Qu'est qu'un obfuscateur ?
Pour se protéger de ce type d'attaque, on peut avoir recours à un "obfuscateur". Il s'agit d'un utilitaire qui transforme le bytecode en un bytecode équivalent mais plus difficile à décompiler.
- RetroGuard : un des meilleurs obfuscateurs Open Source.
Le PATH n'est pas une notion propre à Java, mais se retrouve dans la plupart (voir la totalité) des systèmes d'exploitations.
Il s'agit d'une variable d'environnement qui contient une liste de répertoires dans lesquels vont être recherchés les fichiers exécutables.
Attention, sous Unix/Linux et assimilé, les chemins sont séparés par deux-points (':'), alors que sous Windows le séparateur est un point-virgule (';').
Ainsi, afin de pouvoir utiliser les outils du JRE/JDK, il peut être nécessaire de modifier le PATH afin d'y ajouter le répertoire bin du JRE/JDK.
On peut modifier le PATH de manière temporaire avec les commandes suivantes (depuis une console) :
Sous Unix/Linux :
export PATH=$PATH:/_chemin_du_jdk_/bin
Sous Windows :
set PATH=%PATH%;C:\_chemin_du_jdk_\bin
Il est également possible de définir le PATH de manière définitive :
Sous Unix/Linux, en effectuant la manipulation ci-dessus dans le fichier de configuration de l'utilisateur (~/.bashrc).
Sous Windows via l'onglet "Avancé" des propriétés du poste de travail.
Le CLASSPATH permet de spécifier à la machine virtuel Java les emplacements à partir desquels les resources (bytecode et autres) devront être recherché.
A l'instar de la variable d'environnement PATH, le CLASSPATH se présente sous la forme d'une liste d'éléments, qui peuvent correspondre à un répertoire ou à une archive (*.jar ou *.zip).
Lorsque la machine virtuelle a besoin de charger une resource ou une classe, elle le recherche dans les divers éléments du CLASSPATH dans l'ordre de leur déclaration.
Chaque élément du CLASSPATH correspond à une racine, et les classes sont recherchées dans les sous-répertoires correspondant au nom de leurs packages.
Par exemple, pour un CLASSPATH comportant les deux éléments suivants :
- Le répertoire /projet/classes
- L'archive /projet/lib/archive.jar
Lors du chargement de la classe com.monsite.MaClasse, la JVM recherchera d'abord le fichier /projet/classes/com/monsite/Maclasse.class.
Si ce dernier n'existe pas, la JVM recherchera alors le fichier com/monsite/Maclasse.class à l'intérieur de l'archive /projet/lib/archive.jar.
Il y a différentes manières de définir le CLASSPATH.
Lorsqu'on compile ou qu'on lance un programme Java, deux solutions s'offre à nous :
1) En créant une variable d'environnement CLASSPATH.
Exemple Unix/Linux :
export CLASSPATH=./lib/archive.jar:./classes
java ma.classe.Principale
Exemple Windows :
set CLASSPATH=./lib/archive.jar;./classes
java ma.classe.Principale
2) En utilisant les options -classpath ou -cp de java/javac.
Exemple Unix/Linux :
java -classpath ./lib/archive.jar:./classes ma.classe.Principale
Exemple Windows :
java -classpath ./lib/archive.jar;./classes ma.classe.Principale
Si la variable d'environnement CLASSPATH existe, elle est ignoré et écrasé par l'usage de ces options.
Lorsqu'on exécute un jar exécutable avec l'option -jar de java, les deux solutions précédentes ne fonctionnent pas.
La seule et unique solution consiste à renseigner l'attribut Class-Path de son fichier Manifest. A noter toutefois que le jar exécutable fera automatiquement partie du CLASSPATH.
Lorsqu'on exécute une application Java Web Start, les différents éléments du CLASSPATH sont défini dans le descripteur *.jnlp via l'élément resources.
Remarque : la plupart des EDIs permettent de configurer simplement le CLASSPATH depuis leur interface graphique.
Lien : Qu'est-ce que le CLASSPATH ?
Lien : Qu'est-ce que Java Web Start ?
Lien : Comment créer un jar exécutable ?
Le BOOTCLASSPATH fonctionne de la même manière que le CLASSPATH, si ce n'est qu'il est prioritaire sur ce dernier : il est utilisé pour définir les classes standards de l'API. Il dépend donc fortement de la machine virtuelle et ne devrait donc pas être modifié
Il est toutefois possible de le remplacer ou d'y ajouter des éléments à la fin ou en tête de liste avec les options non-standard -Xbootclasspath, -Xbootclasspath/a et -Xbootclasspath/p de la JVM de Sun (reportez-vous à la documentation pour les autres JVM).
Attention toutefois : le fait d'utiliser cette technique pour remplacer une classe du fichier rt.jar (qui comporte toutes les classes standard de l'API) vient à l'encontre de la licence d'utilisation de la JVM de Sun.
Bien que cela ne vienne pas à l'esprit, il existe une taille maximum pour le code d'une méthode sur certaines machines et qui est de 65535 octets. Cela peut sembler énorme et suffisant, ce qui est vrai pour la grande majorité des cas mais avec les editeurs graphiques qui générent du code cette limite peut étre dépassée assez aisément : vous obtientrez alors une erreur du type code too large.
Lien : Lien sur le sujet
Selon le types des méthodes, Java dispose de quatre mode d'invocation, défini par les instructions invokevirtual, invokespecial, invokestatic et invokeinterface.
- invokestatic permet d'invoquer les méthodes statiques, qui par définition ne sont lié à aucune instance de classe. La résolution de la méthode est donc effectué lors de la compilation.
- invokespecial permet d'invoquer les méthodes d'instances qui peuvent être résolues dès la compilation et qui ne dépendent donc pas du type de l'instance, c'est à dire les méthodes privées (private), les appels de méthode de la classe parente (dont l'appel est préfixé par super), ou encore pour les appels de constructeur (ainsi que this() ou super()).
- invokeinterface permet d'invoquer une méthode sur une référence dont le type est une interface. Etant donné qu'il ne s'agit pas d'un type concret, la résolution de la méthode est forcément effectué à l'exécution selon le type réel de l'instance.
- Enfin, invokevirtual permet d'invoquer les méthodes d'instances virtuelles d'une classe. C'est à dire que la résolution de la méthode à appeler est effectué lors de l'exécution selon le type réel de l'instance.
Dans tous les cas, la présence, le nombre et le type des paramètres et des valeurs de retour sont vérifié à la compilation.
Ainsi, les méthodes invoqués avec invokeinterface et invokevirtual nécessitent un traitement supplémentaire lors de l'exécution afin de rechercher la bonne méthode selon le type exacte de la référence sur laquelle elles sont utilisées. Toutefois les JVMs modernes peuvent optimiser ce type d'appel de méthodes en se basant sur l'état de l'application (en particulier le nombre et le type des classes chargées).
A noter également l'existence de la JSR-292 pour Java SE 7, dont l'objectif est d'introduire l'instruction invokedynamic afin de mieux supporter les langages de scripts. Cette instruction serait nettement moins contraignante car elle ne vérifierait pas la présence de la signature de méthode dans la classe à la compilation mais seulement lors de l'exécution, et devrait introduire un mécanisme de gestion d'erreur (une méthode par défaut à appeler si la méthode demandée n'existe pas).
Il faut préciser que ces appels se font au niveau du bytecode et non au niveau Java.
Lien : JSR 292
Dans le langage, on ne peut spécifier qu'un type pour un paramètre. Ainsi, si une méthode doit utiliser des objets qui implémentent deux interfaces, on ne peut en utiliser qu'un seul dans la définition de la méthode, ce qui oblige à un cast potentiellement dangereux à l'exécution :
public void method(Serializable data) {
Comparable cData = (Comparable) data; // throw ClassCastException
// Traitement ici
}
Ce type de code a le désavantage de provoquer une exception si le type passé en paramètre n'implémente pas la seconde interface.
Avec les Generics de Java 5.0 il est possible de reporter ce problème à la compilation. En effet les Generics ne se limitent pas seulement à paramétrer des classes, ils peuvent également s'appliquer aux méthodes, et ainsi permettent donc de spécifier plusieurs contraintes grâce à la covariance :
public <T extends Serializable & Comparable<T>> void method(T data) {
// 'data' implémente les interfaces Serializable et Comparable
// Traitement ici
}
Dans cet exemple, la méthode est paramétrée par un type T qui implémente à la fois les interfaces Serializable et Comparable<T>. Ainsi, si la méthode est utilisée avec un objet qui n'implémente pas ces deux interfaces, le compilateur génèrera une erreur à la compilation.
Bien que Sun prône une compatibilité ascendante, ce n'est pas toujours le cas.
Déjà il faut prendre en compte deux niveaux de compatibilité : binaire et source.
La compatibilité binaire est celle qui est le plus assuré. Elle permet à un code compilé avec un JDK plus ancien de fonctionner de la même manière sur une JVM plus récente. Toutefois il peut y avoir des exceptions à cela :
- Un bug ou une régression (personne n'est à l'abri de cela).
- A l'inverse une correction de bug peut avoir une influence sur les programmes existants et qui font avec.
- Certain comportement apporté par les nouvelles fonctionnalités peuvent avoir des effets indésirables sur des fonctionnalitées existantes.
La migration d'une application n'est pas aussi simple, et peut poser quelques problèmes malgré la compatibilité ascendante. De ce fait la migration a un coût et elle est généralement retardée. Bien souvent on saute même des versions (je pense que beaucoup d'entreprise vont passer de Java 1.4.2 à la version 6 directement).
Par exemple, le passage à Java 5.0 avait introduit des lenteurs réseaux sur certaines machines, dont l'origine a été assez difficile à cibler. En fait au final il s'agissait d'un bug introduit par le support du protocol NetBIOS et sur la résolution des noms de machine, qui posait problème avec la résolution des adresses IP...
Bref une entreprise ne peut pas forcément se permettre de perdre un temps fou à débugger simplement pour une nouvelle fonctionnalité ! A noter que cela n'est pas propre à Java.
Ensuite, il faut prendre en compte la compatibilité des sources : c'est bien beau qu'un ancien programme fonctionne sur la nouvelle JVM, mais il faut que ce programme puisse être recompilé afin qu'il puisse éventuellement évoluer...
Or c'est déjà nettement plus complexe, car les évolutions du langages ou les modifications de l'API peuvent poser de nouveaux problèmes de compilation, par exemple :
- L'introduction de nouveau mot-clef (assert, enum) peuvent poser problèlme s'ils étaient utilisé comme identifieur...
- L'introduction de nouvelle méthode peuvent poser des problèmes de compilation (ambiguité sur la méthode a appelé ou autre problème si des méthodes du même nom existe déjà dans la classe ou les classes filles).
- Nouveaux warning (en particulier en ce qui concerne les Generics), alors qu'un code "zéro-warning" peut être requis (par le client par exemple).
En bref tout n'est pas aussi simple que cela, même si c'a l'est bien plus que pour d'autre langage/plateforme...
On peut également noter qu'à chaque version, Sun met à disposition une liste des incompatibilitées connues (comprendre volontaire) par rapport à la version précédente :


















