# Einleitung
## Nötiges Vorwissen

Als Vorwissen für dieses Buch wird vorausgesetzt, dass der Nutzer mit dem Computer und der Kommandozeile (Shell) umgehen kann. Des Weiteren werden Kenntnisse der objektorientierten Programmierung vorausgesetzt.
Nicht notwendig, aber nützlich, ist die Kenntnis einer anderen mit Java verwandten Programmiersprache, wie etwa C++.

## Geschichte und Namensgebung

Die Programmiersprache Java wurde 1991 von James Gosling und anderen im Hause Sun Microsystems entwickelt. Der ursprüngliche Name lautete jedoch Oak für eine große Eiche außerhalb des goslingschen Büros.
Eine ausführliche Beschreibung mit Spezifikationen der Programmiersprache ist in der deutschsprachigen Wikipedia zu finden.

### Versionen von Java

Es gibt mehrere Versionen von Java, wobei grob gesagt werden kann, dass die vorletzte Version die am häufigsten eingesetzte Version ist. Dieses Buch ist im Grundstil dafür geschrieben, dass mit dieser Version gearbeitet wird. Zur Zeit ist die Version 1.4 die am meisten eingesetzte Version.
Auf die neueren Features von Java 5.0 (Tiger) wird ebenfalls an den geeigneten Stellen eingegangen.

#### Version 1.1 (1997)

Wesentliche Änderung:
* Neues Event Handling

#### Version 1.2 (1998) / Java 2

Wesentliche Änderung:
* Aufnahme von Swing in die J2SE

#### Version 1.4 (2002)

Wesentliche Änderungen:
* Unterstützung von Zusicherungen (Assertions)
* Aufnahme einer Logging API
* Aufnahme einer API für reguläre Ausdrücke

#### Version 5.0 (2004)

Wesentliche Änderungen:
* Generische Datentypen
* Enumerationen
* Neue zusätzliche Syntax für for-Schleifen über Datenstrukturen
* Annotationen für Metadaten

#### Version 6.0 (2006)

Sun Microsystems hat erstmalig sehr früh einen Einblick in die neue Version (Codename Mustang) gewährt. Einige Themen stehen zur Diskussion, darunter unter anderem aspekt orientierte Entwicklung [AOP], ein Thema, welches dem Entwickler sicher ebenso viel Freude machen dürfte wie die generischen Datentypen in Version 5 oder die Logging API in Version 1.4.

## Warum Java?

Hier werden Ihnen die Vor- und Nachteile von Java aufgezeigt, damit Sie sich besser entscheiden können, ob es sich für Sie lohnt, diese Programmiersprache zu erlernen.

### Vorteile

Java ist mittlerweile für die verschiedensten Computersysteme verfügbar und hat eine weite Verbreitung gefunden. Ebenso bringt Java eine umfangreiche Klassenbibliothek mit, die für (fast) alle täglichen Programmieraufgaben eine Unterstützung enthält. Durch das Konzept der virtuellen Maschine ist ein einmal compilierter Programmcode auf jeder Plattform, für die eine Java VM vorhanden ist, lauffähig. Ein erneutes Übersetzen auf der jeweiligen Zielplattform (wie bei C/C++) ist nicht mehr notwendig. Ein weiterer Vorteil sind die sogenannten "Applets". Dies sind Java-Programme, die innerhalb eines Web-Browsers gestartet werden können und somit sehr einfach Applikationen über das Internet verfügbar machen.
Ein handfester Vorteil - nicht nur für große Projekte - ist die mittlerweile freie Verfügbarkeit von integrierten Entwicklungsumgebungen, allen voran die Eclipse-Plattform. Für viele Programmierer ist gerade die Werkzeugunterstützung ein entscheidendes Kriterium bei der Auswahl einer Programmiersprache. Hier ist Java eine der am aktivsten unterstützen Plattformen.
Java hat sich mittlerweile als Industriestandard etabliert.

### Nachteile

Java-Programme benötigen zur Ausführung eine Laufzeit-Umgebung. Auf vielen Computern ist diese nicht vorinstalliert und muss erst separat eingerichtet werden. Gleiches gilt jedoch auch für andere beliebte Programmiersprachen, z.B. .NET oder Perl. Ebenso sind die in gängigen Browsern eingebauten Java-Applet-Laufzeit-Umgebungen häufig veraltet. Will man Java-Programme für diese Browser schreiben, so muss man sich auf eine alte Sprachversion beschränken oder auf dem Browser eine aktuelle Laufzeitumgebung nachinstallieren.
Des Weiteren ist Java nicht geeignet, um systemnahe Programme wie etwa Hardwaretreiber zu entwickeln. Das liegt im Wesentlichen daran, dass Java-Programme auf theoretisch beliebigen Rechnerarchitekturen und Betriebssystemen unverändert lauffähig sein sollen. Diese Abstraktion lässt einen direkten Zugriff auf spezifische hardwarenahe Funktionen nicht mehr zu. Andere Sprachen wie etwa C oder C++ sind für derartige Aufgaben besser geeignet.

### Geschwindigkeit von Java-Programmen

Die vorherrschende Meinung zur Geschwindigkeit von Java-Programmen ist, dass Java-Programme langsamer als vergleichbare C- oder C++-Programme seien. Das kann man jedoch nicht pauschal so sagen, denn die Geschwindigkeit von Java-Programmen hängt von verschiedenen Faktoren ab.
Eine große Rolle spielt zunächst die Virtuelle Maschine (VM), auf der das Java-Programm abläuft. In den Anfangszeiten wurde Java-Code interpretiert. Dies führte zu Leistungseinbußen, die bei modernen Java-VMs praktisch nicht mehr gegeben sind. Die Java-VM von SUN beispielsweise "kompiliert" Java-Programme sozusagen zur Laufzeit. Im Ergebnis erhält man ein Programm, das kaum noch langsamer ist als ein vergleichbares, das in C oder C++ geschrieben wurde.
Einen grundsätzlichen Geschwindigkeitsnachteil haben Java-Programme beim "Anfahren", denn jedes Java-Programm muss zunächst für sich eine eigene VM starten. Außerdem dauert das Laden der Klassen sehr lange. Neuere Implementierungen der VM (2004) beheben letzteren Nachteil dadurch, dass Klassen von mehreren Programmen gleichzeitig benutzt werden können, so dass, nachdem die erste Java-Applikation gestartet wurde, für die nachfolgenden das Laden entfällt.
Einen weiteren Geschwindigkeitsnachteil haben Java-Programme dadurch, dass bei jedem Feldzugriff die Bereichsgrenzen überprüft werden. Moderne VMs können aber die Überprüfung weitestgehend "wegoptimieren", indem bei Schleifendurchläufen - anstatt bei jedem Feldzugriff - die Bereichsüberprüfung vor dem Schleifenrumpf platziert wird. Auf diese Art lassen sich etwa 80 Prozent der ansonsten anfallenden Bereichsüberprüfungen eliminieren.
Noch ein Nachteil entsteht Java-Code dadurch, dass viele Methoden (genauer: nicht-finale Instanzmethoden) zunächst virtuell sind. Auch hier haben jedoch Compiler die Möglichkeit, Optimierungen durchzuführen; und weil die Laufzeitumgebung von Java auf die Ausführung von virtuellen Methoden optimiert ist, sind Aufrufe von virtuellen Methoden in Java erheblich schneller als in den meisten C++-Compilern.
Nicht zuletzt spielt auch die Bibliothek eine Rolle. Die von SUN favorisierte Swing-Bibliothek, die in erster Linie für die Grafikausgabe zuständig ist, steht nicht im Ruf, besonders schnell zu sein.
Es gibt aber auch Bedingungen, unter denen Java-Programme Geschwindgkeitsvorteile gegenüber C- oder C++-Programmen haben. Beispielsweise ist die Objekterzeugungsgeschwindigkeit bei Java sehr hoch. Wenn es also darum geht, viele Objekte in kurzer Zeit zu erzeugen, können Java-Programme in der Praxis hier Vorteile ausspielen. Java hat auch weniger Aliasing-Probleme als C oder C++. Aliasing bedeutet, dass sich Speicherbereiche von formal unterschiedlichen Objekten überlappen. Da es in Java weniger Aliasing-Probleme gibt, können Java-Programme bei numerischen Aufgaben gewinnbringend eingesetzt werden. (Siehe Leistungsvergleich zwischen Java und C++.)
Ob Ihr eigenes Java-Programm in der Praxis schneller oder langsamer ist als eines, das in C++ geschrieben wurde, hängt aber noch von vielen anderen Faktoren ab. Wie schon angedeutet, können Java-Programme auf schnellen und auf langsamen VMs laufen. Und wenn Sie die Geschwindigkeit mit C++ vergleichen, dann spielt selbstverständlich auch die Implementierung des zugrundeliegenden C++-Compilers eine Rolle.
Groß ist der praktische Geschwindigkeitsunterschied heutzutage in den meisten Fällen jedenfalls nicht.
Jedes Java-Programm lässt sich aber unendlich langsam machen, wenn man nur unendlich schlecht programmiert. Der Hauptfaktor dabei sind also Sie.
Um mit Java zu arbeiten, benötigt man - wie in jeder anderen Programmiersprache auch - ein paar Werkzeuge, wie zum Beispiel einen Compiler und einen Editor. Diese Werkzeuge werden hier jetzt erläutert, damit Sie wissen, was Sie benötigen, wenn Sie mit Java anfangen wollen.

## Allgemeines
### SDK mit JRE

Zur Programmierung von Java benötigt man zum Anfang eigentlich wenige Werkzeuge. Minimal benötigt man:
* Ein Java-Software-Development-Kit (Java SDK, früher und jetzt wieder auch JDK genannt) für das verwendete Betriebssystem. Das SDK muss für das Betriebssystem bestimmt sein. Im Gegensatz zu Java-Programmen selbst ist das SDK nicht plattformunabhängig. Sun stellt verschiedene SDKs für gängige Betriebssysteme wie Windows und Linux und die Sun-spezifische Unix-Variante Solaris zur Verfügung, die von Suns Webseite heruntergeladen werden können. Benötigt wird zu Anfang nur die mit JSE 6 bezeichnete aktuelle Version (JSE steht hierbei für Java Standard Edition)! Je nach Arbeitsrichtung können später noch spezielle APIs und/oder eine andere Java Edition hinzukommen. Wird man bei Sun für das eigene Betriebssystem nicht fündig, so ist der Betriebssystem-Hersteller der nächste Ansprechpartner. So bieten z.B. Apple und IBM Java SDKs für die eigenen Betriebssysteme auf ihren Webseiten an. Bitte achten Sie beim Herunterladen darauf, dass Sie wirklich das SDK herunterladen (ca. 50 MB) und nicht das JRE (Java Runtime Environment) - dies ist im SDK enthalten.
* Einen beliebigen Texteditor. Dies kann z.B. unter Windows notepad sein (nicht sonderlich bequem) oder aber ein typischer Programmiereditor wie vi oder emacs aus der Unix-Welt.
Zusätzlich lohnt sich:
* Die Java Dokumentation - sie beinhaltet u. a. die Java API Dokumentation im sogenannten Javadoc-Format. Aber es enthält auch eine vollständige Sprachbeschreibung, die Beschreibung aller Werkzeuge, wie Compiler oder virtuelle Maschine, Tutorien und vieles mehr. Es lohnt sich, die Dokumentation lokal zu installieren. Man kann sie sich z.B. auch von der Sun Webseite herunterladen.
* Ein Webbrowser zum Lesen der Java Dokumentation. Einen Browser besitzen Sie zweifellos, da Sie diesen Text gerade lesen.
Wenn die Entwicklung in Java allerdings komfortabel sein soll, dann gibt es diverse so genannte integrierte Entwicklungsumgebungen (IDEs), die Ihnen die täglichen Routineaufgaben erleichtern bzw. abnehmen. Professionelle IDEs wie das sehr populäre Eclipse sind groß, mächtig und es braucht einige Zeit sie komplett zu beherrschen. Daher wird auf IDEs hier nicht weiter eingegangen. Der Umgang mit einer speziellen IDE wird ggf. Bestandteil eines eigenen Wikibook werden.
Ein Hinweis auf eine speziell für das Erlernen von Java und objektorientierter Konzepte gedachte IDE sei hier dennoch erlaubt: BlueJ wird von diversen Universitäten gepflegt, ist bewusst einfach gehalten und wird gerne im Lehrbetrieb eingesetzt.
In diesem Buch wird jedoch vom einfachsten Fall ausgegangen, dass Sie einen Editor besitzen und das Java-Software-Development-Kit.
Neben dem Begriff SDK findet man auch den Begriff JRE. Das JRE (Java Runtime Environment) ist die Laufzeitumgebung, die dazu dient, Java-Programme auszuführen. Das SDK von Sun enthält bereits eine Version des JRE, so dass man dieses nicht separat herunterladen und installieren muss. Alleine mit dem JRE lassen sich keine Programme entwickeln (es fehlt z.B. der Compiler). Zur Entwicklung braucht man immer das SDK. Zur Ausführung von Java-Programmen reicht das JRE. Die JRE ist ebenso plattformspezifisch wie das SDK.

## Installation des SDK
### Installieren des SDKs unter Windows

Für Windows installieren Sie einfach die selbst-extrahierende Datei. Nach dem Neustart könnten Sie schon anfangen, möchten Sie jedoch z.b. die Programme "javac.exe", "java.exe", "javaw.exe", "jar.exe" etc. von jedem Ordner aus ausführen können ohne immer den vollständigen Pfad angeben zu müssen, müssen Sie die Umgebungsvariable "PATH" verändern.
Wir nehmen mal an, Sie haben JDK an dem Ort "C:\jdk1.6.0_<version>" installiert. Nun müssen Sie die PATH-Variable um den Eintrag "C:\jdk_1.6.0_<version>\bin" erweitern. Die PATH-Variable kann man unter Windows 2000/XP unter Start -> Einstellungen -> Systemsteuerung dann auf System und Erweitert verändern. In diesem Dialog wählen Sie die Schaltfläche Umgebungsvariablen und suchen sich unter Systemvariablen die PATH-Variable aus und fügen den Pfad des SDK an. Der neue Pfad wird von den Alten durch ein Semikolon getrennt. Nach dem Bestätigen können Sie testen, ob die PATH-Variable verändert wurde, in dem Sie in der Eingabeaufforderung PATH eingeben. In der Auflistung sollten Sie nun den Pfad des SDK wiederfinden.
Unter Vista kommen Sie dort hin mit: Windows+Pause -> Erweiterte Systemeinstellungen -> Reiter Erweitert -> Button Umgebungsvariablen... -> Scrollfeld Systemvariablen.
Nach den Änderungen sollten Sie Ihren PC neu starten.

#### Registry Einträge

Bei der Standardinstallation werden in der Windows Registry verschiedene Schlüssel eingetragen. Diese unterscheiden sich in ihrer Position je nach Windows Version:
| Version | Basisschlüssel |
| Windows 95 | HKLM\Software\JavaSoft |
| Windows 98 | HKLM\Software\JavaSoft |
Tipp: Auch wenn die Standardinstallation sich in der Registry einträgt, um somit u.a. die aktuellste Java Version zu finden, sind diese nicht zwingend. Jedoch muss ansonsten die JAVA_HOME Umgebungsvariable korrekt gesetzt sein.
Unterhalb dieser Schlüssel werden im Prefs/ Teil die Benutzereinstellungen des Pakets java.util.prefs gesichert.

### Installieren des SDK unter Linux

Die Schwierigkeit unter Linux ist die Organisation der Dateien, die von Distribution zu Distribution variieren können. Deshalb wird hier nur beispielhaft erklärt, wie für welche Distribution das SDK installiert wird.
Seit einiger Zeit bietet Sun selber ein SDK für Linux an. Man kann auch dieses von Suns Webseite herunterladen. Alternativ hat bereits früher die Blackdown-Gruppe Suns Unix-SDK mit einer Lizenz von Sun nach Linux portiert. Enventuell sind für die saubere Installation des SDK von Sun bzw. Blackdown noch weitere Schritte notwendig um das SDK gut ins Betriebssystem einfügen zu können.
Zudem sind verschiedene (freie) Java-Clones für Linux erhältlich, die aber leider häufig nicht auf dem Stand von Suns SDK sind, so dass sie sich nur unter eingeschränkten Bedingungen zur Java-Entwicklung eignen.

#### SuSE Linux

Sie benötigen, um Java mit SuSE Linux programmieren zu können, die Professional-Ausgabe dieses Betriebssystems. Dies ist notwendig, da nur dort die benötigten Entwicklungstools mit auf den CDs bzw. DVDs enthalten sind. Alternativ können Sie sich die fehlenden Bestandteile aus dem Internet zusammen suchen. Ein guter Anlaufpunkt ist dafür der FTP-Server von SuSE.
Nun die Schritte im Einzelnen:
* Starten Sie Yast. Das geschieht über Kontrollzentrum -> YAST2 Module -> Software -> Software installieren.
* Klicken Sie nun auf die Schaltfläche Systemverwaltungsmodus und geben Sie Ihr Root-Passwort ein.
* Wählen Sie jetzt Paketgruppen aus und Klicken sie auf Entwicklung -> Programmiersprachen -> Java.
* Jetzt müssen die die Pakete Java 2 und Java 2 JRE auswählen.
* Klicken Sie jetzt auf Akzeptieren und die benötigte Software wird auf Ihrem Linux-Rechner installiert.
Die CLASSPATH-Umgebungsvariable müssen Sie für dieses Beispiel nicht extra setzen ;).
Suse liefert in der aktuellen Distribution (z.Zt. Suse 9.3) Java 1.4 mit, was zum Erlernen von Java ausreichen sollte. Falls dies bei Ihnen nicht der Fall sein sollte (z.B. weil Sie spezielle Features von Java 5.0 benötigen oder ausprobieren wollen) müssen Sie folgende Schritte für Ihr System nachvollziehen:
* Installation der JPackage-Pakete von der Suse CD/DVD (suchen nach "JPackage")
* Download von Suns SDK (jdk-1_5_0_04-linux-<architektur>.bin, wobei "architektur" für die jeweilige Architektur steht also z.B. "i586" oder "Amd64".
* Verschieben oder kopieren des heruntergeladenen SDK mit cp jdk-1_5_0_04-linux-<architektur>.bin /usr/src/packages/SOURCES
* Wechseln des Verzeichnisses cd /usr/src/packages
* Bauen der einzelen RPMs mit rpmbuild -bb SPECS/java-1.5.0-sun.spec
* Die fertigen Pakete liegen jetzt in /usr/src/packages/RPMS/<architektur>" - diese können mit rpm -Uhv java* installiert werden.

#### Debian

Das Sun JDK wurde nicht unter GPL gestellt. Daher ist sowohl Suns JDK als auch die Blackdown-Variante nicht in den Free bzw. Non-Free-Zweigen der Debian-Distributionen enthalten. Eine Linux-Binary kann jedoch von www.oracle.com heruntergeladen werden. Dort sind auch alle Installationshinweise zu finden.
Alternativ bietet Debian ein SDK, welches komplett aus freien Komponenten besteht. Während es nicht unbedingt alle Funktionalität des Sun-SDKs bietet, reicht es für viele Anwendungen aus. Die Installation erfolgt mittels
Nach dem Setzen der JAVA_HOME-Umgebungsvariable steht ein SDK mit gewöhnlicher Bedienung zur Verfügung.

#### Red Hat

Bevor man das JDK auf Red Hat Linux installieren kann, muss man sicherstellen das GCJ und seine Komponenten nicht installiert sind oder wenn sie installiert sind, das man sie entfernt.

#### Gentoo Linux

Die einfachste Möglichkeit Java unter Gentoo zu installieren ist, die blackdown-version zu emergen.
Bei diesem ebuild sind alle nötigen Programme enthalten. Jetzt muss man nur noch blackdown als Standard-VM setzen, was am einfachsten mittels java-config geschieht.
Dieser Befehl listet alle verfügbaren VMs auf. Nun wählt man die Blackdown-VM aus.
Nun sollte das Kompilieren mit javac [datei.java] klappen. Aufgerufen werden die Programme mit java [datei], ohne die .class-Endung. Wer die Sun-j2sdk emergen will sollte trotzdem erst Blackdown installieren, da bei dieser z.B. java-config schon enthalten ist, bei der Sun-Version nicht. Man kann ja danach die VM auf Sun-j2sdk setzen.

#### Ubuntu

Die Installation des Java SDK(JDK) unter Ubuntu ist sehr einfach: Das JDK von Sun befindet sich in den offiziellen Quellen (multiverse) ab Version 7.04 (Feisty Fawn). Über den Paketmanager installiert man das Paket sun-java6-jdk oder führt folgenden Befehl im Terminal aus:
Überprüfen kann man die Installation, indem man im Terminal den Befehl
ausführt. Folgende Meldung sollte erscheinen:

### Mac OS X

Java ist integraler Bestandteil des Betriebssystems Mac OS X und muss dort nicht gesondert installiert werden. Es ist herstellerseitig unter /System/Library/Frameworks/JavaVM.framework/Versions installiert. In diesem Verzeichnis befinden sich jeweils Ordner mit den entsprechenden Java-Versionen. Standardmäßig sind folgende Versionen installiert bzw. erhältlich:
| Mac OS X | Vorinstalliert | erhältlich |
| 10.1 | 1.3.1 | 1.3.1 |
| 10.2 | 1.3.1 | 1.4.2 |
| 10.3 | 1.3.1 | 1.4.2 |
| 10.4 | 1.4.2 | 1.5.0 |
| 10.5 | 1.5.0 | 1.6.0 |
Die erhältlichen Java-Versionen können automatisch über Software-Update bezogen und installiert werden. Sind mehrere Java-Versionen installiert, so kann mit Hilfe eines kleinen Programmes eingestellt werden, welche JRE verwendet wird.

### BSD

Unter BSDs gibt es zwei Probleme beim Installieren von Java: zum einen darf man die Installationsdateien aus lizenztechnischen Gründen nicht automatisiert runterladen, zum anderen stellt Sun keine nativen Binärdateien von Java für BSD bereit. Man muss entsprechende Dateien also manuell herunterladen. Falls es sich dabei nicht um inoffizielle BSD-Binarys handelt, muss man zuerst eine JDK-Umgebung mit Linux-Emulator installieren die als Bootstraper fungiert, aus der man danach native Binarys kompilieren kann. Da das aber unnötig lange dauert, wird hier nur der direkte Weg über inoffizielle Pakete beschrieben.

#### FreeBSD

Die einfachste Möglichkeit an ein JDK zu kommen ist der Port java/diablo-jdk15. Dazu lädt man einfach den entsprechenen Tarball von http://www.freebsdfoundation.org/downloads/java.shtml runter, legt ihn in /usr/ports/distfiles ab und gibt dann
oder
ein. Alternativ lädt man sich das Package von der Seite herunter und installiert es mittels
wobei Werte in spitzen Klammern vor der Eingabe ersetzt werden müssen.

#### Pkgsrc

Unter Pkgsrc muss man sich zuvor das JDK (jdk-1_5_0-p3-bin-duh1-bsd-i586.tar.bz2) von http://www.duh.org/NetBSD/java2/ runterladen, in /usr/pkgsrc/distfiles/ ablegen und anschließend den Port lang/scsl-jdk15 mittels
installieren.

## Eine IDE einrichten
### Eclipse

Eclipse ist eine kostenlose IDE, die ursprünglich von IBM ins Leben gerufen wurde und nun als Open-Source-Projekt, unterstützt von einem Konsortium namhafter Firmen wie z.B. Intel, HP, SAP oder SuSE, voran getrieben wird. Das von Haus aus als erweiterbare Plattform für Plug-ins konzipierte Framework erlangt erst durch diese seine Funktionen. Die mittlerweile beliebteste in Java geschriebene IDE ist für die Betriebssysteme Linux, Max OS X sowie MS-Windows als Download von der Hersteller-Website verfügbar und bringt in der Grundausstattung einen sehr komfortablen Java-Editor mit. Mithilfe von entsprechenden Plug-ins kann man unter Eclipse auch noch mit anderen Programmiersprachen (u. a. C/C++, Cobol und PHP) arbeiten. Die Anzahl der Plug-ins steigt sehr rasant an und reicht von kostenlosen Erweiterungen bis hin zu teueren kommerziellen Produkten.
* Zur Installation der Entwicklungsumgebung Eclipse benötigen Sie nur das JRE oder das Java Software Development Kit (Java SDK). Letzteres enthält neben der JRE je nach Version eine mehr oder weniger umfangreiche Sammlung von Werkzeugen zum Entwickeln und Testen von Anwendungen.
* Unter Windows beschränkt sich die Installation auf das Entpacken der *.zip Datei in das gewünschte Verzeichnis. Beim ersten Start durch einen Doppelklick auf eclipse.exe wird die Installation vervollständigt und das Framework ist einsatzbereit.
* Unter Linux ist die Installation ebenfalls einfach: Entweder Sie wählen die bei Ihrer Distribution mitgelieferten Pakete und installieren diese, oder Sie laden die entsprechende Datei für Ihre Rechnerarchitektur herunter, entpacken diese, wechseln in das Verzeichnis, in das Sie Eclipse entpackt haben, und starten dann Eclipse mit ./eclipse.
* Unter Mac OS X wird die Installation analog durchgeführt. Das Archiv wird entpackt. Dadurch wird ein Verzeichnis erstellt, das die ausführbare Datei enthält.

### JBuilder

JBuilder ist eine IDE, die von Borland entwickelt wird. Sie ist nicht als Open Source verfügbar. Für die Foundation Version von JBuilder gibt es eine kostenlose Nutzungslizenz. Für die Professional- bzw. für die Enterprise-Version gibt es eine kostenpflichtige Nutzungslizenz.
* Der JBuilder hat ein entsprechendes SDK bereits mit dabei. Sie sollten sich jedoch trotzdem noch ein aktuelles SDK besorgen, da hier der JBuilder streikt.
* Aufgrund von Änderungen des Aufbaus der class-Dateien sollten Sie auf die JBuilder Version achten:
** JBuilder bis Version 3: native implementiert, daher sehr schnell und auch für langsamere PCs geeignet.
** JBuilder bis Version 5: JDK 1.3 und früher
** JBuilder Version 6 bis Version X: JDK 1.4 und früher
** JBuilder Version 2005, 2006: JDK 5 und früher, Betriebssysteme jedoch nur noch Win XP, Win 2000 oder höher
** Für JDK 6 ist bereits eine neue Version des JBuilders in Entwicklung
* Unter Windows reicht ein Doppelklick auf die Installationsdatei, um den JBuilder in Windows üblicher Manier zu installieren. Es gibt auch die Möglichkeit einer Silent Installation.

### NetBeans

NetBeans ist eine IDE, die ursprünglich von der Firma NetBeans als Open Source entwickelt wurde. NetBeans wurde später von Sun übernommen und blieb als Open Source erhalten. Für NetBeans gibt es eine kostenlose Nutzungslizenz. Die NetBeans-IDE ist für die Betriebssysteme Linux, Mac OS X, MS-Windows sowie Solaris als Download von der Hersteller-Website verfügbar.
Diese wird auch beim Download des SDK mit angeboten, wir empfehlen Ihnen hier jedoch, die beiden Pakete NetBeans und SDK getrennt zu installieren, um diese bei Bedarf einfach deinstallieren zu können.

### Java-Editor

Nur für Windwos
Der Java-Editor ist eine sehr einfache und intuitiv bedienbare IDE für Java und UML. Sie wendet sich an alle User, die nicht erst stundenlang ein Tool installieren und konfigurieren möchten, und hat trotzdem alle Attribute einer ausgewachsenen Softwareentwicklungsumgebung, wie Syntax-Highlighting, Code-Vervollständigung (bei installierter Dokumentation der Pakete) und einen visuellen GUI-Builder. Das Tool erinnert von seiner Benutzung her an Borlands JBuilder oder Delphi (mit dem es auch geschrieben wurde) und lässt sich ähnlich einfach benutzen. Klassen können modelliert und dann wie in BlueJ interaktiv getestet werden. Da das Tool ursprünglich für Schüler der Sekundarstufe II entwickelt wurde, gibt es eine recht ausführliche Dokumentation in deutscher Sprache.
Hier kommen wir direkt zu unserem ersten Programm. Wir werden ein Programm schreiben, das auf der Eingabeaufforderung (oder Konsole, wenn Sie Linux verwenden sowie Terminal unter Mac) eine Textmeldung ausgibt und sich danach einfach wieder beendet.
Die Eingabeaufforderung - auch als DOS-Fenster bekannt - erreichen Sie unter Windows indem Sie Start → Ausführen anwählen und dort cmd eingeben (Windows NT, 2000, XP, 8, 8.1) bzw. command unter Windows 95, 98, ME bzw. Win32 (Windows 3.11). In Windows 8 und 8.1 drücken sie die Start-Taste um das Metro-Menü aufzurufen und geben einfach cmd ein und drücken Return bzw. wählen Sie das Programm cmd aus den Suchergebnissen aus.
Unter Linux können Sie über das Menü die Konsole auswählen oder mit ALT + Funktionstasten zu einer freien Konsole wechseln.
Unter Mac OSX 10.4 (Tiger) gehen Sie in den Ordner Programme und danach auf den Ordner Dienstprogramme, dort finden Sie das Terminal.app. In Mac OSX (10.5-10.10) finden sie das Programm "Terminal.app" im Finder->Programme->Dienstprogramme.

## Hello Java World!

Jetzt starten Sie bitte Ihren Editor oder Ihre IDE. Dort geben Sie das folgende Programm ein. Achten Sie dabei genau auf die Groß- und Kleinschreibung! Alternativ können Sie das Programm auch einfach aus dieser Webseite kopieren und in den Editor einfügen, so sind Sie ein paar Sekunden schneller und müssen sich nicht um die Groß-/Kleinschreibung kümmern.
Machen Sie sich jetzt noch keine Gedanken darüber, was die einzelnen Befehle zu bedeuten haben, die Erklärung folgt ein wenig weiter unten.
Speichern Sie das Programm jetzt in einem Verzeichnis Ihrer Wahl unter dem Namen HelloWorld.java. Beachten Sie bitte genau auch hier die Groß- und Kleinschreibung des Dateinamens und ändern Sie den Namen nicht. Es muss unbedingt der Name sein, den Sie in der Programmzeile public class HelloWorld verwendet haben, ergänzt um die Dateinamensendung .java.
Gehen Sie jetzt in der Eingabeaufforderung in dieses Verzeichnis und übersetzen Sie das Programm mit folgendem Befehl:
Ein möglicher Fehler ist "error: cannot read: HelloWorld.java". Schreiben Sie dann einfach den Pfad davor (C:\Pfad\HelloWorld.java). Ein kurzer Pfad ist empfehlenswert. Wenn die Übersetzung fehlerfrei durchgelaufen ist, können Sie das Programm mit der folgenden Eingabe ausführen:
Fallen Ihnen zwei kleine, aber wichtige Unterschiede bei den beiden Befehlen auf? Richtig:
* Im ersten Fall (zum Compilieren) wird das Programm javac (mit einem 'c' am Ende) verwendet. Im zweiten Fall (zum Ausführen) aber das Programm java (ohne 'c' am Ende).
* Beim Compilieren mit javac mussten Sie die Dateinamensendung .java mitangeben. Bei der Programmausführung mit java dürfen Sie diese Endung nicht mitangeben.
Falls eine Fehlermeldung wie
auftritt, müssen Sie nachschauen, ob der aktuelle Pfad auch im CLASSPATH enthalten ist. Wie das gemacht wird, ist weiter oben beschrieben. Ebenso sollten Sie genau prüfen, ob Sie der Java-Datei wie oben beschrieben den richtigen Namen gegeben haben, und ob Sie versehentlich die Endung des Dateinamens beim Aufruf von java angegeben haben.
Wenn das Programm fehlerfrei durchgelaufen ist, dann müsste auf der Konsole der folgende Text erscheinen:

## Hello Java!

An dieser Stelle haben Sie bereits Ihr erstes Java-Programm geschrieben und wollen nun wissen, was denn nun diese einzelnen Befehle und kryptischen Zeichen bedeuten. Wir gehen hier davon aus, dass Sie sich bereits mit der Objektorientierung beschäftigt haben und somit wissen was Klassen, Objekte (Instanzen), Methoden (Operationen) und Eigenschaften (Attribute) sind. Falls Sie dies noch nicht wissen sollten, folgen Sie doch einfach dem oberen Link, wo Sie sicher fündig werden.
Hier ist nochmals das Listing unseres Hello-World-Programms:
Wir haben die Zeilen durchnummeriert, um so die Bestandteile des Programms besser erklären zu können.
In der ersten Zeile definieren wir die Klasse "HelloWorld". Dabei ist zu beachten, dass die Klasse wie der Dateiname heißen muss, also in unserem Beispiel muss die Datei "HelloWorld.java" heißen. Jeder kann auf unsere Klasse zugreifen, deshalb ist sie auch "public". Man kann die Rechte von Klassen auch einschränken, aber dazu kommen wir später.
In Zeile zwei wird die Main-Methode definiert. Diese finden Sie bei jeder Java-Anwendung (Applikationen), nicht jedoch bei Applets, Servlets oder Midlets. Diese ist sozusagen das Herz jeder Java-Anwendung. Von dieser Methode ausgehend können Sie sich die komplette Funktionsweise eines Programms erschließen.
In der Zeile 3 geben wir unsere Meldung, bei uns "Hello Java World", aus, was nicht allzu viel zu sagen hat, aber der Zweck unseres Programms ist. Nebenbei bemerkt ist es sozusagen die "höhere Weihe" eines Programmierers in der Programmiersprache seiner Wahl ein "Hello World" auszugeben. Sie finden in fast jedem Tutorial zu irgendeiner Programmiersprache ein solches "Hello-World"-Programm.
Die vierte Zeile heißt, dass wir die Anwendung beenden wollen und zwar mit einem Rückgabewert von 0. Dies beendet auch gleichzeitig die Java Virtual Machine (JVM), sodass wir wieder auf der Eingabeaufforderung landen. Auch hierbei gilt, dass nur Java-Anwendungen mit diesem Befehl beendet werden. In der Eingabeaufforderung kann man diesen Wert auch auswerten, so dass man z.B. ein Java-Programm schreiben kann, das durch verschiedene Rückgabewerte den Ablauf eines Batch-Programmes oder Shellskripts steuern kann.

## Pakete

Java-Klassen und auch Schnittstellen (Interface) können und werden in so genannte Pakete (Packages) gruppiert. Ein Paket ist dabei einfach eine Sammlung von Klassen. Pakete werden in den geläufigen Betriebssystemen in Form von Verzeichnissen abgebildet. Klassen und Schnittstellen, welche in einem Paket liegen, beginnen dabei mit der package Anweisung, gefolgt von den Paketnamen und dem Semikolon. Zum Beispiel:
Üblicherweise gruppiert man thematisch verwandte Klassen in einem Paket.
Oft ist der Domainname des Autors Teil des Paketnamens, so dass ein Programmierer schnell die Herkunft des Pakets ermitteln und auf der zugehörigen Webseite weitere Informationen zu dem Paket finden kann. Hierbei wird zudem eine Eindeutigkeit der Pakete und somit der Java Klassen / Schnittstellen erreicht. Beispiel: org.apache.log4j → www.apache.org

## Klassenbibliothek

Java enthält eine sehr umfangreiche Klassenbibliothek. Es ist dringend zu empfehlen, bei der Installation des SDK auch die zugehörige Klassenbibliotheksdokumentation (API Documentation) herunterzuladen und lokal zu installieren, bzw. in die IDE zu integrieren.
Die beim SDK Standard Edition mitgelieferte Klassenbibliothek ist in Pakete (packages) eingeteilt. Es lohnt sich, sich im Laufe der Zeit zumindest einen Überblick über die vorhandenen Pakete und deren grundsätzliche Bedeutung zu verschaffen. Einige Pakete werden bei jeder Art von Java-Programmierung so häufig gebraucht, dass deren Inhalt früher oder später in Fleisch und Blut übergehen sollte.
Dabei ist es ist nicht unbedingt notwendig, jeden einzelnen Methodenparameter auswendig zu lernen (Ausnahme: Einige gerade im US-amerikanischen Raum beliebte Programmierer-Zertifizierungen fragen solches "Wissen" in ihren Zertifizierungstests ab). Methodenparameter kann man immer schnell in der API-Dokumentation nachschlagen, oder sie werden von modernen IDEs sogar direkt angezeigt. Eine grundsätzliche Vorstellung davon, was wo und wofür in der Klassenbibliothek zu finden ist, sollte man allerdings schon haben, um zügig arbeiten zu können und halbwegs effiziente Programme zu schreiben.
Zu Anfang lohnt es sich, einen Blick auf die Dokumentation der Klassen in den folgenden Paketen zu werfen:
| Paket | Inhalte |
| java.lang | Basis-Klassen wie Object. Das Rückgrat der Sprache (lang = Language = Sprache) |
| java.io | Einfache Ein- und Ausgabeklassen für Text- und Binärdaten, Dateizugriffe und Kodierung und Enkodierung von Daten. |
| java.util | Sehr nützliche Hilfsklassen. Insbesondere finden sich hier die sog. Collection classes. Dies ist eine Sammlung von Klassen, die gängige Datenstrukturen zur Verknüpfung von Objekten bereitstellen. Dank dieser Klassen ist es für einen Java-Programmierer in den allermeisten Fällen unnötig z.B. selber Listen, Mengen oder eine Hashtable zu implementieren. |
| Je nachdem, welche Art von Programmen man entwickeln möchte, sollte ein Blick in folgende Pakete folgen: ||
| java.net | Basisklassen für Netzwerkkommunikation. |
| java.awt javax.swing | Klassen zur Programmierung grafischer Benutzeroberflächen |
Java ist eine einfach aufgebaute, leicht zu erlernende und robuste rein objektorientierte Programmiersprache. Seit der Verbreitung der javafähigen Webbrowser Mitte der 1990er Jahre ist sie neben C++ zu einer der wichtigsten imperativen Programmiersprachen aufgestiegen und hat inzwischen nicht nur auf dem Desktop (J2SE), sondern auch auf mobilen Endgeräten (J2ME) und Unternehmensanwendungen (J2EE) einen festen Platz gefunden.
Bei Programmiersprachen wie C oder C++ wird beim Kompilieren Maschinencode erzeugt. Dieser kann dann direkt auf dem Computer ausgeführt werden.
Im Gegensatz dazu verfolgte SUN bei der Einführung der Programmiersprache das Konzept "Write once, run everywhere!". Das heißt, man wollte eine Programmiersprache entwickeln, mit der man einmal ein Programm schreibt, welches dann auf fast allen Betriebssystemen läuft. Dazu führte man das Konzept der Java Virtual Machine (JVM) ein. Die Java Virtual Machine ist eine Abstraktionsschicht zwischen dem Javaprogramm und dem eigentlichen Betriebssystem. Bei der Kompilierung mit javac wird kein nativer Maschinencode erzeugt, sondern ein Bytecode, der dann von der JVM intepretiert werden kann. Deshalb können kompilierte Javaprogramme auch nicht direkt aufgerufen werden, sondern müssen immer über die virtuelle Maschine in Form von "java test" oder "java -jar test.jar" aufgerufen werden. Man kann sich die virtuelle Maschine als Blackbox um das Java Programm vorstellen, die die Interaktion mit dem Betriebssystem übernimmt.
Java Quelltext -- javac → Java Bytecode -- java → Betriebssystem
In Java werden standardmäßig verschiedene Anwendungsarten unterschieden.

## Applets

Sind mehr oder weniger komplexe Anwendungen, die speziell für das Laufen in einem Webbrowser entwickelt werden. Sie benötigen zur Ausführung eine HTML-Datei mit einem Applet-Tag in dem sie ähnlich wie ein Bild in einer HTML-Seite eingebettet werden. Außerdem haben nichtsignierte Applets nur sehr beschränkte Zugriffsrechte auf den Host-Rechner. Damit unterliegen Sie besonderen Bedingungen. Java Standard: Applets Durch die Entwicklung bei JavaScript und HTML5 sind Applets aus der Mode gekommen und werden in diesem Buch nicht länger behandelt.

## Applikationen

Applikationen sind die "normalen" Anwendungen auf Ihrem Computer und haben volle Zugriffsmöglichkeiten auf alle Bestandteile des Rechners. Sie werden mit Hilfe des javac Compilers übersetzt und mit Hilfe des Java-Interpreters java bzw. javaw ausgeführt. Es gibt hierbei noch einige Besonderheiten in Zusammenhang mit Java Webstart.

## Servlets

Servlets sind die Java-Variante der sog. CGI-Skripten und gehören in die Server--Welt. Hierbei wird Java-Code auf dem Server ausgeführt, der dort z.B. Dateien entgegennimmt oder in Datenbanken schreibt.
Diese Anwendungsart gehört zur Java Enterprise-Version (J2EE).

## Midlets

Midlets sind die kleinen Anwendungen, welche typischerweise auf Handys etc. laufen. Diese werden mit Hilfe der Java Micro-Version (J2ME) entwickelt.

# Grundlagen
## Worum geht es?

Variablen sind Speicherorte für Daten wie Zahlen, Texte oder Adressen. Java ist eine statisch typisierte Programmiersprache. Das bedeutet, dass zu dem Zeitpunkt, wo das Java-Programm erstellt wird bekannt sein muss, welchen Typ eine Variable hat. Typen können so genannte primitive Datentypen sein oder beliebig komplexe Klassen.

## Was sind Primitive Datentypen?

Primitive Datentypen sind eine Gruppe von Typen, mit denen man Variablen erstellen kann, die Zahlen, einzelne Zeichen oder logische Werte aufnehmen. Für jeden primitiven Datentyp gibt es zudem eine eigene, so genannte Wrapperklasse, die diesen Datentyp aufnimmt. Nachdem wir die einzelnen primitiven Datentypen besprochen haben, besprechen wir die zugehörigen Wrapperklassen und zeigen Vor- und Nachteile auf.
Die primitiven Datentypen, ihr typischer Wertebereich und die zugehörige Wrapperklasse haben wir in der folgenden Tabelle für Sie aufgeführt.
| Typname | Größe | Wrapper-Klasse | Wertebereich | Beschreibung |
| boolean | undefiniert | java.lang.Boolean | true / false | Boolescher Wahrheitswert, Boolescher Typ |
| char | 16 bit | java.lang.Character | 0 ... 65.535 (z. B. 'A') | Unicode-Zeichen (UTF-16) |
| byte | 8 bit | java.lang.Byte | -128 ... 127 | Zweierkomplement-Wert |
| short | 16 bit | java.lang.Short | -32.768 ... 32.767 | Zweierkomplement-Wert |
| int | 32 bit | java.lang.Integer | -2.147.483.648 ... 2.147.483.647 | Zweierkomplement-Wert |
| long | 64 bit | java.lang.Long | -2$^{63}$ bis 2$^{63}$-1, ab Java 8 auch 0 bis 2$^{64}$ -1 | Zweierkomplement-Wert |
| float | 32 bit | java.lang.Float | +/-1,4E-45 ... +/-3,4E+38 | 32-bit IEEE 754, es wird empfohlen, diesen Wert nicht für Programme zu verwenden, die sehr genau rechnen müssen. |
| double | 64 bit | java.lang.Double | +/-4,9E-324 ... +/-1,7E+308 | 64-bit IEEE 754, doppelte Genauigkeit |
* ↑ Mindestgröße, soweit bekannt
* ↑ https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html
* ↑ Wir gebrauchen zur zeit in diesem Buch die Begriffe "Boolescher Typ" und "Wahrheitswert" synonym, wünschen uns aber eine Vereinheitlichung in Richtung "Boolescher Typ" oder "Boolesche Variable, wenn Variablen dieses Typs gemeint sind.
* ↑ https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html
Wir zeigen ihnen nun den Umgang mit den einzelnen Typen jeweils an einem Beispiel.

## Zeichen

Der Datentyp char kann jedes beliebige Unicode-Zeichen aufnehmen, insbesondere europäische und asiatische Zeichen sind damit abgedeckt. Hierfür benötigt er 2 Bytes an Speicherplatz pro Zeichen. Zeichen werden in Hochkommata eingeschlossen.
Es spielt für Java keine Rolle, ob Sie eine char-Variablen ein Zeichen oder eine Zahl zuweisen. Ferner können Sie mit Zeichen auch rechnen:
Dieses Programm erzeugt die Ausgabe "B A". Addiert man zu einem Zeichen eine 1, dann ist damit das nächste Zeichen gemeint. Ebenso können Sie Zeichen auch numerisch eingeben, wie buchstabe2 = 65 zeigt. 65 ist der Zahlenwert für das Zeichen 'A'.

## Ganze Zahlen
### byte

Ein byte ist der kleinste numerische Datentyp in Java, er ist 8 bit lang. Dieser Datentyp tritt zumeist im Zusammenhang mit Feldern auf, auf die wir in einem späteren Kapitel zu sprechen kommen.
Obenstehendes Beispiel zeigt, wie man Variablen vom Typ byte deklariert und initialisiert.

### short

Der Datentyp short ist 2 Bytes groß und vorzeichenbehaftet. Oft werden Konstanten mit diesem Datentyp angelegt, tatsächlich aber wird short nur selten wirklich gebraucht.

### int

Der Datentyp int ist wohl der am häufigsten eingesetzte primitive Typ. Er belegt 4 Bytes, was in der Regel für viele Anwendungsbereiche ausreicht.

### long

der Datentyp long ist die erweiterte Form des int-Typs. Im Gegensatz zum int hat dieser Datentyp 8 Bytes. Wenn man bei der Darstellung von Zahlenliteralen Wert darauf legen möchte, dass sie zum Datentyp long gehören, dann fügt man den Suffix "L" oder "l" (kleines L) an. Das muss man aber nicht, der Compiler wandelt Literale entsprechen um.
Ein Beispiel:
Die Ausgabe ist 10 + 20 = 30.

## Gleitkommatypen

Mit den Datentypen float und double können Sie eine Teilmenge der rationalen Zahlen darstellen. Sprachlich sind Gleitkomma- und Fließkommazahlen gebräuchlich. Beide Typen unterscheiden sich durch ihre Genauigkeit und den Speicherverbrauch. Gemeinsam ist, dass solche Zahlen nur ungefähr richtig gespeichert werden.

### float

Eine Variable vom Typ float speichert eine Gleitkommazahl mit einer Größe von 4 Byte. Die Genauigkeit liegt bei 7 signifikanten Stellen, man spricht hier von einfacher Genauigkeit (engl: single precision). Zahlenliteralen stellt man ein "f" oder "F" nach, sonst nimmt der Java-Compiler an, es handele sich um double-Literale.
Ein Beispiel:
Ausgabe:
1.0/3.0 = 0.33333334 0.33333334*3.0 = 1.0 ( 1.0)
Dieses Beispiel zeigt gleichzeitig ein Problem mit Gleitkommazahlen, da hier (1/3) in der ersten Zeile falsch dargestellt wird, die Gesamtrechnung ist aber offenbar richtig.
Verwenden Sie den Datentyp float nur, wenn es ihnen nicht auf Präzision ankommt.

### double

Der Typ double bietet Gleitkommavariablen mit einer Größe von 8 Byte. Die Genauigkeit liegt bei 15 signifikanten Stellen, dies bezeichnet man als doppelte Genauigkeit (engl. double precision).
Ausgabe:
1.0/3.0 = 0.3333333333333333 0.3333333333333333*3.0 = 1.0 ( 1.0)

## Boolescher Typ

Eine boolesche Variable boolean kann einen von zwei Zuständen annehmen: true oder false. Dies repräsentiert in Ausdrücken zumeist eine Bedingung ist erfüllt – oder eben nicht.
Boolsche Variablen werden zumeist im Zusammenhang mit Verzweigungen gebraucht, auf die wir im Kapitel über Kontrollstrukturen zu sprechen kommen.

## Casting in Java

Casting nennt man die Überführung eines Datentypen in einen Anderen. Es gibt implizites und explizites Casting. Ist die Wertemenge eines numerische Datentyps Teilmenge eines anderen Datentyps, dann lässt sich der erste Datentyp in den Zweiten überführen. Hierfür braucht man nichts weiter zu tun, man spricht vom impliziten Casting. Ist aber der Wertebereich eines Datentyps eine echte Obermenge eines anderen, dann kann es zu Datenverlusten führen, den ersten Datentyp in den Zweiten zu überführen. Beispielsweise kann man byte nach int überführen, umgekehrt aber nur explizit, das heißt, man schreibt explizit hin, dass man diese Umwandlung wünscht und akzeptiert, dass es zu Datenverlust kommen kann.
Häufig benötigt ein Programmierer mehrere zusammengehörige Variablen desselben Datentyps, die logisch oder verwaltungstechnisch zusammengehören. Es wäre aber sehr aufwendig, diese Variablen alle einzeln zu deklarieren und zu verarbeiten. Deswegen wird in Java, wie in anderen Programmiersprachen auch, die Verwendung von Arrays (deutsch etwa: Felder) unterstützt. In Arrays lassen sich alle primitiven Datentypen und alle Objekte speichern und systematisch bearbeiten. Alle Variablen haben einen gemeinsamen Namen, werden aber über unterschiedliche Indexe angesprochen.

## Syntax

Ein Array wird sehr ähnlich wie eine normale Variable deklariert: erst wird der Datentyp genannt, dann der Bezeichner für diese Variable. Bitte beachten Sie aber den Unterschied, dass hinter dem Datentyp eckige Klammern als Zeichen gesetzt werden. Sie zeigen an, dass wir es hier mit einem Array dieses Typs zu tun haben:
Im Gegensatz zu anderen Variablendeklarationen muss der Platz für das Array aber noch reserviert werden; die Deklaration sagt dem Compiler nur, unter welchem Namen das Feld angesprochen werden soll. (Für Leser mit Vorwissen aus anderen Programmiersprachen: Dies ist lediglich ein Zeiger. Solange dem Bezeichner kein Array zugewiesen wurde ist der Bezeichner mit null initialisiert.) Um den Platz für das Array zu reservieren und es damit funktionsfähig zu machen muss dieser Platz mit dem Schlüsselwort new ausdrücklich angefordert werden. Dafür gibt es mehrere Möglichkeiten. Die Einfachste nennt die Anzahl der Elemente, die in dem Feld gespeichert werden soll:
Jetzt verweist der Bezeichner array auf ein Feld von zehn Variablen des Typs int. Diese einzelnen Variablen sprechen wir an, indem wir den Namen des Feldes und den Index der gewünschten Variablen angeben. Im folgenden Beispiel setzen wir den Wert des 5. Wertes im Feld auf 3:
Bitte beachten Sie dabei, dass die Zählung bei 0 beginnt. Wenn Sie den 5. Wert setzen wollen muss der Index also 4, der gewünschte Platz minus 1, sein.
Sie können einem Array auch bei der Definition Werte zuweisen:
Auch dieses Array ist zehn Felder lang, die aber bei der Deklaration sofort initialisiert werden. Übrigens werden durch den Java-Compiler alle numerischen Variablen eines Arrays bei der Initialisierung automatisch auf 0 gesetzt; bei Objekten wird initial der Wert null zugewiesen. Eine manuelle Initialisierung auf diese Werte ist also überflüssig.
Bitte beachten Sie, dass Arrays bei der Definition eine konkrete Anzahl von Elementen zugewiesen wird, in unseren Beispielen zehn Werte. Diese Anzahl bleibt unveränderlich; es können weder zusätzliche Werte aufgenommen noch überflüssige Werte freigegeben werden. Java überprüft bei jedem Zugriff auf ein Array, ob der gewünschte Zugriff gültig ist. Falls der Index kleiner 0 oder größer als die Länge des Feldes ist wird eine Fehlermeldung generiert, die den Programmablauf normalerweise abbricht. Es ist also sinnvoll, den Zugriff auf Elemente des Arrays nur mit eigenen Methoden zu erlauben, die einen solchen Zugriff überwachen. Das könnte im einfachsten Fall folgendermaßen aussehen:
Diese - sehr einfache - Fehlerbehandlung sorgt dafür, dass das Programm nur gültige Indexe verarbeitet. Wenn das Array also wie hier mit dem Schlüsselwort private für andere Klassen verborgen wird, dann kann der Zugriff nur mit den von außen sichtbaren Methoden setValue und getValue erfolgen, die die Gültigkeit des Zugriffs sicherstellen. Das Programm läuft stabiler.
Zusätzlich wird in den gezeigten Methoden auf eine Eigenschaft zugegriffen, die wir noch ansprechen müssen: Die Länge des Arrays. Sie wird für jedes Array in der Variablen length gespeichert, die das Programm jederzeit abfragen kann, indem der Bezeichner des Arrays durch einen Punkt und den Variablennamen length ergänzt wird. Hier geschieht es in den Abfragen zum Gültigkeitsbereich: Der an die Methode übergebene Index muss kleiner sein als der Wert in value.length. Dadurch können weitere Fehler beim Programmieren ausgeschlossen werden. Falls nämlich das Feld value im Zuge weiterer Programmierungen in der Größe geändert werden muss, kann der Programmierer einfach die Deklaration im Kopf der Klasse ändern - und fertig. Alle Abfragen passen sich automatisch an, denn der Compiler ändert während der Übersetzung des Programmcodes diese Variable in den aktuellen Wert. Außerdem wird der Quellcode der Klasse leichter lesbar, denn durch die Verwendung des Namens statt einer Zahl wird deutlicher, was diese konkrete Programmierung bewirken soll.

## Standardlösungen: Die Klasse java.util.Arrays

Für viele Bearbeitungen, die auf Arrays angewendet werden können, gibt es in Java bereits Lösungen. Einige von ihnen sind in der Klasse Arrays verwirklicht, die im Package java.util untergebracht ist. Zu diesen Standardaufgaben gehören unter Anderem die Initialisierung, die Sortierung und die Suche von Werten in Arrays. Um diese Methoden zu nutzen genügt der einfache Aufruf mit dem vorgesetzten Klassenpfad, denn die Methoden sind alle statisch. Zwei Beispiele für solche Aufrufe, "fill" und "sort", finden Sie in folgendem Code, den Sie in Ihre Programmier-Umgebung kopieren und dort ausführen lassen können; er ist in dieser Form vollständig lauffähig.
In diesem Beispiel werden zwei verschiedene Methoden der Klasse Arrays aufgerufen. Die Erste ist fill, mit der das Array mit einem vorgegebenen Wert, hier -1, initialisiert wird. In einem zweiten Aufruf wird nur ein Teil des Arrays befüllt, indem zusätzliche Parameter für den gewünschten Bereich angegeben werden. Die Parameter geben die Untergrenze (hier 3) und die Obergrenze (hier: 6) des Index an, die für den Aufruf gelten. Dabei wird die Untergrenze eingeschlossen, die Obergrenze aber ausgeschlossen. Der Aufruf füllt in diesem Fall also die Felder array[3], array[4] und array[5] mit dem Wert -2, belässt aber den Wert array[6] wie er ist. Dieses Verhalten gilt für alle Methoden der Klasse Arrays, die Teilbearbeitungen ermöglichen.
Wichtig ist ebenfalls, dass die geänderten Felder den Platz 4, 5 und 6 im Array besetzen, denn die Java-interne Zählung der Felder beginnt bei 0 statt bei 1. In der Funktion print ist das an der Ausgabeschleife gut zu verfolgen, denn die Schleife beginnt bei 0 und läuft nur bis zur Länge des Feldes -1, in unserem Beispiel also bis 9.
Die Übersicht über die Klasse Arrays und ihrer Funktionen finden Sie hier. Es lohnt sich, die dort genannten Lösungen für Standardaufgaben zu kennen. Sie beschleunigen die eigene Arbeit und sind zudem bereits auf korrekte Funktion geprüft.

## Mehrdimensionale Arrays

In vielen Programmiersprachen sind auch Arrays von Arrays möglich; so auch in Java. Die Deklaration dieser Arrays erfolgt durch entsprechend häufiges Setzen der eckigen Klammern:
Mit diesen Aufrufen wird für array2 ein zweidimensionales Array aus double-Werten definiert, für array3 sogar ein dreidimensionales Array (also ein Array aus Arrays aus Arrays). Diese Vervielfachung lässt sich beliebig tief stapeln.
Bei der Speicherreservierung gehen wir wieder vor wie bereits oben beschrieben und reservieren den Speicherplatz mit new. Im Folgenden gehen wir nur auf das zweidimensionale Beispiel ein; alle weiteren Ebenen werden in der gleichen Form behandelt.
Wie bei einem eindimensionalen Array muss auch ein mehrdimensionales Array seinen Speicherplatz mit dem Schlüsselwort new zugewiesen bekommen. Das kann geschehen, indem in beiden Klammern die gewünschte Zahl an Elementen angegeben wird:
Diese Form des Aufrufs ergibt eine Tabelle mit fünf Zeilen und vier Spalten. Es kann aber sinnvoll sein, die Anzahl der Spalten fortzulassen und erst später eine entsprechende Zuweisung vorzunehmen. Das sieht dann wie folgt aus:
Diese Definition reserviert den Platz für fünf später zuzuweisende Arrays von double-Werten, deren Größe aber noch nicht genannt wird. Einem solchen Array lässt sich ein anderes Array folgendermaßen zuweisen:
Damit hat das Array array2 den Zeiger auf das Array test gespeichert. Es entsteht keine Kopie des Arrays test; vielmehr können wir auf die Werte des Arrays nun unter zwei verschiedenen Namen zugreifen. Wenn wir also den Wert test [2] von 3.0 auf 4.0 ändern und danach den Wert array2 [4][2] abfragen bekommen wir als Ergebnis 4.0 zurück.
Dieses Vorgehen ermöglicht auch die Speicherung verschieden langer Arrays in einem multidimensionalen Array. Wenn wir ein Array test2 definieren, das aus lediglich zwei Werten besteht, dann können wir es trotzdem im übergeordneten Array array2 speichern.
Werden Arrays auf diese Weise zugewiesen muss der Programmierer aber vor Abfragen immer sicherstellen, dass das untergeordnete Array, auf das zugegriffen werden soll, tatsächlich existiert, weil sonst ein Zugriff auf ein Feld versucht wird, das mit null initiiert ist. Das löst eine Fehlermeldung aus, die zum Programmabbruch führt. Zusätzlich sollte der Programmierer Zugriffe vermeiden, die auf Werte hinter dem Ende des Unter-Arrays liegen, weil auch das zu einem Programmabbruch führt. Die Länge eines Unter-Arrays kann wieder über die Variable length abgefragt werden:

## Anonyme Arrays

In seltenen Fällen werden Arrays nur für die Initialisierung irgendwelcher Daten oder für den Aufruf von Methoden benötigt. In solchen Fällen kann man sich die Vergabe eines Bezeichners sparen. Das sollten Sie aber immer wohlüberlegt machen, weil dadurch Übersichtlichkeit im Quellcode verloren geht.

## Flexible Arrays

Eine wichtige Beschränkung bei der Arbeit mit Arrays ist die festgelegte Länge. In der Praxis werden aber häufig Listen und Felder benötigt, deren Größe zunächst unbekannt ist oder sich im Laufe der Arbeit ändern kann. Arrays sind in solchen Fällen keine gute Lösung. Java bietet dafür aber eine Reihe maßgeschneiderter Lösungen an, die im Java Collection Framework zusammengefasst sind. Die Arbeit mit diesen Klassen ist aber etwas komplizierter als die Arbeit mit Arrays. Wir werden auf sie im Abschnitt über fortgeschrittene Programmierung zurückkommen. An dieser Stelle sei nur darauf hingewiesen, dass es diese Problemlösungen bereits gibt; Sie müssen keine zusätzliche Zeit für die Lösung dieser Aufgaben einplanen.

## Exceptions bei der Arbeit mit Arrays

Die Arbeit mit Exceptions wird zwar erst später in diesem Buch besprochen, doch damit das Thema Arrays geschlossen behandelt werden kann ergänzen wir hier noch die üblichen Fehlermeldungen, die beim Arbeiten mit Arrays ausgelöst werden. Sofern Sie eigene Methoden definieren, die auf Fehler bei der Eingabe so reagieren sollen wie die Klassen der Java-Bibliotheken - was empfehlenswert ist - und sie den auftretenden Fehler nicht in der aufgerufenen Methode abfangen und behandeln können oder wollen, sollten Sie diese Exceptions benutzen.
Es handelt sich um folgende Exceptions:
* ArrayIndexOutOfBoundsException - Wird ausgelöst, falls bei einem Index ein Wert kleiner 0 oder größer als die vorgegebene Länge des Feldes angegeben wurde.
* ArrayStoreException - Es wurde versucht, dem Array einen falschen Typ hinzu zu fügen, zum Beispiel ein Integer-Wert einem String-Array.
* NegativeArraySizeException - Wird ausgelöst, wenn das Programm versucht, ein Array mit weniger als 0 Werten zu erzeugen.
Zusätzlich sind folgende allgemeine Exceptions üblich:
* NullPointerException - Wird an die aufgerufene Methode als Parameter statt der erwarteten Referenz auf ein Array nur null übergeben wird diese Exception ausgelöst.
* IllegalArgumentException - Falls bei einem Methoden-Aufruf mit zwei Parametern, die einen Teilbereich des Arrays definieren, der Index, der die Untergrenze darstellt, größer ist als der Index der Obergrenze.

## Bezeichner

Bezeichner (engl.: Identifier) bezeichnen in Java Klassen, Interfaces, Variablen (bzw. Objekte), Methoden und Konstanten. Bezeichner sind also, einfach gesprochen, die Namen der zuvor genannten Elemente.
Mit Hilfe von Bezeichnern kann man die diesen Namen zugeordneten Speicherbereiche ansprechen und nutzen.

### Gültige Namen

Legale Identifier können in Java aus folgenden Zeichen bestehen:
* Buchstaben
* Ziffern
* Währungssymbole
* Unterstrich
Gültige Identifier:
* starten mit einem Buchstaben, Währungssymbol oder Unterstrich
* starten nicht mit einer Ziffer
* können nach dem ersten Zeichen alle Kombinationen von Buchstaben, Ziffern, Währungssymbolen enthalten
* theoretisch ist die Anzahl der Zeichen pro Identifier unbegrenzt
* sind keine Java-Schlüsselwörter wie new
* Identifier sind case-sensitive, sprich Java unterscheidet zwischen Groß- und Kleinschreibung.
Gültige Bezeichner können mit folgendem Code getestet werden
Beispiel:
Quelle: https://openbook.rheinwerk-verlag.de/javainsel/02_001.html#u2.1.3

### Konventionen

Ähnlich wie in der "realen Welt" sollte man sich bei der Programmierung ebenfalls um einen guten Ton bemühen.
esisteinunterschiedobichalleskleinundzusammenschreibe ODER
_leserlich_formatiere_sodass_mein_Code_besser_nachvollzogen_werden_kann
Grundlegende Regel hierbei ist die Verständlichkeit und leichte Nachvollziehbarkeit des verfassten Codes (und die Kommentare nicht vergessen). Aus diesem Grund wurden die Java-Code-Konventionen geschaffen:

#### Klassen und Interfaces

* Erster Buchstabe immer groß
* "UpperCamelCase" anwenden. Wenn mehrere Worte in einem Identifier verbunden werden, sollten die Anfangsbuchstaben groß geschrieben werden.
* Für Klassen Nomen verwenden (Hund, Katze...)
* Für Interfaces Adjektive verwenden (Essbar...)

#### Methoden

* erster Buchstabe immer klein.
* "lowerCamelCase" anwenden.
* Methodennamen sollten Kombinationen aus Verben und Nomen darstellen. So kann am besten beschrieben werden, wozu die Methode dient. Gute Beispiele findet man natürlich in der Java API.
* Bsp.: getTasche, fuelleTasche( ... )

#### Variablen

* wie bei Methoden "lowerCamelCase" und erster Buchstabe immer klein.

#### Konstanten

* Konstanten werden erzeugt, indem man Variablen static und final deklariert.
* Sie werden nur in Großbuchstaben geschrieben und einzelne Worte werden durch Unterstrich voneinander getrennt.
* Bsp.: MAX_MENGE

## Variable
### Deklaration

Variablen in Java sind immer lokale Variablen. Bevor man eine Variable benutzen kann, muss sie erst deklariert werden. Dies kann an beliebiger Stelle innerhalb einer Methode, in der statischen Initialisierung einer Klasse oder im Initialisierungsteil einer for-Schleife geschehen. Nur in diesem Bereich ist die Variable sichtbar. Der Name der Variablen muss innerhalb dieses Sichtbarkeitsbereichs eindeutig sein.
Da Java eine streng typisierte Sprache ist, muss bei Deklaration einer Variablen immer ein Datentyp mit angegeben werden. Dies kann ein primitiver Datentyp sein (boolean, char, byte, short, int, long, float, double) oder ein Referenztyp (eine Klasse oder Interface).
Optional kann eine Variable bei Deklaration durch einen Ausdruck zur Laufzeit mit einem Wert initialisiert werden.
Mit dem ebenfalls optionalen Schlüsselwort final wird verhindert, dass der Wert einer Variablen nach dessen Deklaration geändert werden kann; lediglich eine erstmalige Zuweisung im Konstruktor einer Klasse für Instanzvariablen ist möglich.
Die Syntax einer Variablendeklaration:
zum Beispiel:

### Sichtbarkeits- und Zugriffsmodifizierer

Die drei Schlüsselwörter private, protected und public dienen der Modifikation der Sichtbarkeit und des Zugriffs.
* private erlaubt nur der eigenen Klasse den Zugriff.
* protected erlaubt der eigenen Klasse, der Paketklasse und der Elternklasse den Zugriff.
* public erlaubt jeder Klasse, auch fremden Klassen, den Zugriff.
Ist eine Methode als private static final gekennzeichnet, ist der Zugriff am schnellsten.
Um Fehlern vorzubeugen, sollte der Zugriff so stark wie möglich eingeschränkt werden.

### Initialisierung

Vor der Verwendung der Variablen muss ihnen ein Wert zugewiesen werden, der dem Datentyp entspricht. So kann man einem Integerwert(int) nicht den String "Hallo" zuweisen (zumindest nicht ohne vorherige Umwandlung)
oder:

## Welche Operatoren gibt es in Java?

Java kennt eine Vielzahl von arithmetischen, logischen, und relationalen Operatoren, sowie einen, der außerhalb von Java keine Rolle spielt. Operatoren werden nach der Anzahl der möglichen Operanden unterteilt (unärer-, binärer- und ternärer Operator) und selbstverständlich nach der Funktion, die sie berechnen. Dieses Kapitel beschreibt die verfügbaren Operatoren in Tabellenform. Bis auf wenige Ausnahmen sollten alle Operatoren und das, was sie leisten, aus der Schule bekannt sein.

## Arithmetische Operatoren

| Operator | Beschreibung | Kurzbeispiel |
| + | Addition | int antwort = 40 + 2; |
| - | Subtraktion | int antwort = 48 - 6; |
| * | Multiplikation | int antwort = 2 * 21; |
| / | Division | int antwort = 84 / 2; |
| % | Teilerrest, Modulo-Operation, errechnet den Rest einer Division | int antwort = 99 % 57; |
| + | positives Vorzeichen, in der Regel überflüssig | int j = +3; |
| - | negatives Vorzeichen | int minusJ = -j; |
Für zwei besonders in Schleifen häufig anzutreffende Berechnungen gibt es eine abkürzende Schreibweise.
| Operator | Beschreibung | Kurzbeispiel |
| ++ | Postinkrement, Addiert 1 zu einer numerischen Variablen | x++; |
| ++ | Preinkrement, Addiert 1 zu einer numerischen Variablen | ++x; |
| -- | Postdekrement, Subtrahiert 1 von einer numerischen Variablen | x--; |
| -- | Predekrement, Subtrahiert 1 von einer numerischen Variablen | --x; |
Post- und Pre-Operatoren verhalten sich bezüglich ihrer Berechnung absolut gleich, der Unterschied ist der Zeitpunkt, wann die Operation ausgeführt wird. Zum Tragen kommt das bei Zuweisungen:

## Operatoren für Vergleiche

Das Ergebnis dieser Operationen ist aus der Menge true, false:
| Operator | Beschreibung | Kurzbeispiel |
| == | gleich | 3 == 3 |
| != | ungleich | 4 != 3 |
| > | größer als | 4 > 3 |
| < | kleiner als | -4 < -3 |
| >= | größer als oder gleich | 3 >= 3 |
| <= | kleiner als oder gleich | -4 <= 4 |

## Boolesche Operatoren

| Operator | Beschreibung | Kurzbeispiel |
| ! | Negation, invertiert den Ausdruck | boolean lügnerSpricht = !wahrheit; |
| && | Und, true, genau dann wenn alle Argumente true sind | boolean krümelmonster = istBlau && magKekse; |
| || | or true, wenn mindestens ein Operand true ist | boolean machePause = hungrig || durstig; |
| ^ | Xor true wenn genau ein Operand true ist | boolean zustandPhilosoph = denkt ^ ist; |

## Operatoren zur Manipulation von Bits

| Operator | Beschreibung | Kurzbeispiel |
| ~ | (unäre) invertiert alle Bits seines Operanden | 0b10111011 = ~0b01000100 |
| & | bitweises "und", wenn beide Operanden 1 sind, wird ebenfalls eine 1 produziert, ansonsten eine 0 | 0b10111011 = 0b10111111 & 0b11111011 |
| | | bitweises "oder", produziert eine 1, sobald einer seiner Operanden eine 1 ist | 0b10111011 = 0b10001000 | 0b00111011 |
| ^ | bitweises "exklusives oder", wenn beide Operanden den gleichen Wert haben, wird eine 0 produziert, ansonsten eine 1 | 0b10111011 = 0b10001100 ^ 0b00110111 |
| Operator | Beschreibung | Kurzbeispiel |
| >> | Arithmetischer Rechtsshift: Rechtsverschiebung, alle Bits des Operanden werden um eine Stelle nach rechts verschoben, stand ganz links eine 1 wird mit einer 1 aufgefüllt, bei 0 wird mit 0 aufgefüllt | 0b11101110 = 0b10111011 >> 2 |
| >>> | Logischer Rechtsshift: Rechtsverschiebung mit Auffüllung von Nullen | 0b00101110 = 0b01011101 >>> 1 |
| << | Linksverschiebung, entspricht bei positiven ganzen Zahlen einer Multiplikation mit 2, sofern keine "1" rausgeschoben wird. | 0b10111010 = 0b01011101 << 1 |

## Zuweisungsoperatoren

Zu vielen Operatoren aus den vorstehenden Tabellen gehört eine Schreibweise, mit der gleichzeitig zugewiesen werden kann. Damit spart man sich oft etwas Schreibarbeit. Also, statt etwa x = x * 7; zu schreiben kann man etwas verkürzt schreiben: x *= 7;.
| Operator | Beschreibung | Kurzbeispiel |
| = | einfache Zuweisung | int var = 7; |
| += | Addiert einen Wert zu der angegebenen Variablen | plusZwei += 2; |
| -= | Subtrahiert einen Wert von der angegebenen Variablen | minusZwei -= 2; |
| /= | Dividiert die Variable durch den angegebenen Wert und weist ihn zu | viertel /= 4; |
| *= | Multipliziert die Variable mit dem angegebenen Wert und weist ihn zu | vierfach *= 4; |
| %= | Ermittelt den Modulo einer Variablen und weist ihn der Variablen zu | restModulo11 %= 11; |
| &= | "und"-Zuweisung | maskiert &= bitmaske; |
| |= | "oder"-Zuweisung | |
| ^= | "exklusives oder"-Zuweisung | |
| ^= | bitweise "exklusive oder"-Zuweisung | |
| >>= | Rechtsverschiebungzuweisung | |
| >>>= | Rechtsverschiebungzuweisung mit Auffüllung von Nullen | |
| <<= | Linksverschiebungzuweisung | achtfach <<= 3; |

## Bedingungsoperator

Den einzigen ternären Operator ?: stellen wir im Kapitel Kontrollstrukturen vor.

## Konkatenation

Zwei Strings lassen sich mit "+" aneinanderschreiben, so wie Sie es schon aus früheren System.out.println("Hallo" + " Welt" + "!");-Beispielen kennen.

## Rangfolge von Operatoren

Die Rangfolge der Operatoren (engl. "operator precedence" oder auch "precedence rules") bestimmt in der Regel, in welcher Reihenfolge sie ausgewertet werden. Es geht darum, Klammern zu sparen. Weiß man, dass && einen höheren Rang als || hat, dann wird der Ausdruck (A && B) || C zu A && B || C. Selbstverständlich darf man trotzdem Klammern setzen.
Ganz allgemein gilt, dass Ausdrücke von links nach rechts ausgewertet werden. Das gilt nicht für Zuweisungsoperatoren.
In der folgenden Tabelle werden die Operatoren und ihre Ränge aufgeführt. Je weiter oben ein Operator in der Tabelle auftaucht, desto eher wird er ausgewertet. Operatoren mit dem gleichen Rang (in der gleichen Zeile) werden von links nach rechts ausgewertet.
| Rangfolge | Typ | Operatoren |
| 1 | Postfix-Operatoren, Postinkrement, Postdekrement | x++, x-- |
| 2 | Einstellige (unäre) Operatoren, Vorzeichen | ++x, --x, +x, -x, ~b, !b |
| 3 | Multiplikation, Teilerrest | a*b, a/b, a % b |
| 4 | Addition, Subtraktion | a + b, a - b |
| 5 | Bitverschiebung | d << k, d >> k, d >>> k |
| 6 | Vergleiche | a < b, a > b, a <= b, a >= b, s instanceof S |
| 7 | Gleich, Ungleich | a == b, a != b |
| 8 | UND (Bits) | b & c |
| 9 | Exor (Bits) | b ^ c |
| 10 | ODER (Bits) | b | c |
| 11 | Logisch UND | B && C |
| 12 | Logisch ODER | B || C |
| 13 | Bedingungsoperator | a ? b : c |
| 14 | Zuweisungen | a = b, a += 3, a -= 3, a *= 3, a /= 3, a %= 3, b &= c, b ^= c, b |= c, d <<=k, d >>= k, d >>>= k |
* ↑ siehe nächsten Abschnitt Fallen
* ↑ Zum Teil entnommen von https://docs.oracle.com/javase/tutorial/java/nutsandbolts/operators.html

## Fallen

Es gibt zum Glück wenig Fallstricke im Gebrauch von Operatoren. Postfix-Operatoren werden immer zuerst nach dem aktuellen Wert, den sie haben ausgewertet, erst dann erfolgt die Operation darauf.
Nicht in allen Fällen kann man sich bei Beachtung der Rangfolge Klammern sparen. Versuchen Sie doch einmal, den Ausdruck int x = ++y++; auszuwerten (wobei y vorher deklariert wurde). Trotz der klaren Vorrangregeln lässt sich dieser Ausdruck nicht kompilieren. Gut für alle, die einen solchen Quelltext lesen müssen...
Für weitere schwer zu durchschauende Fallen siehe auch Strukturierte Programmierung / Komplexe Ausdrücke.

## Rechengenauigkeit

Beim Rechnen mit zwei Datentypen unterschiedlicher Genauigkeit (z.B. int und long) muss beachtet werden, dass als Ergebnis der "genaue" Datentyp berechnet wird.
Wird nur ein "ungenauerer" Wert benötigt, so muss das dem Compiler mitgeteilt werden (cast).
Die Genauigkeit ist hier durch den Zahl gegeben. Ein Datentyp int kann eine 32-Bit-Ganzzahl darstellen, während der Typ long 64-Bit-Ganzzahlen aufnehmen kann (= 8 Byte). Deshalb "passt" ein int-Wert problemlos in einen long-Wert. Umgekehrt kann es da schon passieren, dass der long-Wert größer als der größtmögliche int-Wert ausfällt!

## Verzweigung (if)

Eine einfache Verzweigung wird durch das "if-then-else"-Konstrukt gelöst, wobei lediglich if und else in Java Schlüsselwörter sind.
Eine if-Verzweigung führt stets die nachfolgende Anweisung aus, wenn der <boolesche Ausdruck> wahr ist. Sollen mehrere Anweisungen ausgeführt werden so sind diese in einen Block zusammenzufassen (mit Hilfe der geschweiften Klammern). Die else Bedingung ist optional - auch hier gilt dass mehrere Anweisungen in einen Block zusammenzufassen sind.
Das vorstehende Beispiel zeigt einen typischen Fehler in Zusammenhang mit dem if-Konstrukt. Der Befehl System.exit(0); wird immer ausgeführt, da kein Block gebildet wurde.
Es ist auch eine Frage des guten Programmierstils solche if-Abfragen immer in geschweifte Klammern zu fassen, dadurch lassen sich die einzelnen Ausdrücke besser dem jeweiligen if zuordnen.
Beim unteren Quelltext wird im Gegensatz zum oberen klar, das System.exit(0) immer ausgeführt wird, da es nicht in den Klammern steht.

## Ternärer Operator (?:)

Wenn nur zwischen zwei Ausgabewerten unterschieden werden soll, so gibt es für die If-Then-Else-Anweisung eine Kurzform; und zwar den "Ternary-Operator".

### Beispiel

Anstelle der Anweisung
kann man kürzer schreiben
oder vielleicht etwas eleganter

## Mehrfachverzweigung (switch)

Das if-Konstrukt führt in Zusammenhang mit mehreren Möglichkeiten meist zu einer unschönen Kaskadierung. Hier kann switch helfen. Um dieses einzusetzen müssen Sie einen Datentyp int abprüfen bzw. einen kleineren (also byte, short, char), da dieser durch die JVM automatisch gecastet wird.
Eine switch Anweisung wird stets mit dem Schlüsselwort case und meist mit default und break verwendet. Der Wert hinter dem case muss eine Konstante sein und dient dem Vergleich mit dem übergebenen Wert (hier myIntWert). Wenn diese gleich sind werden alle Anweisungen bis zum nächsten break oder dem Ende des Blocks ausgeführt. Wurden keine Übereinstimmung gefunden so werden die Anweisung nach default ausgeführt. Seit Java 7 ist es ebenfalls möglich, den Datentyp String in Switch-Anweisungen zu verwenden. Zuvor war es seit Java 5.0 lediglich möglich, anstelle von String den Datentyp enums zu benutzen.

## For-Schleife

Die for-Schleife oder Zählschleife zählt von einem vorgegebenen Startwert zu einem ebenfalls vorgegebenen Endwert und führt für jeden Schritt von Start- bis Endwert alle Anweisungen im Schleifenkörper aus. Es muss also zusätzlich festgelegt werden, in welchen Intervallen bzw. Schritten von Start bis Ende gezählt wird.
For-Schleifen bestehen aus folgenden Teilen bzw. Anweisungen und Bedingungen:
* Schleifenkopf
** Initialisierung der Zählervariable auf den Startwert
** Startbedingung mit Limitierung auf den Endwert - muss immer einen boolschen Wert ergeben (true | false)
** Anweisung zum Zählen
* Schleifenkörper
** Anweisungen, die pro Schleifendurchlauf ausgeführt werden sollen

### Die Syntax

Die grundlegende Syntax sieht folgendermaßen aus:
In obigem Beispiel sieht man eine for-Schleife, die von 0 bis 9 zählt. Warum nur bis 9? Weil die Startbedingung i kleiner als 10 und nicht kleiner gleich 10 lautet.
* Zunächst muss eine Zählervariable auf einen Startwert initialisiert werden int i=0. Wird diese Variable im Schleifenkopf deklariert, ist sie auch innerhalb ihres Namensraumes, also dem Schleifenkopf selbst sowie dem Schleifenkörper bekannt. Außerhalb der Schleife kann die Zählervariable folglich nicht angesprochen werden.
* Dann wird die Startbedingung für die for-Schleife festgelegt: i < 10. Sie läuft also "solange i kleiner als 10 ist". Trifft diese Bedingung nicht zu, werden die Anweisungen im Schleifenkörper nicht ausgeführt. Die Startbedingung muss also immer einen boolschen Wert (true | false) ergeben.
* Zuletzt muss noch definiert werden in welchen Intervallen gezählt wird: i++. Die Schleife zählt also in Schritten von 1 nach oben bzw. addiert nach jedem Schleifendurchlauf 1 auf die Zählervariable i.

### Ablauf einer for-Schleife

Nehmen wir folgende Schleife an:
Sie wird folgendermaßen durchlaufen:
   * Start: Initialisierung der Zählervariable auf den Wert 0
   * Prüfung der Startbedingung: i = 0 ist kleiner als 3 ( i < 3 = true ), also dürfen die Anweisungen des Schleifenkörpers ausgeführt werden
   * Erster Durchlauf: Die Zählervariable i wird am Bildschirm ausgegeben: 0
   * Hochzählen: Die Zählervariable wird um 1 erhöht: 0 + 1 = 1
   * Prüfung der Startbedingung: i = 1 ist kleiner als 3 ( i < 3 = true ), also dürfen die Anweisungen des Schleifenkörpers ausgeführt werden
   * Zweiter Durchlauf: Die Zählervariable i wird am Bildschirm ausgegeben: 1
   * Hochzählen: Die Zählervariable wird um 1 erhöht: 1 + 1 = 2
   * Prüfung der Startbedingung: i = 2 ist kleiner als 3 ( i < 3 = true ), also dürfen die Anweisungen des Schleifenkörpers ausgeführt werden
   * Dritter Durchlauf: Die Zählervariable i wird am Bildschirm ausgegeben: 2
   * Hochzählen: Die Zählervariable wird um 1 erhöht: 2 + 1 = 3
   * Prüfung der Startbedingung: i = 3 genauso groß wie 3 ( i < 3 = false ), also dürfen die Anweisungen des Schleifenkörpers nicht mehr ausgeführt werden

### Verwendungszweck

For-Schleifen sind nützlich um eine bekannte Anzahl an immer wiederkehrenden Anweisungen auszuführen. Klassisch hierfür dürfte das Auslesen der Werte eines Arrays mittels einer Schleife sein. Beispielsweise dürfte ohne Schleifen die Ausgabe von in einem Array enthaltenen Werten sehr mühsam für den Programmierer sein. Dies würde bei zehn Werten wie folgt aussehen:
Diese Aufgabe lässt sich mittels einer Schleife erheblich erleichtern:
Mittels .length erhält man die Länge des Arrays als int-Wert. Somit lässt sich immer die Länge des Arrays bestimmen, auch wenn man diese zum Zeitpunkt der Programmierung noch nicht kennt.
Ein Array kann also mittels einer for-Schleife durchlaufen werden, da man einen Startwert = 0 sowie einen Endwert = .length hat. Da man alle Werte aus dem Array auslesen möchte (und nicht nur bestimmte), wird die Zählervariable immer um eins erhöht.
Im Schleifenkörper kann nun jeder Arrayplatz mit der Zählervariable angesprochen werden: einArray[i].
Innerhalb des Schleifenkörpers kann jede Art von Anweisung durchgeführt werden. Muss man beispielsweise eine größere Anzahl an Parametern nacheinander an ein und dieselbe Methode übergeben, kann man dies mittels einer Schleife tun:
Es ist natürlich ebenfalls möglich mehrmals Objekte des gleichen Typs zu erstellen.

### Abkürzung

Bei Arrays gibt es eine Kurzschreibweise, um über ein vorher belegtes Array zu iterieren:

### Variationen

Bei der Implementierung des Schleifenkopfes ist man nicht strikt an die in obigem Beispiel vorgestellte Form gebunden. Vieles ist möglich, solange man sich an die Syntax hält. Die folgenden Beispiele sollen nur kleine Anregungen sein.

## Schleife mit Vorabprüfung (while)

Die while-Schleife führt den Anweisungsblock aus, solange die Prüfung true ergibt. Die Prüfung der Bedingung erfolgt dabei vor dem Betreten der Schleife. Beispiele

## Schleife mit Nachprüfung (do)

Die do-Schleife führt alle beinhalteten Anweisungen solange aus, wie die Prüfung true ergibt. Die Prüfung der Bedingung erfolgt dabei nach dem ersten Schleifendurchlauf. Zu einer do Schleife wird stets das Schlüsselwort while zur Bedingungsangabe benötigt. Beispiele

## Schleifen verlassen und überspringen (break und continue)

Innerhalb einer do, while oder for-Schleife kann mit break die gesamte Schleife verlassen werden. Soll nicht die gesamte Schleife, sondern nur der aktuelle Schleifendurchlauf verlassen und mit dem nächsten Durchlauf begonnen werden, kann die Anweisung continue verwendet werden. Im folgenden Beispiel werden in einem Iterator über eine Personenkartei alle Personen gesucht, die zu einer Firma gehören. Dabei werden gesperrte Karteikarten übersprungen. Wird eine Person gefunden, die zu dieser Firma gehört und als Freiberufler tätig ist, wird die weitere Suche abgebrochen, da angenommen wird, dass ein Freiberufler der einzige Angehörige seiner Firma ist.
Diese Aussprünge ähneln den goto-Befehlen anderer Programmiersprachen, sind aber nur innerhalb der eigenen Schleifen erlaubt. Bei Schachtelung mehrerer Schleifen können diese auch mit Bezeichnern (Labels) versehen werden, so dass sich die break- oder continue-Anweisung genau auf eine Schleife beziehen kann:

## Übungen

* Schreibe ein einfaches Programm, welches für jeden Monat die Anzahl der Tage ausgibt. Nutze hierzu die einfache Verzweigung.
* Schreibe ein einfaches Programm, welches für jeden Monat die Anzahl der Tage ausgibt. Nutze hierzu die Mehrfachverzweigung.
* Schreibe eine einfache Applikation, welche mit Hilfe der Zählschleife die Übergabeparameter ausgibt. Sofern du das JDK 1.5 oder höher verwendest nutze hierfür die alte und neue Variante.
* Wie oft wird die folgende do-Schleife ausgeführt und warum?
Die Sprache Java gehört zu den objektorientierten Programmiersprachen. Die Grundidee der objektorientierten Programmierung ist die softwaretechnische Abbildung in einer Art und Weise, wie wir Menschen auch Dinge der realen Welt erfahren. Die Absicht dahinter ist, große Softwareprojekte einfacher verwalten zu können, und sowohl die Qualität von Software zu erhöhen als auch Fehler zu minimieren. Ein weiteres Ziel der Objektorientierung ist ein hoher Grad der Wiederverwendbarkeit von Softwaremodulen.
Allgemeines zum Thema Objektorientierung findet sich im dazugehörigen Wikipedia-Eintrag. Dieses Kapitel beschäftigt sich speziell mit der Umsetzung in Java.
Ab der frühen Kindheit wird uns beigebracht, hinter den Dingen ein Schema zu erkennen. Wir lernen, dass Bello ein Hund ist. Zu diesen Bildern ordnen wir Eigenschaften und Fähigkeiten zu ("Farbe ist schwarz" oder "kann bellen"). Diese Verallgemeinerung ist eine der Stärken der Menschen. Es wird wohl daran liegen, dass die meisten Menschen nicht mehr als sieben Dinge gleichzeitig berücksichtigen können. Wen wundert es, wenn wir versuchen dieses Vorgehen in unsere Programmiersprachen zu übertragen. Somit können wir Dinge aus der Wirklichkeit auf die Maschine übertragen, weil sie abbildbar sind.
Der Hund wird in Java als Klasse repräsentiert. Bello wird als Objekt/Exemplar der Klasse verstanden.
Wesentliche Ziele von objektorientierter Programmierung sind Übersichtlichkeit, einfache Modifizierbarkeit, Flexibilität und einfache Wartung des Programmcodes. Erreicht wird dies durch den Ansatz, Objekte als relativ eigenständig zu verstehen. So ist es beispielsweise für das Gassigehen unerheblich, welchen Hund wir nun konkret an die Leine nehmen: Das kann Bello sein, es kann aber auch der Hund der Nachbarin sein, die im Urlaub ist. Das Vorgehen ist beide Male das Gleiche, unabhängig davon welche Farbe der Hund hat oder welcher Rasse er angehört. Um Gassigehen zu können, muss es sich um einen Hund handeln. Nur dieser Punkt interessiert. Ob der Hund womöglich auch noch prämierter Gewinner von Schönheitswettbewerben ist oder auf einem Skateboard fahren kann, ist unwichtig.
Das hört sich sehr banal an, hat aber weitreichende Konsequenzen. Es ist ein fundamentales Konzept von objektorientierter Programmierung nur diejenigen Eigenschaften eines Objektes zu betrachten, die einen auch wirklich interessieren.
Durch einen Übersetzungsfehler des Wortes „instance" aus dem Englischen wird immer wieder von einer Instanz gesprochen, wobei hier der Begriff „Instanz" falsch ist. Besser passende Übersetzungen für „instance" sind „Objekt", „Ausprägung", „Exemplar", oder auch „realisiertes Beispiel".

## Aufbau einer Java-Klasse

Jede mit "public" gekennzeichnete Klasse muss in einer eigenen Datei gespeichert werden, die Klassenname.java heißt. Schlüsselwörter wie "public" und "private" sind Zugriffsmodifizierer, "final" bezeichnet in diesem Kontext eine Konstante und wird ebenso wie "static" weiter unten erklärt. Die "Testklasse" enthält zwei Methoden: "gib_etwas_aus" und "main(String args)". "klassenkonstante" und "anzahl" nennt man Klassenvariablen, man erkennt Klassenvariablen am Schlüsselwort "static".
Dieses Beispiel enthält zwei verschiedene Klassen. Die Variable "eineVariable" in der Klasse "AndereKlasse" ist eine Instanz-Variable, hingegen ist "a" aus der Methode "main" eine lokale Variable. In der Variablen "a" ist das Objekt AndereKlasse gespeichert. Klasse und Objekt sind also zwei verschiedene Dinge.

## Zugriffsmodifizierer

In der Objektorientierung kennt man so genannte Zugriffsmodifizierer (engl. access modifier), die die Rechte anderer Objekte einschränken (Kapselung) oder die ein bestimmtes Verhalten von einem Unterobjekt verlangen (Abstraktion/Vererbung).
Manchmal hört man auch die Bezeichnung Sichtbarkeitsmodifizierer (engl. visibility modifier). Diese Bezeichnung ist aber eigentlich falsch, weil die Zugriffsmodifizierer den Zugriff auf einen Member verbieten, der Member als solches bleibt jedoch sichtbar, z.B. über Reflection. Dennoch sollte man diese Bezeichnung verstehen, da sie unter Java-Programmierern weit verbreitet ist.
Java kennt folgende Zugriffsmodifizierer:
| | Die Klasse selbst, innere Klassen | Klassen im selben Package | Unterklassen | Sonstige Klassen |
| private | Ja | Nein | Nein | Nein |
| (default) | Ja | Ja | Nein | Nein |
| protected | Ja | Ja | Ja | Nein |
| public | Ja | Ja | Ja | Ja |

### private

private ist der restriktivste Zugriffsmodifizierer. Er verbietet jeglichen Zugriff von außerhalb der Klasse auf den entsprechend modifizierten Member. Auf eine private Variable kann nur die Klasse selbst zugreifen, ebenso auf einen privaten Konstruktor, eine private Methode oder einen privaten geschachtelten Datentyp.
Klassenvariablen werden üblicherweise als private deklariert. Das Verändern der Variablen wird über passende Methoden, meist Getter und Setter ermöglicht. Dieses Prinzip nennt man Geheimnisprinzip.
Allgemein werden sämtliche Member als private deklariert, die ein Implementierungsdetail darstellen, auf das sich keine andere Klasse verlassen bzw. das von keiner anderen Klasse verwendet werden darf.

### (default)

Als "default" oder "package private" bezeichnet man die Zugreifbarkeit für den Fall, dass kein Zugriffsmodifizierer angegeben wurde. Auf einen package private Member können nur Klassen zugreifen, die sich im selben Paket wie die Klasse des Members befinden.
Der "default" Zugiffsmodifizierer wird dann eingesetzt, wenn eine Klasse auf die Daten einer anderen Klasse (innerhalb des selben Packages) Zugriff haben soll, aber diese Funktionalitäten nach außen nicht verfügbar gemacht werden sollen.
Dieser Zugriffsmodifizierer wird insbesondere bei der Entwicklung von API eingesetzt.

### protected

Mit dem Zugriffsmodifizierer protected ist der Zugriff nicht nur Klassen aus dem selben Package (wie "default"), sondern auch Subklassen der Klasse erlaubt. Dies gilt auch, wenn die betreffenden Subklassen aus einem anderen Package sind als die Klasse des betreffenden Members.
Der Zugriffsmodifizierer protected wird verwendet, wenn es nur für Subklassen Sinn ergibt, den betreffenden Member zu verwenden.
Diese Zugriffsmodifizierer findet in der API-Programmierung Einsatz. Auch Muster wie das Schablonenmuster (engl. template pattern) nutzen diesen Mechanismus.

### public

Der Zugriffsmodifizierer public gestattet sämtlichen Klassen Zugriff auf den betreffenden Member. Er ist der freizügigste Zugriffsmodifizierer.
Die Zugreifbarkeit public findet man hauptsächlich bei Methoden, die von anderen Klassen verwendet werden sollen z.B. bei Konstruktoren.

### Welcher Zugriffsmodifizierer?

Welchen Zugriffsmodifizierer soll man nun verwenden? Im einfachsten Fall verwendet man private für Variablen sowie public für Methoden, Konstruktoren und Datentypen. Eine Regel, die sich in der Praxis sehr bewährt hat, lautet "so streng wie möglich, so freizügig wie nötig".

## Polymorphie-Modifizierer

Polymorphie-Modifizierer sind dazu da, ein bestimmtes Verhalten einer Unterklasse zu erzwingen, bzw. dieses zu erleichtern. Das heißt, dass wenn eine Klasse von einer abstrakten Klasse abgeleitet werden soll, die Unterklasse diese Attribute bzw. Methoden implementieren muss, wenn es eine konkrete Klasse werden soll. Doch nun zu den einzelnen Modifizierern selbst:

### abstract

Es können Methoden und Attribute als abstract bezeichnet (deklariert) werden, was bedeutet, dass entweder die Unterklasse diese implementieren muss oder aber die abgeleitete Klasse ebenfalls als abstrakt deklariert werden muss.
Von einer abstrakten Klasse können keine Instanzen gebildet werden, so dass diese immer erst implementiert werden muss, um das gewünschte Ergebnis zu erreichen. Ein Beispiel:
Dies ist eine abstrakte Klasse mit einer Methode. Was genau berechnet werden soll, steht hier aber nicht - deswegen heißt diese auch "abstrakt". Jetzt erweitern wir diese Klasse um eine Addition zu erhalten:
Wie man an diesem konkreten Beispiel sieht, wird erst in der "konkreten" Klasse der Algorithmus implementiert.

### final

Es können Klassen, Methoden, Attribute und Parameter als final bezeichnet (deklariert) werden. Einfach ausgedrückt bedeutet final in Java "du kannst mich jetzt nicht überschreiben".
Für finale Klassen bedeutet dies, dass man von ihr nicht erben kann (man kann keine Unterklasse erzeugen). Sie kann also nicht als Vorlage für eine neue Klasse dienen. Grundlegende Klassen, wie zum Beispiel die String-Klasse sind final. Wenn sie es nicht wäre, dann könnte man von ihr erben und ihre Methoden überschreiben und damit das Verhalten der erweiterten Klasse verändern.
Finale Methoden können in Subklassen nicht überschrieben werden.
Finale Attribute und auch Klassen-Variablen können nur ein einziges Mal zugewiesen werden. Sobald die Zuweisung erfolgt ist, kann eine finale Variable ihren Wert nicht mehr ändern. Bei Member-Variablen muss die Zuweisung bei der Instanzierung, bei Klassen-Variablen beim Laden der Klasse erfolgen.
Finale Parameter können ausschliesslich den beim Methodenaufruf übergebenen Wert besitzen. In der Methode selbst lassen sie sich nicht überschreiben.
Ein Beispiel:
Der Compiler hat die Möglichkeit, finale Member-Variablen, denen Konstanten zugewiesen werden, direkt im kompilierten Code zu ersetzen.
Ein Beispiel:
Der Compiler macht daraus:
Wie Sie sehen, hat der Compiler hier einfach die finale Variable durch den Wert ersetzt. Diese Optimierung ist aber nur möglich, da der Wert konstant ist und direkt zugewiesen wird.
In folgendem Beispiel kann der Compiler nicht optimieren:
Der Wert der Variable antwortKlasse wird beim Laden der Klasse zugewiesen. Die Klasse wird dann geladen, wenn sie das erste Mal zur Laufzeit benötigt wird. Der Wert der Variable antwortInstanz wird beim Instanzieren der Klasse, genauer gesagt bei der Initialisierung des Objekts auf Ebene der Klasse WievielMillisSindVerstrichen, also mit new WievielMillisSindVerstrichen zugewiesen.
Noch eine Warnung beim Verwenden von Konstanten in Java. In Java deklariert man Konstanten wie folgt:
Der Java Compiler ersetzt dann überall die Variable durch dessen Konstante. Dadurch gelangt die Konstante (42) und nicht die Variable (ICH_BIN_EINE_KONSTANTE) in das Kompilat (Konstante.class und Beispiel.class).
gibt wie erwartet die Zahl 42 aus.
Wenn ich jetzt den Wert der Konstante von 42 auf 99 ändere und nur die Klasse Konstante compiliere, wird es gefährlich:
gibt immer noch die Zahl 42 aus, obwohl ich doch den Wert der Variable ICH_BIN_EINE_KONSTANTE geändert habe. Warum? Als das Kompilat der Klasse Beispiel (Beispiel.class) erzeugt wurde, war der Wert von ICH_BIN_EINE_KONSTANTE noch 42. Der Compiler hat zu dem Zeitpunkt den Wert 42 in die Klasse Beispiel eingesetzt. Weil die Klasse Beispiel nicht nochmals kompiliert wurde steht im Kompilat immer noch den Wert 42 und der wird dann auch ausgegeben.
hilft und gibt dann auch 99 aus.
Konsequenzen: Bei einer Änderung von public/protected final static sollte immer der gesamte Code neu kompiliert werden. Wenn das nicht möglich ist (z.B. in einer Klasse, die von verschiedenen anderen Projekten benutzt wird), sollte man auf die Verwendung von Konstanten verzichten und stattdessen einfach eine Methode verwenden:
Ein letztes Beispiel soll aufzeigen, dass mit final lediglich die Zuweisung (das Überschreiben), nicht aber der Gebrauch geschützt wird.
Wie man hier schön sieht, kann man auf finalen Member-Variablen, hier die internenNamensliste, Methoden ausführen (wie das Hinzufügen mit interneNamensliste.add(name)). Da die Member-Variable interneNamensliste final ist, kann man ihr keinen anderen Wert zuweisen. Eine zusätzliche Methode
ist nicht zulässig und würde beim Kompilieren mit einer Fehlermeldung enden. Richtig riskant ist die Methode gibListe. Indem die interneNamensliste der Außenwelt (außerhalb der Klasse) verfügbar gemacht wird, kann man von der Außenwelt auch alle Methoden der Liste aufrufen. Damit ist die Liste außerhalb des Einflussbereiches der Klasse. Da hilft es auch nicht, dass die Member-Variable interneNamensliste final ist.

### static

Es können Methoden und Klassenvariablen als static bezeichnet (deklariert) werden.
Statische Methoden und Variablen benötigen keinerlei Instanzen einer Klasse, um aufgerufen zu werden. Ein Beispiel für einen statischen Member ist z.B. die Konstante PI in der Klasse java.lang.Math.
Auch die Methoden dieser Klasse können einfach aufgerufen werden, ohne vorher eine Instanz dieser Klasse anzulegen, z.B. java.lang.Math.max(3,4).
Sofern eine statische Klassenvariable erst zur Laufzeit dynamisch einen Wert erhalten soll, können Sie dies mit einem statischen Block erreichen.
Beispiel:
Es ist dennoch möglich, statische Methoden oder Attribute über ein Objekt aufzurufen, davon wird aber dringend abgeraten. Denn dies führt zu unangenehmen Ergebnissen.
Beispiel:
Die Ausgabe ist:
Erstaunlich ist die zweite Zeile: Obwohl unser object vom Typ SubClass ist, wird die Methode von SuperClass aufgerufen. Offensichtlich funktioniert hier das Überschatten nicht. Das liegt daran, dass statische Methodenaufrufe nicht vom Laufzeittyp abhängen! Konkret bedeutet dies, dass die Entscheidung welche statische Methode nun aufgerufen werden soll, unabhängig davon getroffen wird, welcher Klasse das Exemplar angehört.
Um diesen irreführenden Effekt zu vermeiden, sollte man statische Methoden immer auf Klassen aufrufen und nicht auf Objekten.

### strictfp

strictfp kennzeichnet Klassen und Methoden, deren enthaltene Fließkommaoperationen streng auf eine Genauigkeit von 32 bzw. 64 Bit beschränkt sind. Dadurch wird sichergestellt, dass die JVM darauf verzichtet, Fließkommaoperationen intern mit einer höheren Genauigkeit zu berechnen (beispielsweise 40 bzw. 80 Bit) und nach Abschluss der Berechnung wieder auf 32 bzw. 64 Bit zu kürzen. Dies ist wichtig, da es sonst bei verschiedenen JVMs oder verschiedener Hardware zu unterschiedlichen Ergebnissen kommen kann und somit das Programm nicht mehr plattformunabhängig ist.
Ausdrücke, die zur Kompilierzeit konstant sind, sind immer FP-strict.

### native

native kann nur vor Methoden stehen und bedeutet, dass die Implementierung der betreffenden Methode nicht in Java, sondern einer anderen Programmiersprache geschrieben wurde, und von der virtuellen Maschine über eine Laufzeitbibliothek gelinkt werden muss. Die Syntax der Methode entspricht dann einer abstrakten Methode. Ein Beispiel:
Um eine solche Methode zu verwenden muss sie nach dem Compilieren über einen "Java-Pre-Compiler" (javah) gejagt werden, d.h. dieser generiert aus einer "native" - Methode ein entsprechenden C-Header und Rumpf, der dann mit Leben gefüllt werden kann. Diese Rümpfe werden als dll unter Windows bzw. lib unter Linux/Unix compiliert. Diese compilierten Libs müssen dann aber auch zur Laufzeit des Programms zugreifbar sein, andernfalls erhält der Nutzer eine Exception.

## Klassen, Objekte, Instanzen

Eine Klasse beschreibt die (allgemeine) Definition. Alles mit Ausnahme der primitiven Datentypen (int, boolean, long etc.) in Java ist abgeleitet von "java.lang.Object". Das heißt, dass jede Java-Klasse, die Sie schreiben, bestimmte Methoden bereits von "Object" geerbt hat.
Ein Objekt – auch Instanz genannt – ist ein bestimmtes Exemplar einer Klasse und wird zur Laufzeit des Programms erzeugt.

## Konstruktoren

Um eine Instanz einer Klasse zu erschaffen, wird der Konstruktor benutzt. Der Konstruktor ist namentlich wie die Klasse zu benennen. Die Syntax entspricht hierbei einer Methode jedoch gibt der Konstruktor keinen Wert, das heißt auch kein void, zurück.

## Destruktoren

Destruktoren gibt es in Java nicht. Es besteht eine gewisse Wahrscheinlichkeit dafür, dass die finalize Methode einer Instanz vor dessen Zerstörung durch die Garbage Collection aufgerufen wird. Dies ist jedoch nicht sichergestellt.

## Methoden in "java.lang.Object"

Hier sind nun einmal die wichtigsten Methoden, die man in allen Java-Objekten finden und aufrufen kann, aufgeführt.

### toString

Diese Methode ist während der Entwicklung eines Programmes von großem Nutzen. Jede Klasse, welche toString überschreibt, kann hier den relevanten Inhalt der Klasse in Textform ausgeben. Mit System.out.println(object); kann man nun den Inhalt eines Objektes ansehen.

### equals(Object)

Java unterscheidet zwei Arten von Gleichheit:
Identisch: Zwei Objekte sind identisch, wenn sie beide das selbe Objekt (exakt am selben Ort im Speicher) referenzieren, was mittels "==" getestet wird. In der Objektorientierung heißt das auch, dass diese eine gemeinsame Instanz haben. Stellen Sie sich das einfach so vor, als wenn Hausnummern in einer Stadt verglichen werden: Die Hausnummern sind zwar gleich, aber es können verschiedene Leute im Haus wohnen.
Beispiel:
Gleich resp. equal: Zwei Objekte sind gleich, wenn sie denselben semantischen Inhalt repräsentieren und das wird mittels equals(..) getestet. Um beim Hausbeispiel zu bleiben: Hier vergleichen wir die Leute, die in einem Haus wohnen, mit der Liste von Leuten, die in diesem Haus wohnen sollen.
Beispiel:
Ein Beispiel aus der realen Welt: Zwillinge sind gleich, aber nicht identisch. Weshalb: wenn man dem einen Zwilling z.B. die Haare färbe, dann behält der andere Zwilling seine Haarfarbe. Dasselbe gilt für Objekte:
Wenn zwei Objekte gleich, nicht aber identisch sind, dann kann ich im ersten Objekt etwas ändern, ohne dass sich dadurch das zweite Objekt ändert.
Wenn zwei Objekte identisch sind und ich ändere im ersten Objekt etwas, dann ist diese Änderung auch beim zweiten Objekt sofort vorhanden (beide Objekte sind eben identisch).
Wenn Objekte identisch sind, dann sind sie immer auch gleich (zumindest sollte es so sein, sofern man equals korrekt implementiert hat).
Benutzung der Methode equals: Hier muss man sicherstellen, dass das Objekt, auf welchem die Methode equals aufgerufen werden soll, nicht null ist. Typischweise sieht man dann sowas:
Eigene Implementierung Wenn Sie eine eigene Klasse anlegen sollten Sie stets diese Methode implementieren.

### hashCode

Die Methode hashCode liefert einen int als Rückgabewert und wird überall dort verwendet wo direkt oder indirekt mit Hashtables oder Hash-Sets gearbeitet wird. Zur Definition einer Hashtable siehe weiter unten. Wichtig: wenn zwei Objekte gleich (equals) sind, dann sollten sie unbedingt denselben hashCode zurückliefern. Umgekehrt ist es aber erlaubt, dass, wenn zwei Objekte nicht gleich sind, ihre beiden hashCodes gleiche Werte zurückliefern. Deshalb sollte man, wenn man equals überschreibt auch gerade hashCode überschreiben.
Und was geschieht, wenn man equals überschreibt, aber den hashCode nicht? Solange man die Objekte nicht in einer Hashtable/HashMap oder einem HashSet unterbringt hat man keine Probleme. Das ändert sich aber, sobald man die Objekte in Hashtables/HashMap oder HashSets unterbringen will. Um zu verstehen, was dabei "schiefgeht", muss man verstehen, wie Hashtables funktionieren.
Zur Definition einer Hashtable: Es ist eine Datenstruktur, welche erlaubt, sehr schnell Objekte anhand ihres Schlüssels abzulegen und anhand dieses Schlüssels wieder aufzufinden. Einfach ausgedrückt ist eine Hashtable ein Array von Schlüssel-Objekt-Paaren einer bestimmten Größe. Der Hash-Wert des Schlüssels modulo Größe der Hashtable dient dabei als Index, wo der Schlüssel selbst und das dazugehörige Objekt abgelegt werden. Falls nun mehrere Schlüssel an denselben Platz in der Hashtable platziert werden, so wird (in Java, nicht zwingend aber in anderen Programmiersprachen) einfach eine Liste benutzt, wo alle Schlüssel-Werte-Paare der entsprechenden Hashtable-Position gespeichert werden. Um Objekte aus der Hashtable herauszuholen, wird fast dasselbe gemacht wie beim Einfügen. Es wird die Position in der Hashtable berechnet (hash-Code des Schlüssels modulo Hashtable-Größe) und dann alle dort gefunden Objekte mittels der equals-Methode verglichen. Sobald die equals-Methode erfolgreich war, so hat man das richtige Objekte gefunden. Das Ganze ist dann besonders effizient, wenn die Hashtable klein ist und alle Schlüssel genau einen eigenen Index rsp. Hashtable-Position haben. Als Faustregel gilt: Ist eine Hashtable zu 50% gefüllt, sinkt die Effizienz bei weiterem Einfügen schnell. Zudem sollten die hashCode-Werte möglichst gut verteilt sein. Am schlimmsten wäre es, wenn alle Objekte derselben Klasse als hashCode denselben Wert zurückliefern. Die Größe einer Hashtable kann man beim Erzeugen definieren. Zusätzlich kann man ihr einen Füllgrad angeben, ab wann sie sich vergrößern soll. Die Vergrößerung einer Hashtable ist eine sehr teure Operation, die man indirekt durch Hinzufügen eines neuen Schlüssel-Werte-Paares auslöst. Dabei werden alle Schlüssel-Werte-Paare in einer neuen, größeren Hashtable abgelegt. Das geschieht zwar automatisch, ist aber zeitaufwändig.
Was geschieht nun, wenn man in einer Klasse K equals überschreibt, nicht aber hashCode? Dann wird der hashCode der Oberklasse benutzt (was bei der Objekt-Klasse mehr oder weniger der Speicheradresse gleichkommt). Wenn nun als Schlüssel Instanzen der Klasse K benutzt werden, dann werden alle Instanzen mit großer Wahrscheinlichkeit gleichmäßig in der Hashtable abgelegt (das wäre ja noch gut). Beim Auffinden eines Objektes anhand eines Schlüssels wird der hashCode des Schlüssels berechnet, um die Position in der Hashtable herauszufinden. Wenn nun zwei Schlüssel gleich sind, aber unterschiedliche hashCodes haben, dann wird jedes Schlüssel-Wert-Paar an eine andere Position abgelegt. Die Folge: man findet Objekte mit großer Wahrscheinlichkeit nicht mehr, da man am "falschen" Ort sucht.
Beispiel, was falsch läuft:
Was fehlt, ist der hashCode:

### wait, notify und notifyAll

Die sogenannte Vererbung ermöglicht es Informationen (Variablen) und Verhalten (Methoden / Operationen) weiterzugeben. Dies ist eine wesentliche Möglichkeit um Redundanz zu vermeiden. Die Erben fügen dann weitere Informationen und/oder Verhalten hinzu. Zwei Klassen stehen dabei zueinander als Superklasse (Erblasser) und Subklasse (Erbe) in Beziehung.
Vererbung ist ein zentrales Thema in der objektorientierten Programmierung (OOP) - siehe auch w:Objektorientierte Programmierung.

## Erzeugen und Zerstören von Subklassen

Das Erzeugen und Zerstören von Subklassen erfolgt analog zu einer normalen Klasse. Intern werden jedoch auch die Standardkonstruktoren der jeweiligen Superklasse beim Erzeugen und analog die finalize Methode beim Zerstören aufgerufen. Dies ist wichtig, da wir die Informationen und das Verhalten der Superklasse verwenden. Evtl. Grundstellen der Informationen oder Aufräumarbeiten beim Zerstören unserer Instanz sind somit auch bei den ererbten Informationen notwendig.

## Überschreiben von Methoden

In der Subklasse können Methoden der Basisklasse "überschrieben" werden. Damit wird der Inhalt der ursprünglichen Methode verändert.
Wird die methode-Methode für ein Objekt des Typs MeineSubklasse aufgerufen, wird der Satz "Wir sind in der Subklasse" ausgegeben.
Überschriebene Methoden werden für die Anwendung der Laufzeit-Polymorphie in Java benötigt. Dabei werden Methoden erst zur Laufzeit (im Gegensatz zur Compile-Zeit) den Objekten zugeordnet.
Anmerkung: Im Deutschen wird das Verb "überschreiben" benutzt. Im Englischen heißt es jedoch "override", nicht "overwrite".
Mit dem JDK 1.6 / Java 6 sollte die zudem eine Annotation (Anmerkung) angebracht werden:

## Javaspezifische Implementierung

In Java sind alle Objekte von der Klasse Object abgeleitet. Object ist somit die Basisklasse von allen anderen Klassen. Alle Klassen sind Subklassen von Object.
Man leitet eine eigene Klasse von der Basisklasse durch extends ab:

## static

Als static-deklarierte Elemente gehören keinem Objekt an, sondern der Klasse (oder Schnittstelle), in der sie definiert sind. Das berühmteste Beispiel ist hier
Die main-Methode muss als static deklariert sein, da vor ihrem Aufrufen ja kein Objekt instanziiert sein kann.
Als static können sowohl Variablen als auch Methoden deklariert werden.
Da static-Methoden von allen Objekten unabhängig sind, haben sie Einschränkungen:
* Es können aus ihnen heraus nur andere static-Methoden aufgerufen werden.
* Sie können auch nur auf static-Variablen zugreifen.
* static-Methoden und -Variablen können nicht mit this oder super angesprochen werden.

## abstract

Als abstract-deklarierte Methoden werden in der Basisklasse nur deklariert. Die Definition findet dann in den Subklassen statt.
In der Basisklasse wird nur angegeben, dass die Methode existiert, aber nicht wie sie implementiert ist. Damit wird also zugesichert, dass jedes Objekt des Typs BeispielKlasse - und damit auch jedes Objekt einer davon abgeleiteten Klasse - die Methode schreibIrgendwas besitzen muss.
In BeispielSubklasse muss die abstrakte Methode daher implementiert werden, ansonsten gibt es einen Compilerfehler. Wird eine abstrakte Methode in einer Unterklasse nicht implementiert, so muss diese Klasse selbst auch wiederum als abstract gekennzeichnet werden.
Generell muss jede Klasse, die mindestens eine abstrakte Methode enthält, auch selbst als abstrakt deklariert werden. Dies hat den Effekt, dass keine Objekte direkt von dieser Klasse erstellt werden können. Im obigen Beispiel wäre es also nicht zulässig, ein Objekt der Klasse BeispielKlasse mit
zu erzeugen.

## final

Durch die Benutzung von final kann das Ableiten einer Klasse oder Überschreiben einer Methode verhindert werden.
Das funktioniert nicht. Durch das final-Schlüsselwort kann von der Klasse Beispielklasse nicht abgeleitet werden.
Hier wird zwar die Subklasse erstellt, jedoch kann die Methode schreibIrgendwas nicht überschrieben werden.

## super

Um den Konstruktor der Basisklasse aufzurufen, wird die Methode super verwendet. Sie wird im Konstruktor der Subklasse verwendet. super wird benutzt, um private-Elemente der Basisklasse anzusprechen.
super ruft hier den Konstruktor von Beispiel auf, und könnte somit private-Elemente manipulieren.
Als zweite Anwendungsmöglichkeit kann super im Zusammenhang mit einem Element der Basisklasse benutzt werden.
Durch diese Aufrufe werden aus der Subklasse heraus die Methoden/ Variablen der Basisklasse aufgerufen.

## Einfluss von Modifizierern auf die Vererbung
### public und protected

Sowohl public- wie auch protected-Elemente werden an die abgeleitete Klasse vererbt. An ihrem public bzw. protected-Status ändert sich nichts.

### private

Private-Elemente werden nicht vererbt.

### packagevisible

Dies ist der voreingestellte Modifizierer, der angewandet wird, wenn kein anderer Modifizierer angegeben wird. Durch ihn können nur Objekte aus dem gleichen Paket auf die Elemente zugreifen.
Er wird ohne Einschränkungen an die Subklasse vererbt.

## Was ist ein Interface?

Interfaces als Java-Typ beschreiben eine öffentliche Schnittstelle der implementierenden Klassen. Interfaces sind hierbei eine Möglichkeit die Probleme der Mehrfachvererbung (in Java sowieso nicht möglich) elegant zu umgehen.
Schlüsselwort für die Deklaration eines Interface ist interface, welches anstelle der class Deklaration tritt. Ein Interface selbst kann nicht instanziert werden.

## Deklaratorische Interfaces

Ein deklaratorisches Interface deklariert keine weiteren Methoden. Es stellt somit lediglich sicher, dass alle implementierenden Klassen vom Typ des Interface sind.
Ein Beispiel für ein Deklaratorisches Interface ist unser MyInterface.

## "Normale" Interfaces

Normalerweise deklarieren Interfaces Methoden, die durch die implementierenden Klassen definiert werden. Die deklarierten Methoden sind dabei immer von der Sichtbarkeit public, auch wenn dies nicht explizit erwähnt wird.

## Interface als Konstantensammlung

Interfaces werden auch gern zur Sammlung von Konstanten verwendet. Ein schönes Beispiel hierfür ist in javax.swing.WindowConstants zu finden. Jedoch wird davon abgeraten, Interfaces als Konstantensammlungen zu benutzen. Denn eigentlich definieren Interface neue Typen. Sun Microsystems hat dieses Problem nun adressiert und bietet mittlerweile einen eigenen Ausdruck für den Import von Konstanten aus anderen Klassen an: import static. Siehe dazu die Schlüsselwortreferenz für import.

## Interfaces benutzen

Um ein Interface zu benutzen, muss dieses mit implements hinter dem Klassennamen spezifiziert werden. Anschließend müssen alle deklarierten Methoden des Interfaces implementiert (oder die Klasse als abstract deklariert) werden.
Es können auch durchaus mehrere Interfaces implementiert werden. Diese werden dann durch Kommata getrennt: ... implements Interface1, Interface2, Interface3 {
Das Paket java.lang enthält die elementaren Grundtypen von Java. Es wird per Default immer bereitgestellt, so dass es nicht notwendig ist einen import dieses Pakets vorzunehmen.

## Object - die Mutter aller Klassen

Die Klasse Object ist die Wurzel im Vererbungsgraphen von Java. Jede Klasse, die nicht explizit von einer anderen Klasse erbt, erbt automatisch von Object. Somit ist Object die einzige Javaklasse ohne Vorfahren ("parent"). In Object sind nur eine handvoll Methoden versammelt, die aber wichtig für das gesamte Java-Laufzeitsystem sind. Diese Methoden werden von den abgeleiteten Klassen überschrieben und jeweils angepasst. Die Methoden kann man verschiedenen Zwecken zuordnen:
| Verwendungszweck | Methodennamen |
| Erzeugung- und Initialisierung | Object - Defaultkonstruktor |
| Objektbeseitigung | finalize - wird vom Garbage Collector aufgerufen |
| inhaltlicher Vergleich zweier Objekte | equals |
| vollständige Kopie | clone - erzeugt eine "tiefe" (physikalische) Kopie eines Objektes (vergleichbar mit Copyconstructor in C++) |
| Serialisierung in String | toString - schreibt das aktuelle Objekt mit allen Infos in einen String |
| Laufzeitklasse | getClass - gibt die Laufzeitklasse zurück |
| eindeutiger Identifier | hashCode - gibt die eindeutige ID der Klasse zurück |
| Threadverwaltung | notify, notifyAll, wait |
Die Klasse Math ist das Matheobjekt mit allen Operationen für einfache numerische Berechnungen. Neben Konstanten PI und E werden auch viele mathematische Operationen wie Wurzelziehen, Exponentialzahlen, Sinus und Cosinus zur Verfügung gestellt. Alle Konstanten und Methoden in der Math-Klasse sind static, damit man kein eigenes Math-Objekt für jede Berechnung anlegen muss. Der Ergebnistyp fast aller Operationen ist double.
Konstanten: PI, E
Wurzelziehen, Logarithmus und Exponentialfunktion: sqrt, log, pow
Trigonometrische Funktionen: sin, cos, acos, asin, atan, atan2
Wertetabelle für die ersten 10 Sinuswerte im Intervall [0..2*PI]
Minimum und Maximum: min, max
Absolutwert, Runden und Abschneiden: abs, ceil, floor, rint, round
Umrechnung Grad (0..360) in Radian (0..2*PI)
Pseudozufallswert ausgeben aus dem Bereich von größer oder gleich 0.0 bis kleiner 1.0

## Was ist der Sinn von Wrapperklassen?

Wrapperklassen ("Hüllklassen") dienen als Verbindungsglied zwischen den Ordinaltypen von Java (byte, short, int, long, float, double, char) und den Klassen in Java und dabei insbesondere der Klasse String. Ein Grundproblem bei der Benutzung von Oberflächen wie AWT und Swing ist, dass bei Eingaben (z.B. in ein Textfeld) immer nur Texte verwaltet werden. Diese Texte müssen in "richtige" Zahlen verwandelt werden, um mit ihnen zu rechnen, und dann wieder in Texte zurückgewandelt werden, um sie in den GUI-Komponenten wieder anzuzeigen. Für dieses Verfahren, was auch als Boxing/Unboxing bekannt ist, werden die Wrapper-Klassen gebraucht. Bis auf die Klasse Character stammen alle Wrapper-Klassen von java.lang.Number ab. Es gibt nun zu jedem ordinalen Datentyp eine Wrapperklasse:
| Ordinaltyp | Wrapperklasse |
| byte | Byte |
| short | Short |
| int | Integer |
| long | Long |
| float | Float |
| double | Double |
| boolean | Boolean |
| char | Character |

## Umwandlung von Ordinaltyp nach String

Beispiele für die Wandlung von Ordinaltyp -> String:
oder kürzer:

## Umwandlung von String nach Ordinaltyp

Beispiele für die Wandlung von String -> Ordinaltyp:

## Umwandlung in andere Zahlensysteme

Mit Wrapperklassen ist auch die Umwandlung vom Dezimalsystem in andere Zahlensysteme (Hex, Oct, Dual) möglich. Auch für diese Operationen braucht kein neues Integer-Objekt angelegt werden weil die Operationen static sind.
Beispiele für die Umwandlung (das Ergebnis ist aber ein String!):

## Autoboxing/Autounboxing

In Java 5.0 wird vom Compiler mittlerweile ein automatisches Boxing/Unboxing vorgenommen. Dadurch ist es unnötig geworden, Ordinaltypen aus den Wrapperklassen mittels den toByte/toShort/toInt/toLong/toFloat/toDouble Methoden zu gewinnen. Andersherum kann einem Objekt einer Wrapperklasse direkt ein Ordinaltyp zugewiesen werden. Dieses Feature verkürzt den Code und macht ihn lesbarer. Allerdings muss nun der Programmierer dafür Sorge tragen, dass nicht ständig zwischen einem Wrapper-Objekt und einem Ordinaltyp hin- und hergewechselt werden muss, da dies enorm viele Resourcen beansprucht.
Beispiel:

## Welche Vor- und Nachteile hat man durch Wrapperklassen?

WrapperKlassen haben den Nachteil, dass der Overhead beim instanziieren geringfügig höher ist, sie sind einige Bytes größer als der dazugehörige primitive Datentyp.
Erstellt man größere Mengen, wirkt sich dies negativ auf die Geschwindigkeit und den benötigten Speicher eines Programmes aus.
Wrapper sind zum Beispiel erforderlich, um threadsichere primitive Datentypen zur Verfügung zu stellen.
Dieses Kapitel überschneidet sich mit Java Standard: Zeichenketten. Aus praktischen Gründen gehören die Inhalte auf jeden Fall zu den Grundlagen. Es ist zu überlegen, ob das Kapitel "String" als Teil von java.lang erhalten bleibt und sich schwerpunktmäßig mit den theoretischen Grundlagen befassen soll oder ob es gestrichen werden kann.

## Die Klasse String und StringBuffer

Zur Verarbeitung von Texten oder neudeutsch Zeichenketten gibt es in Java die Klasse String. Strings ermöglichen das effiziente Erstellen, Vergleichen und Modifizieren von Texten. Wie man am großen "S" schon sieht, ist String eine Klasse und kein Ordinaltyp wie char (Ordinaltypen beginnen immer mit einem Kleinbuchstaben). Strings werden sehr häufig benutzt, wenn man Werte aus GUI-Oberflächen auslesen bzw. verändern oder Textverarbeitung betreiben möchte. Darum gibt es für Strings einige Vereinfachungen, um den Umgang mit ihnen zu erleichtern:
* zur Benutzung muss man kein String-Objekt erzeugen (man kann es natürlich trotzdem tun)
* man kann Strings einfach mit einer Zuweisung einer Zeichenkette = ".." initialisieren
* Strings können einfach mit Hilfe des +-Zeichens aneinandergehängt werden (Konkatenation)
* Die Klasse String muss nicht explizit importiert werden
* Vorsicht: Um zwei Strings auf Gleichheit bzgl. des Inhalts zu überprüfen, kann man nicht == benutzen. Mit == wird überprüft, ob die beiden Objekte identisch sind, nicht ob deren Inhalt der gleiche ist. Für den Test auf Inhaltsgleichheit benutzt man deshalb die Methode equals die von der Klasse String bereitgestellt wird.
ein paar Beispiele:

## Unicode-Unterstützung

Die Zeichenketten (Strings) in Java verwenden zur Laufzeit eine UTF-16-Codierung, um die einzelnen Zeichen zu speichern. Das bedeutet, dass normalerweise ein Zeichen 16 Bit belegt. Beim Schreiben und Lesen von Dateien kann eine Konvertierung in verschiedene Zeichensatzcodierungen erfolgen.

## Immutable-Objekte

Zeichenketten (Strings) sind unveränderbare Objekte (immutable). Das bedeutet, dass ein Zeichenkettenobjekt, das einmal erzeugt worden ist, nicht verändert werden kann. Methoden, die Zeichenketten verändern, wie z.B. substring, erzeugen in Wirklichkeit ein neues Zeichenkettenobjekt. Das gilt auch für "+" und "+=".
Man sollte beachten, daß substring zwar ein neues Zeichenkettenobjekt erzeugt, aber weiterhin dieselbe interne Struktur für die Zeichen der Zeichenkette referenziert. Wenn man also eine sehr lange Zeichenkette hat, die nur temporär verwendet wird, und dann mit substring davon eine kurze Zeichenkette gewinnt, die man lange aufbewahrt, bleiben intern die Zeichen der langen Zeichenkette weiterhin gespeichert. Normalerweise ist das erwünscht.
Bei den bisherigen Formulierungen sind Sinn und Inhalt dieses Kapitels nicht klar. <T> bezieht sich auf generische Typen, während Class eine Grundlage für "alles" bietet. Beides ist wichtig und müsste genauer herausgearbeitet werden.

## Klassen und generische Typen

Die Klasse Class repräsentiert Klassen und Interfaces in einer laufenden Java-Applikation.
Sie stellt in Java eine Möglichkeit dar, Metadaten, sprich Informationen über Informationen zu erhalten. Man erhält also Informationen über die beerbte Klasse bzw. das implementierte Interface, nicht das Objekt an sich.
Eine Anwendungsmöglichkeit ist die Verwendung von Methoden eines Objektes, die einem zum Zeitpunkt der Programmierung unbekannt sind, jedoch mittels Class zur Laufzeit ermittelt werden können (siehe auch: java.lang.reflect.Method).
Des Weiteren ist es möglich Objekte zum Zeitpunkt der Programmierung unbekannten Datentyps zur Laufzeit zu erzeugen (siehe auch: java.lang.reflect.Constructor).

## Der Type Parameter <T>

Seit Java 1.5 muss ein Type Parameter an die Klasse Class übergeben werden. Durch die Angabe des Typs kann die Typprüfung zur Kompilierzeit vorgenommen werden.
Der Type Parameter T bestimmt welchen Datentypen ein Class-Objekt abbilden soll. Beispielsweise ist die Angabe für String Class<String>. Wenn der Typ unbekannt ist, wird ein Fragezeichen, eine so genannte Wildcard verwandt Class<?>.
Eine Wildcard gestattet also jeden Datentypen in einem Class-Objekt abzubilden.
Wildcards ihrerseits können eingeschränkt werden. Beispielsweise möchte man nur Erben von Number zulassen:

## Ein Class Objekt erzeugen

Die Klasse Class besitzt keine Konstruktoren, die public sind. Jedes Objekt in Java besitzt jedoch eine Methode getClass, die ein Class-Objekt als Repräsentation der beerbten Klasse des Objektes bereitstellt:
Eine andere Möglichkeit zur Erzeugung ist die statische Methode Class.forName( "Klassenname" ). Hierbei muss jedoch beachtet werden, dass dann nur eine Wildcard (?) als Type Parameter möglich ist, da zur Kompilierzeit noch nicht feststeht welchen Datentyp der übergebene String "Klassenname" darstellen soll:
Beachte: Man muss dem Klassennamen den kompletten Paketpfad der abzubildenden Klasse voranstellen. Bsp.: java.sql.ResultSet.
Das Abbilden primitiver Datentypen ist ebenfalls möglich:
Die dritte Möglichkeit ist die Erzeugung über das Signalwort class:

## Anwendungsbeispiel mit Method

Nehmen wir an, man hätte folgendes Interface.
Nun soll dieses Interface von irgendwem implementiert werden können und wir möchten, dass er seine Implementierung einfach nur in einen Ordner legen muss, damit die verwendende Applikation das Interface aufnehmen kann.
Hier hätten wir eine solche Implementierung.
Jetzt stehen wir vor dem Problem, dass wir eine Klasse mit uns unbekanntem Namen zur Laufzeit verfügbar machen müssen. Das erledigen wir mittels java.io.File.
So, nun hätten wir schonmal den Namen der Datei und die Endung. Uns interessieren natürlich nur die .class Dateien. Jetzt müssen wir die Klasse wie gesagt noch laden. Class.forName( "Name" ), funktioniert, solange alle zu ladenden Klassen in dem selben Verzeichnis liegen wie die aufrufende Klasse.
Da die zu ladenden Klassen aber eher in einem anderen Verzeichnis liegen werden, kann man auf einen ClassLoader zurückgreifen.
Der java.net.URLClassLoader kann auf die übergebenen URL`s zugreifen und aus diesen Quellen Klassen laden. Das kann auch ein Webverzeichnis sein, muss also nicht auf dem ausführenden Rechner liegen.
Abschließend noch ein Beispiel für die aufrufende Klasse. Es beruft sich auf obiges Interface und die Implementierung.
Nur noch zur Erläuterung: getDeclaredMethod gibt ein Method-Objekt zurück, das die über den String sowie durch das Class-Array identifizierte Methode des Class-Objektes repräsentiert.
Will man die Methode ausführen bzw. aufrufen, muss man invoke verwenden. Dabei werden das Objekt, aus dem die Methode aufgerufen werden soll und die Parameter als Object-Array übergeben.
Möchte man eine Methode aus einer statischen Klasse aufrufen, muss man statt einem Object null übergeben.

# Forgeschrittene Themen

Java Standard: Applets
Für die Dateiverarbeitung gibt es in der J2SE zwei wesentliche Pakete:
* java.io als bereits unter Java 1.0 vorhandenes Paket und
* java.nio als Erweiterung von java.io um dessen Probleme zu beheben.
Dabei werden durch beide Pakete allgemeine Funktionalitäten bereitgestellt, welche über die "Datei"-Verarbeitung im eigentlichen Sinne hinausgehen. So basiert die Verarbeitung auf Datenströmen, wie sie durch eine Datei, eine Netzwerkverbindung oder z.B. auch über den Parallelport empfangen und/oder gesendet werden können.

## Überblick

In Java wird die Datenverarbeitung durch Datenströme (engl. Streams) realisiert. Zu diesem Zweck gibt es zwei Oberklassen, welche die Basisfunktionalitäten bereitstellen:
* InputStream für eingehende Daten und
* OutputStream für ausgehende Daten.
Die Daten können dabei als geordnete Folge von einzelnen Bytes angesehen werden. Um die verschiedenen Funktionalitäten abzubilden gibt es schließlich eine Reihe von Implementierungen, die diese Oberklassen erweitern.
Insbesondere für die Nutzung von Textdateien stehen zwei weitere wesentliche Klassen zur Verfügung:
* Reader für eingehende Daten und
* Writer für ausgehende Daten.
Reader und Writer arbeiten hierbei auf Basis von UNICODE und somit des Datentyps char welcher zwei (!) Bytes repräsentiert.

## InputStream

Der reine InputStream ist eine Abstrakte Java klasse. Von ihm werden folgende InputStreams abgeleitet:
* AudioInputStream
* ByteArrayInputStream
* FileInputStream
* FilterInputStream
    BufferedInputStream
    CheckedInputStream
    CipherInputStream
    DataInputStream
    DeflaterInputStream
    DigestInputStream
    InflaterInputStream
       GZIPInputStream
       ZipInputStream
    LineNumberInputStream
    ProgressMonitorInputStream
    PushbackInputStream
* ObjectInputStream
* PipedInputStream
* SequenceInputStream
* StringBufferInputStream
Der InputStream ist die Super Klasse und repräsentiert einen byte Strom. Die von ihm abgeleiteten Klassen sind auf bestimmte Bereiche spezialisiert, z.b. liest der ObjectInputStream Objekte für die Weiterverarbeitung ein.

## OutputStream

Genau wie der InputStream ist auch der OutputStream eine Abstrakte Klasse in Java. Von ihm werden folgende Ströme abgeleitet:
* ByteArrayOutputStream
* FileOutputStream
* FilterOutputStream
    BufferedOutputStream
    CheckedOutputStream
    CipherOutputStream
    DataOutputStream
    DeflaterOutputStream
       GZIPOutputStream
       ZipOutputStream
    DigestOutputStream
    InflaterOutputStream
    PrintStream
       LogStream
* ObjectOutputStream
* PipedOutputStream

## Reader

Abgeleitete Klassen von Reader:
* BufferedReader
    LineNumberReader
* CharArrayReader
* FilterReader
    PushbackReader
* InputStreamReader
    FileReader
* PipedReader
* StringReader

## Writer

Abgeleitete Klassen von Writer:
* BufferedWriter
* CharArrayWriter
* FilterWriter
* OutputStreamWriter
    FileWriter
* PipedWriter
* PrintWriter
* StringWriter

## Dateien und Java

Dateien sind in Java leider nicht ganz so einfach zu benutzen wie in C++ und Delphi. In Java laufen alle Ein- und Ausgaben über Streams, egal ob es sich nun um Lesen und Schreiben von Konsole oder in und aus Dateien handelt. Auf der einen Seite ist diese Vorgehensweise zwar für Einsteiger relativ umständlich, andererseits dafür aber auch sehr elegant, da sämtliche IO nach dem gleichen Prinzip läuft: egal ob Konsole, Dateien, Netzwerk oder Internet - alles wird genau gleich abgehandelt, nur die Namen der Klassen heißen anders.
Zum Einstieg sieht man hier ein kleines Programm, das eine Nachricht (einen String) in eine Textdatei schreibt. Dazu müssen drei Streams miteinander verkoppelt werden: nämlich FileOutputStream muss in einen OutputstreamWriter gepackt werden und dieser wieder in einem BufferedWriter. Das ganze muss natürlich in einem try..catch-Block passieren, da sich Java sonst weigert das Programm überhaupt zu übersetzen.

## Einleitung

Nebenläufigkeit (concurrency) ist die Fähigkeit eines Systems, zwei oder auch mehrere Aufgaben (scheinbar) gleichzeitig auszuführen. In Java kann die Ausführungsparallelität innerhalb eines Programmes mittels Threads (lightweight processes) erzwungen werden. Laufen mehrere Threads parallel, so spricht man auch von Multithreading.

## Threads erzeugen und starten

Threads sind Bestandteil des Java-Standardpackages java.lang.

### Methode 1: Die Thread-Klasse

Die Klasse Thread implementiert die Schnittstelle Runnable.
Prinzipielle Vorgehensweise:
* Eine Klasse, abgeleitet von Thread, erstellen
* Die Thread-Methode public void run überschreiben
* Instanz(en) der Thread-Subklasse bilden
* Die Thread-Instanz(en) mittels public void start starten
Beispiel:
oder

### Methode 2: Das Runnable-Interface

Prinzipielle Vorgehensweise:
* Eine Runnable implementierende Klasse erstellen
* Die Runnable-Methode public void run überschreiben
* Instanz(en) der Runnable implementierenden Klasse bilden
* Thread-Instanz(en) erstellen. Als Parameter wird eine Runnable-Instanz übergeben.
* Die Thread-Instanz(en) mittels public void start starten

## Der main-Thread

Jede Java-Applikation besitzt zumindest einen Thread, den main-Thread.
zeigt

## Thread-Zustände

Threads können in verschiedenen Zuständen vorliegen:
| Thread.State | Erläuterung |
| NEW | erzeugt, aber noch nicht gestartet |
| RUNNABLE | lauffähig; wird in der Java Virtual Machine (JVM) ausgeführt oder wartet auf die Freigabe von Ressourcen |
| BLOCKED | geblockt; wartet auf einen Monitor-Lock (siehe Synchronisation) |
| WAITING | wartet; das ist der Fall wenn eine der folgenden Methoden aufgerufen wurde: Object.wait(...) ohne Timeout Thread.join(...) ohne Timeout LockSupport.park |
| TIME_WAITING | wartet eine definierte Zeitspanne; das ist der Fall wenn eine der folgenden Methoden aufgerufen wurde: Thread.sleep(...) Object.wait(...) mit Timeout Thread.join(...) mit Timeout LockSupport.parkNanos(...) LockSupport.parkUntil(...) |
| TERMINATED | beendet; eine einmal beendete Thread-Instanz kann nicht mehr erneut gestartet werden |
Abfragen kann man den Thread-Zustand mit der bereits in vorhergehenden Abschnitt verwendeten Funktion
Thread.State.getState.

## Threads beenden
### Das stop-Chainsaw Massacre

Die Klasse Thread implementiert die Funktion void stop zur manuellen Beendigung eines Threads. Diese Funktion ist problembehaftet, daher als deprecated gekennzeichnet und soll nicht benutzt werden.

### Der run-Suizid

Implementiert man in der run-Methode keine Endlosschleife, dann löst sich das Problem durch Zeitablauf von selbst.
ergibt

### Referenz-Methode

Eine Variante der Flag-Methode ist hier angegeben. Sie benutzt kein Extra-Flag sondern stattdessen die Referenz zum Thread.

### Interrupt

Mit Hilfe der Thread-Methoden
void interrupt
und
boolean isInterrupted
können wir auch einen Thread beenden.

## Threads anhalten

Ein Thread kann mit den Funktionen
static void sleep(long millis)
static void sleep(long millis, int nanos)
für millis Millisekunden (+ nanos Nanosekunden) angehalten werden. Diese Funktion kennen wir schon aus früheren Codebeispielen.
Zusätzlich kann anderen wartenden Threads der Vortritt gewährt werden.
static void yield
zum temporären Pausieren des momentan ausgeführten Threads, um andere Threads ausführen zu können.
ergibt

## Auf das Ende eines Threads warten

void join
Warte auf das Ende eines Threads
void join(long millis)
void join(long millis, int nanos)
Warte längstens millis Millisekunden (+ nanos Nanosekunden) auf das Ende eines Threads. Übergibt man als Parameter 0, so bedeutet dies, dass beliebig lange auf das Ende des Threads gewartet wird.
ergibt

## Thread-Priorität

Durch Anwendung der Thread-Methode
void setPriority(int newPriority)
kann die Priorität eines Threads im Bereich von 1 (Thread.MIN_PRIORITY) bis 10 (Thread.MAX_PRIORITY) geändert werden. Ein Thread erhält zuerst immer die Priorität des Threads, in dem er gestartet wurde. Der main-Thread weist standardmäßig die Priorität 5 auf. Die konkrete Umsetzung der zugewiesenen Priorität hängt dabei sehr stark vom jeweiligen Betriebssystem ab.
Die Abfrage der momentanen Thread-Priorität geschieht mittels der Thread-Methode
int getPriority

## Scheduler

Die Ausführungsplanung zum Umschalten zwischen aktiven Threads und Prozessen nennt man Scheduling. Mögliche Scheduling-Strategien:
* Prioritätssteuerung (Preemption): Es wird immer der Thread mit der höchsten Priorität ausgeführt
* Zeitsteuerung (Time-Slicing): Der Scheduler weist den einzelnen Threads Zeitabschnitte zu, während der sie zur Ausführung gelangen
* Prioritäts- und Zeitsteuerung kombiniert

## Dämonen

Ein Dämon ist ein Thread der im Hintergrund ausgeführt wird. Mit der Thread-Methode
void setDaemon(boolean on)
kann zwischen den Thread-Typen Dämon-Thread (on = true) und konventionell im Vordergrund laufendem Thread (off = false) umgeschaltet werden.
Abfragen kann man den Thread-Typ mittels
boolean isDaemon
Nicht jeder Thread eignet sich zum Dämon-Thread. Es gilt folgende Regel: Eine Java-VM beendet sich, wenn keine Nicht-Dämon-Threads mehr laufen.
Ein prominenter Dämon ist übrigens der Garbage Collector - es würde auch wenig Sinn ergeben, wenn er weiter arbeiten würde, nachdem ein Programm zu Ende ist.

## Threadgruppen

Threads kann man auch gruppieren. Beim Start einer Applikation wird automatische eine main-Threadgruppe angelegt. Der main-Thread ist Teil dieser Gruppe. All Threads sind automatisch Bestandteil einer Threadgruppe.

## Threads synchronisieren
### Race Conditions

Definition (aus Wikipedia, der freien Enzyklopädie vom 27.08.2005):
Als Race Condition (zu deutsch Wettlaufsituation oder Wettkampfbedingung) bezeichnen Programmierer Konstellationen, in denen das Ergebnis einer Operation vom zeitlichen Verhalten bestimmter Einzeloperationen abhängt. Unbeabsichtigte Race Conditions sind ein häufiger Grund für schwer auffindbare Programmfehler, so genannte Heisenbugs. ...
Genau solche Race Conditions können auch bei Threads vorkommen. Greifen mehrere Threads auf bestimmte Ressourcen (Dateien, Variablen, Datenbanken, Drucker, etc.) zu, so kann sich der Programmierer nicht darauf verlassen, dass die Threads dies immer in einer bestimmten Reihenfolge und kollisionsfrei tun. Das hängt auch von Faktoren ab, die der Programmierer nicht beeinflussen kann, zum Beispiel der Scheduling-Strategie oder der konkreten Umsetzung der gewünschten Thread-Priorität.
Deshalb muss eine Programmiersprache Mechanismen bereitstellen, um derartige Probleme zu lösen. Eine Methode wird als thread-sicher bezeichnet, wenn sie bedenkenlos von Threads aufgerufen werden kann.

### Atomare Operationen

Definition (aus Wikipedia, der freien Enzyklopädie vom 27.08.2005):
Eine Atomare Operation [...] bezeichnet eine Operation im Computer, welche durch keine andere Operation unterbrochen werden kann. Atomare Operationen sind wichtig beim Synchronisieren von Daten. ...
Auch diesen Aspekt muss man beim Programmieren mit Threads beachten (Stichwort: Transaktionen bei Datenbanken).
Selbst bei einfachen Variablen kann man sich nicht auf atomares Verhalten verlassen. Um sicherzustellen, dass Objekt- oder Klassenvariablen vor jedem Zugriff auf den aktuellen Stand gebracht werden verwendet man das Schlüsselwort volatile (flüchtig, launisch, unbeständig).

### Das Schlüsselwort synchronized

Greifen mehrere Threads auf dieselben Ressourcen zu, so kann es zwecks Problemvermeidung notwendig sein Threads zu synchronisieren.
Eine Methode können wir durch das Schlüsselwort synchronized kennzeichnen
Die VM wird diese Methode nun bei Bedarf automatisch sperren und entsperren.
Auch einzelne Code-Blöcke können synchronisiert werden

### Monitore

Die JVM definiert für Synchronisationszwecke sogenannte Monitore. Jedes Objekt mit synchronisiertem Code ist in Java ein Monitor. Dieser Monitor besitzt einen Monitor-Lock (Lock, Sperre) und führt eine Warteliste von Threads die ausgesperrt wurden. Beendet ein Thread eine synchronized-Methode oder einen synchronized-Block, so wird die Sperre aufgehoben und der nächste Thread kommt zum Zug. Der Aufruf von sleep oder yield hebt eine solche Sperre allerdings nicht auf.

### Deadlocks

Ein Problem bei Synchronisation können sogenannte Deadlocks (Verklemmungen) darstellen. Dabei sperren sich zwei oder mehrere Threads gleichzeitig von benötigten Ressourcen aus. Thread A wartet darauf, dass Thread B eine Ressource freigibt. Gleichzeitig wartet aber Thread B, dass Thread A seine gesperrte Ressource freigibt. Setzt man im Vorfeld keine geeigneten Maßnahmen, dann werden die beiden Threads ewig warten und mit den Threads auch der genervte und ratlose Programmbenutzer.
Zur Erkennung von Deadlock-Situationen können Deadlock-Detection-Utilities hilfreich sein. Aktuelle Java-Releases und auch IDEs wie zum Beispiel Eclipse 3.1 bieten derartige Möglichkeiten.

### Das wait-notify-Konzept

Mit Hilfe der Object-Methode
können Threads in einen Wartezustand versetzt werden. Sie geben dann den Monitor frei.
Besitzt ein Thread den Monitor eines Objektes, so kann er durch
oder
wartende Threads benachrichtigen und aus dem Wartezustand erlösen.

## Concurrent-Programming ab Java 5.0

Ab Java 5.0 werden in den Packages
* java.util.concurrent
* java.util.concurrent.atomic
* java.util.concurrent.locks
zusätzlich zur konventionellen Thread-Programmierung weitere Möglichkeiten für nebenläufiges Programmieren bereitgestellt. Nachfolgend werden einführend in diese Thematik ganz kurz ein paar Klassen und Möglichkeiten dieser Pakete angesprochen.

### Callable

Das Interface Callable<> dient ähnlichen Zwecken wie das Interface Runnable, ist aber ein bisschen flexibler. Außerdem ist anstelle der run-Methode die call-Methode zu implementieren .

### Executors

Die Klasse Executors enthält Fabriks- und Hilfsmethoden für
* Callable
* Executor
* ExecutorService
* ScheduledExecutorService
* ThreadFactory

### Future und FutureTask

Die Schnittstelle Future<> implementiert Runnable. Die Klasse FutureTask<> implementiert Future<>.

### Thread-Pools

Zwecks optimaler Performance kann die Kreierung von Thread-Pools sinnvoll sein. Thread-Pools fassen Threads zu gemanagten Kollektionen zusammen.

## Zeitgesteuerte Task-Ausführung

TimerTask implementiert Runnable und kann ein- oder mehrmalig durch einen Timer ausgeführt werden.
Die schedule-Methode gibt es mit unterschiedlichen Signaturen. Im Beispiel wurde eine Initialverzögerung (delay) von 1000ms und eine Wiederholung (period) alle 2000ms gewählt.
Java Standard: Threads Grundlagen Java Standard: Threads Runnable
Das Paket java.util beinhaltet zahlreiche Klassen und Interfaces für alltägliche Aufgaben und ist für Sie als eine Art Werkzeugladen zu betrachten. Dabei werden Klassen für die Zeichenkettenbearbeitung, für die Datumsverarbeitung, für die Generierung von "Zufällen", die Komprimierung und nicht zu vergessen für die Datenhaltung zur Laufzeit bereitgestellt. Auch die Logging-API ist unterhalb von java.util angesiedelt.
Für die Erstellung von grafischen Oberflächen stehen verschiedene APIs zur Verfügung.
* Das Graphics Object – Wer es gern etwas aufwendiger mag, darf seine Oberflächen auch selbst programmieren. Hierfür gibt es das Graphics bzw. Graphics2D Objekt.
* AWT – Das Abstract Window Toolkit (AWT) als Implementation einer plattformspezifischen aber -unabhängigen Oberfläche ist im Java Software Development Kit der Standard Edition enthalten.
* Swing – Swing als plattformunspezifische und -unabhängige Oberfläche ist im Java Software Development Kit [JDK] der Standard Edition ab Version 1.2 bzw. Java 2 enthalten.
* SWT – Das Standard Widget Toolkit (SWT) ist eine plattformabhängige Oberflächen-API.
* Java3D – Die Java3D-API steht alternativ für 3D-Oberflächen zur Verfügung.
Siehe auch Wikipedia:
* AWT Abstract Window Toolkit
* Swing Swing
* SWT Standard Widget Toolkit

### Einführung

Die Schnittstelle, um graphische Objekte wie Shapes, oder aber auch Bilder zu zeichnen, ist in Java das Graphics-Objekt. Dieses ist seit der Version 1.0 im JDK enthalten, mit der Version 1.2 ist das Graphics2D Objekt hinzugefügt worden.
Beginnen wir mit einem Beispiel. Die einfachste Variante, um mal einige Erfahrungen mit Graphics zu sammeln, ist die paint(Graphics g) Methode von dem JFrame.
Als erstes legen wir einen Nachfahren von JFrame an, welcher die Methode überschreibt:
Nun wird noch ein wenig Start-Up Code benötigt, welcher das Fenster erzeugt und anzeigt:

### Aufbau des Bildschirms

Der Bildschirm hat den Aufbau eines Rasters, wobei die einzelnen Punkte Pixel genannt werden. Der Punkt 0,0 des Rasters ist die linke obere Ecke des Bildschirms. Wenn ein Objekt auf dem Bildschirm gezeichnet werden soll, muss man die Koordinaten dafür angeben:
Am Punkt 10,40 wird nun begonnen, das Objekt zu zeichnen. Der Punkt 10,40 ist dabei der linke obere Punkt des zu zeichnenden Objektes.

### Aufbau des Graphics

Der Bildschirm oder auch der Drucker, wird in Java der Device Space genannt, das Gegenstück ist der User Space. Wenn mittels Graphics gezeichnet wird, wird auf dem User Space gezeichnet. Der User Space ist eine abstrakte Zeichnungsebene, auf der ohne Gedanken an das Endgerät (Monitor oder Drucker) gezeichnet werden kann. Aus diesem Grund wird der User Space nicht in Pixel sondern in Units unterteilt. 72 Units bilden einen Inch. Java konvertiert während des Renderns vom User Space in den Device Space.

### Einfache Beispiele
#### Linien

Versuchen wir nun eine einfache Linie zu zeichnen. Dazu verwenden wir obigen Code und bauen ihn entsprechend um:
In SimpleFrame deaktivieren wir die Titelleiste, so lässt sich das Frame einfacher als Zeichenfläche gebrauchen:
Wie Sie vielleicht gemerkt haben, besitzen die Java2D Klassen wie Line2D keinen öffentlichen Konstruktor. Sie müssen statt dessen eine der inneren Klassen instanziieren - in diesem Fall Double.

#### Rechtecke

Rechtecke werden mit drawRect, fillRect, drawRoundRect oder fillRoundRect gezeichnet.
Das Abstract Window Toolkit [AWT] ist eine API zum Entwickeln quasi-plattformunabhängiger grafischer Oberflächen mit Java. Diese "Plattformunabhängigkeit" wurde erreicht, indem komplexere Oberflächenelemente wie Bäume und Tabellen, welche nicht auf allen Betriebssystemen vorhanden sind, nicht in das AWT aufgenommen wurden. Diese Beschränkungen können Sie umgehen, indem Sie die seit Java 1.2 im J2SE enthaltenen Swing Komponenten verwenden.
Für die Entwickler von Applets ist das AWT vielfach jedoch noch der kleinste gemeinsame Nenner, da alle heute gängigen Browser lediglich den Java 1.1 Standard beherrschen.

## Grafische Komponenten

AWT-Komponenten sind entweder im Package java.awt oder in den dazugehörenden Subpackages zu finden.

### Fenster mit Rahmen

Die Klasse Window repräsentiert ein Fenster ohne Rahmen und ohne Menüleiste. Frame ist eine Subklasse von Window und beinhaltet Fensterrahmen und die Möglichkeit eine Menüleiste einzubinden.
Beispiel:

### Menüs

Für die Erstellung von Menüs sind folgende wesentliche Java-AWT-Klassen notwendig:
* MenuBar - die Menüleiste, wie sie auch in Ihrem Browser zu finden ist
* Menu - ist ein Menü oder Untermenü (z.B. "Datei")
* MenuItem - ist ein Menüeintrag (z.B. "Neues Fenster")
Um Untermenüs zu erzeugen, fügen Sie das Untermenü dem Menü mit der Methode add (MenuItem) hinzu.
Beispiel:

### Schaltflächen

AWT-Schaltflächen sind durch die Klasse Button zu erstellen.
Beispiel:

### Beschriftungen

Beschriftungen können Sie mit Label generieren. Positionieren können Sie die Beschriftungen über die Methode void setAlignment(int alignment) mit den Konstanten
* Label.LEFT
* Label.CENTER
* Label.RIGHT

### Texteingabefelder
#### Einzeilig

Einzeilige Texteingabefelder lassen sich mit der Klasse TextField erstellen. Den Inhalt eines Texteingabefeldes können Sie mittels der Methode String getText auslesen. Zum Zwecke der Erstellung von Passworteingabefeldern lässt sich die Anzeige des Eingabetextes durch die Methode void setEchoChar(char c) maskieren.
Beispiel:

#### Mehrzeilig

Mehrzeilige Texteingabefelder können Sie mit der Klasse TextArea erstellen. Auch diese Klasse implementiert bzw. erbt eine Vielzahl von Methoden durch welche sie das Erscheinungsbild anpassen und Text setzen oder abfragen können.
Beispiel:

### Kontrollkästchen (Checkboxes) und Optionsfelder (Radiobuttons)

Zur Erstellung von Kontrollkästchen dient die Klasse Checkbox. Mittels boolean getState ist der Zustand einer Checkbox abfragbar. Durch eine Zusammenfassung mehrerer Checkboxes in einer CheckboxGroup sind auch Radiobuttons realisierbar.
Beispiele:

### Aufklappbare Auswahlliste (Choice)

Ein Choice ist eine ausklappbarer Auswahlliste. Die momentane aktive Auswahl wird auch im eingeklappten Zustand angezeigt. Die Funktion eines Choice ist vergleichbar mit einer Gruppe von Radiobuttons. Durch die Methode void add(String item) lassen sich Strings in die Auswahlliste eingefügen. Die momentan gewählte Option lässt sich durch die Methode int getSelectedIndex oder String getSelectedItem abfragen.
Beispiel:

### Auswahlliste (List)

Eine weitere Möglichkeit zur Selektion verschiedener Optionswerte bietet die List (nicht zu verwechseln mit dem Kollektions-Interface java.util.List). Bei einer List ist im Gegensatz zum/zur Choice standardmäßig keine Vorauswahl getroffen. Ein Listeneintrag kann aber mittels der Methode void select(int index) vorausgewählt werden. In einer Auswahlliste können mehrere Einträge ausgewählt werden (Multiselektion), wenn ein derartiges Verhalten vom Programmierer über den List-Konstruktor oder die Methode void setMultipleMode(boolean b) vorgesehen wird.
Beispiel:

### Panel

Ein Panel ist eine simple Containerklasse zur Aufnahme anderer AWT-Komponenten. Besonders im Zusammenhang mit komplexeren AWT-GUI-Layouts ist der Einsatz der Klasse Panel im Zusammenwirken mit Layout-Managern unverzichtbar. Auch als "Zeichenfläche" eignet sich ein Panel. Panel-Konstruktoren sind Panel und Panel(LayoutManager layout) . AWT-Komponenten werden mit diversen add-Methoden zu einem Panel hinzugefügt. Applet ist eine Panel-Subklasse.
Beispiel 1:
Beispiel 2:

### Canvas

Ein Canvas ist eine leere AWT-Komponente ohne Grundfunktionalität. Ein Canvas kann wie ein Panel als reine "Zeichenfläche" verwendet werden oder als Grundlage für die Erstellung eigener AWT-Komponenten dienen.

### ScrollPane

Eine ScrollPane ist ein Container zur Aufnahme einer AWT-Komponente. Eine ScrollPane bietet vertikale und horizontale Scrollbars. Wann und wie diese Scrollbars erscheinen, kann vom Programmierer festgelegt werden (SCROLLBARS_ALWAYS, SCROLLBARS_AS_NEEDED, SCROLLBARS_NEVER ). Des Weiteren kann auch das Verhalten der Scrollbars beinflusst werden (z.B. ob Scrolling auch mit dem Mausrad möglich sein soll oder die initiale Scrollposition).
Beispiel:

### Dialoge

Dialog ist eine Window-Subklasse. Dialoge können modal oder nichtmodal sein. Ein Dialog wird immer mit einem Konstruktor erstellt, dem als erster Parameter ein Frame, ein anderer Dialog oder nullübergeben wird. Sinnvollerweise wird die Klasse Dialog für Benutzereingaben, Meldungsfenster, About-Dialoge oder dergleichen genutzt.

#### Dateiauswahldialog

Mit der Klasse FileDialog lässt sich sehr einfach ein modaler Dateiauswahldialog generieren.
Beispiel:

## Layoutmanager

Die Layoutmanager für AWT und Swing werden in dem Kapitel Swing: Layoutmanager behandelt.

### FlowLayout

Beispiel zum FlowLayout:

### BorderLayout

Dieses Layout platziert Komponenten in 5 möglichen Bereichen: oben, unten, links, rechts, zentriert.
Beispiel zum BorderLayout:

### GridLayout

Beispiel zum GridLayout:

### GridBagLayout

Das GridBagLayout ist ein komplexer LayoutManager2, mit welchem eine Menge an Möglichkeiten geboten werden. Die eigentliche Ausrichtigung der Komponenten erfolgt über das GridBagConstraints Objekt, welches beim Hinzufügen zum Container anzugeben ist.
Beispiel zum GridBagLayout:

### NullLayout

Ein NullLayout ist im eigentlichen Sinne kein Layout. Hierbei können die Elemente frei, mittels Positionsangaben, auf der Oberfläche positioniert werden.
Beispiel zum "Null-Layout":

## Ereignisse

Damit AWT-Komponenten nicht nur mäßig schön am Bildschirm erstrahlen, sondern auch Funktionalität aufweisen, müssen sie auf Benutzeraktionen reagieren können.
Das Ereignis-Delegations-Modell (Event Delegation Model, Delegation Based Event Handling) ab Java 1.1 basiert auf dem Prinzip des Beobachter-Entwurfsmusters (Observer Pattern).
Was ein Beobachter-Entwurfsmusters ist, kann folgenden Quellen entnommen werden:
* Beobachter (Entwurfsmuster)
* In diesem Buch in dem Kapitel Muster Observer
* Wikibooks: (Entwurfs) Muster, Kapitel Muster: Observer
Jede AWT-Komponente kann Ereignisquelle sein. Jedes Objekt kann Ereignisempfänger sein. Damit ein Objekt Ereignisse empfangen kann, muss es bei einer Ereignisquelle als Ereignisempfänger registriert werden.

### AWT-Ereignisse

AWT-Komponenten, als Ereignisquellen, reagieren auf externe Aktivitäten (z.B. Tastendruck, Mausbewegung, Mausklick) mit der Konstruktion von Ereignis-Objekten. Je nach Typ der Aktivität wird ein geeignetes Objekt erzeugt. Nachfolgendes Bild zeigt ein Klassendiagramm (basierend auf der Java 2 SE 5.0-API-Dokumentation), aus dem diese Ereignis-Objekte generiert werden. Alle möglichen AWT-Ereignisse sind Subklassen der abstrakten Klasse AWTEvent. Auch zusätzliche Swing-Events werden von dieser Klasse abgeleitet.

### Ereignisempfänger (EventListener)

Als Ereignisempfänger bietet das Package java.awt.event verschiedene EventListener-Interfaces. Diese Ereignisempfänger werden bei der das Ereignis auslösenden AWT-Komponente registriert. Zu diesem Zweck besitzen die AWT-Komponenten geeignete add<X>Listener-Methoden. Für manche Listener-Interfaces existieren Adapter-Klassen. Diese implementieren das entsprechende Interface mit leeren Funktionsrümpfen.
Beispiel: Schaltflächen lösen beim Anklicken ein ActionEvent aus. Der Ereignisempfänger ist vom Typ ActionListener. Die Methode zum Registrieren dieses Ereignisempfänger heißt void addActionListener(ActionListener l). Das entsprechende Implementierungsbeispiel wurde bereits im Absatz Schaltflächen gezeigt.

### Ereignisempfänger (EventAdapter)

Die Ereignisempfänger (EventListener) sind Interfaces. Dem großen Vorteil, die Problematik der nicht vorhandenen Mehrfachvererbung umgangen zu haben, steht somit (leider) der erhöhte Implementierungsaufwand entgegen. Um dieses Ärgernis zu Umgehen hat Sun netterweise sogenannte Adapterklassen bereitgestellt. Diese enthalten eine leere Defaultimplementation aller zu überschreibenen Methoden (siehe NullPattern). Lediglich für den ActionListener gibt es keinen Adapter - nunja dort gibt es auch nur eine Methode zu überschreiben.
Mit Swing hat Sun Microsystems eine API (Application Programming Interface, zu Deutsch Programmierschnittstelle) geschaffen um den Beschränkungen des AWT zu entkommen. Hierdurch können auch komplexe grafische Oberflächen wie Bäume oder Tabellen Verwendung finden. Swing - seit Java 1.2 zu finden im Paket javax.swing - benutzt hierbei jedoch zahlreiche Funktionalitäten des java.awt Paket so dass Vorkenntnisse im Bereich AWT sinnvoll sind.

### Top-Level Container

* JFrame
* JDialog
** JOptionPane
* JApplet

### Leichtgewichtige Container

* JComponent
* JPanel
* JDesktopPane
* JInternalFrame
* JLayeredPane
* JScrollPane
* JSplitPane
* JTabbedPane
* JToolBar

### Kontrollelemente

* Controls
** JButton
** AbstractButton
** JToggleButton
** JCheckBox
** JRadioButton
** ButtonGroup
** JScrollBar
** JSlider
** JSpinner
** JComboBox
* Menus
** JMenuBar
** JMenuItem
** JMenu
** JCheckBoxMenuItem
** JRadioButtonMenuItem
** JPopupMenu
** JToolBar
** JTree
** JSeparator

### Anzeigenelemente (Ausgabe)

* JLabel
* Icon
* ImageIcon
* JToolTip
* JProgressBar

### Textverarbeitung (Ein- und Ausgabe)

* JTextComponent
* JTextField
* JTable
* JTextArea
* JPasswordField
* JFormattedTextField
* JTextPane
* JEditorPane
* JList

### LayoutManager

* BorderLayout
* FlowLayout
* ViewportLayout
* GridLayout
* GroupLayout
* ScrollPaneLayout
* GridBagLayout
* CardLayout
* BoxLayout
* OverlayLayout
* SpringLayout
* "NullLayout"

## Grafische Oberflächenelemente
### Icon

Icon ist eine grafische Komponente für die Anzeige von - meist kleinen - Bildern.

#### ImageIcon

ImageIcon ist eine direkte Unterklasse von Icon.

### JLabel

JLabel als äquivalent zu java.awt.Label und stellt eine "einfache" Beschriftung dar, welche optional um ein Icon erweitert werden kann. Eine JLabel Instanz kann hierbei einer anderen Komponente als Beschriftung über die Methode setLabelFor (JComponent) zugewiesen werden.

### AbstractButton

Mit AbstractButton werden die allgemeinen Eigenschaften von Schaltflächen bereitgestellt. Hierzu gehören:
* setMnemonic zur Definition des Buchstabens über den per Tastatur die Schaltfläche aktiviert werden kann.
* doClick zur Aktivierung der Schaltfläche ohne Benutzerinteraktion
* setIcon um ein Bild der Schaltfläche hinzuzufügen. Hierzu kommen noch die Methoden setDisabledIcon, setSelectedIcon, setRolloverIcon, setDisabledSelectionIcon und setRolloverSelectedIcon zur genauen Steuerung.

#### JButton

Der Typ JButton ist die Implementierung für eine "normale" Schaltfläche. Auf die Betätigung der Schaltfläche kann über einen ActionListener bzw. ein Action Objekt reagiert werden.

#### JToggleButton

Ein JToggleButton ist eine Schaltfläche, welche beim ersten Betätigen aktiviert wird und ein zweites gesondertes Betätigen zur Deaktivierung benötigt.

### JCheckBox

Eine JCheckBox ist ein Auswahlfeld, welches an- und ausgeschaltet werden kann.

### JRadioButton

Ein JRadioButton ist ein Auswahlfeld, welches an- und ausgeschaltet werden kann. JRadioButtons werden hierbei üblicherweise nur in Verbindung mit einer ButtonGroup verwendet.

### ButtonGroup

Eine ButtonGroup dient dazu insbesonder RadioButtons zusammenzufassen, so dass nur eine JRadioButton aktiv ist.

### Border

Bei einem Border handelt es sich um einen Rahmen, der um beliebige andere grafische Komponenten gelegt werden kann.

### JToolTip

Bei einem JToolTip handelt es sich um Tooltip-Element, wie man es von verschiedenen Programmen kennt. Es zeigt nach kurzem Zeitraum eine kurze Hilfe zu einem bestimmten Element an.

### JTextComponent
#### JTextField

und JTextField erzeugt ein Textfeld

#### JPasswordField

Das JPasswordField ist ein spezielles JTextField, welches die Zeichen nicht auf dem Bildschirm darstellt, sondern ein alternatives Zeichen zeigt, das so genannte Echozeichen. Standardmäßig ist das ein Sternchen. So lassen sich Passwort-Felder anlegen, die eine Eingabe verbergen.

#### JFormattedTextField

Das formatierte Eingabefeld dient dazu, Eingaben nur in einer bestimmten vorgegebenen Form zuzulassen. Im Gegensatz zu anderen Sprachen werden dabei die fest definierten Zeichen mit als Inhalt zurückgegeben. Eine einfache Möglichkeit, Formatierungen vorzugeben ist der MaskFormatter.

#### JTextPane

JTextPane erzeugt einen Textcontainer, der nur dazu da ist, mit Text gefüllt zu werden. Der in ihm enthaltene Text ist nicht editierbar.

#### JEditorPane

Mit Hilfe des JEditorPane kann ein bereits formatierter Text editiert werden. Das JEditorPane unterstützt als Formate RTF (Rich Text Format) und HTML.

### JProgressBar

Mit der JProgressBar lässt sich der Fortschritt einer Aktion visualisieren. Bei der Instanziierung wird eine Unter- und Obergrenze angegeben. Innerhalb der Aktion, deren Fortschritt visualisiert werden soll, muss der aktuelle Wert der JProgressBar in bestimmten Abständen inkrementiert werden.

### JComboBox

Die JComboBox beinhaltet verschiedene Einträge, die angewählt werden können.

### JList

Das JList-Element beinhaltet eine Liste von Einträgen, die, wie in der JComboBox, angewählt werden können.

### JMenuBar

In Swing können alle Hauptfenster mit Ausnahme von JWindow eine Menüleiste haben. Dabei handelt es sich um eine Instanz der Klasse JMenuBar, die dem Hauptfenster durch Aufruf von addJMenuBar hinzugefügt wird.

### JMenuItem

Ein einzelnes Element innerhalb eines JMenu, beispielsweise "Datei-Drucken".

### JMenu

Dient als Container für JMenuItems und JSeparators.

### JCheckBoxMenuItem

Hat gegenüber dem JMenuItem den Vorteil, dass ein Haken beim aktuellen Status erscheint. Die entsprechenden Methoden sind: isSelected und setSelected

### JSeparator

Die einzelnen Elemente eines JMenu können mit dem JSeparator in logische Gruppierungen unterteilt werden. Es handelt sich um eine Trennlinie.

### JPopupMenu

Ein JPopupMenu wird meist als Kontextmenü genutzt und entsprechend z.B. über die Maus oder Tastatur aktiviert.

### JToolBar

Eine Toolbar kann man vereinfacht als die kleinen Leisten mit Bildchen beschreiben, wie man sie in nahezu jeder Textverarbeitung sieht.

### JTabbedPane

JTabbedPane ermöglicht das Aufteilen der grafischen Oberfläche über sog. Reiter. Diese können beliebig positioniert und auch mit Icons versehen werden.
Codebeispiel

### JSplitPane

JSplitPane ermöglicht die Aufteilung der grafischen Oberflächen in zwei Bereiche, wahlweise horizontal oder vertikal. Standardmässig kann der Anwender hierbei die Größen der zwei Komponenten der JSplitPanel beliebig in Ihrer Größe ändern.

### JTable

Eine JTable ermöglicht eine grafische Tabelle, optional auch mit Tabellenkopf.

#### Beispiel
### JTree

Swing stellt eine Komponente für die Darstellung von Baumstrukturen zur Verfügung - JTree.

## Layoutmanager
### BorderLayout

Dieses Layout platziert Komponenten in 5 möglichen Bereichen: oben, unten, links, rechts, zentriert.
Beispiel zum BorderLayout:

### FlowLayout

Durch die Verwendung eines FlowLayouts werden alle GUI-Komponenten in eine Zeile der Reihe nach angehängt, bis diese durch deren Größe nicht mehr positioniert werden können. Sollte dies der Fall sein, so werden die folgenden Komponenten in die nächste Zeile versetzt. Beim FlowLayout kann jedoch kein Platz zwischen den einzelnen Grafikobjekten freigelassen werden (in der Hinsicht auf die Positionierung anderer Komponenten).

### GridLayout

Dieses Layout bildet ein Gitter, dessen Zellen alle gleich groß sind. Die Anzahl der Spalten und Reihen, die dieses Gitter enthalten soll, kann spezifiziert werden. Pro Zelle kann dann genau eine Komponente zum Layout hinzugefügt werden. Die Komponenten werden in ihrer Größe gestreckt, damit sie die ganze Zelle ausfüllen. Außerdem kann ein horizontaler und vertikaler Abstand zwischen den einzelnen Zellen in Pixeln angegeben werden.
Beispiel zum GridLayout:

### ScrollPaneLayout

Für gewöhnlich wird dieses Layout nie explizit benutzt. Stattdessen erzeugt man ein ScrollPanel, welches sich dann automatisch dieses Layout setzt, um die ScrollBars, die Eckkomponenten, den Inhalt und die Zeilen- und Spaltenheader zu setzen.

### GridBagLayout

Das GridBagLayout ist ein komplexer LayoutManager2, mit welchem eine Menge an Möglichkeiten geboten werden. Die eigentliche Ausrichtigung der Komponenten erfolgt über das GridBagConstraints Objekt, welches beim Hinzufügen zum Container anzugeben ist.
Beispiel zum GridBagLayout:

### CardLayout

Ein Layout, vergleichbar mit Karteikarten.

### BoxLayout

* LINE_AXIS
* PAGE_AXIS
* X_AXIS
* Y_AXIS

### OverlayLayout

Mit dem OverlayLayout ist es möglich mehrere Componenten übereinander anzuordnen.

### "NullLayout"

Ein NullLayout ist im eigentlichen Sinne kein Layout. Hierbei können die Elemente frei, mittels Positionsangaben, auf der Oberfläche positioniert werden. Beispiel zum "Null-Layout":

## Aktionen

Über die grafische Benutzeroberfläche setzt der Anwender Befehle zur Durchführung von Aktionen ab. Hierzu unterstützt Swing unter anderem Tastatur und Maus als Eingabegeräte. Die Ereignisse werden über Swing's Event Dispatch Thread an die für ein bestimmtes Ereignis (Event) registrierten Empfänger (EventListener) weitergeleitet. Einige Elemente von Swing, z. B. JMenuItem und JButton können hierbei die Low Level Events wie Mouse Clicked automatisch in semantisch höherwertige Semantic Events (z. B. ActionEvent) übersetzen welche dann wiederum durch den EDT an die jeweiligen Empfänger (ActionListener) weitergeleitet werden.
Um dem Programmierer die Nutzung von ActionEvents zu vereinfachen, unterstützt Swing daher mit dem Interface Action sowie dessen abstrakter Implementierung AbstractAction das sogenannte Command Pattern.
Damit der EDT nicht durch langwierige Operationen blockiert wird und die Oberfläche "hängt" (vgl. Responsiveness), ist es eine übliche Vorgehensweise, die langwierige Arbeit in einem Worker Thread durchzuführen. Hierzu bietet Swing die Klasse SwingWorker. Diese nimmt dem Programmierer die Koordination des EDT mit dem Worker Thread weitgehend ab.
Die 3D-Programmierung läßt das Herz jedes Spielers höher schlagen. Endlich einmal ein eigenes Spiel realisieren und Freunde damit tief beeindrucken. Java bietet dazu sowohl Highlevel APIs wie Java3D an aber auch Lowlevel APIs wie OpenGL JOGL an. Der Unterschied zwischen beiden ist die Herangehensweise: OpenGL ist vergleichbar mit einem Assembler für Graphik. Es kennt nur Punkte, Linien, Dreiecke und einfache Polygone sowie Vektoren und Matrizen für die Transformationen. Man ist gezwungen alles von Hand zu machen, dafür ist die Anwendung aber auch sehr performant. Es ist sogar möglich die Graphikhardware direkt mittels Vertex- und Pixelshadern zu programmieren. Java3D benutzt dagegen einen Szenengraphen zur Organisation der Szene. Mit dieser baumartigen Struktur kann man sehr einfach und übersichtlich neue Körper, Sounds oder Animationen in die Szene integrieren und miteinander interagieren lassen. Die Highlevel APIs verwenden die Lowlevel APIs zum Rendering.

## Download

Bevor Sie mit Java3D arbeiten können, müssen Sie dieses herunterladen: http://java3d.java.net/binary-builds.html
Am besten laden Sie sich das ZIP-Archiv herunter und entpacken Sie es in Ihren Classpath.

## Grundlegendes

Java3D ist eine Highlevel 3D-Graphik-API und wurde 1997 von SUN, HP und SGI initiiert. Im Gegensatz zu OpenGL und DirectX verwendet Java3D einen Szenengraphen zur Verwaltung der 3D-Objekte und benutzt lowlevel Rendering-APIs, wie OpenGL und DirectX, zum Darstellen der 3D-Objekte. Vom Szenengraphen her ähnelt Java3D stark VRML2, allerdings sind die Events zwischen den Objekten nicht als ROUTES sondern als spezielle Java-Events realisiert. Wie VRML2 ist Java3D nicht nur in der Lage zu 3D-Objekte darzustellen, sondern kann auch Sound, Verhalten, Animationen und unkonventionelle Eingabe- und Ausgabegeräte managen. 3D-Objekte müssen nicht in Java3D Geometrieformat abgelegt sein - es gibt auch eine ganze Anzahl von Loadern für verschiedene 3D-Formate wie OBJ, WRL, 3DS oder DXF.
Java3D wird nicht mit den offiziellen Java SDK- oder JRE-Releases ausgeliefert. Aus diesem Grund muß Java3D manuell ins Java-System eingebunden werden.
Das Programmieren in Java3D ist erst einmal gar nicht so einfach, da man verschiedene Dinge braucht um überhaupt etwas angezeigt zu bekommen:
* einen leeren Szenengraphen (VirtualUniverse)
* ein Fenster zum Rendern (Frame + 3D-Canvas)
* ein Objekt zum Anzeigen (z.B. eine farbige Box)
* eine Lichtquelle - damit man die Kiste überhaupt sehen kann (ist in unserem Beispiel schon in die ColorBox integriert)
* einen Betrachter mit Standort und Blickrichtung (Sie sind ja jetzt in 3D)
* eine BoundingSphere (Hüllkugel), da Java3D so auf Optimierung aus ist, daß nur Dinge, die in der aktuellen Szene (sprich: der BoundingSphere) enthalten sind überhaupt gezeichnet werden. Andere Optimierungsschritte sind z.B. das Setzen der Capability-Bits in der Transformgruppe, da zur Laufzeit nur Dinge verändert werden können (z.B. mittels Animation), deren Capability-Bits vorher gesetzt wurden.
Man teilt die Bestandteile nun in Content-Branch (alles was angezeigt werden soll, sprich: Lichtquelle und Box) und View-Branch (die Beschreibung eines virtuellen Betrachters und die Umsetzung auf den Rendercanvas und den Frame) ein. Das hört sich zuerst einmal relativ aufwendig an, ermöglicht aber später die einfache und elegante Erweiterung um mehrere "Levels" als Content-Braches und mehrere "Spieler" als View-Branches.
Das erste Beispiel besteht nun aus drei Teilen:
* createScenegraph: baut den Content-Branch auf (Colorbox + Animation + Transformation)
* HelloWorld: Konstruktor - baut den View-Branch (vordefiniertes SimpleUniverse) auf und integriert den Content-Branch aus createSceneGraph
* main-Methode: ruft den Konstruktor HelloWorld im Fenster MainFrame auf (dieses läßt sich als Applet oder als Application betreiben)
Ein erstes Beispiel (eine bunte Kiste mit eingebauter Lichtquelle) könnte nun so aussehen:
Nun ein Beispiel mit Mausnavigation und einer weissen Box, die man mit der Maus drehen kann. Dazu wird im Unterschied zum ersten Beispiel einfach die Methode createSceneGraph angepaßt. Damit Java3D das MouseBehavior und die Box kennt muß es noch oben in die import-Liste eingetragen werden mittels:

## Einleitung

OpenGL JOGL

## Grundlegendes

JOGL wird nicht mit den offiziellen Java SDK- oder JRE-Releases ausgeliefert. Aus diesem Grund muss JOGL manuell ins Java-System eingebunden werden.

### Download der Jogl-Bibliothek

Auf der JOGL-Website finden sich für verschiedene Betriebssysteme und Prozessoren vorkompilierte jogl-Bibliotheken. Zusätzlich stehen dort auch die API-Manuals, sowie die Quellcode-Dateien zum Download bereit.

### Entpacken

Entpacken der plattformabhängigen Datei, z.B.: unzip jogl-x.y.z-linux-i586.zip

### Einbinden

Um diese Bibliotheken nun in das Java-System einzubinden gibt es mehrere Möglichkeiten. Prinzipiell gilt:
* Die Dateien jogl.jar und gluegen-rt.jar müssen in den CLASSPATH eingebunden werden.
* Die nativen Bibliotheksdateien (libjogl_cg.so, libjogl.so, libjogl_awt.so ) müssen im java.library.path gefunden werden, sonst hagelt es bei der Programmausführung nur Laufzeitfehler.
Wie sie das bewerkstelligen, bleibt ihnen überlassen. In manchen Tutorials wird empfohlen, die Dateien in die entsprechenden Java-Unterverzeichnisse zu kopieren. Davon wird aber im aktuellen Jogl-User's Guide dringend abgeraten. Nachfolgend wird eine Kommandozeilen-Variante gezeigt:
* Die JOGL-Bibliotheksdateien werden in das Projektverzeichnis kopiert.
* Kompilierung im Projektverzeichnis: javac -classpath jogl.jar:gluegen-rt.jar JoglTest.java
* Programmstart im Projektverzeichnis: java -classpath jogl.jar:gluegen-rt.jar: -Djava.library.path=. JoglTest
Die nachfolgenden Beispiele basieren auf dem JOGL-Release-Candidate 1.1.0-rc3. Frühere JOGL-Versionen wiesen u.a. eine andere Packagestruktur auf.

## Weitere OpenGL-Bindings für Java

* LWJGL

## Überblick

Das Sound-Paket von Java besteht aus zwei grundsätzlich verschiedenen Komponenten.
* javax.sound.sampled – Hier sind die Klassen zur Bearbeitung, Aufnahme und Wiedergabe von Audiodaten gruppiert, die aus einzelnen Abtastwerten bestehen.
* MIDI-Daten – In diesem Paket befinden sich die Klassen, die für den Input/Output, die Sequenzierung und die Synthese von MIDI-Daten nötig sind.

## Einleitung
### Darstellung im Computer

Zuerst einmal muss man sich die Frage stellen, wie Schallwellen überhaupt im Computer dargestellt werden sollen. Hilfreich dafür ist ein einfaches Beispiel mit Mikrofonen. Schall besteht aus Druckwellen, die sich durch die Luft fortpflanzen. Die einfachste Möglichkeit ist also sicherlich die Aufzeichnung der Schwingungskurven, die ein Teilchen erfährt, wenn es den Schallwellen ausgesetzt wird. Mikrofone übersetzen nun diese Luftschwingungen in elektrische Schwingungen. Bis hierhin ist aber noch immer nichts digitales geschehen. Computer können aber nur digitale, also diskrete Daten bearbeiten. Mit den analogen Schwingungen können sie nichts anfangen. Deshalb werden diese Schwingungen nun diskretisiert.
Nun gibt es mehrere Fragen, die es zu beantworten gilt:
* Wie exakt, also mit welcher Präzision sollen die Amplituden der Schwingungen aufgezeichnet werden?
* Wie oft pro Sekunde soll überhaupt ein Wert aufgezeichnet werden?
* Mit wievielen Mikrofonen soll die Geräuschwelle aufgezeichnet werden?
Hier kommen nun die Begriffe Samplerate, Samplesize und Kanäle ins Spiel. Die Samplerate gibt an, wieviele Signale pro Sekunde abgetastet werden sollen, die Einheit ist somit Hertz. Die Samplesize definiert den Wertebereich und damit Präzision der Abtastwerte, sie wird in Bits gemessen. Die Anzahl der Kanäle gibt an, wieviele Tonspuren simultan aufgezeichnet werden. Für eine handelsübliche CD sind beispielsweise 44100 Abtastwerte pro Sekunde, 16 Bit Samplesize und zwei Kanäle, also stereo üblich. Bei DVDs beispielsweise wird oft mit 20 oder sogar 24 Bit Samplesize bei einer Samplerate von 96 oder 192 kHz gearbeitet. Wegen der geringen Übertragungsrate sind diese hohe Qualitäten für die Übertragung per Telefon nicht im Geringsten geeignet.

### Anfallende Datenmengen

Für unkomprimierte Audiodaten lässt sich die benötigte Datenmenge pro Sekunde ganz einfach berechnen:
Schauen wir uns also mal ein kleines Beispiel an. Wir haben einen üblichen Song von 3 Minuten Länge mit CD-Qualität, das sind 180 Sekunden. Dann benötigen wir bereits:
Dies entspricht mehr als 31 Megabytes. Dies veranschaulicht, warum Kompressionsverfahren so wichtig sind.

### Darstellung im Computer

Zuerst einmal muss man sich die Frage stellen, wie Schallwellen überhaupt im Computer dargestellt werden sollen. Hilfreich dafür ist ein einfaches Beispiel mit Mikrofonen. Schall besteht aus Druckwellen, die sich durch die Luft fortpflanzen. Die einfachste Möglichkeit ist also sicherlich die Aufzeichnung der Schwingungskurven, die ein Teilchen erfährt, wenn es den Schallwellen ausgesetzt wird. Mikrofone übersetzen nun diese Luftschwingungen in elektrische Schwingungen. Bis hierhin ist aber noch immer nichts digitales geschehen. Computer können aber nur digitale, also diskrete Daten bearbeiten. Mit den analogen Schwingungen können sie nichts anfangen. Deshalb werden diese Schwingungen nun diskretisiert.
Nun gibt es mehrere Fragen, die es zu beantworten gilt:
* Wie exakt, also mit welcher Präzision sollen die Amplituden der Schwingungen aufgezeichnet werden?
* Wie oft pro Sekunde soll überhaupt ein Wert aufgezeichnet werden?
* Mit wievielen Mikrofonen soll die Geräuschwelle aufgezeichnet werden?
Hier kommen nun die Begriffe Samplerate, Samplesize und Kanäle ins Spiel. Die Samplerate gibt an, wieviele Signale pro Sekunde abgetastet werden sollen, die Einheit ist somit Hertz. Die Samplesize definiert den Wertebereich und damit Präzision der Abtastwerte, sie wird in Bits gemessen. Die Anzahl der Kanäle gibt an, wieviele Tonspuren simultan aufgezeichnet werden. Für eine handelsübliche CD sind beispielsweise 44100 Abtastwerte pro Sekunde, 16 Bit Samplesize und zwei Kanäle, also stereo üblich. Bei DVDs beispielsweise wird oft mit 20 oder sogar 24 Bit Samplesize bei einer Samplerate von 96 oder 192 kHz gearbeitet. Wegen der geringen Übertragungsrate sind diese hohe Qualitäten für die Übertragung per Telefon nicht im Geringsten geeignet.

### Anfallende Datenmengen

Für unkomprimierte Audiodaten lässt sich die benötigte Datenmenge pro Sekunde ganz einfach berechnen:
Schauen wir uns also mal ein kleines Beispiel an. Wir haben einen üblichen Song von 3 Minuten Länge mit CD-Qualität, das sind 180 Sekunden. Dann benötigen wir bereits:
Dies entspricht mehr als 31 Megabytes. Dies veranschaulicht, warum Kompressionsverfahren so wichtig sind.

## Einleitung

Um zu verstehen, warum das Paket javax.sound.sampled auf den ersten Blick so seltsam aufgebaut wurde, muss man sich erst einmal die Zielsetzung vor Augen halten:
* Einheitliche Schnittstelle
* Erweiterbarkeit
Das Problem bei der Entwicklung dieses Paketes war, dass auf die Verschiedenheit der Systeme, auf denen die Javaprogramme später laufen würden, unbedingt geachtet werden musste. Z.B. besitzen nicht alle Soundkarten neben der normalen Ausgabe auch noch einen Line Out. Außerdem werden nicht alle Audioformate nativ von dem zur Soundkarte gehörenden Mixer unterstützt. Einige Soundkarten lassen die gleichzeitige Wiedergabe mehrerer Spuren zu, andere wiederum nicht. Dies sind nur einige wenige Beispiele, es gibt noch sehr viele mehr. Trotzdem muss eine einheitliche Schnittstelle zum Soundsystem angeboten werden, um die API plattformunabhängig zu halten. Ein weiterer Punkt ist die Erweiterbarkeit des Paketes. Mit speziellen Klassen sollte es möglich sein, dass auch andere Formate unterstützt werden. Die Dienste, die diese neue Klassen anbieten, müssen natürlich für die Javaprogramme verfügbar sein, ohne dass diese eigentlich davon wissen. Erreicht wurde das mit dem Unterpaket javax.sound.sampled.spi, wobei SPI für Service Provider Interface steht.

## Die Klasse AudioSystem

Zentrale Anlaufstelle für alle Belange, die mit dem Einlesen oder Schreiben von Datenströmen mit Sounddaten zu tun haben, ist die Klasse AudioSystem. Sämtliche Methoden in AudioSystem sind als statisch deklariert. Die Wichtigsten sind:
Wenn es darum geht, mit Datenquellen und Datensenken zu arbeiten, ist die Vorgehensweise meistens wie folgt:
* Das Java-Programm erzeugt ein Line.Info Objekt, das beschreibt, was genau das Programm nun tun möchte, also ob eine Datensenke oder eine Datenquelle erwünscht ist und ob der Datenfluss mit einem Port oder einem bestimmten Mixer verbunden werden soll. Zusätzlich können noch erwünschte Audioformate und Puffergrößen spezifiziert werden. Es müssen nicht alle Informationen angegeben werden.
* Als nächstes wird das AudioSystem gefragt, ob es diese Anforderungen erfüllen kann.
* Zuletzt wird dann im positiven Falle vom AudioSystem der entsprechende Datenfluss abgerufen. Mit diesem kann nun gearbeitet werden.
Ziel war es also, dass das Java-Programm zum Zeitpunkt des Kompilierens nicht wissen muss, mit welchen Audioformaten es während seiner Laufzeit konfrontiert wird, auf welchen Plattformen es läuft und welche Audiokapatibilitäten diese zur Verfügung stellt.

## Das Interface Line

Ein ganz zentraler Punkt in diesem Paket ist das Interface Line. Eine Line repräsentiert alle Datenflüsse, die im AudioSystem auftreten. Es kann sich dabei um die Wiedergabe, Aufnahme, verschiedene Ports oder Pipes in den Mixer hinein oder heraus handeln. Mit diesen Audiodatenflüssen können ganz grundlegende Dinge getan werden. Bevor man damit arbeiten kann, muss man sie öffnen. Sobald dieses geschehen ist, werden Systemresourcen belegt. Nach der Benutzung sollte die Line auch wieder geschlossen werden, damit die Systemresourcen freigegeben werden können. Es ist möglich die Controls einer Line abzufragen. Dies sind Objekte, welche die Audiodaten in gewisser Weise beeinflussen. Beispielsweise gehören dazu das Verändern der Balance, der Lautstärke, der allgemeinen Lautstärke oder auch die Samplerate. Nicht alle Controls sind bei allen Lines verfügbar.

## Das Subinterface Port

Ports repräsentieren die typischen Ein- und Ausgabemöglichkeiten der Soundkarte. Zu den Wiedergabeports gehören zum Beispiel Speakers, Headset oder Line Output. Zu den Aufnahmeports gehören beispielsweise das Mikrofon, das CD-Laufwerk oder der Line Input. Auch hier gilt wieder, dass nicht auf allen Systemen alle Ports vorhanden sind.
Vollständig implementiert wurden Ports erst im J2SDK 5.0

## Drucken mit Java

Seit Java1.2 ist es relativ einfach mit Java einen angeschlossenen Drucker anzusprechen. Dazu benutzt man, ähnlich wie bei der Verarbeitung von Bildern, die Klasse Toolkit. Zuerst wäre es ja einmal interessant die aktuellen Parameter des angeschlossenen Druckers zu ermitteln. Dazu holt man das Default-Toolkit, erzeugt einen dummy-Frame und ermittelt die Werte des Druckers. Dies könnte so geschehen:

## Text auf dem Drucker ausgeben

Nachdem wir nun gesehen haben wie man ermittelt ob ein Drucker angeschlossen ist und welche physikalischen Parameter er besitzt möchten wir als nächstes ein paar Zeilen auf dem Drucker selbst ausgeben:
Das Paket java.util enthält viele Hilfsklassen für den alltäglichen Gebrauch. Von generischen Datenstrukturen wie Vector, Stack und Hashtabelle, über Kalender und Datum bis hin zum Collections Framework, der Internationalisierung und einem Bit-Array bietet das Paket alles, was man sich für die tägliche Arbeit wünscht. Auch ein Timer ist vorhanden.
In diesem Abschnitt werden mehrere Themen ausführlicher beschrieben, die für alltägliche Programmieraufgaben von Nutzen sein können. Hier folgt nun ein Überblick.

## Überblick über die behandelten Themen

* Arrays
* StringTokenizer
* Datumsverarbeitung
* Random
* Kompression mit ZIP, JAR und GZ
* Collection Framework
* Logging API von Java
ACHTUNG – veraltet (deprecated). Laut Dokumentation der Java API sollte stattdessen die Methode split(Regular Expression) der Klasse String genutzt werden.
Mit der Klasse java.util.StringTokenizer kann eine Zeichenkette in einzelne Elemente zerlegt werden, indem 1-n Trennzeichen übergeben werden.
Diese Klasse wird folgende Ausgabe erzeugen:
Ein gleiches Verhalten kann seit Java 1.4 durch die Regulären Ausdrücke mit Hilfe der Methode split (String regex) direkt auf dem String erreicht werden. Hierdurch wird ein Array mit Strings zurückgeliefert.
Für die Datumsverarbeitung gibt es in Java mehrere Datentypen. Hierzu zählen
* java.util.Date
* java.util.Calendar
* java.util.GregorianCalendar
sowie für unsere Datenbankfreunde
* java.sql.Date

## Datum und Uhrzeit

Der Umgang mit Datum und Uhrzeit ist über die Klassen "Date" und "Calendar" geregelt.

### Date (veraltet)

Die aktuelle Zeit und das aktuelle Datum kann man z.B. mit Hilfe der Date-Klasse so erfragen (Achtung: dieses Vorgehen ist deprecated, d.h. veraltet - funktioniert aber trotzdem und ist recht einfach zu verstehen. Die neue Herangehensweise sieht man im nächsten Beispiel):

### Calendar (aktuell)

Nach der neuen Methode verwendet man jetzt die Klasse Calendar zur Ermittlung von Datum und Zeit.
Dieser Code gibt folgende Daten aus (Hier wurde das Programm am 9.8.2011 um 16:23:2:362 geöffnet):
Random ist eine Klasse zur Erzeugung von Pseudozufallszahlen. Die statische Funktion Math.random macht z.B. direkt Gebrauch davon.
Random erzeugt eine Pseudo-Zufallszahl, d.h. keine richtige Zufallszahl. Der Unterschied liegt darin, dass zwei Random-Instanzen, wenn sie direkt gleichzeitig gestartet werden, genau die gleichen Zufallszahlen erzeugen, was bei "echten" Zufallszahlen nicht der Fall wäre. Um dieses Manko abzuschalten, gibt es eine abgeleitete Klasse SecureRandom, die "echte" Zufallszahlen mit anderen numerischen Algorithmen erstellt als Random. Random benutzt einen 48-Bit großen Startwert ("seed") zur Erzeugung der Zufallszahlen. Die Zufallszahlen (z) liegen immer im Bereich $0,0\leq z<1,0$.
Ein einfaches Beispiel zur einfachen Erzeugung von Lottozahlen – ein Array aus 10 Integern wird mit Math.random initialisiert:
Da Math.random eine Zahl kleiner 1 erzeugt, muss man, um eine Zahl zwischen 1 und 49 zu erhalten, das Ergebnis der Funktion Math.random mit 49 multiplizieren und diese Zahl dann um 1 vergrößern.
Ein einfaches Beispiel zur Erzeugung von Lottozahlen mit Hilfe der Random-Klasse
Für die Datenkompression stellt die J2SE eigene Pakete bereit:
* java.util.zip für die Verarbeitung von GZ und ZIP
* java.util.jar für die Verarbeitung von JAR

## sinnvolle Vorkenntnisse

Sie sollten das Prinzip der Streams verstanden haben.
Das Paket java.util bietet mit dem Collection Framework einige interessante Klassen, die von der Funktionalität ähnlich arbeiten wie die Standard Template Library (STL) von C++. Dazu gehören Vector, Array, Sets, Maps, abstrakte Datentypen und Iteratoren. Ab Java1.5 (Java5) sind die Collections auch generisch, d.h. die Collections arbeiten mit Generics.
In den folgenden Abschnitten werden Beispiele für die Anwendungen dieser Datenstrukturen und auch die Vorteile der Generizität aufgezeigt.

## Vector

Unter einem Vector kann man sich eine Liste vorstellen, der beliebig viele Objekte hinzugefügt werden können. Dies ist der gravierende Vorteil gegenüber einem Array, bei dem man zur Laufzeit eine fixe Länge zuweisen muss. Ist aber die Anzahl der Elemente einer Liste von komplexen Bedingungen abhängig, so kann die Berechnung der Array-Länge schwierig werden. In solchen Fällen ist es ratsam, einen Vector zu verwenden.
Im folgenden Beispiel wird abhängig von einer zufälligen Ja-Nein-Entscheidung ein String-Wert dem Vector hinzugefügt.
Lässt man diesen Code mehrmals laufen, so stellt man fest, dass der Vector unterschiedlich viele Elemente enthalten kann. Bei der Ausgabe der Vector-Elemente wurde die toString-Methode verwendet, die in der Klasse Object definiert ist, und somit für jeden Typ einen String-Wert zurück gibt. Was geschieht aber, wenn man aber andere Operationen mit den Elementen durchführen will?
Wird wie gesagt nur ein Vector ohne die Anwendung von Generizität erstellt, so muss man bei der Bearbeitung der Elemente Cast-Operationen durchführen, d.h. man muss überprüfen, ob es sich bei einem Element, um den richtigen Typ für eine bestimmte Operation handelt.

## Set

Hier wird in einem ersten Beispiel der Umgang mit der Collection Set (Menge) demonstriert. Ein Set ist eine Datenstruktur, in der jedes Element nur einmal vorkommen darf, d.h. der Test obj.equals( obj2 ) darf nicht positiv sein. Hier wird nun beispielhaft der Umgang mit einem TreeSet demonstriert. Der Set wird aufgebaut und mit einem Iterator ausgelesen:
Das Kapitel Test, Trace und Logging wurde von Sun Microsystems lange Zeit nicht mit der (vielleicht) notwendigen Sorgfalt betrachtet. So fanden erst mit dem JDK 1.4 entsprechende Spracherweiterungen und eine API Eingang in die Standard Edition.
Ersatzweise wurden Teile schon vorab aufgegriffen. Folgende Möglichkeiten stehen inzwischen zur Verfügung:
* Logging API von Java – Protokollierung von Arbeitsabläufen
* Assertions
* java.awt.Robot für grafische Oberflächen
* JUnit – API zum Testen von Klassen
Mit Logging wird das Protokollieren eines Programmablaufes beschrieben.
Grundsätzlich reicht dazu schon ein System.out.println("Nachricht"); aus. Allerdings bringt es die weitere Entwicklung recht schnell mit sich, dass das Interesse an "alten" Debug-Nachrichten schwindet oder diese das Protokoll unleserlich oder überfrachtet erscheinen lassen. So ist der Entwickler gezwungen, diese nun überflüssigen Nachrichten entweder auszukommentieren oder zu löschen. Beides erfordert einigen Aufwand: In welcher Klasse wird die Nachricht erzeugt? Wird die Nachricht eventuell noch einmal benötigt? Usw.
Seit Java 1.4 wird die "Java Logging API" ausgeliefert. Damit ist es möglich, im Programmcode den einzelnen Nachrichten verschiedene Dringlichkeiten, so genannte Loglevels, zuzuordnen. Über diese Loglevels ist es möglich, zentral zu steuern, welche Nachrichten von welcher Klasse mit welcher Dringlichkeit mitzuprotokollieren sind. Für die "Java Logging API" werden diese Einstellungen in der logging.properties eingetragen. Die Original-Datei liegt im Java Installationsverzeichnis unterhalb des lib Verzeichnis.
Die Properties sind in einer Baumstruktur organisiert. Der erste Knoten also die Wurzel des Baumes ist ".level"; hier wird der Default-Loglevel festgelegt. Alle Kinder erben den Loglevel des Eltern-Knotens. Also in obigem Beispiel sind "de" und "de.wikibooks" auf dem Log-Level der Wurzel, erst "de.wikibooks.loggingapi" und dessen Kinder haben den Log-Level FINEST.
Falls nicht die Original-logging.properties-Datei benutzt werden soll, kann über die System-Property java.util.logging.config.file die stattdessen zu verwendende Datei angegeben werden (der Beispielpfad D:\pfad\zur\datei\logging.properties ist in Windows-Notation angegeben. Andere Betriebssystem verwenden ggf. eine andere Notation) :
In die Java-Klassen müssen einige Imports eingefügt werden
Dann muss der Logger erstellt werden
Das Protokoll dieser Anweisungen sieht dann in etwa so aus.

## Weblinks

Ein Werkzeug, um Java-Code automatisch mit Logging-Ausgaben zu versehen: Loggifier
Das Gegenstück zur Exception ist die Assertion (deutsch etwa: "Behauptung"). Mit ihr werden Programmierfehler aufgespürt und gemeldet, wenn das Programm in einem Testmodus gestartet wird. Sie werden deswegen meist an Stellen in der Programmierung eingebaut, an denen die Verarbeitung der Daten bereits erfolgt ist.
Um eine solche Überprüfung in ein Programm einzupflegen gibt es ein eigenes Schlüsselwort: assert. Es wird an einer beliebigen Stelle im Code eingebaut, gefolgt von einer Abfrage, die entweder true oder false zurückgibt. Falls diese Überprüfung positiv endet, wird das Programm fortgesetzt; andernfalls wird eine Exception ausgelöst, ein AssertionError, der eine Meldung auf dem Bildschirm ausgibt und das Programm üblicherweise an dieser Stelle beendet.
An dieser Stelle wird im Programmcode die Variable x darauf getestet, dass sie einen Wert größer drei ergibt; andernfalls wird der Programmlauf mit einer Fehlermeldung abgebrochen. Weil eine solche Standard-Fehlermeldung oft zusätzliche Informationen liefern sollte, als es mit dem Standardtext der assert-Meldung möglich ist, kann man den Befehl um einen eigenen Fehlertext erweitern. Dazu wird der Teil hinter der Prüfung mit einem Doppelpunkt abgetrennt und dann die gewünschte Meldung angegeben:
So kann das Problem deutlich leichter eingekreist werden. Natürlich sind auch andere Fehlermeldungen denkbar, zum Beispiel die Ausgabe der Variablen selbst:
Auch wesentlich aufwendigere Prüfungen sind möglich, indem für die Tests beliebige Funktionen definiert werden, die als Ergebnis true oder false liefern. In diesem Fall muss aber sehr genau darauf geachtet werden, dass die Testfunktion keine Zustände des Programms beeinflusst, also Variablen innerhalb der Klasse verändert werden. Da die Prüfung im normalen Betrieb unterbleibt würde auch die Veränderung des Status der Klasse nicht vorgenommen werden, sprich: die Klasse reagiert mit Test anders als ohne Test. Solch einen Fehler aufzuspüren kostet jede Menge graue Haare.
Auf diese Weise kann man fehlerhaften Code in der Programmierung relativ leicht einkreisen. Wichtig ist, dass der Test hinter dem Schlüsselwort als Ergebnis true zurückliefert, wenn die getestete Programmierung ein korrektes Ergebnis liefert.

### Aktivierung des Softwaretests

Die Verwendung des Schlüsselwortes assert hat einen zusätzlichen Vorteil: Sie kann im Code des Programmes auch dann stehen bleiben, wenn alle Softwaretests erfolgreich abgeschlossen wurden und die Software für die Benutzer freigegeben werden kann. Bei einem normalen Aufruf von Java wird das Schlüsselwort und alle damit verbundenen, möglicherweise zeitintensiven Tests bei der Ausführung komplett ignoriert. Die Tests müssen beim Aufruf des Programms ausdrücklich angeschaltet werden. Wahrscheinlich arbeiten Sie mit einer Entwicklungsumgebung; bitte suchen Sie sich hier die entsprechende Einstellung aus den Menüs heraus. Falls es keine solche Einstellung gibt oder falls Sie Java-Programme über die Kommandozeile starten, gehen Sie bitte wie folgt vor:
Unter Java Version 1.4 wird das Programm über den Compiler mit einer eigenen Option übersetzt, die die Überprüfungen einschaltet; der auszuliefernde Code muss später ohne diese Option erneut compiliert werden:
javac -source 1.4 WikiBooks
Ab Java Version 5 wird die Prüfung direkt im Interpreter vorgenommen, es bedarf also keines zusätzlichen Compilerlaufes. Das hierfür vorgesehene Flag lautet -ea (oder -enableassertations) zum Einschalten der Prüfung; dahinter wird der Name des Paketes angefügt:
java -ea WikiBooks
Eine einzelne Klasse innerhalb eines Paketes kann ebenfalls getestet werden, ohne dass dafür das komplette Paket mitgetestet wird. In diesem Fall wird hinter dem Kommandozeilenparameter -ea: (jetzt direkt hinter dem Parameter mit Doppelpunkt angefügt) der Pfad zur Klasse angegeben und dahinter das Paket genannt, in dem die Klasse zu finden ist:
java -ea:testumgebung.wikibooks.BeispielKlasse WikiBooks
Wenn in dem zu testenden Paket weitere Pakete stecken, die zu testen sind, ist auch das problemlos möglich. Dafür müssen hinter dem vollständigen Pfad nur drei Punkte angegeben werden:
java -ea:testumgebung.wikibooks...
Gelegentlich ist es sinnvoll, einzelne Teile des Paketes auszunehmen. Auch das ist mit einem Kommandozeilenparameter möglich. Er lautet -da bzw. -disableassertions und wird mit dem kompletten Pfad des auszuschließenden Teiles aufgerufen:
java -ea WikiBooks -da:testumgebung.wikibooks.BeispielKlasse
Selbstverständlich lässt sich auch hier wieder mit dem -ea-Parameter ein Teil des ausgeschlossenen Paketes doch wieder testen, indem der Parameter mit dem kompletten Pfad zu dem betreffenden Code angehängt wird.

### Übungen

Alles verstanden? Zum Selbsttest gibt es hier einige Übungen. Die Lösungen dafür finden Sie hier.

#### 1: Ein switch-Test

In einem Programm finden Sie folgende switch-Anweisung:
Obwohl in der assert-Anweisung kein Test vorgenommen wird, funktioniert diese Anweisung ordnungsgemäß: falls die Variable ja_nein einen anderen Wert als JA oder NEIN enthält wird das Programm mit einer Fehlermeldung abgebrochen.
1.1) Erklären Sie, warum die Anweisung auch ohne einen Test die Ausführung des Programms abbricht. 1.2) Welche Fehlermeldung wird der Programmierer zu Gesicht bekommen?

#### 2: Do it yourself

Als Grundlage gegeben sei folgende Funktion, die einen Würfelwurf simulieren soll:
Schreiben Sie eine Funktion public int diceTest, die die Summe von 100 Würfen mit dieser Funktion ermittelt und zurückliefert. Stellen Sie dabei bei jedem Wurf sicher, dass eine Zahl zwischen 1 und 6 gewürfelt wird. Nutzen Sie dabei zwei Tests: Einen für Zahlen größer 6 und einen für Zahlen kleiner 1. Tatsächlich ist ein Programmabbruch durch eine der assert-Anweisungen zu erwarten. Welche?
Java ist eine der ersten Programmiersprachen welche von Grund auf mit Netzwerkunterstützung entwickelt wurde. Es waren auch die Applets welche Java zum Durchbruch in der Programmierwelt verhalfen.
Eine der wichtigsten Neuerungen in Java war, dass man einen sehr geringen Aufwand als Programmierer leisten muss, um eine Software netzwerkfähig zu machen. Die "Magie" in Java (oder konkret die Socketklasse) erledigt den Hauptteil der Arbeit. Jeder der schon einmal einen kleinen Server / Client in C geschrieben hat, kann davon berichten wie aufwendig dies sein kann. Im Gegensatz dazu bietet das java.net.* package alle Grundlagen, die es braucht um in 5 Minuten ein kleines Netzwerkbasierendes Programm zu schreiben.

### Grundlagen der Netzwerkprogrammierung

In diesem Kapitel werden die Grundzüge netzwerkbasierter Software, Protokolle, Sockets, Streams etc. erläutert. – Hinweis: Es gibt Überschneidungen mit den folgenden Kapiteln.

### Sockets für Clients

In diesem Kapitel wird beschrieben, wie ein Programm Verbindung mit einem Server aufnimmt und Daten mit diesem austauschen kann.
In den meisten Fällen geschieht die Datenübertragung zwischen Server und Host auf der Basis von TCP. Die java.net.Socket Klasse stellt uns eine solche TCP - Verbindung zur Verfügung. Es sind jedoch nicht alle Ports eines Betriebssystems für die Datenübertragung auf Basis von TCP ausgelegt. Um zu wissen auf welche Ports wir eine TCP Verbindung öffnen könnten, können wir uns mit Java einen eigenen kleinen Portscanner "basteln".
Das Programm testet alle Ports im Bereich 1 - 1024. Ist auf einem dieser Ports ein TCP - fähiger Server am "lauschen", so wird eine entsprechende Meldung ausgegeben. Wichtig an diesem Programm ist Zeile 15. Hier wird einer der Konstruktoren der Klasse Socket gerufen.
Hier die schnellere Variante:

### Sockets für Server

In diesem Kapitel wird beschrieben wie man einen Server schreibt, welcher auf eingehende Verbindungen "hört" und auf die Anfragen antwortet.
Java Standard: Socket ServerSocket (java.net) UDP und TCP IP

## Einleitung, Grundbegriffe

* RMI
RMI ist die Abkürzung von 'Remote Method Invocation' und bedeutet 'Aufruf einer entfernten Methode' (i.a. über ein Netzwerk). Der Aufruf selbst ist transparent, d.h. der Nutzer merkt nichts davon, dass die Methode auf einem entfernten Rechner implementiert ist und dort abgearbeitet wird. Parameter und Ergebnis werden transparent zwischen Client und Server ausgetauscht. Im Hintergrund übernehmen 2 Klassen (genannt Skeleton/Stub) stellvertretend für Server/Client die Kommunikation.
Das hier beschriebene Beispiel setzt Java 1.5 oder höher voraus, damit entfällt die zuvor erforderliche Nutzung der 'Java-RMI-Tools'.
* Anforderungen an die Applikation
Definiere ein Interface für das 'remote object' (im Beispiel 'Hello'), die von Server und Client gemeinsam benutzte Methode.
* RMI-Server
    1. Implementiere eine Instanz des 'remote object' ('HelloImpl', Name beliebig)
    2. Exportiere die Instanz
das geschieht mit 'UnicastRemoteObject.exportObject' oder durch Erweiterung der Instanz mit 'UnicastRemoteObject'. Dadurch wird automatisch der Konstruktor von 'UnicastRemoteObject' aufgerufen, der den Export durchführt.
Durch den Export entsteht die Skeleton-Klasse, die Kommunikation und Datenaustausch mit dem Client durchführt.
    3. Registry
Erzeuge eine Registry in der das 'remote object' mit der Methode 'registry.[re]bind' angemeldet wird. Dabei ist ein eindeutiger Name und ein Kommunikationsport (Standard 1099) festzulegen. Diesen Namen benutzt später die Stub-Klasse des Client (der Partner der Skeleton-Klasse des Servers), um die RMI durchzuführen.
Nach dieser Anmeldung ist der Server bereit, Client-Anfragen entgegen zu nehmen. Die Anfragen werden in der implementierten Klasse 'HelloImpl' behandelt.
* RMI-Client
Zuerst verschafft man sich Zugang zur Registry des Servers, um dort nach dem gewünschten 'remote object' zu fragen (Naming.lookup). Steht dieses zur Verfügung wird automatisch eine Stub-Klasse bereit gestellt, die die Kommunikation und den Datenaustausch mit dem Server durchführt.
* Parameter/Ergebnis der aufzurufenden Methode des 'remote object'
* Es wird in jedem Falle 'call by value' durchgeführt.
* Einfache Variable
* Objekte
Werden Objekte benutzt müssen diese das Interface 'Serializable' implementieren (Datenübertragung als serieller Bytestrom).
Die meisten Standardklassen von Java erfüllen diese Bedingung, so dass für den Anwender in diesem Falle kein weiterer Aufwand entsteht.
Im Beispiel wird für das Ergebnis des Aufrufs der entfernten Methode eine eigene Klasse (RmiResult) verwendet, die auf Client und Server bekannt sein muss.
* Dynamisches Laden von Objekten
Dieser Punkt ist für das Funktionieren des Beispiels unerheblich. Hier wird nur eine Zusatzmöglichkeit für die verteilte Verarbeitung beschrieben.
Unter RMI ist es möglich, Objekte über das Netz zu laden. Dabei können sowohl Server als auch Client Quelle oder Ziel sein. Für das Laden kann u.a. das http-Protokoll verwendet werden, wenn auf Quellseite ein Webserver vorhanden ist.
Hier wurde dafür ein Beispiel mit der Klasse 'LoadClient' erstellt, die auf Client-Seite die Klasse 'TClient' vom RMI-Server (TServer) lädt und abarbeiten lässt.
Das zuvor beschriebene Beispiel mit RMI-Client und RMI-Server kann natürlich ohne 'LoadClient' verwendet werden. 'TClient' ist allerdings so programmiert, dass es mit oder ohne 'LoadClient'-Klasse funktioniert.
Beim dynamischen Laden von externem Bytecode ist ein eigener Sicherheitsmanager erforderlich und in der Datei '.java.policy' sind die entsprechenden Zugriffsrechte zu erteilen (das Ziel braucht Connect-Recht bei der Quelle und für den Bytecode Zugriffsrecht auf dem eigenen Rechner). Im Beispiel wurde für den RMI-Client folgende Policy benutzt:
'rechner_name' ist die Webadresse des Servers oder einfacher aber risikoreicher:
Die Policy-Datei ist im Home-Verzeichnis des Nutzers, unter Windows bspw.: "c:\Dokumente und Einstellungen\nutzername\"
Mit der Folgeanweisung kann eine andere Policy-Datei benutzt werden: java -Djava.security.policy=rmi/client.policy rmi/LoadClient

## Das Interface der 'remote method' und die Ergebnisklasse

Müssen bei Server und Client verfügbar sein.

## Der RMI-Client

Der vom Schalter 'loadclient' abhängige Code ist nur für den Fall bedeutsam, dass der RMI-Client über die Klasse 'LoadClient' und nicht als eigenständige Applikation über die Shell aufgerufen wird.

## Klasse LoadClient

Zusatzmöglichkeit für die verteilte Verarbeitung.

## Abarbeitung des Beispiels

Beispiel TServer/TClient :
| | Rechner A | Rechner B |
| Dateien in 'basispfad/rmi': | TServer,Hello,HelloImpl,RmiResult | TClient,Hello,RmiResult |
| Übersetzen | cd basispfad javac rmi/*.java | cd basispfad javac rmi/*.java |
| Abarbeiten | cd basispfad java rmi/TServer | cd basispfad java rmi/TClient |
Beispiel LoadClient :
| | Rechner A | Rechner B |
| Dateien in 'basispfad/rmi': | TServer,Hello,HelloImpl,RmiResult | LoadClient,RmiResult,client.policy |
| Dateien in 'pfad_webserver/wicki/rmi': | class-Dateien: TClient,Hello,RmiResult | |
| Übersetzen | wie Beispiel 1 | cd basispfad javac rmi/*.java |
| Abarbeiten | wie Beispiel 1 | cd basispfad java -Djava.security.policy=rmi/client.policy rmi/LoadClient |

## Einleitung, Grundbegriffe

* Verweise zum Thema CORBA
    Vorlage zum Beispiel
    Beschreibung CORBA
    Überblick: RMI, CORBA, IDL
* CORBA
CORBA (Common Object Request Broker Architecture) unterstützt verteilte Anwendungen, die plattformübergreifend also unabhängig von Sprache und Betriebssystem sind. Darin unterscheidet es sich von RMI, das nur zwischen JAVA-Anwendungen möglich ist. CORBA beschreibt die Architektur und ein ORB (Object Request Broker) stellt eine spezielle Implementierung dar.
Ein Server könnte also auf einem Linux-System laufen und in C++ geschrieben sein während ein Client auf einem Windows-PC gestartet wird und in Java geschrieben ist. Der Aufruf selbst ist transparent, d.h. der Nutzer merkt nichts davon, dass die Methode auf einem entfernten Rechner implementiert ist und dort abgearbeitet wird. Parameter und Ergebnis werden transparent zwischen Client und Server ausgetauscht.
CORBA benutzt die IDL (Interface Definiton Language) zur Beschreibung der Schnittstelle zwischen Server und Client, zu der die zu benutzenden entfernten Methoden gehören. Ein IDL-Compiler (für Java 'idlj') generiert daraus die erforderlichen Klassen (stub, skeleton und weitere Hilfsklassen). Im Hintergrund übernehmen diese generierten Klassen stellvertretend für Server/Client Kommunikation und Datenaustausch.
* POA: Portable Object Adapter
Der POA als Teil des ORB vermittelt die Anforderung des Clients (Aufruf der entfernten Methode) an den Server, der diese Methode implementiert hat.
* Vererbungs-Modell (POA): Die Implementierungsklasse erbt (per 'extends') von der Skeleton-Klasse, die der IDL-Compiler generiert hat.
* Delegation-Modell (POA/Tie) benutzt 2 Klassen: Eine Tie-Klasse erbt vom Skeleton (POA), delegiert aber die Anforderung an die eigentliche Implementierungs-Klasse.
* Anforderungen an die Applikation
Für die Verbindung zwischen Client und Server ist die Schnittstelle zwischen beiden zu definieren (im Beispiel 'Hello.idl').
* CORBA-Server
* Schreibe eine öffentliche Serverklasse nach der Vorlage im Beispiel (HelloServer.java)
* Implementiere in dieser Serverklasse die Interfaces (im Beispiel 'HelloImpl','AdderImpl') in Form von je einer Klasse
* Generiere die Klassen für die Verbindung Client/Server mit dem idlj-Compiler
* Übersetze nun alle Klassen
* CORBA-Client
* Schreibe eine öffentliche Clientklasse nach der Vorlage im Beispiel (HelloClient.java)
* Formuliere in dieser Klasse die Aufrufe der entfernten Methoden.
* Generiere die Klassen für die Verbindung Client/Server mit dem idlj-Compiler
* Übersetze nun alle Klassen

## Das Interface für die entfernten Methoden

Muss bei Server und Client verfügbar sein. Es folgt die Datei 'Hello.idl':

## Ablauf für die Abarbeitung des Beispiels

Die Programme 'idlj', 'orbd' sind Bestandteil des JDK.
Sind Server und Client auf dem gleichen Rechner, sollten für sie 2 unabhängige Verzeichnisse gewählt werden.
Zum Beispiel: c:\basispfad\Server und c:\basispfad\Client
* Server und Client
    Generierung der erforderlichen Klassen mit dem IDL-Compiler:
    idlj -v -fall Hello.idl
* Client
    Übersetzung aller Java-Klassen:
    javac *.java HelloApp/*.java
* Server
    Übersetzung aller Java-Klassen:
    javac *.java
    Start des ORB-Dämons (verantwortlich u.a. für den Naming-Service), überwacht Port 1050.
    Die Port-Nr. kann geändert werden, muss aber bei Server und Client übereinstimmen.
    start /b orbd -ORBInitialPort 1050
    bzw. unter UNIX als Hintergrund-Prozess:
    orbd -ORBInitialPort 1050 &
    Start des Servers:
    java HelloServer -ORBInitialPort 1050
* Client
    Start des Clients:
    java HelloClient -ORBInitialPort 1050 -ORBInitialHost nameserverhost
    Wenn der Client auf einem 2. Rechner gestartet wird, ist unter 'nameserverhost' der Rechner mit dem
    ORB-Dämon anzugeben. Andernfalls kann '-ORBInitialHost nameserverhost' weggelassen werden.
Hinweis für Windows-Nutzer:
Man kann den Start von orbd und Server und die Beendigung von orbd nach einem Server-shutdown in einer Batch-Datei zusammenfassen. Ein Beispiel ist die beiliegende Datei 'server.bat'. Das Tool 'pskill' ist unter der Verweisadresse verfügbar.
Ggf. kann 'orbd.exe' auch über den Task-Manager beendet werden.

## Ein Corba-Generator
### Beschreibung

* Zielstellung:
    Es werden 3 Template-Dateien vorgegeben, aus denen mit dem Programm 'CorbaGenerator' 3 Corba-taugliche Java-Quellen erzeugt werden.
    Diese enthalten alle Corba-spezifischen Codeteile, die für die Kommunikation zwischen Client und Server erforderlich sind.
    Der Anwender muss in den generierten Quellen nur noch die Aufgaben-spezifischen Teile ergänzen.
* Templates:
    Die Template-Vorgaben sind 'Server.templ', 'Servant.templ' (zur Implementierung einer Methode auf dem Server), 'Client.templ'.
    Der Anwender muss die IDL-Datei zur Definition der Schnittstelle Client/Server bereitstellen.
* Aufruf:
    java CorbaGenerator idl_file
* Parameter:
    Name der IDL-Datei. In dieser sind nur 1 'module'-Anweisung, aber mehrere 'interface'-Anweisungen möglich.
    Die Werte dieser Anweisungen sind für die Generierung erforderlich. Sie müssen von Leerzeichen umgeben sein.
    Die Anweisungen dürfen jedoch in Spalte 1 beginnen und unmittelbar nach dem 2. Wert enden.
* Ergebnis:
    Die generierten Quellen müssen noch anwendungsspezifisch angepasst werden:
    Implementierung der jeweiligen Methode in der 'Servant'-Quelle und
    Implementierung der Methoden-Aufrufe in der 'Client'-Quelle.
* Ablauf einer Abarbeitung:
    a) Aufruf 'idlj'-Compiler zur Generierung der Hilfsklassen aus der IDL-Datei
    b) Generierung der Corba-tauglichen Java-Quellen aus den Templates
    c) Anpassung der Quellen aus Punkt b
    d) Übersetzung aller Java-Quellen
    e) Start 'orbd'-Dämon und Server
    f) Start von Clients

### Der Corba-Generator

Bei den 3 Template-Dateien werden Zeichenketten vom Typ !!identifier!! (Bsp.: !!clientNaming!!) durch passenden Code ersetzt, den der Generator erzeugt. Die Namen der generierten Dateien enthalten den IDL-modulname bzw. das IDL-interface. Beispiel, IDL:
* modulname HelloApp
* interface Hello
Es entstehen die Java-Dateien:
* HelloAppServer, HelloServant, HelloAppClient
Der Server ist bereits komplett und muss nicht mehr angepasst werden.
Bei Servant und Client sind Ergänzungen in dem markierten Kommentarbereich vorzunehmen. Eventuell müssen noch im Kopfbereich erforderliche import-Anweisungen eingefügt werden.
Java ist auch in der Lage, mit Datenbanken zu kommunizieren.
Die Verbindung von Java und (relationalen) Datenbanken ist eine der Schlüsseleigenschaften von unternehmensweiten Java-Anwendungen (J2EE).

## Java Data Base Connectivity (JDBC)

Dazu verwendet es einen speziellen Zugangsmechanismus: das JDBC (Java Data Base Connectivity) und eine spezielle Zugriffssprache: SQL (structured querry language). Datenbanken sind im Gegensatz zur objektorientierten Hochsprache Java nicht objektorientiert, sondern relational orientiert. Relational orientiert bedeutet, dass Datenbanken Daten (Attribute) in großen Tabellen halten und über spezielle Links (Relationen) miteinander verbinden können.

## Java Persistence API (JPA)

siehe vorerst Java Persistence API

## Siehe auch

* Einführung in SQL

## Rechtliches

Java™ und JDBC™ sind Trademarks der Firma Sun Microsystems. Auch andere verwendete Soft- oder Hardwarenamen können, ohne besonders gekennzeichnet zu sein, eingetragene Markenbezeichnungen sein und sollen auch als solche betrachtet werden.

## Einleitung

JDBC ist die Abkürzung für Java Database Connectivity. Die JDBC-API ermöglicht den Zugriff auf RDBMS (relationale Datenbankmanagementsysteme) mittels Java und SQL.
Die JDBC-API residiert in folgenden Packages:
* java.sql
* javax.sql (erweitert JDBC um Server-Side-Möglichkeiten)

## Datenbanktreiber

RDBMS gibt es fast so viele wie Sandkörner am Strand. Jedes weist seine Besonderheiten auf und unterstützt verschiedene SQL-Versionen mit herstellerspezifischen Einschränkungen oder Erweiterungen.
Um nun die Möglichkeit zu schaffen diese Datenbanksysteme mittels eines einheitlichen Interfaces, nämlich der JDBC-API, ansprechen zu können, bedarf es noch mindestens einer Zwischenschicht. Diese Zwischenschicht oder zumindest einen Teil davon stellen die JDBC-Datenbanktreiber dar.

### Typen von Datenbanktreibern

* Typ 1: JDBC-ODBC-Bridge
* Typ 2: Setzt auf einen herstellerspezifischen Treiber auf
* Typ 3: JDBC-Netzwerktreiber
* Typ 4: Nativer JDBC-Treiber
Wie diese Treibertypen genau funktionieren soll hier nicht weiter interessieren.
Prinzipiell kann aber folgendes gesagt werden: Je höher die Typnummer, desto besser und effizienter die Datenbankanbindung. Ein Typ 4-Treiber ist, falls für das jeweilige Datenbanksystem vorhanden, den anderen Treibertypen normalerweise vorzuziehen.
Ein JDBC-ODBC-Bridge-Treiber (= Typ 1-Treiber) ist in den aktuellen Java-Releases enthalten. Sun Microsystems weist aber ausdrücklich darauf hin, dass dieser nur für experimentelle Zwecke verwendet werden soll oder wenn keine anderen Treiber für die Datenbank verfügbar sind.
Sun Microsystems listet unter viele verfügbare JDBC-Datenbanktreiber.

### Einen Datenbanktreiber laden

Alle nachfolgenden Beispiele beziehen sich auf das RDBMS PostgreSQL 8.0 und den JDBC-Treiber "8.0-312 JDBC3". Dieser Typ 4-Treiber ist unter als Datei "postgresql-8.0-312.jdbc3.jar" verfügbar. Diese JAR-Datei muss natürlich für ein funktionsfähiges Programm in den CLASSPATH eingebunden werden.
Der Klassenname ist treiberabhängig. Suns JDBC-ODBC-Bridge würde mittels sun.jdbc.odbc.JdbcOdbcDriver angesprochen. In der Regel finden Sie diesen in der Dokumentation zum entsprechenden Treiber des Datenbankherstellers.

## Der Treibermanager

Bei fehlerfreier Abarbeitung des obigen Codefragmentes ist der Treiber nun beim Treibermanager (Klasse DriverManager) angemeldet.
Folgendes Programmstück schreibt die Aktivitäten des Treibermanagers und der Treiber in die Log-Datei test.log.
Alternativ zur forName-Methode kann ein Datenbanktreiber auch so geladen werden
Auch die Verbindung zu einer konkreten Datenbank wird durch den Treibermanager hergestellt. Dazu mehr im nächsten Abschnitt.

## Datenbankverbindung

Wir wollen nun eine Verbindung mit der PostgreSQL-Datenbank testdb herstellen. Die Datenbank ist am lokalen Rechner (localhost) abgelegt und es wird der Standardport 5432 verwendet. Der Datenbankbenutzer soll user mit dem Passwort password sein.
Die getConnection-Methode der Klasse DriverManager gibt es mit verschiedenen Signaturen. Der erste Parameter ist immer erforderlich. Dabei handelt es sich um die sogenannte URL (Uniform Ressource Locator) der Datenbank. Diese URL beginnt immer mit jdbc:, dann folgt die Datenbankprotokoll-/Treiberidentifikation und abschließend noch die Angabe der Datenquelle. Die genaue Syntax dieser URL ist treiberabhängig. Im Anwendungsfall also immer das maßgebliche RDBMS-Handbuch und/oder die Treiberdokumentation konsultieren.
Die Verbindung zur Datenbank kann mittels close wieder geschlossen werden.

## Datenbankabfragen
### Beispieldatenbank

Die Datenbank testdb enthalte eine Tabelle (Relation) leute mit der Tabellenstruktur
| Spaltenbezeichnung | SQL-Datentyp | PostgreSQL-Datentyp | Anmerkung |
| id | INTEGER | INTEGER | PRIMARY KEY |
| vorname | VARCHAR(15) | VARCHAR(15) | |
| nachname | | TEXT | |
| geburtsdatum | DATE | DATE | |
und dem Inhalt
| id | vorname | nachname | geburtsdatum |
| 1 | Hansi | Hubsi | 1999-12-01 |
| 2 | Willy | Wupp | 1964-02-22 |
| 3 | Struppi | Strupp | 2001-03-27 |
| 4 | Milly | Miker | 1948-11-08 |

### Statement und ResultSet

Alle JDBC-Datenbankabfragen setzen auf Statement-Interfaces auf.

#### Statement

Die Schnittstelle Statement kann für alle einfachen SQL-Abfragen verwendet werden.

#### ResultSet

Damit man an die Daten in der Datenbank herankommt, führt man die Statement-Methode executeQuery aus. Diese Methode retourniert eine ResultSet-Instanz mit den angeforderten Daten.

#### Hinweise

* Pro Statement-Instanz kann jeweils nur eine ResultSet-Instanz existieren.
* Der übergebene SQL-String muss natürlich SQL-konform, sinnvoll und korrekt sein. Übergibt man Datenmüll, so bekommt man auch nur Fehlermeldungen oder Unsinn zurück.
* Gefährlich: Man muss keinen SELECT-String übergeben. Man kann z.B. auch einen INSERT-String übergeben. Man erhält dann zwar eine Fehlermeldung, der Datensatz wurde aber trotzdem eingefügt.

#### Daten aus ResultSet herausholen

In der ResultSet-Instanz sind nun die vom Datenbanksystem als Reaktion auf unsere Anfrage zurückgegebenen Daten gespeichert.
Die einzelnen Tupel kann man mit der ResultSet-Methode next durchlaufen. Damit der Datensatzcursor auf das erste Tupel zeigt, muss next einmal aufgerufen werden.
Um an die einzelnen Datenwerte des Tupels heranzukommen, liefert ResultSet verschiedene getter-Methoden (hier nur auszugsweise dargestellt):
* int getInt(int columnIndex)
* int getInt(String columnName)
* String getString(int columnIndex)
* String getString(String columnName)
* Date getDate(int columnIndex)
* Date getDate(String columnName)
Die Identifikation der gewünschten Spalte erfolgt mittels Index oder direkt durch Angabe der Spaltenbezeichnung. Bei Angabe der Spaltennummer ist zu beachten, dass der Index bei 1 beginnt (Spalte1 = 1). Weiters kann man durch die SQL-Abfrage die Tabellenspalten durcheinanderwürfeln. Das muss bei der Indexmethode zusätzlich berücksichtigt werden.
liefert wie erwartet als Ergebnis

#### NULL-Check

* Bei getXXX-Methoden, die als Ergebnis ein Objekt zurückliefern, kann man einen NULL-Wert durch den Rückgabewert null erkennen.
* Ansonsten erfolgt die Überprüfung eines Datenwertes auf NULL mit der wasNull-Methode
liefert

### Scrollable ResultSet

(ab JDBC 2.0)
Eine komfortable Datensatznavigation ermöglichen folgende Connection-Methoden:
* Statement createStatement(int resultSetType, int resultSetConcurrency);
* Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability);
mit
resultSetType:
* ResultSet.TYPE_FORWARD_ONLY
* ResultSet.TYPE_SCROLL_INSENSITIVE
* ResultSet.TYPE_SCROLL_SENSITIVE
resultSetConcurrency:
* ResultSet.CONCUR_READ_ONLY
* ResultSet.CONCUR_UPDATABLE
resultSetHoldability:
* ResultSet.HOLD_CURSORS_OVER_COMMIT
* ResultSet.CLOSE_CURSORS_AT_COMMIT
Die genaue Bedeutung dieser Parameter soll hier nicht erläutert werden. Für ein scrollbares ResultSet ist der Parameter resultSetType auf ResultSet.TYPE_SCROLL_INSENSITIVE oder ResultSet.TYPE_SCROLL_SENSITIVE zu setzen.
Schon kann der Datensatzcursor fast beliebig positioniert werden:
| next | Bewegt den Datensatzcursor zum nächsten Datensatz |
| previous | Bewegt den Datensatzcursor zum vorherigen Datensatz |
| first | Bewegt den Datensatzcursor zum ersten Datensatz |
| last | Bewegt den Datensatzcursor zum letzten Datensatz |
| afterLast | Bewegt den Datensatzcursor hinter den letzten Datensatz |
| beforeFirst | Bewegt den Datensatzcursor vor den ersten Datensatz |
| absolute(int n) | Bewegt den Datensatzcursor auf den n-ten Datensatz |
| relative(int n) | Bewegt den Datensatzcursor relativ zur momentanen Position |
liefert

### PreparedStatement

Will man SQL-Abfragen parametrisieren, dann ist die Schnittstelle PreparedStatement genau richtig. PreparedStatement ist ein Subinterface von Statement.
liefert
Darüber hinaus speichert die Datenbank alle Prepared Statements (genauer gesagt den berechneten Execution Plan) um es bei nachfolgenden Ausführungen zu beschleunigen.

## Datenbankmanipulation

JDBC-Datenbankmanipulationen setzen auf den bereits bekannten Statement-Interfaces auf.

### executeUpdate

Die Statement-Anweisung
int executeUpdate(String sql)
ist für die Ausführung von INSERT-, UPDATE-, DELETE- oder DDL-Anweisungen gedacht.

### Updateable ResultSet

Wir haben bereits die Realisierung scrollbarer ResultSets unter Zuhilfenahme der Connection- Methode
Statement createStatement(int resultSetType, int resultSetConcurrency)
kennengelernt.
Setzen wir darin den zweiten Parameter auf ResultSet.CONCUR_UPDATEABLE, so können wir auch auf diese Weise Datensätze einfügen, löschen oder einzelne Datenwerte ändern, wenn für die Tabelle ein Primärschlüssel vorhanden ist.
Datensätze kann man mit der ResultSet-Methode void insertRow einfügen und mit void deleteRow löschen.

### Transaktionen

Auch Transaktionen lassen sich mit Hilfe der Connection-Methoden
* void setAutoCommit(boolean autoCommit)
* void commit
* void rollback
* void rollback(Savepoint savepoint)
nachbilden.
Standardmäßig arbeitet JDBC im AutoCommit-Modus.
Als Beispiel wollen wir nun einige Datensätze "in einem Rutsch" in die Tabelle leute einfügen. Die Betonung liegt auf dem Wörtchen "wollen".
Was geschieht bei der Ausführung dieses Codes? Die letzte INSERT-Anweisung verletzt die Bedingung für einen Primärschlüssel, somit wird eine SQLException geworfen. Die commit-Anweisung wird nie aufgerufen. Allfällige Änderungen werden durch ein Rollback wieder rückgängig gemacht. Die Tabelle bleibt konsistent im ursprünglichen Zustand erhalten.
Alternativ können Transaktionen natürlich auch ohne die JDBC-Transaktionsmethoden komplett mittels SQL-Code übergeben werden.

### Batch-Updates

(ab JDBC 2.0)
Sind viele Daten auf einmal zu manipulieren, so spielt die Effizienz des Übertragungsvorganges eine große Rolle. Batch-Updates sind dann den konventionellen execute-Methoden überlegen.

## Metadaten

Die Struktur der in einer Datenbank gespeicherten Daten wird durch die so genannten Metadaten repräsentiert.

### Datenbank-Metadaten

liefert

### Tabellen-Metadaten

liefert

## Ausblick

Im Rahmen dieses Konvoluts konnte das komplexe Thema JDBC nur an der Oberfläche angekratzt werden. Interessierte werden zwecks weiterführender Information auf die Java-API-, JDBC-API-Dokumentation und die Sun-Tutorials (in englischer Sprache) verwiesen. Die API-Dokumentationen und die Sun-JDBC-Tutorials können unter Oracle Java-Homepage gefunden werden.

## Oracle Database
### Bibliographie

* Hanspeter Mössenböck, Sprechen Sie Java? Eine Einführung in das systematische Programmieren

### Links
#### Oracle

* Java-Hauptseite mit vielen weiteren Hinweisen, darunter den folgenden
* Technische Artikel
* User-Groups

#### Weblinks

* gailer-net.de – ein interaktives Lernprogramm der Sprache Java
* Java-Kurs – ein Kurs-Skriptum zu Java

#### Newsgroups

Vor dem Schreiben bitte immer die Netiquette und die entsprechende Newsgroup-FAQ lesen und beherzigen.
* Google Groups – Überblick
* de.comp.lang.java

## Java Coding Conventions

Bei Sun gab es vor 1999 Code Conventions. Nach der Übernahme durch Oracle wurden sie nicht erneuert. Die nachfolgenden Hinweise basieren darauf; viele Programmierer richten sich weiterhin danach.
Unabhängig davon legen viele Firmen ihre eigenen Regeln fest. Jeder Programmierer wird diesen Regeln folgen müssen.

## Kommentare

Kommentare beschreiben die Abläufe im Programm. Der Compiler übergeht sie, sie sind nur für den Menschen gedacht. Somit kann jede Art der Sprache verwendet werden. Aber ganz frei ist es auch nicht. Nur weil man alles damit machen kann und keine Fehlermeldung bekommt, heißt das noch lange nicht, dass es auch gut ist, was man geschrieben hat.
Schreibt die Kommentare so, dass sie für jeden Leser verständlich sind. Manche Sachen sind nur begrenzt für andere verständlich:
* lokal/regional/national begrenzte Beschreibungen - Wenn Ihr euren Code im Internet veröffentlicht, macht es wenig Sinn, die Kommentare auf Deutsch zu schreiben. Damit werden viel weniger Menschen Euren Code anschauen! Die Lingua Franca des Internets ist nun mal Englisch, ob man das mag oder nicht.
* Eigennamen, die nur Du verstehst - Auch das ist nicht sinnvoll. Vielleicht macht es Spaß Geheimnisse vor der kleinen Schwester zu haben, aber unter Programmierern ist das eher schwierig.
Es gibt drei Kommentarstile in Java:

### Einzeilige Kommentare //

Einzeilige Kommentare werden für kurze Beschreibungen benutzt. Diese sollten nicht die Syntax oder Sachen die der Programmierer auf den ersten Blick erkennt, erklären, sondern eher die Bedeutung einer Zeile für den Gesamtkontext.
Ein Codebeispiel sowie ein guter und schlechter Kommentar:
* Code:
* schlechter Kommentar:
Das hier ist ein schlechter Kommentar, weil ohnehin aus dem Quelltext hervorgeht, das hier ein neues Objekt erstellt wird. Dieser ist in der Regel beim Lesen von Quelltexten nur hinderlich - er muss mitgelesen werden, aber enthält keine wirklichen Informationen.
* guter Kommentar:
wobei die Pünktchen natürlich die Funktion des Objekts beschreiben sollten.
Dieser hier ist besser, da er erklärt wozu die Instanz verwendet wird, bzw. in welchem Zusammenhang das Objekt mit dem Programm steht.

### Mehrzeilige Kommentare

Einleitung mit /*
Schluss mit */
Diese Kommentare werden wie die obigen benutzt, nur eben für komplexere Sachverhalte.

### Dokumentationskommentare

Einleitung mit /** Schluss mit */
Jede Klasse wird mit dem Kommentar /** beschrieben. Dies hat einen wichtigen Grund: Mit dem Dokumentationsprogramm javadoc werden diese speziellen Kommentare ausgelesen und zu einer html-Dokumentation zusammengefasst. Ein gutes Beispiel ist die offizielle Java-API http://java.sun.com/j2se/1.5.0/docs/api/ Sie wurde mit dem javadoc-Programm erstellt - und somit auch mit den Kommentarkonventionen geschrieben.
Vor allem anstehende Aufgaben sollte man mit TODO kennzeichnen, um nicht zu vergessen, dass an der vermerkten Stelle noch etwas zu berichtigen ist

## Sprechende Variablennamen

Wenn Klassen, Variablen oder Methoden selbst geschrieben werden, sollten die Namen folgender Konvention folgen:

### "sprechende" Namen

Die Namen sollten "sprechend" sein. Auch wenn ein Fremder den Code anschaut, sollte er in etwa verstehen, wofür der Name steht. Bei diesem Fremden kann man aber davon ausgehen, dass er selber Java vom Ansatz her kann.
Sind mehrere Wörter im Namen zusammengefasst (z. B. Methode toString), so werden die Wörter gross und zusammen geschrieben. Die Regeln für die ersten Buchstaben wird weiter unten erklärt.

### Klassen

Klassen sollen groß geschrieben werden. Klassen sollen als Namen Nomen (Hauptwörter) besitzen. Also keine Verben, Adjektive, usw.

### Methoden

Methoden sollen aus einem Verb und einem Nomen bestehen, z. B. loescheDatei. Die Wörter werden wie in 1. erwähnt zusammen und gross geschrieben. Der Anfangsbuchstabe allerdings klein! Fällt Euch kein Nomen ein, ist es auch in Ordnung, wenn nur ein Verb benutzt wird.

### Variablen/ Objekte/ Instanzen

Diese drei sollen alle mit Nomen benannt werden. Auch hier soll der Anfangsbuchstabe klein geschrieben werden.

### static final Variablen/Objekte/Instanzen

Im Gegensatz zu ihren normalen Verwandten werden diese komplett groß geschrieben, um zu verdeutlichen, dass es sich hierbei um Konstanten handelt.

## Verschachtelte Methodenaufrufe

Auch wenn es für Euch manchmal keinen Sinn macht; schreibt eure Aufrufe von Methoden und Konstruktoren nicht alle ineinander. Drei Methoden pro Zeile sind schon genug, sonst leidet die Lesbarkeit sehr darunter. Wenn Ihr in euer eigenes Programm guckt, was Ihr vor einem halben Jahr geschrieben habt, findet Ihr euch selber manchmal nicht zurecht (Mir geht es so :-)). Da helfen klare Methodenaufrufe schon enorm.
Weitere Vorteile, jeden Aufruf in eine eigene Zeile zu schreiben:
* Stack Traces mit Zeilennummer sind dann hilfreicher. z.B. ist eine NullPointerException mit der Nummer einer Zeile, in der mehrere Aufrufe stehen, mehrdeutig.
* Mit einem Debugger kann man gezielter Breakpoints setzen.

## Codeeinrückung

Code sollte, und wird in praktisch allen Lehrbüchern und Codes, eingerückt geschrieben werden. Die Grundregel dafür lautet in etwa: Bei jedem Anfang eines logischen Abschnitts wird eingerückt. Dies ist bei { geschweiften Klammern } auf jeden Fall so! Aber man kann auch eine Folge von Methodenaufrufen untergliedern.
Leerzeichen nehmen keinen Platz weg, der Computer ignoriert sie sowieso; also spart nicht mit Einrückungen.
Einrückungen kann man mit TABs oder mit Leerzeichen machen. Letztere haben den Vorteil, dass die Einrückungstiefe bei allen Werkzeugen gleich ist.

## Leerzeilen

Spart nicht mit Leerzeilen - damit sind keine 20 Zeilen nacheinander gemeint. Aber lasst ruhig nach jedem logischen Abschnitt ein bis zwei Zeilen frei. In einem Deutschaufsatz schreibt Ihr ja auch nicht alles aneinander, sondern Ihr lasst Absätze?!

## Zeilenlänge

Im Grunde genommen gibt es aus DOS-Zeiten eine Minimaleinschränkung von 80 Zeichen. Bei den größeren Displays heutzutage sind aber Zeilenlängen von 120 Zeichen aber schon in Ordnung. Unschön kann jedoch der Ausdruck von Code auf Papier werden. Daher sollte man sich mit Bedacht auf eines festlegen!

## Reservierte Begriffe

Die folgenden Schlüsselwörter sind in Java reserviert und dürfen nicht für Variablenbezeichner verwendet werden:
Die Schlüsselworte const und goto werden nicht verwendet.

## Komplexe Typen

Java kennt auch die Definition eigener Typen. Dabei gibt es vier verschiedene Arten eigener Typen: Klassen, Schnittstellen, Aufzählungstypen und Annotationen.

### Klassen: class

Eine Klasse wird mit dem Schlüsselwort class definiert. Klassen, die an hierarchisch oberster Stelle in einem Quelltext stehen, heißen nicht-geschachtelte Top-Level-Klassen. Klassen, die in einer anderen Klasse definiert sind, heißen geschachtelte Klassen.
Eine geschachtelte Klasse, die als static deklariert wurde, heißt geschachtelte Top-Level-Klasse. Eine geschachtelte Klasse, die nicht als static deklariert wurde, heißt innere Klasse. Eine Klasse, die in einer Methode definiert wurde, heißt lokale Klasse. Darüberhinaus besteht auch die Möglichkeit, für die einmalige Verwendung Klassen ohne Namen und ohne das Schlüsselwort class zu deklarieren. Solche Klassen heißen anonyme Klassen.
Nicht-geschachtelte Top-Level-Klassen sind der Regel-Fall. Wenn es sich bei einer Klasse um eine nicht-geschachtelte Top-Level-Klasse handelt, darf die Klasse nur die Zugreifbarkeit public oder package default besitzen und außerdem nicht als static deklariert werden. Eine nicht-geschachtelte Top-Level-Klasse, die als public deklariert ist, muss zudem genauso heißen wie die Quelltext-Datei, inklusive Berücksichtigung der Groß- und Kleinschreibung. Das gilt auch unter Betriebssystemen, die eigentlich nicht zwischen Groß- und Kleinschreibung unterscheiden, wie z.B. Microsoft Windows.
Geschachtelte Klassen dürfen jede Zugreifbarkeit tragen.
Sämtliche Klassen dürfen als entweder abstract, final oder keines von beidem, nicht jedoch beides zugleich deklariert werden. Eine als abstract deklarierte Klasse heißt abstrakte Klasse, eine als final deklarierte Klasse heißt finale Klasse.
Es ist nicht möglich, abstrakte Klassen zu instanzieren. Stattdessen muss man sich eine geeignete Subklasse suchen oder selbst schreiben.
Es ist nicht möglich, eine Subklasse einer finalen Klasse zu bilden.

### Schnittstellen (Interfaces): interface

Eine Schnittstelle ist eine vollständig abstrakte Klasse. Da eine vollständig abstrakte Klasse keine Schwierigkeiten für die Implementierung in Bezug auf Mehrfachvererbung mit sich bringen kann, gestattet Java die Mehrfachvererbung nur in Bezug auf Interfaces. Um dies konsequent zu gewährleisten, unterscheidet Java streng zwischen Klassen und Interfaces.
Ein Interface kann keine Konstruktoren und somit auch keine Instanzinitialisierer enthalten.
Methoden in Interfaces sind automatisch public und abstract. Sie dürfen keine andere Zugreifbarkeit als public haben. Sie dürfen nicht final, static oder native sein.
Variablen in Interfaces sind automatisch public, static und final. Sie dürfen keine andere Zugreifbarkeit als public haben.
Ansonsten gilt für Interfaces das gleiche wie für Klassen. Interfaces können also auch Typen, z.B. innere Klassen enthalten.

### Annotationen (Annotations): @interface

Eine Annotation ist eine spezielle Schnittstelle für die Hinterlegung von Informationen über Java-Programme. Annotationen sind mit der Version 5.0 in Java eingeführt worden und werden hauptsächlich zur Ergänzung der Möglichkeiten von Reflection und zur Code-Generierung verwendet.
Für Annotationen gelten vergleichbar strenge Regeln wie für Interfaces.

### null

null ist kein Schlüsselwort im eigentlichen Sinn sondern ein Literal. Es dient dir dazu den Wert einer komplexen Datentyps zu setzen oder zu prüfen. Es handelt sich insoweit jedoch um einen Bezeichner, welchen du nicht vergeben kannst.

### void

void wird verwendet um bei der Signatur einer Methode den Rückgabetyp leer zu deklarieren.

### package

package deklariert die Paketzugehörigkeit eines komplexen Datentyps. Die Namensgebung eines Pakets sollte eindeutig sein und orientiert sich meist an der URI/URL des Eigentümers bzw. Erstellers. Bei einer Paket angabe handelt es sich grundsätzlich um die erste Anweisung im Java-Quelltext des Pakets.

### import

import importiert komplexe Typen, so dass sie ohne voll qualifizierten Namen verwendet werden können. Es können durch Nutzung des Wildcard * auch alle komplexen Typen eines Pakets importiert werden.
Seit Java 5.0 können auch statische Member von Klassen importiert werden.
| Funktionalität | Standard Edition | Mobile Edition | Enterprise Edition |
| Anwendung beenden | System.exit(int) | Midlet.notifyDestroyed | Systembeendigung durch Anwendung unzulässig |
| Bildformate (standardmäßig unterstützt) | PNG, JPEG/JPG, GIF (auch animierte) | PNG | PNG, JPEG/JPG, GIF (auch animierte) |