1.1.2 Die Programmiersprache Java
Die Programmiersprache Java ist von der Syntax her stark an C/C++ angelehnt, während die Objektorientierung eher von SmallTalk stammt. Java wurde deshalb so erfolgreich, weil die Stärken der Vorfahren genommen und deren Schwächen ausgemerzt sowie über eine vertraute Syntax die Einstiegshürden niedrig gehalten wurden. Dazu kam die Ergänzung dann noch fehlender, sinnvoller Innovationen. Die genauen Hintergründe wollen wir später behandeln. Schauen wir uns nur kurz an, wie der Java-Erfinder Sun schon zu Beginn der Java-Karriere seine geniale Erfindung selbst charakterisiert hat:
Java: eine einfache, objektorientierte, dezentrale, interpretierte, stabil laufende, sichere, architekturneutrale, portierbare und dynamische Sprache, die Hochgeschwindigkeits-Anwendungen und Multithreading unterstützt.
Untersuchen wir die Details.
- Java wird von Sun als »einfach« bezeichnet. Das kann man in Bezug auf den Lernaufwand sehen. Zum Anderen aber – und darum geht es eher – in Bezug auf die Strukturen der Sprache. Und hier ist Java – insbesondere am Anfang – viel einfacher als diverse Konkurrenztechnologien gewesen. Java an sich ist klein. Die Sprache Java ist insofern einfach, als es nur wenige Elemente und vor allen wenige Axiome (Grundregeln zum Aufbau des logischen Konzepts) gibt. Wenn man wenige – wenngleich oft abstrakte – Regeln berücksichtigt, baut sich die gesamte Java-Philosophie daraus auf. Leider2 hat sich Java aber in den letzten Jahren sehr an Features aus Konkurrenztechnologien orientiert und diese ebenso integriert. Was deutlich zu Lasten der Einfachheit ging.
- Java ist eine strenge objektorientierte Technologie. In Java gibt es – bis auf wenige sinnvolle Ergänzungen – nichts außer Objekten und deren Bestandteilen. Das macht Java stabil, sicher und – wenn man das Konzept verinnerlicht hat – logischer als Sprachen, die nicht so streng sind.
- Der Begriff »dezentral« in der Beschreibung der Eigenschaften von Java bedeutet, ein Java-Programm kann auf verschiedene Systeme verteilt werden. Teile eines Vorgangs laufen beispielsweise auf einem Rechner, andere Teile auf einem anderen. Oder bestimmte Bestandteile (Bibliotheken) sind auf verschiedene Ressourcen verteilt. Sie werden zur Laufzeit von der Java-Laufzeitumgebung zusammengefügt.
- Java gilt als interpretiert und kompiliert zur gleichen Zeit, was im Grunde einen Widerspruch darstellt. Ohne die Vorgänge der Interpretation und Kompilierung hier weiter zu verfolgen (dazu kommen wir ausführlich), wäre ein passender Vergleich, wenn man von einem schwarzen Schimmel reden würde. Was nun? Entweder, oder? Beide Vorgänge (Interpretation und Kompilierung) beschreiben den Vorgang der Übersetzung von Quelltext in lauffähigen Binärcode, der von einem Computer ausgeführt werden kann. Dies kann man auf zwei Arten machen. Entweder, der Quelltext wird auf einen Schlag mit einem geeigneten Programm übersetzt und dann dieser daraus resultierende Binärcode auf den Computer zum Laufen gebracht. Das bedeutet dann, dass der Quelltext kompiliert wurde. Man kann aber auch mit einem anderen Programmtyp den Quelltext laden und Zeile für Zeile lesen und direkt zur Laufzeit des Programms übersetzen lassen. Das ist dann der Vorgang der Interpretation. Java macht beides. Der eigentliche Quellcode wird in einen binären Zwischencode (so genannten Bytecode) kompiliert, der ein architekturneutrales und noch nicht vollständiges Object-Code-Format ist. Er ist noch nicht lauffähig und muss von einer Laufzeitumgebung interpretiert werden. Dies ist die sogenannte JRE (Java Runtime Environment), deren wesentlichen Bestandteil die JVM (Java Virtual Machine – ein virtuelle Prozessor) ist. Da jede Java-Laufzeitumgebung plattformspezifisch ist, arbeitet das endgültige ausgeführte Programm auf dieser spezifischen Plattform. Dort werden alle Elemente hinzugebunden, die für eine spezielle Plattform notwendig sind. Die Tatsache, dass der letzte Teil der Übersetzung des Bytecodes von einem plattformspezifischen Programm auf der Plattform des Endanwenders ausgeführt wird, nimmt dem Entwickler die Verantwortung, verschiedene Programme für verschiedene Plattformen erstellen zu müssen. Die Interpretation erlaubt zudem, Daten zur Laufzeit zu laden, was die Grundlage für das dynamische Verhalten von Java ist.
- Java ist stabil in der Bedeutung von »zuverlässig«. Dies bedeutet, Java-Programme werden seltener abstürzen als in den meisten anderen Sprachen geschriebene Programme. Die gesamte Philosophie von Java ist darauf ausgerichtet und zahlreiche hochintelligente Details im Hintergrund sorgen dafür.
- Java ist nicht nur stabil, sondern auch sehr sicher. So ist die Unterbindung von direkten Speicherzugriffen nicht nur ein Stabilitätskriterium, sondern trägt gleichfalls zur Sicherheit bei. Dazu kommt, dass sich Bytecode-Anweisungen von in Java implementierten Sicherheitsstellen gut überprüfen lassen.
- Java ist architekturneutral, d.h., es ist auf verschiedenen Systemen mit unterschiedlichen Prozessoren und Betriebssystemarchitekturen lauffähig. Der kompilierte Java-Bytecode kann auf jedem System ausgeführt werden, das die JRE samt der so genannten virtuellen Maschine (Java virtual Machine – JVM oder kurz VM) von Java implementiert.
- Java ist portierbar, was bedeutet, durch zahlreiche Spezifikationen (etwa standardisierte Datentypen, die sich auf jeder Plattform gleich verhalten) kann Java auf alle denkbaren Plattformen übertragen und dort implementiert werden.
- Java ist dynamisch. Das kann man als reine Marketingaussage auffassen, aber so ist es nur in zweiter Linie gemeint. Die Aussage beschreibt, dass sich Java an eine sich ständig weiter entwickelnde Umgebung anpassen kann. Wenn ein Java-Programm sich an veränderte Bedingungen anpassen muss, werden einfach einzelne Module ausgetauscht oder neu hinzugenommen. Sogar während der Laufzeit kann ein Java-Programm neu benötigte Funktionalitäten einfach hinzubinden.
- Ein Charakteristikum von Java ist nach Aussage von Sun seine Leistungsfähigkeit gewesen. Hier muss man aber realistisch bleiben. Gerade in frühen Versionen von Java war die absolut mangelhafte Performance einer der Hauptkritikpunkte. Allerdings haben sowohl interne Optimierungen von Java (u.a. die Hotspot-Optimierung) selbst als auch die mittlerweile sehr hohe Leistungsfähigkeit selbst von Billigcomputern zu einer konkurrenzfähigen Leistungsfähigkeit von Java geführt.
- Java unterstützte von Anfang an Multithreading. Bei Java ist das Multithreading-Konzept voll integrierter Bestandteil der Philosophie. Der hoch entwickelte Befehlssatz in Java, um Threads zu synchronisieren, ist in die Sprache integriert, macht diese stabil und einfach in der Anwendung. Und gerade das Aufkommen von Mehrkernprozessoren in den letzten Jahren macht Multithreading zu einem interessanten Aspekt bei der Erstellung von leistungsfähigen Applikationen.