Informatique

Java, le langage « écrit une fois, exécuté partout »

Né chez Sun Microsystems pour des appareils électroniques grand public, lancé en 1995 avec l'essor du Web, Java est devenu l'un des langages les plus utilisés au monde : serveurs des banques et des administrations, applications Android, cartes à puce, traitement de données massives, et même le jeu Minecraft. Cinq planches pour découvrir son bytecode et sa machine virtuelle, ses objets, ses collections, ses lambdas, puis pour exécuter de vrais programmes Java.

Du projet « Green » au Web

En 1991, chez Sun Microsystems, une petite équipe menée par James Gosling travaille sur le projet « Green » : programmer les futurs appareils électroniques grand public, comme les décodeurs de télévision. Ces appareils utilisent des processeurs très différents ; il faut donc un langage dont les programmes fonctionnent partout, sans être recompilés. Gosling conçoit Oak, qui reprend la syntaxe du C++ en le simplifiant : pas de pointeurs manipulables, une gestion automatique de la mémoire, des objets partout. Le marché de la télévision interactive ne décolle pas, mais le Web, lui, explose : rebaptisé Java (un nom de café), le langage est présenté le 23 mai 1995, avec la promesse « Write once, run anywhere » : écrit une fois, exécuté partout.

Les versions de Java (en haut) et quelques grands usages (en bas). Depuis 2018, une nouvelle version sort tous les six mois, en mars et en septembre.
Planche 1

Le bytecode et la machine virtuelle Java

1995

Le compilateur javac ne produit pas de code pour un processeur réel, mais du bytecode : les instructions d'une machine imaginaire à pile, la machine virtuelle Java (JVM). Chaque système (Windows, macOS, Linux, Android, carte à puce…) possède sa propre JVM, qui exécute le même fichier .class. Voici le vrai bytecode produit par javac pour quatre méthodes, extrait avec l'outil javap, et sa simulation pas à pas.

4

Java

Bytecode (javap -c)

    Chaque appel de méthode crée un cadre avec ses variables locales (les paramètres d'abord) et sa propre pile d'opérandes. iload empile une variable, istore la range, irem remplace les deux valeurs du sommet par le reste de leur division, if_icmpgt compare et saute, invokestatic appelle une méthode.
    Instructions exécutées / cadres empilés
    —
    Instruction en cours
    —
    Résultat
    —
    Contrôle : résultats de la simulation comparés au programme exécuté par la JVM d'OpenJDK 21
    —
    Ce qu'il faut retenir. Le bytecode est compact et indépendant du processeur : c'est ce qui a permis aux applets de 1995 de s'exécuter dans n'importe quel navigateur. Interpréter ce code instruction par instruction serait lent ; depuis 2000, la JVM HotSpot repère les méthodes les plus utilisées et les compile à la volée (JIT, just in time) en code machine optimisé, pendant l'exécution. La JVM vérifie aussi le bytecode avant de l'exécuter (pas de saut hors du code, pas de pile qui déborde), ce qui fait partie de la sécurité de Java. Remarquez que factorielle(13) déborde : un int Java a toujours 32 bits.
    Planche 2

    Classes, héritage et polymorphisme

    1995

    En Java, presque tout est objet. Une classe décrit des objets : leurs données (les champs) et leurs actions (les méthodes). Une classe peut en étendre une autre et redéfinir ses méthodes : un Carre est un Rectangle, qui est une Forme. Quand le programme demande f.aire() à une forme, c'est la JVM qui choisit, au moment de l'exécution, la méthode de la classe réelle de l'objet : c'est le polymorphisme. Suivez la boucle du programme Formes.

    En haut, la hiérarchie des classes : chaque classe hérite de celle du dessus. En bas, les cinq objets du tableau Forme[] formes, rangés dans le tas (la mémoire des objets). Pour l'objet en cours, la flèche montre la classe dont la méthode aire() est réellement exécutée.
    Objet en cours
    —
    Méthode aire() exécutée
    —
    Ligne affichée par le programme
    —
    Contrôle : sortie du programme Formes comparée à celle de la JVM d'OpenJDK 21
    —
    Ce qu'il faut retenir. La classe Forme est abstraite : elle annonce les méthodes aire() et perimetre() sans les écrire, et on ne peut pas créer de « forme » tout court. Le Carre n'écrit aucune méthode : il hérite de celles du Rectangle. Le code qui parcourt le tableau ne connaît que Forme ; on peut ajouter une nouvelle sorte de forme sans le modifier. Java n'autorise qu'une seule classe parente (extends), mais une classe peut réaliser plusieurs interfaces (implements), des contrats qui listent des méthodes à fournir. Toutes les classes héritent de Object, d'où la méthode toString() que l'on redéfinit ici.
    Planche 3

    À l'intérieur d'une HashMap

    1998

    Depuis Java 1.2, la bibliothèque standard offre des collections prêtes à l'emploi : listes (ArrayList), ensembles, tables d'association. La plus utilisée, HashMap, retrouve une valeur à partir d'une clé en un temps presque constant, même parmi des millions. Le secret : un calcul de hachage. Pour un mot, hashCode() calcule un entier à partir de ses lettres (h = 31 × h + code de la lettre) ; ce nombre désigne une case d'un tableau. Regardez les mots d'une phrase se ranger dans les cases, et le tableau doubler quand il se remplit.

    3
    Le tableau de la HashMap : 16 cases au départ, puis 32, puis 64. Chaque case contient une petite liste chaînée des mots qui y tombent (les « collisions »). Le dernier mot inséré est en orange.
    Mot / hashCode() / case
    —
    Mots différents / cases / seuil de doublement
    —
    Plus longue liste dans une case
    —
    Contrôle : hashCode et ordre de parcours des clés après chaque insertion, et contenu final, comparés à la vraie HashMap d'OpenJDK 21
    —
    Ce qu'il faut retenir. La case vaut (h ^ (h >>> 16)) & (taille − 1) : on mélange les bits de poids fort et de poids faible, puis on garde les derniers bits. Quand le nombre d'éléments dépasse les trois quarts du tableau (le facteur de charge 0,75), le tableau double et les éléments sont redistribués. C'est pourquoi l'ordre dans lequel une HashMap énumère ses clés paraît aléatoire et peut changer au fil des ajouts : il ne faut jamais compter dessus. Pour un ordre alphabétique, on utilise une TreeMap (arbre équilibré) ; pour l'ordre d'insertion, une LinkedHashMap. Si une case accumule plus de 8 éléments, Java la transforme en arbre.
    Planche 4

    Lambdas et flux : le style fonctionnel

    2014

    Java 8 introduit les expressions lambda, de petites fonctions écrites sur place : m -> m.length() > 4, et les flux (Stream), qui enchaînent des opérations sur une collection : filtrer, transformer, trier, limiter. Un flux est paresseux : rien ne se passe avant l'opération finale, puis chaque élément traverse toute la chaîne avant le suivant, et le calcul s'arrête dès que le résultat est connu. Comparez les trois chaînes d'opérations sur dix mots.

    3
    Les étapes du flux, de haut en bas. Chaque mot descend la chaîne ; un mot refusé par filter s'arrête, sorted doit tout recevoir avant de laisser passer quoi que ce soit, limit et findFirst arrêtent le flux.

    Le code Java

    Les appels, dans l'ordre

    Mots lus dans la liste / appels de lambdas
    —
    Résultat
    —
    Les trois chaînes : appels de lambdas
    —
    Contrôle : ordre des appels comparé à celui des flux d'OpenJDK 21 (trois chaînes)
    —
    Ce qu'il faut retenir. Dans la première chaîne, map n'est appelé que pour trois mots, et les cinq derniers mots ne sont jamais lus : la paresse évite le travail inutile. Avec sorted, c'est différent : pour trier, il faut d'abord tous les mots, donc tous passent par filter. Ce style dit quoi calculer plutôt que comment le faire avec des boucles ; il se prête au calcul en parallèle (parallelStream()). Depuis, Java a ajouté le mot-clé var (2018), les record (2021), le filtrage par motifs dans switch et les threads virtuels (2023), qui permettent de lancer des millions de tâches simultanées.
    Planche 5 · signature

    Exécuter de vrais programmes Java

    2026

    Voici un petit interpréteur Java, écrit pour cette page, qui exécute dans votre navigateur un sous-ensemble du langage : classes, constructeurs, héritage, classes abstraites, interfaces, polymorphisme, classes génériques ; types int, long, double, char, boolean avec les vrais débordements et les règles de conversion de Java ; tableaux à plusieurs dimensions ; String, StringBuilder, ArrayList, HashMap (avec son vrai ordre de parcours), Math, Arrays ; if, switch, boucles, exceptions avec try, catch, finally. L'affichage des réels et printf suivent exactement Java, réglé en français. Chaque exemple a aussi été compilé par javac et exécuté par la JVM d'OpenJDK 21.

    Le programme

    La console

    
          

    Les classes du programme

    Opérations élémentaires / durée
    —
    Exception non rattrapée
    —
    Message du compilateur
    —
    Contrôle : sortie identique à celle de la JVM d'OpenJDK 21 (exemple d'origine), et 3 000 affichages de réels
    —
    Ce qu'il faut retenir. Tout programme Java est fait de classes ; l'exécution commence par la méthode public static void main(String[] args). Le type de chaque variable est déclaré, et le compilateur le vérifie. System.out.println écrit les réels avec un point, toujours ; printf et String.format suivent les conventions du pays de l'ordinateur, ici la France, d'où la virgule. Une exception non rattrapée arrête le programme avec un message sur la console d'erreur. Ce petit interpréteur ne connaît pas les lambdas, les flux, les threads ni la lecture au clavier ; essayez quand même de modifier les exemples, par exemple d'ajouter une forme dans l'exemple 2.

    Où trouve-t-on Java aujourd'hui ?

    Serveurs d'entreprise

    Banques, assurances, commerce en ligne, administrations : une grande partie des applications de gestion tournent sur des serveurs Java, souvent avec le cadre Spring. Java est 4e du classement TIOBE d'octobre 2026.

    Android

    Lancé en 2008, Android a choisi le langage Java pour ses applications, exécutées par sa propre machine virtuelle. Depuis 2019, Google privilégie Kotlin, un autre langage qui fonctionne sur la JVM et cohabite avec Java.

    Cartes à puce

    Java Card, une version minuscule de Java, fait fonctionner des milliards de cartes SIM, de cartes bancaires et de passeports électroniques : chaque carte contient une petite machine virtuelle.

    Données massives

    Les grands outils de traitement de données, comme Hadoop, Kafka, Elasticsearch ou Spark (écrit en Scala, un autre langage de la JVM), reposent sur la machine virtuelle Java et sa capacité à exploiter des grappes de serveurs.

    Jeux et logiciels

    Minecraft, le jeu vidéo le plus vendu de l'histoire, a été écrit en Java en 2009 ; sa « Java Edition » est toujours la favorite des créateurs de modifications. Les environnements de développement IntelliJ IDEA et Eclipse sont eux-mêmes écrits en Java.

    Enseignement

    Java est enseigné dans de nombreuses universités et écoles d'ingénieurs pour la programmation orientée objet ; aux États-Unis, l'examen Advanced Placement d'informatique se passe en Java depuis 2004.

    Frise des jalons

    Pour aller plus loin

    Les exemples de la planche 5, le bytecode de la planche 1, l'ordre de la HashMap de la planche 3 et l'ordre des appels des flux de la planche 4 ont été produits par javac et la JVM d'OpenJDK 21 au moment de la fabrication de la page, avec les réglages régionaux français. Votre navigateur refait tous ces calculs et les compare.