Der Java-Compiler “JavaCC” und der Java-Interpreter “Java”
Java wird zur Kompilierungszeit zu einem “Bytecode” kompiliert. Dies steht im Gegensatz zu einer Sprache wie C, die zur Kompilierungszeit in die Maschinensprache übersetzt wird. Der Java-Byte-Code kann nicht direkt auf der Hardware ausgeführt werden, wie es der kompilierte C-Code kann. Stattdessen muss der Bytecode zur Laufzeit von der JVM (Java Virtual Machine) interpretiert werden, um ausgeführt zu werden.
Einleitung
Der primäre Nachteil einer Sprache wie C ist, dass diese Binärdatei beim Kompilieren nur auf einer bestimmten Architektur (z.B. x86) funktioniert. Interpretierte Sprachen wie PHP sind hingegen systemunabhängig und basieren auf einem system- und architekturspezifischen Interpreter. Dies führt zu einer viel größeren Portabilität. Diese Interpretation führt jedoch zu einem deutlichen Leistungsrückgang. Höhere Programmiersprachen wie PHP benötigen mehr Zeit zum Interpretieren als maschinenspezifische Anweisungen, die von der Hardware ausgeführt werden können.
Funktion von Java
Java sucht einen Kompromiss zwischen einer rein kompilierten Sprache (ohne Portabilität) und einer rein interpretierten Sprache (die wesentlich langsamer ist). Er erreicht dies, indem er den Code in eine Form kompiliert, die näher an der Maschinensprache liegt (eigentlich ist Java-Byte-Code eine Maschinensprache, einfach für die Java Virtual Machine), aber trotzdem leicht zwischen den Architekturen transportiert werden kann. Da Java zur Ausführung noch eine Softwareschicht (die JVM) benötigt, ist es eine interpretierte Sprache. Der Interpreter (die JVM) arbeitet jedoch auf einer Zwischenform, die als Bytecode bekannt ist, und nicht auf den rohen Quelldateien. Dieser Bytecode wird zur Kompilierzeit vom Java-Compiler generiert. Daher ist Java auch eine kompilierte Sprache. Auf diese Weise erhält Java einige der Vorteile kompilierter Sprachen, aber auch einige der Vorteile von interpretierten Sprachen. Zugleich erbt Java auch einige Einschränkungen dieser beiden Typen.
Was ist der Java-Compiler “javac”?
Der javac-Befehl in Java kompiliert ein Programm aus einer Eingabeaufforderung. Er liest ein Java-Quellprogramm aus einer Textdatei und erzeugt daraus eine kompilierte Java-Klassendatei.
Wie benutzt man javac?
Die Grundform des javac-Befehls lautet
javac Dateiname [Optionen]
Um beispielsweise ein Programm namens HelloWorld.java zu kompilieren, verwendest Du diesen Befehl:
javac HelloWorld.java
Normalerweise kompiliert der javac-Befehl nur die Datei, die Du auf der Kommandozeile angibst. Du kannst javac jedoch auch dazu bringen, mehr als eine Datei gleichzeitig zu kompilieren, indem Du eine der folgenden Techniken verwendest.
Wenn die Java-Datei, die Du auf der Kommandozeile angibst, einen Verweis auf eine andere Java-Klasse enthält, die durch eine Java-Datei im gleichen Ordner definiert ist, kompiliert der Java-Compiler automatisch auch diese Klasse.
Du kannst mehr als einen Dateinamen im javac-Befehl auflisten. Der folgende Befehl kompiliert drei Dateien:
javac TestProgramm1.java TestProgramm2.java TestProgramm3.java
Du kannst einen Platzhalter verwenden, um alle Dateien in einem Ordner wie diesem zu kompilieren:
javac *.java
Wenn Du viele Dateien gleichzeitig kompilieren musst, aber keinen Platzhalter verwenden möchtest (vielleicht möchtest Du eine große Anzahl von Dateien kompilieren, aber nicht alle Dateien liegen in einem Ordner), kannst Du eine Argumentdatei erstellen, die die zu kompilierenden Dateien auflistet. In der Argumentdatei kannst Du beliebig viele Dateinamen eingeben und diese durch Leerzeichen oder Zeilenumbrüche trennen. Hier ist eine Argumentdatei namens TestProgramme, die drei zu kompilierende Dateien auflistet:
TestProgramm1.java TestProgramm2.java TestProgramm3.java
Du kannst alle Programme in dieser Datei kompilieren, indem Du auf der javac-Befehlszeile wie folgt ein @-Zeichen verwendest, gefolgt von dem Namen der Argumentdatei:
javac @TestProgramme
Der Befehl javac hat eine Reihe von Optionen, mit denen Du die Kompilierung Deiner Programme beeinflussen kannst.
Was ist der Java-Interpreter “java”? Wofür ist er da und wie benutzt man ihn?
Eines der wichtigsten Argumente für Java ist die Plattformunabhängigkeit. Der Computer benötigt lediglich einen Interpreter für den Java-Bytecode. Ein solcher Interpreter simuliert die virtuelle Java-Maschine auf die gleiche Weise wie Virtual PC, Virtual Box, VMware usw. einen PC.
Natürlich wird für jeden Computertyp ein anderer Jave-Bytecode-Interpreter benötigt, aber sobald es einen Interpreter für die Plattformgibt, kann er jedes beliebige Java-Bytecode-Programm ausführen. Und das gleiche Java-Bytecode-Programm kann auf jedem Computer mit einem solchen Interpreter ausgeführt werden. Dies ist eine der wesentlichen Eigenschaften von Java: das gleiche kompilierte Programm kann mit dem Interpreter auf vielen verschiedenen Arten von Computern ausgeführt werden.
Viele Java-Programme werden über ein Netzwerk heruntergeladen. Dies führt zu offensichtlichen Sicherheitsbedenken: Du willst kein Programm herunterladen und ausführen, das Deinen Computer oder Ihre Dateien beschädigt. Der Java-Interpreter dient als Puffer zwischen Deiner Infrastruktur und dem heruntergeladenen Programm. Du führst lediglich den Interpreter aus, der das heruntergeladene Java-Programm indirekt ausführt. Der Interpreter kann Dich vor potentiell gefährlichen Aktionen seitens des Programms schützen.
Die JVM arbeitet direkt auf dem Bytecode. Der Java-Interpreter ist so eng in die JVM integriert, dass sie nicht wirklich als separate Entitäten betrachtet werden sollten.
Der Java-Interpreter wird ebenfalls direkt von der Befehlszeile gestartet. Dabei können auch für den Interpreter Optionen angegeben werden, sowie alle für die Anwendung benötigten Programmargumente:
java [Interpreteroptionen] Klassenname [Programmargumente]
Die Klasse sollte als voll qualifizierter Klassenname angegeben werden, einschließlich des Klassenpakets, falls vorhanden.
% java tiere.voegel.GrosserVogel % java TestProgramm1
Sobald die Klasse geladen ist, folgt Java einer C-ähnlichen Konvention und sucht nach der Klasse, die eine Methode namens main() enthält. Wenn der Interpreter eine geeignete main()-Methode findet, führt er diese Methode aus, um die Anwendung zu starten. Von dort aus startet die Anwendung weitere Threads, referenziert andere Klassen und erstellt ihre Benutzeroberfläche.
Fazit
Der Entwickler nutzt den Java-Compiler, um aus dem Quellcode plattformunabhängigen Bytecode zu erstellen. Dieser wird vom Anwender mit dem Java-Interpreter auf seinem Rechner ausgeführt. Dabei ist das kompilierte Java-Programm auf jeder Plattform lauffähig, für die es einen Interpreter gibt.