Class, JAR, WAR, PYC, BEAM : le bytecode compilé selon l'écosystème (JVM, Python, Erlang/Elixir)
Aucun de ces fichiers n'exécute le code source original : chacun est une forme intermédiaire compilée, interprétée par une machine virtuelle ou un interpréteur propre à son écosystème. Ce qu'ils ont en commun, et ce qui les distingue.
Ces cinq formats n’ont pas vocation à être comparés pour un choix (chacun est imposé par le langage utilisé) mais partagent un même principe : aucun ne contient le code source original, seulement une forme intermédiaire compilée qu’une machine virtuelle ou un interpréteur spécifique sait exécuter. Comprendre ce point commun aide à saisir pourquoi ces fichiers ne s’ouvrent jamais par double-clic ordinaire, et dans quelle mesure ils peuvent être décompilés.
| Format | Écosystème | Runtime requis | Contenu | Décompilation |
|---|---|---|---|---|
| Class | JVM (Java, Kotlin, Scala...) | JVM | Bytecode d'une seule classe | Approximative (outils comme CFR, JD-GUI) |
| JAR | JVM | JVM | Archive ZIP de .class + manifeste | Idem, classe par classe |
| WAR | Jakarta EE (ex-Java EE) | Serveur d'applications (Tomcat, WildFly) | Application web complète (JAR + web.xml) | Idem, via ses JAR internes |
| PYC | Python | Interpréteur Python (version précise) | Bytecode d'un module | Relativement aisée |
| BEAM | Erlang / Elixir | Machine virtuelle BEAM | Bytecode d'un module | Peu répandue en pratique |
Le Class est le bytecode d’une seule classe Java, produit par javac et interprété (ou compilé à la volée) par la JVM, le pilier du « écrit une fois, exécuté partout » de la plateforme. D’autres langages de la JVM (Kotlin, Scala, Groovy) compilent vers ce même format, ce qui leur permet d’interopérer nativement avec du code Java existant. Sa décompilation vers un code source lisible reste possible mais approximative : les noms de variables et certains commentaires d’origine sont généralement perdus.
Le JAR regroupe des fichiers .class compilés, des ressources et un manifeste dans une archive ZIP standard, distribuable et exécutable via java -jar. Il a été introduit avec le JDK 1.1 en 1997 pour éviter de multiplier les requêtes HTTP par fichier .class lors du chargement d’une applet. Le WAR est une variante spécialisée du JAR pour une application web Jakarta EE complète : classes compilées, bibliothèques dépendantes, pages JSP et un descripteur web.xml (facultatif depuis Servlet 3.0), le tout nécessitant un serveur d’applications compatible (Apache Tomcat, WildFly) pour s’exécuter : un serveur web générique ne sait servir que des fichiers statiques, pas interpréter ce bytecode packagé.
Le PYC diffère des deux précédents par sa nature : c’est avant tout un cache de performance, généré automatiquement par l’interpréteur Python (souvent dans un dossier __pycache__) pour éviter de recompiler le code source à chaque exécution, plutôt qu’un format de distribution à proprement parler. Son en-tête change à chaque version mineure de Python, ce qui le rend généralement incompatible d’une version à l’autre, et sa décompilation reste nettement plus aisée que celle d’un binaire natif, offrant une protection limitée à qui chercherait à distribuer du code Python sans révéler sa logique interne.
Le BEAM est le bytecode compilé exécuté par la machine virtuelle du même nom, partagée par Erlang et Elixir, deux langages de syntaxe différente qui compilent néanmoins vers exactement le même format binaire intermédiaire, à l’image de la relation entre Kotlin et le bytecode Java. Un module BEAM compilé depuis Elixir interopère directement avec un module compilé depuis Erlang, sans couche de conversion, ce qui permet à l’écosystème Elixir de réutiliser directement l’immense bibliothèque OTP d’Erlang.
Ces cinq formats ne sont donc interchangeables ni entre eux ni avec leur code source : chacun exige le runtime précis de son écosystème (JVM, serveur Jakarta EE, interpréteur Python d’une version donnée, machine virtuelle BEAM) pour s’exécuter, et aucun ne protège efficacement contre une décompilation à des degrés de fidélité variables selon le format.
Voir les fiches techniques complètes →
Formats concernés
- Java Class
- JAR (archive Java)
- WAR / EAR (archive Java d'entreprise)
- Python compilé (PYC)
- BEAM (bytecode Erlang)
Catégories concernées
Questions fréquentes
Que signifie l'erreur UnsupportedClassVersionError au lancement d'un .class ou d'un .jar ?
La JVM a lu un fichier .class dont le numéro de version majeur dépasse ce qu'elle sait exécuter : le code a été compilé avec un JDK plus récent que le runtime utilisé. Ce numéro vaut 52 pour Java 8, 55 pour Java 11, 61 pour Java 17 et 65 pour Java 21, et chaque JVM accepte les versions de 45 jusqu'à la sienne.
Python peut-il exécuter un fichier .pyc sans le .py correspondant ?
Seulement s'il est placé là où se trouverait le fichier source, sous le nom module.pyc : un .pyc rangé dans __pycache__ est ignoré si le .py est absent. L'option `python -m compileall -b` écrit justement les .pyc à cet emplacement historique.
Sources
- Oracle : spécification de la machine virtuelle Java
- Oracle : spécification du format JAR
- Jakarta EE : Packaging (documentation officielle)
- Python : documentation du module compileall
- Erlang/OTP : BEAM documentation (erts, Erlang runtime system)
- Oracle : JVM Specification SE 21, chapitre 4 (table 4.1-A des versions)
- Oracle : Java SE 21 API, UnsupportedClassVersionError
- Python : PEP 3147, PYC Repository Directories
Dernière mise à jour :