Kompiliert der Befehl 'java' Java-Programme?

145

Die meisten Websites im Internet sagen:

"Verwenden Sie den javacBefehl, um eine .javaDatei zu kompilieren . Führen Sie sie dann mit dem javaBefehl aus."

Aber heute habe ich versucht, ein Java-Programm ohne auszuführen, javacund ich habe ein seltsames Ergebnis erzielt.

Hier ist der Inhalt einer Datei namens hello.java:

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

Dann rannte ich:

$ javac hello.java

Was mir diesen Fehler gibt:

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

Aber wenn ich es ohne den javacBefehl ausführe , wird es ohne Fehler ausgeführt.

$ java hello.java
hello world

Hat der javaBefehl auch das Programm zusammenstellen ? Wenn ja, warum brauchen wir den javacBefehl?

Die Version meines Java ist:

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)
Milad
quelle
11
Welche Version verwenden Sie? Ich denke, sie haben Java Console in Java 9 eingeführt, und das haben Sie vielleicht erlebt.
Matthieu
6
Sie müssen den Klassennamen mit dem Dateinamen abgleichen - das ist der Java-Standard. Ändern Sie einfach den Dateinamen in Myclass.javaund kompilieren Sie ihn dann über die Befehlszeile wie folgt javac Myclass.javaund führen Sie ihn dann so aus java Myclass.
Unnsse
6
Ja, wird javacimmer noch zum Kompilieren verwendet, wenn Sie keinen Quellcode bereitstellen möchten oder wenn Sie mehr als eine einzelne Datei haben ( Dokumentation der javaOption für die Quelldatei:
Wird
@Matthieu Die Ausgabe von "java -version" lautet: openjdk version "12.0.2" 2019-07-16 OpenJDK-Laufzeitumgebung (Build 12.0.2 + 10) OpenJDK 64-Bit-Server-VM (Build 12.0.2 + 10, gemischt) Modus)
Milad
1
@Milad - Was passiert, ist Folgendes: javacKompiliert die Java-Quelle in JVM-spezifisch interpretierten Bytecode und der javaBefehl lädt ihn in den ClassLoader der JVM.
Unnsse

Antworten:

188

Um Ihren Code vor Java 11 auszuführen, müssen Sie ihn zuerst kompilieren und dann ausführen. Hier ist ein Beispiel:

javac test.java
java test

Seit Java 11 können Sie immer noch javac+ javaausführen oder javaselbst ausführen, um Ihren Code zu kompilieren und automatisch auszuführen. Beachten Sie, dass keine .classDatei generiert wird. Hier ist ein Beispiel:

java test.java

Wenn Sie ausführen java -help, werden die verschiedenen zulässigen Verwendungen angezeigt. So sieht es auf meinem Computer aus. Der letzte ist der, auf den Sie gestoßen sind: java [options] <sourcefile> [args]der "ein einzelnes Quelldateiprogramm ausführen" wird.

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

AKTUALISIEREN:

Wie von @BillK hervorgehoben, fragte OP auch:

Warum brauchen wir den Befehl javac?

Der Grund, den wir brauchen, javacist das Erstellen von .classDateien, damit Code wie heute erstellt, getestet, verteilt, ausgeführt, freigegeben usw. werden kann. Die Motivation für JEP 330 bestand darin, es für "frühe Phasen des Lernens von Java und beim Schreiben kleiner Hilfsprogramme" einfacher zu machen, ohne andere vorhandene Verwendungen zu ändern.

Kaan
quelle
49
eingeführt in Java 11: Was ist neu oder / und JEP 330: Starten von Single-File-Quellcode-Programmen
user85421
danke @CarlosHeuberger für die zusätzlichen Details. Ich nahm eine kleine Änderung in meiner Antwort vor, um zu reflektieren, dass es in Java 11 eingeführt wurde.
kaan
7
@ Spikatrix, das ist Java 8 (Sie haben das 1.in 1.8neueren Versionen eingestellt)
Muru
1
Sie haben die Frage nicht beantwortet, warum wir noch Javac benötigen. Ich denke, Java funktioniert nur mit der einzelnen Datei, die Sie bereitstellen, und den zuvor kompilierten Dateien. Ich glaube, Sie müssen alle anderen Dateien, die Sie verwenden möchten, aus der von Ihnen aufgerufenen Datei kompilieren.
Bill K
2
In dieser Antwort wird nicht angesprochen, warum diese neue Methode nicht zu einem Fehler zwischen Dateiname und Klassenname führt, wie von gemeldet javac.
sebrockm
52

Wenn Sie Java 11 ausführen , gibt es eine neue Funktion, die die Ausführung von Dateien aus einer Quelle ermöglicht. Der Single-Source-Compiler ist in Bezug auf Klassennamen und Dateinamen promiskuitiver. Auf diese Weise können Sie zwar ausführen, aber nicht erfolgreich kompilieren.

Wenn Sie eine frühere Version von Java verwenden, wird Ihre aktuelle Datei hello.java aufgrund von Kompilierungsfehlern, insbesondere um den Klassennamen, nicht kompiliert. Das Aufrufen von java hello.java hat Ihren Code also auf keinen Fall kompiliert, da er nicht kompiliert wird.

Es ist sehr wahrscheinlich, dass Sie beim Ausführen des Java-Befehls zuvor kompilierten Code ausgeführt haben.

Evan
quelle
Vielen Dank, Java-Version ist: openjdk-Version "12.0.2" 16.07.2019 OpenJDK-Laufzeitumgebung (Build 12.0.2 + 10) OpenJDK 64-Bit-Server-VM (Build 12.0.2 + 10, gemischter Modus)
milad
5
Aktivieren Sie das Kontrollkästchen Verwenden des Quelldateimodus zum Starten von Quellcodeprogrammen für einzelne Dateien : "Der Compiler erzwingt nicht die optionale Einschränkung, die am Ende von JLS 7.6 definiert wurde. Es sollte ein Typ in einem benannten Paket in einer Datei vorhanden sein, deren Name lautet zusammengesetzt aus dem Typnamen, gefolgt von der Erweiterung .java. "
user85421
2
Die Java-Skript-API und der Java Single-File-Quellcode-Programmstart ( JEP 330 ) sind zwei völlig getrennte und völlig unabhängige Dinge.
David Conrad
@ DavidConrad, Sprache entsprechend aktualisiert. Vielen Dank.
Evan
Schätzen Sie die Eingabe @TJCrowder. Aber ich bin mir ziemlich sicher, dass ich es so schreiben wollte, wie es ist. Außerdem zweite Definition in Ihren Links: Promiscuous bedeutet, eine breite Palette verschiedener Dinge einzuschließen.
Evan
6

Um zu beantworten, warum dieser Fehler angegeben wird, muss der Klassenname für die Datei mit dem der Datei übereinstimmen basename.

Sie haben zwei Möglichkeiten, damit dieser Code für den traditionellen Code funktioniert javac. javaReihenfolge:

  1. Benennen Sie die Klasse in public class Hellooder um

  2. Umbenennen hello.javain myclass.java.

Der javaInterpreter für Java 11 legt diese Anforderung nicht fest. Die enthaltene Klasse mainkann einen beliebigen Namen haben, solange es sich um die erste Klasse in der Datei handelt. Dies sollte vor allem den Lernprozess für Anfänger erleichtern und "Java Scripting" mit dem Shebang ermöglichen ( Ref. ).

SS Anne
quelle
5

Ja, aber nicht so, wie Sie es wahrscheinlich meinen.

Wenn Sie den javacBefehl verwenden, um eine Java-Datei in eine Klassendatei zu kompilieren, wird die Ausgabe als Bytecode bezeichnet. Bytecode ist der Maschinencode (native Anweisungen) für eine theoretische CPU, der auf der Java Virtual Machine-Spezifikation basiert.

Diese virtuelle CPU-Spezifikation ist eine Art Durchschnitt der CPU-Typen, die zum Zeitpunkt der Erstellung der Spezifikation üblich waren. Aus diesem Grund liegt es in der Nähe vieler verschiedener CPU-Typen, was es einfacher macht, dieselben Java-Klassendateien auf mehreren CPU-Typen auszuführen.

Beim ersten Start von Java javalas der Befehl die .class-Datei, interpretierte die Bytecode-Anweisungen nacheinander und ordnete sie dann der entsprechenden nativen Anweisung für die CPU zu, auf der sie tatsächlich ausgeführt wurde. Das hat funktioniert, war aber nicht besonders schnell. Um dies zu verbessern, wurde der Java Runtime eine JIT-Kompilierung (Just in Time) hinzugefügt.

Mit JIT nimmt der javaBefehl den Bytecode und kompiliert ihn erneut zu den nativen Anweisungen für die CPU, auf der er ausgeführt wird. Moderne Java-Laufzeiten beginnen in der Regel damit, den Bytecode zu interpretieren, während JIT im Hintergrund kompiliert wird, und wechseln zu den kompilierten nativen Anweisungen, wenn sie fertig sind. Außerdem wird die laufende Anwendung profiliert und der Bytecode erneut mit verschiedenen Optimierungen neu kompiliert, um die bestmögliche Leistung zu erzielen.

EDIT (um die Down-Wähler zu beschwichtigen):

In Ihrem speziellen Fall (da Sie eine neuere JRE als Version 11 ausführen) wird der Code (mindestens) zweimal kompiliert

  1. Als einzelne .java-Datei zum Bytecode
  2. Über den JIT-Compiler, der den Bytecode interpretiert (obwohl für helloWorld möglicherweise keine Zeit zum Ausführen des kompilierten nativen Codes vorhanden ist)
hardillb
quelle
7
Dies beantwortet die Frage nicht.
David Conrad
2
@ DavidConrad Aber es tut! Die Antwort auf "Kompiliert der Befehl 'java' Java-Programme?" ist aus den Gründen, die hardlib hier angibt, ein klares "Ja": Es kompiliert Bytecode just-in-time zu nativen Anweisungen (für nicht triviale Programme mit Standardeinstellungen).
Peter - Monica
Ist die Kompilierung jetzt obligatorisch? Historisch gesehen konnte Java-Bytecode interpretiert werden. Die JIT-Kompilierung war optional.
MSalters
Die JIT ist heutzutage standardmäßig (für eine sehr lange Zeit) eingeschaltet, wie mixed-modedie Ausgabe in der Version zeigt
hardillb