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

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

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

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 ».

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

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.

Le JDK fournit un débogueur nommé jdb (Java DeBugger) utilisable depuis la ligne de commande.

Mode interactif

modifier

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

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

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

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 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 permet de lister les membres et désassembler la classe compilée spécifiée.

javap -c -classpath directory-list classname

Options

modifier
-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

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
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

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.

Quelques types de constantes
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

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
  • Charger l'argument 0 (a) dans la pile ;
  • Dépiler la référence, si elle est non nulle, aller à l'adresse 6 ;
  • Charger l'argument 1 (b) dans la pile ;
  • Dépiler la référence et l'utiliser comme valeur de retour (fin de la méthode).

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
  • Charger l'argument 1 (b) dans la pile ;
  • Dépiler la référence, si elle est non nulle, aller à l'adresse 12 ;
  • Charger l'argument 0 (a) dans la pile ;
  • Dépiler la référence et l'utiliser comme valeur de retour (fin de la méthode).

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
  • Charger l'argument 0 (a) dans la pile ;
  • Dépiler l'objet référencé, appeler sa méthode intValue() retournant un entier, mis dans la pile ;
  • Charger l'argument 1 (b) dans la pile ;
  • Dépiler l'objet référencé, appeler sa méthode intValue() retournant un entier, mis dans la pile ;
  • Additionner les deux entiers dépilés du haut de la pile et empiler le résultat ;
  • Appeler la méthode statique Integer.valueOf() pour convertir l'entier dépilé en objet, placé sur la pile ;
  • Retourner la référence dépilée du haut de la pile.
      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.


Voir aussi

modifier