Daß Java wirklich kein kalter Kaffee ist, sondern von jedem selbst frisch aufgebrüht werden kann, soll der folgende kurze Vergleich eines ObjectGEM- und Java-Sourcecodes zeigen. Auch wenn ObjectGEM nicht jedem bekannt ist, ist die Sprache dieser Bibliothek - PurePascal - vielen sicherlich nicht unbekannt, und ein Pascalprogramm allgemein werden die meisten wohl schon gesehen haben. Daher gebe ich im folgenden nur einen kurzen Überblick über Java.
Java ist eine
Es gibt relativ wenig Sprachkonstrukte. Die Sprache sieht für C- und C++-Programmierer "bekannt" aus, ohne daß der Overhead von C++ (nette Spielereien, die aber kaum jemand nutzt bzw. Konstrukte, die zur unübersichtlichen und fehleranfälligen Programmierung ermuntern) übernommen wurde. Und es gibt keine (!) Pointer.
Java ist komplett objektorientiert (wie z.B. Eiffel), hybride Programmierung wie in C++ oder ObjektPascal ist nicht möglich.
Java ist dafür vorbereitet, im Netz (sei es im Internet oder in einem betriebsinternen Intranet) zu arbeiten und Ressourcen (Dateien, Bilder, Sounds) von dort anzufordern.
Java-Sourcecodes werden zum sogenannten "Bytecode" compiliert. Dies ist eine Art prozessorunabhängige Maschinensprache, die vom Java-Interpreter (z.B. javai aus dem Java Development Kit von Sun) interpretiert wird.
Mittlerweile wird allerdings an Java-Inlinecompilern (JILs) gearbeitet, die Java-Bytecode zur Laufzeit in echten (d.h. prozessorabhängigen) Maschinencode übersetzen.
Mit Java ist es leichter möglich, zuverlässige Software zu schreiben, wofür verschiedene Sprachkonstrukte zur Verfügung stehen. Ausgeschlossen werden können Programmierfehler natürlich nicht.
Java ist eine sichere Sprache, d.h. sie ist gegen Hackversuche aus dem Netz (Manipulation eines Rechners von außen) geschützt.
Die Sicherheitsbedenken, die durch die Netze geisterten, betrafen ausschließlich die fehlerhafte Java-Implementation in einer Netscape 2.x-Version, nicht aber die Sprache an sich.
Abgesehen vom prozessorunabhängigen Bytecode sind sämtliche Zugriffe auf Systemressourcen (Fenster, Dialoge etc.) standardisiert.
Zusätzlich zur Architekturneutralität sind auch solch grundlegenden Dinge wie der Aufbau und die Größe von elementaren Datentypen festgelegt, so daß der Bytecode zwischen allen Rechnerwelten portabel ist.
Obwohl Java eine interpretierte Sprache ist, ist sie nur um etwa den Faktor 20 langsamer als übliche C-Programme. Dieser Wert relativiert sich zudem, da der Prozessor bei einer grafischen Benutzeroberfläche die meiste Zeit mit Warten verbringt.
Ferner ist der Java-Bytecode so ausgelegt, möglichst optimal in prozessorabhängigen Maschinencode übersetzt werden zu können.
MiNT hat es eingeschränkt, MagiC bietet es jetzt auch (und dafür gleich besser), bei Java ist es von Anfang an mit dabei: Threads. Man kann in Java ohne großen Aufwand mehrere Aktionen nebenläufig ablaufen lassen - um die meisten kritischen Sachen kümmert sich Java automatisch.
Klassen werden nur bei Bedarf nachgeladen.
Im folgenden kleinen Einblick können nicht alle dieser Eigenschaften erläutert werden, aber zumindest die Einfachheit und Objektorientierung sollten deutlich werden.
Ein jeder kennt dieses Programm, seine Funktionsweise, und der Sourcecode ist auch für Nichtkenner einer Sprache ohne größere Probleme lesbar.
Zunächst sind die kompletten Sourcecodes aufgelistet, danach kommt der versprochene Vergleich.
program Hello; uses Gem,OTypes,OWindows; type TMyApplication = object(TApplication) procedure InitMainWindow; virtual; end; PMyWindow = ^TMyWindow; TMyWindow = object(TWindow) procedure Paint(var PaintInfo: TPaintStruct); virtual; end; var MyApp: TMyApplication; procedure TMyApplication.InitMainWindow; begin new(PMyWindow,Init(nil,'')) end; procedure TMyWindow.Paint(var PaintInfo: TPaintStruct); begin v_gtext(vdiHandle,Work.X+10,Work.Y+20,'Hello World!') end; begin MyApp.Init('HelloWorld'); MyApp.Run; MyApp.Done end.
import java.awt.*; public class HelloWorld { public static void main(String args[]) { MyFrame f = new MyFrame(); f.resize(200,100); f.show(); } } public class MyFrame extends Frame { public MyFrame() { super(""); } public void paint(Graphics g) { g.drawString("Hello World!",10,20); } }
Los geht's mit der ersten Zeile des Pascal-Programms: program Hello;. Bei Pascal ist die Zeichenkette hinter program ziemlich egal, kaum ein Compiler erwartet hier spezielle Angaben. Der Name der späteren Programmdatei wird meistens aus dem Namen der Sourcecodedatei erzeugt (also z.B. "HELLO.PRG" aus "HELLO.PAS"), dieser hat mit der Ausführung des Programms aber nichts zu tun.
In Java fehlt eine entsprechende Zeile, außerdem sind die Dateinamen viel enger mit dem Sourcecode verknüpft. Aus dem obigen Java-Sourcecode würden z.B. die beiden Klassen "HelloWorld.class" und "MyFrame.class" erzeugt bzw. - wenn alle zu einem Projekt gehörenden Klassen zu einer ausführbaren Datei zusammengelinkt werden - die Datei "HelloWorld.out", da dies die Klasse mit der main()-Methode ist.
Danach werden die nötigen Bibliotheken eingebunden: Gem (AES- und VDI-Aufrufe), OTypes (ObjectGEM-Konstanten und -Typen) und OWindows (die nötigen ObjectGEM-Objekte) bei PurePascal, alle java.awt-Klassen ("advanced windowing toolkit", Klassen zur systemunabhängigen Fenster- und Dialogdarstellung) bei Java.
Anschließend folgt bei Pascal die Deklaration der Objekte, ein Applikationsobjekt (TMyApplication) und ein Fensterobjekt (TMyWindow). Bei Java fehlt ein solcher Deklarationsteil, die Deklaration geschieht direkt bei der Implementation der Objekte. Eine getrennte Deklaration ist auch gar nicht nötig, da alle Methoden an allen Stellen des Programms aufgerufen werden können (forward ist also überflüssig), wenn sie nicht explizit vor einem Zugriff geschützt werden. Neben den von Pascal bekannten Schlüsselwörtern public und private kann man in Java die Zugriffsrechte allerdings noch wesentlich genauer differenzieren. Zu bemerken ist noch, daß auch bei Java ein Art "Applikationsobjekt" (HelloWorld) und ein Fensterobjekt (MyFrame) angelegt wird.
In der folgenden Zeile instantiiert Pascal dann das Applikationsobjekt (var MyApp: TMyApplication;), der Aufruf geschieht mit den drei Methoden Init(), Run und Done im Hauptprogramm am Ende des Quelltextes. In Java wird das Objekt mit der main()-Methode automatisch instantiiert, und diese Methode wird ebenfalls automatisch aufgerufen (main() ist - analog zu C und C++ - das eigentliche Hauptprogramm).
In der überschriebenen Methode von TApplication, InitMainWindow, wird das Fensterobjekt vom Typ TMyWindow schließlich erzeugt und das Fenster implizit geöffnet. Genauso wird in main() das Fensterobjekt vom Typ MyFrame erzeugt, muß danach allerdings explizit geöffnet werden (f.show();).
War diese Aktion schon recht ähnlich, wird es jetzt nahezu gleich: Die Ausgabe der Zeichenkette "Hello World!" wird in den jeweiligen Paint-Methoden vorgenommen. Der Grafikkontext (Clipping etc.) - bei ObjectGEM als vdiHandle übergeben, bei Java beschreibt g selbst den Kontext - ist vor dem Aufruf passend eingerichtet, so daß innerhalb der Methoden nur noch die Textausgaberoutine aufgerufen werden muß.
Mehr gibt es im direkten Vergleich der Quelltexte eigentlich nicht zu sehen, wenn man nicht auch noch die Sprachsyntax mit einbezieht. Drei wesentliche Punkte möchte ich davon dann doch noch erwähnen.
In Pascal geschieht Vererbung bei der Typendeklaration des Objekts, bei unserem Beispiel type TMyWindow = object(TWindow) ... end;, der Ableitungsoperator ist hierbei object(). Bei Java übernimmt diese Rolle extends, ansonsten sieht die Vererbung der von Pascal recht ähnlich: class MyFrame extends Frame { ... }.
Beide Sprachen haben gemeinsam, daß sie Mehrfachvererbung nicht unterstützen, ein Objekt kann also immer nur von genau einem Objekt abgeleitet werden, kann also nur genau einen Vorfahren haben. Java erlaubt allerdings die Verwendung sogenannter "interfaces" in beliebiger Zahl. Dies sind keine Objekte bzw. Klassen, sondern Schnittstellendefinitionen (abstrakte Methodendeklarationen), die eine das Interface verwendende Klasse implementieren muß.
Außerdem nicht ganz offensichtlich ist, daß Pascal standardmäßig statische Methoden verwendet, die durch das Schlüsselwort virtual virtuell gemacht werden können. In Java dagegen sind alle Methoden virtuell, wenn sie nicht mit static explizit statisch ausgelegt werden.
Zum Abschluß gibt es noch ein bißchen Statistik:
ObjectGEM | Java | |
Programmgröße | 160 KB | 6 KB, zzgl. |
1.5 MB vorinstallierter | ||
Klassenbibliotheken | ||
Compilerzeit | 2 Sekunden | 25 Sekunden |
Bleibt mir nur noch zu erwähnen, daß es einen Java-Interpreter bzw. -Compiler leider (noch?) nicht für GEM gibt. Sollte jetzt der eine oder andere Programmierer aufgeschreckt sein: Die (ANSI-C- bzw. Java-)Sourcen gibt es bei Sun, viel Spaß beim Portieren!