web-dev-qa-db-fra.com

La commande 'Java' compile-t-elle les programmes Java?

La plupart des sites Web sur Internet disent:

"utilisez la commande javac pour compiler un .Java fichier. Exécutez-le ensuite à l'aide de la commande Java "

Mais aujourd'hui, j'ai essayé d'exécuter un programme Java sans javac et j'ai obtenu un résultat étrange.

Voici le contenu d'un fichier appelé hello.Java:

public class Myclass {
 public static void main(String[] args){
    System.out.println("hello world");
  }
}

Puis j'ai couru:

$ javac hello.Java

Ce qui me donne cette erreur:

hello.Java:1: error: class Myclass is public, should be declared in a file named Myclass.Java
public class Myclass {
       ^
1 error

Mais lorsque je l'exécute sans la commande javac, il s'exécute sans erreur.

$ Java hello.Java
hello world

La commande Java compile-t-elle également le programme? Si oui, pourquoi avons-nous besoin de la commande javac?

La version de mon Java est:

openjdk version "12.0.2" 2019-07-16
OpenJDK Runtime Environment (build 12.0.2+10)
OpenJDK 64-Bit Server VM (build 12.0.2+10, mixed mode)
145
milad

Avant Java 11, pour exécuter votre code, vous devez d'abord le compiler, puis vous pouvez l'exécuter. Voici un exemple:

javac test.Java
java test

Depuis Java 11, vous pouvez toujours faire javac + Java, ou vous pouvez exécuter Java par lui-même pour compiler et exécuter automatiquement votre Notez qu'aucun .class le fichier sera généré. Voici un exemple:

Java test.Java

Si vous exécutez Java -help, vous verrez les différentes utilisations autorisées. Voici à quoi cela ressemble sur ma machine. Le dernier est ce que vous avez rencontré: Java [options] <sourcefile> [args] qui "exécutera un seul programme de fichier source".

$ Java -help
Usage: Java [options] <mainclass> [args...]
           (to execute a class)
   or  Java [options] -jar <jarfile> [args...]
           (to execute a jar file)
   or  Java [options] -m <module>[/<mainclass>] [args...]
       Java [options] --module <module>[/<mainclass>] [args...]
           (to execute the main class in a module)
   or  Java [options] <sourcefile> [args]
           (to execute a single source-file program)

MISE À JOUR:

Comme l'a souligné @BillK, OP a également demandé:

pourquoi avons-nous besoin de la commande javac?

La raison pour laquelle nous avons besoin de javac est de créer .class fichiers pour que le code puisse être créé, testé, distribué, exécuté, partagé, etc. comme c'est le cas aujourd'hui. La motivation pour JEP 3 était de faciliter les "premiers stades d'apprentissage de Java et lors de l'écriture de petits programmes utilitaires" sans changer aucune autre utilisation existante.

187
kaan

Si vous exécutez Java 11, il y a une nouvelle fonctionnalité qui permet l'exécution de fichiers source unique. Le compilateur source unique est plus promiscuité en termes de nom de classe par rapport au nom de fichier , c'est ainsi que vous pouvez exécuter, mais pas réussir la compilation.

Si vous utilisez une version précédente de Java, alors votre hello.Java actuel ne se compile pas, à cause d'erreurs de compilation, en particulier autour du nom de la classe. Il n'y a donc aucun moyen d'appeler Java hello.Java a compilé votre code, car il ne compile pas.

Il semble très probable que vous exécutiez du code précédemment compilé lors de l'exécution de la commande Java.

52
Evan

Pour répondre à la raison de cette erreur, le nom de classe du fichier doit correspondre à basename du fichier.

Vous avez deux options pour que ce code fonctionne pour le traditionnel javac; Java séquence:

  1. Renommez la classe en public class Hello ou

  2. Renommer hello.Java à myclass.Java.

L'interpréteur Java pour Java 11 n'impose pas cette exigence. La classe qui contient main peut avoir n'importe quel nom, tant que c'est la première classe de Ce fichier était principalement destiné à faciliter le processus d'apprentissage pour les débutants et à permettre le "script Java" avec le Shebang ( ref. ).

6
S.S. Anne

Oui, mais pas comme vous l'entendez probablement.

Lorsque vous utilisez la commande javac pour compiler un fichier .Java en fichier .class, la sortie est quelque chose appelée bytecode. Bytecode est un code machine (instructions natives) pour un CPU théorique basé sur la spécification Java Virtual Machine).

Cette spécification de CPU virtuel est en quelque sorte une moyenne des types de CPU qui étaient courants au moment où la spécification a été écrite. Pour cette raison, il est proche de nombreux types de CPU différents, ce qui facilite l'exécution des mêmes fichiers Java .class sur plusieurs types de CPU).

Lorsque Java a été lancé pour la première fois, la commande Java lit le fichier .class et interprète les instructions de bytecode une à la fois, puis les mappe à l'instruction native équivalente pour ce que le CPU ait jamais fait. il fonctionnait réellement. Cela a fonctionné mais n'a pas été particulièrement rapide. Pour améliorer cette compilation Just in Time (JIT) a été ajoutée au Runtime Java.

Avec JIT, la commande Java prend le bytecode et le compile à nouveau dans les instructions natives du CPU sur lequel il s'exécute. Modern Java runtimes ont tendance à commencer à interpréter le bytecode pendant la compilation JIT en arrière-plan et à basculer vers les instructions natives compilées quand il est prêt et profilera également l'application en cours d'exécution, puis recompilera à nouveau le bytecode avec différents optimisation pour obtenir les meilleures performances possibles.

EDIT (pour apaiser les électeurs déchus):

Donc, dans votre cas spécifique (comme vous exécutez un JRE plus récent que v11), le code est compilé (au moins) deux fois

  1. En tant que fichier .Java unique à bytecode
  2. Via le compilateur JIT car il interprète le bytecode (bien que pour helloWorld, il se peut qu'il n'ait pas le temps d'exécuter le code natif compilé)
5
hardillb