Il comando 'java' compila i programmi Java?


146

La maggior parte dei siti Web su Internet afferma:

"usa il javaccomando per compilare un .javafile. Quindi eseguilo usando il javacomando"

Ma oggi ho provato a eseguire un programma Java senza javace ho ottenuto uno strano risultato.

Ecco i contenuti di un file chiamato hello.java:

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

Quindi ho corso:

$ javac hello.java

Il che mi dà questo errore:

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

Ma quando lo eseguo senza il javaccomando, viene eseguito senza errori.

$ java hello.java
hello world

Il javacomando compila anche il programma? Se sì, perché abbiamo bisogno del javaccomando?

La versione del mio java è:

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)

11
Che versione stai usando? Penso che abbiano introdotto Java Console in Java 9, e potrebbe essere quello che hai provato.
Matthieu,

6
Devi abbinare il nome della classe al suo nome file - questo è lo standard Java. Basta cambiare il nome del file in Myclass.javae quindi dalla riga di comando compilarlo in questo modo javac Myclass.javae quindi eseguirlo in questo modo java Myclass.
annullare l'inserimento del

6
Sì, javacancora utilizzato per la compilazione se non si desidera distribuire il codice sorgente, o se si dispone di più di un singolo file ( la documentazione di java: per l'opzione source-file solo usato per lanciare un unico programma sorgente-file.)
user85421

@Matthieu l'output di "java -version" è: versione openjdk "12.0.2" 2019-07-16 OpenJDK Runtime Environment (build 12.0.2 + 10) OpenJDK 64-Bit Server VM (build 12.0.2 + 10, misto modalità)
milad,

1
@Milad - Ciò che accade è questo - javaccompila l'origine Java in bytecode interpretato specifico per JVM e il javacomando lo carica all'interno del ClassLoader di JVM.
annullare l'inserimento del

Risposte:


189

Prima di Java 11, per eseguire il codice è necessario prima compilarlo, quindi è possibile eseguirlo. Ecco un esempio:

javac test.java
java test

Da Java 11, puoi ancora fare javac+ java, oppure puoi eseguirlo javada solo per compilare ed eseguire automaticamente il tuo codice. Si noti che non .classverrà generato alcun file. Ecco un esempio:

java test.java

Se corri java -help, vedrai i vari usi consentiti. Ecco come appare sulla mia macchina. L'ultimo è quello in java [options] <sourcefile> [args]cui ti sei imbattuto: che "eseguirà un singolo programma di file sorgente".

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

AGGIORNARE:

Come sottolineato da @BillK, OP ha anche chiesto:

perché abbiamo bisogno del comando javac?

Il motivo di cui abbiamo bisogno javacè creare .classfile in modo che il codice possa essere creato, testato, distribuito, eseguito, condiviso, ecc. Come è oggi. La motivazione di JEP 330 è stata quella di semplificare "le prime fasi dell'apprendimento di Java e quando si scrivono piccoli programmi di utilità" senza modificare altri usi esistenti.



grazie @CarlosHeuberger per i dettagli aggiuntivi. Ho fatto una piccola modifica nella mia risposta per riflettere che è stato introdotto in Java 11.
Kaan

7
@Spikatrix che è Java 8 (hanno rilasciato il 1.in 1.8nelle versioni più recenti)
muru

1
Non hai risposto alla domanda sul perché abbiamo ancora bisogno di javac - penso che java funzioni solo sul singolo file che lo fornisci e sui file precedentemente compilati. Credo che tu debba compilare tutti gli altri file che desideri utilizzare dal file che chiami.
Bill K,

2
Questa risposta non spiega perché questo nuovo metodo non provochi un errore di nome file e nome classe come riportato da javac.
sebrockm,

52

Se si esegue Java 11, è disponibile una nuova funzionalità che consente l'esecuzione di singoli file di origine. Il compilatore single source è più promiscuo in termini di nome della classe rispetto al nome del file, quindi è così che sei in grado di eseguire ma non compilare correttamente.

Se utilizzi una versione precedente di Java, il tuo hello.java corrente non viene compilato, a causa di errori di compilazione, in particolare attorno al nome della classe. Quindi non c'è assolutamente modo che chiamare java hello.java abbia compilato il tuo codice, perché non si compila.

Sembra assolutamente probabile che tu stia eseguendo un codice precedentemente compilato durante l'esecuzione del comando java.


grazie, la versione java è: openjdk versione "12.0.2" 16-07-2019 Ambiente di runtime OpenJDK (build 12.0.2 + 10) VM server OpenJDK 64-bit (build 12.0.2 + 10, modalità mista)
milad

5
controlla usando la modalità file sorgente per avviare programmi in codice sorgente a file singolo : "Il compilatore non applica la limitazione facoltativa definita alla fine di JLS ?? 7.6, che un tipo in un pacchetto denominato dovrebbe esistere in un file il cui nome è composto dal nome del tipo seguito dall'estensione .java. "
user85421

2
L'API di scripting Java e il lancio del programma Java-File Source Code ( JEP 330 ) sono due cose completamente separate e totalmente indipendenti.
David Conrad,

@DavidConrad, aggiornato verbosità di conseguenza. Grazie.
Evan,

Apprezzo l'input, @TJCrowder. Ma sono abbastanza sicuro di voler scrivere così com'è. Inoltre, seconda definizione nei tuoi link: promiscuo significa includere una vasta gamma di cose diverse.
Evan,

6

Per rispondere al motivo per cui viene fornito questo errore, il nome della classe per il file deve corrispondere a quello del file basename.

Hai due opzioni per far funzionare questo codice per il tradizionale javac; javasequenza:

  1. Rinomina la classe in public class Helloo

  2. Rinomina hello.javain myclass.java.

L' javainterprete per Java 11 non impone questo requisito. La classe che contiene mainpuò avere qualsiasi nome, purché sia ​​la prima classe nel file. Lo scopo era principalmente quello di facilitare il processo di apprendimento per i principianti e di consentire "java scripting" con lo shebang ( rif. ).


5

Sì, ma non nel modo in cui probabilmente intendi.

Quando si utilizza il javaccomando per compilare un file .java in un file .class l'output è qualcosa chiamato bytecode. Bytecode è un codice macchina (istruzioni native) per una CPU teorica basata sulla specifica Java Virtual Machine.

Questa specifica di CPU virtuale è una sorta di media di tipi di CPU che erano comuni al momento della stesura della specifica. Per questo motivo è vicino a molti tipi diversi di CPU, rendendo più semplice l'esecuzione degli stessi file .class Java su più tipi di CPU.

Quando Java è stato lanciato per la prima volta, il javacomando leggeva il file .class e interpretava le istruzioni bytecode una alla volta, quindi le associava all'istruzione nativa equivalente per qualsiasi CPU su cui fosse effettivamente in esecuzione. Questo ha funzionato ma non è stato particolarmente veloce. Per migliorare questa compilazione Just in Time (JIT) è stata aggiunta a Java Runtime.

Con JIT il javacomando prende il bytecode e lo compila nuovamente secondo le istruzioni native per la CPU su cui è in esecuzione. I runtime Java moderni tendono a iniziare a interpretare il bytecode mentre JIT si compila in background e passano alle istruzioni native compilate quando è pronto e anche profilano l'applicazione in esecuzione e quindi ricompilano nuovamente il bytecode con diverse ottimizzazioni per ottenere le migliori prestazioni possibili.

EDIT (per placare gli elettori in ribasso):

Quindi nel tuo caso specifico (mentre stai eseguendo un JRE più recente della v11) il codice viene compilato (almeno) due volte

  1. Come singolo file .java in bytecode
  2. Tramite il compilatore JIT mentre interpreta il bytecode (anche se per HelloWorld potrebbe non avere il tempo di eseguire il codice nativo compilato)

7
Questo non risponde alla domanda.
David Conrad,

2
@DavidConrad Ma lo fa! La risposta a "Il comando 'java' compila i programmi Java?" è un clamoroso "sì" per i motivi qui indicati da hardlib: compilerà il codice byte in istruzioni native just-in-time (per programmi non banali, con impostazioni standard).
Peter - Ripristina Monica il

La compilation è ora obbligatoria? Storicamente il codice byte Java potrebbe essere interpretato; La compilazione JIT era facoltativa.
Salmi,

La JIT è attiva per impostazione predefinita in questi giorni (per molto tempo), come mostrato mixed-modedall'output nella versione
hardillb
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.