Titel   Inhalt   Suchen   Index   API  Go To Java 2, Zweite Auflage, Handbuch der Java-Programmierung
 <<    <     >    >>  Kapitel 1 - Was ist Java?

1.2 Eigenschaften von Java



1.2.1 Sprachmerkmale

Java wurde vollständig neu entworfen. Die Designer versuchten, die Syntax der Sprachen C und C++ soweit wie möglich nachzuahmen, verzichteten aber auf einen Großteil der komplexen und fehlerträchtigen Merkmale beider Sprachen. Das Ergebnis ihrer Bemühungen haben sie wie folgt zusammengefaßt:

»Java soll eine einfache, objektorientierte, verteilte, interpretierte, robuste, sichere, architekturneutrale, portable, performante, nebenläufige, dynamische Programmiersprache sein.«

Der Erfolg von Java hängt eng damit zusammen, daß ein wesentlicher Teil dieser Forderungen tatsächlich in einer für viele Programmierer akzeptablen Weise umgesetzt wurde - obgleich wir am Ende dieses Kapitels auch einige kritische Anmerkungen dazu geben werden.

Java ist eine objektorientierte Programmiersprache in der Tradition von Smalltalk als auch eine klassische imperative Programmiersprache nach dem Vorbild von C. Im Detail unterscheidet sich Java aber recht deutlich von C++, das denselben Anspruch erhebt. Durch die Integration einer großen Anzahl anspruchsvoller Features wie Multithreading, strukturiertem Exceptionhandling oder eingebauten grafischen Fähigkeiten implementiert Java eine Reihe interessanter Neuerungen auf dem Gebiet der Programmiersprachen.

Zudem profitiert Java davon, daß viele der Features von C++ nicht realisiert wurden und die Sprache dadurch schlank und übersichtlich wurde. So gibt es beispielsweise keine expliziten Pointer, keine separaten Header-Dateien, keine Mehrfachvererbung und keine Templates in Java. Wer allerdings glaubt, Java sei lediglich das Skelett einer Programmiersprache, die nur das Nötigste bietet, irrt. Tatsächlich ist Java eine elegante Sprache, die auch für größere Projekte und anspruchsvolle Aufgaben genügend Reserven besitzt.

In Java gibt es die meisten elementaren Datentypen, die auch C besitzt. Arrays und Strings sind als Objekte implementiert und sowohl im Compiler als auch im Laufzeitsystem verankert. Methodenlose Strukturtypen wie struct oder union gibt es in Java nicht. Alle primitiven Datentypen sind vorzeichenbehaftet und in ihrer Größe exakt spezifiziert. Java besitzt einen eingebauten logischen Datentyp boolean.

Java bietet semidynamische Arrays, deren initiale Größe zur Laufzeit festgelegt werden kann. Arrays werden als Objekte angesehen, die eine eingeschränkte Menge an Methoden bieten. Mehrdimensionale Arrays werden wie in C dadurch realisiert, daß einfache Arrays ineinandergeschachtelt werden. Dabei können auch nicht-rechteckige Arrays erzeugt werden. Alle Array-Zugriffe werden zur Laufzeit auf Einhaltung der Bereichsgrenzen geprüft.

Die Ausdrücke in Java entsprechen weitgehend denen von C und C++. Java besitzt eine if-Anweisung, eine while-, do- und for-Schleife und ein switch-Statement. Es gibt die von C bekannten break- und continue-Anweisungen in normaler und mit einem Label versehenen Form. Letztere ermöglicht es, mehr als eine Schleifengrenze zu überspringen. Java besitzt allerdings kein allgemeines goto-Statement. Variablendeklarationen werden wie in C++ als Anweisungen angesehen und können an beliebiger Stelle innerhalb des Code-Parts eines Programms auftauchen.

Als OOP-Sprache besitzt Java alle Eigenschaften moderner objektorientierter Sprachen. Wie C++ erlaubt Java die Definition von Klassen, aus denen Objekte erzeugt werden können. Objekte werden dabei als Referenzdatentypen behandelt, die wie Variablen angelegt und verwendet werden können. Zur Initialisierung gibt es Konstruktoren, und es kann eine optionale Finalizer-Methode definiert werden, die aufgerufen wird, wenn das Objekt zerstört wird. Seit 1.1 gibt es lokale Klassen, die innerhalb einer anderen Klasse definiert werden.

Alle Methodenaufrufe in Java sind dynamisch. Methoden können überladen werden, Operatoren allerdings nicht. Anders als in C++ ist das Late-Binding standardmäßig aktiviert, kann aber unterdrückt werden. Java erlaubt zwar Einfach-, aber keine Mehrfachvererbung. Mit Hilfe von Interfaces (das sind abstrakte Klassendefinitionen, die nur aus Methoden bestehen) ist eine restriktive Form der Mehrfachvererbung möglich, die einen Kompromiß zwischen beiden Alternativen darstellt. Java erlaubt zudem die Definition abstrakter Basisklassen, die neben konkreten auch abstrakte Methoden enthalten, die in abgeleiteten Klassen ausdefiniert werden müssen.

Neben Instanzvariablen und -methoden können auch Klassenvariablen und -methoden definiert werden. Alle Elemente einer Klassendefinition können mit Hilfe der aus C++ bekannten Schlüsselwörter public, private und protected in ihrer Sichtbarkeit eingeschränkt werden. Objektvariablen werden als Referenzen implementiert. Mit ihrer Hilfe ist eine gegenüber C/C++ eingeschränkte Zeigerverarbeitung möglich, die das Erstellen dynamischer Datenstrukturen ermöglicht.

Das Speichermanagement in Java erfolgt automatisch. Während das Erzeugen von Objekten (von Ausnahmen wie String- und Array-Literalen abgesehen) immer einen expliziten Aufruf des new-Operators erfordert, erfolgt die Rückgabe von nicht mehr benötigtem Speicher automatisch. Ein Garbage-Collector, der als niedrigpriorisierter Hintergrundprozeß läuft, sucht in regelmäßigen Abständen nach nicht mehr referenzierten Objekten und gibt den durch sie belegten Speicher an das Laufzeitsystem zurück. Viele der Fehler, die bei der Programmierung in C oder C++ dadurch entstehen, daß der Entwickler selbst für das Speichermanagement verantwortlich ist, können in Java nicht mehr auftreten.

In Java gibt es ein strukturiertes Exceptionhandling. Damit ist es möglich, Laufzeitfehler zu erkennen und in strukturierter Weise zu behandeln. Eine Methode muß jeden Laufzeitfehler, der während ihrer Abarbeitung auftreten kann, entweder abfangen oder durch eine geeignete Deklaration an den Aufrufer weitergeben. Dieser hat dann seinerseits die Pflicht, sich um den Fehler zu kümmern. Exceptions sind normale Objekte; die zugehörigen Klassen können erweitert und als Grundlage für anwendungsspezifische Fehler-Handler verwendet werden.

1.2.2 Applets: Eine neue Klasse von Programmen

Eine der am meisten gebrauchten Erklärungen für den überraschenden Erfolg von Java ist die enge Verbindung der Sprache zum Internet und zum World Wide Web. Mit Hilfe von Java ist es möglich, Programme zu entwickeln, die über das Web verbreitet und mit Hilfe eines Browsers wie Netscape Navigator, Sun HotJava oder Microsoft Internet Explorer gestartet werden können. Dazu wurde die Sprache HTML um das APPLET-Tag erweitert. Sie bietet so die Möglichkeit, kompilierten Java-Code in normale Web-Seiten einzubinden.

Ein Java-fähiger Browser enthält einen Java-Interpreter (die virtuelle Java-Maschine, auch kurz VM genannt) und die Laufzeitbibliothek, die benötigt wird, um die Ausführung des Programms zu unterstützen. Die genaue Beschreibung der virtuellen Maschine ist Bestandteil der Java-Spezifikation, und Java-VMs sind bereits auf eine große Anzahl unterschiedlicher Plattformen portiert worden. Ein Applet kann damit als eine neue Art von Binärprogramm angesehen werden, das über verschiedene Hardware- und Betriebssystemplattformen hinweg portabel ist und auf einfache Weise im Internet verteilt werden kann.

Im Gegensatz zu den eingeschränkten Möglichkeiten, die Script-Sprachen wie JavaScript bieten, sind Applets vollständige Java-Programme, die alle Merkmale der Sprache nutzen können. Insbesondere besitzt ein Applet alle Eigenschaften eines grafischen Ausgabefensters und kann zur Anzeige von Text, Grafik und Dialogelementen verwendet werden. Einer der großen Vorteile von Applets gegenüber herkömmlichen Programmen ist ihre einfache Distributierbarkeit. Anstelle explizit auszuführender Installationsroutinen lädt der Classloader des Browsers die Bestandteile eines Applets einfach aus dem Netz und führt sie direkt aus. Das ist vor allem bei kleineren und mittelgroßen Anwendungen in einer lokalen Netzwerkumgebung sehr hilfreich, insbesondere wenn diese sich häufig ändern.

Sicherheit war eines der wichtigsten Designziele bei der Entwicklung von Java, und es gibt eine ganze Reihe von Sicherheitsmechanismen, die verhindern sollen, daß Java-Applets während ihrer Ausführung Schaden anrichten. So ist es einem Applet, das in einem Web-Browser läuft, beispielsweise nicht erlaubt, Dateioperationen auf dem lokalen Rechner durchzuführen oder externe Programme zu starten.

 Hinweis 

1.2.3 Grafikprogrammierung

Die Java-Laufzeitbibliothek bietet umfassende grafische Fähigkeiten. Diese sind im wesentlichen plattformunabhängig und können dazu verwendet werden, portable Programme mit GUI-Fähigkeiten auszustatten. Seit der Version 1.2 des JDK werden diese Fähigkeiten unter dem Begriff Java Foundation Classes (kurz JFC) zusammengefaßt, deren drei wichtigste Komponenten die folgenden sind:

Es ist eine bemerkenswerte Innovation, daß Elemente für die GUI-Programmierung in einer Programmiersprache portabel zur Verfügung gestellt werden. Zwar gab es auch früher schon Programmiersprachen, die grafische Fähigkeiten hatten, aber wer einmal die Aufgabe hatte, eine grafische Benutzeroberfläche unter Windows, OS/2, UNIX und auf dem MAC zur Verfügung zu stellen, hatte meistens erheblichen Portierungsaufwand. Mit Standardmitteln der Sprachen C oder C++ und ihren Laufzeitbibliotheken war dies jedenfalls nicht möglich. Mit Java und ihren Klassenbibliotheken steht nun erstmals eine einfach zu verwendende Sprache zur Verfügung, die all diese Dinge bereits bietet.

 Hinweis 

Das AWT stellt eine Reihe von elementaren Operationen zur Verfügung, um grafische Ausgabeelemente, wie Linien, Polygone, Kreise, Ellipsen, Kreisabschnitte oder Rechtecke, zu erzeugen. Diese Methoden können auch in einem Füllmodus verwendet werden, der dafür sorgt, daß die gezeichneten Flächen mit Farbe ausgefüllt werden. Wie in den meisten Grafik-Libraries realisiert auch Java die Bildschirmausgabe mit Hilfe des Konzepts eines Grafikkontexts, der eine Abstraktion des tatsächlichen Ausgabegerätes bildet.

Neben grafischen Elementen kann natürlich auch Text ausgegeben und an beliebiger Stelle innerhalb der Fenster plaziert werden. Text kann skaliert werden, und es ist möglich, mit unterschiedlichen Fonts zu arbeiten. Das AWT bemüht sich, einen portablen Weg zur Font-Auswahl anzubieten, indem eine Reihe von elementaren Schriftarten auch über Plattformgrenzen hinweg angeboten werden. Mit Hilfe von Font-Metriken können numerische Eigenschaften der verwendeten Schriftarten bestimmt und bei der Ausgabe berücksichtigt werden.

Das Farbmodell von Java basiert auf dem RGB-Modell, das seine Farben additiv auf der Basis der enthaltenen Rot-, Grün- und Blauanteile bestimmt. Daneben wird auch das HSB-Modell unterstützt (hue, saturation, brightness), und es gibt Methoden zur Konvertierung zwischen beiden. Das Farbsystem unterstützt eine Reihe von vordefinierten Farben, die plattformübergreifend zur Verfügung stehen.

Neben Grafik kann auch Sound ausgegeben werden. Java unterstützt die Wiedergabe von au-Dateien (ein von Sun eingeführtes Format zur Speicherung von digitalen Sound-Samples) und seit der Version 1.2 auch wav- und aiff-Dateien , die entweder über das Internet oder aus einer lokalen Datei geladen werden können. Die Samples können einmalig oder in einer Schleife wiederholt aufgerufen werden. Daneben ist es möglich, zwei oder mehr Sound-Dateien gleichzeitig abzuspielen. Neben Wave-Dateien gibt es seit dem JDK 1.2 auch die Möglichkeit, Midi-Dateien abzuspielen.

Das AWT erlaubt die Anzeige und Manipulation von Bilddaten. Mit Hilfe von Standardmethoden können Grafiken in elementaren Formaten wie GIF oder JPEG geladen, skaliert und auf dem Bildschirm angezeigt werden. Zusätzlich gibt es das Paket java.awt.image, das für die Manipulation von Bilddaten entworfen wurde und ausgefeilte Funktionen zur Bild- und Farbmanipulation zur Verfügung stellt.

Wie in den meisten grafischen Entwicklungsumgebungen wird auch beim AWT der Programmfluß durch Nachrichten gesteuert. Sie werden beim Auftreten bestimmter Ereignisse an das Programm gesendet und von diesem in geeigneter Weise behandelt. Java stellt Nachrichten zur Bearbeitung von Maus-, Tastatur, Fenster-, Dialog- und vielen anderen Ereignissen zur Verfügung. Das Event-Handling des JDK 1.1 erlaubt es, Nachrichten an jedes beliebige Objekt zu senden, das die Schnittstelle eines Nachrichtenempfängers implementiert.

 Hinweis 

Die zweite graphische Oberfläche des JDK, das Swing-Toolkit, bietet noch weitreichendere Fähigkeiten als das AWT. So stehen nicht nur zusätzliche Dialogelemente, wie Tabellen, Trees oder Karteikarten, zur Verfügung, sondern auch die Architektur wurde vollständig neu entworfen. Anstatt wie im AWT auf die Eigenschaften vorgefertigter GUI-Elemente zu vertrauen, verwendet Swing lediglich einen sehr eingeschränkten Satz an plattformspezifischen Grafikoperationen. Alle Dialogelemente werden unter Verwendung einfacher und portabler Grafikprimitive selbst dargestellt. Die Anzahl der Unterschiede zwischen den unterschiedlichen Plattformen wird auf diese Weise drastisch reduziert.

1.2.4 Umfangreiche Klassenbibliothek

Die Java-Klassenbibliothek bietet eine ganze Reihe nützlicher Klassen und Interfaces, die eine problemnahe Programmierung ermöglichen. Einige dieser Features sind von Anfang an nützlich, andere erschließen sich erst nach einiger Einarbeitung.

Neben grafischen Ausgabemöglichkeiten stellt Java auch einfache Textausgaben zur Verfügung, ähnlich den entsprechenden Funktionen in C oder C++. Damit ist es möglich, Programme mit einfachen, zeilenorientierten Ein-/Ausgabemöglichkeiten auszustatten, wenn keine aufwendige Benutzerschnittstelle benötigt wird. Einfache Textausgaben werden mit den Methoden der Klasse PrintStream erzeugt. Diese erlauben es, alle gängigen Datentypen in ein Terminalfenster auszugeben. Die Klassenvariable System.out bietet einen vordefinierten PrintStream, der vom Laufzeitsystem initialisiert wird. In ähnlicher Weise steht mit System.in die Möglichkeit zur Verfügung, einfache Texteingaben von der Tastatur einzulesen.

Eines der wichtigsten Elemente der Klassenbibliothek ist die Klasse String, die Java-Implementierung von Zeichenketten. String bietet eine Vielzahl wichtiger Methoden zur Manipulation und zum Zugriff auf Zeichenketten, wie beispielsweise Operationen für numerische Konvertierungen, Zeichen- und Teilstringextraktion sowie für Textsuche und Stringvergleich.

Interessanterweise kann sich der Inhalt eines Strings in Java nicht verändern, sondern bleibt nach seiner Initialisierung fest. Das ist aber nicht weiter störend, denn in Zusammenarbeit mit der Klasse StringBuffer (die variabel lange Strings bietet) und der Fähigkeit des Compilers, String-Initialisierung, -Zuweisung und -Verkettung mit Hilfe der impliziten Verwendung der StringBuffer-Klasse auszuführen, fällt es gar nicht auf. Dank des automatischen Speichermanagements und der effizienten Konvertierung von StringBuffer nach String ähnelt der Umgang mit Strings aus der Sicht des Programmierers dem mit variabel langen Zeichenketten in anderen Programmiersprachen. Wegen des automatischen Speichermanagements sind Java-Strings insbesondere sehr viel sicherer als nullterminierte Strings in C oder C++.

Ein Vector in Java ist eine lineare Liste, die jede Art von Objekt aufnehmen kann und auf deren Elemente sowohl sequentiell als auch wahlfrei zugegriffen werden kann. Die Länge eines Vektors ist veränderlich, und Elemente können am Ende oder an einer beliebigen anderen Stelle eingefügt werden. Aufgrund dieser Flexibilität kann ein Vector oft da verwendet werden, wo ansonsten eine lineare Liste durch Verkettung von Objektreferenzen manuell erstellt werden müßte. Wie gewöhnlich erfolgt auch das Speichermanagement eines Vektors vollkommen automatisch. Neben Vector gibt es noch weitere Container-Klassen. So bietet beispielsweise Hashtable die Möglichkeit, beliebige Paare von Schlüsseln und Werten zusammenhängend zu speichern und effizient wieder aufzufinden.

Ein nützlicher Mechanismus zum Durchlaufen von Container-Klassen ist das Enumeration-Interface. Eine Klasse, die Enumeration implementiert, stellt die Methoden hasMoreElements und nextElement zur Verfügung. Diese können verwendet werden, um in einer Schleife alle Elemente des Containers zu durchlaufen. Die vordefinierten Container-Klassen von Java stellen meistens die Methode elements zur Verfügung, die ein Enumeration-Objekt zum Durchlaufen der eigenen Elemente zurückgibt.

Seit dem JDK 1.2 gibt es in Java eine eigene Bibliothek für Container-Klassen, das Collection-API. Sie stellt eine umfassende Sammlung an Interfaces für Container-Klassen zur Verfügung und bietet unterschiedliche Implementierungen für verschiedene Anwendungsfälle. Die zuvor erwähnte Klasse Enumeration wird hier durch das Interface Iterator ersetzt, das einfacher zu bedienen ist. Das Collection-API stellt daneben einige Algorithmen zur Verarbeitung von Containern zur Verfügung (z.B. Sortieren), die es in den einfachen Container-Klassen nicht gab.

Java stellt auch Zufallszahlen zur Verfügung. Das Paket java.util bietet eine Klasse Random, die das Initialisieren von Zufallszahlengeneratoren und den Zugriff auf ganzzahlige oder Fließkomma-Zufallszahlen ermöglicht. Neben gleichverteilten stellt die Klasse Random auch normalverteilte Zufallszahlen zur Verfügung.

Seit dem JDK 1.1 stehen darüber hinaus eine ganze Reihe hochspezialisierter (und teilweise sehr aufwendiger) Bibliotheken zur Verfügung. So bietet beispielsweise JDBC (Java Database Connectivity) den Zugriff auf relationale Datenbanken, JavaBeans stellt eine portable Komponentenarchitektur zur Verfügung, und mit dem Networking-API und RMI (Remote Method Invocation) kann unternehmensweit auf Netzwerkressourcen und verteilte Objekte zugegriffen werden. Per Serialisierung können Objekte persistent gemacht werden, und mit dem Reflection-API kann der Aufbau von Objekten und Klassen zur Laufzeit untersucht und dynamisch darauf zugegriffen werden. Wir werden in diesem Buch die wichtigsten dieser Bibliotheken ausführlich erläutern.


 Titel   Inhalt   Suchen   Index   API  Go To Java 2, Zweite Auflage, Addison Wesley, Version 2.0
 <<    <     >    >>  © 2000 Guido Krüger, http://www.gkrueger.com