Compiler und interpreter?
Wa sind die Unterschiede?
Vor- und Nachteile jeweils?
Und warum ist Java beides?
3 Antworten
Ein Compiler übersetzt einmal den Quellcode in (und jetzt kommts) entweder Bytecode, der von einer Runtime wiederum interpretiert wird (wie bei Java oder .NET) oder direkt in prozessorabhängigen Maschinencode. Das Kompilat kann aber verteilt werden, ohne dass der Endanwender auch den Compiler braucht.
Ein Interpreter nimmt den Quellcode bei jeder Ausführung erneut übersetzt - teilweise sogar während der Ausführung (JIT - just in time).
Java (und auch teilweise .NET Programme) sind daher beides, denn es gibt einen Compiler, der den Quellcode zunächst in so genannten IL-Code oder Java-Bytecode übersetzt, der dann von einer Runtime in den eigentlich plattformabhängigen Maschinencode übersetzt wird, wenn die Anwendung ausgeführt wird. Bei .NET gibt es noch die Besonderheit, dass man eine IL-Code Anwendung mit einem weiteren Compiler auch direkt für sein System compilieren kann, so dass der JIT-Compiler wegfällt.
Vorteile dieses Ansatzes (und anderer Interpreter). Das Programm ist auf jeder Plattform ausführbar, für die es den entsprechenden Interpreter gibt (Java Runtime, .NET Environment, Python, etc.)
Nachteil: Interpretierte Anwendungen haben häufig längere Startzeiten oder auch immer mal wieder kleinere Hänger, weil zunächst die Übersetzung in Bytecode stattfinden muss.
Ein Interpreter nimmt den Quellcode bei jeder Ausführung erneut übersetzt
Eieiei, was schrieb ich denn da... also eigentlich sollte das heißen:
Ein Interpreter nimmt den Quellcode und übersetzt ihn bei jeder Ausführung erneut.
Compiler
- übersetzt den Quelltext in Maschinensprache
- die übersetzte Anwendung kann direkt ausgeführt werden
- die übersetzte Anwendung ist nur auf der entsprechenden Plattform lauffähig (um das Problem zu lösen, gibt es Cross-Compiler)
- Vorteil: Im Regelfall schneller als ein vergleichbares Programm, das einen Interpreter nutzt
- Nachteil: Programm ist an die jeweilige Plattform gebunden
Interpreter
- betrachtet/untersucht den Quelltext und übersetzt diesen zur Laufzeit und führt diesen dann aus
- ein Interpreter ist auf der entsprechenden Zielplattform notwendig, um das Programm überhaupt ausführen zu können
- die Anwendung ist im Regelfall auf verschiedenen Plattformen lauffähig. Es muss nur den entsprechenden Interpreter für die verschiedenen Plattformen geben.
- Vorteil: Plattformunabhängiger, da Ausführung vom Interpreter abhängt
- Nachteil: Im Regelfall langsamer als eine native Anwendung.
Du hast bei den Themen Java angegeben. Java ist eine Besonderheit. Da dort beide Techniken zum Einsatz kommen.
- Java Quelltext wird nicht in Maschinensprache übersetzt, sondern in Bytecode
- Die Java Virtual Machine führt den Bytecode zur Laufzeit aus und greift dabei sowohl auf einen Compiler, als auch einen Interpreter zurück.
- Java kann in bestimmten Situationen zur Laufzeit den Bytecode für die entsprechende Plattform kompilieren (Just-In-Time Compiler)
- Weniger wichtiger Code, der schnell ausgeführt wird, kann dagegen über einen Interpreter interpretiert werden.
Es wird zwar gern gesagt, dass Java-Anwendungen langsam seien. Aber das ist Unsinn. Die JVM ist mittlerweile wirklich gut und kann in einigen Fällen auch gleiche Anwendungen in anderen Sprachen schlagen.
Evtl. ist dir schon einmal aufgefallen, dass eine Java-Anwendung beim Start etwas länger baucht. Das ist u. a. durch oben genannte Punkte bedingt. Aber ich sehe Java auch eher im Backend als auf dem Heimrechner. Und auf einem Application Server spielt es keine Rolle, ob die Java Anwendung drei Sekunden länger baucht zum Hochfahren.
Wenn Du ein Programm schreibst, kannst Du das theoretisch direkt in Maschinensprache machen, also als Byte-weisen Code. Das macht aber kein Spaß, ist zwingend linear (so wie Assembler) und die jeweiligen Byte-Zeichen einzugeben eine Qual.
Deswegen gibt es Programmierhilfen, welche die Möglichkeit bieten, in vernünftiger Sprache ein Programm zu schreiben, das dann von der Programmierhilfe in von der Maschine (dem Prozessor) lesbaren Byte-Code umgeschrieben wird. Hierzu gibt es zwei grundsätzliche Methoden:
Compiler in Maschinencode: Das bedeutet, dass Dein Programmcode in nicht maschinenlesbarer Sprache auf einmal komplett umgeschrieben in einen maschinenlesbaren Code (z.B. eine .EXE- oder .COM-Datei bzw. in ein executable file). Dann hast Du das Programm, welches jederzeit gestartet werden kann, ohne dass es irgendwie nochmals übersetzt werden müsste. Bekannte Compiler-Sprachen sind C, C++. Das Programm ist sehr schnell und in den Möglichkeiten unbegrenzt. Problem: Die erstellte ausführbare Datei ist plattformabhängig.
Interpreter: Das bedeutet, dass Dein Programm nicht in ein anderes Programm umgeschrieben wird, sondern dass die Programmhilfe (der Interpreter) Zeile für Zeile liest und zeilenweise oder Abschnittsweise in maschinenlesbaren Code umwandelt. Vorteil: Plattformunabhängig. Nachteil: Langsamer, eingeschränkte Funktonalität, man braucht immer eine Interpreterumgebung. Beispiel: Basic, Macro-Sprachen.
Kombinationen: Möglich ist, den Code in eine Zwischensprache zu compiliren, welche zwar nicht maschinenlesbar ist, jedoch noch plattformunabhängig. Dieser Zwischencode wird dann interpretiert, was dann aufgrund der Vorcompilierung schneller geht. Beispiel: Java/VM, C#/.NET/CIL.
Es gibt noch Assemblieren. Das ist so wie ein Compiler, allerdings ist die Assemblersprache schon äußerst nahe am Maschinencode, im Prinzip werden die Code-Bytes einfach nur benannt mit ADD, MOV, INT etc. Sehr schnell, sehr mächtig, prozessabhängig, keine hoch-strukturierte Programmierung möglich bzw. nur sehr schwer möglich (dann würde man wieder Zusätze im Assembler benötigen, Präprozessoren etc., wäre dann kaum noch klas. Assembler, vgl. WIN32API-Asm).