Il comando' java ' compila programmi Java?


La maggior parte dei siti web su Internet dice:

"utilizzare il comando javac per compilare un file .java. Quindi eseguirlo utilizzando il comando java"

Ma oggi ho provato a eseguire un programma java senza javac e ho ottenuto uno strano risultato.

Ecco il contenuto di un file chiamato hello.java:

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

Poi ho corso:

$ javac hello.java

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 comando javac, è stato eseguito senza errori.

$ java hello.java
hello world

Anche il comando java compila il programma? Se sì, perché abbiamo bisogno del comando javac?

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)
Author: LogicalBranch, 2019-09-24

4 answers

Prima di Java 11, per eseguire il codice devi prima compilarlo, quindi puoi eseguirlo. Ecco un esempio:

javac test.java
java test

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

java test.java

Se esegui java -help, vedrai i vari usi consentiti. Ecco come appare sulla mia macchina. L'ultimo è quello in cui ti sei imbattuto: java [options] <sourcefile> [args] 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)

AGGIORNAMENTO:

Come sottolineato da @BillK, OP ha anche chiesto:

perché abbiamo bisogno del comando javac?

Il motivo per cui abbiamo bisogno di javac è creare file .class in modo che il codice possa essere creato, testato, distribuito, eseguito, condiviso, ecc. come oggi. La motivazione per JEP 330 era di rendere più facile per "le prime fasi di apprendimento di Java e quando si scrivono piccoli programmi di utilità" senza modifica di altri usi esistenti.

 190
Author: kaan, 2019-09-28 02:51:48

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

Se sei su una versione precedente di Java, allora il tuo attuale hello.java non viene compilato, a causa di errori di compilazione, in particolare attorno al nome della classe. Quindi non c'è assolutamente modo di chiamare java hello.Java compilato il tuo codice, perché non viene compilato.

Sembra molto probabile che si stesse eseguendo del codice precedentemente compilato durante l'esecuzione del comando java.

 52
Author: Evan, 2019-09-25 18:03:46

Per rispondere al motivo di questo errore, il nome della classe per il file deve corrispondere a basename del file.

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

  1. Rinominare la classe in public class Hello o

  2. Rinominare hello.java in myclass.java.

L'interprete java per Java 11 non impone questo requisito. La classe che contiene main può avere qualsiasi nome, purché sia la prima classe nel file. Questo è stato principalmente destinato a facilitare il processo di apprendimento per i principianti, e per consentire "java scripting" con la shebang ( ref.).

 6
Author: S.S. Anne, 2019-09-27 22:44:09

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

Quando si utilizza il comando javac per compilare un .file java ad un.file di classe l'output è qualcosa chiamato bytecode. Bytecode è un codice macchina (istruzioni native) per una CPU teorica basata sulle specifiche della macchina virtuale Java.

Questa specifica della CPU virtuale è una sorta di media dei tipi di CPU che erano comuni al momento in cui la specifica è stata scritta. Per questo motivo è vicino a molti tipi diversi di CPU rendendo più facile per eseguire lo stesso Java .file di classe su più tipi di CPU.

Quando Java è stato lanciato per la prima volta il comando java leggeva il .class file e interpretare le istruzioni bytecode una alla volta e quindi mapparle all'istruzione nativa equivalente per qualsiasi CPU fosse effettivamente in esecuzione. Questo ha funzionato ma non è stato particolarmente veloce. Per migliorare questo Just in Time (JIT) compilazione è stato aggiunto al Runtime Java.

Con JIT il comando java prende il bytecode e lo compila di nuovo nelle istruzioni native per la CPU su cui è in esecuzione. I runtime Java moderni tendono a iniziare a interpretare il bytecode mentre JIT compila in background e passa alle istruzioni native compilate quando è pronto e profilerà anche l'applicazione in esecuzione e quindi ricompilerà nuovamente il bytecode con un'ottimizzazione diversa per ottenere le migliori prestazioni possibili.

MODIFICA (per placare gli elettori down):

Quindi nel tuo caso specifico (come stai eseguendo un JRE più recente di 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 uno qualsiasi del codice nativo compilato)
 5
Author: hardillb, 2019-09-27 08:35:55