Programmation Java/JDK
Le JDK est un ensemble d'outil permettant de développer en Java.
Pour obtenir la liste des options d'un outil, il suffit de lancer l'outil sans aucun argument.
Compiler le code
[modifier | modifier le wikicode]javac est le compilateur qui convertit le code source .java en fichier .class (contenant le bytecode Java).
Supposons que vous avez :
- un dossier « src » qui contient vos sources (tous vos fichiers .java) ;
- un dossier « bin » où vous placerez tous les fichiers compilés (les fichier .class correspondant).
# compile seulement la classe Exemple et place le résultat dans bin javac -d bin src/Exemple.java # compile toutes les sources trouvées dans src et les place dans bin javac -d bin src/**/*.java
Si la compilation échoue parce que votre code utilise des classes que javac ne connait pas (erreur Unable to find symbol), vous devez préciser à javac un classpath comme expliqué plus loin.
Lancer l'application
[modifier | modifier le wikicode]java
permet une dans lancer une application java en ligne de commande, il faut passer en paramètre le nom complet (pleinement qualifié) de la classe.
java org.wikibooks.fr.Exemple argument_1 argument_2
La ligne de commande ci-dessus appel la méthode public static void main(String[] args) de la classe Exemple du package org.wikibooks.fr avec args, un tableau à deux éléments : "argument_1" et argument_2".
javaw permet une application Java sans console (interface graphique seule).
javaw org.wikibooks.fr.Exemple
Une archive java (*.jar) avec l'option -jar
, un petit fichier (appelé « Manifest ») contenu dans le jar indique lui-même le nom de la classe principale à lancer.
java -jar chemin/vers/le/fichier.jar
Préciser le CLASSPATH
[modifier | modifier le wikicode]Dans toutes les commandes ci-dessus, il faut permettre à java de trouver tous les fichiers compilés nécessaire à l'exécution du code (les fichiers *.class
générés avec javac
). Pour cela, il faut préciser à java
les répertoires ou celui-ci pourra trouver les classes et les packages nécessaires à l'application.
Pour cela, il faut définir ce qu'on appelle le « CLASS PATH », c'est une simple chaîne qui définit plusieurs chemins pour trouver des .class séparés par ":" sous Linux ou ";" sous Windows. Les chemins peuvent être des chemins vers des fichiers .jar ou vers des répertoires contenant des fichiers .class
. Il y a deux façons de préciser le CLASSPATH à java, la première est d'utiliser le paramètre -classpath
de ligne de commande.
Sous Linux, les chemins sont séparés par le caractère deux-points :
java -classpath chemin/vers/une/premiere/bibliotheque.jar:chemin/vers_une_autre/bibliotheque.jar:bin org.wikibooks.fr.Exemple
Sous Windows, les chemins sont séparés par le caractère point-virgule :
java -classpath X:\chemin\vers\une\premiere\bibliotheque.jar;Y:\chemin\vers_une_autre\bibliotheque.jar;bin org.wikibooks.fr.Exemple
Ici, java essaiera de trouver le fichier Exemple.class dans les deux jars donnés puis dans le dossier bin. Si le fichier n'est trouvé dans aucun de ces éléments, il y aura une erreur (Class not found exception).
La seconde façon de préciser le CLASSPATH est de définir une variable d'environnement système. Sous Linux :
export CLASSPATH="chemin/vers/une/premiere/bibliotheque.jar:chemin/vers_une_autre/bibliotheque.jar"
Sous Windows :
SET "CLASSPATH=X:\chemin\vers\une\premiere\bibliotheque.jar;Y:\chemin\vers_une_autre\bibliotheque.jar"
Attention à ne pas confondre java -jar fichier.jar
et java -cp fichier.jar
, la première commande permet de lancer le programme qui se trouve dans fichier.jar et fonctionne ; la seconde précise que des classes peuvent être chargée depuis fichier.jar mais oublie de préciser quelle classe il faut lancer : java indiquera qu'un paramètre est manquant. Enfin, sachez que vous pouvez remplacer « -classpath » par « -cp ».
jar
[modifier | modifier le wikicode]L'outil jar
permet de regrouper les classes (fichiers *.class
) et ressources d'une application en une seule archive exécutable.
Cette archive est au format ZIP mais possède l'extension .jar
.
Dans cette archive, un répertoire spécial situé à la racine nommé META-INF
contient des fichiers d'information et de configuration pour la machine virtuelle Java, dont notamment le fichier MANIFEST.MF
(fichier manifest, MF = Meta File).
Une archive JAR peut être exécutable si la classe principale (contenant une méthode statique nommée main
) de l'application est spécifiée dans ce fichier MANIFEST.MF
.
Dans ce cas, l'application peut se lancer avec la commande suivante :
java -jar chemin_de_l_archive.jar ...arguments passés à l'application si besoin...
Ce fichier manifest est au format texte. Exemple :
Manifest-Version: 1.0 Ant-Version: Apache Ant 1.7.1 Created-By: 19.1-b02 (Sun Microsystems Inc.) Main-Class: org.wikibooks.fr.ApplicationExemple Class-Path: .
Il possède différents champs. Chaque champ possède un nom, suivi de deux-points et de sa valeur. Si une valeur est longue, elle peut être répartie sur plusieurs lignes, chaque ligne additionnelle commençant alors par au moins un caractère espace.
Pour plus de détails sur les fichiers manifest voir http://docs.oracle.com/javase/tutorial/deployment/jar/manifestindex.html
Le champ Class-Path
dans une archive JAR diffère du paramètre classpath passé aux outils Java :
- Il ne peut contenir que des chemins relatifs à d'autres archives Java (*.jar) ; les répertoires ne sont pas supportés ;
- Le séparateur est un caractère espace. Les fichiers référencés ne peuvent donc en contenir dans leur nom.
Pour créer une archive JAR à partir d'un répertoire contenant les classes et ressources (les sous-répertoires devant correspondre aux packages), et d'un fichier texte pour le fichier manifest :
jar cfm mon_archive.jar mon_manifest.txt -C répertoire .
Quel que soit le nom et l'extension du fichier source pour le manifest, il sera nommé MANIFEST.MF
dans l'archive.
Les arguments de la commande sont décrits ci-dessous :
- cfm
- Une série de caractères dont le premier spécifie l'action principale :
- c Créer une archive (Create).
- t Afficher le contenu de l'archive (Table of content).
- x Extraire les fichiers de l'archive (eXtract files).
- u Mettre à jour l'archive existante (Update archive).
- Les caractères suivants donne l'ordre des arguments qui suivent :
- f Le nom du fichier archive (archive File).
- m Le nom du fichier manifest à utiliser (Manifest file).
- mon_archive.jar
- Le nom du fichier archive.
- mon_manifest.txt
- Le nom du fichier manifest à utiliser.
- -C répertoire
- Précise le chemin du répertoire pour les chemins relatifs
- .
- Inclus le fichier spécifié (
.
désignant le répertoire courant sous la plupart des systèmes d'exploitation).
Eclipse possède une interface interactive pour générer un fichier JAR à partir des classes d'un projet Java, ou d'une configuration d'exécution.
javadoc
[modifier | modifier le wikicode]L'outil javadoc
est le générateur de documentation, qui génère automatiquement de la documentation à partir des commentaires du code source.
Voir le chapitre sur les commentaires pour plus de détails sur l'outil et son utilisation.
jdb
[modifier | modifier le wikicode]Le JDK fournit un débogueur nommé jdb
(Java DeBugger) utilisable depuis la ligne de commande.
Mode interactif
[modifier | modifier le wikicode]Lancez la ligne de commande jdb
pour accéder au débogueur interactif :
- Entrez
version
pour obtenir les versions de l'outil et de Java, - Entrez
help
pour obtenir la liste des commandes disponibles, - Entrez
exit
pour quitter le débogueur.
Initializing jdb ... > version This is jdb version 1.6 (Java SE version 1.8.0_05) Java Debug Interface (Reference Implementation) version 1.6 Java Debug Wire Protocol (Reference Implementation) version 1.6 JVM Debug Interface version 1.2 JVM version 1.8.0_05 (Java HotSpot(TM) 64-Bit Server VM, mixed mode, sharing) > help ** command list ** connectors -- list available connectors and transports in this VM run [class [args]] -- start execution of application's main class threads [threadgroup] -- list threads thread <thread id> -- set default thread suspend [thread id(s)] -- suspend threads (default: all) resume [thread id(s)] -- resume threads (default: all) where [<thread id> | all] -- dump a thread's stack wherei [<thread id> | all]-- dump a thread's stack, with pc info up [n frames] -- move up a thread's stack down [n frames] -- move down a thread's stack kill <thread id> <expr> -- kill a thread with the given exception object interrupt <thread id> -- interrupt a thread print <expr> -- print value of expression dump <expr> -- print all object information eval <expr> -- evaluate expression (same as print) set <lvalue> = <expr> -- assign new value to field/variable/array element locals -- print all local variables in current stack frame classes -- list currently known classes class <class id> -- show details of named class methods <class id> -- list a class's methods fields <class id> -- list a class's fields threadgroups -- list threadgroups threadgroup <name> -- set current threadgroup stop in <class id>.<method>[(argument_type,...)] -- set a breakpoint in a method stop at <class id>:<line> -- set a breakpoint at a line clear <class id>.<method>[(argument_type,...)] -- clear a breakpoint in a method clear <class id>:<line> -- clear a breakpoint at a line clear -- list breakpoints catch [uncaught|caught|all] <class id>|<class pattern> -- break when specified exception occurs ignore [uncaught|caught|all] <class id>|<class pattern> -- cancel 'catch' for the specified exception watch [access|all] <class id>.<field name> -- watch access/modifications to a field unwatch [access|all] <class id>.<field name> -- discontinue watching access/modifications to a field trace [go] methods [thread] -- trace method entries and exits. -- All threads are suspended unless 'go' is specified trace [go] method exit | exits [thread] -- trace the current method's exit, or all methods' exits -- All threads are suspended unless 'go' is specified untrace [methods] -- stop tracing method entrys and/or exits step -- execute current line step up -- execute until the current method returns to its caller stepi -- execute current instruction next -- step one line (step OVER calls) cont -- continue execution from breakpoint list [line number|method] -- print source code use (or sourcepath) [source file path] -- display or change the source path exclude [<class pattern>, ... | "none"] -- do not report step or method events for specified classes classpath -- print classpath info from target VM monitor <command> -- execute command each time the program stops monitor -- list monitors unmonitor <monitor#> -- delete a monitor read <filename> -- read and execute a command file lock <expr> -- print lock info for an object threadlocks [thread id] -- print lock info for a thread pop -- pop the stack through and including the current frame reenter -- same as pop, but current frame is reentered redefine <class id> <class file name> -- redefine the code for a class disablegc <expr> -- prevent garbage collection of an object enablegc <expr> -- permit garbage collection of an object !! -- repeat last command <n> <command> -- repeat command n times # <command> -- discard (no-op) help (or ?) -- list commands version -- print version information exit (or quit) -- exit debugger <class id>: a full class name with package qualifiers <class pattern>: a class name with a leading or trailing wildcard ('*') <thread id>: thread number as reported in the 'threads' command <expr>: a Java(TM) Programming Language expression. Most common syntax is supported. Startup commands can be placed in either "jdb.ini" or ".jdbrc" in user.home or user.dir > exit
Ligne de commande
[modifier | modifier le wikicode]Pour les options de la ligne de commande, entrez la commande jdb -help
Usage: jdb <options> <class> <arguments> where options include: -help print out this message and exit -sourcepath <directories separated by ";"> directories in which to look for source files -attach <address> attach to a running VM at the specified address using standard connector -listen <address> wait for a running VM to connect at the specified address using standard connector -listenany wait for a running VM to connect at any available address using standard connector -launch launch VM immediately instead of waiting for 'run' command -listconnectors list the connectors available in this VM -connect <connector-name>:<name1>=<value1>,... connect to target VM using named connector with listed argument values -dbgtrace [flags] print info for debugging jdb -tclient run the application in the HotSpot(TM) Client Compiler -tserver run the application in the HotSpot(TM) Server Compiler options forwarded to debuggee process: -v -verbose[:class|gc|jni] turn on verbose mode -D<name>=<value> set a system property -classpath <directories separated by ";"> list directories in which to look for classes -X<option> non-standard target VM option <class> is the name of the class to begin debugging <arguments> are the arguments passed to the main() method of <class> For command help type 'help' at jdb prompt
Déboguer une classe
[modifier | modifier le wikicode]Cette section montre le débogage d'une classe simple :
package org.wikibooks.fr; /** * Une classe simple à déboguer. * @author fr.wikibooks.org */ public class Addition { public static Integer somme(Integer a, Integer b) { if (a==null) return b; if (b==null) return a; return a + b; } public static void main(String[] args) { // null équivaut à 0 pour la méthode somme System.out.println("Somme 1+2 = "+somme(1,2)); System.out.println("Somme +2 = "+somme(null,2)); } }
Après compilation de la classe, la ligne de commande pour lancer de débogueur est la suivante, en supposant que les fichiers sources dans un sous-répertoire nommé src
et le code compilé dans un sous-répertoire nommé bin
:
jdb -classpath bin -sourcepath src org.wikibooks.fr.Addition
Beaucoup de commandes ne sont pas disponibles tant que la JVM n'est pas lancée :
Initializing jdb ... > print 10+15 Command 'print' is not valid until the VM is started with the 'run' command > trace methods Command 'trace' is not valid until the VM is started with the 'run' command
Lancez la classe spécifiée en ligne de commande :
> run run org.wikibooks.fr.Addition Set uncaught java.lang.Throwable Set deferred uncaught java.lang.Throwable > VM Started: Somme 1+2 = 3 Somme +2 = 2 The application exited
L'application a été exécutée et s'est terminée, et le débogueur a quitté également. Le débogueur n'est utilisable que durant l'exécution de l'application, que son exécution soit active ou suspendue soit par un point d'arrêt soit par une exécution pas à pas.
Point d'arrêt et pas à pas
[modifier | modifier le wikicode]La pose d'un point d'arrêt peut se faire par la commande stop in
qui a besoin du nom de la classe (paquetage inclus) et de la méthode.
jdb -classpath bin -sourcepath src org.wikibooks.fr.Addition
Posez ensuite un point d'arrêt à l'entrée de la méthode main
et lancez l'exécution :
Initializing jdb ... > stop in org.wikibooks.fr.Addition.main Deferring breakpoint org.wikibooks.fr.Addition.main. It will be set after the class is loaded. > run run org.wikibooks.fr.Addition Set uncaught java.lang.Throwable Set deferred uncaught java.lang.Throwable > VM Started: Set deferred breakpoint org.wikibooks.fr.Addition.main Breakpoint hit: "thread=main", org.wikibooks.fr.Addition.main(), line=19 bci=0 19 System.out.println("Somme 1+2 = "+somme(1,2)); main[1]
Les commandes testées auparavant sont désormais disponibles :
main[1] print 10+15 10+15 = 25 main[1] trace methods
Exécutez ensuite l'application pas à pas avec la commande step
pour exécuter la ligne de code suivante en entrant dans les méthodes appelées, ou la commande next
pour ne pas entrer dans les méthodes appelées.
À chaque pas, vous pouvez afficher la valeur des variables locales, évaluer une expression, ...
- La commande
where
affiche la pile des appels du thread courant, - La commande
list
liste le code en cours d'exécution du thread courant.
main[1] step > Method entered: Step completed: "thread=main", org.wikibooks.fr.Addition.somme(), line=11 bci=0 11 if (a==null) return b; main[1] print a a = "1" main[1] print b b = "2" main[1] print a+b com.sun.tools.example.debug.expr.ParseException: Invalid operation '+' on an Object a+b = null main[1] where [1] org.wikibooks.fr.Addition.somme (Addition.java:11) [2] org.wikibooks.fr.Addition.main (Addition.java:19) main[1] list 7 public class Addition 8 { 9 public static Integer somme(Integer a, Integer b) 10 { 11 => if (a==null) return b; 12 if (b==null) return a; 13 return a + b; 14 } 15 16 public static void main(String[] args) main[1] step > Step completed: "thread=main", org.wikibooks.fr.Addition.somme(), line=12 bci=6 12 if (b==null) return a; main[1] step > Step completed: "thread=main", org.wikibooks.fr.Addition.somme(), line=13 bci=12 13 return a + b; main[1] step > Method exited: return value = instance of java.lang.Integer(id=394), "thread=main", org.wikibooks.fr.Addition.somme(), line=13 bci=24 13 return a + b; main[1] step > Step completed: "thread=main", org.wikibooks.fr.Addition.main(), line=19 bci=23 19 System.out.println("Somme 1+2 = "+somme(1,2)); main[1] step > Somme 1+2 = 3 Step completed: "thread=main", org.wikibooks.fr.Addition.main(), line=20 bci=32 20 System.out.println("Somme +2 = "+somme(null,2)); main[1] step > Method entered: Step completed: "thread=main", org.wikibooks.fr.Addition.somme(), line=11 bci=0 11 if (a==null) return b; main[1] step > Method exited: return value = instance of java.lang.Integer(id=395), "thread=main", org.wikibooks.fr.Addition.somme(), line=11 bci=5 11 if (a==null) return b; main[1] step > Step completed: "thread=main", org.wikibooks.fr.Addition.main(), line=20 bci=52 20 System.out.println("Somme +2 = "+somme(null,2)); main[1] step > Somme +2 = 2Step completed: "thread=main", org.wikibooks.fr.Addition.main(), line=21 bci=61 21 } main[1] step > Method exited: return value = <void value>, "thread=main", org.wikibooks.fr.Addition.main(), line=21 bci=61 21 } main[1] step > The application exited
Après un point d'arrêt ou un pas d'exécution, pour continuer l'exécution jusqu'à la fin ou le prochain point d'arrêt, utiliser la commande cont
(continue).
javah
[modifier | modifier le wikicode]javah permet de générer un fichier d'en-tête C (*.h) contenant la déclaration des fonctions correspondantes aux méthodes natives de la classe compilée spécifiée.
javah -classpath directory-list classname
- Pour plus de détails voir : Développer en Java/Faire appel à du code natif.
javap
[modifier | modifier le wikicode]javap permet de lister les membres et désassembler la classe compilée spécifiée.
javap -c -classpath directory-list classname
Options
[modifier | modifier le wikicode]-help
--help
-?
- Afficher les options possibles.
-version
- Information de version.
-v
-verbose
- Afficher toutes les informations supplémentaires.
-l
- Afficher les numéros de ligne et les tables de variables locales.
-public
- N'afficher que les classes et membres publics.
-protected
- Afficher les classes et membres publics ou protégés.
-package
- Afficher les classes et membres publics, protégés ou paquetage (par défaut).
-p
-private
- Afficher toutes les classes et tous les membres.
-c
- Désassembler le code.
-s
- Afficher les signatures des types internes.
-sysinfo
- Afficher les informations systèmes (chemin, taille, date, MD5) des classes traitées.
-constants
- Afficher les constantes finales et statiques.
-classpath chemin
-cp chemin
- Spécifier le chemin où trouver les classes.
-bootclasspath chemin
- Redéfinir le chemin des classes bootstrap.
Exemple avec désassemblage du code
[modifier | modifier le wikicode]La classe désassemblée dans cet exemple est produite à partir de ce fichier source :
package org.wikibooks.fr;
/**
* Une classe simple à désassembler.
* @author fr.wikibooks.org
*/
public class Addition
{
public static Integer somme(Integer a, Integer b)
{
if (a==null) return b;
if (b==null) return a;
return a + b;
}
public static void main(String[] args)
{
// null équivaut à 0 pour la méthode somme
System.out.println("Somme 1+2 = "+somme(1,2)); // -> 3
System.out.println("Somme +2 = "+somme(null,2)); // -> 2
}
}
L'option verbose permet d'afficher toutes les informations sur le fichier .class :
> javap -cp W:\Programme\TestJava\bin -v org.wikibooks.fr.Addition
Classfile /W:/Programme/TestJava/bin/org/wikibooks/fr/Addition.class Last modified 31 mai 2022; size 1117 bytes MD5 checksum 0a72b766cde42eff71b4b8f7f4a67266 Compiled from "Addition.java" public class org.wikibooks.fr.Addition SourceFile: "Addition.java" minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Class #2 // org/wikibooks/fr/Addition #2 = Utf8 org/wikibooks/fr/Addition #3 = Class #4 // java/lang/Object #4 = Utf8 java/lang/Object #5 = Utf8 <init> #6 = Utf8 ()V #7 = Utf8 Code #8 = Methodref #3.#9 // java/lang/Object."<init>":()V #9 = NameAndType #5:#6 // "<init>":()V #10 = Utf8 LineNumberTable #11 = Utf8 LocalVariableTable #12 = Utf8 this #13 = Utf8 Lorg/wikibooks/fr/Addition; #14 = Utf8 somme #15 = Utf8 (Ljava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Integer; #16 = Methodref #17.#19 // java/lang/Integer.intValue:()I #17 = Class #18 // java/lang/Integer #18 = Utf8 java/lang/Integer #19 = NameAndType #20:#21 // intValue:()I #20 = Utf8 intValue #21 = Utf8 ()I #22 = Methodref #17.#23 // java/lang/Integer.valueOf:(I)Ljava/lang/Integer; #23 = NameAndType #24:#25 // valueOf:(I)Ljava/lang/Integer; #24 = Utf8 valueOf #25 = Utf8 (I)Ljava/lang/Integer; #26 = Utf8 a #27 = Utf8 Ljava/lang/Integer; #28 = Utf8 b #29 = Utf8 StackMapTable #30 = Utf8 main #31 = Utf8 ([Ljava/lang/String;)V #32 = Fieldref #33.#35 // java/lang/System.out:Ljava/io/PrintStream; #33 = Class #34 // java/lang/System #34 = Utf8 java/lang/System #35 = NameAndType #36:#37 // out:Ljava/io/PrintStream; #36 = Utf8 out #37 = Utf8 Ljava/io/PrintStream; #38 = Class #39 // java/lang/StringBuilder #39 = Utf8 java/lang/StringBuilder #40 = String #41 // Somme 1+2 = #41 = Utf8 Somme 1+2 = #42 = Methodref #38.#43 // java/lang/StringBuilder."<init>":(Ljava/lang/String;)V #43 = NameAndType #5:#44 // "<init>":(Ljava/lang/String;)V #44 = Utf8 (Ljava/lang/String;)V #45 = Methodref #1.#46 // org/wikibooks/fr/Addition.somme:(Ljava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Integer; #46 = NameAndType #14:#15 // somme:(Ljava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Integer; #47 = Methodref #38.#48 // java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder; #48 = NameAndType #49:#50 // append:(Ljava/lang/Object;)Ljava/lang/StringBuilder; #49 = Utf8 append #50 = Utf8 (Ljava/lang/Object;)Ljava/lang/StringBuilder; #51 = Methodref #38.#52 // java/lang/StringBuilder.toString:()Ljava/lang/String; #52 = NameAndType #53:#54 // toString:()Ljava/lang/String; #53 = Utf8 toString #54 = Utf8 ()Ljava/lang/String; #55 = Methodref #56.#58 // java/io/PrintStream.println:(Ljava/lang/String;)V #56 = Class #57 // java/io/PrintStream #57 = Utf8 java/io/PrintStream #58 = NameAndType #59:#44 // println:(Ljava/lang/String;)V #59 = Utf8 println #60 = String #61 // Somme +2 = #61 = Utf8 Somme +2 = #62 = Utf8 args #63 = Utf8 [Ljava/lang/String; #64 = Utf8 SourceFile #65 = Utf8 Addition.java { public org.wikibooks.fr.Addition(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #8 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 7: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lorg/wikibooks/fr/Addition; public static java.lang.Integer somme(java.lang.Integer, java.lang.Integer); descriptor: (Ljava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Integer; flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=2, args_size=2 0: aload_0 1: ifnonnull 6 4: aload_1 5: areturn 6: aload_1 7: ifnonnull 12 10: aload_0 11: areturn 12: aload_0 13: invokevirtual #16 // Method java/lang/Integer.intValue:()I 16: aload_1 17: invokevirtual #16 // Method java/lang/Integer.intValue:()I 20: iadd 21: invokestatic #22 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 24: areturn LineNumberTable: line 11: 0 line 12: 6 line 13: 12 LocalVariableTable: Start Length Slot Name Signature 0 25 0 a Ljava/lang/Integer; 0 25 1 b Ljava/lang/Integer; StackMapTable: number_of_entries = 2 frame_type = 6 /* same */ frame_type = 5 /* same */ public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=4, locals=1, args_size=1 0: getstatic #32 // Field java/lang/System.out:Ljava/io/PrintStream; 3: new #38 // class java/lang/StringBuilder 6: dup 7: ldc #40 // String Somme 1+2 = 9: invokespecial #42 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V 12: iconst_1 13: invokestatic #22 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 16: iconst_2 17: invokestatic #22 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 20: invokestatic #45 // Method somme:(Ljava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Integer; 23: invokevirtual #47 // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder; 26: invokevirtual #51 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 29: invokevirtual #55 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 32: getstatic #32 // Field java/lang/System.out:Ljava/io/PrintStream; 35: new #38 // class java/lang/StringBuilder 38: dup 39: ldc #60 // String Somme +2 = 41: invokespecial #42 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V 44: aconst_null 45: iconst_2 46: invokestatic #22 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 49: invokestatic #45 // Method somme:(Ljava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Integer; 52: invokevirtual #47 // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder; 55: invokevirtual #51 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 58: invokevirtual #55 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 61: return LineNumberTable: line 19: 0 line 20: 32 line 21: 61 LocalVariableTable: Start Length Slot Name Signature 0 62 0 args [Ljava/lang/String; }
Informations générales
[modifier | modifier le wikicode]public class org.wikibooks.fr.Addition SourceFile: "Addition.java" minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER
La première partie indique la version de java utilisée pour compiler la classe (52.0 supportée par Java 8). La classe est publique (ACC_PUBLIC) et a une classe de base (ACC_SUPER) ; seule la classe java.lang.Object n'en a pas.
Pool de constantes
[modifier | modifier le wikicode]Les constantes litérales sont regroupées en un seul endroit du fichier de classe et numérotées.
Elles proviennent du code source mais aussi des constantes implicites utilisées en interne, comme par exemple le nom de la classe de base java/lang/Object
quand aucune n'est spécifiée explicitement.
Constant pool: #1 = Class #2 // org/wikibooks/fr/Addition #2 = Utf8 org/wikibooks/fr/Addition #3 = Class #4 // java/lang/Object #4 = Utf8 java/lang/Object #5 = Utf8 <init> #6 = Utf8 ()V #7 = Utf8 Code #8 = Methodref #3.#9 // java/lang/Object."<init>":()V #9 = NameAndType #5:#6 // "<init>":()V
Chaque constante a un type (Class, Utf8, Methodref) et une ou deux valeurs associés. La valeur peut faire référence à d'autres constantes définies ailleurs, auquel cas la référence est suivi d'un commentaire donnant la valeur référencée.
Type | Description |
---|---|
Utf8
|
Chaîne de caractères encodées en UTF-8. |
String
|
Référence à une chaîne de caractères (Utf8 ) initialisant un objet de type java.lang.String .
|
Class
|
Référence à une chaîne de caractères (Utf8 ) donnant un nom de classe.
|
NameAndType
|
Références à une chaîne de caractères (Utf8 ) donnant un nom de membre et à une autre chaîne de caractères donnant la signature de son type.
|
Methodref
|
Références à une classe (Class ) et un de ses membres (NameAndType ) méthode de la classe.
|
Fieldref
|
Références à une classe (Class ) et un de ses membres (NameAndType ) attribut de la classe.
|
Code des méthodes
[modifier | modifier le wikicode]Le code de chaque méthode (bytecode) de la classe est affiché, comme celui du constructeur de la classe pour l'exemple ci-dessous :
public org.wikibooks.fr.Addition(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #8 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 7: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lorg/wikibooks/fr/Addition;
Aucun constructeur n'est pourtant déclaré dans le code source de l'exemple plus haut, mais le compilateur en a généré un par défaut.
Le nom du constructeur en interne est en fait <init>
.
L'indicateur d'accès ACC_PUBLIC
signifie que ce constructeur est public.
Le descripteur ()V
indique que le constructeur n'a pas d'argument (parenthèses vides) et ne retourne rien (V = void).
Code: stack=1, locals=1, args_size=1
Le code a besoin d'un élément de pile, d'une variable locale, et utilise un argument implicite (this) référençant l'objet créé à initialiser.
0: aload_0 1: invokespecial #8 // Method java/lang/Object."<init>":()V 4: return
Le constructeur effectue dans l'ordre :
- (adresse 0, instruction codée sur 1 octet) Charge l'argument 0 (this) dans la pile (push)
- (adresse 1, instruction codée sur 3 octets) Appeler la méthode
<init>
(le constructeur) de la classe de base (java.lang.Object
par défaut) sur l'objet référencé par l'élément au sommet de la pile. - (adresse 4, instruction codée sur 1 octet) Retour de méthode (aucune valeur de retour).
LineNumberTable: line 7: 0
L'instruction à l'adresse 0 correspond à la ligne 7 dans le code source, mais comme ce constructeur a été généré implicitement, la ligne source correspond à la déclaration de la classe.
Une option du compilateur permet de ne pas générer la table des lignes source LineNumberTable
.
LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lorg/wikibooks/fr/Addition;
Le constructeur utilise une variable locale (slot 0) nommée "this", dont le scope va de l'adresse 0 à l'adresse 5, de type Addition
.
Pour la méthode somme
:
public static java.lang.Integer somme(java.lang.Integer, java.lang.Integer); descriptor: (Ljava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Integer; flags: ACC_PUBLIC, ACC_STATIC
La méthode est publique et statique (pas de référence this en argument implicite), prend deux arguments de type java.lang.Integer
et sa valeur de retour est du même type, comme indiqué par la signature de méthode (Ljava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Integer;
.
Code: stack=2, locals=2, args_size=2
La méthode utilise deux emplacements dans la pile, deux variables locales, et a deux arguments.
0: aload_0 1: ifnonnull 6 4: aload_1 5: areturn 6: aload_1 7: ifnonnull 12 10: aload_0 11: areturn 12: aload_0 13: invokevirtual #16 // Method java/lang/Integer.intValue:()I 16: aload_1 17: invokevirtual #16 // Method java/lang/Integer.intValue:()I 20: iadd 21: invokestatic #22 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 24: areturn LineNumberTable: line 11: 0 line 12: 6 line 13: 12
En regroupant par ligne de code source :
Lignes sources | Code source | Assembleur bytecode | Description |
---|---|---|---|
Ligne 11 (adresses 0 à 5) |
if (a==null) return b; |
0: aload_0 1: ifnonnull 6 4: aload_1 5: areturn |
Remarque : les instructions sont préfixées par le type manipulé (a pour les références, i pour les entiers, ...). |
Ligne 12 (adresses 6 à 11) |
if (b==null) return a; |
6: aload_1 7: ifnonnull 12 10: aload_0 11: areturn |
Remarque : instructions similaires à la ligne source précédente. |
Ligne 13 (adresses 12 à 25) |
return a + b; |
12: aload_0 13: invokevirtual #16 // Method java/lang/Integer.intValue:()I 16: aload_1 17: invokevirtual #16 // Method java/lang/Integer.intValue:()I 20: iadd 21: invokestatic #22 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 24: areturn |
|
LocalVariableTable: Start Length Slot Name Signature 0 25 0 a Ljava/lang/Integer; 0 25 1 b Ljava/lang/Integer;
La méthode utilise deux variables locales nommées a et b dont la portée va des adresses 0 à 25 (tout le code de la méthode).
StackMapTable: number_of_entries = 2 frame_type = 6 /* same */ frame_type = 5 /* same */
L'attribut de méthode StackMapTable
facilite la vérification des types des valeurs dans les tables de variables locales et la pile lorsque le code contient des sauts d'instructions comme dans cet exemple.
Sans cette information, la vérification de code, ne pouvant pas se fier aux instructions qui précédent seulement pour vérifier la cohérence, doit parcourir tous les chemins d'exécution possible, ce qui prendrait du temps.