Sie sind auf Seite 1von 298

Tutorium zu Jetzt lerne ich Android 4-Programmierung

ISBN 978-3-8272-4818-3 Inhalt Seite 1

Inhalt

1 2 Willkommen beim Java-Schnellkurs ...................................................... 8 Technik der Programmerstellung .......................................................... 11 2.1 2.2 2.3 2.4 3 3.1 3.2 Compiler und Interpreter............................................................... 11 Die Java-Laufzeitumgebung JRE.................................................. 14 Programmerstellung mit dem JDK ............................................... 14 bung 1: HalloWelt - das erste Java-Programm ........................... 19 Einleitung ...................................................................................... 26 Vom Maschinencode zu den hheren Programmiersprachen ....... 28 Assembler ............................................................................. 29 Das Variablenkonzept ........................................................... 29 Die hheren Programmiersprachen ....................................... 31 Kontrollstrukturen ................................................................. 34 Typisierung ........................................................................... 39 Funktionen ............................................................................ 46 Selbst definierte Datentypen ................................................. 51 Objektorientierte Problemlsung .......................................... 58 Objektorientierte Programmierung in Java ........................... 60

Einfhrung fr Programmieranfnger ................................................... 26

3.2.1 3.2.2 3.2.3 3.2.4 3.3 3.3.1 3.3.2 3.4 3.4.1 3.4.2 3.4.3 3.5 4 4.1 4.2

Die strukturierte Programmierung ................................................ 39

Die objektorientierte Programmierung ......................................... 51

Noch Fragen? ................................................................................ 70 Kommentare.................................................................................. 72 Pakete und Import-Anweisung...................................................... 74

Anwendungsgrundgerst und Standardbibliothek ................................ 71

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Inhalt Seite 2

4.2.1 4.2.2 4.2.3 4.3 4.4

Ordnung schaffen mit Paketen .............................................. 74 Klassen aus Paketen verwenden ............................................ 75 Eigene Pakete ........................................................................ 76

Klassen .......................................................................................... 78 Eintrittspunkt ................................................................................. 80 Der Java-Eintrittspunkt: main() ............................................. 81 Der Android-Eintrittspunkt: onCreate() ................................ 83 Text (Strings) ausgeben ......................................................... 85 Zahlen und andere Daten ausgeben ....................................... 86 Text einlesen ......................................................................... 90 Zahlen einlesen...................................................................... 91

4.4.1 4.4.2 4.5 4.5.1 4.5.2 4.5.3 4.5.4 4.6 4.7 4.8 5 5.1

Ein- und Ausgabe .......................................................................... 84

Namensgebung .............................................................................. 92 Stil ................................................................................................. 93 bung 2: Daten einlesen und ausgeben ........................................ 94 Konstanten .................................................................................. 100 Literale ................................................................................ 100 Konstanten........................................................................... 102 Variablendefinition.............................................................. 102 Werte in Variablen speichern .............................................. 105 Initialisierung ...................................................................... 105 Werte von Variablen abfragen ............................................ 106 Gltigkeitsbereiche.............................................................. 107 Die elementaren Datentypen ............................................... 109

Praxisteil: Variablen und Konstanten .................................................. 100 5.1.1 5.1.2 5.2 5.2.1 5.2.2 5.2.3 5.2.4 5.2.5 5.3 5.3.1

Variablen ..................................................................................... 102

Datentypen .................................................................................. 108

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Inhalt Seite 3

5.3.2 5.3.3 5.3.4 5.3.5 5.3.6 5.3.7 5.4 5.4.1 5.4.2 5.4.3 5.5 5.6 6 6.1

Die komplexen Datentypen ................................................. 111 Klassen ................................................................................ 113 Interfaces (Schnittstellen) ................................................... 118 Arrays.................................................................................. 119 Aufzhlungen ...................................................................... 121 Strings ................................................................................. 122 Automatische oder implizite (widening) Typumwandlungen 124 Explizite (narrowing) Typumwandlungen ...................... 125 Selbst definierte Typumwandlungen................................... 125

Typumwandlung ......................................................................... 124

Wrapper-Klassen ........................................................................ 126 Quiz............................................................................................. 128 Die Operatoren ............................................................................ 132 Allgemeines ........................................................................ 132 Arithmetische Operatoren ................................................... 135 Zuweisungen ....................................................................... 136 Inkrement und Dekrement .................................................. 136 Die Vergleichsoperatoren ................................................... 137 Die logischen Operatoren.................................................... 140 Operatorhnliche Symbole .................................................. 143 Wichtige Methoden der Klasse Math .................................. 144 String-Literale ..................................................................... 146 String-Variablen .................................................................. 148

Praxisteil: Operatoren ......................................................................... 132 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 6.1.6 6.1.7 6.2 6.3 6.2.1 6.3.1 6.3.2

Mathematische Funktionen ......................................................... 143 Strings (Zeichenketten) ............................................................... 146

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Inhalt Seite 4

6.3.3 6.3.4 6.3.5 6.4 7 7.1

Konkatenation ..................................................................... 149 Vergleiche mit == und != und String-Pooling ..................... 149 Wichtige Methoden der Klasse String ................................. 151

bung 3: Berechnungen durchfhren ......................................... 153 Verzweigungen ........................................................................... 160 Die if-Konstruktion ............................................................. 160 Die if-else-Konstruktion ...................................................... 162 Die switch-Konstruktion ..................................................... 163

Praxisteil: Kontrollstrukturen .............................................................. 159 7.1.1 7.1.2 7.1.3 7.2 7.3

bung 4: Benutzereingaben prfen ............................................. 165 Schleifen...................................................................................... 168 Die while-Schleife ............................................................... 169 Die do-while-Schleife ......................................................... 172 Die for-Schleife ................................................................... 172 Abbruchbefehle ................................................................... 174

7.3.1 7.3.2 7.3.3 7.3.4 7.4 8 8.1

bung 5: Daten filtern ................................................................ 174 Eine Vektor-Klasse ..................................................................... 178 Zweidimensionale Vektoren................................................ 178 Die Klassendefinition .......................................................... 180 Gltigkeitsbereich ............................................................... 182 Zugriff von auerhalb der Klasse ........................................ 183 Statische Felder ................................................................... 186 Weiterfhrung des Beispiels ............................................... 187 Aufbau von Methodendefinitionen ..................................... 189

Praxisteil: Klassen ............................................................................... 178 8.1.1 8.1.2 8.2 8.2.1 8.2.2 8.2.3 8.2.4 8.3 8.3.1

Felder .......................................................................................... 182

Methoden .................................................................................... 188

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Inhalt Seite 5

8.3.2 8.3.3 8.3.4 8.3.5 8.3.6 8.4 8.5 8.6 9 9.1 9.2

Parameter ............................................................................ 191 Rckgabewerte .................................................................... 195 this....................................................................................... 199 berladung.......................................................................... 200 Weiterfhrung des Beispiels ............................................... 201

Der Konstruktor .......................................................................... 202 Zugriffschutz............................................................................... 206 bung 6: Body Mass Index-Klasse............................................. 210 Syntax ......................................................................................... 215 Besonderheiten geerbter Elemente.............................................. 218 Basisklassenelemente bilden ein Unterobjekt ..................... 218 Der Zugriffsspezifizierer protected ..................................... 220 Aufruf des Basisklassenkonstruktors .................................. 221

Praxisteil: Vererbung .......................................................................... 214

9.2.1 9.2.2 9.2.3 9.3 9.4 9.5 9.6

berschreibung ........................................................................... 223 Die Klasse Object ....................................................................... 224 bung 7: toString() berschreiben .............................................. 226 Polymorphie ................................................................................ 228 Dynamische Bindung .......................................................... 230 Typidentifizierung zur Laufzeit .......................................... 233

9.6.1 9.6.2 10

Exkurs: Collections ......................................................................... 235

10.1 Allgemeines ................................................................................ 235 10.2 Container anlegen ....................................................................... 236 10.3 Objekte ablegen und auslesen ..................................................... 237 10.4 Container-Auswahl ..................................................................... 237 10.5 Iteratoren ..................................................................................... 238 10.6 Suchen und Sortieren in Containern ........................................... 240

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Inhalt Seite 6

11

Exkurs: Schnittstellen...................................................................... 242

11.1 Abstrakte Methoden und Klassen................................................ 242 11.2 Interfaces ..................................................................................... 243 11.2.1 11.2.2 11.2.3 11.2.4 12 Interfaces und Polymorphie................................................. 243 Interfaces als Vertrge ......................................................... 244 Interfaces definieren ............................................................ 246 Interfaces implementieren ................................................... 247

Exkurs: Ausnahmen ........................................................................ 249

12.1 Schema einer Exception-Behandlung ......................................... 249 12.2 Exceptions auslsen .................................................................... 251 12.3 Exceptions abfangen ................................................................... 253 12.4 Exceptions und Methodendeklaration ......................................... 255 12.5 Exception-Klassen....................................................................... 256 12.6 finally-Klausel ............................................................................. 257 13 14 Exkurs: Anonyme Objekte .............................................................. 260 Exkurs: Innere Klassen ................................................................... 261

14.1 Innere Klassen ............................................................................. 261 14.2 Lokale Klassen ............................................................................ 261 14.3 Anonyme Klassen ....................................................................... 262 15 Exkurs: Threads .............................................................................. 263 15.1.1 Threads erzeugen ................................................................ 263 15.1 Die Klasse Thread ....................................................................... 263 15.2 Das Runnable-Interface ............................................................... 267 15.3 Thread-Synchronisierung ............................................................ 267 16 17 Exkurs: Ereignis-Listener................................................................ 270 Exkurs: Java Generics ..................................................................... 274

17.1 Syntax ......................................................................................... 275

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Inhalt Seite 7

17.1.1 17.1.2 17.1.3 17.1.4 18 19

Generische Klassen ............................................................. 275 Generische Interfaces .......................................................... 276 Generische Methoden ......................................................... 276 Eingeschrnkte Platzhalter .................................................. 277

17.2 Parameter und Variablen von generischen Typen....................... 277 Exkurs: Zufallszahlen ..................................................................... 280 Ein- und Ausgabe............................................................................ 281 19.1.1 File ...................................................................................... 281

19.1 Dateien ........................................................................................ 281 19.2 Ein- und Ausgabestrme (Streams) ............................................ 283 19.3 Byteorientierte Dateiein-/ausgabe ............................................... 284 19.3.1 19.3.2 19.4.1 19.4.2 19.4.3 20 FileInputStream/FileOutputStream ..................................... 284 BufferedInputStream/BufferedOutputStream ..................... 286 FileReader/FileWriter ......................................................... 287 InputStreamReader/OutputStreamWriter ............................ 288 BufferedReader/BufferedWriter ......................................... 289

19.4 Zeichenorientierte Ein-/Ausgabe ................................................ 287

Schlsselwrter ............................................................................... 291

Stichwortverzeichnis................................................................................... 292

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Willkommen beim Java-Schnellkurs Seite 8

1 Willkommen beim JavaSchnellkurs


Dieser Kurs wurde als Begleitmaterial zu dem Buch Jetzt lerne ich Android konzipiert und richtet sich an Leser mit grundlegenden Java-Kenntnissen, die dieses Wissen vertiefen und ausbauen mchten, Umsteiger von anderen Programmiersprachen, die sich mit den Javatypischen Konzepten und Syntaxformen vertraut machen mchten, und gegebenenfalls sogar absolute Anfnger, die mit diesem Tutorium den Einstieg in die Programmierung wagen mchten.

Sie knnen diesen Kurs vorab durcharbeiten oder und diese Vorgehensweise wrden wir Ihnen empfehlen parallel zu dem Buch Jetzt lerne ich Android lesen. Das Android-Buch enthlt dazu in den Text eingestreute Hinweise, wann Sie welche Tutorien (Kapitel) dieses Kurses durcharbeiten sollten. Der Kurs selbst gliedert sich in drei grere Abschnitte: einem ausfhrlichen Grundlagenteil dieser fhrt Sie in die wichtigsten Programmierkonzepte moderner objektorientierter Programmiersprachen ein, erlutert die Technik der Erstellung und Ausfhrung von JavaProgrammen und stellt Ihnen verschiedene Anwendungsgerste vor. Der Grundlagenteil umfasst die Tutorien 2 bis 4. einem Praxisteil hier lesen Sie, wie die in Tutorium 3 vorgestellten Programmierkonzepte in der Sprache Java umgesetzt sind, und erhalten Gelegenheit, das Gelernte in bungen umzusetzen. Der Praxisteil umfasst die Tutorien 5 bis 9 und sollte mglichst in einem Zug durchgearbeitet werden. einem Exkursteil dieser umfasst diverse Tutorien zu ausgesuchten, fortgeschrittenen Themen.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Willkommen beim Java-Schnellkurs Seite 9

Ziel des Kurses ist es, dem Leser so viele Java-Kenntnisse zu vermitteln, dass er a) den Erluterungen im Buch Jetzt lerne ich Android folgen kann und b) eine gute Basis fr weiterfhrende Java-Studien erhlt. Der Kurs legt zu diesem Zweck viel Wert auf die verstndliche Vermittlung zentraler Programmierkonzepte (siehe hierzu auch Tutorium 3, das mit besonderem Augenmerk auf diejenigen Leser geschrieben wurde, die noch keine Programmiererfahrung haben oder zumindest noch nie mit einer hheren, objektorientierten Programmiersprache gearbeitet haben) ... ... sowie auf die Vorstellung der wichtigsten Java-Syntaxformen, beginnend mit Tutorium 4. Der Kurs ist eine zustzliche Hilfe, die wir allen Android-Interessierten zur Verfgung stellen, um sich die ntigen Java-Grundkenntnisse zu erarbeiten. Er kann aber natrlich nicht die gleiche Qualitt oder die gleiche Leserspezifizitt haben, wie ein eigenes Lehrbuch, das zudem speziell auf die Bedrfnisse eines bestimmten Leserkreises zugeschnitten ist, wie z.B.: Das Java-Easy-Buch aus dem Markt+Technik-Verlag Ideal fr den blutigen Programmieranfnger. Mit leicht und sicher nachzuvollziehenden Schritt-fr-Schritt-Anleitungen. Ein Buch, mit dem jeder den Einstieg in die Java-Programmierung schaffen kann. Das Jetzt lerne ich Java-Buch aus dem Markt+Technik-Verlag Zur Wiederholung, Vertiefung und Fortbildung. Leicht verstndlich, mit Spa am Programmieren, aber ohne Anspruch auf Vollstndigkeit. Eines der erfolgreichsten Java-Einsteigerbcher auf dem deutschen Markt. Das Fromzero2hero Java-Buch aus dem Markt+Technik-Verlag Gleicher Anspruch wie das Jetzt lerne ich, aber in etwas flippigerer, visuell orientierter Aufmachung. Das Java Kompendium aus dem Markt+Technik-Verlag Umfassendes Standardwerk zur Java-Programmierung. Die Bereitstellung eines passenden Java-Kurses als Begleitmaterial zu einem anderen Einsteigertitel ist auch fr uns ein Novum. Wir wrden uns daher freuen, wenn Sie uns mitteilen wrden, wie Sie mit dem Kurs bzw. der parallelen Einarbeitung in Java und die Android-Programmierung zurechtgekommen sind, ob der Kurs eher ausfhrlicher oder stringenter sein sollte und was wir vielleicht noch ansonsten verbessern knnten. Unsere Mail-Adresse: autoren@carpelibrum.de.
Icon HINWEIS

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Willkommen beim Java-Schnellkurs Seite 10

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Technik der Programmerstellung Seite 11

2 Technik der Programmerstellung


In diesem Tutorium wollen wir klren, wie aus einem Java-Quelltext ein ausfhrbares Java-Programm wird. Sie werden lernen, was es mit den JavaHilfsprogrammen javac und java auf sich hat, was sich hinter den Begriffen Compiler, Linker und Virtual Machine verbirgt und wie Sie mithilfe des JDKs oder auch Eclipse Java-Programme erstellen.

2.1

Compiler und Interpreter

Vor vielen, vielen Jahren, als Arbeitspeicher noch in Kbyte gemessen wurde und Java eine kaum bekannte Insel war, da verstanden die Menschen noch die Sprache der ... nein, nicht die Sprache der Tiere ist gemeint, sondern die Sprache der Prozessoren. Der Prozessor ist das Herz eines jeden Rechners. Er ist es, der die Programme ausfhrt. Der Prozessor ist sehr schnell, aber er besitzt wenig Intelligenz. Er ist eine Maschine, die stur die Befehle abarbeitet, die an ihn geschickt werden. Ein Programm ist demnach nichts anderes als eine Folge solcher Befehle. Der Prozessor kann allerdings nur Befehle verarbeiten, die er kennt. Die Summe dieser Befehle wird auch als Befehlssatz bezeichnet. Zudem mssen die Befehle als Bitfolgen codiert sein, denn der Prozessor als digitaler Baustein kann eben nur Bitinformationen (Null oder Eins, sprich: Spannung liegt an, Spannung liegt nicht an) verarbeiten. Frher mussten Programmierer ihre Programme direkt mithilfe der Befehle aus dem Befehlssatz des Prozessors schreiben. Dies war natrlich sehr mhselig und so fand man schnell einen Weg, sich die Programmierarbeit zu erleichtern: Man verfasste die Programme zuerst als reine Quelltexte in einer speziellen Programmiersprache. Dann lie man diese Quelltexte in einem zweiten Schritt von einem passenden bersetzungsprogramm in ein ausfhrbares Programm (sprich eine Folge von binren Maschinenbefehlen) bersetzen. Seither wurden Tausende von Programmiersprachen entwickelt und fr jede dieser Sprachen gibt es passende bersetzerprogramme. Diese

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Technik der Programmerstellung Seite 12

bersetzerprogramme zerfallen grundstzlich in zwei Kategorien: Compiler und Interpreter.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Technik der Programmerstellung Seite 13

Compiler arbeiten, wie man es vom Beruf der bersetzer her kennt. Man bergibt dem Compiler den Quelltext und erhlt als Ergebnis das komplett bersetzte Programm, das anschlieend jederzeit ausgefhrt werden kann. Interpreter arbeiten eher wie Dolmetscher. Sie werden zwischengeschaltet, wenn das Programm ausgefhrt werden soll. Dann lesen sie das Programm, das nur als Quelltext vorliegt, blockweise ein, bersetzen den aktuellen Block und lassen ihn vom Prozessor ausfhren. Beide Anstze haben ihre Vor- und Nachteile, auf die wir hier jedoch nicht weiter eingehen. Wichtiger ist fr uns, dass Java das Beste aus beiden Welten verbindet, d.h. Java-Programme werden zuerst compiliert und dann interpretiert.
Rechner des Anwenders
0010 0001 1101 1010 0110 P r o z e s s o r P r o z e s s o r

Interpreter

Rechner des Programmierers


0011 1100 1110 0101 1001

Compiler

Rechner des Anwenders


0010 0001 1101 1010 0110

Interpreter

Abbildung 2.1: Kompilierung und Ausfhrung eines Java-Programms Zuerst wird auf dem Rechner des Programmierers der Java-Quelltext in Abbildung 2.1 symbolisiert durch das Blatt ganz links mit den Schriftlinien mithilfe des Java-Compilers javac in binren Code bersetzt. Dieser Code ist allerdings noch kein echter Maschinencode, denn er basiert auf einem mehr oder weniger fiktiven Befehlssatz, den sich die Entwickler von Java ausgedacht haben. Wir nennen diesen Code daher auch den Bytecode (als Abgrenzung zu dem prozessorspezifischen Maschinencode). Das als Bytecode vorliegende Programm kann dann an Freunde, Kunden oder wen auch immer weitergegeben und auf den Rechnern dieser Anwender ausgefhrt werden vorausgesetzt es ist auf dem Rechner ein JavaInterpreter installiert. Der wird dann zusammen mit dem Programm gestartet,

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Technik der Programmerstellung Seite 14

bersetzt den Bytecode in den Maschinencode des aktuellen Rechners und lsst ihn sogleich ausfhren.

2.2

Die Java-Laufzeitumgebung JRE

Es wurde im vorangehenden Abschnitt schon angedeutet: Damit ein JavaProgramm auf einem Rechner ausgefhrt werden kann, muss auf diesem Rechner ein Java-Interpreter installiert sein. Wirklich nur ein Interpreter? Wie so oft sind die wahren Verhltnisse komplizierter, als es zuerst den Anschein hat. Der Java-Interpreter bernimmt nmlich nicht nur die Aufgabe, den Bytecode blockweise zu lesen und zu bersetzen. Vielmehr simuliert er einen (nahezu) kompletten virtuellen Rechner und fhrt das Programm quasi auf diesem Rechner aus. Man spricht daher auch von der Java Virtual Machine. Alles, was zur Erzeugung dieser virtuellen Maschine ntig ist, inklusive dem eigentlichen Interpreter, der Java-Standardbibliothek (einer Sammlung grundlegender Klassen (CodeBausteine), die jeder Java-Programmierer beim Schreiben eigener Programme verwenden kann) sowie Browser-Plugin und anderer Hilfsprogramme, bildet zusammen die sogenannte Java-Laufzeitumgebung (Java Runtime Environment, kurz JRE). Die JRE gibt es fr eine Vielzahl von Plattformen und kann kostenlos von der Oracle-Website http://www.oracle.com/technetwork/java/javase/downl oads/index.html heruntergeladen werden. Eine aktuelle Version ist auch im JDK enthalten.

2.3

Programmerstellung mit dem JDK

In Java knnen Sie die verschiedensten Arten von Programmen schreiben. Die drei wichtigsten Grundtypen sind Konsolenanwendungen, GUI-Anwendungen und Applets.

Zum Einstieg in die Java-Programmierung konzentrieren wir uns ganz auf die Konsolenanwendungen.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Technik der Programmerstellung Seite 15

Konsolenanwendungen Konsolenanwendungen sind unserer Meinung nach zu Unrecht die Stiefkinder der modernen Software-Entwicklung. Ohne Fenster und ohne grafische Benutzeroberflche fristen sie in der bunten Welt der WindowManager ein kmmerliches Nischendasein. Viele PC-Benutzer, insbesondere aus der Microsoft-Windows-Gemeinde, wissen nicht einmal mehr, was eine Konsole ist und wie man mit ihr arbeitet. Die Schuld daran trgt nicht allein der Zeitgeist, sondern auch die Microsoft-Betriebssystemdesigner haben dazu beigetragen, die nachdem sie zu einer Zeit, als Mac- und UNIX-Benutzer schon lngst von leistungsfhigen Window-Managern profitierten, ihre Anhnger mit mittelmigen Surrogaten wie Windows 3.1 oder Windows 95 qulten nunmehr dazu bergegangen sind, die Erinnerung an MS-DOS zu lschen und die Konsole (unter Windows meist Eingabeaufforderung oder MS-DOS-Eingabeaufforderung tituliert) immer geschickter vor den Augen der Anwender zu verbergen. Dabei haben Konsolenanwendungen durchaus ihre Vorzge: Die Programme sind klein und schlank, schnell in der Ausfhrung und sofern man einigermaen mit der Arbeit auf der Konsole vertraut ist gut zu bedienen. Sie eignen sich vorzglich als Lehr- und bungsbeispiele zum Einstieg in die Programmierung (weswegen es sich bei den Beispielprogrammen aus den ersten Teilen dieses Buches fast ausnahmslos um Konsolenanwendungen handelt), werden aber auch weiterhin in der professionellen SoftwareEntwicklung eingesetzt beispielsweise fr Webserver-Software (gelegentlich ergnzt um fensterbasierte Konfigurationsprogramme), Tools fr Systemadministratoren oder eben fr Entwickler (siehe die JDKHilfsprogramme). Eine kurze Einfhrung in die Bedienung der Konsole finden Sie auf www.carpelibrum.de.
Icon REF

Ein einfaches Konsolen-Grundgerst Viele Programmierlehrbcher beginnen mit einem kleinen Programm, das die Meldung Hello World auf den Bildschirm ausgibt. Wir wollen uns dieser Tradition anschlieen und eine Konsolenanwendung erzeugen, die sich mit einem freudigen Hallo Welt meldet.
public class HalloWelt { public static void main(String[] args) {

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Technik der Programmerstellung Seite 16

System.out.println("Hallo Welt!"); } }

Was dieser Code bedeutet und wie er aufgebaut ist, soll uns im Moment noch nicht interessieren. Worum es uns geht, ist, wie wir diesen Quelltext erstellen, bersetzen und ausfhren knnen. Konsolenanwendungen erstellen und ausfhren Um Konsolenanwendungen auf Ihrem Computer zu erstellen und auszufhren, gehen Sie folgendermaen vor: 1. Rufen Sie einen beliebigen Texteditor auf, mit dem Sie Ihren Quelltext als reinen, unformatierten Text abspeichern knnen. Unter Windows eignet sich beispielsweise der Notepad-Editor, den Sie ber das Start-Men mit START/PROGRAMME/ZUBEHR/EDITOR aufrufen knnen. Alternativ knnen Sie das Start-Men ffnen und unten in das Suchfeld den Begriff notepad eingeben. Komfortabler als der Windows-eigene Notepad-Editor ist der Editor Notepad++, den Sie von der Webseite http://sourceforge.net/projects/notepad-plus herunterladen knnen. Unter Linux knnen Sie z.B. den vi, KEdit oder KWrite verwenden. 2. Legen Sie in Ihrem Editor eine neue Datei an (blicherweise Menbefehl DATEI/NEU), tippen Sie obigen Quelltext ein und speichern Sie die Datei unter dem Namen HalloWelt.java. Wichtig ist dabei, dass die Quelltextdatei exakt den gleichen Namen trgt wie die in dem Quelltext definierte Klasse (hier also class HalloWelt), wobei auch die Gro- und Kleinschreibung zu beachten ist. Weiterhin wichtig ist, dass die Datei die Dateiendung .java trgt! Bei Verwendung von Notepad unter Windows XP gibt es manchmal Probleme, weil der Notepad-Editor die Dateiendung .txt anhngt (aus HalloWelt.java wird dann HalloWelt.java.txt). Um dies zu vermeiden, gibt es zwei Mglichkeiten. Die erste Lsung besteht darin, den kompletten Dateinamen, samt Extension, in Anfhrungszeichen zu setzen: "HalloWelt.java". Die zweite Mglichkeit ist, die Extension .java im Windows Explorer zu registrieren. Speichern Sie dazu nach Methode 1 eine Datei mit der Extension .java. Wechseln Sie danach in den Windows
Icon REF

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Technik der Programmerstellung Seite 17

Explorer und doppelklicken Sie auf die Datei. Ist die Extension noch nicht registriert, erscheint jetzt der FFNEN MIT-Dialog. Whlen Sie als gewnschtes Bearbeitungsprogramm Notepad aus und aktivieren Sie die Option DIESE DATEI IMMER MIT DIESEM PROGRAMM FFNEN. Wenn Sie den Dialog jetzt abschicken, wird die Extension .java registriert und mit Notepad als Standardverarbeitungsprogramm verknpft. Danach knnen Sie .javaDateien per Doppelklick in Notepad laden und werden nie wieder rger mit an Java-Dateien angehngte .txt-Extensionen haben.

3.

Kompilieren Sie den Quelltext, indem Sie den Java-Compiler javac aufrufen und beim Aufruf den Namen der zu kompilierenden Quelltextdatei bergeben. ffnen Sie dazu ein Konsolenfenster und wechseln Sie in diesem zum Verzeichnis Ihrer Java-Quelldatei.

Im Gegensatz zu Linux-Anwendern sind viele Windows-Anwender heutzutage gar nicht mehr mit dem Umgang der Konsole vertraut. Unter Windows heit die Konsole Eingabeaufforderung oder MS-DOSEingabeaufforderung und wird ber das Start-Men aufgerufen (START/PROGRAMME/ oder START/PROGRAMME/ZUBEHR). In der Konsole mssen Sie nun mithilfe des cd-Befehls in das Verzeichnis wechseln, in dem Sie die Datei HalloWelt.java abgespeichert haben. Nehmen wir an, es war das Verzeichnis c:\Beispiele. Dann tippen Sie hinter dem Prompt der Konsole den Befehl cd c:\Beispiele ein und schicken ihn durch Drcken der (Enter)Taste ab.

Icon STOPP

Danach tippen Sie zum Kompilieren folgenden Befehl ein: javac HalloWelt.java Schicken Sie den Befehl durch Drcken der (Enter)-Taste ab. Hat sich kein Tippfehler eingeschlichen, wird als Ergebnis eine ausfhrbare Bytecode-Datei mit der Extension .class erzeugt in unserem Beispiel also HalloWelt.class. Sollten Sie beim Abschicken des Befehls eine Meldung in der Form Befehl oder Dateiname nicht gefunden erhalten, ist Ihr System nicht so eingerichtet, dass Sie die Java-Entwicklungsprogramme aus jedem beliebigen Verzeichnis aufrufen knnen. Lesen Sie dann bitte noch einmal in dem Buch
Icon STOPP

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Technik der Programmerstellung Seite 18

Jetzt lerne ich Android den Abschnitt 1.2.2 zur Eintragung des JDK in den Systempfad.

Wenn Sie irgendwann anfangen, den Quelltext des Programms auf mehrere Icon AUFSTEIGER Klassen/Dateien zu verteilen, bergeben Sie dem Compiler beim Aufruf eine Liste der Dateinamen oder wenn alle Dateien zusammen in einem Verzeichnis stehen einfach *.java.

4.

Lassen Sie die fertige Anwendung ausfhren. Dazu rufen Sie den Java-Interpreter (java) auf und bergeben diesem als Parameter den Namen Ihrer kompilierten Bytecode-Datei, aber ohne die Endung .class:
java HalloWelt

Sollten Sie daraufhin eine Fehlermeldung der Form Exception in thread "main" java.lang.NoClassDefFoundError: HalloWelt erhalten, bedeutet dies, dass der Interpreter die gewnschte Java-Klasse nicht findet. Dies kann daran liegen, dass die .class-Datei nicht erzeugt wurde (kontrollieren Sie nach dem Kompilieren mithilfe des Befehls dir, ob die Datei HalloWelt.class im Verzeichnis angelegt wurde). Mglich ist auch, dass Sie den Klassennamen nicht exakt so eingegeben haben, wie er im Quelltext definiert ist (auf gleiche Gro- und Kleinschreibung achten). Manchmal liegt es aber auch daran, dass irgendeines der auf Ihrem System installierten Programme die Java-Umgebungsvariable CLASSPATH so gesetzt hat, dass die Class-Dateien im aktuellen Verzeichnis nicht mehr gefunden werden. Dann mssen Sie die CLASSPATH-Variable bearbeiten und um den Platzhalter fr das aktuelle Verzeichnis (;.) erweitern. Klassenpfad Java-Programme bestehen aus Klassen. Diese sind in Quelltextdateien (Extension .java) oder als Bytecode in .class-Dateien (Extension .class) definiert. Wenn Sie ein Java-Programm kompilieren oder ausfhren, suchen sich die zustndigen Java-Hilfsprogramme (Compiler oder Interpreter) zu allen im Programm verwendeten Klassen die zugehrigen Quelltext- oder .class-Dateien zusammen.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Technik der Programmerstellung Seite 19

Standardmig wird im aktuellen Arbeitsverzeichnis (also von dem aus z.B. der Interpreter aufgerufen worden ist) und in den Class-Archiven .jar im LIB-Verzeichnis der JDK-Installation gesucht. Solange Sie fr jedes Programm ein eigenes Verzeichnis anlegen und die Quelltextdateien des Programms zusammen in diesem Verzeichnis speichern, gestaltet sich die Programmerstellung und -ausfhrung recht einfach. Probleme gibt es meist nur dann, wenn irgendein anderes Programm bei der Installation die CLASSPATH-Variable gesetzt hat. Dann suchen die JDKProgramme nmlich nicht mehr im aktuellen Verzeichnis es sei denn, das aktuelle Verzeichnis symbolisiert durch einen Punkt (.) wurde explizit in der Umgebungsvariablen mit aufgefhrt. Meist ist dies aber nicht der Fall, sodass Sie den Eintrag fr das aktuelle Verzeichnis selbst anhngen mssen. alter Eintrag: SET CLASSPATH=C:\programme\aerger neuer Eintrag: SET CLASSPATH=C:\programme\aerger;. Windows XP/Vista/7: Bearbeiten Sie die CLASSPATHUmgebungsvariable im Dialogfeld der Systemeigenschaften (analog zu der im Buch Jetzt lerne ich Android beschriebenen Einrichtung der PATH-Variablen). Linux: Setzen oder passen Sie die CLASSPATH-Variable in .login, .profile, .tcshrc, .bashrc o.. an (analog zu der im Buch Jetzt lerne ich Android beschriebenen Einrichtung der PATH-Variablen). Fr csh beispielsweise: setenv CLASSPATH /bin/aerger;.

2.4 bung 1: HalloWelt - das erste JavaProgramm


Aufgabenstellung Schreiben Sie ein Programm mit der Klasse HalloName, wobei Sie Name durch Ihren Vornamen ersetzen. ndern Sie auch den Text, den das Programm bei der Ausfhrung ausgibt, sodass Sie persnlich gegrt werden. Kompilieren Sie das Programm und fhren Sie es aus.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Technik der Programmerstellung Seite 20

Versuchen Sie die Aufgabe zuerst selbststndig zu lsen. Wenn Sie nicht weiter wissen und Hilfe bentigen, lesen Sie die Lsung. Lesen Sie den Lsungsabschnitt aber auch dann durch, wenn Sie die bung selbststndig bearbeiten knnen. Wir haben auf dem beschriebenen Lsungsweg absichtlich ein paar lehrreiche Fehltritte eingebaut. Lsung 1. 2. ffnen Sie Ihren Editor. Tippen Sie zunchst den ursprnglichen Quelltext ein.

3.

Speichern Sie die Datei unter dem Namen HalloWelt.java. Bitte die Datei nicht schlieen. Wir werden Sie gleich weiter bearbeiten.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Technik der Programmerstellung Seite 21

4.

Kontrollieren Sie, dass in der Titelleiste der korrekte Dateiname angezeigt wird. Falls Ihr Editor den Dateinamen nicht in der Titelleiste anzeigt, ffnen Sie den Windows Explorer und lassen Sie sich den Inhalt des Verzeichnisses anzeigen, in dem Sie die Datei gespeichert haben.

5. 6. 7.

ffnen Sie ein Konsolenfenster. Wechseln Sie in das Verzeichnis, in der die Java-Quelltextdatei gespeichert ist. Kompilieren Sie die HalloWelt.java. Datei mit dem Befehl javac

Kontrollieren Sie mithilfe des dir-Befehls, ob die Class-Datei erzeugt wurde.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Technik der Programmerstellung Seite 22

Wenn Sie nach Aufruf des Compilers javac Fehlermeldungen erhalten, vergleichen Sie noch einmal den Quelltext im Editor mit dem oben abgedruckten Code. Vermutlich haben sich Tippfehler eingeschlichen. Beachten Sie auch die Gro- und Kleinschreibung, die bei Java sehr wichtig ist. Lesen Sie die Fehlermeldungen des Compilers. Oft enthalten die Fehlermeldungen nhere Angaben zu der Art des Fehlers oder der Zeile, wo der Fehler ungefhr auftrat.

Icon STOPP

Java unterscheidet strikt zwischen Gro- und Kleinschreibung.

Icon MERKSATZ

So weit, so gut! Als nchsten Schritt werden wir den Namen der Klasse ndern. 8. 9. Wechseln Sie noch einmal in den Editor. Ersetzen Sie im Klassennamen HalloWelt den Teil Welt durch Ihren Vornamen. Wenn Sie also z.B. Dirk heien, sollte die Klasse nun den Bezeichner HalloDirk tragen.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Technik der Programmerstellung Seite 23

10. Speichern Sie die Datei. 11. Kompilieren Sie die Datei.

Hoppla! Der Compiler beschwert sich, dass die Klasse HalloDirk nicht in einer Datei HalloDirk.java definiert ist. Richtig. Wir haben ja vergessen, den Dateinamen zu ndern. Ein Hinweis zur Codeorganisation. Sie knnen in einer Java-Quelltextdatei beliebig viele Klassen definieren. Aber nur eine dieser Klassen darf als public definiert sein. Gibt es eine public-Klasse, muss die Datei exakt genauso heien wie die Klasse.
Icon MERKSATZ

12. Speichern Sie die Datei unter dem Namen der Klasse (Extension .java nicht vergessen).

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Technik der Programmerstellung Seite 24

13. Kompilieren Sie die Datei.

Sehr schn. Jetzt mssen wir nur noch die Ausgabe ndern. Um zu sehen, was die Ausgabe des Programms ist, sollten Sie das Programm jetzt einmal ausfhren.

Aha, die Ausgabe ist die Textpassage, die im Quelltext in den Anfhrungszeichen steht. Programmierer nennen so etwas einen String eine Zeichenfolge, die vom Icon MERKSATZ Programm verarbeitet sind. Um diese Zeichenfolgen von dem umliegenden Programmcode zu unterscheiden, werden sie blicherweise in Anfhrungszeichen gesetzt.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Technik der Programmerstellung Seite 25

14. ndern Sie den auszugebenden String in einen Gru, der an Sie gerichtet ist. 15. Speichern Sie die Datei. 16. Kompilieren Sie die Datei. 17. Fhren Sie das Programm aus.

Aufgabe erfllt!

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 26

3 Einfhrung fr Programmieranfnger
Dieses Tutorium, das wir aus dem Java-Kompendium bernommen haben, ist vor allem fr Leser gedacht, die noch berhaupt keine Erfahrung in der objektorientierten Programmierung haben, und fhrt anhand theoretischer Gedankenspiele und -modelle in die Grundprinzipien der Programmierung ein.

3.1

Einleitung

Java ist eine wunderbare Programmiersprache. Sie ist modern, leistungsfhig, vielseitig, in gewisser Weise sogar sthetisch ... Eines ist sie jedoch ganz bestimmt nicht: leicht zu erlernen. Nun, das alleine wre ja noch gar nicht mal so schlimm schlielich erwartet ja niemand, dass eine so mchtige Sprache von einem Tag auf den anderen zu meistern wre. Whrend sich der hoffnungsvolle Novize jedoch in die meisten anderen Sprachen Schritt fr Schritt einarbeiten kann, muss er sich in Java gleich zu Beginn mit einer Vielzahl sehr komplizierter Konzepte auseinandersetzen. So besteht bereits das einfachste Programm, das in Java geschrieben werden kann, aus mindestens vier Zeilen, vollgepackt mit kryptischem Code:
public class Programm { public static void main(String[] args) { System.out.println("Hallo Anwender!"); } }

Das gleiche Programm, das brigens nichts anderes macht, als den Benutzer mit einem freundlichen Hallo auf der Konsole zu begren, htte ein Basic-Programmierer Anfang der Neunziger wie folgt geschrieben:
print "Hallo Anwender!"

Die erste Hrde liegt fr den Java-Programmierer also extrem hoch, sodass ihm letzten Endes nur drei Mglichkeiten bleiben:

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 27

1.

Er luft unter der Hrde durch, d.h., er akzeptiert die ihm nicht verstndlichen Syntaxformen des Grundgersts als gottgegeben und arbeitet sich danach so gut es geht schrittweise in die Sprache ein.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 28

2.

Er wartet mit dem Programmieren, bis er sich theoretisch so weit in die Sprache eingearbeitet hat, dass er smtliche im Grundgerst vorkommenden Konzepte verinnerlicht hat. Dann erst nimmt er die Hrde. Er verzichtet auf jegliche Eleganz und klettert ber die Hrde.

3.

Den letzten Weg werden Sie jetzt einschlagen. Indem Sie in einem kurzen Abriss die historische Entwicklung der Programmiersprachen von den ersten Anfngen ber das alte Basic und C bis hin zu Java nachvollziehen, werden Sie sich mit den wichtigsten Konzepten moderner Programmiersprachen zumindest soweit vertraut machen, dass Sie das Grundgerst verstehen und einfache Programme schreiben knnen.

3.2 Vom Maschinencode zu den hheren Programmiersprachen


Programmieren bedeutet, dem Rechner Befehle zu erteilen, die er ausfhren kann. Frher wurden diese Befehle vom Rechenwerk ausgefhrt, das in den ersten Rechenmaschinen aus dem 19. Jahrhundert noch mechanisch arbeitete. Heute ist das Herzstck des Rechners der Prozessor. Doch eines hat sich nicht gendert: Jeder Rechner/Prozessor verfgt nur ber einen ganz begrenzten Satz an Befehlen, und auch diese versteht er nur, wenn sie binr, d.h. als eine Folge von Nullen und Einsen, codiert vorliegen.1

Ein moderner Maschinenbefehl sieht vereinfacht etwa wie folgt aus:

10000011 1100000 00000011

10000011 ist der Befehlscode des Addieren-Befehls. Er weist den Prozessor an, den Wert des im ersten Operanden angegebenen Registers um den Wert des zweiten Operanden zu erhhen. Die Bitfolge 1100000 steht fr das Register EAX (Register sind einzelne, interne Speicherzellen des Prozessors, in denen er die zu verarbeitenden Daten, etwa aus dem Arbeitsspeicher geladene Daten, zwischenspeichern kann). Der zweite Operand ist eine einfache Ganzzahl, die 3, nur eben binr codiert im Dualsystem: 00000011. Der gesamte Befehl lautet demnach: Addiere zu dem aktuellen Wert des Registers EAX den Wert 3.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 29

10100001 00111111101001100110010100000001 10000011 1100000 00000000000000000000000000000011 10100011 00111111101001100110010100000001

3.2.1 Assembler
Da die Programmierung mit binr codierten Maschinenbefehlen uerst mhselig und fehleranfllig ist, sann man schon frh auf Mglichkeiten, die Programmierung zu vereinfachen. Ein erster Schritt in diese Richtung war Assembler. Assembler-Programmierung ist immer noch Programmierung auf Maschinenebene, nur dass der Programmierer die Befehle nicht mehr binr codiert, sondern in Form sogenannter Mnemonics niederschreibt.
MOV EAX, [3FA66501] ADD EAX, 3 MOV [3FA66501], EAX

Ein spezielles bersetzerprogramm, das wie die Sprache ebenfalls Assembler genannt wird, bersetzt die Befehlsnamen (MOV, ADD ...), Registerbezeichnungen (EAX, EDX ...) Speicheradressen ([3FA66501] ) und Zahlen (3 ) in die zugehrigen Binrfolgen.

3.2.2 Das Variablenkonzept


Einfache Zahlen knnen zumeist direkt in die Maschinenbefehle integriert und vom Prozessor verarbeitet werden (siehe den Befehl ADD EAX, 3). Fr komplexere Daten wie z.B. Zeichenfolgen (Dies ist ein Text) ist dies nicht mglich. Sie mssen im Arbeitsspeicher abgelegt und bei Bedarf in den Prozessor geladen werden. Zeichenfolgen werden in der Programmierung gemeinhin als Strings bezeichnet.
1.

Auch Daten, denen im Programm eine bestimmte Bedeutung zukommt und deren Wert sich im Laufe des Programms ndern kann, mssen im Arbeitsspeicher verwahrt werden. Ein Programm, das die Mausklicks des Anwenders zhlt, knnte beispielsweise einen bestimmten Bereich im Arbeitsspeicher fr die Anzahl der Mausklicks reservieren. Beim Programmstart schreibt es den Wert 0 in diesen Speicherbereich. Danach

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 30

lauscht es auf Mausklicks, und jedes Mal, wenn der Anwender eine Maustaste drckt, liest es den aktuellen Wert des Speicherbereichs in den Prozessor, addiert den Wert 1 und schreibt das Ergebnis zurck in den Speicherbereich. So werden aus an sich bedeutungslosen Zahlenwerten sinnvolle Daten! In den obigen Maschinenbefehlen wurden die Speicheradressen, von denen Daten geladen oder in die Daten geschrieben werden sollten, stets als explizite (hexadezimale oder binre) Adressen angegeben. Dies hat zwei gravierende Nachteile: Der Programmierer muss sich merken oder gesondert notieren, welche Daten an welchen Adressen stehen, und er ist selbst fr die korrekte Speicherbelegung verantwortlich, muss also beispielsweise aufpassen, dass sich die Speicherbereiche zweier Daten nicht berlappen.

0xEF01 0xEF02 0xEF03 0xEF04 0xEF05

0xEF01 0xEF02 0xEF03 Preis 0xEF04 0xEF05

0xEF01 0xEF02

0xEF03 Preis

0xEF05

Abbildung 3.1: Variablen sind ein wenig wie Schubladen, in denen man Werte aufbewahren kann. Hier bringt das Konzept der Variablen, das schnell auch in Assembler Einzug fand, Abhilfe. Statt numerischer Speicheradressen vergibt der Programmierer Namen und berlsst dem bersetzerprogramm (im Falle der AssemblerProgrammierung also dem Assembler) die Zuordnung dieser Namen zu echten Speicheradressen. Statt nichts sagender Zahlen kann der Programmierer nun Namen auswhlen, die auf Art und Zweck der gespeicherten Daten hinweisen, beispielsweise mausklickZaehler, alter oder preis.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 31

Das Beziehungsgefge aus Name, zugehrigem Speicherort und darin abgelegten Daten wird als Variable bezeichnet. Im alltglichen Sprachgebrauch wird die Variable aber auch hufig mit ihrem Wert, d.h. mit den in ihr abgelegten Daten, gleichgesetzt. Wenn ein Programmierer also davon spricht, dass er die Variable A zur Variablen B addiert, so meint er damit, dass der Wert in der Variablen A zu dem Wert der Variablen B hinzuaddiert wird.

Icon INFO

3.2.3 Die hheren Programmiersprachen


Ende der Fnfziger, Anfang der Sechziger wurden die ersten hheren Programmiersprachen entwickelt. Anders als die Assemblersprachen, bei denen jeder Befehl der Sprache exakt einem Maschinenbefehl entspricht, arbeiten die hheren Programmiersprachen mit Anweisungen, die weitaus komplexere Operationen ausfhren und in eine ganze Folge von Maschinenbefehlen bersetzt werden. Klar, dass es hierfr spezielle, entsprechend leistungsfhige bersetzerprogramme geben muss. Dabei wird je nach der prinzipiellen Arbeitsweise zwischen Compilern und Interpretern unterschieden: Ein Compiler liest den gesamten Quelltext des Programms (oder Programmmoduls) ein, analysiert ihn und bersetzt ihn dann in Maschinencode. Dieser Maschinencode kann mithilfe eines weiteren Programms, des Linkers, mit anderem Maschinencode verbunden und in ein ausfhrbares Programm verwandelt werden (beispielsweise eine Windows-EXE-Datei). Zum Starten des Programms wird die ausfhrbare Programmdatei aufgerufen. Ein Interpreter liest den Quelltext Zeile fr Zeile ein. Jede Zeile wird sofort bersetzt und direkt zur Ausfhrung an den Prozessor weitergereicht. Zum Ausfhren des Programms muss also nur der Quelltext des Programms an den Interpreter bergeben werden.

Fr jede hhere Programmiersprache gibt es einen eigenen Compiler oder Interpreter. Wortschatz und Grammatik der Programmiersprache sind in der Spezifikation der Sprache niedergeschrieben und im Compiler (oder Interpreter) implementiert. Die Sprache wird also genauso gut durch den Compiler (Interpreter) wie durch ihre Spezifikation definiert. Oder um es noch drastischer zu formulieren: Wenn Sie ein Programm geschrieben haben, das sich mit dem zugehrigen Compiler nicht bersetzen lsst, nutzt es Ihnen

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 32

gar nichts, wenn Sie belegen knnen, dass Ihr Quelltext exakt den Regeln der Sprachspezifikation folgt. Letzte Instanz ist in so einem Fall der Compiler. Sie knnen sich bei dem Compiler-Hersteller beschweren, aber wenn Sie Ihr Programm bersetzen mchten, mssen Sie den Regeln folgen, die der Compiler implementiert2. Die obige Unterscheidung zwischen Compiler und Interpreter beschreibt die traditionellen Grundprinzipien, die mit Kompilation und Interpretation verbunden sind. Obwohl diese Grundprinzipien nach wie vor gelten, knnen moderne Compiler und Interpreter in einzelnen Punkten davon abweichen. (Der Java-Compiler erzeugt beispielsweise weder echten Maschinencode noch ausfhrbare EXE-Dateien, sondern Bytecode, siehe Tutorium Technik der Programmerstellung.)
Icon REF

Ein einfaches Programm, das von der Konsole eine Radiusangabe einliest, den zugehrigen Kreisumfang berechnet und diesen auf die Konsole ausgibt, wrde in Basic geschrieben wie folgt aussehen:
' Programm zur Berechnung des Kreisumfangs print "Geben Sie einen Radius ein: " input radius umfang = 2 * 3.1415 * radius print "Der Kreisumfang betraegt " umfang

Das Programm beginnt damit, dass es einen Text ausgibt, der den Anwender auffordert, ber die Tastatur einen Radiuswert einzutippen. Dieser wird mit dem Schlsselwort input in die Variable radius eingelesen. (Die Variable radius wird dabei automatisch eingerichtet und mit ausreichend Speicher verbunden.) In der vorletzten Quelltextzeile wird der Kreisumfang berechnet und in der neuen Variablen umfang abgespeichert. Schlielich gibt das Programm einen kurzen erluternden Text und den Inhalt von umfang auf die Konsole aus.

rgerlich ist es, wenn es zu einer Programmiersprache mehrere Compiler (bzw. Interpreter) gibt, die die Syntax und Grammatik der Sprache jeder fr sich ein wenig verndern oder eigenmchtig interpretieren. In so einem Fall schafft jeder dieser Compiler (Interpreter) einen eigenen, inkompatiblen Sprachdialekt (wie dies Microsoft beispielsweise mit der Einfhrung seines Visual J++-Compilers anstrebte).

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 33

Das Beispiel zeigt nicht nur, wie einfach die Programmierung in hheren Programmiersprachen sein kann; es demonstriert auch den Einsatz einiger wichtiger Elemente, die fr Quelltexte hherer Programmiersprachen typisch sind: Kommentare, die den Quelltext erklren und vom Programmierer eingefgt werden, damit er selbst oder andere Programmierer sich spter schneller in den Quelltext einarbeiten knnen. Kommentare werden vom bersetzerprogramm ignoriert. (' Programm zur Berechnung des Kreisumfangs). Konstante Werte, die in der Programmierung als Literale bezeichnet werden ("Geben Sie einen Radius ein! ", 2, 3.1415 ...). Beachten Sie, dass in Dezimalzahlen die Nachkommastellen durch einen Punkt und nicht wie im Deutschen blich durch ein Komma abgetrennt werden! Variablen, zum Abspeichern und Verwalten der Daten (radius, umfang). Operatoren, zur Durchfhrung einfacher, grundlegender Bearbeitungsschritte wie der Multiplikation (*) oder der Zuweisung eines berechneten Werts an eine Variable (=). In der Sprache oder in den Standardbibliotheken der Sprache implementierte hhere Befehle, die hufig bentigte Aufgaben erledigen beispielsweise das Einlesen von Daten ber die Tastatur (input) oder die Ausgabe von Strings auf die Konsole (print).

Bildschirmausgaben und Konsolenanwendungen Die meisten PC-Benutzer, vor allem Windows- oder KDE-Anwender, sind daran gewhnt, dass die Programme als Fenster auf dem Bildschirm erscheinen. Dies erfordert aber, dass das Programm mit dem Fenstermanager des Betriebssystems kommuniziert und spezielle Optionen und Funktionen des Betriebssystems nutzt. Programme, die ohne fensterbasierte, grafische Benutzeroberflche (GUI = graphical user interface) auskommen, knnen hierauf jedoch verzichten und stattdessen die Konsole zum Datenaustausch mit dem Benutzer verwenden. Die Konsole ist eine spezielle Umgebung, die dem Programm vorgaukelt, es lebe in der guten alten Zeit, als es noch keine Window-Systeme gab und immer nur ein Programm zurzeit ausgefhrt werden konnte. Dieses

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 34

Programm konnte dann uneingeschrnkt ber alle Ressourcen des Rechners verfgen beispielsweise die Tastatur, das wichtigste Eingabegert, oder auch den Bildschirm, das wichtigste Ausgabegert. Der Bildschirm war in der Regel in den Textmodus geschaltet, wurde also nicht aus Pixelreihen, sondern aus Textzeilen aufgebaut. Unter Windows heit die Konsole MS-DOS-Eingabeaufforderung oder auch nur Eingabeaufforderung und kann je nach Betriebssystem ber START/PROGRAMME oder START/PROGRAMME/ZUBEHR aufgerufen werden. Konsolenprogramme werden meist von einem Konsolenfenster aus aufgerufen, d.h., am Eingabeprompt (Ende der untersten Textzeile der Konsole) wird der Name des Programms eingetippt und mit der (Enter)Taste abgeschickt. Die Ausgaben des Programms erscheinen Zeile fr Zeile darunter (sind die Zeilen der Konsole vollgeschrieben, werden sie nach oben gescrollt). Eingaben ber die Tastatur werden in der aktuellen Zeile der Konsole angezeigt und nach Drcken der (Enter)-Taste an das Programm weitergeleitet.

Abbildung 3.2: Ausfhrung eines Java-Programms auf der Windows-Konsole

3.2.4 Kontrollstrukturen
Maschinenbefehle werden grundstzlich der Reihe nach so wie sie in den Arbeitsspeicher geladen wurden oder wie der Interpreter sie an den Prozessor

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 35

schickt ausgefhrt. Wo es ntig oder opportun ist, von dieser sequenziellen Ausfhrung abzuweichen, kann der Programmierer Sprungbefehle einbauen, die dafr sorgen, dass die Programmausfhrung an einer beliebigen anderen Stelle des Programms fortgefhrt wird. Hhere Programmiersprachen, auch Basic, geben die Fhigkeit Sprnge zu vollziehen meist auf verschiedene Weise an den Programmierer weiter: durch direkte Sprnge zu beliebigen Anweisungen (das zugehrige Schlsselwort heit in der Regel goto) durch spezielle Kontrollstrukturen, die der bersetzer mithilfe von Sprngen realisiert durch Funktionsaufrufe (siehe Abschnitt Funktionen)

Die direkten Sprnge mit goto sollen uns nicht weiter interessieren. Sie fhren schnell zu wirrem Spagetticode und werden in Java daher nicht untersttzt. Wesentlich interessanter sind da schon die Kontrollstrukturen, zu denen die bedingte Ausfhrung, die Verzweigung und die Schleife

gehren. Die bedingte Ausfhrung Eine bedingte Ausfhrung dient dazu zu entscheiden, ob eine nachfolgende Anweisung oder ein Anweisungsblock ausgefhrt werden soll oder nicht. In den meisten Programmiersprachen wird die bedingte Ausfhrung mit dem Schlsselwort if eingeleitet. In Basic hat sie folgenden Aufbau:
if (Bedingung) then Anweisung(en) end if

Diese Konstruktion kann man wie einen deutschen Konditionalsatz lesen: Wenn die Bedingung erfllt ist, dann (und nur dann) fhre die Anweisungen aus. Bei Ausfhrung des Programms wird zuerst die Bedingung ausgewertet. Die Bedingung ist dabei nichts anderes als ein Vergleich, beispielsweise

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 36

verkaufszahlen < 1000 (ist der Wert von verkaufszahlen kleiner 1000?). Liefert der Vergleich als Ergebnis wahr, ist die Bedingung erfllt und der zur if-Bedingung gehrende Anweisungsblock wird ausgefhrt; andernfalls wird das Programm mit der nchsten Anweisung unter der if-Anweisung (d.h. unter der Zeile end if) fortgesetzt. Die meisten Programmiersprachen stellen fr das Aufsetzen von Vergleichen die folgenden Vergleichsoperatoren zur Verfgung (siehe Tabelle 3.1).
Operator Bedeutung gleich ungleich kleiner grer kleiner oder gleich grer oder gleich Beispiel (fr i = 3 und j = 50)

== != < > <= >=

i == 4 i != 4 i < j i > j i <= 5 i >= 3

// unwahr // wahr // wahr // unwahr // wahr // wahr

Tabelle 3.1: Gngige Vergleichsoperatoren

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 37

Die Verzweigung Eine Verzweigung bedeutet, dass das Programm in Abhngigkeit vom Wert einer Bedingung einen von mehreren Anweisungsblcken ausfhren soll. Die einfachste Verzweigung liegt vor, wenn man eine if-Bedingung um einen else-Zweig erweitert:
if (Bedingung) then Anweisungen A else Anweisungen B end if

Diese Konstruktion kann man wie folgt lesen: Wenn die Bedingung erfllt ist, dann fhre die Anweisungen A aus, berspringe den else-Block mit den Anweisungen B und fahre mit der nchsten Anweisung hinter der if-else-Konstruktion fort. Wenn die Bedingung nicht erfllt ist, berspringe den Block mit den Anweisungen A, fhre den else-Block mit den Anweisungen B aus, und fahre mit der nchsten Anweisung hinter der if-else-Konstruktion fort. Eine weitere wichtige Form der Verzweigung ist die select- oder caseVerzweigung, die in Abhngigkeit vom Wert eines Ausdrucks zu verschiedenen Stellen in einem Anweisungsblock springt.
Icon INFO

Die Schleife Schleifen dienen dazu, eine Anweisung oder einen Anweisungsblock mehrfach hintereinander ausfhren zu lassen. Die wichtigsten Schleifentypen sind die for- und die while-Schleife. Typisch fr Schleifen ist die Einrichtung einer Schleifenvariablen, ber die man kontrolliert, wie oft die Schleife ausgefhrt wird. Dazu wird die Schleifenvariable bei Eintritt in die Schleife auf einen Anfangswert gesetzt, in der Schleife in Einerschritten erhht (oder in irgendeiner anderen Weise verndert) und vor jedem neuen Schleifendurchgang getestet.
i = 1 do while (i <= 10) print "Quadrat von " i " ist gleich " i * i

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 38

i = i + 1 loop

Wie wird diese Schleife ausgefhrt? Vor Eintritt in die Schleife wird die Schleifenvariable i auf 1 gesetzt. Danach beginnt die Schleife, die aus dem Schlsselwort while, der Schleifenbedingung und dem Schleifenkrper (dem nachfolgenden Anweisungsblock) besteht. In der Schleifenbedingung wird geprft, ob der Wert von i kleiner oder gleich 10 ist. Solange wie die Schleifenbedingung erfllt ist, wird die Schleife ausgefhrt. Beim Eintritt in die Schleife ist i gleich 1. Die Bedingung ist also erfllt und der Schleifenkrper wird ausgefhrt. Damit die Schleife etwas halbwegs Sinnvolles tut, geben wir im Schleifenkrper zuerst mithilfe von print das Quadrat der Schleifenvariablen aus. Danach wird der Wert der Schleifenvariablen inkrementiert (i = i + 1). Jetzt ist der aktuelle Schleifendurchgang beendet, nicht jedoch die Schleife! Die Programmausfhrung springt an dieser Stelle nmlich zurck zum Anfang der Schleife und zur Schleifenbedingung. Wieder wird berprft, ob der Wert der Variablen i (der jetzt gleich 2 ist) noch kleiner gleich 10 ist. Da dies der Fall ist, wird der Schleifenkrper ein zweites Mal ausgefhrt. So wird der Schleifenkrper zehn Mal hintereinander ausgefhrt. Beim zehnten Schleifendurchgang wird der Wert von i von 10 auf 11 hoch gesetzt. Nach dem zehnten Schleifendurchgang wird noch einmal die Schleifenbedingung getestet, doch da i jetzt grer als 10 ist, ist die Bedingung nicht mehr erfllt, das heit, der Schleifenkrper wird nicht mehr ausgefhrt, die Programmausfhrung springt hinter die Schleife und wird mit der nchsten Anweisung nach der Schleife fortgesetzt. Auf dem Bildschirm bleibt die Ausgabe der Schleife zurck:
Quadrat von 1 ist gleich 1 Quadrat von 2 ist gleich 4 Quadrat von 3 ist gleich 9 ... Quadrat von 10 ist gleich 100

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 39

3.3

Die strukturierte Programmierung

Die Programmierung, die Sie im vorangehenden Abschnitt kennengelernt haben mit Daten auf der einen Seite und Daten verarbeitenden Operatoren und Anweisungen auf der anderen Seite , bezeichnet man als imperative Programmierung. Die ersten imperativen Programmiersprachen waren Fortran (1957), Algol (1958), Cobol (1960) und Basic (1964). Daneben entstanden weitere Programmiersprachen, die anderen Programmierparadigmen folgten: beispielsweise dem Paradigma der objektorientierten Programmierung, welches statt der Daten die Objekte in den Mittelpunkt der Programmierung rckte. Noch aber dominierte die imperative Programmierung die Szene und die Siebziger und Achtziger des letzten Jahrhunderts standen ganz im Zeichen einer Sprache: C.

3.3.1 Typisierung
Im Vergleich zu Basic, das interpretiert wurde, gehrte C zu den kompilierten Sprachen3. Fr den Benutzer hat dies verschiedene Vorteile. Zum einen braucht er keinen Interpreter, um die Programme ausfhren zu knnen. Zum anderen wird die Ausfhrungsgeschwindigkeit der Programme wesentlich beschleunigt, da die Programme als Maschinencode vorliegen (EXE-Dateien) und direkt ausgefhrt werden knnen (und nicht erst nach und nach in Maschinencode bersetzt und durch Vermittlung des Interpreters ausgefhrt werden). Fr uns Entwickler hat die Umstellung ebenfalls Vorteile. Beispielsweise werden die Programme nicht mehr als fr jeden lesbaren Quelltext an die Benutzer und Kunden ausgeliefert, sondern als binre EXE-Datei. Der Quelltext und damit die in das Programm investierte Entwicklungsarbeit werden dadurch vor Nachahmern und illegaler Verwertung geschtzt. Die Umstellung bringt aber auch Nachteile mit sich. Da Maschinencode prozessorspezifisch ist (also nur von einem bestimmten Prozessor oder einer Prozessorfamilie ausgefhrt werden kann), sind die erstellten EXE-Dateien nicht portabel knnen also nicht zwischen Rechnern mit inkompatiblen Prozessoren und Betriebssystemen ausgetauscht werden.

Die Vorstufen zu C waren noch interpretiert.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 40

Am unmittelbarsten betreffen uns aber die Konsequenzen, die das Sprachdesign betreffen. In interpretierten Sprachen ist es meistens mglich, in ein und derselben Variablen nacheinander unterschiedliche Arten von Daten (der Fachbegriff lautet Datentyp) zu speichern:
eineVar = 1 ... eineVar = "Hallo"

Hier wird in eineVar zuerst eine Zahl (1) und spter ein String ("Hallo") gespeichert. Zahlen und Strings stellen aber zwei gnzlich verschiedene Datentypen dar, deren Werte unterschiedlich viel Speicher belegen, nach ganz verschiedenen Verfahren in Bitfolgen und wieder zurck in Werte codiert werden, in ganz unterschiedlicher Weise bearbeitet werden knnen (Zahlen kann man beispielsweise addieren, multiplizieren, dividieren etc. mit Strings geht dies nicht).
Icon STOPP

Grundstzlich gilt, dass jeder Datentyp eine bestimmte Klasse von Daten beschreibt und Speichergre, Binrcodierung und untersttzte Operationen festlegt. Die fr die Programmierung wichtigsten Datentypen sind Ganzzahlen (Integer), Dezimalzahlen (Gleitkommazahlen), Zeichen, boolesche Wahrheitswerte und Strings.

Dezimalzahlen werden in Programmiersprachen blicherweise mit dem Punkt als Trennzeichen zwischen Vorkomma- und Nachkommastellen geschrieben: 3.141592653

Icon ACHTUNG

Werden in einer Variablen nacheinander Werte unterschiedlicher Datentypen gespeichert, mssen Speicherbelegung und Binrcodierung der Daten an den Datentyp angepasst werden. Ein Interpreter kann dies leisten, ein Compiler kann es nicht. Warum? Der Compiler muss den gesamten Quelltext bersetzen, bevor das Programm ausgefhrt wird. Kann eine Variable unterschiedliche Arten von Daten aufnehmen, ergeben sich aber schnell

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 41

Situationen, in denen sich nicht vorhersagen lsst, welche Art von Wert zu einem bestimmten Zeitpunkt in einer Variablen steht. Fazit: Der Compiler kann nicht entscheiden, wie er den Wert der Variablen decodieren oder verarbeiten soll. Sehen Sie sich dazu folgenden Code an, wobei n einen Wert hat, der erst zur Laufzeit festgelegt wird (er knnte beispielsweise ber die Tastatur vom Benutzer eingelesen werden):
eineVar = 3; if (n > 10) { eineVar = "Hallo"; } zweiteVar = eineVar; // siehe Funote4

Welcher Wert wird hier in zweiteVar abgespeichert? Die Zahl 3 oder der String Hallo? Ohne den Wert von n zu kennen, kann diese Frage nicht beantwortet werden von uns ebenso wenig wie von dem Compiler. Ein Interpreter knnte diesen Quelltext dagegen ohne Probleme bersetzen, da er den Code Schritt fr Schritt bersetzt und ausfhrt. Er muss nur irgendwo protokollieren, welche Variable gerade welche Art von Daten enthlt (und diese Information immer dann anpassen, wenn in einer Variablen ein Wert eines anderen Datentyps abgespeichert wird). Bei der Programmierung stellt sich oftmals die Frage, wann eine bestimmte Information (etwa der Datentyp einer Variablen) verfgbar und bekannt ist. Unterschieden wird hierbei zwischen der Laufzeit (whrend der Ausfhrung des Programms) und der Kompilierzeit (vor der Ausfhrung des Programms; also zu einem Zeitpunkt, wo nur der reine, noch zu kompilierende Quelltext vorliegt).
Icon REF

Das Codefragment wurde bereits ein wenig an die C- (und Java-) typische Syntax angepasst: Anweisungen werden mit Semikolon abgeschlossen! Anweisungsblcke, etwa von if-Bedingungen werden in geschweifte Klammern eingefasst!

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 42

Typisierte Variablen Damit ein Programm kompilierbar ist, mssen die Datentypen der Variablen und Werte (weitgehend) zur Kompilierzeit bekannt sein. Kompilierte Programmiersprachen wie C oder Java fordern daher vom Programmierer, dass er Variablen, mit denen er arbeiten mchte, vorab deklariert. In der Deklaration sind der Name und der Datentyp der Variablen (bzw. der Werte, die in der Variablen gespeichert werden knnen) anzugeben. Gltige Variablendeklarationen in C sind beispielsweise:
int zaehler; float quotient; char zeichen; int wert = 3; char option = 'b'; float bruch = 0.33333;

// Deklaration mit gleichzeitiger // Wertzuweisung (Initialisierung)

int, float und char sind Schlsselwrter5 von C, die speziell fr die Variablendeklaration in die Sprache aufgenommen wurden. Fortan kann der Programmierer nur noch mit Variablen arbeiten, die deklariert sind. Versucht er, neue Variablen wie bisher direkt zu verwenden, quittiert der Compiler dies bei der bersetzung des Quelltextes mit einer Fehlermeldung.
zahl = 3; quadr = zahl * zahl; // Fehler: zahl nicht definiert // Fehler: quadr nicht definiert

Korrekt wre:
int zahl; int quadr; zahl = 3; quadr = zahl * zahl;

In gleicher Weise schmettert der Compiler Versuche ab, in einer Variablen einen Wert abzuspeichern, der nicht zum Datentyp der Variablen passt:
int zahl; zahl = 3.4; /* Fehler: zahl ist vom Typ int, zugewiesen wird aber ein Gleitkommaliteral */

Wrter, die zum festen Wortschatz der Sprache gehren

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 43

Korrigierte Version:
float zahl; zahl = 3.4;

Positive Folgen der Typisierung Der Compiler stellt sicher, dass Werte und Variablen eines Datentyps nur in einer typgemen Weise verwendet werden. (Sie knnen also beispielsweise nicht Strings miteinander multiplizieren.) Keine Fehler durch falsch geschriebene Namen Wenn Sie einen Variablennamen falsch schreiben, knnen Sie froh sein, wenn Sie mit einem Compiler arbeiten.
float prozentsatz = 0.012; float guthaben = 2000; float gewinn = guthaben * prozenstatz;

Ein Interpreter, der Variablen nach Bedarf erzeugt, wird prozenstatz fr eine neue Variable halten, die er diensteifrig anlegt und deren Wert er mit guthaben multipliziert. Welchen Wert hat prozenstatz? Entweder weist der Interpreter der neu angelegten Variablen einen Standardwert zu, beispielsweise 0, oder er interpretiert einfach das zufllige Bitmuster, das er in der neu angelegten Variablen vorfindet, als Wert. Auf jeden Fall wird der Wert nicht dem Wert in prozentsatz entsprechen und das Programm wird falsche Ergebnisse liefern. Ein Compiler wird dagegen sofort feststellen, dass der Name prozenstatz nicht deklariert ist und eine Fehlermeldung ausgeben. Einfachere und effizientere Speicherverwaltung Auch wenn Sie in hheren Programmiersprachen mit Integern, Gleitkommazahlen, Strings und anderen Daten arbeiten, drfen wir nicht vergessen, dass alle diese Daten vom bersetzer in Bitfolgen codiert werden. Fr jeden Datentyp gibt es dazu ein eigenes Codierungsverfahren: fr Integer beispielsweise das 2n+1-Komplement, fr Gleitkommazahlen die IEEE 754, fr Zeichen den Unicode, Strings werden meist als Folgen von Zeichen codiert. Fr die elementaren Datentypen (Integer, Gleitkomma, Zeichen, Boolean, nicht aber String!) liefern diese Codierungsverfahren Bitfolgen fester Gre. Steht der Datentyp einer Variablen von vornherein fest, kann der bersetzer dem Datentyp entnehmen, wie viel Speicher er fr die

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 44

Variable reservieren muss. Dieses sehr effiziente und speicherschonende Verfahren ist typisch fr Compiler. Interpreter, die Datentypwechsel gestatten, mssen den bentigten Speicher hingegen von vornherein so berechnen, dass er fr alle Datentypen ausreicht, oder dynamisch, d.h. zur Laufzeit, bei jedem Datentypwechsel neuen Speicher reservieren. bersichtliche Zusammenfassung der Variablendeklarationen Variablendeklarationen mssen nicht an dem Ort stehen, wo die Variable erstmalig verwendet wird. Sie mssen der Verwendung lediglich vorangestellt sein. Der Programmierer kann dies dazu nutzen, wichtige Variablen am Anfang des Programms zusammenzuziehen. Die Programme werden dadurch meist bersichtlicher und besser verstndlich. Lediglich lokal bentigte Hilfsvariablen, beispielsweise Schleifenvariablen, werden vor Ort deklariert. Negative Folgen der Typisierung Die strenge Abgrenzung der Datentypen, die vom Compiler berwacht wird, fhrt zu besseren, weil sichereren Programmen. Sie kann sich aber auch als extrem strend und nervttend erweisen dann nmlich, wenn der Programmierer darauf angewiesen ist, einen Wert von einem Datentyp in einen anderen umzuwandeln. Betrachten wir noch einmal das BasicProgramm aus dem Abschnitt Die hheren Programmiersprachen:
' Programm zur Berechnung des Kreisumfangs print "Geben Sie einen Radius ein: " input radius umfang = 2 * 3.1415 * radius print "Der Kreisumfang betraegt " umfang

In der dritten Zeile liest das Programm eine Eingabe ber die Tastatur ein und speichert diese in der Variablen radius. Eingaben von der Tastatur sind aber stets Zeichenfolgen (Strings). Wenn der Anwender also beispielsweise 10 eintippt, so schickt er nicht die Zahl 10, sondern den String "10" an das Programm! Der Basic-Interpreter macht radius daher zu einer String-Variablen. Eine Zeile darunter taucht radius in einer Multiplikation auf. Die Multiplikation ist aber nur fr Zahlen, nicht fr Strings mglich. Der BasicInterpreter merkt dies und wandelt den String "10" automatisch in die Integer-Zahl 10 um und rechnet mit dieser weiter.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 45

In der letzten Zeile haben wir schlielich die umgekehrte Typwandlung: In umfang steht eine Gleitkommazahl, die vom Interpreter fr die Ausgabe auf die Konsole in einen String umgewandelt wird. Ein Compiler wrde eine solche Vorgehensweise nie untersttzen. Zuerst wrde er vom Programmierer fordern, dass radius als String-Variable und umfang als float-Variable deklariert werden mssen. Kommt der Programmierer dieser Aufforderung nach, bemngelt der Compiler, dass die String-Variable radius nicht in Multiplikationen und die float-Variable umfang nicht in Ausgaben verwendet werden knnen. Typumwandlungen Das obige Beispiel verdeutlicht wohl eindrcklich, dass eine sinnvolle Programmierung ohne die Mglichkeit zur Umwandlung von Datentypen nicht denkbar ist. Kompilierte und interpretierte Sprachen unterscheiden sich aber zumeist darin, welche Art von Typumwandlungen sie zulassen und wie diese durchgefhrt werden. So erlauben die meisten interpretierten Programmiersprachen die Umwandlung des Typs von Variablen, die kompilierten Programmiersprachen hingegen nur die Umwandlung von Werten.
int eineZahl = 3; float andereZahl; andereZahl = eineZahl;

Hier wird in der dritten Zeile der Wert 3 aus der int-Variablen ausgelesen, in einen float-Wert umgewandelt (3.0) und in der float-Variablen andereZahl abgespeichert. eineZahl enthlt danach immer noch den int-Wert 3! Weiterhin gibt es in streng typisierten, kompilierten Sprachen nur wenige Typumwandlungen, die automatisch durchgefhrt werden. (Ein Beispiel fr eine automatische Typumwandlung in C ist die im obigen Beispiel demonstrierte Umwandlung eines int-Werts in einen float-Wert.) Bestimmte Typumwandlungen knnen vom Programmierer durch Voranstellung des gewnschten Zieltyps erzwungen werden beispielsweise die Umwandlung eines float-Werts in einen int-Wert (wobei die Nachkommastellen verloren gehen).

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 46

int eineZahl; float andereZahl = 3.4; eineZahl = (int) andereZahl;

Schlielich gibt es die Mglichkeit, die gewnschte Typumwandlung selbst zu programmieren. Diese Mglichkeit steht selbstverstndlich immer offen, kann sich aber als recht mhsam erweisen. Manchmal hat der Programmierer aber auch Glck und es gibt in der Standardbibliothek passende Funktionen, die die gewnschte Typumwandlung implementieren.

3.3.2 Funktionen
Funktionen sind ein von vielen Programmiersprachen angebotenes Hilfsmittel zur Modularisierung des Programmcodes (in rein objektorientierten Sprachen wie Java treten an die Stelle der Funktionen die Klassen und deren Methoden, doch dazu spter mehr). Warum empfiehlt es sich, Programmcode zu modularisieren? Erstens wird der Programmquelltext bersichtlicher. Wenn Sie ein mittelgroes Programm von einigen Hundert Zeilen, Anweisung fr Anweisung aufsetzen, werden Sie irgendwann groe Schwierigkeiten haben zu verstehen, was in Ihrem Programm eigentlich vorgeht (noch schwieriger drfte dies fr andere Programmierer sein, die Ihr Programm spter eventuell berarbeiten und warten mssen). Mithilfe von Funktionen knnen Sie grere Programme in Teilprobleme auflsen. Nehmen wir an, Sie mchten ein Programm schreiben, das mehrere Zahlenwerte einlesen und daraus den Mittelwert berechnen soll. Anstatt den Code direkt Anweisung fr Anweisung niederzuschreiben, knnen Sie das Programm in die folgenden drei Teilprobleme auflsen:
Werte einlesen Mittelwert berechnen Ergebnis ausgeben

Nachdem Sie dies getan haben, schreiben Sie fr jedes der drei Teilprobleme eine eigene Funktion, die das Teilproblem bearbeitet. Im Hauptteil des Programms brauchen Sie dann nur noch nacheinander die drei Funktionen aufzurufen. Der zweite Grund, der fr die Auslagerung von Code in Funktionen spricht, ist, dass man Funktionen sehr gut wiederverwerten kann. Eine einmal im Programm definierte Funktion kann man nmlich an jeder beliebigen Stelle

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 47

des Programms aufrufen. Stellen Sie sich vor, Sie mssen in Ihrem Programm an verschiedenen Stellen eine recht komplizierte mathematische Formel berechnen. Ohne Funktionen mssten Sie an jeder Stelle, an der die Formel berechnet werden soll, die Anweisungen zur Berechnung der Formel neu aufsetzen. (Sie knnen den Code natrlich kopieren, doch wenn Sie spter im Code einen Fehler bemerken, haben Sie immer noch das Problem, nachtrglich smtliche Stellen aufsuchen und den Fehler beheben zu mssen.) Mit Funktionen knnen Sie eine Funktion zur Berechnung der Formel schreiben und brauchen diese dann nur noch an den betreffenden Stellen aufzurufen. Definition und Aufruf Letzten Endes ist eine Funktion nichts anderes als ein Anweisungsblock, der mit einem Namen (dem Funktionsnamen) versehen ist, damit man ihn von beliebigen Stellen des Programms aus aufrufen kann.
funktionsname() { Anweisung(en); }

Weiter unten im Programm knnte diese Funktion dann wie folgt aufgerufen werden:
... funktionsname(); ...

Der Funktionsaufruf bewirkt einfach, dass die Programmausfhrung in den Anweisungsblock der Funktion springt. Nach Abarbeitung des Funktionscodes kehrt die Programmausfhrung dann wieder in die Zeile des Aufrufs zurck und das Programm wird fortgesetzt (natrlich ohne nochmalige Ausfhrung der Funktion). Funktionen wren aber nicht sehr hilfreich, wenn es nur darum ginge, einen ausgelagerten Anweisungsblock auszufhren. Darum gestatten Funktionen es auch, Werte vom Aufrufer entgegenzunehmen und Ergebnisse an den Aufrufer zurckzuliefern. Betrachten Sie hierzu die folgende C-Funktion, die einen int-Wert entgegennimmt und das Quadrat dieses Werts zurckliefert.
int quadrat(int n) int ergebnis; ergebnis = n * n; {

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 48

return ergebnis; }

Der Name dieser Funktion ist quadrat. Sie definiert einen int-Parameter namens n, ber den sie beim Aufruf einen int-Wert als Argument entgegennimmt. Dann folgt der Anweisungsblock der Funktion, in dem zuerst eine lokale Variable ergebnis deklariert wird. Diese Variable kann nur innerhalb der Funktion quadrat verwendet werden. In der nchsten Zeile wird das Quadrat des bergebenen int-Werts berechnet (n * n) und in der lokalen Variablen ergebnis abgespeichert. In der letzten Anweisung wird das berechnete Quadrat an den Aufrufer zurckgeliefert. Um einen Ergebniswert zurckliefern zu knnen, muss man in der Funktionsdefinition vor dem Funktionsnamen den Datentyp des zurckgelieferten Werts angeben (in unserem Beispiel int) und im Anweisungsblock der Funktion den Wert mithilfe des Schlsselworts return abschicken. Das Schlsselwort return liefert nicht nur den bergebenen Wert zurck, sondern beendet auch die Funktion. Nachfolgende Anweisungen werden also nicht mehr ausgefhrt.
Icon STOPP

Soll eine Funktion keinen Rckgabewert zurckliefern, gibt man in der Funktionsdefinition als Rckgabetyp void an und verzichtet auf die return-Anweisung.
void eine_funktion() { ... }

Icon REF

Sehen wir uns noch an, wie eine solche Funktion aufgerufen wird.
main() als Startpunkt des Programms

Wenn Sie ein Programm aufrufen, wird es Anweisung fr Anweisung ausgefhrt. Das bedeutet aber nicht, dass die erste ausgefhrte Anweisung auch die oberste Anweisung im Programmquelltext ist. Die meisten Programmiersprachen definieren vielmehr spezielle Eintrittspunkte. In C ist dies beispielsweise eine besondere Funktion namens int main(). Jedes C-Programm muss ber eine solche main()-Funktion verfgen, und mit dem Aufruf dieser Funktion beginnt die Ausfhrung des Programms.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 49

01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20

#include <stdio.h> int quadrat(int n) { int ergebnis; ergebnis = n * n; return (ergebnis); } int main() { int loop; int erg; for (loop=1; loop <= 10; ++loop) { erg = quadrat(loop); printf("Quadrat von %d ist %d\n",loop,erg); } } return 0;

Dies ist ein vollstndiges, lauffhiges C-Programm. Die Zeilennummern gehren allerdings nicht zum Programmcode, sie stehen nur hier im Buch, damit wir uns bei der Besprechung leichter auf einzelne Zeilen des Quelltextes beziehen knnen. Das Programm beginnt mit einer Anweisung, die Sie noch nicht kennen. Es handelt sich hierbei um eine Direktive an den C-Compiler, den Inhalt der Header-Datei stdio.h in den Programmquelltext einzufgen. Die HeaderDatei enthlt die Deklarationen verschiedener vordefinierter Funktionen aus der C-Laufzeitbibliothek. Insbesondere die Funktion printf(), die wir in Zeile 16 zur Ausgabe der berechneten Quadratzahlen verwenden, ist in stdio.h deklariert. Indem wir stdio.h mit include einbinden, brauchen wir keine eigene Ausgabefunktion aufzusetzen, sondern knnen die vorgefertigte printf()-Funktion aus der C-Laufzeitbibliothek verwenden. In den Zeilen 2 bis 8 folgt die Definition der oben beschriebenen Funktion zur Berechnung des Quadrats. Darunter, in Zeile 10, beginnt die main()-Funktion. Wird das Programm gestartet, springt die Programmausfhrung also zuerst in diese main()Funktion. Diese wird dann Anweisung fr Anweisung abgearbeitet. Nach dem Anlegen der Variablen loop und erg tritt die Programmausfhrung in Zeile 14 in eine for-Schleife ein, die zehnmal durchlaufen wird. Bei jedem

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 50

Durchlauf der for-Schleife wird zuerst die Funktion quadrat() aufgerufen und ihr als Argument der aktuelle Wert der Schleifenvariablen loop bergeben (Zeile 15). Dieser Wert wird beim Aufruf in den Parameter n der Funktion kopiert. Jetzt wird die Funktion ausgefhrt. Sie berechnet das Quadrat von n und liefert das Ergebnis an den Aufrufer zurck. Zurck in Zeile 15 nimmt der Aufrufer (hier die main()-Funktion) den von der Funktion zurckgelieferten Wert entgegen und speichert ihn in der Variablen erg. In Zeile 16 wird der Wert von erg ausgegeben. Danach beginnt der nchste Schleifendurchgang. Insgesamt gibt das Programm also die Quadrate der Zahlen von 1 bis 10 aus. Fr eine so einfache Berechnung wie das Quadrat einer Zahl wrde man selbstverstndlich keine eigene Funktion aufsetzen. Erstens spart dies keine Tipparbeit, zweitens kostet ein Funktionsaufruf immer auch zustzliche Laufzeit (weswegen man allgemein versuchen sollte, Funktionen nicht in Schleifen aufzurufen). Da wir gerade bei der Laufzeitanalyse sind, sei auch noch angemerkt, dass man den Anweisungsblock der Funktion quadrat() auch krzer schreiben kann:
int quadrat(int n) { return n * n; }
Icon REF

Imperative Programmierung mit Funktionen wird auch als strukturierte Programmierung bezeichnet.

Icon INFO

Bibliotheken Die meisten Programmiersprachen verfgen nur ber wenige, fest in die Sprache integrierte Funktionalitt. Damit die Programmierer aber deswegen nicht laufend das Rad neu erfinden mssen, verfgen diese Programmiersprachen ber umfangreiche Bibliotheken, in denen fr viele Standardaufgaben fertige Lsungen angeboten werden (meist in Form von Funktionen, Klassen oder Objekten).

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 51

So verfgt C anders als Basic ber keinen in die Sprache integrierten Befehl zum Ausgeben von Daten auf die Konsole, dafr gibt es aber in der CLaufzeitbibliothek die Funktion printf().

3.4

Die objektorientierte Programmierung

Die Programmierung mit Zeichen, Integer, Gleitkommazahlen und Strings ist auf die Dauer recht unbefriedigend. Ebenso wie der Programmierer in seinen Quelltexten bei Bedarf Zahlen addiert, multipliziert und dividiert, mchte er irgendwann auch Adressen erfassen, durchsuchen, ausdrucken, ComicFiguren zeichnen, vergrern, verkleinern oder fr Kreise, Quadrate und andere geometrische Formen Umfang und Flche berechnen. Kurzum, er mchte mit beliebigen Daten arbeiten und hofft, dass die Programmiersprache ihn dabei mglichst tatkrftig untersttzt. Der uerst wichtigen und interessanten Frage, wie diese Untersttzung aussehen kann, werden wir im Folgenden ausfhrlich nachgehen und dabei ganz nebenbei den Sprung von der imperativen zur objektorientierten Programmierung vollziehen.

3.4.1 Selbst definierte Datentypen


Die Grundvoraussetzung fr die Programmierung mit eigenen Datentypen ist, dass diese auf elementare und vordefinierte Datentypen zurckgefhrt werden knnen, die dem Compiler bekannt sind. Die elementaren Datentypen sind in der Sprache selbst verankert. Zu ihnen gehren in der Regel die Zeichen (char), verschiedene Integer- und Gleitkommatypen, die sich im Wertebereich unterscheiden (beispielsweise short fr Integer-Zahlen von -32.768 bis 32.767 und int fr IntegerZahlen von -2147483648 bis 2147483647 sowie float fr Gleitkommazahlen mit einfacher und double fr Gleitkommazahlen mit doppelter Genauigkeit). Moderne Sprachen wie Java definieren zudem einen eigenen elementaren Datentyp fr Wahrheitswerte (boolean). Strings sind in der Regel nicht als eigener Typ in der Sprache verankert. In Java gehren sie zu den vordefinierten Typen, die in der Standardbibliothek implementiert sind. Wir drfen sie also ruhigen Gewissens als Ausgangsmaterial fr unsere eigenen Datentypen verwenden.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 52

1. Stufe Die erste Stufe besteht darin, dass die Sprache auer den elementaren und vordefinierten Datentypen keine weitere Untersttzung fr die Programmierung mit eigenen Datentypen bietet (Stufe der frhen imperativen Programmiersprachen). Auf dieser Stufe deklariert der Programmierer einfach die elementaren Daten, durch die er seinen eigenen Datentyp simuliert, und manipuliert diese, wie es dem angestrebten Datentyp gem ist.
Beispiel

Sie erhalten den Auftrag, ein Programm zu schreiben, das Umfang und Flche von Kreisen berechnet. Eine sptere Version des Programms soll auch feststellen knnen, ob sich zwei Kreise schneiden. Umfang und Flche eines Kreises hngen nur von seinem Radius ab. Fr die erste Version knnten Sie einen Kreis also einfach durch eine doubleVariable reprsentieren, die den Radius des Kreises enthlt. Bei der fr spter anvisierten Schnittpunktberechnung mssen aber auch die Kreismittelpunkte bekannt sein, sodass Sie sich entschlieen, fr jeden Kreis Radius und die Koordinate des Mittelpunkts festzuhalten.
// Kreis, gegeben durch Radius und Mittelpunktkoordinaten double radius; double xMittelpunkt; double yMittelpunkt;

Um einen Kreis zu setzen, weisen Sie die Kreisdaten den entsprechenden Variablen zu:
radius = 1.5; xMittelpunkt = 0; yMittelpunkt = 0;

Fr komplexere, hufiger bentigte Operationen auf Kreisen beispielsweise die Berechnung von Umfang und Flche knnen Sie eigene Funktionen schreiben:
// Kreisumfang double umfang(double r) { return 2 * 3.14159 * r; } // Kreisflche double flaeche(double r) { return 3.14159 * r * r; }

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 53

Wie Sie sehen, ist es gar nicht so schwer, beliebige Datentypen auf Resmee elementare Datentypen zurckzufhren. Tatschlich ist eine solche Rckfhrung immer mglich sei es, dass Sie wie oben komplexere Datengebilde aus elementaren Daten zusammensetzen, sei es, dass Sie neue Daten durch elementare Daten codieren (Schulnoten wie Sehr gut, Gut, Befriedigend etc. knnten Sie beispielsweise durch die entsprechenden Strings, aber auch durch int-Werte von 1 bis 6 codieren), sei es durch Kombination und Codierung. Trotzdem ist das obige Verfahren in vieler Hinsicht unzulnglich. So gibt es den neuen Datentyp Kreis ebenso wie seine Daten, die einzelnen Kreise, nur im Kopf des Programmierers. Dieser muss nicht nur den berblick darber behalten, welche Variablen zu dem Datentyp gehren. Wenn es mehrere Kreise gibt, mit denen das Programm gleichzeitig arbeiten soll, muss er auch noch die Variablen der einzelnen Kreise auseinander halten:
radiusKreis1 = 1.5; xMittelpunktKreis1 = 0; yMittelpunktKreis1 = 0; radiusKreis2 = 4.2; xMittelpunktKreis2 = 5; yMittelpunktKreis2 = 10;

Viel Arbeit erspart die Implementierung der datentypspezifischen Operationen als Funktionen, doch auch hier gilt, dass die Zuordnung der Funktionen zu dem Datentyp allein im Kopf des Programmierers stattfindet. Verarbeitet das Programm beispielsweise neben den Kreisen auch Quadrate, die durch ihre Seitenlnge definiert sind und fr die eine Funktion flaecheQuadrat(double s) definiert wurde, muss der Programmierer aufpassen, dass er zur Berechnung der Flche eines Quadrats nicht aus Versehen die Kreis-Funktion flaeche() aufruft:
... double f = 0; double seiteQuadrat = 12.5; f = flaeche(seiteQuadrat); //Fehler, fhrt zu falsch berechneter Flche

Whrend der Compiler fr die elementaren Datentypen sicherstellen kann, dass der Programmierer auf diesen nur die typspezifischen Operationen ausfhrt, ist er hier machtlos, da es aus seiner Sicht weder die Datentypen Kreis und Quadrat noch irgendwelche datentypspezifischen Operationen gibt.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 54

2. Stufe Der erste Schritt hin zu einem echten Datentyp, der auch vom Compiler als solcher erkannt und honoriert wird, besteht darin, die Datenelemente, aus denen sich der neue Datentyp zusammensetzt, in einer Datentypdefinition zusammenzufassen. (Stufe leistungsfhiger strukturierter Programmiersprachen wie Pascal oder C.)
class Kreis { double radius; double x; double y; }

// Mittelpunkt

Das Schlsselwort class zeigt dem Compiler an, dass ein neuer Datentyp namens Kreis definiert wird. (Das wir hier class als Schlsselwort gewhlt haben, liegt natrlich daran, dass wir letztlich auf die Definition von Klassentypen hinarbeiten.) Jetzt knnen Sie Variablen vom Typ Kreis definieren:
Kreis k1; Kreis k2;

Mithilfe des Punktoperators knnen Sie auf die Datenelemente eines classTyps zugreifen:
k1.radius = 1.5; k1.x = 0; k1.y = 0; k2.radius = 4.2; k2.x = 5; k2.y = 10;

Auch die Funktionen, die uns als Ersatz fr datentypspezifische Operatoren dienen, knnen jetzt so umgeschrieben werden, dass sie mit den KreisVariablen arbeiten:
// Kreisumfang double umfang(Kreis k) { return 2 * 3.14159 * k.radius; } // Kreisflche double flaeche(Kreis k) { return 3.14159 * k.radius * k.radius; }

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 55

Um bei soviel unterschiedlichen Arten von Variablen und Daten nicht den berblick zu verlieren, fhren wir an dieser Stelle eine neue Terminologie ein. Aufgrund ihrer im Vergleich zu einfachen int- oder double-Werten hheren Komplexitt bezeichnen wir die Werte der selbst definierten Datentypen als Objekte oder Instanzen ihrer Klasse. Die in der Typdefinition aufgefhrten Datenelemente bezeichnen wir als Felder oder Instanzvariablen (weil es Variablen sind, von denen jede Instanz einen Satz eigener Kopien bekommt). Die Variablen der selbst definierten Typen bezeichnen wir weiterhin einfach als Variablen oder wenn die besondere Machart ihrer Werte hervorgehoben werden soll als Objektvariablen. k1 und k2 aus den vorangehenden Codefragmenten sind demnach Variablen, genauer gesagt Objektvariablen. Ihre Werte sind Objekte oder Instanzen ihres Klassentyps. Meist werden wir aber wie im Falle der elementaren Datentypen die Variable mit dem von ihr reprsentierten Wert gleichsetzen und daher von den Objekten k1 und k2 sprechen (statt von den Objekten, die durch k1 und k2 reprsentiert werden). radius, x und y sind Felder oder Instanzvariablen.

Icon REF

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 56

Klassendefinition
class Kreis { double radius; double x; double y; }

Felder Objekte der Klasse


radius

Objektvariablen
Kreis k1; k1.radius = 1.5; k1.x = 0; k1.y = 0; Kreis k2; k2.radius = 4.2; k2.x = 5; k2.y = 10; x y

1.5 0 0

radius
4.2

x
5

y
10

Abbildung 3.3: Objektorientierte Terminologie (Achtung, noch keine hundertprozentige Java-Syntax!)

Resmee

Jetzt gibt es endlich echte eigene Datentypen. Ein Kreisobjekt ist jetzt ein echtes Objekt und nicht mehr nur eine Anhufung von Variablen, die nur im Kopf des Programmierers verknpft werden. Mehrere Objekte knnen durch ihre Variablennamen unterschieden werden, und selbst die missbruchliche Anwendung von Funktionen wird eingeschrnkt, denn wenn Sie versuchen, der Funktion flaeche(Kreis k) einen int-Wert oder gar ein Objekt eines zweiten selbst definierten Datentyps Quadrat zu bergeben, wird der Compiler dies mit einer Fehlermeldung abblocken. Trotzdem ist die Implementierung der datentypspezifischen Operationen in Form von Funktionen immer noch eine Krcke. Wir bessern daher nach.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 57

3. Stufe die Klassendefinition Im letzten Schritt ziehen wir die Funktionen, die die datentypspezifischen Operationen implementieren, in die Typdefinition hinein:
class Kreis { double radius; double x; double y;

// Mittelpunkt

// Kreisumfang double umfang() { return 2 * 3.14159 * radius; } // Kreisflche double flaeche() { return 3.14159 * radius * radius; } }

Zwei wichtige Punkte haben sich in den Funktionsdefinitionen gendert: Die Definition des Kreis-Parameters ist entfallen. Dies hngt damit zusammen, dass die Funktion spter ganz so wie ein Feld ber den Punktoperator angesprochen wird (k1.flaeche()) und dann automatisch das Kreis-Objekt bearbeitet, fr das sie aufgerufen wurde. Das zu bearbeitende Objekt geht also aus dem Aufruf hervor und muss nicht mehr als Argument bergeben werden! In der Funktionsdefinition greifen Sie direkt auf die Felder des KreisTyps zu (radius statt obj.radius).
Icon REF

Unsere Typdefinition kann die hnlichkeit zu den Klassendefinitionen von C++ oder Java nun nicht mehr weiter verheimlichen. Wir sprechen daher von nun an offiziell von einer Klassendefinition. Um die Funktionen einer Klasse von den normalen Funktionen zu unterscheiden, bezeichnen wir sie als Methoden. Klassen sind in C++ oder Java nicht die einzige, wohl aber die bedeutendste Mglichkeit, eigene Datentypen zu definieren.

Mithilfe der Klasse Kreis ist die Berechnung des Umfangs eines Kreises mit einem Radius von 2,7 cm ein Kinderspiel:

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 58

Kreis k; double umfang; k.radius = 1.5; umfang = k.umfang();

3.4.2 Objektorientierte Problemlsung


Was bedeutet es berhaupt zu programmieren? Es bedeutet, Probleme oder Aufgaben zu lsen. Manchmal sind die gestellten Aufgaben zu komplex, um sie direkt lsen zu knnen. Dann zerlegt der Programmierer die Aufgaben so lange, bis sich lsbare Teilaufgaben ergeben. Diese Divide-And-ConquerTechnik6 gilt fr jegliche Programmierbemhungen. Die einzelnen Paradigmen unterscheiden sich aber darin, wie die Teilaufgaben zu erledigen sind. Bei der imperativen Programmierung legt der Programmierer selbst Hand an, indem er auf die entsprechenden Daten zugreift und diese verarbeitet. Bei der objektorientierten Programmierung nimmt er dagegen ein geeignetes Objekt und erteilt diesem den Auftrag, die Aufgabe zu lsen. Eine solche Aufgabe knnte beispielsweise darin bestehen, die Durchschnittstemperatur zu berechnen, die im Monat Mai an der AmundsenScott-Station am geografischen Sdpol herrscht7. Imperative Programmierung bedeutet, die im Monat Mai gemessenen Daten von irgendwoher (einzelnen Variablen, Datei etc.) einzulesen, aufzuaddieren und dann durch die Anzahl der Messwerte zu teilen. In einem objektorientierten Programm wren die Daten dagegen bereits in einem Objekt gekapselt, das vielleicht amundsenScottStation hiee, und der Programmierer msste dieses Objekt nur noch auffordern, ihm die Durchschnittstemperatur fr den Monat Mai zurckzuliefern. (In Java she diese Aufforderung so aus, dass eine entsprechende Methode des Objekts aufgerufen wrde, doch dies nur nebenbei.) Objekte kommen allerdings nicht aus dem Nichts. Sie mssen vom Programmierer erzeugt werden. Hier kommt das Konzept der Klasse ins Spiel. Eine Klasse ist eine allgemeine Beschreibung fr eine bestimmte Art (Klasse) von Objekten. In der Klasse ist festgelegt, wie die Objekte der Klasse aufgebaut sind und wie und wofr sie verwendet werden knnen. Ein

6 7

Teile und Gewinne, auch Salami-Taktik genannt etwa -56 Grad Celsius

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 59

Programm, das drei rollende Kugeln animiert, knnte beispielsweise eine Klasse Kugel definieren, in der die Merkmale (Farbe, Gre ...) und Verhaltensweisen (Anstoen, Rollen ...) angelegt sind, und von dieser Klasse drei Objekte mit unterschiedlichen Merkmalsausprgungen (groe rote Kugel, kleine blaue Kugel, kleine gelbe Kugel) erzeugen. Die Klassendefinitionen mssen natrlich erst einmal implementiert werden (es sei denn, es findet sich eine passende Klasse in einer zur Verfgung stehenden Klassenbibliothek oder auf der Festplatte eines Arbeitskollegen). Ein Groteil der Arbeit des objektorientierten Programmierers besteht daher darin, Klassen zu definieren. An diesem Punkt beit sich die Katze brigens in den Schwanz, denn beim Schreiben der Klassendefinitionen kommt wieder die imperative Programmierung zum Zuge. Rufen Sie sich noch einmal das Beispiel mit der Berechnung der Durchschnittstemperaturen in Erinnerung. Sicherlich waren Sie erfreut zu lesen, dass Sie bei der objektorientierten Programmierung die Berechnung des Mittelwerts dem Objekt amundsenScottStation berlassen knnen. Dies setzt aber natrlich voraus, dass eine passende Klassendefinition vorhanden ist, aus der Sie das Objekt amundsenScottStation erzeugen knnen. Falls nicht, mssen Sie die Klasse erst definieren und in der Klassendefinition dann auch die Methode implementieren, die die Durchschnittstemperatur berechnet. Wenn Sie zum Schluss aber doch imperativ programmieren, wozu dann berhaupt der ganze Aufwand mit der objektorientierten Verkleidung? Sicher, der Aufwand ist anfangs etwas grer wegen der Kapselung des Codes in den Klassendefinitionen. Wenn die Klassen aber erst einmal fertig sind, gestaltet sich die weitere Arbeit mit den Objekten der Klassen wesentlich einfacher. Und es ergeben sich noch weitere Vorteile: Die Arbeit mit Objekten (seien es Blle, Antarktisstationen, mathematische Gebilde wie Vektoren oder auch die Schaltflchen eines GUI-Programms) kommt der menschlichen Art zu denken sehr entgegen. Objektorientierter Code ist daher besser verstndlich (immer vorausgesetzt, der Leser ist mit der objektorientierten Syntax vertraut).

Durch die Kapselung von Code und Daten in Objekten wird das Programm modularer. Dies erleichtert: die Wiederverwendung das Debuggen

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 60

die Pflege des Codes

Schlielich knpft sich an das Klassenkonzept eine Reihe von Techniken und Design-Optionen, die helfen knnen, die Programmierung mit den Objekten der Klasse komfortabler und sicherer, d.h. fehlerfreier, zu gestalten: Instanzbildung mit Konstruktoren Zugriffsspezifizierer berladung von Methoden

Da Sie in Java von Anfang mit Klassen und Objekten zu tun haben, werden wir uns diese Konzepte im nachfolgenden Abschnitt noch kurz nher anschauen.

3.4.3 Objektorientierte Programmierung in Java


Java ist vollstndig objektorientiert

Java-Quelltexte bestehen (nahezu) ausschlielich aus Klassendefinitionen. Dies bedeutet, dass Variablen nur als Felder, Parameter oder lokale Variablen von Methoden auftreten und dass Anweisungen sieht man einmal von Feldinitialisierungen und statischem Klassencode ab nur in Methodendefinitionen zu finden sind. Globale Variablen, Anweisungen oder Funktionen, die auerhalb der Klassen stehen, gibt es in Java nicht! Diese radikale Konzentrierung auf objektorientierte Konzepte frdert Sicherheit, Robustheit, Modularitt und Wiederverwertbarkeit des erstellten Codes, ist aber auch der Grund dafr, dass ein leichter, allmhlicher Einstieg in die Sprache kaum mglich ist. Ohne Grundkenntnisse zur Definition von Klassen kann der Programmiereinsteiger keinen ausfhrbaren Java-Code schreiben, ohne eine gewisse Vertrautheit im Umgang mit Objekten, kann er die vielen Klassen und Methoden, die ihm die Java-Standardbibliothek zur Verfgung stellt und die er bereits fr so grundlegende Aufgaben wie das Einlesen oder Ausgeben von Daten ber die Tastatur bentigt, nicht nutzen. Den Abschluss dieses Ausflugs in die grundlegenden Konzepte und Begriffe der Programmierung bildet daher ein Crash-Kurs zur Programmierung mit Klassen und Objekten in Java. Klassendefinition Eine Klassendefinition fhrt einen neuen Datentyp ein. Sie setzt sich aus Feldern (Datenelementen) und Methoden zusammen.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 61

class Kreis { double radius; double x; double y; double umfang() { return 2 * 3.14159 * radius; } double flaeche() { return 3.14159 * radius * radius; } }

// Felder

// Methoden

Instanzbildung (Instanzierung) Die Deklaration einer Objektvariablen (Kreis k;) erzeugt noch kein Objekt der Klasse ebenso wenig wie die Deklaration einer int-Variablen einen int-Wert erzeugt. Es wird lediglich der Speicher reserviert, der bentigt wird, um einen Wert in der Variablen abzulegen. Die Werte von Klassen sind so haben Sie es gelernt die Objekte der Klasse. Wer jetzt aber schliet, dass in einer Variablen vom Typ einer Klasse auch Objekte dieser Klasse abgespeichert werden, sieht sich getuscht. Anders als beispielsweise in C++, dem berhmten Vorgnger und Paten von Java, werden Objekte nie im Speicher der zugehrigen Variablen verwahrt. Stattdessen wird das Objekt an beliebiger Stelle im Speicher angelegt und in der Variablen lediglich ein Verweis auf das Objekt (letztlich die Adresse des Speicherbereichs, in dem das Objekt residiert) verwahrt. Klassentypen werden in Java daher auch als Verweis- oder Referenztypen bezeichnet.
Icon REF

Welchen Sinn dieses etwas umstndliche Verfahren hat und welche Konsequenzen fr die Programmierung mit Objekten (und Objektvariablen) daraus resultieren, werden wir spter noch nher untersuchen. Hier interessiert uns lediglich die spezielle Syntax, die in Java zur Erzeugung und Speicherung von Objekten bentigt wird.
Kreis k; k = new Kreis();

Die erste Zeile deklariert eine Variable vom Typ Kreis.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 62

Die zweite Zeile erzeugt mithilfe des Schlsselworts new und des Ausdrucks Kreis() ein Objekt der Klasse Kreis und liefert eine Referenz auf das Objekt zurck. Diese Referenz wird durch die Zuweisung in der Variablen k abgelegt.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 63

Codespeicher

Datenspeicher

Objektvariablendeklaration Kreis k;

Objekt erzeugen k = new Kreis();

radius
0

x
0

y
0

3 Zugriff auf Instanzvariablen


k.radius = 1.5; k.x = 0; k.y = 5;

radius
1.5

x
0

y
5

Abbildung 3.4: Objektvariable und Objekt

Die Erzeugung eines Objekts einer Klasse wird auch als Instanzbildung oder Instanzierung bezeichnet.

Icon REF

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 64

Fr den Zugriff auf das Objekt ber die Variable ist keine spezielle Syntax erforderlich:
k.radius = 1.5; double umfang = k.umfang();

Konstruktoren Die Instanzbildung ist stets mit dem Aufruf eines Konstruktors verbunden. Der Konstruktor ist eine spezielle Methode der Klasse, die den gleichen Namen trgt wie die Klasse und ohne Rckgabetyp definiert wird. Er ist fr die Einrichtung des Speichers und die Initialisierung der Felder der erzeugten Objekte verantwortlich. Jede Klasse verfgt ber einen Konstruktor. Wenn der Programmierer keinen Konstruktor definiert, erzeugt der Compiler einen Konstruktor. Im vorangehenden Abschnitt wurde das Kreis-Objekt obj mithilfe des vom Compiler erzeugten Konstruktors Kreis() erzeugt.
Icon REF

class Kreis { double radius; double x; double y; Kreis() { // Konstruktor, der keinen } // besonderen Code ausfhrt double umfang() { return 2 * 3.14159 * radius; } double flaeche() { return 3.14159 * radius * radius; } }

berladung Java erlaubt die Definition mehrerer Methoden gleichen Namens, sofern die Methoden sich in Anzahl und/oder Typ der Parameter unterscheiden. Auf diese Weise knnen Sie beispielsweise fr eine Klasse mehrere Konstruktoren einrichten.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 65

class Kreis { double radius; double x; double y; Kreis() { // Konstruktor, der keinen } // besonderen Code ausfhrt Kreis(double r) { // Konstruktor, der den Radius radius = r; // mit dem Wert des bergebenen } // Arguments initialisiert double umfang() { return 2 * 3.14159 * radius; } double flaeche() { return 3.14159 * radius * radius; } }

Jetzt knnen Objekte von Kreis direkt bei der Instanzbildung mit sinnvollen Radien initialisiert werden:
Kreis k = new Kreis(5.2); 5.2 k.umfang(); // k.radius ist jetzt gleich // liefert 32.67256 zurck

Sicherheit Eingangs dieses Unterkapitels wurde behauptet, dass die Konzentrierung auf objektorientierte Konzepte die Programmierung sicherer und robuster macht. Fr die Klasse Kreis trifft dies jedoch ganz und gar nicht zu. So hat z.B. ein Kreis stets einen positiven Radius. Fr Objekte der Klasse Kreis knnen dem Feld radius aber ohne Probleme auch negative Werte zugewiesen werden sei es aus Versehen, Unwissenheit oder Bsartigkeit. Nachfolgende Aufrufe der Methoden umfang() und flaeche() liefern dann falsche Ergebnisse, die zu gravierenden und oft nur schwer zu entdeckenden Fehlern im Programm fhren knnen.
Kreis k1 = new Kreis(100); Kreis k2 = new Kreis(); ... k2.radius = x + 12; // falls x < -12 wird radius negativ! ... double schnittflaeche = k1.flaeche k2.flaeche; // noch korrekt??

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 66

Die objektorientierte Programmierung kennt jedoch Mittel, wie Klassen (bzw. Objekte von Klassen) vor derartigen falschen Feldwerten geschtzt werden knnen: die Zugriffsspezifizierer public, protected und private. Diese Schlsselwrter werden in der Klassendefinition den Klassenelementen vorangestellt und regeln, von wo aus auf die Elemente zugegriffen werden darf. Whrend zum Beispiel auf Klassenelemente, die in der Klasse als public deklariert sind, von berall zugegriffen werden kann, sind Klassenelemente ohne speziellen Zugriffsspezifizierer nur in der Quelltextdatei (genauer gesagt dem Paket) der Klassendefinition verfgbar. Und auf Elemente, die als private deklariert sind, knnen sogar nur die Methoden der eigenen Klasse zugreifen.
class Kreis { private double radius; private double x; private double y;

// werden in dieser Version nicht // weiter untersttzt

public Kreis() { } public Kreis(double r) { if (r >= 0) { radius = r; } } public double umfang() { return 2 * 3.14159 * radius; } public double flaeche() { return 3.14159 * radius * radius; } } ... // in gleicher Quelldatei Kreis k1 = new Kreis(); k.radius = 12; Element

// Fehler! Zugriff auf private-

Natrlich muss der Autor der Klasse, wenn er ein Element als private deklariert, auch dafr sorgen, dass das Element ber zugngliche (in der Regel public-) Methoden sinnvolle Werte zugewiesen bekommt und sein Wert gegebenenfalls auch abgefragt werden kann.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 67

In obiger Implementierung der Klasse Kreis kann der Nutzer der Klasse8 den Konstruktor Kreis(double r) verwenden, um seinen KreisObjekten von Anfang an sinnvolle Radien zuzuweisen. Tatschlich muss er sogar diesen Konstruktor verwenden, da er sonst keine Mglichkeit hat, den Radius eines Kreis-Objekts zu ndern. Die Implementierung des Konstruktors, sprich die if-Bedingung, stellt sicher, dass dem Radius keine negativen Werte zugewiesen werden knnen. (Bei bergabe eines negativen Werts an r wird die Zuweisung an radius nicht ausgefhrt. radius behlt den Standardwert 0, mit dem der Compiler alle Felder einer Klasse automatisch initialisiert.) Abfragen kann der Programmierer den Wert des Feldes radius berhaupt nicht, er kann sich lediglich von den public-Methoden umfang() und flaeche() die auf dem Radius basierenden Werte fr Kreisumfang und flche zurckliefern lassen. Wollte der Autor der Klasse das Abfragen oder nachtrgliche ndern des radius-Werts gestatten, msste er dazu entsprechende public-Methoden definieren.
class Kreis { ... double getRadius() { return radius; } void setRadius(double r) { if (r >= 0) { radius = r; } } ... }

Statische Elemente Die vornehmste Bestimmung einer Klasse ist, dass aus ihr Objekte erzeugt werden, dass ihre Felder als Instanzvariablen an die Objekte weitergegeben werden und dass ihre Methoden zur Programmierung mit den Objekten verwendet werden. Doch in einer rein objektorientierten Programmiersprache

Der Programmierer, der Objekte der Klasse erzeugt und verwendet. (Kann durchaus mit dem Autor der Klasse identisch sein.)

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 68

mssen Klassen auch anderen Zwecken dienen beispielsweise als Funktionensammlung. In Abschnitt Funktionen haben Sie die Funktionen als ein vorzgliches Mittel kennengelernt, um Teilprobleme modular zu lsen. Wenn Sie in Java Teilprobleme modular lsen mchten, mssen Sie dazu Methoden implementieren. Dies hat zwei Nachteile: Erstens mssen Sie, um diese Methoden aufrufen zu knnen, immer erst ein Objekt der Klasse erzeugen. Zweitens besteht die Mglichkeit, ja es ist sogar wahrscheinlich, dass die Felder und Methoden einer solchen Klasse gar keine sinnvollen Objekte bilden (zumindest keine Gebilde, die nach menschlicher Vorstellung als Objekte tituliert werden knnten). Ein gutes Beispiel hierfr ist die Java-Klasse Math, die dem Programmierer eine Reihe von wichtigen mathematischen Methoden und Konstanten zur Verfgung stellt. Damit der Programmierer die Methoden und Konstanten der Klasse verwenden kann, ohne erst ein (ansonsten sinn- und nutzloses) Objekt der Klasse erzeugen zu mssen, sind smtliche Elemente der Klasse als static deklariert.
// aus Math public static double tan(double a) { return StrictMath.tan(a); // default impl. delegates to StrictMath }

Das Schlsselwort static teilt dem Compiler mit, dass die so deklarierten Elemente nicht Teil der Objekte der Klasse sind, sondern allein im Besitz der Klasse bleiben und daher direkt ber den Namen der Klasse aufgerufen werden knnen.
// Berechnung einer Mauerhhe aus Winkel und Entfernung double winkel = 30; // in Grad double entfernung = 12.0; // in Meter double hoehe = entfernung * Math.tan(Math.toRadians(winkel));

In einer Klassendefinition knnen statische und nicht-statische Elemente kombiniert werden.

Icon REF

Die Eintrittsmethode main() Auch der Programmeintrittspunkt main(), der in C oder C++ als Funktion definiert ist, wurde in Java durch eine statische Methode ersetzt.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 69

public class Programm { public static void main(String[] args) { // Hier beginnt die Programmausfhrung } }

Vererbung Zu guter Letzt sei noch auf ein fortgeschrittenes, aber sehr wichtiges Konzept der objektorientierten Programmierung hingewiesen: die Vererbung. Die Vererbung gestattet es, neue Klassen auf der Basis bereits vorhandener Klassen zu definieren.
class Basis { int basisFeld; void eineMethode() { basisFeld = 12; } } class Abgeleitet extends Basis { int abgFeld; void andereMethode() { eineMethode(); abgFeld = basisFeld; } }

Die neue, abgeleitete Klasse erbt smtliche Elemente der nach dem Schlsselwort extends angegebenen Basisklasse und kann soweit es die in der Basisklasse vergebenen Zugriffsspezifizierer erlauben auf die geerbten Elemente zugreifen. Und auch der Nutzer der abgeleiteten Klasse kann wiederum sofern es die in der Basisklasse vergebenen Zugriffsspezifizierer erlauben ber die Objekte auf die geerbten Elemente zugreifen:
Abgeleitet a = new Abgeleitet(); a.eineMethode();

Die abgeleitete Klasse erbt immer alle Elemente der Basisklasse (mit Ausnahme der Konstruktoren); sie kann nicht selbst entscheiden, welche Elemente sie erben mchte und welche nicht. Immerhin aber kann die

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Einfhrung fr Programmieranfnger Seite 70

abgeleitete Klasse geerbte Methoden berschreiben, indem sie eine eigene Methode definiert, die den gleichen Namen wie eine geerbte Methode trgt:
class Abgeleitet extends Basis { int abgFeld; void eineMethode() { basisFeld = 112; } void andereMethode() { eineMethode(); abgFeld = basisFeld; }

// abgFeld = 112!

3.5

Noch Fragen?

Nach dieser doch recht umfangreich gewordenen Einfhrung sind Sie gewappnet, sich in den nachfolgenden Kapiteln dieses Buches ernsthaft in die Programmierung mit Java einzuarbeiten. Sollten Sie nicht alles verstanden haben oder angesichts der Flle an vorgestellten Konzepten, Begriffen und Syntaxformen zu verwirrt sein, um Ihren derzeitigen Wissenstand klar beurteilen zu knnen, so seien Sie versichert, dass Sie bestimmt weit mehr erfasst und verstanden haben, als Ihnen jetzt womglich bewusst ist. Lesen Sie einfach weiter, beginnen Sie selbst in Java zu programmieren, und Sie werden feststellen, dass Sie gute Fortschritte machen. Und sollten Sie doch einmal Verstndnisfragen haben, die sich auf grundlegende Konzepte beziehen und in den weiteren Kapiteln des Buches nicht geklrt werden, blttern Sie einfach hierher zurck (eine Wiederholung des Stoffes dieses Tutoriums zu einem spteren Zeitpunkt, wenn Sie mehr praktische Erfahrungen gesammelt haben, kann nur zu Ihrem Vorteil gereichen). Sie mchten noch mehr ber die Grundlagen der Programmiersprachen erfahren: Eine noch ausfhrlichere Einfhrung in die Grundprinzipien der Programmierung und die Geschichte der Programmiersprachen finden Sie auf unserer Website www.carpelibrum.de.
Icon REF

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Anwendungsgrundgerst und Standardbibliothek Seite 71

4 Anwendungsgrundgerst und Standardbibliothek


Es gibt eine Reihe von typischen Programmelementen, die man in so gut wie jedem Java-Programm wiederfindet: Kommentare dienen dazu, den Quelltext zu erlutern. import-Anweisungen Kein Programmierer kann es sich heutzutage leisten, den gesamten Code, der fr ein Programm bentigt wird, komplett selbst zu schreiben. Also greifen wir zur Erledigung bestimmter Aufgaben auf vorgefertigte Lsungen zurck: In Java bedeutet dies blicherweise, dass wir vordefinierte Klassen aus der JavaStandardbibliothek oder einer anderen von uns erworbenen Bibliothek verwenden. import-Anweisungen dienen dazu, den Zugriff auf Elemente aus Bibliotheken zu vereinfachen. Klassen Java-Code ist in Klassen organisiert. einem Eintrittspunkt Irgendwo muss das Programm ja beginnen. Java-Programme verfgen aus diesem Grund ber einen genormten Eintrittspunkt. Wie dieser Eintrittspunkt genau aussieht, hngt von der Virtual Machine ab, innerhalb der das Programm ausgefhrt wird. Hier werden wir uns zwei Eintrittspunkte ansehen: die Eintrittsfunktion main(), die von traditionellen Java-Programmen verwendet wird, sowie die Activity-Methode onCreate(), die von Apps als Eintrittspunkt verwendet wird (Android-Apps werden in einer speziellen Virtual Machine, der Dalvik Virtual Machine, ausgefhrt).

Bevor ich Ihnen diese Programmelemente im Einzelnen vorstelle, sollten wir jedoch einen Blick auf den vollstndigen Quelltext des Programms werfen. Wer schon einmal ein Lehrbuch fr eine andere Programmiersprache wie C oder C++ gelesen hat, wird unschwer erkennen, dass es sich um eine Adaption des klassischen "Hello World"-Programms von Kernighan und Ritchie handelt.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Anwendungsgrundgerst und Standardbibliothek Seite 72

// Hallo Welt-Programm import java.lang.*; public class HalloWelt { public static void main(String[] args) { System.out.println("Hallo Welt!"); } }

Packen Sie jetzt bitte Ihr Sezierbesteck aus und schrfen Sie Ihren Verstand. Wir beginnen mit der Analyse. Java unterscheidet streng zwischen Gro- und Kleinschreibung. Beachten Sie dies, wenn Sie die Quelltexte oder Codebeispiele aus diesem Kurs abtippen.
Icon MERKSATZ

4.1

Kommentare

Die erste Zeile des Beispielprogramms ist ein Kommentar.


// Hallo Welt-Programm import java.lang.*; public class HalloWelt { public static void main(String[] args) { System.out.println("Hallo Welt!"); } }

Kommentare sind Anmerkungen des Programmierers, die er als Gedchtnissttze und zur Erluterung des eigentlichen Quelltextes einfgt. Fr den Compiler sind sie berflssig und werden von ihm ignoriert. Wozu aber etwas aufschreiben, dass der Java-Compiler sowieso nicht braucht? Nun, Kommentare sind vor allem fr Sie gedacht! Oder vielleicht auch fr Kollegen oder Freunde, die irgendwann einmal Ihren Quellcode

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Anwendungsgrundgerst und Standardbibliothek Seite 73

lesen wollen. Vllig unkommentierter Quellcode ist meistens nur sehr schlecht oder mit hohem Zeitaufwand nachvollziehbar. Daher sollten Sie sich angewhnen, jedes Programm an sinnvollen Stellen mit kleinen Kommentaren zu ergnzen. Wenn Sie spter mal wieder in den Quelltext hineinschauen, sei es nun eine Woche oder gar ein Jahr spter werden Sie viel schneller wieder verstehen, was Sie damals programmiert hatten! Java kennt zwei Formen von Kommentaren. Krzere Kommentare, die in einer Zeile stehen, werden durch die Zeichenfolge // eingeleitet. Alle Zeichen, die zwischen // und dem Ende der Zeile stehen, werden vom Compiler als Kommentar angesehen.
// Hallo Welt-Programm import java.lang.*; public class HalloWelt // Hauptklasse { // main()-Methode public static void main(String[] args) { System.out.println("Hallo Welt!"); } }

Grere Kommentare, die sich ber mehrere Zeilen erstrecken, erzeugen Sie, indem Sie jede der betreffenden Zeilen mit // beginnen oder den Kommentar zwischen die Klammern /* und */ setzen.
/* Dies ist ein mehrere Zeilen umfassender Kommentar */

Sinnvolles Kommentieren So einfache Programme wie das obige Hallo Welt-Programm bedrfen im Grunde keiner Kommentierung. Kommentare sind nicht dazu gedacht, einem Programmieranfnger Java zu erklren. Kommentare sollen gestandenen Java-Programmierern helfen, sich in einen Quelltext einzudenken und diesen zu erklren. Kommentare sollten daher eher kurz und informativ sein. Kommentieren Sie beispielsweise die Verwendung wichtiger Variablen sowie die Aufgabe grerer Anweisungsabschnitte. Professionellen Programmierern bietet Java die Mglichkeit, Methoden und Klassen mittels spezieller Kommentare zu erlutern, aus denen dann
Icon HINWEIS

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Anwendungsgrundgerst und Standardbibliothek Seite 74

automatisch eine API-Dokumentation erstellt werden kann. (Siehe z.B. Erluterungen zum javadoc-Tool im Java-Kompendium.)

4.2

Pakete und Import-Anweisung

Springen wir nun zur zweiten Zeile.


// Hallo Welt-Programm import java.lang.*; public class HalloWelt { public static void main(String[] args) { System.out.println("Hallo Welt!"); } }

Hier haben wir eine sogenannte import-Anweisung vorliegen. Zur Erluterung dieser Zeile mssen wir etwas weiter ausholen.

4.2.1 Ordnung schaffen mit Paketen


Ein Java-Programm besteht letzten Endes aus einer Menge von Klassen. Wenn man nun ein neues Java-Programm schreibt, wird man a) eine gewisse Anzahl an Klassen neu entwerfen und b) eine mehr oder weniger groe Zahl von schon vorhandenen Klassen wiederverwenden. Fertige, vordefinierte Klassen, mit deren Hilfe man eine Vielzahl von typischen Programmieraufgaben lsen kann (Schreiben in die Konsole, Berechnung mathematischer Funktionen, Arbeiten mit Strings (Text), Datum- und Zeitangaben, Dateien etc.), finden Sie vor allem in der JavaStandardbibliothek, die Teil des JDK ist. Allerdings gibt es da noch ein kleines organisatorisches Problem: Die Bibliothek der zum JDK gehrenden Klassen ist sehr umfangreich. Da kann es durchaus passieren, dass in einem greren Programm Klassen definiert werden, die genauso heien wie Klassen aus der Java-Standardbibliothek. Dies wrde natrlich die bersetzung des Programms unmglich machen, denn wie soll der Java-Compiler entscheiden, welche Klasse nun gemeint ist?

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Anwendungsgrundgerst und Standardbibliothek Seite 75

Um solche Konflikte zu vermeiden, gibt es das Konzept der Pakete (in anderen Programmiersprachen auch als Namensrume oder Namespaces bezeichnet). Diese unterteilen die Standardbibliothek in benannte Unterbereiche, eben besagte Pakete. Wichtige Pakete der Standardbibliothek sind z.B.: java.lang: Hier finden sich ganz elementare Klassen, die von fast allen Programmen direkt oder indirekt bentigt werden. java.io: Hier gibt es viele ntzliche Klassen fr die Ein- und Ausgabe mit Dateien. java.util: Eine bunte Sammlung allgemein ntzlicher Klassen.
Icon HINWEIS

Paketnamen werden blicherweise klein geschrieben.

Einen vollstndigen berblick ber die Pakete der Java-Laufzeitbibliothek finden Sie in der JDK-API-Spezifikation: http://download.oracle.com/javase/6/docs/api/.

Icon HINWEIS

4.2.2 Klassen aus Paketen verwenden


Will man eine Klasse aus einem Paket verwenden, muss man ber ihren vollen die Programmierer sagen auch voll qualifizierten Namen auf die Klasse zugreifen. Zu dem vollen Namen gehrt aber auch das Paket, in dem die Klasse zu finden ist. Um also z.B. auf die Klasse System zugreifen zu knnen, mssten wir also schreiben:
java.lang.System

Das ist sicherlich nicht weiter tragisch, kann aber auf die Dauer recht lstig sein, speziell in Programmen, in denen hufiger auf die Klasse System zugegriffen wird. Hier bringt die import-Anweisung Erleichterung. Wenn man davon ausgehen kann, dass es keine Namenskonflikte zwischen dem eigenen Programm und den Elementen aus einem Paket gibt, kann man dem Compiler mithilfe der import-Anweisung mitteilen, dass man alle Klassen aus dem

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Anwendungsgrundgerst und Standardbibliothek Seite 76

angegebenen Paket direkt, d.h. ohne voll qualifizierten Namen, ansprechen mchte. Indem wir also die Zeile
import java.lang.System;

an den Anfang unseres Programms stellen, brauchen wir fortan in unserem Programmtext nur noch System zu schreiben, und der Compiler wei automatisch, dass eigentlich java.lang.System gemeint ist. Meistens braucht man aber mehrere Klassen aus einem Paket und importiert daher alle Klassen aus diesem Paket, indem man den Joker * stellvertretend fr alle Klassennamen angibt; so haben wir es im Beispiel gemacht:
import java.lang.*;

brigens: Die Klassen aus dem Paket java.lang sind von so grundlegender Natur, dass die Java-Designer beschlossen haben, dass Namen aus diesem Paket automatisch importiert werden. Die import-Anweisung import java.lang.*; ist daher im Grunde berflssig.
Icon HINWEIS

4.2.3 Eigene Pakete


Die Definition eigener Pakete ist vor allem fr Java-Entwickler wichtig, die Klassenbibliotheken entwerfen (verhindert Namenskonflikte zwischen den Bibliothekselementen und den Elementen, die die Anwendungsentwickler definiert haben, die die Bibliothek verwenden), oder Entwickler, die mit mehreren anderen Entwicklern oder Entwickler-Teams zusammen an einem greren Programm arbeiten (verhindert Namenskonflikte, wenn der Code der einzelnen Teams zum fertigen Programm zusammengefgt wird). Aber auch fr den Android-Programmierer ist es wichtig, die Klassen (und sonstigen Datentypen) seiner App in einem eigenen Paket zu definieren. Dies hngt natrlich damit zusammen, dass auf einem Smartphone Apps von vielen verschiedenen Anbietern zusammenkommen. Da kann es schnell passieren, dass zwei Apps zufllig Klassen gleichen Namens verwenden. (Bei Namen wie Spielbrett, Spiellogik, Figur oder Vektor kann man sich leicht vorstellen, dass Klassen dieses Namens in vielen verschiedenen Apps vorkommen.) Sind die Klassen aber in unterschiedlichen Paketen definiert, kann man sie unterscheiden.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Anwendungsgrundgerst und Standardbibliothek Seite 77

Das Prinzip ist in etwa das Gleiche wie bei Vor- und Zunamen. Es gibt viele Menschen, die Maier heien, aber nur wenige die Jutta Maier oder Jutta Angelika Maier heien. Um Apps problemlos auf einem Smartphone installieren zu knnen, sollten Sie daher die Klassen und sonstigen Typen Ihrer App in Paketen definieren. Firmen verwenden im Paketnamen meist den umgedrehten Domnennamen also z.B. com.UnsereFirma.AppA , da registrierte Domnennamen eindeutig sind (zumindest insofern als es keine zwei gleichlautende registrierte Domnennamen gibt). Wie aber legt man fest, dass eine im Code definierte Klasse Teil eines bestimmten Pakets ist? Die folgende Tabelle gibt Ihnen eine grobe bersicht darber, was zu tun ist und was Ihnen Eclipse und das Android-Plugin freundlicherweise abnehmen. (Das Fazit dieser Tabelle ist kurz gesagt, dass sich Eclipse um alles Ntige kmmert. Es schadet aber nicht, einen Blick auf die Tabelle zu werfen, um die Arbeit von Eclipse besser verstehen und honorieren zu knnen.)
Bereich Code Aufgabe Um zu erreichen, dass alle Klassen (und andere Datentypen), die in einer Quelltextdatei definiert sind, einem bestimmten Paket angehren, mssen Sie am Anfang der Datei eine packageAnweisung mit dem Paketnamen einfgen, z.B.: package de.IhreFirma; Eclipse Wenn Sie mit Eclipse fr ein AndroidProjekt eine neue Quelltextdatei anlegen (Befehl FILE/NEW/CLASS), wird die packageAnweisung automatisch eingefgt. Eclipse legt die Verzeichnisse an und verteilt auch die Dateien korrekt auf die Verzeichnisse.

Festplatte

Pakete mssen sich auf dem Computer in einer gleich aufgebauten Verzeichnisstruktur widerspiegeln. Fr jedes Paket mssen Sie ein eigenes Verzeichnis anlegen und in dieses die .class-Dateien der Java-Klassen des Pakets kopieren. Wenn Sie Pakete mithilfe des .-Operators hierarchisch gliedern (wie in de.ihrefirma.ihreabteilung), mssen auch die entsprechenden Verzeichnisse in gleicher Weise

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Anwendungsgrundgerst und Standardbibliothek Seite 78

hierarchisch gegliedert werden. Verzeichnis de mit ihrefirma mit ihreabteilung. Kompilierung und Ausfhrung Unterverzeichnis Unterverzeichnis Eclipse verwendet automatisch die richtigen BuildBefehle zum Erstellen.

Sie mssen dem Compiler anzeigen, dass er die erzeugten .class-Dateien auf die Paketverzeichnisse verteilen soll: javac -d . Wenn die Quelldateien ebenfalls auf Verzeichnisse entsprechend der Paketstruktur verteilt sind, wird der Aufruf noch komplizierter, z.B.: javac -d . ./de/firma/Klasse1.java Zum Ausfhren geben Sie den voll qualifizierten Namen der Klasse mit der main()-Methode an: java de.firma.Klasse1 Mglicherweise ist auch explizit Angabe des Klassenpfads ntig. die

Zugriff

Pakete dienen nicht nur der Gruppierung von Klassen, sie regeln auch den Zugriff auf Klassen. So kann eine Klasse, die einem Paket angehrt, ohne Probleme auf alle anderen Klassen des Pakets zugreifen. Dagegen ist der Zugriff auf eine Klasse eines anderen Pakets nur dann mglich, wenn die Klasse, auf die zugegriffen werden soll, als public deklariert wurde (Gleiches gilt fr Methoden und Felder von Klassen).

Eclipse definiert die Klassen, die Sie mit dem Befehl FILE/NEW/CLASS einem AndroidProjekt hinzufgen, per Voreinstellung als public.

4.3

Klassen

Als Programmieranfnger stellt man sich einen Programmquelltext meist als eine Abfolge von Anweisungen vor, die vom Computer nacheinander ausgefhrt werden. Diese Vorstellung ist an sich auch ganz richtig, doch

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Anwendungsgrundgerst und Standardbibliothek Seite 79

muss man beachten, dass diese Anweisungen nicht einfach irgendwo im Quellcode herumstehen drfen. So drfen in Java Anweisungen nur in Methodendefinitionen stehen, und Methoden knnen ihrerseits nur als Elemente von Klassen existieren. Daraus kann man zwei Schlussfolgerungen ziehen: 1. Ein Java-Programm besteht letzten Endes aus nichts anderem als aus einer oder mehreren Klassendefinitionen. 2. Wenn Sie ein Java-Programm schreiben, mssen Sie auch mindestens eine Klasse definieren.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Anwendungsgrundgerst und Standardbibliothek Seite 80

Sehen wir uns die Klasse unseres Hallo Welt-Programms an:


// Hallo Welt-Programm import java.lang.*; public class HalloWelt { public static void main(String[] args) { System.out.println("Hallo Welt!"); } }

Eingeleitet wird die Klassendefinition durch das Schlsselwort class. Vor dem Schlsselwort class kann noch das Schlsselwort public stehen, welches anzeigt, dass diese Klasse berall verwendet werden kann. (Im Gegensatz zu Klassen, die nur innerhalb ihres Pakets verwendet werden knnen.) In einer Java-Quelltextdatei knnen beliebig viele Klasse definiert werden, aber nur eine public-Klasse. Gibt es eine public-Klasse, muss die Datei den gleichen Namen tragen wie diese Klasse.
Icon ACHTUNG

Auf das Schlsselwort class folgt der Name der Klasse, den wir weitgehend frei whlen knnen (siehe Abschnitt 4.6, Namensgebung). Die ffnende geschweifte Klammer zeigt an, dass jetzt die Auflistung der Klassenelemente beginnt, die schlieende geschweifte Klammer zeigt das Ende der Klassendefinition an. Die wichtigsten Klassenelemente, die innerhalb einer Klasse definiert werden knnen, sind wie Sie aus dem Abschnitt 3.4.3 wissen Felder, Methoden und Konstruktoren. Fr unser Hallo Welt-Programm bentigen wir nur eine einzige Methode: main(). Diese Methode ist allerdings etwas Besonderes.

4.4

Eintrittspunkt

In den Frhzeiten der Programmierung als es noch Sprachen gab, deren Quelltexte aus einer einfachen Auflistung von Anweisungen an den Prozessor bestanden, lag die Antwort auf die Frage nach dem Eintritts- oder Startpunkt eines Programms auf der Hand: es war einfach die oberste

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Anwendungsgrundgerst und Standardbibliothek Seite 81

Anweisung im Quelltext. Doch mit der Organisation des Codes in Funktionen und spter Klassen musste ein neuer Eintrittspunkt gefunden werden. Da der Eintrittspunkt die Schnittstelle zwischen Programm und aufrufendem System bildet, muss er standardisiert sein, d.h. die Sprache gibt vor, wie der Eintrittspunkt aussieht, und der Programmierer muss dafr sorgen, dass sein Programm einen solchen Eintrittspunkt definiert ansonsten ist das Programm nicht ausfhrbar.
Sprache Altes Basic C und C++ Java Android Eintrittspunkt Oberste Anweisung in Quelltext Funktion main() Methode main()

onCreate()-Methode einer Activity-Klasse

Tabelle 4.1: Eintrittspunkte verschiedener Programmiersprachen

4.4.1 Der Java-Eintrittspunkt: main()


Jedes Java-Programm muss eine Klasse haben, die eine spezielle Methode namens
public static void main(String[] args)

bereitstellt. Die main()-Methode ist die erste Methode, die bei der Programmausfhrung (durch den Interpreter java.exe) aufgerufen und abgearbeitet wird.
Aufruf Was passiert Der Java-Compiler HalloWelt.class. sucht nach einer Datei

java HalloWelt

Kann er sie finden, liest er den darin enthaltenen Bytecode und durchsucht ihn nach einer Definition fr main(). Findet er eine korrekt definierte main()-Methode, beginnt er mit der Ausfhrung der in main() definierten Anweisungen.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Anwendungsgrundgerst und Standardbibliothek Seite 82

Abgesehen von der oben erwhnten Besonderheit ist die main()-Methode eine ganz normale Methode. In ihrem Rumpf knnen Sie Anweisungen platzieren, die beim Aufruf von main() ausgefhrt werden sollen. In unserem Beispiel wre dies die Zeile
System.out.println("Hallo Welt!");

Bei dieser Zeile handelt es sich um einen Aufruf der Methode println(). Mit der println()-Methode von System.out knnen Sie beliebige Strings (Textpassagen, hier Hallo Welt!) auf die Konsole ausgeben. Dazu mehr im Abschnitt Ein- und Ausgabe. Doch zurck zu unserer main()-Methode. Da sie die Schnittstelle zwischen unserem Programm und der ausfhrenden Laufzeitumgebung (der Java Virtual Machine) bildet, ist ihr Name strikt vorgegeben. Und nicht nur der Name. Der gesamte Kopfteil der Methode, die sogenannte Signatur, ist fest vorgegeben! Zur Verdeutlichung ist im folgenden Listing die Signatur noch einmal durch Fettdruck hervorgehoben.
// Hallo Welt-Programm import java.lang.*; public class HalloWelt { public static void main(String[] args) { System.out.println("Hallo Welt!"); } }

Was bedeuten die einzelnen Teile der Signatur? main() Der Name der Methode ist main(). ber diesen Namen wird sie von der Laufzeitumgebung aufgerufen. void main() Das Schlsselwort void vor dem Methodennamen zeigt an, dass die Methode keinen Ergebniswert (Rckgabewert) zurckgibt. void main(String[] args) Die Angabe in den runden Klammern ist eine Parameterdefinition. Parameter dienen dazu, der Methode beim Aufruf Werte hineinzureichen, die dann von der Methode bearbeitet werden knnen. Die main()-Methode bernimmt ein String-Array, ber das dem Programm Aufrufargumente bergeben werden knnen eine Technik, mit der wir uns in diesem Kurs nicht weiter beschftigen. Trotzdem drfen Sie die Parameterdefinition nicht weglassen, sonst stimmt die Signatur nicht

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Anwendungsgrundgerst und Standardbibliothek Seite 83

mehr und der java-Interpreter findet in Ihrem Programm keine main()Eintrittsmethode. static void main(String[] args) Wie Sie vielleicht noch aus dem Einfhrungskurs (Tutorium 3) wissen, gilt fr die meisten Klassen, dass man zuerst Objekte der Klassen erzeugt und dann ber diese Objekte die Methoden aufruft. Wenn Sie eine Methode schreiben mchten, die man direkt ber die Klasse aufrufen kann, mssen Sie die Methode als static definieren. Die main()-Methode muss statisch sein, da sie vom Interpreter direkt ausgefhrt wird (d.h. der Interpreter erzeugt keine Instanz der Klasse, in der main() definiert ist). public static void main(String[] args) Zu guter Letzt mssen Sie die Methode mit dem Zugriffsspezifizierer public definieren, damit auch der Interpreter das Recht hat, sie auszufhren.

4.4.2 Der Android-Eintrittspunkt: onCreate()


Obwohl wir in diesem Kurs das Hauptaugenmerk auf Java und die Erstellung traditioneller Java-Programme (wie sie z.B. auf einem Windows- oder LinuxRechner ausgefhrt werden) werfen wollen, ist es sicherlich ganz lehrreich, das traditionelle Java-Ausfhrungsmodell einmal dem AndroidAusfhrungsmodell gegenberzustellen. Whrend traditionelle Java-Programme in der Umgebung einer Java Virtual Machine ausgefhrt werden, gibt es fr Apps eine eigene Laufzeitumgebung: die Dalvik Virtual Machine. Die Dalvik Virtual Machine unterscheidet sich von der Java Virtual Machine nicht allein dadurch, dass sie zum Teil andere Bibliotheken zur Verfgung stellt und auch eine andere Form von Bytecode interpretiert9. Sie stellt auch andere Forderungen an den Eintrittspunkt: die App muss in ihrer Manifestdatei eine Startaktivitt angeben und Sie sollten die onCreate()-Methode dieser Aktivitt berschreiben, um festzulegen, was bei Start der App geschehen soll.

Der Java-Bytecode Ihrer App wird in einem zustzlichen Schritt in sogenannten DEX-Bytecode umgewandelt.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Anwendungsgrundgerst und Standardbibliothek Seite 84

package carpelibrum.hallo; import android.app.Activity; import android.os.Bundle; public class HalloSagen extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } }

4.5

Ein- und Ausgabe

Programme verarbeiten Daten. Manchmal stammen diese Daten aus dem Programmcode selbst (wie im Falle des Strings Hallo Welt! unseres Hallo Welt-Programms), meist aber werden die Daten von auerhalb des Programms eingelesen, verarbeitet und die Ergebnisdaten ausgegeben. So wre ein Programm, das bei jedem Start die Zahlen 3 und 4 multipliziert und das Ergebnis ausgibt, auf die Dauer doch recht langweilig und wenig ntzlich. Ein Programm, mit dessen Hilfe man jedoch zwei beliebige Zahlen multiplizieren kann, wre dagegen wesentlich pfiffiger und knnte vielleicht sogar zu einem Taschenrechner ausgebaut werden. Wie aber knnen Programme Daten von auerhalb einlesen und wie knnen sie Ergebnisdaten ausgeben. Nun, Sie wren erstaunt, wie viele Mglichkeiten es fr die Ein- und Ausgabe gibt:
Technik Grafische Benutzeroberflche Schaltflchen, Eingabefeldern etc. Internet mit Mgliche Eingabe Eingabe Eingabefelder, Listenfelder, Optionsfelder etc. ber Mgliche Ausgabe Ausgabe ber Textfelder

Daten aus Webseiten auslesen oder von Webservices abfragen Daten aus Datei einlesen Daten aus Datenbank

als ad hoc Webseite

erzeugte

Datei Datenbank

Daten in Datei schreiben Daten in Datenbank

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Anwendungsgrundgerst und Standardbibliothek Seite 85

abfragen Konsole Einlesen von Konsole

bearbeiten Schreiben auf Konsole

Tabelle 4.2: Beispiele fr mgliche Ein- und Ausgabetechniken Die in der Tabelle zuletzt aufgefhrte Option ist vor allem fr Konsolenanwendungen interessant. Und da wir im Zuge dieses Kurses als bungen ausschlielich Konsolenanwendungen erstellen, sollten wir uns die wichtigsten Techniken zur Ein- und Ausgabe auf Konsole kurz ansehen.

4.5.1 Text (Strings) ausgeben


Text bzw. Zeichenfolgen werden in der Programmierung als Strings bezeichnet. Es gibt in Java verschiedene Wege, Strings in unterschiedlicher Perfektion auszugeben. Ein recht einfacher Weg fhrt ber die Methode System.out.println().
class Demo { public static void main(String[] args) { // Ausgabe eines String-Literals System.out.println("Dies ist ein String-Literal."); // Ausgabe eines Strings, der in einer String-Variablen // gespeichert ist String komponist = "Edvard Grieg"; System.out.println("Norwegischer Komponist : " + komponist); } }

Beachten Sie den +-Operator im obigen Code. Mit seiner Hilfe kann man nicht nur Zahlen addieren, sondern auch Strings aneinanderhngen. System.out.println() beendet die Ausgabe automatisch mit einem Zeilenumbruch. Wenn Sie dagegen mchten, dass die Eingabeposition hinter der Ausgabe verbleibt, verwenden Sie stattdessen die Schwestermethode System.out.print().
Icon HINWEIS

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Anwendungsgrundgerst und Standardbibliothek Seite 86

Mit System.out.println() ausgegebene Umlaute werden auf der Konsole nicht korrekt angezeigt. Als Lsung besteht die Mglichkeit, die Umlaute zu umschreiben (ae statt ) oder zur Ausgabe System.console().printf() zu verwenden.

Icon HINWEIS

Eigentlich heit die Methode nur println(). (Zur Erinnerung: Java- Icon AUFSTEIGER Bezeichner drfen keine Satzzeichen, also auch keine Punkte enthalten. Ein Punkt bedeutet vielmehr, dass auf ein Element einer Klasse oder eines Objekts zugegriffen wird.) Sie ist in der Java-Klasse PrintStream definiert und dient dazu, in das PrintStream-Objekt zu schreiben, ber das sie aufgerufen wird. Allerdings nutzt es uns nichts, in irgendein beliebiges PrintStream-Objekt zu schreiben. Wir bentigen ein spezielles PrintStream-Objekt, das mit dem Konsolenfenster verbunden ist. Dieses Objekt ist ebenfalls bereits vordefiniert (d.h., es wird beim Programmstart erzeugt und in dem statischen Feld out der Java-Klasse System gespeichert.) Wir greifen also mit System.out auf das PrintStreamObjekt zu und hngen dann mit dem Punkt direkt den Aufruf von println() an.

4.5.2 Zahlen und andere Daten ausgeben


Zahlen knnen ebenfalls mit System.out.println() ausgegeben werden.
class Demo { public static void main(String[] args) { int alter = 25; double groesse = 1.80; System.out.println("Alter : " + alter); System.out.println("Groesse : " + groesse); } }

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Anwendungsgrundgerst und Standardbibliothek Seite 87

Ja, Sie knnen mithilfe von System.out.println() sogar beliebige Objekte ausgeben.
// Die Klassendefinition class Bekannter { private String name; public Bekannter(String s) { name = s; } } class Demo { public static void main(String[] args) { // Ein Objekt der Klasse Bekannter wird erzeugt Bekannter jim = new Bekannter("Jim Schmidt"); // Das Objekt wird ausgegeben System.out.println("Hallo " + jim); } }

Das Ergebnis ist allerdings manchmal ziemlich enttuschend.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Anwendungsgrundgerst und Standardbibliothek Seite 88

Natrlich hatten wir gehofft, dass der Name in der Ausgabe erscheinen wrde. Doch stattdessen wird der Klassentyp des Objekts ausgegeben (Bekannter), gefolgt von einem kryptischen Code, bei dem es sich brigens um einen sogenannten Hashcode des Objekts handelt. Wie kann die Ausgabe von Objekten auf die Konsole berhaupt funktionieren? Ist die Methode println() so genial implementiert, dass sie es tatschlich schafft, beliebige Objekte in Strings umzuwandeln? Oder steckt dahinter irgendeine geheimnisvolle Magie des Compilers? Keins von beidem. Der Trick ist sogar hchst simpel und fhrt doch tief in die Interna von Java ein. Am Ende des Tutoriums 3 haben wir kurz die Technik der Vererbung angesprochen. Was wir Ihnen nicht verraten haben, ist, dass in Java alle Klassen automatisch von einer obersten Basisklasse namens Object abgeleitet werden. Von dieser Klasse erben Sie einige grundlegende Methoden, die somit fr alle Objekte aufgerufen werden knnen. Eine dieser Methoden lautet toString(). Ihre Aufgabe ist es, eine Stringdarstellung fr das aktuelle Objekt zurckzuliefern. Der Trick der System.out.println()-Methode besteht nun darin, dass sie gar nicht versucht, ein ihr bergebenes Objekt in eine Stringdarstellung umzuwandeln. Nein, sie ruft einfach fr das bergebene Objekt die Methode toString() auf. Das ist, als wrde sie das bergebene Objekt ansprechen und auffordern: He, sag du mir, was ich als Text fr dich ausgeben soll. Sie knnen die Methode toString() natrlich auch selbst fr ein Objekt aufrufen, beispielsweise um gleich einen String an System.out.println() zu bergeben:
System.out.println("Hallo : " + jim.toString());
Icon HINWEIS

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Anwendungsgrundgerst und Standardbibliothek Seite 89

Jetzt gibt es allerdings noch ein Problem. Die Klasse Object, in der die vererbte Methode toString() implementiert ist, kann natrlich eine ganz allgemeine Ausgabe erzeugen: eben den Klassennamen und einen objektspezifischen Hashcode. Sollen fr die Objekte einer Klasse sinnvollere Stringdarstellungen zurckgeliefert werden, muss die Klasse die geerbte toString()-Methode berschreiben. Das heit, sie verbindet den Namen der Methode mit neuem Code (der aber natrlich nur dann ausgefhrt wird, wenn die Methode ber ein Objekt dieser Klasse aufgerufen wird). Der folgende Code zeigt, wie die berschreibung der Methode toString() fr unsere Bekannter-Klasse aussehen knnte.
class Bekannter { private String name; public Bekannter(String s) { name = s; } public String toString() { // liefere als Stringdarstellung einfach den Wert // im Feld name zurck return name; } } class Demo { public static void main(String[] args) { Bekannter jim = new Bekannter("Jim Schmidt"); System.out.println("Hallo " + jim.toString()); } }

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Anwendungsgrundgerst und Standardbibliothek Seite 90

4.5.3 Text einlesen


Als Pendant zu dem Objekt System.out, ber das wir Ausgaben in das Konsolenfenster schreiben knnen, gibt es auch noch ein Objekt System.in, ber das wir Eingaben von der Konsole entgegennehmen knnen. Doch es gibt da ein Problem. Mit System.in knnen wir nur rohe Bytes einlesen. Aus diesem Grund schalten wir ein Objekt der Klasse Scanner dazwischen, welches die rohen Bytes der Eingabe fr uns in Strings umwandelt.
import java.util.Scanner; class Demo { public static void main(String[] args) { String name = ""; System.out.print(" Geben Sie Ihren Namen ein: "); Scanner sc = new Scanner(System.in); name = sc.nextLine(); System.out.println(); System.out.println(" Hallo " + name + "!");

} }

Die Klasse Scanner ist im Paket java.util definiert. Um nicht jedes Mal den voll qualifizierten Namen angeben zu mssen, importieren wir den Namen zu Beginn des Programms:
import java.util.Scanner;

In main() teilen wir dem Anwender zunchst mit, welche Daten er eingeben soll. Dann beginnen wir mit dem Einlesen.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Anwendungsgrundgerst und Standardbibliothek Seite 91

Wir erzeugen ein Objekt der Klasse Scanner, das mit der Konsoleneingabe (System.in-Objekt) verbunden ist. Dann rufen wir die Methode nextLine() auf. Das Programm wird daraufhin angehalten. Solange, bis der Anwender auf der Konsole eine Eingabe macht und mit der (Enter)-Taste abschickt. Die Eingabezeile wird von der Methode entgegengenommen, in ein String-Objekt verpackt und als Ergebnis zurckgeliefert. Wir mssen es nur noch in einer passenden Variablen (hier name) speichern.

4.5.4 Zahlen einlesen


Zahlen knnen ebenfalls mithilfe eines Scanner-Objekts eingelesen werden. Zum Einlesen rufen wir dann aber nicht die Methode nextLine(), sondern nextInt() oder nextDouble() auf und das Ziel der Einleseoperation sollte entsprechend eine Variable des zugehrigen Zahlentyps sein, also int oder double.
import java.util.Scanner; class Demo { public static void main(String[] args) { int ganzeZahl; double gleitkommaZahl; System.out.print(" Geben Sie eine ganze Zahl ein : "); Scanner sc = new Scanner(System.in); ganzeZahl = sc.nextInt(); System.out.print(" Geben Sie eine Dezimalzahl ein: "); gleitkommaZahl = sc.nextDouble();

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Anwendungsgrundgerst und Standardbibliothek Seite 92

System.out.println(); System.out.println(" Ganze Zahl : " + ganzeZahl); System.out.println(" Dezimalzahl: " + gleitkommaZahl); } }

Beachten Sie, dass Sie im Code in double-Literalen zur Abtrennung der Nachkommastellen einen Punkt (3.5), bei der Eingabe ber die Konsole aber das deutsche Komma (3,5) verwenden. (Scanner bercksichtigt automatisch, welche nationalen Eigenheiten auf dem aktuellen Rechner eingestellt sind whrend sich System.out.println()an die englische Schreibweise hlt.)

Icon ACHTUNG

4.6

Namensgebung

Sieht man einmal von der main()-Methode ab, knnen Sie die Namen von Programmelementen, die Sie selbst definieren (Klassen, Methoden, Eigenschaften, Variablen etc.), frei whlen. Sie mssen lediglich folgende Regeln zur Namensgebung beachten: Der Name muss mit einem Buchstaben oder einem Unterstrich "_" anfangen. Innerhalb des Namens sind auch Zahlen erlaubt. Der Name darf keine Leer- oder Sonderzeichen. Der Name darf kein Schlsselwort von Java sein.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Anwendungsgrundgerst und Standardbibliothek Seite 93

Der Name muss in seinem Gltigkeitsbereich eindeutig sein. Sie drfen also nicht in einem Paket zwei Klassen mit gleichem Namen oder in einer Klasse zwei Methoden gleichen Namens definieren.

Ansonsten sollte der Name nicht zu lang, aber dennoch aussagekrftig sein, damit man am Namen die Verwendung des Elements ablesen kann. Fr Hilfsvariablen, die keine besonderen Daten speichern, gibt es aber oft keine sinnvollen Namen. Solche Variablen heien dann meist n, m, x, y oder tmp. Statt von Namen spricht man in der Programmierung hufig auch von Bezeichnern.
Icon HINWEIS

Java unterscheidet streng zwischen Gro- und Kleinschreibung. Die beiden Bezeichner meinObjekt und MeinObjekt sind also nicht identisch.

Icon ACHTUNG

4.7

Stil

Zum Abschluss noch ein Wort ber guten und schlechten Stil. Java besitzt eine ziemlich kryptische Syntax, die daraus resultiert, dass es viele bedeutungstragende Syntaxelemente gibt, die durch einzelne Zeichen dargestellt werden ({, (, ++, %, . etc.), und dass sich die einzelnen Syntaxelemente zu den merkwrdigsten Konstrukten verbinden lassen. Zwar kann man den sich daraus ergebenden Quelltexten eine gewisse asketische Eleganz kaum absprechen, doch trgt dies weder zur Lesbarkeit noch zur Wartbarkeit der Programme bei was umso schwerer wiegt, als ein Tippfehler in nur einem Zeichen in Java schnell zu einem katastrophalen Fehler fhren kann. Tun Sie also Ihr Bestes, um den Quelltext bersichtlich und gut lesbar zu gestalten: Schreiben Sie mglichst nur eine Anweisung in eine Zeile. Rcken Sie Anweisungsblcke ein. Verwenden Sie Leerzeichen und Leerzeilen zur optischen Auflockerung. Kommentieren Sie Ihren Code.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Anwendungsgrundgerst und Standardbibliothek Seite 94

Achten Sie also darauf, dass Ihre Quelltexte nicht wie folgt aussehen:
import java.lang.*; public class HalloWelt {public static void main(String[] args){System.out.println("Hallo Welt!");}}

sondern so:
// Hallo Welt-Programm import java.lang.*; public class HalloWelt { public static void main(String[] args) { System.out.println("Hallo Welt!"); } }

oder im Android-Stil:
// Hallo Welt-Programm import java.lang.*; public class HalloWelt { public static void main(String[] args) { System.out.println("Hallo Welt!"); } }

4.8

bung 2: Daten einlesen und ausgeben

Aufgabenstellung Schreiben Sie ein Programm Personendaten, das Name und Alter des Anwenders abfragt und beides anschlieend wieder ausgibt. Versuchen Sie, die Aufgabe zuerst selbststndig zu lsen. Wenn Sie nicht weiter wissen und Hilfe bentigen, lesen Sie die Lsung. Lesen Sie den Lsungsabschnitt aber auch dann durch, wenn Sie die bung selbststndig bearbeiten knnen. Wir haben auf dem beschriebenen Lsungsweg absichtlich ein paar lehrreiche Fehltritte eingebaut.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Anwendungsgrundgerst und Standardbibliothek Seite 95

Lsung 1. 2. 3. Legen Sie eine neue Quelltextdatei Personendaten.java an. Tippen Sie das Java-Anwendungsgerst ein. Speichern Sie.

Abbildung 4.1: Die Datei Personendaten.java mit dem Anwendungsgerst (hier in Notepad++, Download von http://sourceforge.net/projects/notepad-plus) 4. Kompilieren Sie die Datei und fhren Sie das Programm aus, um sich zu versichern, dass es keine Fehler enthlt.

So weit, so gut! Als Nchstes fgen wir den Code zum Einlesen des Namens hinzu. Gehen Sie immer in kleinen Schritten vor.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Anwendungsgrundgerst und Standardbibliothek Seite 96

5.

Wir ersetzen die Zeile mit dem System.out.println()-Aufruf durch Code, der den Anwender zur Eingabe seines Namens auffordert, diesen dann mithilfe eines Scanner-Objekts einliest und zur Kontrolle wieder ausgibt.

public class Personendaten { public static void main(String[] args) { String name; System.out.print(" Geben Sie Ihren Namen ein: "); Scanner sc = new Scanner(); name = sc.nextLine(); System.out.println(); System.out.println(name); } }

6.

Speichern Sie und kompilieren Sie die Datei.

Hoppla, der Compiler hat Fehler in unserem Code gefunden. Beide Fehler treten in Zeile 8 auf und haben damit zu tun, dass der Compiler mit dem Bezeichner Scanner nichts anfangen kann. Nanu, kennt der Compiler pltzlich die Klasse Scanner aus der Standardbibliothek nicht mehr?

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Anwendungsgrundgerst und Standardbibliothek Seite 97

Fehler der Form cannot find symbol entstehen meist durch Tippfehler in den Bezeichnern, durch fehlende Paketangaben oder durch Methodenaufrufe mit falschen Parametern. Ein prfender Blick in unseren Code ergibt, dass wir weder den voll qualifizierten Namen verwendet noch eine passende import-Anweisung vorangestellt haben. 7. Fgen Sie eine import-Anweisung fr Scanner ein.

import java.util.Scanner; public class Personendaten { public static void main(String[] args) { String name; System.out.print(" Geben Sie Ihren Namen ein: "); Scanner sc = new Scanner(); name = sc.nextLine(); System.out.println(); System.out.println(name); } }

8.

Speichern Sie und kompilieren Sie die Datei.

Sapperlot! Schon wieder der cannot find symbol-Fehler!

Aber diesmal ist es nur eine Fehlermeldung. Und sie besagt, dass der Compiler speziell mit dem Konstruktoraufruf Scanner() Probleme hat.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Anwendungsgrundgerst und Standardbibliothek Seite 98

Ah, richtig! Wir haben vergessen, dem Konstruktor das System.in-Objekt als Argument zu bergeben. Der Compiler kann natrlich nicht jeden falschen Methoden- oder Konstruktoraufruf entdecken. Wenn Sie aber zu wenige oder zu viele Argumente bergeben oder der Datentyp eines Arguments nicht zum Datentyp des Parameters passt, wird der Compiler dies anmahnen.
Icon HINWEIS

9.

Korrigieren Sie den Konstruktoraufruf.

import java.util.Scanner; public class Personendaten { public static void main(String[] args) { String name; System.out.print(" Geben Sie Ihren Namen ein: "); Scanner sc = new Scanner(System.in); name = sc.nextLine(); System.out.println(); System.out.println(name); } }

10. Speichern Sie und kompilieren Sie die Datei. Jetzt sollte alles glatt gehen. 11. Kopieren Sie den Code zum Einlesen des Namens und passen Sie ihn so an, dass damit das Alter des Anwenders abgefragt wird. 12. Geben Sie Name und Alter des Anwenders aus.
import java.util.Scanner; public class Personendaten { public static void main(String[] args) { String name; int alter;

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Anwendungsgrundgerst und Standardbibliothek Seite 99

System.out.print(" Geben Sie Ihren Namen ein: "); Scanner sc = new Scanner(System.in); name = sc.nextLine(); System.out.print(" Geben Sie Ihr Alter ein : "); alter = sc.nextInt(); System.out.println(); System.out.println(" " + name + " ist " + alter + " Jahre alt."); } }

13. Speichern Sie und kompilieren Sie die Datei. 14. Fhren Sie das Programm aus.

Abbildung 4.2: Prima!

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Variablen und Konstanten Seite 100

5 Praxisteil: Variablen und Konstanten


Dieses Tutorium ist den Daten gewidmet. Daten knnen in einem Programm in zwei Formen vorkommen: als Konstanten oder als Variablen
Icon HINWEIS

Dieses Tutorium ist ziemlich theorielastig. Lesen Sie es sich gemtlich durch, versuchen Sie, mglichst viel zu verstehen, aber versuchen Sie nicht, sich gleich alles einzuprgen. Dafr enthlt dieses Tutorium zuviel Stoff. Hinzukommt, dass ein nicht unerheblicher Teil des hier behandelten Stoffes fortgeschrittene Themen und Hintergrundinformationen berhrt, die Sie anfangs gar nicht bentigen. Lesen Sie sich daher alles gut durch, um einen berblick zu gewinnen und die wichtigsten Begriffe und Konzepte schon einmal gesehen zu haben, und schlagen Sie spter dann bei Bedarf die entsprechenden Stellen noch einmal nach.

5.1

Konstanten

Konstanten wiederum knnen ebenfalls in zwei Varianten vorliegen: als Literal oder als symbolische Konstante.

5.1.1 Literale
Literale sind Werte elementarer Datentypen, Strings oder Nullwerte, die direkt im Quelltext stehen. Sie werden beispielsweise zur Initialisierung von Variablen, als Vergleichwerte in Bedingungen oder als Konstanten in Formeln verwendet:
int eineVar = 122; if (eineVar < 10) { eineVar = 10 * eineVar; ...

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Variablen und Konstanten Seite 101

Welchem Datentyp ein Literal angehrt, erkennt der Compiler aus dem Format des Literals.
Datentyp Literale true, false

boolean Nur zwei Werte: char Einzelne in Hochkommata gestellte Zeichen:


'c', ''

Escape-Sequenzen (siehe Abschnitt 5.3.1):


'\n' // Escapezeichen fr einen Zeilenumbruch

Angabe des Unicodes des Zeichens:


'\u0011'

int

Positive und negative ganze Zahlen:


12, -128

Hexadezimalzahlen beginnen mit 0x:


0x12, 0xEEFF

long double

Wie int-Zahlen, aber mit angehngtem l oder L:


12l, -077L, 0xEEFFL

Zahl mit Dezimalpunkt:


47.11, 0.0, .01

Zahl in Exponentialschreibweise:
10e-2d, 3e4, 0.3e0.4

float Strings Null-Typ

Wie int-Zahlen, aber mit angehngtem f oder F:


47.11f, 0.0F, 0.1f, 10e-2F

Zeichenfolge, die in Anfhrungszeichen steht:


"Dies ist ein String"

Nur ein Wert: null

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Variablen und Konstanten Seite 102

Tabelle 5.1: Literale Der Buchstabe e wird in Gleitkommaliteralen zur Kennzeichnung eines nachfolgenden Exponenten zur Basis 10 verwendet. 3.14e3 bedeutet also 3.14 * 103 und nicht etwa 3.14 * e3 (mit e gleich der Eulerschen Zahl).
Icon ACHTUNG

5.1.2 Konstanten
Symbolische Konstanten sind Konstanten, die mit einem Namen verbunden wurden, der im weiteren Quelltext als Alias fr die Konstante verwendet werden kann. Symbolische Konstanten werden mit dem Schlsselwort final definiert.
final double PI = 3.14159265358979323846; ... umfang = 2 * PI * radius;

Symbolische Konstanten eignen sich vor allem fr Gren mit einer festen Bedeutung (wie z.B. PI oder der Maximalzahl der erlaubten Spieler in einem PC-Spiel). Da der Wert nur einmal im Quelltext auftaucht und danach stets der Konstantenname verwendet wird (der auf die Bedeutung der Konstante hinweisen sollte), wird der Quelltext besser verstndlich und, wenn bei einer spteren berarbeitung des Programms der Wert der Konstante gendert werden soll, muss dazu nur eine Stelle im Quellcode, nmlich die Konstantendefinition, aufgesucht werden.

5.2

Variablen

Konstanten sind eine wunderbare Sache, aber um richtig programmieren zu knnen, reichen Konstanten nicht aus. Wir brauchen zustzlich auch noch eine Mglichkeit, wie man Daten zwischenspeichern kann und zwar so, dass wir jederzeit auf die Daten zugreifen und sie bei Bedarf auch verndern knnen. Diese Mglichkeiten erffnen uns die Variablen.

5.2.1 Variablendefinition
Variablen bezeichnen Speicherbereiche im RAM (Arbeitsspeicher), in denen ein Programm Werte ablegen kann. Um also mit Daten arbeiten zu knnen, mssen Sie zuerst eine Variable fr diese Daten definieren, beispielsweise

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Variablen und Konstanten Seite 103

int meineVar;

Der Compiler sorgt dann dafr, dass bei Ausfhrung des Programms Arbeitsspeicher fr die Variable reserviert wird. Fr den Compiler ist der Variablenname einfach ein Verweis auf den Anfang eines Speicherbereichs. Als Programmierer identifiziert man eine Variable mehr mit dem Wert, der gerade in dem zugehrigen Speicherbereich abgelegt ist. Bei der Definition geben Sie nicht nur den Namen der Variablen (im obigen Beispiel meineVar), sondern auch deren Datentyp an (im Beispiel int). Dieser Datentyp teilt dem Compiler mit, wie der Inhalt des Speicherbereichs der Variablen zu interpretieren ist. Dies ist ntig, weil alle Daten im Arbeitsspeicher binr kodiert sind, also als eine Folge von Nullen und Einsen gespeichert werden. Dabei gibt es fr die verschiedenen Arten von Daten (Text, Ganzzahlen, Gleitkommazahlen) unterschiedliche Kodierungsverfahren, die festlegen, wie die Werte der unterschiedlichen Datentypen binr kodiert werden beziehungsweise wie die binr kodierten Werte wieder zurckverwandelt werden. Sie als Programmierer brauchen nicht zu wissen, wie diese Kodierungen im Detail aussehen (die Kodierung wird ganz vom Compiler bernommen), aber Sie sollten sich stets bewusst sein, dass eine solche Kodierung stattfindet, denn darauf beruht das gesamte System der Datentypen. Fr die elementaren Datentypen gibt es in Java spezielle Schlsselwrter, beispielsweise:
Datentypen Art der Werte Wahrheitswerte true (wahr) und false (nicht wahr) Ganzzahlen Gleitkommazahlen einzelne Zeichen

boolean int double char

Tabelle 5.2: Einige wichtige elementare Java-Datentypen Mithilfe dieser Schlsselwrter sind wir jetzt in der Lage, Variablen fr eine Vielzahl von Aufgaben zu definieren. Um beispielsweise den Computer eine kleine Addition ausfhren zu lassen, knnten wir drei int-Variablen definieren: zwei int-Variablen fr die zu addierenden Zahlen, eine intVariable zum Abspeichern des Ergebnisses:

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Variablen und Konstanten Seite 104

class Demo { public static void main(String[] args) { int ersteZahl; int zweiteZahl; int ergebnis; // ... } }

Wenn Sie wie im obigen Beispiel mehrere Variablen eines Datentyps definieren, brauchen Sie nicht fr jede Variable eine eigene Definition aufzusetzen. Sie knnen die Variablennamen auch durch Kommata getrennt hinter dem Datentyp auflisten:
int ersteZahl, zweite Zahl, ergebnis;

Welche Version man whlt, hngt meist davon ab, wie wichtig die betreffenden Variablen sind. Wichtige Variablen definiert man meist allein in einer Zeile (und schreibt hinter die Variablendefinition vielleicht noch einen kleinen Kommentar), weniger wichtige oder bedeutungsmig eng zusammengehrende Variablen wird man eher in einer Zeile definieren. Wichtiger ist die Frage, wo man die Variablen definiert. Grundstzlich kann man Variablen in Methoden (als lokale Variablen), als Methodenparameter und in Klassen (als Felder) definieren. Wir werden uns erst einmal auf die lokalen Variablen konzentrieren, die in Methoden definiert werden. Da man eine Variable erst nach ihrer Definition verwenden kann, werden die Variablen meist am Anfang der Methoden vor den Anweisungen definiert. Variablen, die man erst weiter unten bentigt, kann man aber auch erst spter, mitten zwischen den Anweisungen der Methode, definieren. Es muss lediglich sichergestellt sein, dass die Variable nicht vor ihrer Definition in einer Anweisung benutzt wird. Definitive Assignment Definitive Assignment bedeutet, dass einer Variablen zuerst ein definierter Wert zugewiesen werden muss, bevor der Wert der Variablen abgefragt werden kann.

Bezglich der Benennung von Variablen gelten die Regeln aus dem Abschnitt 4.6, Namensgebung.

Icon HINWEIS

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Variablen und Konstanten Seite 105

5.2.2 Werte in Variablen speichern


Nun war schon so oft die Rede davon, dass man in Variablen Werte speichern kann, dass es Zeit wird, sich dies in der Praxis anzuschauen:
class Demo { public static void main(String[] args) { int ersteZahl; int zweiteZahl; int ergebnis; ersteZahl = 8000; zweiteZahl = 312; } }

Hier wird in der Variablen ersteZahl der Wert 8000 und in der Variablen zweiteZahl der Wert 312 abgelegt. Das Gleichheitszeichen, das dabei zur Zuweisung des Wertes an die Variable verwendet wird, ist der sogenannte Zuweisungsoperator. Eine Variable kann immer nur einen Wert enthalten. Wenn Sie einer Variablen einen Wert zuweisen, bedeutet dies daher, dass der alte Wert verloren geht er wird einfach berschrieben.
Icon ACHTUNG

Wenn Sie einer Variablen einen Wert zuweisen, muss der Datentyp des Wertes zum Datentyp der Variablen passen.

Icon HINWEIS

5.2.3 Initialisierung
Wenn Sie mchten, knnen Sie Ihren Variablen bereits bei der Definition einen Anfangswert zuweisen. Man bezeichnet dies als Initialisierung:
int alter = 24; int i = 0, j = 1, n = 2;

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Variablen und Konstanten Seite 106

Welchen Anfangswert haben nicht initialisierte Variablen? Hier ist Icon AUFSTEIGER zwischen Feldern von Klassen und lokalen Variablen zu unterscheiden. Felder bekommen den Nullwert ihres Datentyps zugewiesen, lokale Variablen werden berhaupt nicht initialisiert.

5.2.4 Werte von Variablen abfragen


Einen Wert in einer Variablen abzuspeichern, ist natrlich nur dann interessant, wenn man auf den Wert der Variablen spter noch einmal zugreifen mchte beispielsweise um den Wert in einer Formel einzubauen oder auszugeben.
class Demo { public static void main(String[] args) { int ersteZahl; int zweiteZahl; int ergebnis; ersteZahl = 8000; zweiteZahl = 312; ergebnis = ersteZahl + zweiteZahl; System.out.println(ergebnis); } }

Offensichtlich kann man ber den Variablennamen der Variablen sowohl einen neuen Wert zuweisen als auch den aktuellen Wert der Variablen abfragen. Woher aber wei der Compiler, wenn er auf einen Variablennamen trifft, ob er der Variablen einen Wert zuweisen oder ob er den aktuellen Wert der Variablen abfragen soll? Ganz einfach! Taucht der Variablenname auf der linken Seite einer Zuweisung auf (wie in zahl = 100;), weist der Compiler der Variablen den Wert des Ausdrucks auf der rechten Seite des =-Operators zu.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Variablen und Konstanten Seite 107

Taucht der Variablenname an irgendeiner anderen Stelle auf (wie in System.out.println(zahl);), verwendet der Compiler anstelle des Variablennamens den aktuellen Wert der Variablen.
Icon HINWEIS

Es ist sogar mglich, in einer Anweisung den Wert einer Variablen abzufragen, zu verndern und der Variablen wieder zuzuweisen:
zahl = zahl * 3; // den Wert in zahl verdreifachen

5.2.5 Gltigkeitsbereiche
Als Programmieranfnger wrde man sich manchmal sicher wnschen, man knnte alle bentigten Variablen einfach vorab am Anfang der Quelltextdatei definieren und dann berall im Code verwenden. Doch dieses Verfahren wre bei umfangreicheren Programmen viel zu fehleranfllig. In Java hat jede Variable daher einen eigenen begrenzten Gltigkeitsbereich (englisch scope).
Variable Lokale Variablen Gltigkeitsbereich Den kleinsten Gltigkeitsbereich haben die lokalen Variablen. Sie sind nur in dem Anweisungsblock gltig, in dem sie deklariert wurden. Dies kann der Anweisungsblock einer Methodendefinition, aber auch der Block einer ifVerzweigung, einer Schleife oder sogar der Kopf einer forSchleife sein. Lokale Variablen werden erzeugt, wenn die Methode, in der sie definiert wurden, aufgerufen wird. Wenn die Methode beendet wird, werden alle lokale Variablen gelscht (um beim nchsten Aufruf der Methode neu angelegt zu werden). Parameter Felder Parameter sind berall in ihrer Methode gltig. Der Gltigkeitsbereich der Felder ist ihre Klasse, d.h. sie knnen in allen Methoden der Klasse verwendet werden. Statische Felder existieren das ganze Programm ber. Die normalen Instanzfelder werden in den Objekten der Klasse angelegt und existieren nur so lange, wie das Objekt existiert.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Variablen und Konstanten Seite 108

Tabelle 5.3: Gltigkeitsbereiche

class Demo { int wert = 1; void methode() { int j = 0; int n = 1; for(int i = 1; i < 5; ++i) { n *= i; } } }
Abbildung 5.1: Gltigkeitsbereiche

Klassenbereich Methodenblock

for-Block

5.3

Datentypen

Java unterscheidet die untersttzten Datentypen in elementare und komplexe Datentypen. Die elementaren oder primitiven Datentypen korrespondieren mit den klassischen Datentypen (Ganzzahlen, Gleitkommazahlen, boolesche Werte, Zeichen und Bytes), wie sie bereits auf Maschinenebene vom Befehlssatz des Prozessors untersttzt werden. Sie sind fest in die Sprache integriert. Die komplexen Datentypen werden vom Programmierer selbst definiert und aus Elementen bestehender Datentypen (elementare wie auch bereits definierte komplexe Datentypen) zusammengesetzt. Elementare und komplexe Datentypen unterscheiden sich auch in der Art der Speicherung. Die Werte der elementaren Datentypen werden direkt in der Variablen gespeichert. (Der Compiler reserviert fr Variablen elementarer Datentypen so viel Platz, wie ntig ist, um beliebige Werte ihres Datentyps aufnehmen zu knnen.)

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Variablen und Konstanten Seite 109

Die Werte der komplexen Datentypen sind grundstzlich Objekte im Sinne der objektorientierten Programmierung. Diese Objekte werden frei im Heap-Bereich des Arbeitsspeichers abgelegt. In den Variablen komplexer Datentypen werden lediglich Verweise (Referenzen) auf die Objekte gespeichert (siehe Tutorium 3, Abschnitt Objektorientierte Programmierung in Java). In der Java-Sprachspezifikation werden diese Typen daher auch als Referenztypen bezeichnet.

5.3.1 Die elementaren Datentypen


Die elementaren Datentypen sind fest in der Sprache verankert. Fr jeden elementaren Datentyp gibt es in Java ein eigenes Schlsselwort (zur Definition von Variablen und symbolischen Konstanten des Typs), eine eigene Syntax fr Literale, einen festen Wertebereich (ergibt sich aus dem Kodierungsverfahren, nach dem die Werte des Typs binr kodiert werden, und der Gre des Speicherbereichs, der fr Variablen des Typs reserviert wird) sowie einen Satz vordefinierter Operationen (samt passender Operatoren), die auf die Werte des Datentyps angewendet werden drfen, und eine sogenannte Wrapper-Klasse, die zum einen ntzliche Methoden und Konstanten fr die Arbeit mit den Daten bereitstellt, zum anderen eine Objektreprsentation der elementaren Daten erlaubt (siehe weiter unten).
Gre 1 Beschreibung und Wertebereich Beispiele

Typ

boolean

Fr boolesche Wahrheitswerte (wie true sie in Bedingungen von Schleifen und false Verzweigungen verwendet werden)

true (wahr) und false (falsch) char


2 Fr einzelne Zeichen

'a' '\n' -3 0

Wertebereich sind die ersten 65536 '?' Zeichen des Unicode-Zeichensatzes

byte

Ganze Zahlen sehr kleinen Betrags -128 bis 127

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Variablen und Konstanten Seite 110

98 short
2 Ganze Zahlen kleinen Betrags -32.768 bis 32.767

-3 0 1205 -3 0 1000000 -3 0 1000000000000


geringer 123.56700

int

Standardtyp fr ganze Zahlen -2147483648 bis 2147483647

long

Fr sehr groe ganze Zahlen -9223372036854775808 bis 9223372036854775807

float

Fr Gleitkommazahlen Genauigkeit +/-3,40282347*1038

-3.5e10

double

Standardtyp fr Gleitkommazahlen 123.456789 mit grerer Genauigkeit +/-1,79769313486231570*10308

12005.55e-12

Tabelle 5.4: Die elementaren Datentypen berlauf Die Integer-Typen fr ganze Zahlen unterliegen der Problematik des berund Unterlaufs: Rechenoperationen knnen zu unerwarteten Ergebnissen fhren, wenn das Ergebnis auerhalb des Wertebereichs des Typs liegt. Wenn Sie mit sehr groen oder sehr kleinen Werten rechnen, sollten Sie selbst wenn die Werte an sich ganzzahlig sind, unter Umstnden lieber Gleitkommatypen verwenden. Genauigkeit und Rundungsfehler Die Gleitkommatypen knnen zwar sowohl sehr groe als auch sehr kleine Zahlen reprsentieren, haben aber gegenber den Integer-Typen das Manko, dass es durch die interne Codierung zu Rundungsfehlern kommen kann.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Variablen und Konstanten Seite 111

Escape-Sequenzen Escape-Sequenzen sind mit einem Backslash eingeleitete Zeichenfolgen, die es Ihnen gestatten, Zeichen, fr die es keine grafische Darstellung gibt (etwa der Zeilenumbruch) oder die vom Compiler ansonsten nicht als einfaches Zeichen, sondern als Bedeutung tragendes Symbol (etwa das \n-Zeichen fr den Zeilenumbruch) interpretiert werden, in einen String einzubauen.
Escape-Sequenz Beschreibung Einfaches Anfhrungszeichen Doppeltes Anfhrungszeichen Backslash Rckschritttaste Seitenvorschub Neue Zeile (Zeilenumbruch) Horizontaler Tabulator Wagenrcklauf

\' \" \\ \b \f \n \t \r

Tabelle 5.5: Die Escape-Sequenzen Beispiel:


String text = "Es heit: \"Der Tod ist der Snde Sold.\""

5.3.2 Die komplexen Datentypen


Komplexe Datentypen sind Datentypen, die vom Programmierer selbst definiert werden knnen. In Java sind zudem alle komplexen Datentypen Referenztypen. In den folgenden Abschnitten werden die einzelnen komplexen Datentypen kurz vorgestellt. Allgemeines In Java sind alle komplexen Datentypen Referenztypen, d.h. ihre Werte werden nicht wie die Werte elementarer Datentypen im Speicherbereich ihrer Variablen, sondern frei im Arbeitsspeicher angelegt. Zudem spricht man bei den komplexen Datentypen blicherweise nicht von Werten, sondern von Objekten.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Variablen und Konstanten Seite 112

Objekte von Referenztypen werden mit dem new-Operator erzeugt:


DemoKlasse obj = new DemoKlasse(); int[] einArray = new int[100]; // Erzeugung eines // Klassenobjekts // Erzeugung eines // Array-Objekts

Das Objekt wird im Speicher erzeugt, der new-Operator liefert die Referenz auf das Objekt zurck, die in einer passenden Variablen gespeichert werden kann. Dies hat Folgen fr die Programmierung. Ebenso wie wir elementare Variablen als Reprsentanten der in ihnen gespeicherten Werte ansehen, betrachten wir Objektvariablen als Reprsentanten der Objekte, auf die sie verweisen. Dies ist selbstverstndlich statthaft, darf jedoch nicht dazu fhren, dass wir vergessen, dass der Wert einer Objektvariablen eine Referenz ist (und nicht das Objekt). Wird einer Objektvariablen ein anderes Objekt zugewiesen, wird die Referenz und nicht das Objekt kopiert. Gleiches gilt fr Vergleiche mit == und !=, die fr Objektvariablen nur die Referenzen, nicht die Objekte vergleichen. Der Vergleich obj1 == obj2 liefert daher genau dann true zurck, wenn die Referenzen in obj1 und obj2 identisch sind und auf ein und dasselbe Objekt verweisen. Die Lebensdauer eines Objekts ist nicht an eine bestimmte Objektvariable gekoppelt. Es besteht so lange, wie es mindestens eine Variable gibt, die eine Referenz auf das Objekt enthlt. Gibt es keine Referenz mehr, wird das Objekt von der automatischen Speicherbereinigung (Garbage Collection) aufgelst.

Die automatische Speicherbereinigung Die Speicherbereinigung entsorgt die berflssigen Objekte allerdings nicht unmittelbar. Vielmehr wird die Speicherbereinigung in periodischen Zeitabstnden von der Laufzeitumgebung aufgerufen. Dann prft sie, ob es Objekte ohne Referenzen gibt, und lscht diese. Wenn der Arbeitsspeicher zu einem kritischen Faktor wird (etwa weil Ihre Anwendungen auf Systemen mit wenig Arbeitsspeicher laufen sollen oder viele, umfangreiche Objekte erzeugen und verwerfen), sollten Sie die Speicherbereinigung selbst starten: mit System.gc().

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Variablen und Konstanten Seite 113

Das Konzept der Referenztypen hat verschiedene Vorteile: Die Lebensdauer der Objekte ist nicht an die Variablen geknpft wodurch insbesondere der Austausch ber Methodengrenzen hinweg (siehe obiges Beispiel) vereinfacht wird. Wenn Methoden ber Parameter oder Rckgabewerte Objekte austauschen, tauschen sie nicht die tatschlichen Objekte, sondern nur die Referenzen. Dies spart Speicher und Zeit, denn statt umfangreicher Objekte werden nur Referenzen kopiert. Zudem kann die aufgerufene Methode als Argumente bergebene Objekte direkt bearbeiten. Der Programmierer muss sich selbst nicht um die Speicherverwaltung kmmern. Er erzeugt die Objekte nach Bedarf und kann sich darauf verlassen, dass die Objekte, wenn sie nicht mehr bentigt werden (d.h., wenn es keine Referenzen mehr auf sie gibt), automatisch entsorgt werden.

5.3.3 Klassen
Der mit Abstand wichtigste komplexe Datentyp in Java ist die Klasse, denn auf diesem Datentyp beruht die gesamte objektorientierte Programmierung in Java. Aus diesem Grund wurde den Klassen ein eigenes Kapitel gewidmet (siehe Tutorium 8). Der vorliegende Abschnitt fasst nur noch einmal die wichtigsten Konzepte zusammen. (Fr eine ausfhrlichere Erluterung in Sinn und Bedeutung der Klassen fr die objektorientierte Programmierung siehe Tutorium 3.4 ). Klassen sind Datentypen, ihre Werte werden als Objekte bezeichnet und mssen explizit mit new erzeugt werden (siehe unten). Die Klassendefinition beschreibt, wie die Objekte der Klasse aufgebaut sind und wie man mit ihnen programmieren kann. Zu diesem Zweck enthlt sie Feld-, Konstruktor- und Methodendefinitionen. Eingeleitet wird die Klassendefinition mit dem Schlsselwort class:
class Klassenname { Felder Konstruktoren Methoden }

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Variablen und Konstanten Seite 114

Klassenname

Der Klassenname ist innerhalb der fr Bezeichner geltenden Regeln frei whlbar. Per Konvention beginnen Klassennamen in Java mit einem Grobuchstaben.

Felder

Die Variablen einer Klasse werden als Felder bezeichnet. Wenn spter mit new Objekte der Klasse erzeugt werden, erhlt jedes Objekt einen Satz Kopien von den in der Klasse definierten Feldern (Ausnahme: statische Felder). Die Felder einer Klasse knnen in allen Methoden der Klasse verwendet werden. Je nach Zugriffsregelung (siehe Tutorium 8.5) kann auch ber das Objekt auf die Felder zugegriffen werden.

Konstruktoren

Konstruktoren sind spezielle Methoden (siehe Tutorium 8.3), die den Namen der Klasse tragen und automatisch bei der Objekterzeugung aufgerufen werden. Konstruktoren dienen dazu, den Feldern der Objekte Anfangswerte zuzuweisen oder andere Initialisierungsarbeiten durchzufhren.

Methoden

Die Methoden der Klasse legen fest, wie mit den Objekten der Klasse programmiert werden kann. Sie sind die Operatoren des Klassentyps.

Klassen und die objektorientierte Programmierung Das Konzept, welches hinter den Klassen und allgemein der objektorientierten Programmierung steht, beruht auf der alltglichen Erfahrung, dass wir die Objekte der realen Welt nach zwei Mastben beurteilen: einmal nach Merkmalen wie Form und Farbe, zum anderen nach bestimmten Verhaltensweisen, die ein Objekt aufweist und die beispielsweise festlegen, wie man mit ihm umzugehen hat, wie man es manipulieren kann oder welche Aufgaben es fr einen erledigen kann. In der objektorientierten Terminologie entsprechen die Merkmale den Feldern und die Verhaltensweisen den Methoden. Eine Klasse ist in diesem Sinne eine Schablone zur Erzeugung von Objekten mit gleichen Merkmalen und Verhaltensweisen. So knnte eine Klasse Ware beispielsweise folgendermaen aussehen.
Beispiel: Klassendefinition
class Ware { String name; // Felder

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Variablen und Konstanten Seite 115

double preis; Ware(String n, double p) { name = n; preis = p; } String getName() { return name; } double getPreis() { return preis; } void rabattieren() { preis = preis * 0.9; } } // Konstruktor

// Methoden

Instanzbildung Die Erzeugung eines Objekts einer Klasse wird als Instanzbildung oder Instanzierung bezeichnet (d.h. das Objekt wird als Instanz ihrer Klasse gesehen). Bei der Instanzbildung, die mit dem Schlsselwort new erfolgt, wird ein Konstruktor der Klasse aufgerufen. Der Konstruktor dient dazu, das neu erzeugte Objekt in einen definierten Anfangszustand zu versetzen beispielsweise indem er Werte fr die Felder des Objekts entgegennimmt und diesen zuweist. Auf diese Weise entsteht durch Spezialisierung ein individuelles Objekt.
Ware obj1 = new Ware("Schachspiel", 19.95); Ware obj2 = new Ware("Espresso-Tasse", 3.90);

Kapselung und ffentliche Schnittstelle Die Zusammenfassung von Datenelementen (Feldern) und Methoden wird als Kapselung bezeichnet. Mit ihr verbinden sich die Kriterien des Information hidings, der ffentlichen Schnittstelle und der Abgeschlossenheit. Unter Information hiding versteht man, dass der Benutzer der Klasse (der Programmierer, der Objekte der Klasse erzeugt) mit den Objekten der Klasse arbeiten kann, ohne sich ber Implementierungsdetails der Klasse informieren zu mssen. Fr die Methode rabattieren() der Klasse Ware bedeutet dies beispielsweise, dass der Benutzer der Klasse anhand des

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Variablen und Konstanten Seite 116

Methodennamens und eventuell einer kurzen Beschreibung (Dokumentation der Klasse) auf Zweck und Einsatzmglichkeiten der Methode schlieen kann. Um die Methode aufrufen zu knnen, muss er dann nur noch wissen, welche Argumente der Methode zu bergeben sind und was fr einen Rckgabewert sie hat. Was der Benutzer der Klasse nicht wissen muss, ist, wie die Methode ihrer Aufgabe nachkommt, welche Felder die Methode manipuliert und ob sie intern selbst weitere Methoden aufruft. Aus dem Information hiding ergibt sich die Forderung nach einer ffentlichen Schnittstelle. Damit eine Klasse ordnungsgem funktioniert, ist es oft ntig, dass sie Elemente (Felder oder Methoden) definiert, die fr die interne Implementierung vonnten sind, deren Manipulation oder direkter Aufruf ber ein Objekt (d.h. durch Benutzer der Klasse) unerwnscht, ja sogar gefhrlich ist. Beispielsweise knnte der Programmierer der Klasse Ware das Ziel verfolgen, dass der Preis einer Ware bei der Instanzbildung festgesetzt und danach nur durch Rabattierungsschritte zu jeweils 10 Prozent reduziert, nicht aber strker reduziert, erhht oder beliebig gendert werden kann. Um dies zu erreichen, muss er das Feld preis vor dem Zugriff durch den Benutzer (d.h. Zugriff ber ein Objekt) schtzen. Hierzu gibt es in Java das Konzept der Zugriffsspezifizierer, die regeln, welche Klassenelemente von auerhalb der Klasse (beispielsweise ber ein Objekt) angesprochen werden knnen. Java kennt vier Zugriffsebenen, von denen hier nur die beiden Extreme private (das Element kann nur innerhalb der eigenen Klassendefinition benutzt werden) und public (das Element ist frei verfgbar) erwhnt seien. Die Gesamtheit der publicElemente bezeichnet man als ffentliche Schnittstelle.
Beispiel: Einsatz von Zugriffsspezifizierern
public class Ware { private String name; private double preis; public Ware(String n, double p) { name = n; preis = p; } public String getName() { return name; } // private Felder // ffentlicher // Konstruktor

// ffentliche // Methoden

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Variablen und Konstanten Seite 117

public double getPreis() { return preis; } public void rabattieren() { preis = preis * 0.9; } }

Nun knnen name und preis der erzeugten Objekte nicht mehr direkt manipuliert oder abgefragt werden.
Ware obj1 = new Ware("Schachspiel", 19.95); obj1.preis = 12.95; // Fehler, kein Zugriff System.out.println(obj1.preis); // Fehler, kein Zugriff

Preis und Name mssen ber die public-Methoden getPreis() und getName() abgefragt werden. Der Name kann nicht nachtrglich gendert werden, der Preis kann mithilfe von rabattieren() reduziert werden:
public class Test_Ware { public static void main(String[] args) { Ware obj1 = new Ware("Schachspiel", 19.95); Ware obj2 = new Ware("Espresso-Tasse", 3.90); obj2.rabattieren(); System.out.println(" Unsere Preise:\n"); System.out.println("\t" + obj1. getName() + " : " + obj1. getPreis()); System.out.println("\t" + obj2. getName() + " : " + obj2. getPreis()); } }

Vererbung Klassen knnen auf der Basis bereits vorhandener Klassen definiert werden. Bei diesem, als Vererbung bezeichneten Vorgang wird die vererbende Klasse mit dem Schlsselwort extends an den Namen der zu definierenden Klasse angehngt:
class AbgeleiteteKlasse extends Basisklasse { ... }

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Variablen und Konstanten Seite 118

Die neue, abgeleitete Klasse erbt alle Elemente der Basisklasse (mit Ausnahme der Konstruktoren). Zudem knnen Objekte einer abgeleiteten Klasse immer auch als Objekte vom Typ der Basisklasse angesehen werden ein Konzept, das in der objektorientierten Programmierung eine groe Rolle spielt und durch das Konzept der Interfaces (siehe unten) ergnzt wird. In Java gehen alle Klassen automatisch auf die oberste Basisklasse Object zurck und erben deren Elemente, sodass eine gewisse Grundfunktionalitt garantiert ist (siehe 4.5.2).

5.3.4 Interfaces (Schnittstellen)


Interfaces sind Kontrakte mit Datentypcharakter. Sie werden mit dem Schlsselwort interface definiert und enthalten ausschlielich Methodendeklarationen (ohne Anweisungsblock), die automatisch public sind.
interface Verschiebbar { void verschieben(int dx, int dy); }

Von Interfaces selbst knnen allerdings keine Objekte erzeugt werden. Sie sind dafr gedacht, von Klassen implementiert zu werden. Eine Klasse, die ein Interface implementiert, zeigt dies mit dem Schlsselwort implements an und definiert alle in dem Interface deklarierten Methoden:
class Demo implements Verschiebbar { ... // Interface-Methoden definieren void verschieben(int dx, int dy) { ... } }

Entscheidend ist, dass die Objekte einer Klasse nicht nur als vom Typ ihrer Klasse angesehen werden knnen, sondern auch als Objekte vom Typ aller Interfaces, die die Klasse implementiert. Neben der Vererbung stellt die Interface-Implementierung daher die zweite Mglichkeit dar, Objekte verschiedener Klassentypen auf einen gemeinsamen Typ zurckzufhren (wobei der gemeinsame Typ im ersten Fall durch Vererbung von einer gemeinsamen Basisklasse und im zweiten
Icon HINWEIS

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Variablen und Konstanten Seite 119

Fall durch Implementierung eines gemeinsamen Interface definiert wird). Die Rckfhrung von Objekten verschiedener Klassen auf einen gemeinsamen Typ ist die Grundlage fr die Polymorphie, siehe 8.6.

5.3.5 Arrays
Arrays sind Typen, die eine Sammlung von Werten (oder Objekten) eines Typs reprsentieren. Wenn Sie beispielsweise 100 Messwerte einlesen und bearbeiten mssen, ist es einfacher, diese in einem Array von 100 doubleWerten zu speichern als in 100 explizit zu deklarierenden doubleVariablen. Array-Erzeugung Arrays sind Objekte und werden als solche mit dem Schlsselwort new erzeugt.
new Typ[anz_elemente]; Typ Datentyp der Elemente, die in dem Array gespeichert werden

anz_elemente Anzahl der Elemente im Array Der Datentyp eines Arrays wird bezeichnet durch den Typ der Elemente, gefolgt von den leeren Dimensionsklammern: Typ[].
int[] monatsumsatz = new int[12]; Ware[] waren = new Ware[100];

Als Grenangabe sind nur positive Integer-Werte grer null erlaubt.

Icon HINWEIS

Initialisierung Array-Objekte knnen auch implizit erzeugt werden mithilfe einer Initialisierungsliste. In dieser werden einfach die Werte aufgefhrt, die als Elemente in das Array aufgenommen werden sollen. Die Gre des ArrayObjekts ergibt sich dabei automatisch aus der Anzahl der aufgelisteten Werte:
int[] zahlen = {1, 2, 3, 7, 12, 24}; double[] weitereZahlen = {7.2, var1, var2 3.0, 0.5};

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Variablen und Konstanten Seite 120

Der Compiler erzeugt hier implizit ein passendes Array-Objekt, initialisiert dessen Elemente mit den Werten aus der Initialisierungsliste und speichert die Referenz auf das Objekt in der Array-Variablen. Zugriff auf Array-Elemente Auf die einzelnen Elemente des Arrays wird ber einen Index zugegriffen, der in eckigen Klammern steht. Das erste Element eines Arrays hat immer den Index 0. Das letzte Element hat den Index groesse - 1. Die folgende Anweisung weist dem 12. Element im Array daten den Wert 123.5 zu:
int[] daten = new int[20]; daten[11] = 123.5;

Sollen alle Elemente eines Arrays bearbeitet werden, ist es blich, das Array mit einer Schleife (siehe Tutorium 6.4) zu durchlaufen.
// Array mit 10 Integer-Werten anlegen und in diesen die // Quadratzahlen von 1 bis 10 ablegen int[] zahlen = new int[10]; for (int i = 0; i < zahlen.length; ++i) { zahlen[i] = (i+1)*(i+1); }

Hier wird die Schleifenvariable i von 0 bis zum letzten Index im Array hochgezhlt und im Schleifenblock als Index fr die Adressierung der einzelnen Array-Elemente verwendet (zahlen[i]). Wenn Sie den Index der Elemente nicht bentigen, sondern nur die Elemente selbst, knnen Sie auch die neue "for-each"-Syntax whlen:
for(int zahl : zahlen) { System.out.println(zahl); }

Hier wird das Array zahlen automatisch durchlaufen und die einzelnen Elemente werden nacheinander in zahl abgespeichert und im Schleifenblock ausgegeben. Achten Sie darauf, nur Indizes zu verwenden, die im Bereich [0, AnzahlElemente-1] liegen. Zugriffe ber Arraygrenzen hinweg lsen eine ArrayIndexOutOfBoundsException-Ausnahme aus.
Icon ACHTUNG

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Variablen und Konstanten Seite 121

Array-Lnge Jeder Array-Typ verfgt neben den von Object geerbten Methoden ber ein final-Feld namens length, das die Gre des Arrays angibt:
System.out.println(meinArray.length);

Die Klasse java.util.Arrays Schlielich gibt es im Paket java.util die Utility-Klasse Arrays mit statischen Methoden zum Fllen (fill()), Vergleichen (equals()), Sortieren (sort()), schnellem Durchsuchen (binarySearch()) und Ausgeben (toString()) von Arrays. Jede dieser Methoden ist fr die verschiedenen elementaren Datentypen und fr Argumente vom Typ Object berladen.

5.3.6 Aufzhlungen
Aufzhlungen sind Datentypen, deren Wertebereich aus einer Gruppe von Konstanten besteht. Welche Konstanten zu einer Aufzhlung gehren, legt der Programmierer selbst fest. Typische Beispiele sind Aufzhlungen fr Monate, Dateiflags etc.
enum typname { Element1, Element2, ...}

typname

Name des neuen Aufzhlungstyps

Element1... Die Namen der einzelnen Konstanten des Aufzhlungstyps


Die einzelnen Konstanten erinnern semantisch an IntegerKonstanten, werden aber intern durch Objekte vom Typ der Aufzhlung reprsentiert. Die Reihenfolge der Konstanten in der Aufzhlungsdefinition bleibt den Konstanten zu eigen und kann mithilfe der Methode compareTo() abgefragt werden.

Von Aufzhlungstypen knnen Sie wie von anderen Typen Variablen definieren. Als Werte knnen Sie diesen ausschlielich die Konstanten des Aufzhlungstyps zuweisen.
enum Fehler { ERROR_LESEN, ERROR_SCHREIBEN } Fehler f = Fehler.ERROR_LESEN;

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Variablen und Konstanten Seite 122

Sie knnen Aufzhlungskonstanten vergleichen, jedoch nicht mit IntegerWerten, sondern nur untereinander mithilfe der Methode compareTo(), die -1, 0 oder 1 zurckliefert, je nachdem, ob die Position der aktuellen Konstante kleiner, gleich oder grer als die der bergebenen Konstante ist.
if (f.compareTo(Fehler.ERROR_SCHREIBEN) == 0) System.out.println("Fehler beim Schreiben");

enum-Konstanten knnen auch als case-Konstanten in switchVerzweigungen (siehe Tutorium 6.4) verwendet werden:
switch (f) { case ERROR_LESEN: System.out.println("Fehler beim Lesen"); break; case ERROR_SCHREIBEN: System.out.println("Fehler beim Schreiben"); break; default: System.out.println("Unbekannter Fehler"); }

Die Zuweisung von Integer-Werten an enum-Konstanten ist nicht mglich, da Aufzhlungskonstanten Objekte vom Typ der Aufzhlung sind.

Icon HINWEIS

5.3.7 Strings
Strings werden in Java durch die Klasse String reprsentiert. Das heit., es handelt sich um einen Klassentyp und nicht wie im Falle von Aufzhlungen oder Arrays um eine eigene Kategorie komplexer Datentypen. Im Vergleich zu anderen Klassentypen nehmen Strings in Java allerdings eine Sonderstellung ein, die es dem Programmierer erlaubt, Strings fast schon wie einen elementaren Datentyp zu verwenden. So gibt es String-Literale:
"Ich bin ein String!";

String-Operatoren: Sie knnen Strings aneinanderhngen: mit dem Konkatenationsoperator +

str = "Dieser String ist so gross, dass " + " er der besseren bersicht wegen " + " auf drei Zeilen verteilt wurde.";

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Variablen und Konstanten Seite 123

Da Strings in Java Objekte der Klasse String sind, werden bei Vergleichen mit den Operatoren == und != lediglich die Referenzen auf die String-Objekte verglichen. Der Vergleich str1 == str2 liefert daher nur dann true, wenn str1 und str2 auf dasselbe Objekt verweisen, whrend zwei verschiedene String-Objekte, die den gleichen Text enthalten, als verschieden angesehen werden. Dies gilt jedoch nicht fr String-Literale. Diese werden von der internen Java-Implementierung in einem String-Pool verwaltet, der dafr sorgt, dass es zu jedem StringLiteral immer nur ein String-Objekt gibt. Ein Vergleich:
String c = "Panther"; String d = "Panther"; System.out.println(c == d);

liefert daher true. String-Typumwandlungen: Wenn Sie einen Wert oder ein Objekt mit print() oder println() auf die Konsole ausgeben, wird der Wert (das Objekt) automatisch in einen String verwandelt.
int zahl = 3; System.out.println(zahl); // gibt den // String "3" aus

Und wenn Sie einen Wert eines elementaren Datentyps oder ein Objekt mithilfe des Konkatenationsoperators + mit einem String verketten, wird der Wert (das Objekt) ebenfalls automatisch in einen String verwandelt:
int zahl = 3; String str = "-fach"; str = zahl + str;

// erzeugt den // String "3-fach"

Die Erklrung fr dieses Phnomen ist, dass in den obigen Fllen die toString()-Methode der Objekte aufgerufen wird. (Im Falle von elementaren Datentypen die toString()-Methode der zugehrigen Wrapper-Klasse.) Zudem ist die Klasse String in dem Paket java.lang definiert, sodass der Programmierer String ohne Angabe des Pakets und ohne importAnweisung verwenden kann.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Variablen und Konstanten Seite 124

5.4

Typumwandlung

In Java haben alle Programmelemente, die mit Daten zu tun haben, einen festen, nicht-vernderlichen Datentyp. Gelegentlich ist es jedoch wnschenswert oder erforderlich, dass ein Wert eines bestimmten Datentyps als einem anderen Datentyp zugehrig angesehen wird. Dabei ist zwischen den widening, narrowing und selbst definierten Typumwandlungen zu unterscheiden.

5.4.1 Automatische oder implizite (widening) Typumwandlungen


Dies sind Typumwandlungen, die der Compiler ohne Fehler und greren Informationsverlust vornehmen kann. Zu ihnen zhlen die Umwandlungen zwischen byte short int long float und double sofern ein links aufgefhrter Typ in einen weiter rechts stehenden Typ umzuwandeln ist. Fr Referenztypen werden die folgenden impliziten Typumwandlungen automatisch ausgefhrt: von abgeleiteter Klasse (Interface) in Basisklasse (Basis-Interface) von Klasse in Interface, das die Klasse implementiert von null in Klasse, Interface oder Array von Klasse, Interface oder Array in Object

short s = 1234; int i = 2; long l; i = s; l = 12345; // Umwandlung von short in int // Umwandlung von int (Standard fr // ganzzahlige Literale) in long
Icon ACHTUNG

Nicht alle widening-Typumwandlungen knnen ganz ohne Informationsverlust durchgefhrt werden. Bei der Umwandlung eines int-

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Variablen und Konstanten Seite 125

Werts in einen float-Wert sowie bei der Umwandlung von long in float oder double kann es wegen der geringeren Zahl signifikanter Stellen in den Gleitkommatypen durchaus zu Informationsverlusten kommen

5.4.2 Explizite (narrowing) Typumwandlungen


Explizite Typumwandlungen (Casting) werden mithilfe des (typ)Operators durchgefhrt:
int iZahl = 124; short sZahl = (short) iZahl;

Beachten Sie, dass dabei nicht der Typ der Variablen iZahl oder ihres Wertes gendert wird. Der Wert der Variablen wird ausgelesen, umgewandelt und der umgewandelte Wert wird in sZahl geschrieben! Abgesehen von den impliziten Typumwandlungen knnen auch folgende Umwandlungen mithilfe des (typ)-Operators vorgenommen werden: Umwandlungen von char in byte oder short Umwandlungen beliebiger Integer- oder Gleitkommatypen in char oder andere Integer- oder Gleitkommatypen Rcknahme einer impliziten Typumwandlung auf Referenztypen (siehe 9.6.2, Typidentifizierung zur Laufzeit).

5.4.3 Selbst definierte Typumwandlungen


Die letzte Form der Typumwandlung ist natrlich immer mglich. In diese Kategorie fallen Typumwandlungen, die der Compiler nicht leisten kann oder die vom Sprachdesigner als zu riskant oder zu exotisch betrachtet werden, um sie direkt zu untersttzen (beispielsweise die Umwandlung beliebiger Klassentypen in Strings wofr Java ja die Methode toString() vorgibt, die in jeder Klasse berschrieben und typspezifisch implementiert werden kann).

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Variablen und Konstanten Seite 126

5.5

Wrapper-Klassen

In der Java-Standardbibliothek gibt es zu jedem elementaren Typ eine passende Klasse, eine so genannte Wrapper-Klasse. Die Bezeichnung Wrapper-Klassen deutet schon an, wofr die Klassen verwendet werden: zur Erzeugung objektorientierter Hllen um elementare Daten.
Elementarer Datentyp Wrapper-Klasse

boolean char byte short int long float double

Boolean Character Byte Short Integer Long Float Double

Tabelle 5.6: Wrapper-Klassen Wozu werden diese objektorientierten Hllen gebraucht? Zum einen stellen sie eine Reihe von ntzlichen Methoden zur Bearbeitung elementarer Daten zur Verfgung. Zum anderen ist die Kapselung elementarer Werte in Objekte allein schon ein groer Vorteil jedenfalls in einer ansonsten vollkommen objektorientierten Programmiersprache.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Variablen und Konstanten Seite 127

Ntzliche Klassenelemente Alle Wrapper-Klassen verfgen ber Konstruktoren, mit deren Hilfe Wrapper-Objekte aus elementaren Daten oder Strings erzeugt werden knnen:
Double dObj = new Double(123.5); Double dObj = new Double("123.5");

verschiedene ntzliche Methoden zum Bearbeiten der Objekte:


int i = dObj.compareTo(43.56); boolean b = dObj.isFinite(); String s = dObj.toString();

sowie Methoden, mit deren Hilfe eine Typumwandlung in ausgewhlte elementare Typen vorgenommen werden kann:
byte b = dObj.byteValue(); int i = dObj.intValue(); long l = dObj.longValue();

Fr die wichtigsten Manipulationen ist die Erzeugung eines Wrapper-Objekts nicht einmal ntig: Die Klassen stellen leistungsfhige statische Methoden zur Verfgung, die Sie direkt ber den Klassennamen aufrufen knnen fr Double beispielsweise:
double d = 12.2; int erg = Double.compare(d, 100,1); long l = Double.doubleToLongBits(d); boolean b = Double.isInfinite(d); b = Double.isNaN(d); double d = Double.parseDouble("12.2"); String s = Double.toString(d); Double dObj = Double.valueOf("12.2");

Schlielich definieren die Wrapper-Klassen wichtige, typspezifische Konstanten fr Double beispielsweise:


Double.MAX_VALUE Double.MIN_VALUE // // // Double.NaN // Double.NEGATIVE_INFINITY // Double.POSITIVE_INFINITY // Double.TYPE // grter positiver double-Wert kleinster positiver double-Wert ungleich 0 Not-a-Number neg. Unendlichkeit pos. Unendlichkeit Instanz der Klasse class

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Variablen und Konstanten Seite 128

Autoboxing Java ist eine objektorientierte Sprache. Viele Konzepte und Elemente der Sprache sind daher nur fr Objekte verfgbar. Mithilfe der Wrapper-Klassen knnen diese Mglichkeiten auch fr elementare Daten nutzbar gemacht werden. Vor Java 5 musste die Umwandlung von elementaren Datentypen in Wrapper-Objekte und umgekehrt allerdings explizit vom Programmierer angestoen werden:
double d = 11.11; Double dObj = new Double(d); // double-Wert // Umwandlung eines // double-Werts in ein // Double-Objekt d = dObj.doubleValue(); // Umwandlung eines Double// Objekts in einen double-Wert

Um diese umstndliche und ungelenke Syntax aus der Welt zu schaffen, wurde in Java 5 das Konzept des Autoboxings eingefhrt. Autoboxing bedeutet, dass der Compiler elementare Daten bei Bedarf automatisch in Objekte der zugehrigen Wrapper-Klassen umwandeln kann. Der umgekehrte Weg wird auch als Autounboxing bezeichnet.
double d = 11.11; Double dObj = new Double(22.22); dObj = d; d = dObj; // Autoboxing // Autounboxing // double-Wert // Double-Objekt

5.6

Quiz

Da es schlichtweg unpassend wre, ein so theoretisches Tutorium wie dieses mit einer praktischen bung abzuschlieen, gibt es nun zum guten Schluss ein kleines Quiz. Die Fragen beziehen sich allerdings nicht allein auf das aktuelle Tutorium zu den Variablen und Datentypen, sondern schlieen auch die Tutorien des vorausgehenden Grundlagenteils ein. Die ersten fnf Fragen sollten Sie mglichst aus dem Gedchtnis beantworten. Fr die letzten sechs Fragen drfen Sie (ja sollen Sie sogar) die zugehrigen Erluterungen weiter oben nachschlagen.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Variablen und Konstanten Seite 129

Fragen 1. 2. 3. 4. Mit welchem JDK-Hilfsprogramm werden Java-Programme kompiliert? Was bergeben Sie dem Java-Interpreter java, um ein Programm ausfhren zu lassen? Wozu dient das Schlsselwort int? Sie haben eine Klasse Rechteck geschrieben, deren Konstruktor als Argumente die cm-Werte fr Breite und Lnge (als double-Werte) bernimmt. Die Klasse definiert zudem eine Methode flaeche(), die keine Parameter definiert und als Ergebnis die Flche des Rechtecks zurckliefert (als double-Wert). Gengen Ihnen diese Angaben, um zwei Zeilen Code aufzusetzen, der die Flche eines Rechtecks mit den Seitenlngen 12 cm und 8,5 cm berechnet? Wie sehen die beiden Zeilen aus? Definieren Sie drei Variablen und initialisieren Sie sie mit den Literalen 1, '1' und 1.0. Welche Regeln gelten fr die Auswahl von Variablennamen? Sind die folgenden Variablendefinitionen gltig? Wenn nicht, was ist der Fehler?
int ersterWert; int 2terWert; string s;

5. 6.

7.

Sie haben einen String mit einer Zahlenangabe vorliegen, z.B. "12.3". Wie knnen Sie diesen String in einen double-Wert umwandeln? (Stichwort Wrapper-Klassen) Was knnte man an der folgenden Definition unter Umstnden verbessern? (Denken Sie an das Thema dieses Tutoriums.)
int altersgrenze;

8.

9.

Was ist falsch an der folgenden Zuweisung?


String text = "String-Literale mssen immer in Anfhrungszeichen eingeschlossen werden";

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Variablen und Konstanten Seite 130

10. Knnen Sie einer int-Variablen den Wert 2.000.000.000 zuweisen? Was passiert, wenn Sie der Variablen den Wert 2.500.000.000 zuweisen? 11. Was ist die ffentliche Schnittstelle einer Klasse? Antworten 1. 2. Mit dem Compiler javac. Den Namen der Hauptklasse des Programms (bzw. den Namen der class-Datei der Klasse). Mit Hauptklasse ist dabei einfach die Klasse gemeint, die die main()-Methode des Programms enthlt. Das Schlsselwort int dient zur Definition von Variablen, die ganzzahlige Werte aufnehmen knnen. Die Angaben reichen vollkommen aus:
Rechteck r = new Rechteck(12, 8.5); double flaeche = r.flaeche();

3. 4.

5.

Definieren Sie drei Variablen und initialisieren Sie sie mit den Literalen 1, '1' und 1.0.
int i = 1; char c = 'c'; double d = 1.0;

6.

Sind die folgenden Variablendefinitionen gltig? Wenn nicht, was ist der Fehler?
int ersterWert; int 2terWert; string s; // korrekt // falsch, beginnt mit Ziffer // falsch, string ist kein Datentyp // Der Klassentyp fr Strings heit // String!

7.

Sie haben einen String mit einer Zahlenangabe vorliegen, z.B. "12.3". Wie knnen Sie diesen String in einen double-Wert umwandeln?
String s = "12.3"; double q = Double.parseDouble(s);

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Variablen und Konstanten Seite 131

System.out.println(q);

8.

Was knnte man an der Definition int altersgrenze; unter Umstnden verbessern? Der Name der Variablen lsst darauf schlieen, dass ihr Wert konstant ist. In diesem Fall sollte sie auch als Konstante definiert werden:
final int altersgrenze;

9.

Was ist falsch an der folgenden Zuweisung?


String text = "String-Literale mssen immer in Anfhrungszeichen eingeschlossen werden";

String-Literale knnen nicht auf mehrere Zeilen umbrochen werden. Sie mssen den Text stattdessen in mehrere String-Literale aufteilen und diese mit dem +-Operator wieder zusammenfgen:
String text = "String-Literale mssen immer in " + "Anfhrungszeichen eingeschlossen " + "werden";

10. Knnen Sie einer int-Variablen den Wert 2000000000 zuweisen? Was passiert, wenn Sie der Variablen den Wert 2500000000 zuweisen? Der Wert 2000000000 liegt noch im Wertebereich von int, kann also zugewiesen werden. Der Wert 2500000000 liegt dagegen auerhalb des Wertebereichs und kann nicht zugewiesen werden (lst eine Fehlermeldung des Compilers aus). Der Compiler wird Sie allerdings nicht daran hindern, den Wert 2000000000 einer int-Variablen n zuzuweisen und dann den Wert in n zu verdoppeln: n = n * 2;. In diesem Fall fhrt der Compiler die Berechnung durch, das Ergebnis wird aber falsch sein, da es nicht korrekt durch einen int-Wert reprsentiert werden kann. 11. Was ist die ffentliche Schnittstelle einer Klasse? Die ffentliche Schnittstelle ist die Gesamtheit der public-Elemente einer Klasse. Sie umfasst also die Elemente, die ein Programmierer, der mit der Klasse arbeiten mchte (indem er ihre statischen Methoden aufruft oder Objekte der Klasse erzeugt), verwenden kann. Konnten Sie mindestens fnf Fragen beantworten? Wenn ja, drfen Sie weiterlesen.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Operatoren Seite 132

6 Praxisteil: Operatoren
Bis jetzt waren unsere Beispielprogramme weder besonders ntzlich noch besonders aufregend. Das lag daran, dass wir noch wenig darber erfahren haben, wie man die Daten, die in den Variablen abgespeichert sind, weiterverarbeiten kann.

6.1

Die Operatoren

Dieses Kapitel beginnt mit der Erluterung verschiedener Konzepte wie Prioritt und Klammerung, die fr die Programmierung mit Operatoren von Bedeutung sind. Danach folgen Einzeldarstellungen der wichtigsten Operatorengruppen.

6.1.1 Allgemeines
Die Operatoren sind charakterisiert durch: Typspezifitt. Die Operation, die ein Operator ausfhrt, ist immer typspezifisch. Das heit: Ein Operator akzeptiert nur Operanden passenden Typs:
/* z1, z2 seien vom Typ int, str1 und str2 vom Typ String */ z1 - z2 str1 - str2 // korrekt // falsch

Ist ein Operator fr mehrere Typen definiert, entscheidet der Typ der Operanden ber die auszufhrende Operation:
/* i1, i2 seien vom Typ int, d1 und d2 vom Typ double str1 und str2 vom Typ String */ i1 + i2 d1 + d2 str1 + str2 // Integer-Addition // Gleitkommaa-Addition // String-Konkatenation

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Operatoren Seite 133

Prioritt. Jeder Operator gehrt einer bestimmten Priorittsstufe an. Sind in einem Ausdruck Operatoren verschiedener Priorittsstufen kombiniert, werden die Operationen hherer Prioritt zuerst ausgefhrt. (siehe unten).

Reihenfolge der Operatorenauswertung In Ausdrcken, die aus mehreren Operatoren bestehen, stellt sich die Frage, wie diese Ausdrcke berechnet werden. Dabei spielen die Prioritt und die Assoziativitt der Operatoren, die Reihenfolge der Operandenauswertung sowie die Klammerung eine entscheidende Rolle. Sind in einem Ausdruck Operatoren unterschiedlicher Prioritt kombiniert, werden die Operationen hherer Prioritt zuerst ausgefhrt. Beispielsweise hat die Multiplikation wie in der Mathematik eine hhere Prioritt als die Addition:
int y, x = 2; y = 3 + x * 4; // ergibt y gleich 11

Die Assoziativitt entscheidet darber, in welcher Reihenfolge Operatoren gleicher Priorittsstufe ausgewertet werden. Am hufigsten ist die Auswertung von links nach rechts. Klammerung. Durch das Setzen von Klammern kann der Programmierer die Auswertungsreihenfolge selbst steuern (oder einfach die natrliche Auswertung eines Ausdrucks verdeutlichen).
int y, x = 2; y = 3 + (x * 4); y = (3 + x) * 4; // ergibt y gleich 11 // ergibt y gleich 20

Operandenauswertung. In komplexen Ausdrcken, Teilausdrcke als Operanden auftauchen, gilt:

bei

denen

Bevor eine Operation ausgefhrt wird, werden die Operanden des Operators berechnet. Der rechte Operand wird erst berechnet, nachdem der linke Operand fertig berechnet ist.
ergibt 12, da zuerst der linke Operand ausgefhrt wird -> 3 * 4, statt 4 * 4

int y, x = 3; y = x * ++x; // // // //

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Operatoren Seite 134

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Operatoren Seite 135

6.1.2 Arithmetische Operatoren


Mit den arithmetischen Operatoren knnen Sie, wie es der Name vermuten lsst, einfache arithmetische Rechenoperationen durchfhren.
Operator Operanden Beispiel

+ * / / % %

numerisch

Addition 4 + 3; Subtraktion 4 - 3; Multiplikation 4 * 3;

// 7

numerisch

// 1

numerisch

// 12

Integer

(abgerundete) Ganzzahldivision 7 / 4; // 1

Gleitkomma Division 7.0 / 4.0; Integer

// 1.75

Rest einer Ganzzahldivision 7 % 4; // 3

Gleitkomma Rest einer Ganzzahldivision 7.0 % 4.0; // 3

Bei der Auswertung gilt: Punktrechnung geht vor Strichrechnung. Bei gleicher Prioritt werden die Operatoren von links nach rechts abgearbeitet. Sie knnen durch Setzen von Klammern andere Prioritten vergeben. Die Division durch null fhrt bei Integer-Operanden zur Auslsung einer ArithmeticException (siehe den Exkurs zur Ausnahmenbehandlung), whrend fr Gleitkomma-Operanden als Ergebnis unendlich, reprsentiert durch die Gleitkomma-Konstante NEGATIVE_INFINITY, zurckgeliefert wird.
double quotient = 13.65 / 0.0; if( Double.isInfinite(quotient) )

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Operatoren Seite 136

System.out.println("Unendlichkeit heisst in Java: " + quotient); // Ausgabe: Infinity

6.1.3 Zuweisungen
Bisher wrden Sie, um den Wert einer Variablen zu verndern (sagen wir, ihn mit 3 zu multiplizieren), wie folgt schreiben:
int var = 12; var = var * 3;

Hierfr gibt es eine Kurzform, die auf der Verwendung des kombinierten *=Operators beruht:
int var = 12; var *= 3;

Diese Kurzform ist zunchst zwar etwas gewhnungsbedrftig, spart aber dem Programmierer Tipparbeit und dem Anwender Laufzeit. Kombinierte Zuweisungsoperatoren stehen fr Operationen zur Verfgung: +=, -=, *=, /=, %=. alle arithmetischen

6.1.4 Inkrement und Dekrement


Zwei in der Programmierung hufig bentigte Operationen sind die Erhhung beziehungsweise Verminderung einer numerischen Variablen um den Wert 1. Hierfr gibt es in Java zwei spezielle Operatoren: ++ und --. Die Anweisung
++var;

setzt demnach den Wert der Variablen var um 1 hoch. Die Erhhung um 1 bezeichnet man auch als Inkrement.
Icon MERKSATZ

Die Anweisung
--var;

setzt den Wert der Variablen var um 1 herab.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Operatoren Seite 137

Die Verminderung um 1 bezeichnet man auch als Dekrement.

Icon MERKSATZ

Prfix- und Postfix-Notationen Das Besondere an den Operatoren ++ und -- ist, dass man sie auch in Ausdrcken (also auf der rechten Seite von Zuweisungen) verwenden kann:
var1 = 3 * ++var2;

und dass man sie sowohl vor als auch hinter den Namen der Variablen setzen kann:
var1 = 3 * ++var2; var1 = 3 * var2++;

Zwischen beiden Formen gibt es einen wichtigen Bedeutungsunterschied: Bei der Voranstellung (Prfix-Notation) erhht der Operator den Wert der Variablen und gibt den neuen Wert an den umliegenden Ausdruck weiter, Bei Nachstellung (Postfix-Notation) erhht der Operator den Wert der Variablen, gibt aber den alten Wert an den umliegenden Ausdruck weiter.

Um nicht durch unerwartete Ergebnisse berrascht zu werden, sollten Sie die Inkrement- und Dekrementoperationen immer nur allein in einer Anweisung verwenden.

6.1.5 Die Vergleichsoperatoren


Die vergleichenden und die nachfolgend vorgestellten logischen Operatoren werden in der Programmierung fast ausschlielich zum Aufbau von Bedingungen fr Verzweigungen oder Schleifen verwendet (siehe Tutorium 6.4). Es kann aber nichts schaden, sich vorab schon ein wenig mit diesen Operatoren vertraut zu machen. Mit den vergleichenden Operatoren, die auch relationale Operatoren genannt werden, wird ein Vergleich zwischen zwei Operanden, die auch Ausdrcke sein knnen, durchgefhrt. Das Ergebnis dieser Operation ist vom Datentyp bool und somit entweder wahr (true) oder falsch (false).

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Operatoren Seite 138

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Operatoren Seite 139

Operator

Operanden alle

Beispiel (fr int v = 3;) Gleichheit v == 5 // false

==

boolean option = false; option == false // true Demo Demo obj1 obj1 obj1 = new Demo(); obj2 = new Demo(); == null // false == obj2 // false

!=

alle

Ungleichheit v != 5

// true

boolean option = false; option != false // false Demo Demo obj1 obj1 obj1 = new Demo(); obj2 = new Demo(); != null // true != obj2 // true

< <= > >=

numerisch

Kleiner als v < 3 Kleiner als oder gleich v <= 3 Grer als v > 1 Grer als oder gleich v >= 1

// false

numerisch

// true

numerisch

// true

numerisch

// true

Tabelle 6.1: Vergleichsoperatoren Das Ergebnis eines Vergleichs kann man entweder in einer Variablen vom Typ boolean speichern
int var1 = 12; int var2 = 13; boolean b;

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Operatoren Seite 140

b = var1 < var2; b = var1 > var2;

// b gleich true // b gleich false

oder direkt in den Bedingungen von Verzweigungen oder Schleifen verwenden (mehr hierzu in Tutorium 6.4).
if (var1 == var2) System.out.println("gleich"); else System.out.println("ungleich");

6.1.6 Die logischen Operatoren


Die Programmiersprache Java kennt sechs logische Operatoren fr UND, ODER und NICHT. Bei den logischen UND- und ODER-Operatoren wird der Wahrheitswert der Operanden verknpft, der logische NICHT-Operator konvertiert den logischen Wert seines Operanden ins Gegenteil. Die Operanden mssen selbst boolesche Werte oder Ausdrcke sein. Das Ergebnis einer logischen Verknpfung ist wiederum ein boolescher Wahrheitswert (siehe Vergleichsoperatoren).
Operator Operanden Beispiel

&&, & ||, | ^ !

boolean

Logisches UND if (i > 1 && i < 10) Logisches ODER if (i < 1 || i > 10) Logisches XOR (eXklusives ODER) if (i < 1 ^ i > 10) Logisches NICHT if ! (i == 0)

boolean

boolean

boolean

Tabelle 6.2: Die logischen Operatoren && logisches UND Mit dem Operator && wird eine logische UND-Verknpfung durchgefhrt. Das Ergebnis der Verknpfung hat nur dann den Wert true, wenn beide Operanden den Wert true besitzen.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Operatoren Seite 141

Die folgende Wahrheitstabelle zeigt Ihnen die mglichen Kombinationen.


1. Operand wahr wahr falsch falsch 2. Operand wahr falsch wahr falsch Ergebnis wahr falsch falsch falsch

Tabelle 6.3: UND-Verknpfung Mithilfe der logischen UND-Verknpfung und einer if-Bedingung kann man beispielsweise berprfen, ob der Wert einer Variablen zwischen 10 und 100 liegt:
if( (x > 10) && (x < 100) )

Die Operanden werden von links nach rechts ausgewertet. Wenn der erste Operand den Wert false ergibt, wird der zweite Operand nicht mehr ausgewertet. Soll der zweite Operand stets ausgewertet werden etwa weil er eine wichtige Zuweisung (Inkrement, Dekrement) oder einen auszufhrenden Methodenaufruf enthlt , kann die Auswertung mit dem logischen Operator & erzwungen werden:
if( (x > 10) & (obj.leseWertEin() < 100) )

Icon HINWEIS

|| logisches ODER Der logische ODER-Operator verknpft seine Operanden, sodass das Ergebnis der Verknpfung den Wert true hat, wenn mindestens einer der Operanden den Wert true hat.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Operatoren Seite 142

Die folgende Wahrheitstabelle zeigt Ihnen die mglichen Kombinationen.


1. Operand wahr wahr falsch falsch 2. Operand wahr falsch wahr falsch Ergebnis wahr wahr wahr falsch

Tabelle 6.4: ODER-Verknpfung Mithilfe der logischen ODER-Verknpfung und einer if-Bedingung kann man beispielsweise berprfen, ob der Wert einer Variablen kleiner als 10 oder grer als 100 ist:
if( (x < 10) || (x > 100) )

Wie der &&-Operator wird auch der ||-Operator nur so weit ausgewertet, bis das Ergebnis feststeht. Wenn Sie mchten, dass immer beide Operanden ausgewertet werden, verwenden Sie den Operator | (siehe oben).

Icon HINWEIS

^ logisches XOR Der logische XOR-Operator verknpft seine Operanden so, dass das Ergebnis der Verknpfung den Wert true hat, wenn genau einer der Operanden den Wert true hat. Die folgende Wahrheitstabelle zeigt Ihnen die mglichen Kombinationen.
1. Operand wahr wahr falsch falsch 2. Operand wahr falsch wahr falsch Ergebnis falsch wahr wahr falsch

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Operatoren Seite 143

Tabelle 6.5: XOR-Verknpfung ! logisches NICHT Der logische NICHT-Operator verkehrt den Wahrheitswert seines logischen Operanden ins Gegenteil.

6.1.7 Operatorhnliche Symbole


Neben den eigentlichen Operatoren kennt Java noch eine Reihe von Symbolen und Schlsselwrtern, die mit den Operatoren eng verwandt sind und ihre feste Rolle und Prioritt bei der Ausdrucksauswertung haben.
Operator Operanden new new Typ(Argumente) Beispiel Instanzbildung

() [] . ,

methodenname(Argu Aufruf einer Methode mente) arrayvar[Ausdruck Indizierung (Zugriff auf ein Array-Element) ] bez.bez Zugriff auf ein Klassenelement Qualifizierung von Bezeichnern Anweisung, Anweisung Erlaubt den Einbau mehrerer Anweisungen, wo eigentlich nur eine einfache Anweisung mglich ist, siehe for-Schleife.

6.2

Mathematische Funktionen

Bestimmte, hufig bentigte Rechenoperationen, wie das Ziehen einer Wurzel oder das Berechnen des Sinus eines Winkels, sind mithilfe der Operatoren fr die Grundrechenarten nur sehr schwer umzusetzen. Fr die wichtigsten dieser Rechenoperationen gibt es daher die Klasse Math mit passenden statischen Methoden.
double x = 23.23; double y = -4.5; double z = 20.0; double w; w = Math.abs(y); // absoluter Wert = 4.5

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Operatoren Seite 144

w w w w

= = = =

Math.max(x,y); Math.pow(x,2); Math.sqrt(x); Math.cbrt(x);

// // // //

Maximum = 23.23 Quadrat von x Quadratwurzel aus x Kubische Wurzel aus x

6.2.1 Wichtige Methoden der Klasse Math


static xxx abs(xxx wert) Liefert den absoluten Betrag, |wert|, fr Parameter vom elementaren Datentyp xxx (xxx = int, long, float, double). static double acos(double w) static double asin(double w) static double atan(double w) Berechnet den Arkusk-Kosinus/-Sinus/-Tangens fr Werte w im Bogenma. static double atan2(double x, double y) Umrechnung von kartesischen Koordinaten x,y in Polarkoordinaten (r, ); Rckgabewert ist . static double cbrt(double w) Berechnet die 3. Wurzel aus w. static double ceil(double w) Liefert die nchstgrere ganze Zahl oder w, wenn w bereits ganzzahlig ist. static double cos(double w) static double cosh(double w) Berechnet den Kosinus bzw. Kosinus hyperbolicus von w (w im Bogenma). static double exp(double w) Berechnet e^w. static double floor(double w) Liefert die nchstkleinere ganze Zahl oder w, wenn w bereits ganzzahlig ist.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Operatoren Seite 145

static double log(double w) Berechnet den natrlichen Logarithmus (zur Basis e) von w. static double log10(double w) Berechnet den Logarithmus zur Basis 10 von w. static xxx max(xxx a, xxx b) static xxx min(xxx a, xxx b) Liefert das Maximum bzw. Minimum von a und b als Datentyp xxx (xxx = int, long, float, double). static double pow(double x, double y) Berechnet die Potenz xy. static double random() Liefert eine Zufallszahl x mit 0 <= x < 1.0. static long round() Rundet zur nchsten long-Zahl. static double signum(double w) Liefert das Vorzeichen: Rckgabe von -1 fr w < 0; 0 fr w = 0 und +1 fr w > 0. static double sin(double w) static double sinh(double w) Berechnet den Sinus bzw. Sinus hyperbolicus von w (w im Bogenma). static double sqrt(double w) Berechnet die Quadratwurzel aus w. static double tan(double w) static double tanh(double w) Berechnet den Tangens bzw. Tangens hyperbolicus von w (w im Bogenma). static double toDegrees(double w) static double toRadians(double w) Umrechnung von Bogenma in Gradma oder umgekehrt.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Operatoren Seite 146

Trigonometrische Funktionen Fr die Trigonometrie stehen neben sin(), cos() und tan() auch deren Umkehrfunktionen asin(), acos() und atan() zur Verfgung. Zustzlich existiert eine Methode atan2(), welche die kartesischen Koordinaten x,y in Polarkoordination (r, ) umrechnet:
double th = Math.atan2(1.0,1.0);

Bei den trigonometrischen Funktionen ist zu beachten, dass sie mit dem Bogenma arbeiten; fr Umrechnungszwecke von Grad- nach Bogenma und umgekehrt stehen jedoch entsprechende Umrechnungsmethoden zur Verfgung:
double double double double x y z u = = = = 180.0; Math.toRadians(x); Math.PI / 2.0; Math.toDegrees(z);

Icon ACHTUNG

6.3

Strings (Zeichenketten)

Eine extrem wichtige Aufgabe fr viele Programme ist die Verarbeitung von Zeichenketten (Strings). Sie werden in Java in erster Linie durch die Klasse java.lang.String realisiert; daneben existieren noch verschiedene Untersttzungsklassen, z. B. StringBuffer, StringBuilder und StringTokenizer.

6.3.1 String-Literale
Strings haben wir bisher fast ausschlielich als String-Literale verwendet beispielsweise in den Aufrufen von System.out.println():
System.out.println("Geben Sie die erste Zahl ein: ");

Wie Sie bereits wissen, werden String-Literale dadurch gekennzeichnet, dass sie mit doppelten Anfhrungszeichen beginnen und mit doppelten Anfhrungszeichen enden. Die Frage ist nur, was passiert, wenn ein String selbst doppelte Anfhrungszeichen enthlt.
"Der Pfarrer sprach: "Der Tod ist der Snde Sold.""

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Operatoren Seite 147

Wenn Sie versuchen, einen solchen String auszugeben oder anderweitig zu verarbeiten, werden Sie dafr vom Compiler einen Haufen wtender Fehlermeldungen empfangen. Der Grund ist, dass der Compiler den String nicht nach dem letzten, sondern direkt nach dem zweiten doppelten Anfhrungszeichen beendet sieht. Der Compiler erkennt "Der Pfarrer sprach: " als einen String, dahinter eine Folge von Zeichen Der Tod ist der Snde Sold., mit denen er berhaupt nichts anfangen kann, und schlielich einen zweiten, leeren String "". Um dennoch Strings mit doppelten Anfhrungszeichen definieren und verarbeiten zu knnen, bruchte man einen Weg, wie man dem Compiler anzeigen kann, dass das folgende doppelte Anfhrungszeichen eben nicht das Ende des Strings signalisiert, sondern als normales Zeichen zu behandeln ist. Diese Mglichkeit erffnen uns die Escape-Sequenzen. String-Literale drfen im Code nicht ber mehrere Zeilen reichen, da der Compiler erwartet, dass alle String-Literale am Zeilenende abgeschlossen sind. Um String-Literale dennoch auf mehrere Zeilen zu verteilen, zerteilen Sie den String in Teilstrings und fgen diese mit dem +-Operator wieder zusammen (siehe unten).
Icon ACHTUNG

Escape-Sequenzen Mithilfe des Escape-Zeichens \ kann man zum einen Zeichen, die fr den Compiler eine besondere Bedeutung haben (" oder \), in Strings als einfache Textzeichen kennzeichnen (\" oder \\), zum anderen kann man bestimmte Sonderzeichen in einen Text einfgen (beispielsweise \t zum Einfgen eines Tabulators).
Escape-Sequenz Beschreibung Einfaches Anfhrungszeichen Doppeltes Anfhrungszeichen Backslash Null-Zeichen Signalton Rckschritttaste

\' \" \\ \0 \a \b

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Operatoren Seite 148

\n \t

Neue Zeile (Zeilenumbruch) Horizontaler Tabulator

Tabelle 6.6: Die Escape-Sequenzen Um beispielsweise doppelte Anfhrungszeichen in einem String zu verwenden, brauchen Sie den Anfhrungszeichen im String lediglich das Escape-Zeichen \ voranzustellen:
"Der Pfarrer sprach: \"Der Tod ist der Snde Sold.\""

Mithilfe der Escape-Sequenzen \n und \t kann man auch Textausgaben bersichtlicher gestalten:
class Demo { public static void main(String[] args) { System.out.println(); System.out.println(" Daten von Jim Schmidt: \n"); System.out.println("\t Alter : 39"); System.out.println("\t Groesse : 178 cm"); System.out.println("\t Gewicht : 77 kg"); } }

6.3.2 String-Variablen
Mithilfe des Datentyps String (ein Synonym fr die System.String) knnen wir Variablen fr Strings definieren.
String meinStr;

Klasse

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Operatoren Seite 149

Diesen knnen String-Literale oder Strings aus anderen String-Variablen zugewiesen werden.
class Demo { public static void main(String[] args) { String str1 = "Hallo Welt!"; String str2; str2 = str1; } } System.out.println(str2);

6.3.3 Konkatenation
Die Klasse String ist die einzige Klasse, fr die ein eigener Operator, der Konkatenationsoperator +, definiert ist. Der +-Operator fgt zwei String-Objekte zusammen zu einem neuen String-Objekt und liefert die Referenz auf dieses zurck.
String a = "Am Anfang " + "hie es Oak (Eiche)."; String b = a + " Dann wurde es umbenannt in Java.";

Jede Konkatenation erzeugt ein neues String-Objekt, das sie als Ergebnis zurckliefert. Dies kann bei bermigem Gebrauch (z. B. innerhalb einer Schleife) zu deutlichen Geschwindigkeitseinbuen Ihres Java-Programms fhren. In solchen Fllen sollten Sie auf die Klassen StringBuffer/StringBuilder zurckgreifen.

Icon AUFSTEIGER

6.3.4 Vergleiche mit == und != und String-Pooling


Fr den Vergleich von Strings stellt die Klasse String die Methoden equals(), compareTo() und noch einige weitere zur Verfgung. Mit diesen Methoden knnen die durch die String-Objekte reprsentierten Strings verglichen werden, whrend die Operatoren == und != nur die Referenzen auf die String-Objekte vergleichen. Letztere sind fr unterschiedliche String-

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Operatoren Seite 150

Objekte aber stets verschieden, auch wenn die String-Objekte zufllig gleiche Strings reprsentieren.
String a = new String("Panther"); String b = new String("Panther"); if(a.equals(b)) == true) if(a.compareTo(b) == 0) if(a == b) // liefert true // liefert true // liefert false !!!

Um dennoch direkte String-Vergleiche mit == und != zu gestatten, springt noch einmal die Java-Implementierung bei. String-Literale verwaltet sie intern in einem Pool der Klasse String und liefert fr alle String-LiteralInstanzen eines Programms, die den gleichen String reprsentieren, die gleiche Referenz zurck.
String c = "Panther"; String d = "Panther"; System.out.println(c == d); System.out.println(c == "Panther"); System.out.println(c == "Panter"); // liefert true // liefert true // liefert false

Vergleiche mit equals() und compareTo() Die Methode equals() vergleicht String-Referenzen und liefert true zurck, wenn diese identisch sind (d.h., gleiche Zeichenfolgen enthalten). Die Methode compareTo() fhrt einen lexikographischen Vergleich durch und gibt fr kleiner den Wert -1, bei Gleichheit 0 und bei grer +1 zurck:
// Ausgabe: ungleich und kleiner String a = Treppe; String b = Trupp; if(a.equals(b) == false) System.out.println(ungleich); if(a.compareTo(b) < 0 ) System.out.println(kleiner);

Weitere ntzliche Vergleichsmethoden sind startsWith() und endsWith(), die prfen, ob ein String mit einer gegebenen Zeichenkette beginnt oder endet, z. B.:
String name = (Daten.txt); if(name.endsWith(.txt) == true) System.out.println(Textdatei);

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Operatoren Seite 151

Beliebige Typen in Strings umwandeln Die Klasse String untersttzt die Umwandlung von Werten elementarer Datentypen in Strings mithilfe der berladenen, statischen valueOf()Methode:
int zahl = 3200; String str = String.valueOf(zahl);

Weiterhin erben alle Klassen von der obersten Basisklasse Object (siehe 4.5.2) eine Methode toString(), die jede Klasse so berschreiben kann, dass sie eine passende String-Prsentation des Objekts zurckliefert. Java nutzt diese Methode fr die Konkatenation und Ausgabe von Nicht-StringObjekten: Wann immer der Konkatenationsoperator auf einen String-Operanden und einem Nicht-String-Operanden angewendet wird, ruft der Compiler die toString()-Methode des Operanden auf, die ihm eine StringDarstellung des Operanden zurckliefert. Handelt es sich bei dem Nicht-String-Operanden um einen elementaren Datentyp, erzeugt der Compiler ein Objekt der zugehrigen WrapperKlasse und ruft dessen toString()-Methode auf. hnlich arbeiten die Methoden print() und println(), die fr Strings, Referenztypen und alle elementaren Datentypen berladen sind, und das jeweilige bergebene Argument mittels toString() in einen String umwandeln.

6.3.5 Wichtige Methoden der Klasse String


String(String s) String(byte[] s, String charset) String(char[] c) String(StringBuffer s) String(StringBuilder s) Konstruktor zum Erzeugen eines Strings aus s (bzw. c); beim Erzeugen aus einem byte-Array kann optional noch die Zeichenkodierung angegeben werden. char charAt(int pos) Liefert das Zeichen an Position pos.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Operatoren Seite 152

int compareTo(String s) int compareToIgnoreCase(String s) Lexikographischer Vergleich mit s mit oder ohne Bercksichtigung von Klein-/Groschreibung. Rckgabe -1 (kleiner), 0 (gleich), +1 (grer). String concat(String s) Konkateniert den Inhalt der aufrufenden Instanz mit s und liefert ein neues String-Objekt zurck. boolean contains(CharSequence s) Liefert true, wenn der String s in der aufrufenden Instanz als Teilstring enthalten ist. boolean endsWith(String s) Liefert true, wenn die aufrufende Instanz mit der Zeichenkette s endet. boolean equals(Object s) Liefert true, wenn die aufrufende Instanz und s die gleiche Zeichenkette bezeichnen. indexOf(char c) indexOf(char c, int pos) indexOf(String s) indexOf(String s, int pos) lastIndexOf(char c) lastIndexOf(char c, int pos) lastIndexOf(String s) lastIndexOf(String s, int pos) Liefert die erste bzw. letzte Position des Zeichens c (bzw. Strings s) oder -1, wenn nicht vorhanden. Wird ein Index pos mit bergeben, wird ab der spezifizierten Position gesucht. int length() Die Anzahl der Zeichen (nicht Bytes!) des Strings. boolean matches(String reg) Liefert true, wenn die aufrufende Instanz durch den regulren Ausdruck reg beschrieben wird.

int int int int int int int int

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Operatoren Seite 153

String replace(char alt, char neu) String replace(CharSequence alt, CharSequence neu) Ersetzt alle Zeichen (bzw. Strings) alt durch das Zeichen (bzw. den String) neu. String replaceAll(String reg, String neu) Ersetzt alle Zeichenfolgen im aktuellen String, die dem regulren Ausdruck reg entsprechen, durch den String neu. boolean startsWith(String s) Liefert true, wenn die aufrufende Instanz mit der Zeichenkette s beginnt. String substring(int start, int ende) Liefert den Teilstring von Position start bis ende-1. String toLowerCase() String toUpperCase() Erzeugt einen neuen String, bei dem alle Buchstaben in Kleinbuchstaben bzw. Grobuchstaben konvertiert worden sind. String trim() Liefert einen neuen String, bei dem alle Leerzeichen am Anfang und Ende des Strings entfernt worden sind. String valueOf(xxx c) Erzeugt eine String-Darstellung aus einer Variablen vom elementaren Datentyp xxx (boolean, char, int, short, long, float, double).

6.4

bung 3: Berechnungen durchfhren

Aufgabenstellung Schreiben Sie ein Programm BMI, das Name und Alter des Anwenders abfragt und beides anschlieend wieder ausgibt. Die Formel zur Berechnung des BMI lautet:
bmi = gewicht ----------------(groesse/100)2

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Operatoren Seite 154

Versuchen Sie die Aufgabe zuerst selbststndig zu lsen. Wenn Sie nicht weiter wissen und Hilfe bentigen, lesen Sie die Lsung. Lesen Sie den Lsungsabschnitt aber auch dann durch, wenn Sie die bung selbststndig bearbeiten knnen. Wir haben auf dem beschriebenen Lsungsweg absichtlich ein paar lehrreiche Fehler und Hinweise eingebaut. Lsung 1. 2. 3. Legen Sie eine neue Quelltextdatei BMI.java an. Tippen Sie das Java-Anwendungsgerst ein. Speichern und kompilieren Sie. Fhren Sie das Programm zum Test einmal aus.

Bis hierhin sollte es keine Schwierigkeiten geben. Oder etwa doch? Dann lesen Sie vielleicht noch einmal bung 2. 4. Lesen Sie Krpergre (in cm) und Gewicht (in kg) des Anwenders ein.

import java.util.Scanner; public class BMI { public static void main(String[] args) { int groesse; int gewicht; Scanner sc = new Scanner(System.in); // Gre einlesen System.out.print(" Ihre Koerpergroesse in cm : "); groesse = sc.nextInt(); // Gewicht einlesen System.out.print(" Ihr Gewicht in kg gewicht = sc.nextInt(); } : ");

Der obige Code liest die Angaben zu Gre und Gewicht in int-Werte ein. Der Anwender darf also nur ganze Zahlen als Werte eingeben. Vielleicht sollten wir ihn darauf hinweisen?

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Operatoren Seite 155

5.

Erffnen Sie das Programm mit einem Begrungstext und Infos zur Verwendung.

import java.util.Scanner; public class BMI { public static void main(String[] args) { int groesse; int gewicht; Scanner sc = new Scanner(System.in); System.out.println(); System.out.println(" *** Berechnung des Body Mass Index ***"); System.out.println(" (erlaubt nur ganzzahlige Eingaben) "); System.out.println("\n"); // Gre einlesen System.out.print(" Ihre Koerpergroesse in cm : "); groesse = sc.nextInt(); // Gewicht einlesen System.out.print(" Ihr Gewicht in kg gewicht = sc.nextInt(); } : ");

6.

Berechnen Sie den Body Mass Index und geben Sie ihn aus

import java.util.Scanner; public class BMI { public static void main(String[] args) { int groesse; int gewicht; double bmi; Scanner sc = new Scanner(System.in); System.out.println(); System.out.println(" *** Berechnung des Body Mass Index ***"); System.out.println(" (erlaubt nur ganzzahlige Eingaben)

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Operatoren Seite 156

"); System.out.println("\n"); // Gre einlesen System.out.print(" Ihre Koerpergroesse in cm : "); groesse = sc.nextInt(); // Gewicht einlesen System.out.print(" Ihr Gewicht in kg gewicht = sc.nextInt(); bmi = gewicht / Math.pow( groesse/100, 2); System.out.println(); System.out.println(" Ihr BMI betraegt: " + bmi); } : ");

Beachten Sie, dass wir fr den BMI-Wert eine double-Variable definiert haben, da der BMI selten ein ganzzahliger Wert ist. 7. Kompilieren Sie das Programm und fhren Sie es aus.

Sehr schn, funktioniert ja alles prchtig! Obwohl ..., ist es nicht merkwrdig, dass der Body Mass Index den gleichen Wert hat wie das Gewicht? 8. Prfen Sie, ob die Formel richtig berechnet wird.
// ... System.out.print(" Ihr Gewicht in kg gewicht = sc.nextInt();

Berechnen Sie dazu die einzelnen Zwischenwerte und geben Sie diese aus.
: ");

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Operatoren Seite 157

double tmp = 0.0; tmp = groesse; System.out.println(tmp); tmp = groesse/100; System.out.println(tmp); tmp = Math.pow( groesse/100, 2); System.out.println(tmp); bmi = gewicht / Math.pow( groesse/100, 2); // ...

Sieh an! Die Gre wird offensichtlich korrekt eingelesen, doch nach der Division durch 100 ist das Ergebnis nicht 1,8 sondern 1,0. Kommt Ihnen ein Verdacht? Nein, dann lesen Sie noch einmal den Abschnitt zu den arithmetischen Operatoren. Vielleicht kommen Sie dann drauf. Obwohl ich zugeben muss, dass der hier eingebaute Fehler sehr tckisch und selbst fr professionelle Programmierer unter Umstnden nur schwer zu entdecken ist. Das Problem ist, dass die Variable groesse und das Literal 100, durch das wir teilen, beide vom Typ int sind. Der /-Operator fhrt folglich eine Ganzzahlendivision durch, d.h. er verwirft den Nachkommaanteil. Da nutzt es auch nichts, dass der Compiler das Ergebnis (1) fr die Abspeicherung in der double-Variablen tmp danach pflichtgetreu in einen double-Wert (1.0) umwandelt. 9. Wir lsen dieses Problem, indem wir das Literal in ein Literal vom Typ double umwandeln:

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Operatoren Seite 158

import java.util.Scanner; public class BMI { public static void main(String[] args) { int groesse; int gewicht; double bmi; Scanner sc = new Scanner(System.in); System.out.println(); System.out.println(" *** Berechnung des Body Mass Index ***"); System.out.println(" (erlaubt nur ganzzahlige Eingaben) "); System.out.println("\n"); // Gre einlesen System.out.print(" Ihre Koerpergroesse in cm: "); groesse = sc.nextInt(); // Gewicht einlesen System.out.print(" Ihr Gewicht in kg gewicht = sc.nextInt(); : ");

bmi = gewicht / Math.pow( groesse/100.0, 2); System.out.println(); System.out.println(" Ihr BMI betraegt: " + bmi); } }

Abbildung 6.1: Jetzt ist alles korrekt

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Kontrollstrukturen Seite 159

7 Praxisteil: Kontrollstrukturen
Halten wir einen Moment inne und rekapitulieren wir, wie unsere Programmquelltexte organisiert sind und wie diese vom Rechner ausgefhrt werden. Java-Programme bestehen ein wenig berspitzt formuliert nicht aus Anweisungen, sondern allein aus Klassendefinitionen. In den Klassen sind Felder, Methoden und Konstruktoren definiert. In den Methoden- und Konstruktordefinitionen schlielich stehen Anweisungen. Die Anweisungen einer Methode werden beim Aufruf der Methode in der Reihenfolge ausgefhrt, in der sie von oben nach unten in der Methode stehen. Als erste Methode eines Programms wird immer die main()-Methode ausgefhrt. Wird in der main()-Methode eine andere Methode aufgerufen (beispielsweise System.out.println() oder Math.sin()), verzweigt die Programmausfhrung in die aufgerufene Methode, fhrt deren Anweisungen aus und kehrt dann wieder in die aufrufende Methode an die Stelle hinter den Aufruf zurck. Durch die Verteilung des Codes auf mehrere Methoden (seien diese nun selbst definiert wie main() oder vordefiniert wie System.out.println()) ndert sich aber nichts daran, dass die Anweisungen grundstzlich nacheinander, stur von oben nach unten ausgefhrt werden. Der Aufruf einer Methode bedeutet lediglich, dass ein paar Anweisungen dazwischen geschoben werden. Bleiben wir nun innerhalb des Anweisungsblocks einer Methode. Nicht immer ist es wnschenswert, dass die Anweisungen stur eine nach der anderen ausgefhrt werden. Manchmal wrde man sich wnschen, das Programm knnte, beispielsweise in Abhngigkeit vom Wert einer bestimmten Variablen, unterschiedliche Anweisungen ausfhren. Oder man grmt sich und flucht, weil das Aufsetzen des Programmcodes zur Berechnung der ersten tausend Quadratzahlen so umstndlich dauert:
System.out.println(" 1 * 1 = " + 1*1); System.out.println(" 2 * 2 = " + 2*2); System.out.println(" 3 * 3 = " + 3*3); . . .

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Kontrollstrukturen Seite 160

Zur Lsung solcher Aufgaben und zur Steuerung der Programmausfhrung innerhalb einer Methode gibt es in Java verschiedene Formen von Verzweigungen und Schleifen.

7.1

Verzweigungen

Die einfachste Form der Verzweigung ist die if-Anweisung.

7.1.1 Die if-Konstruktion


Die Syntax der if-Konstruktion sieht wie folgt aus:
... if (Bedingung) Anweisung ...

Eine solche if-Konstruktion bedeutet: Wenn (if) die Bedingung erfllt ist (true liefert), dann fhre die Anweisung aus. Ist die Bedingung nicht erfllt, fhre die Anweisung nicht aus. Mit der if-Konstruktion kann man also kontrollieren, ob eine Anweisung ausgefhrt werden soll oder nicht. Nehmen wir an, Sie schreiben an einem Programm, das den Wert von Bestellungen berechnet. Das Programm addiert die Einzelbetrge der bestellten Posten und addiert diese zum Gesamtbetrag. Falls dieser ber 250 Euro liegt, werden 10 % Rabatt gewhrt.
double gesamtbetrag; ... // Hier wird gesamtbetrag irgendwie berechnet if (gesamtbetrag >= 250) gesamtbetrag *= 0.9; System.out.println("Endbetrag in Euro: " + gesamtbetrag);

Beachten Sie, dass die Zeile


gesamtbetrag *= 0.9;

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Kontrollstrukturen Seite 161

nur dann ausgefhrt wird, wenn der Wert von gesamtbetrag grer oder gleich 250 ist. Ist der Wert kleiner, wird die Zeile nicht ausgefhrt. Unabhngig davon, ob die Zeile ausgefhrt wird oder nicht, fhrt das Programm danach ganz normal mit der nchsten Anweisung fort (im Beispiel mit der Ausgabe via System.out.println() ). Bedingungen von if-Konstruktionen sind Ausdrcke, die wahr (true) oder falsch (false) ergeben. Solche Ausdrcke kann man mithilfe der Vergleichsoperatoren und der logischen Operatoren aufsetzen (siehe Tutorium 6.1.5). Wenn Sie Strings vergleichen wollen, knnen Sie die Operatoren == und != oder die Methoden equals() und compareTo() verwenden.
Icon HINWEIS

Die if-Bedingung kontrolliert immer nur die direkt nachfolgende Anweisung. Hufig mchte man aber mehrere zusammenhngende Anweisungen durch eine if-Bedingung kontrollieren. Im obigen Fall wre es beispielsweise ganz angebracht, wenn das Programm nicht nur den Rabatt einrumt, sondern auch einen entsprechenden Hinweis ausgibt:
System.out.println("Es werden 10% Rabatt eingerumt"); gesamtbetrag *= 0.9;

Selbstverstndlich ist auch dies mglich, und man muss dazu nicht einmal zwei aufeinander folgende if-Konstruktionen aufsetzen. Stattdessen ersetzt man die einzelne Anweisung unter der if-Bedingung durch einen in geschweiften Klammern gesetzten Anweisungsblock. Die if-Bedingung kontrolliert dann nicht die direkt nachfolgende Anweisung, sondern den gesamten nachfolgenden Anweisungsblock.
double gesamtbetrag; ... // Hier wird gesamtbetrag irgendwie berechnet if (gesamtbetrag >= 250) { System.out.println("Es werden 10% Rabatt eingerumt"); gesamtbetrag *= 0.9; } System.out.println("Endbetrag in Euro: " + gesamtbetrag);

Die if-Bedingung kontrolliert immer nur die direkt nachfolgende Anweisung oder den nachfolgenden Anweisungsblock. Sie selbst ist keine

Icon ACHTUNG

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Kontrollstrukturen Seite 162

Anweisung und wird daher nicht mit einem Semikolon abgeschlossen. Falls Sie doch einmal ein Semikolon hinter eine if-Bedingung setzen,
if (gesamtbetrag >= 250); { System.out.println("Es werden 10% Rabatt eingerumt"); gesamtbetrag *= 0.9; }

interpretiert der Compiler das Semikolon als eine so genannte leere Anweisung und kontrolliert diese durch die if-Bedingung, whrend der hinter der leeren Anweisung folgende Anweisungsblock mit der Ausgabe und der Rabattgewhrung immer (also unbedingt) ausgefhrt wird.

7.1.2 Die if-else-Konstruktion


Mit der if-Bedingung kann man nicht nur die Ausfhrung einer einzelnen Anweisung oder eines Anweisungsblocks kontrollieren, man kann auch alternativ einen Anweisungsblock A oder einen Anweisungsblock B ausfhren lassen. Dazu erweitert man die if-Konstruktion um eine elseKlausel. Syntax der if-else-Konstruktion
if (Bedingung) { Anweisung(en); } else { Anweisung(en); }

Bei Ausfhrung des Programms wird als Erstes die Bedingung berprft. Ist diese erfllt (ergibt der Ausdruck in der Bedingung true), wird der direkt folgende Anweisungsblock ausgefhrt. Ist dieser abgearbeitet, wird das Programm direkt mit der nchsten Anweisung unter dem else-Block fortgesetzt. Der else-Block selbst wird bersprungen. Ist die Bedingung nicht erfllt (false), wird der Anweisungsblock direkt unter der ifBedingung bersprungen und das Programm wird mit dem else-Block fortgesetzt.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Kontrollstrukturen Seite 163

Verschachtelung Selbstverstndlich ist es auch mglich, if-Verzweigungen zu verschachteln, d.h., im if- oder else-Teil eine weitere if-Verzweigungen einzubauen. Eine spezielle Form der Verschachtelung sind die else-if-Ketten, bei denen sich an jeden else-Teil eine weitere if-else-Verzweigung anschliet.
if (Bedingung1) { Code1; } else if (Bedingung2) { Code2; } else if (Bedingung3) { Code3; } else { Code4; }

7.1.3 Die switch-Konstruktion


Die Verschachtelung von if-else-Konstrukten bietet sich dann an, wenn grere Wertebereiche oder hierarchische Bedingungen mit verschiedenen Variablen zu prfen sind. Wenn man hingegen ausgehend von einem Wert mehrere Verzweigungsmglichkeiten einrichten mchte, ist die switchKonstruktion meist die klgere Wahl. Allgemeine Syntax
switch(Ausdruck) { case Konstante1:

Anweisungen; break; case Konstante2: Anweisungen; break; case Konstante3: Anweisungen; break; case Konstante4: Anweisungen; break; default: Anweisung; }

Als Ausdruck kann man beispielsweise eine Variable eines Ganzzahltyps (int, short, etc.), ein Zeichen (Typ char) oder eine Variable eines Aufzhlungstyps angeben. Bei der Programmausfhrung wird der Wert

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Kontrollstrukturen Seite 164

dieser Variablen mit den innerhalb der switch-Konstruktion stehenden case-Konstanten verglichen. Stimmt der Wert der Variablen mit einer case-Konstanten berein, werden die zugehrigen Anweisungen ausgefhrt. Die abschlieende break-Anweisung sorgt dafr, dass das Programm danach mit der nchsten Anweisung unter der switch-Verzweigung fortgesetzt wird. Zu dem zu default gehrenden Anweisungsblock wird verzweigt, wenn die berprfung des switch-Ausdrucks mit den case-Marken keine bereinstimmung ergibt. Die folgende switch-Konstruktion demonstriert, wie eine Note von der Reprsentation als Zahlenwert zwischen 1 und 6 in einen String umgewandelt werden kann:
int note; // ... note wird ein Wert zugewiesen String strNote; switch(note) { case 1: strNote break; case 2: strNote break; case 3: strNote break; case 4: strNote break; case 5: strNote break; case 6: strNote break; default: strNote }

= "sehr gut"; = "gut"; = "befriedigend"; = "ausreichend"; = "mangelhaft"; = "ungenuegend"; = "ungueltige Note";

Die case-Marken sind wie Einsprungstellen in den Code der switchVerzweigung. Und die break-Anweisung sind die Austrittsstellen. Wenn Sie die Anweisungen zu einer case-Marke nicht mit einer breakAnweisung beenden, wird das Programm mit den Anweisungen zur nchsten case-Marke fortgesetzt.

Icon ACHTUNG

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Kontrollstrukturen Seite 165

7.2

bung 4: Benutzereingaben prfen

Wenn Sie Eingaben vom Anwender anfordern, mssen Sie immer damit rechnen, dass diese Eingaben nicht den geforderten Bedingungen entsprechen. Mithilfe der if-else-Konstruktion knnen Sie falsche Benutzereingaben abfangen und mit Fehlermeldungen quittieren. Aufgabenstellung Schreiben Sie ein Programm Wurzel, das den Anwender auffordert, eine positive Zahl einzugeben, und von dieser dann die Wurzel berechnet und ausgibt. Gibt der Anwender allerdings eine negative Zahl ein, soll die Wurzel nicht berechnet, sondern ein Fehlermeldung ausgeben werden. Versuchen Sie die Aufgabe zuerst selbststndig zu lsen. Wenn Sie nicht weiter wissen und Hilfe bentigen, lesen Sie die Lsung. Lesen Sie den Lsungsabschnitt aber auch dann durch, wenn Sie die bung selbststndig bearbeiten knnen. Wir haben auf dem beschriebenen Lsungsweg absichtlich ein paar lehrreiche Hinweise eingebaut. Lsung 1. 2. 3. Legen Sie eine neue Quelltextdatei Wurzel.java an. Tippen Sie das Java-Anwendungsgerst ein. Speichern und kompilieren Sie. Fhren Sie das Programm zum Test einmal aus.

Bis hierhin sollte es keine Schwierigkeiten geben. Oder etwa doch? Dann lesen Sie vielleicht noch einmal bung 2. 4. Lesen Sie ber die Konsole eine Zahl ein, berechnen Sie deren Wurzel mithilfe der Methode Math.sqrt() und geben Sie das Ergebnis aus.

import java.util.Scanner; public class Wurzel { public static void main(String[] args) { double zahl; Scanner sc = new Scanner(System.in);

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Kontrollstrukturen Seite 166

System.out.println(); System.out.println(" *** Wurzel-Berechnung *** \n"); // Zahl einlesen System.out.print(" Geben Sie eine Zahl ein: "); zahl = sc.nextDouble(); // Wurzel berechnen double wurzel; wurzel = Math.sqrt(zahl); System.out.println(" Wurzel von " + zahl + " gleich " + wurzel); } }

5.

Kompilieren Sie das Programm und fhren Sie es aus. Testen Sie es sowohl mit positiven als auch negativen Zahlen als Eingaben.

Fr negative Eingaben erscheint stets derselbe Ergebniswert: NaN. Der Grund dafr ist, dass die Methode Math.sqrt() als Ergebnis den Wert Double.NaN zurckliefert (NaN steht fr Not a Number). Wenn Sie diesen Wert mit System.out.println() ausgeben, erscheint in der Ausgabe der String NaN. 6. Setzen Sie jetzt eine if-else-Anweisung auf, die fr positive Eingaben die Wurzel berechnet und ansonsten eine Fehlermeldung ausgibt.

import java.util.Scanner; public class Wurzel {

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Kontrollstrukturen Seite 167

public static void main(String[] args) { double zahl; Scanner sc = new Scanner(System.in); System.out.println(); System.out.println(" *** Wurzel-Berechnung *** \n"); // Zahl einlesen System.out.print(" Geben Sie eine Zahl ein: "); zahl = sc.nextDouble(); // Wurzel berechnen if (zahl >= 0.0) { double wurzel; wurzel = Math.sqrt(zahl); System.out.println(" Wurzel " gleich } else { System.out.println(" Wurzel + "nicht } } }

von " + zahl + " + wurzel);

von negativen Zahlen kann " berechnet werden \n");

7.

Kompilieren Sie das Programm und fhren Sie es aus.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Kontrollstrukturen Seite 168

7.3

Schleifen

Schleifen dienen dazu, eine Anweisung oder einen Anweisungsblock mehrfach hintereinander auszufhren. Sie werden immer dann eingesetzt, wenn eine Aufgabe an einer Stelle wiederholt zu erledigen ist. Nehmen wir an, Sie wollten die ersten 100 Quadratzahlen berechnen und ausgeben. Dazu knnten Sie hundert System.out.println()Ausgaben aufsetzen:
System.out.println("Das Quadrat von 1 ist 1"); System.out.println("Das Quadrat von 2 ist 4"); System.out.println("Das Quadrat von 3 ist 9"); //...

Wenn man aber schon ein Programm schreibt, dann sollte man die Rechenarbeit auch von dem Programm erledigen lassen:
int zahl = 1; System.out.println("Das Quadrat von " + zahl + " ist: " + (zahl*zahl)); ++zahl; System.out.println("Das Quadrat von " + zahl + " ist: " + (zahl*zahl)); ++zahl; ...

Jetzt brauchen Sie die Quadratzahlen nicht mehr selbst auszurechnen, Sie mssen nur noch die beiden Zeilen mit der Ausgabe und der Inkrementierung der Variablen zahl hundertmal kopieren.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Kontrollstrukturen Seite 169

Schn sieht ihr Programm dann allerdings nicht aus. Und sollten Sie nach dem Kopieren feststellen, dass sich in die System.out.println()Ausgabe ein Fehler eingeschlichen hat (beispielsweise ein vergessenes Anfhrungszeichen), so mssen Sie den Fehler hundertmal korrigieren. Eleganter und sinnvoller ist in so einem Fall die Implementierung einer Schleife. Typisch fr Schleifen ist die Einrichtung einer Schleifenvariablen, ber die man kontrolliert, wie oft die Schleife ausgefhrt wird. Dazu wird die Schleifenvariable vor Eintritt in die Schleife auf einen Anfangswert gesetzt, in der Schleife inkrementiert (oder in irgendeiner anderen Weise verndert) und vor jedem neuen Schleifendurchgang (auch Iteration genannt) getestet. Um eine konkretere Vorstellung davon zu bekommen, wie das in der Praxis aussieht, schauen wir uns gleich ein Beispiel an.

7.3.1 Die while-Schleife


Die allgemeine Syntax der while-Schleife sieht wie folgt aus:
Initialisierung; while (Bedingung) { Anweisung(en) inklusive Vernderung; }

Initialisierung bedeutet, dass die Schleifenvariable auf einen Anfangswert gesetzt wird. Die Schleifenvariable geht dann in die Bedingung ein, meist wird sie mit irgendeinem Grenzwert verglichen. (Bedingungen werden mithilfe von vergleichenden und logischen Operatoren aufgesetzt, siehe Tutorium 6.1.5). Solange diese Bedingung erfllt ist, wird die Schleife ausgefhrt. Direkt unter dem Schleifenkopf mit der Schleifenbedingung folgt dann der Anweisungsblock, der bei jedem Durchlaufen der Schleife (Iteration) ausgefhrt wird. Innerhalb des Anweisungsblocks wird auch der Wert der Schleifenvariablen verndert in einer Weise, die sicherstellt, dass die Schleifenbedingung irgendwann nicht mehr erfllt ist. In der Praxis sieht das dann in etwa wie folgt aus:
int loop = 1; while (loop <= 5) { System.out.println("Wert der Schleifenvariable: " + loop);

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Kontrollstrukturen Seite 170

++loop; }

Die Schleifenvariable habe ich in diesem Beispiel sinnigerweise loop (englisch fr Schleife) genannt. Die meisten Programmierer verwenden aber noch krzere Bezeichner wie i, j oder n.

Icon HINWEIS

Wie wird dieser Code ausgefhrt? Vor Eintritt in die Schleife wird die Schleifenvariable loop auf 1 gesetzt. Danach beginnt die Schleife, die aus dem Schlsselwort while, der Schleifenbedingung und dem Schleifenkrper (dem nachfolgenden Anweisungsblock besteht. In der Schleifenbedingung wird geprft, ob der Wert von loop kleiner oder gleich 5 ist. Solange die Schleifenbedingung erfllt ist, wird die Schleife ausgefhrt. Beim Eintritt in die Schleife ist loop gleich 1. Die Bedingung ist also erfllt und der Schleifenkrper wird ausgefhrt. Damit die Schleife etwas halbwegs Sinnvolles tut, geben wir im Schleifenkrper zuerst mithilfe von WriteLine() den Wert der Schleifenvariablen aus. Danach wird der Wert der Schleifenvariablen inkrementiert (++loop;). Jetzt ist der aktuelle Schleifendurchgang beendet, nicht jedoch die Schleife! Die Programmausfhrung springt jetzt nmlich zurck zum Anfang der Schleife und zur Schleifenbedingung. Wieder wird berprft, ob der Wert der Variablen loop (der jetzt gleich 2 ist) kleiner gleich 5 ist. Da dies der Fall ist, wird der Schleifenkrper ein zweites Mal ausgefhrt. Insgesamt wird der Schleifenkrper fnfmal hintereinander ausgefhrt. Beim fnften Schleifendurchgang wird der Wert von loop von 5 auf 6 hoch gesetzt. Nach dem fnften Schleifendurchgang wird noch einmal die Schleifenbedingung getestet, doch da loop jetzt grer als 5 ist, ist die Bedingung nicht mehr erfllt, das heit, der Schleifenkrper wird nicht mehr ausgefhrt, die Programmausfhrung springt hinter die Schleife und wird mit der nchsten Anweisung nach der Schleife fortgesetzt. Auf dem Bildschirm bleibt die Ausgabe der Schleife zurck:
Wert der Schleifenvariable: 1 Wert der Schleifenvariable: 2 Wert der Schleifenvariable: 3

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Kontrollstrukturen Seite 171

Wert der Schleifenvariable: 4 Wert der Schleifenvariable: 5

Wie der Wert der Schleifenvariablen im Schleifenkrper verndert wird, ist grundstzlich egal. Man kann die Schleifenvariable inkrementieren, dekrementieren, in Zweierschritten hochzhlen, neue Werte vom Anwender einlesen und so weiter. Wichtig ist nur, dass der Wert so verndert wird, dass irgendwann die Schleifenbedingung nicht mehr erfllt und die Schleife ganz verlassen wird. Ansonsten hat man eine Endlosschleife erzeugt, die zum Absturz des Programms fhrt. In der Windows-Konsole knnen Sie solche Programme durch Drcken der Tastenkombination (Strg)+(C) beenden.

Icon ACHTUNG

Jetzt sind wir auch in der Lage, das Programm zur Berechnung der ersten hundert Quadratzahlen effizienter zu formulieren:
class Demo { public static void main(String[] args) { int loop = 1; while ( loop <= 100 ) { System.out.println("Das Quadrat von " + loop + " ist: " + (loop*loop)); ++loop; } } }

Die Konstruktion dieser Schleife drfte fr Sie leicht zu verstehen sein. Etwas rgerlich ist allerdings, dass die ausgegebenen Zeilen mit den berechneten Quadratzahlen am Anwender nur so vorbeirauschen. Sie knnen dem Abhilfe schaffen, indem Sie das Programm nach jedem zehnten Schleifendurchlauf anhalten und warten, bis der Anwender die (Enter)-Taste drckt. Fgen Sie dazu unter der System.out.println()-Ausgabe eine ifBedingung ein, die feststellt, ob der aktuelle Schleifendurchlauf ein Vielfaches von 10 ist. Wenn ja, warten Sie auf das Drcken der (Enter)Taste:
if (loop % 10 == 0) sc.nextLine(); // wobei sc ein Scanner-Objekt ist
Icon HINWEIS

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Kontrollstrukturen Seite 172

7.3.2 Die do-while-Schleife


Neben der while-Schleife existiert das Konstrukt der do-while-Schleife. Der wichtigste Unterschied zur while-Schleife besteht darin, dass die Schleifenbedingung nicht am Anfang, sondern am Ende der Schleife berprft wird. Deshalb fhrt die do-while-Schleife mindestens eine Iteration aus.
Initialisierung; do { Anweisung(en) inklusive Vernderung; } while (Bedingung);

Beachten Sie das Semikolon hinter der Bedingung. Bei der normalen while-Schleife darf kein Semikolon auf die Bedingung folgen.

Icon ACHTUNG

7.3.3 Die for-Schleife


Als Alternative zur while- oder do-while-Schleife bieten die meisten Programmiersprachen noch eine weitere Schleifenkonstruktion an: die forSchleife. Diese Konstruktion hat den Vorteil, dass Initialisierung, berprfung und Inkrementierung der Schleifenvariablen bersichtlich im Kopf der Schleife zusammengefasst sind. Gerade Anfnger sollten daher grundstzlich die for-Schleife vorziehen. Aber auch professionelle Programmierer schtzen die for-Schleife, vor allem wenn von vornherein feststeht, wie oft die Schleife ausgefhrt werden soll.
for (Initialisierung; Bedingung; Vernderung) { Anweisung(en); }

Unsere while-Schleife zur Berechnung der ersten hundert Quadratzahlen she als for-Schleife beispielsweise wie folgt aus:

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Kontrollstrukturen Seite 173

class Demo { public static void main(String[] args) { for (int loop=1; loop <= 100; ++loop) { System.out.println("Das Quadrat von " + loop + " ist: " + (loop*loop)); ++loop; } } }

Auf zwei Besonderheiten der for-Schleife mchte ich Sie noch aufmerksam machen: Sie knnen die Schleifenvariable nicht nur im Schleifenkopf initialisieren, Sie knnen sie auch im Schleifenkopf definieren. Die Variable ist dann nur innerhalb der Schleife gltig. In den umliegenden Anweisungen existiert sie nicht. Die letzte Anweisung im Schleifenkopf, die Vernderung, wird nicht mit einem Semikolon abgeschlossen.

Die for-Schleife fr Arrays und Collections Ab Java 5 gibt es eine weitere Variante der for-Schleife: die sogenannte for-each-Schleife. Mit ihr knnen Sie alle Elemente eines Arrays (siehe 5.3.5) oder einer Collection (siehe

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Kontrollstrukturen Seite 174

Exkurs: Collections) durchlaufen:


// gegeben sei ein Array 'zahlen' mit 10 int-Elementen. for(int elem : zahlen) { System.out.println(elem); }

Beachten Sie, dass elem hier automatisch die Elemente in zahlen durchluft.

Icon ACHTUNG

7.3.4 Abbruchbefehle
Die folgenden Schlsselwrter werden verwendet, um Anweisungsblcke zu verlassen.
Abbruchbefehl continue Beschreibung Mit der continue-Anweisung wird zum Anfang einer Schleife zurckgesprungen. Die Ausfhrung aller nach continue stehenden Anweisungen findet also nicht statt. Mit der break-Anweisung wird im Gegensatz zu continue die gesamte Schleife und nicht nur der aktuelle Schleifendurchgang abgebrochen. Mit dem Schlsselwort return kann die Ausfhrung einer Methode unterbrochen und sofort an der Stelle fortgesetzt werden, an der die Methode aufgerufen wurde. Das Schlsselwort return ist damit auch geeignet, um Schleifen zu verlassen.

break

return

7.4

bung 5: Daten filtern

Aufgabenstellung Schreiben Sie ein Programm Filter, das die Zahlen in einem int-Array durchluft und die ungeraden Zahlen herausfiltert. Benutzen Sie als Ausgangspunkt den folgenden Code:

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Kontrollstrukturen Seite 175

import java.util.*; class Filter { public static void main(String[] args) { // Array mit Zufallszahlen erzeugen int[] werte = new int[100]; Random zufallsgenerator = new Random(); for(int i = 0; i < 100; i++) { werte[i] = zufallsgenerator.nextInt(100); } } }

Der Code legt ein Array von 100 int-Werten an (siehe 5.3.5). In der nachgeschalteten for-Schleife werden den Array-Elementen dann zufllige Zahlen aus dem Bereich [0;100) zugewiesen (siehe auch den Exkurs Zufallszahlen). Versuchen Sie, die Aufgabe zuerst selbststndig zu lsen. Wenn Sie nicht weiter wissen und Hilfe bentigen, lesen Sie die Lsung. Ein kleiner Tipp: Ob eine Zahl ungerade ist, knnen Sie mit dem Modulo-Operator % feststellen. Lsung 1. 2. 3. Legen Sie eine neue Quelltextdatei Filter.java an. Tippen Sie das oben abgedruckte Grundgerst ein. Speichern und kompilieren Sie. Fhren Sie das Programm zum Test einmal aus.

Bis hierhin sollte es keine Schwierigkeiten geben. 4. Setzen Sie eine for-each-Schleife auf, die alle Zahlen im Array ausgibt.

import java.util.*; class Filter

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Kontrollstrukturen Seite 176

{ public static void main(String[] args) { // Array mit Zufallszahlen erzeugen int[] werte = new int[100]; Random zufallsgenerator = new Random(); for(int i = 0; i < 100; i++) { werte[i] = zufallsgenerator.nextInt(100); } for (int i : werte) { System.out.print(i + " "); } } }

5.

Kontrollieren Sie die Ausgabe mit einer if-Bedingung, die nur dann true ergibt, wenn das aktuelle Element eine ungerade Zahl enthlt.

import java.util.*; class Filter { public static void main(String[] args) { // Array mit Zufallszahlen erzeugen int[] werte = new int[100]; Random zufallsgenerator = new Random(); for(int i = 0; i < 100; i++) { werte[i] = zufallsgenerator.nextInt(100); } for (int i : werte) { if (i % 2 == 1) System.out.print(i + " "); } } }

Wie funktioniert diese if-Bedingung?

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Kontrollstrukturen Seite 177

Angenommen i enthlt eine gerade Zahl. Dann ergibt die Modulo-Division durch 2 einen Wert mit Rest 0. Der Wert interessiert nicht, der Rest wird als Ergebnis der Modulo-Operation zurckgeliefert. Die Bedingung lautet dann 0 == 1 und ergibt false. Angenommen i enthlt eine ungerade Zahl. Dann ergibt die ModuloDivision durch 2 einen Wert mit Rest 1. Der Wert interessiert nicht, der Rest wird als Ergebnis der Modulo-Operation zurckgeliefert. Die Bedingung lautet dann 1 == 1 und ergibt true. 6. Kompilieren Sie das Programm und fhren Sie es aus.

Abbildung 7.1: Keine geraden Zahlen in der Ausgabe. Der Filter scheint zu funktionieren.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Klassen Seite 178

8 Praxisteil: Klassen
Herzlichen Glckwunsch! Sie beherrschen nun die Grundlagen der Programmierung im Allgemeinen wie auch der Programmierung mit Java im Besonderen. Lehnen Sie sich fr einen Moment zurck und genieen Sie das Gefhl, nicht mehr nur Anfnger, sondern mittlerweile ein erfahrener Geselle zu sein. Doch wie Hermann Hesse bereits festgestellt hat, zhlt nicht das, was man in der Vergangenheit geleistet hat, sondern nur das, was man aktuell leistet.

8.1

Eine Vektor-Klasse

Klassen kann man fr viele Aufgaben verwenden. Man kann mit ihrer Hilfe die Objekte beschreiben, mit denen das Programm zu tun hat (beispielsweise Textpassagen, Adressen, Kundendaten, Autos etc.), man kann sie aber auch als kleine Bibliotheken fr Methoden zu einem bestimmten Aufgabenbereich sehen (siehe die Klasse Math) wobei im letzteren Fall meist keine Objekte der Klassen erzeugt werden (oftmals auch gar nicht erzeugt werden knnen). Wie in Java Klassen definiert werden, ist Thema dieses Kapitels. Als Fhrer durch die vielen mit der Klassendefinition einhergehenden Syntaxformen dient uns dabei eine Klasse fr zweidimensionale Vektoren, die wir nach und nach aufbauen werden.

8.1.1 Zweidimensionale Vektoren


Im zweidimensionalen Raum sind Vektoren durch eine x- und eine yKoordinate definiert. Man knnte einen Vektor also auch als einen Pfeil sehen, der vom Ursprung des Koordinatensystems zu einem Punkt (x, y) zeigt.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Klassen Seite 179

Abbildung 8.1: Vektor als zweidimensionale Koordinate Diese Vektoren kann man addieren (siehe Abbildung 8.2), subtrahieren, man kann sie mit Faktoren oder anderen Vektoren multiplizieren (Skalar- und Vektorprodukt), man kann ihre Lnge berechnen etc.

Abbildung 8.2: Vektoraddition Was die Vektoren fr uns interessant macht, ist, dass sich jeder unter einem Vektor etwas vorstellen kann, dass man mit Vektoren anschaulich programmieren kann (eben die Vektoren addieren, das Vektorprodukt

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Klassen Seite 180

berechnen etc.) und dass anhand der Implementierung einer Vektor-Klasse viele Konzepte der objektorientierten Programmierung gut zu begreifen sind.

8.1.2 Die Klassendefinition


Der erste Schritt besteht darin, die neue Klasse anzulegen. Eine Klassendefinition besteht aus drei Teilen:
class Klassenname { // hier werden die Klassenelemente definiert... }

also: dem Schlsselwort class, das die Klassendefinition einleitet, dem von Ihnen frei gewhlten Namen der Klasse (aber bitte die Regeln zur Namensgebung beachten, siehe 4.6), den Definitionen der Klassenelemente, die in geschweifte Klammern eingefasst direkt nachfolgen.

Optional kann dem Schlsselwort class noch der Zugriffsspezifizierer public vorangestellt werden. Fr allgemein ntzliche Klassen, von denen Sie ausgehen, dass Sie sie spter auch einmal in anderen Programmen verwenden werden, sollten Sie dies unbedingt tun. Die Klasse, die die main()-Methode definiert, wird ebenfalls meist als public definiert. Kleinere Hilfsklassen ohne allgemeinen Nutzen werden dagegen blicherweise nicht als public definiert. public-Klassen Eine Klasse, die ohne Zugriffsspezifizierer definiert wird, kann nur im Code von Klassen verwendet werden, die demselben Paket angehren. Da es blich ist, alle Klassen eines Programms demselben Paket zuzuteilen, luft dies darauf hinaus, dass Klassen ohne Zugriffsspezifizierer nur programmintern verwendet werden knnen (beispielsweise zum Erzeugen von Objekten). Eine Klasse, die als public definiert ist, kann auch in anderen Paketen verwendet werden. Allgemeine ntzliche Klassen sollten daher unbedingt als public definiert werden. Denken Sie aber daran, dass es in einer Quelltextdatei immer nur eine public-Klasse geben darf und dass die Quelltextdatei genauso heien muss wie die Klasse.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Klassen Seite 181

Klassen, die keinem Paket zugeteilt sind, gibt es in Java nicht. Sogar Klassen, die in Quelltextdateien definiert sind, die keine package-Anweisung enthalten, gehren einem Paket an: dem anonymen Standardpaket. (Das Konzept der Pakete wurde bereits in 4.2 vorgestellt.)

Fr unsere Vektor-Klasse bedeutet dies, dass wir sie natrlich in einer eigenen Datei namens Vektor.java definieren:
public class Vektor { }

Listing 8.1: Aus Vektor.java

Parallel legen wir zum Testen gleich eine zweite Quelltextdatei fr die Hauptklasse mit der main()-Methode an:
public class Vektorprogramm { }

Listing 8.2: Aus Vektorenprogramm.java

Zur Erstellung des Programms bergeben Sie dem Compiler einfach beide Quelltextdateien. (Im vorliegenden Beispiel wrde es allerdings auch gengen, nur die Datei mit der Hauptklasse zu bergeben. Der Compiler wrde die Quelltextdatei zur im Programm verwendeten Klasse Vektor dann selbststndig suchen.)
javac Vektorprogramm.java Vektor.java

Zum Ausfhren bergeben Sie wie gehabt nur den Namen der Hauptklasse:
java Vektorprogramm

Na, das war doch gar nicht so schwer, oder? Nun ja, die eigentliche Arbeit kommt ja auch erst. Jetzt mssen wir die Elemente fr unsere VektorKlasse auswhlen und definieren.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Klassen Seite 182

8.2

Felder

Jeder Vektor verfgt ber eine x- und eine y-Koordinate. Es liegt also nahe, zwei double-Elemente x und y in der Klasse zu definieren, in denen wir die x,y-Koordinaten der einzelnen Vektoren (sprich der spter erzeugten Objekte der Klasse Vektor) ablegen knnen.
public class Vektor { double x; double y; }

Es gibt zwei wichtige Unterschiede zwischen Variablen, die man in einer Methode, und solchen, die man in einer Klasse (auerhalb der Methoden der Klasse) definiert: Gltigkeitsbereich und Zugriffsmglichkeiten von auerhalb der Klasse

8.2.1 Gltigkeitsbereich
Variablen, die innerhalb einer Methode definiert sind, nennt man Sie erinnern sich vielleicht lokale Variablen. Lokale Variablen sind nur innerhalb ihrer Methode vorhanden, d.h. innerhalb der Methode kann man auf die lokalen Variablen zugreifen und mit ihnen arbeiten, auerhalb der Methode (beispielsweise in einer anderen Methode der gleichen Klasse) ist dies nicht mglich. Variablen, die in einer Klasse definiert sind, nennt man Felder. Felder sind in der gesamten Klasse vorhanden, d.h. man kann in allen Methoden der Klasse mit ihnen arbeiten. Zur Verdeutlichung sehen wir uns eine fiktive Klasse mit zwei Methoden an:
class Demo { double feld1, feld2; void tue_was() { double lok_var; lok_var = 1;

// Felder

// lokale Variable

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Klassen Seite 183

feld1 = }

2;

void tue_was_anderes() { lok_var = 1; feld1 = 2; } }

// Fehler! // korrekt

8.2.2 Zugriff von auerhalb der Klasse


Zugriff von auerhalb der Klasse bedeutet Zugriff aus einer anderen Klasse heraus. Dies geht nur ber den Klassennamen oder ein Objekt (Instanz) der Klasse. Sie kennen dies im Prinzip schon aus den vorangehenden Programmbeispielen.
class Demo { public static void main(String[] args) { String ausgabe = "Hallo, wie geht es Dir?"; ausgabe = ausgabe.toLowerCase(); System.out.println(ausgabe); } }

String ist, wie Sie wissen, ein Klassentyp. In main() wird zuerst ein String-Objekt erzeugt und der Verweis auf das Objekt in der StringVariablen ausgabe gespeichert. Fr diese wird dann die Methode toLowerCase() aufgerufen. Dies ist die erste Form des Zugriffs von auen, denn hier wird aus der Klasse Demo auf das String-Element toLowerCase() zugegriffen. Die zweite Form des Zugriffs von auen sehen Sie in der letzten Zeile. ber die Klasse System wird auf deren statisches Feld out zugegriffen (und dann die Methode println() des out-Objekts aufgerufen). ber den Klassennamen kann nur auf statische Elemente der betreffenden Klasse zugegriffen werden.
Icon ACHTUNG

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Klassen Seite 184

Wir knnen also in der Klasse Vektorprogramm auf die Elemente x und y unserer Vektor-Klasse zugreifen, oder nicht?
public class Vektor { double x; double y; }

Listing 8.3: Aus Vektor.java

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Klassen Seite 185

public class Vektorprogramm { public static void main(String[] args) { Vektor v = new Vektor(); v.x = 1; v.y = 2; } } // Zugriff ber Objekt

System.out.println(" Vektor: (" + v.x + "," + v.y + ")");

Listing 8.4: Aus Vektorprogramm.java

Tatschlich funktioniert dieser Zugriff, doch wir verdanken dies einem mehr oder weniger glcklichen Zusammentreffen: Beide Klasse sind im selben Paket definiert (da wir keine packageAnweisung verwenden, gehren die Klassen dem anonymen Standardpaket an). Wir haben fr die Klassenelemente keinen Zugriffsspezifizierer angegeben. Zugriffsspezifizierer erlauben der Klasse (bzw. dem Autor der Klasse), Klassenelemente vor dem Zugriff von auen zu schtzen oder sie umgekehrt fr den Zugriff von auen freizugeben. Gibt der Programmierer keinen Zugriffsspezifizierer an, ist das betreffende Element im gesamten Paket zugnglich.10

Zugriffsspezifizierer In Java werden die Zugriffsmglichkeiten fr die einzelnen Klassenelemente mithilfe von fnf Schlsselwrtern, den Zugriffsspezifizierern, geregelt.
Zugriffsspezifizierer Bedeutung Das Element kann innerhalb der eigenen Klasse und in allen anderen Klassen verwendet werden.

public

10

Andere Programmiersprachen sind da wesentlich restriktiver. In C++ und C# sind Klassenelemente ohne explizite Zugriffsspezifizierer automatisch privat, d.h. sie knnen nur im Code der eigenen Klasse verwendet werden.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Klassen Seite 186

keine Angabe

Das Element kann in der eigenen und in allen Klassen, die dem gleichen Paket angehren, verwendet werden. Das Element kann in der eigenen und in Klassen, die von dieser abgeleitet sind (siehe Tutorium 9), verwendet werden. Das Element kann nur innerhalb der eigenen Klasse verwendet werden.

protected

private

Tabelle 8.1: Zugriffsspezifizierer

8.2.3 Statische Felder


Statische Felder sind Elemente der Klasse und verfgbar, ohne dass erst ein Objekt der Klasse erzeugt werden muss. Sie werden mit dem Schlsselwort static definiert:
class EinWert { static double w; } class Demo { public static void main(String[] args) { EinWert.w = 1; System.out.print(EinWert.w); } }

Es ist aber ganz wichtig zu verstehen, dass static nicht einfach nur eine andere Form des Zugriffs auf Klassenelemente darstellt (ber den Klassennamen statt ber Objekte). Vielmehr ist es so, dass diese andere Form des Zugriffs von auen die Konsequenz aus einem anderen Effekt, d.h. der eigentlichen Wirkung der static-Definition ist. Wenn Sie nmlich spter Objekte Ihrer Klasse erzeugen, erhlt jedes Objekt eine eigene Kopie der in der Klasse definierten Felder. Fr unsere Klasse Vektor bedeutet dies z.B., dass jedes Vektor-Objekt zwei Felder x und y erhlt. Nur so ist es mglich, unterschiedliche Vektoren (mit unterschiedlichen x,y-Koordinaten) zu reprsentieren. Statische Felder

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Klassen Seite 187

existieren dagegen nur einmal fr alle Objekte der Klasse. Von der obigen Klasse EinWert knnen Sie also so viele Objekte erzeugen, wie Sie wollen, es gibt immer nur eine Kopie von EinWert.w. Fr die individuellen Daten der Objekte definiert man daher in der Klasse nicht-statische Felder; fr Daten, die sich alle Objekte teilen, kann man statische Felder definieren.

8.2.4 Weiterfhrung des Beispiels


Fr unsere Vektor-Klasse ziehen wir aus dem oben Gesagten folgende Konsequenzen: Wir definieren die Felder x und y als public, damit sie auf jeden Fall unabhngig von irgendwelchen Paketzugehrigkeiten zugnglich sind. Wir definieren die Felder x und y nicht als static, denn jedes Vektor-Objekt soll ja ber eigene, individuelle Koordinaten verfgen.

public class Vektor { public double x; public double y; }

Aus Vektor.java
public class Vektorprogramm { public static void main(String[] args) { Vektor v = new Vektor(); v.x = 1; v.y = 2; } } // Zugriff ber Objekt

System.out.println(" Vektor: (" + v.x + "," + v.y + ")");

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Klassen Seite 188

Aus Vektorprogramm.java

Natrlich knnte man fr Vektoren noch andere Felder definieren, beispielsweise ein Feld fr die Lnge oder Felder fr die Polardarstellung mit Winkel und Radius. Wenn die Vektoren nicht alle automatisch im Ursprungspunkt beginnen sollen, wrde man die Koordinaten des Anfangsund des Endpunkts speichern und so weiter. Welche Felder oder auch Methoden man fr eine Klasse definiert, hngt davon ab, wofr man die Klasse einsetzt. Oftmals wandelt sich das Design auch im Laufe der Implementierung der Klasse: neue Elemente kommen hinzu, bestehende Elemente werden entfernt oder ersetzt. Klassen-Design ist keine ganz einfache Aufgabe. Aus diesem Grunde gibt es fr die professionelle, objektorientierte Programmierung auch eine Reihe von Hilfsmitteln (spezielle Techniken und Programme), die Programmierer, SoftwareIngenieure und Software-Architekten bei der Konzipierung und beim Aufsetzen der Klassen fr ein Programm untersttzen (CRC-Karten, UML, CASE-Tools etc.). Fr kleinere Programme lohnt sich der Einsatz dieser Hilfsmittel aber nicht; auerdem sollte man mit diesen Techniken sowieso erst dann arbeiten, nachdem man selbst eigene Erfahrungen im KlassenDesign gesammelt hat. Halten Sie sich aber bitte an folgende Regel: Definieren Sie immer nur die Elemente, die wirklich bentigt werden. berlegen Sie es sich zweimal, bevor Sie Elemente definieren, nur weil Sie das Gefhl haben, es wre vielleicht ganz ntzlich, die Elemente mit dabei zu haben. Wenn Sie nicht sicher sagen knnen: Ja, diese Elemente werden gebraucht, so lassen Sie sie weg. Es ist grundstzlich viel einfacher, nachtrglich noch weiter bentigte oder hilfreiche Elemente hinzuzufgen, als bestehende Elemente aus einer Klasse zu entfernen. Und zwar nicht, weil das Markieren und Drcken der (Delete)-Taste so mhsam wre, sondern weil es mglicherweise schon Code gibt, der davon abhngig ist, dass die Elemente, die Sie wieder lschen mchten, vorhanden sind.

Icon HINWEIS

8.3

Methoden

Der nchste Schritt besteht darin, die Methoden zu definieren. Grundstzlich gibt es in einer Klasse zwei Arten von Methoden:

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Klassen Seite 189

public-Methoden diese Methoden bestimmen, was man mit den Objekten einer Klasse machen kann. Wenn wir beispielsweise mchten, dass man zu den Objekten der Klasse Vektor andere Vektoren addieren kann, mssen wir eine public-Methode zum Addieren aufsetzen. private- oder protected-Hilfsmethoden diese Methoden untersttzen die interne Implementierung der Klasse. Wenn Sie feststellen, dass Sie in einer oder mehreren public-Methoden der Klasse wiederholt eine bestimmte Teilarbeit verrichten, lohnt es sich, diese Teilarbeit in Form einer eigenen Methode zu implementieren. Diese Methode wird dann als private definiert, denn sie soll ja nicht direkt ber die Instanzen der Klasse, sondern nur von den anderen Methoden der Klasse aufgerufen werden.

Im Moment wollen wir nur zwei public-Methoden addieren() und subtrahieren() definieren, eben um Vektoren addieren und subtrahieren zu knnen.

8.3.1 Aufbau von Methodendefinitionen


Die allgemeine Syntax der Methodendefinition lautet:
Zugriffspez Methodenmod Rckgabetyp Name(Parameterliste) { } Zugriffspez Einer der Zugriffsspezifizierer

public, protected,

private.
Methoden, die ohne Zugriffsspezifizierer definiert werden, sind in allen Klassen ihres Pakets verfgbar. Methoden, die als public deklariert werden, knnen auch in anderen Paketen verwendet werden. Methoden, die als protected deklariert werden, knnen in allen Klassen ihres Pakets sowie allen abgeleiteten Klassen (siehe Tutorium 9) verwendet werden. Methoden, die als private deklariert werden, knnen nur innerhalb der eigenen Klasse verwendet werden. Methodenmod Ein Modifizierer, wie z.B. abstract oder static zur Definition von statischen Methoden. Statische Methoden knnen nur auf andere statische Elemente ihrer Klasse zugreifen.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Klassen Seite 190

Rckgabetyp

Liefert die Methode als Ergebnis mit return einen Wert zurck (siehe 8.3.3), steht hier der Datentyp des Werts. Liefert die Methode keinen Wert zurck, lautet der Rckgabetyp void.

Name

Der Name ist unter Einhaltung der in 4.6 aufgelisteten Regeln frei whlbar. Per Konvention beginnen Methodennamen mit einem Kleinbuchstaben (lowerCamelCase). Parameter sind spezielle Variablen der Methode, denen beim Aufruf der Methode Werte bergeben werden knnen.

Parameterliste

Tabelle 8.2: Komponenten einer Methodendefinition

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Klassen Seite 191

Fr Methoden gelten grundstzlich folgende Regeln: Aufruf: Eine einmal definierte Methode kann jederzeit durch Aufruf ausgefhrt werden. Andere Methoden derselben Klasse knnen die Methode direkt ber ihren Namen aufrufen (wobei bei geerbten Methoden die Zugriffsspezifizierer darber entscheiden, ob der Aufruf erlaubt ist). Ansonsten knnen andere Klassen die Methode ber ein Objekt (nichtstatische Methoden) oder den Klassennamen (statische Methoden) aufrufen. Definiert die Methode Parameter, muss im Aufruf fr jeden Parameter ein Wert (Argument) bergeben werden. Liefert die Methode einen Wert zurck, kann dieser in einen Ausdruck einflieen oder einer Variablen zugewiesen werden. Der Methodenaufruf steht dann quasi als Stellvertreter fr diesen Wert. Zugriff: Methoden knnen uneingeschrnkt auf alle (auch private) Elemente ihrer Klasse zugreifen. Auf geerbte private Elemente knnen sie jedoch nicht zugreifen. Statische Methoden knnen nur auf andere statische Elemente zugreifen. Zweck: Grundstzlich gilt, dass jede Methode eine bestimmte Aufgabe erfllen sollte. Der Name der Methode sollte dabei so gewhlt sein, dass sich ihr Verwendungszweck daraus bereits ablesen lsst. Um ihre Aufgabe erfllen zu knnen, muss die Methode gegebenenfalls Werte entgegennehmen und Ergebnisse zurckliefern.

8.3.2 Parameter
Woher nimmt eine Methode die Daten, mit denen sie arbeitet? Nun, zum einen ist eine Methode ja Bestandteil einer Klassendefinition. Fr die Methode bedeutet dies, dass sie auf alle Felder ihrer Klasse zugreifen kann. Zum anderen kann eine Methode natrlich auch eigene lokale Variablen definieren. Von diesen haben wir in den vorangegangenen Abschnitten bereits eifrig Gebrauch gemacht. Alle dort deklarierten Variablen waren lokale Variablen der Methode main().

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Klassen Seite 192

Wie aber, wenn zwei Methoden unterschiedlicher Klassen Daten austauschen sollen? Aus unseren bisherigen Programmierbeispielen ist Ihnen dieser Vorgang ja schon bestens vertraut wenn Ihnen auch die Problematik dieses Vorgangs bisher vielleicht gar nicht so richtig bewusst geworden ist.
class Demo { public static void main(String[] args) { String ausgabe = "Hallo"; System.out.println(ausgabe); } }

Lassen Sie uns die Beziehung zwischen main() und println() ein wenig nher beleuchten. Da der Aufruf in der Methode main() erfolgt, sagt man auch, dass main() der Aufrufer oder die aufrufende Methode und println() die aufgerufene Methode ist. Worauf es uns in diesem Beispiel ankommt, ist dass der Aufrufer main() und die aufgerufene Methode println() unterschiedlichen Klassen angehren (Vektorprogramm und PrintStream, dem Klassentyp des Objekts System.out). Es gibt daher keine Klassenfelder, ber die beide Methoden Daten austauschen knnten. Die einzige Mglichkeit zum Datenaustausch sind daher die Daten, die beim Aufruf bergeben werden. Damit aber eine Methode beim Aufruf Daten vom Aufrufer entgegennehmen kann, muss sie in ihrer Definition passende Parameter spezifizieren. Die im Beispiel verwendete System.out.println()-Methode definiert zum Beispiel einen String-Parameter. Und genau dies macht die Methode fr uns so wertvoll, denn nur so kann man mithilfe der Methode beliebige Strings ausgeben. Diese werden beim Aufruf der Methode als Argument bergeben. Wichtig ist dabei, dass fr jeden Parameter, den die Methode definiert, ein vom Typ her passendes Argument bergeben wird im Falle der System.out.println()-Methode beispielsweise ein String-Literal oder eine String-Variable. Der eine oder andere Leser wird jetzt vielleicht an den Aufruf Icon AUFSTEIGER System.out.println() denken, bei dem offensichtlich kein Argument an den Parameter bergeben wird. Nun, wie so oft ist die Wahrheit etwas komplizierter als es am Anfang scheint. Tatschlich ist die Methode

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Klassen Seite 193

System.out.println() berladen, d.h., es gibt mehrere Methoden mit Namen System.out.println(), die unterschiedliche Parameter verwenden. Dazu spter mehr.

Parameter definieren Wenn man eigene Methoden definiert, muss man die Parameter in den runden Klammern hinter dem Methodennamen auffhren. Die einzelnen Parameter werden dabei wie ganz normale Variablen definiert und falls mehrere Parameter definiert werden durch Kommata getrennt. Innerhalb der Methode kann man die Parameter dann wie ganz normale lokale Variablen verwenden.
public void tueWas(int zahl) { zahl = 12; // ... } public void tueWasAnderes(int zahl, String text) { zahl = 12; text += "***"; // ... }

Beim Aufruf bergibt man fr jeden Parameter der Methode ein passendes Argument. Passend heit in diesem Fall, dass der Datentyp des Arguments mit dem Datentyp des Parameters bereinstimmen muss. Aufrufe der beiden oben definierten Methoden knnten wie folgt aussehen:
int wert = 12; String s = "Hallo"; tueWas(wert); tueWasAnderes(3, s); ... obj.tueWas(wert); obj.tueWasAnderes(3, s);

// bei Aufruf in Methode // der gleichen Klasse // bei Aufruf aus Methode // einer anderen Klasse
Icon HINWEIS

Viele Programmierer sprechen statt von Argumenten von formalen Parametern oder verwenden den Begriff Parameter sowohl fr die beim Aufruf bergebenen Argumente als auch die in der Methode definierten Parameter. Welcher Terminologie Sie auch folgen, wichtig ist, dass

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Klassen Seite 194

Argument und Parameter zwei unterschiedliche Variablen sind, deren Werte kopiert werden.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Klassen Seite 195

Fr Parameter gibt es nur einen Modifizierer: final. Der Wert eines final-Parameters kann in der Methode nicht gendert werden. Achtung: Die final-Deklaration eines Referenztyp-Parameters garantiert lediglich, dass die Referenz im Parameter nicht gendert werden kann. nderungen am Objekt, auf das die Referenz verweist, sind weiterhin mglich.

Icon ACHTUNG

Argumente werden kopiert! Wenn Sie eine Methode mit einem Parameter aufrufen und dabei eine Variable als Argument bergeben, reserviert der Compiler im Arbeitsspeicher Platz fr den Parameter und kopiert den Wert des Arguments in den Parameter. Im Falle von elementaren Datentypen wird dabei der tatschliche Wert kopiert, sodass man nach dem Kopieren zwei unterschiedliche Variablen hat (das bergebene Argument und den Parameter), die beide den gleichen Wert haben. Im Falle von Instanzen von Klassen werden dagegen nicht die Objekte kopiert, sondern nur die Referenzen auf die Objekte. Nach der bergabe einer Instanz hat man also zwei Variablen (das Argument und den Parameter), die beide auf ein und dasselbe Objekt im Speicher verweisen. Daraus folgt: Im Falle von elementaren Datentypen kann die Methode den Wert des Parameters ndern, ohne dass sich der Wert der Variablen ndert, die als Argument bergeben wurde. Im Falle von Klassentypen ist es genau umgekehrt, da der Parameter auf genau dasselbe Objekt zugreift wie die bergebene Objektvariable.

8.3.3 Rckgabewerte
Was macht eine Methode, die neue Daten berechnet, mit ihren Ergebnissen? Felder verndern Hufig speichert sie die Werte in den Feldern ihrer Klasse. Wir knnten z.B. eine Vektor-Methode addieren() implementieren, die als Parameter ein Vektor-Objekt bernimmt und dieses zu dem aktuellen Vektor-Objekt, fr das die Methode aufgerufen wird, addiert.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Klassen Seite 196

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Klassen Seite 197

public class Vektor { public double x; public double y; public void addieren(Vektor v) { x += v.x; // addiert den Wert von v.x zu dem Feld x y += v.y; // addiert den Wert von v.y zu dem Feld y } }

Ein typischer Aufruf dieser Methode she dann wie folgt aus:
vekt1.addieren(vekt2);

Nach dem Aufruf ist vekt1 gleich der Summe des ursprnglich von vekt1 reprsentierten Vektors und dem Vektor vekt2. Rckgabewerte zurckliefern Methoden knnen auch einen Rckgabewert zurckliefern. Dazu mssen Sie den Datentyp des Rckgabewerts in der Methodendefinition vor dem Methodennamen angeben und im Code der Methode den Rckgabewert mittels einer return-Anweisung zurckliefern. Mithilfe von return knnen wir z.B. eine addieren()-Methode fr Vektoren konzipieren, die ganz anders funktioniert als die oben vorgestellte Implementierung:
Vektor addieren(Vektor v) { Vektor tmp = new Vektor(); tmp.x = x + v.x; tmp.y = y + v.y; return tmp; }

Diese Methode addiert den bergebenen Vektor nicht zu dem aktuellen Vektor, sondern liefert das Ergebnis der Addition der beiden Vektoren als neuen, separaten Vektor zurck. Ein typischer Aufruf dieser Methode she dann wie folgt aus:
Vektor vekt3; vekt3 = vekt1.addieren(vekt2);

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Klassen Seite 198

Nach dem Aufruf reprsentieren vekt1 und vekt2 dieselben Vektoren wie vor dem Aufruf und vekt3 ist gleich dem Vektor, der sich aus der Addition von vekt1 und vekt2 ergibt. In der aufrufenden Methode steht der Methodenaufruf stellvertretend fr das von der Methode zurckgelieferte Ergebnis. Wir knnen dieses Ergebnis daher ohne Probleme: einer Variablen zuweisen
int summe = addieren(1, 2);

direkt in einem Ausdruck weiterverarbeiten (blich bei elementaren Rckgabetypen)


int summe = 3 + potenziere(12);

zum direkten Zugriff auf Klassenelemente verwenden (nur fr Methoden, die Referenzen auf Objekte zurckliefern)
int summe = 3 + Vektor.addieren(v1, v2).x;

Man kann den Rckgabewert aber nicht nur zum Zurckliefern von Ergebnissen verwenden. Wenn beispielsweise die eigentliche Aufgabe der Methode darin besteht, einem bestimmten Feld der Klasse einen neuen Wert zuzuweisen, kann sie den Rckgabewert in unterschiedlichster Weise nutzen: Sie kann den neuen Wert zustzlich als Ergebniswert zurckliefern. Sie kann einen Fehlercode zurckliefern, den der Aufrufer in einer ifBedingung berprfen kann (beispielsweise false, um anzuzeigen, dass die Aufgabe wegen eines Fehlers nicht ordnungsgem erledigt werden konnte, und true, um anzuzeigen, dass alles geklappt hat). Sie braucht berhaupt keinen Rckgabewert zurckzuliefern. In diesem Falle muss man in der Methodendefinition an der Stelle des Rckgabetyps das Schlsselwort void setzen.
Icon ACHTUNG

Sie knnen die return-Anweisung auch dazu nutzen, eine Methode vorzeitig zu beenden. Die Ausfhrung einer return-Anweisung fhrt nmlich dazu, dass die betreffende Methode sofort beendet wird. So kann eine Methode durch Aufsetzen mehrerer return-Anweisungen von unterschiedlichen Stellen aus verlassen werden. Dies macht aber natrlich nur Sinn, wenn die return-Anweisungen durch Bedingungen kontrolliert werden.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Klassen Seite 199

Methoden, die einen Wert zurckliefern, mssen eine return-Anweisung enthalten.

Icon ACHTUNG

8.3.4 this
Werden mehrere Instanzen einer Klasse gebildet, bekommt jede Instanz eine eigene Kopie der Instanzvariablen der Klasse. Die Methoden der Klasse stehen aber nur einmal im Arbeitsspeicher und werden von allen Instanzen einer Klasse gemeinsam benutzt. Wie wird also sichergestellt, dass eine aufgerufene Methode nur auf die Daten zugreift, die zur aufrufenden Instanz gehren? Der Trick ist, dass der Compiler jeder Methode stillschweigend zustzlich zu den von Ihnen beim Aufruf bergebenen Argumenten noch ein weiteres Argument bergibt: eine Referenz auf das aktuelle Objekt. Mithilfe dieser Referenz kann die Methode gezielt auf die Felder des Objekts zugreifen, fr das sie aufgerufen wurde. Sie knnen diese Referenz auf das aktuelle Objekt brigens selbst auch verwenden: die Referenz wird im Code durch das Schlsselwort this reprsentiert. Die folgende Methode nutzt die this-Referenz, um eine dritte Variante der addieren()-Methode fr Vektoren zu implementieren. Diesmal addiert die Methode den als Argument bergebenen Vektor zu dem aktuellen Vektor-Objekt (wie unsere 1. Variante), liefert aber zustzlich den Ergebnisvektor, in diesem Fall also das aktuelle Objekt, als Rckgabewert zurck (wie unsere 2. Variante).
Vektor addieren(Vektor v) { x += v.x; y += v.y; return this; }

Ein typischer Aufruf dieser Methode she dann wie folgt aus:

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Klassen Seite 200

Vektor vekt3; vekt3 = vekt1.addieren(vekt2);

Nach dem Aufruf verweisen vekt1 und vekt3 auf dasselbe VektorObjekt. Welchen Sinn hat es, dass die Methode das aktuelle Objekt verndert und dann zustzlich noch einmal als Rckgabewert zurckliefert?
Icon AUFSTEIGER

Denken Sie daran, dass der Methodenaufruf in Ausdrcken fr seinen Rckgabewert steht. Liefert die Methode das aktuelle Objekt als Ergebnis zurck, knnen Sie den Methodenaufruf in Ausdrcken wie ein Objekt verwenden und z.B. gleich auf eines seiner Elemente zugreifen:
System.out.println(vekt1.addieren(vekt2).x );

Wenn Sie Methoden schreiben, die einem Feld den Wert eines Parameters zuweisen sollen, knnen Sie den Parameter genauso nennen wie das Feld und innerhalb der Methode dann ber die this-Referenz auf das Feld zugreifen:
void setAlter(int alter) { this.alter = alter; )

8.3.5 berladung
Java erlaubt die Definition mehrerer Methoden gleichen Namens, sofern die Methoden sich in Anzahl oder Typ der Parameter unterscheiden. Auf diese Weise kann der Programmierer identische Bezeichner vergeben, whrend der Compiler mit eindeutigen Namen arbeitet. Durch berladung knnen Sie Methodengruppen schreiben, die ein und dieselbe Aufgabe in Abhngigkeit vom Typ (und Anzahl) der Argumente unterschiedlich ausfhren. Ein gutes Beispiel hierfr ist die berladung der Bibliotheksmethode println():
public void println() public void println(boolean x)

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Klassen Seite 201

public public public public public public public public

void void void void void void void void

println(char x) println(int x) println(long x) println(float x) println(double x) println(char x[]) println(String x) println(Object x)

8.3.6 Weiterfhrung des Beispiels


Setzen wir nun die Methoden addieren() und subtrahieren() fr unsere Vektor-Klasse auf. Zuerst mssen wir entscheiden, ob die Methoden das aktuelle Objekt ndern oder ob sie das Ergebnis nur als Rckgabewert zurckliefern sollen. Beide Konzepte sind durchaus sinnvoll. Meist werden Sie das Objekt direkt ndern. Fr unsere Vektor-Klasse ziehen wir allerdings die zweite Variante vor: So hnelt die Programmierung mit Vektor-Objekten mehr dem Rechnen mit Vektoren in der Mathematik.
public class Vektor { public double x; public double y; public Vektor addieren(Vektor v) { Vektor tmp = new Vektor(); tmp.x = x + v.x; tmp.y = y + v.y; return tmp; } public Vektor subtrahieren(Vektor v) { Vektor tmp = new Vektor(); tmp.x = x - v.x; tmp.y = y - v.y; return tmp; } }

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Klassen Seite 202

Listing 8.5: Aus Vektor.java


public class Vektorprogramm { public static void main(String[] args) { Vektor v1 = new Vektor(); v1.x = 10; v1.y = 10; Vektor v2 = new Vektor(); v2.x = 5; v2.y = 5; Vektor v3 = v1.addieren(v2); System.out.println(" v3: (" + v3.x + "," + v3.y + ")"); Vektor v4 = v1.subtrahieren(v2); System.out.println(" v4: (" + v4.x + "," + v4.y + ")"); }

Listing 8.6: Aus Vektorenprogramm.java

8.4

Der Konstruktor

In der Einfhrung zur objektorientierten Programmierung wurde bereits erwhnt, dass bei der Erzeugung eines Objekts einer Klasse:
Vektor vekt1 = new Vektor();

eine ganz spezielle Methode aufgerufen wird, die den Namen der Klasse trgt. Diese Methode nennt man den Konstruktor. Ohne Konstruktor ist es schlichtweg nicht mglich, Objekte einer Klasse zu erzeugen. Aus diesem Grunde stattet der Compiler jede Klasse, die selbst

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Klassen Seite 203

keinen Konstruktor definiert, mit einem Standardkonstruktor aus. Der Standardkonstruktor definiert keine Parameter und fhrt keinen Code aus. Oft ist es aber erforderlich, einen eigenen Konstruktor vorzusehen. Diesen kann man dazu nutzen, den Feldern des neu erzeugten Objekts Anfangswerte zuzuweisen. Fr unsere Vektor-Klasse wollen wir sicherstellen, dass die Koordinaten der neu erzeugten Vektor-Objekte anfangs auf (0,0) gesetzt werden:
// Konstruktor public Vektor() { x = 0; y = 0; }

Fr Konstruktoren gelten die folgenden Regeln: Der Name des Konstruktors muss gleich dem Namen seiner Klasse sein. Es darf kein Rckgabetyp angegeben werden, auch nicht void.

Schn wre es auch, wenn der Benutzer der Vektor-Klasse die x- und yWerte fr seine Vektoren direkt an den Konstruktor bergeben knnte, anstatt sie nachtrglich explizit den Feldern zuweisen zu mssen. Ein passender Konstruktor, der dies leistet, knnte wie folgt aussehen:
public Vektor(double x, double y) { this.x = x; this.y = y; }

Wenn wir jetzt einen Vektor fr die Koordinaten (3,5) erzeugen mchten, knnen wir einfach schreiben:
Vektor v = new Vektor(3,5);

Mehr noch wir knnen den Konstruktor sogar dazu nutzen, die Implementierung unserer Vektor-Methoden zu vereinfachen:
public class Vektor { public double x; public double y; public Vektor() {

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Klassen Seite 204

x = 0; y = 0; } public Vektor(double x, double y) { this.x = x; this.y = y; } public Vektor addieren(Vektor v) { return new Vektor(x + v.x, y + v.y); }

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Klassen Seite 205

public Vektor subtrahieren(Vektor v) { return new Vektor(x - v.x, y - v.y); } }

Listing 8.7: Aus Vektor.java

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Klassen Seite 206

public class Vektorprogramm { public static void main(String[] args) { Vektor v1 = new Vektor(10, 10); Vektor v2 = new Vektor(5, 5); Vektor v3 = v1.addieren(v2); System.out.println(" v3: (" + v3.x + "," + v3.y + ")"); Vektor v4 = v1.subtrahieren(v2); System.out.println(" v4: (" + v4.x + "," + v4.y + ")"); } }

Listing 8.8: Aus Vektorenprogramm.java

Konstruktoren werden hufig berladen, um dem Benutzer der Klasse die Mglichkeit zu geben, seine Objekte mit verschiedenen Stzen von Argumenten zu initialisieren.

Icon HINWEIS

Fr die Zuweisung fester Anfangswerte an Felder knnen Sie auch die normale Form der Variableninitialisierung verwenden:
public class Vektor { public double x = 0.0; public double y = 0.0; // ... }

8.5

Zugriffschutz

Im Laufe des Buches sind Ihnen schon mehrfach die sogenannten Zugriffsspezifizierer (z.B. public) ber den Weg gelaufen und es wird nun Zeit, sich mit diesen nher zu befassen. Eine Grundregel des Klassendesigns besagt:

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Klassen Seite 207

Elemente, die nur der internen Implementierung der Klasse dienen, sollten private sein. Elemente, die der Benutzer der Klasse verwenden soll, sind dagegen public. Letztere bilden die ffentliche Schnittstelle der Klasse. Da unsere Klasse Vektor keine Elemente enthlt, die allein der internen Implementierung dienen, definiert sie alle Elemente als public. Eine weitere Grundregel des Klassendesigns besagt: Felder sollten grundstzlich private sein. Der Zugriff auf die Felder sollte allein durch public-Methoden stattfinden. Diese Grundregel wird von unserer Klasse nicht beachtet. Sollten wir also das Design unserer Klasse berdenken und die Felder als private definieren? Wenn eine Klasse ein Feld als public definiert, erlaubt sie dem Benutzer der Klasse, den Wert des Felds nach eigenem Gutdnken zu verndern:
Vektor v = new Vektor(0,5); v.x = 10; v.x = -30; v.x = 0;

Im Falle unserer Klasse Vektor ist gegen solche Vernderungen nichts einzuwenden, denn jeder Wert, den der Benutzer zuweist, ist im Grunde ein zulssiger Wert. Meist ist es aber so, dass die Werte, die den Feldern zugewiesen werden, bestimmte Bedingungen zu erfllen haben. Betrachten Sie dazu die nachfolgend definierte Klasse Koordinaten, die unserer Vektor-Klasse sehr hnlich ist. Der wesentliche Unterschied ist, dass die Klasse Koordinaten nur positive Werte fr die Felder x und y erlaubt. bergibt der Benutzer dem Konstruktor negative Werte oder fhrt eine Subtraktion zu einem negativen Wert, sorgt die Implementierung der Klasse dafr, dass die entsprechende Koordinate auf 0 gesetzt wird.
public class Koordinaten { public double x; public double y; public Koordinaten() {

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Klassen Seite 208

x = 0; y = 0; } public Koordinaten(double x, double y) { if (x >= 0) this.x = x; else this.x = 0; if (y >= 0) this.y = y; else this.y = 0; } public Koordinaten addieren(Koordinaten v) { return new Koordinaten(x + v.x, y + v.y); } public Koordinaten subtrahieren(Koordinaten v) { double x, y; if (this.x - v.x >= 0) x = this.x - v.x; else x = 0; if (this.y - v.y >= 0) y = this.y - v.y; else y = 0; return new Koordinaten(x, y); } }

Doch was nutzt der ganze Aufwand, wenn der Benutzer der Klasse nicht aufpasst und den Feldern x und y direkt negative Werte zuweist:
Koordianten k = new Koordinaten(0,5); k.x = 0; k.y = -30; // Uups!

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Klassen Seite 209

Um dies zu verhindern, wrde die Klasse Koordinaten die Felder x und y als private definieren:
public class Koordinaten { private double x; private double y; // ... } Koordianten k = new Koordinaten(0,5); k.x = 0; k.y = -30; // nicht zugelassen, da x private // nicht zugelassen, da y private

Ist ein Feld private, kann der Benutzer es nur noch ber publicMethoden der Klasse manipulieren. Im Falle der Klasse Koordinaten schrnkt dies die Programmierung mit Koordinaten-Objekten empfindlich ein, denn es gibt weder eine Mglichkeit, die x- und y-Werte eines Koordinaten-Objekts abzufragen, noch diese auf einfache Weise zu verndern (beispielsweise um die x-Koordinate in einer Schleife schrittweise um 1 zu erhhen). Aus diesem Grund werden fr private-Felder hufig public-Methoden zum Abfragen (Get) und Setzen (Set) definiert. Get- und Set-Methoden Get- und Set-Methoden dienen dazu, den lesenden (Get) und schreibenden (Set) Zugriff auf private-Felder zu kontrollieren. Get-Methoden tragen per Konvention einen Namen, der mit get anfngt und an den sich der Name des Feldes anschliet (wobei der erste Buchstabe des Feldnamens blicherweise grogeschrieben wird (CamelCase-Notation). Sie bernehmen keine Parameter und ihr Rckgabetyp ist natrlich der Typ des abzufragenden Feldes. Da das Abfragen eines Feldes keine kritische Aktion ist, besteht ihr Code meist aus einer einfachen return-Anweisung.
public double getX() { return x; }

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Klassen Seite 210

public double getY() { return y; }

Set-Methoden tragen per Konvention einen Namen der mit set anfngt und an den sich der Name des Feldes anschliet (wobei der erste Buchstabe des Feldnamens blicherweise grogeschrieben wird (CamelCase-Notation). Sie bernehmen einen einzigen Parameter vom Typ des zu setzenden Feldes und ihr Rckgabetyp ist void. Im Methodenrumpf wird berprft, ob das Argument ein gltiger Wert fr das Feld ist. Wenn ja, wird das Argument zugewiesen, wenn nicht, unterbleibt die Zuweisung oder das Feld wird auf einen Standardwert gesetzt.
public void setX(double x) { if (x >= 0) this.x = x; else this.x = 0; } public void setY(double y) { if (y >= 0) this.y = y; else this.y = 0; }

Get- und Set-Methoden mssen nicht zwangsweise paarweise angeboten werden. Sie knnen auch nur eine Get-Methode anbieten oder nur eine SetMethode. Und wenn Sie weder Get- noch Set-Methode anbieten, kann das Feld eben nicht direkt abgefragt oder gesetzt werden, sondern nur mittelbar ber eine der sonstigen angebotenen public-Methoden der Klasse.

Icon HINWEIS

8.6

bung 6: Body Mass Index-Klasse

Aufgabenstellung Schreiben Sie das Programm BMI aus bung 3, Tutorium 6 so um, dass es die Daten des Anwenders in einem Objekt der Klasse Person ablegt.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Klassen Seite 211

Implementieren Sie die Berechnung des Body Mass Index als eine Methode der Klasse Person. geben Sie den BMI des Anwenders zusammen mit seinen persnlichen Daten aus. Versuchen Sie die Aufgabe zuerst selbststndig zu lsen. Wenn Sie nicht weiter wissen und Hilfe bentigen, lassen Sie sich von der Musterlsung inspirieren (die natrlich nicht die einzig mgliche Lsung darstellt). Lsung
public class Person { private String name; private int groesse; private int gewicht; public Person(String name, int groesse, int gewicht) { this.name = name; this.groesse = groesse; this.gewicht = gewicht; } public String getName() { return name; } public int getGroesse() { return groesse; } public int getGewicht() { return gewicht; } public double bmi() { return gewicht / Math.pow( groesse/100.0, 2); } }

Listing 8.9: Aus Person.java

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Klassen Seite 212

import java.util.Scanner; public class BMI { public static void main(String[] args) { String name; int groesse; int gewicht; Scanner sc = new Scanner(System.in); System.out.println(); System.out.println(" *** Berechnung des Body Mass Index ***"); System.out.println(" (erlaubt nur ganzzahlige Eingaben) "); System.out.println("\n"); // Name einlesen System.out.print(" Ihr Name name = sc.nextLine(); : ");

// Gre einlesen System.out.print(" Ihre Koerpergroesse in cm: "); groesse = sc.nextInt(); // Gewicht einlesen System.out.print(" Ihr Gewicht in kg gewicht = sc.nextInt(); : ");

// Person-Objekt erzeugen Person anwender = new Person(name, groesse, gewicht); // Anwenderdaten samt BMI ausgeben System.out.println("\n"); System.out.println(" Name : " + System.out.println(" Groesse : " + + System.out.println(" Gewicht : " + + System.out.println(" BMI : " + } }

anwender.getName() ); anwender.getGroesse() " cm"); anwender.getGewicht() " kg"); anwender.bmi() );

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Klassen Seite 213

Listing 8.10: Aus BMI.java

Abbildung 8.3: Das BMI-Programm

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Vererbung Seite 214

9 Praxisteil: Vererbung
Vererbung ist ein weiteres, ganz wesentliches Konzept der objektorientierten Programmierung, welches es ermglicht, neue Klassen auf der Basis bereits vorhandener Klassen zu definieren. Durch die Vererbung wird festgelegt, dass die neu definierte Klasse, auch abgeleitete oder Sub-Klasse genannt, zustzlich zu den in ihrer Definition aufgefhrten Feldern und Methoden ber smtliche (nicht privaten) Felder und Methoden der Basis- oder Superklasse verfgt. Auf diese Weise kann praktisch jede Klasse von jeder anderen Klasse abgeleitet werden, was jedoch nicht immer sinnvoll ist. Sinnvolle Vererbung erkennt man meist daran, dass das so genannte Ist-ein-Kriterium erfllt ist: Ist-ein-Kriterium: Objekte abgeleiteter Klassen sollten smtliche Eigenschaften der Basisklassen in korrekter Weise teilen, d.h. ein Objekt der abgeleiteten Klasse sollte immer auch als Instanz der Basisklasse angesehen werden kann. So drfte die Ableitung einer Klasse Bungalow von einer Basisklasse Haus sinnvoll sein, da ein Bungalow auch ein Haus ist, whrend die Ableitung von einer Klasse Fahrzeug uerst zweifelhaft ist. Der ernste Hintergrund fr diese Regel ist, dass Objekte abgeleiteter Klassen auch als Objekte ihrer Basisklassen angesehen und eingesetzt werden knnen (Polymorphie, siehe 9.6). Die entsprechenden Typumwandlungen nimmt Java automatisch vor (siehe 5.4). Weitere Vorteile ergeben sich, wenn mehrere Klassen durch Vererbung in eine Klassenhierarchie eingebunden werden: Gemeinsame Eigenschaften von verwandten Klassen (beispielsweise Angestellter, Manager etc.) brauchen durch Verlegung in eine gemeinsame Basisklasse (Mitarbeiter) nur einmal implementiert zu werden, wodurch auch die Wartbarkeit des Quellcodes erleichtert wird. Umgekehrt gewhrt die Ableitung von Basisklassen ein einheitliches Erscheinungsbild verwandter Klassen.

Schlielich ist wichtig zu verstehen, dass bei der Vererbung Implementierung und Schnittstelle vererbt werden.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Vererbung Seite 215

Gerade beim ersten Kontakt mit dem Konzept der Vererbung neigen Programmierer dazu, sie hauptschlich als Mittel zur Wiederverwertung bestehenden Codes anzusehen. Doch hufig ist die Vererbung der ffentlichen Schnittstelle (Namen der public-Felder, Signatur der public-Methoden) viel interessanter, und nicht selten wird die Implementierung der geerbten public-Methoden in den abgeleiteten Klassen sogar durch eigene Implementierungen ersetzt. (berschreibung, siehe 9.3). So knnte die oben angesprochene Klasse Mitarbeiter beispielsweise eine public-Methode gehaltErhoehen() definieren, die in den abgeleiteten Klassen Angestellter und Manager durchaus unterschiedlich implementiert werden kann. Als Basis- oder Superklasse bezeichnet man eine Klasse, die ihre Elemente an eine neu definierte Klasse vererbt. Eine Klasse, die Elemente von einer Basisklasse erbt, bezeichnet man als abgeleitete oder Subklasse.
Icon MERKSATZ

Vererbung versus Einbettung: Der in einer Klassendefinition steckende Code kann nicht nur durch Vererbung, sondern auch durch Einbettung wiederverwendet werden. Einbettung bedeutet dabei, dass eine Klasse A Objekte anderer Klassen als Felder (oder lokale Felder) verwendet. Die Einbettung ist durch das Hat-ein-Kriterium gekennzeichnet. Zur Funktionalitt eines Autos gehrt auch der Motor. Es wre allerdings ein Design-Fehler, eine Klasse Auto deswegen von einer Klasse Motor abzuleiten, denn ein Auto ist kein Motor. Ein Auto hat aber einen Motor, d.h., die Klasse Auto sollte ein Feld vom Typ Motor definieren und sich ber dieses die Motor-Funktionalitt einverleiben.

Icon HINWEIS

9.1

Syntax

Die Basisklasse wird in der Klassendefinition mit dem Schlsselwort extends an den Klassennamen angehngt:
class Klassenname extends Basisklasse { Klassenelemente }

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Vererbung Seite 216

Die Basisklasse vererbt ihre Felder und Methoden an die abgeleitete Klasse. Konstruktoren und private-Elemente werden nicht vererbt. Das folgende, etwas komplexere Beispiel leitet von einer allgemeinen Klasse Konto, die aus einem Paket banking stammt und fr beliebige Kontotypen (Sparkonten, Girokonten, Depotkonten etc.) geschrieben wurde, eine Klasse Girokonto ab, die gegenber dem allgemeinen Konto auch die Einrumung eines Kreditrahmens zulsst.
// aus Konto.java package banking; public class Konto { private String eigentuemer; private int kontonr; private double kontostand; public Konto(String name, int kontonr, double anfBetr) { this.eigentuemer = name; this.kontonr = kontonr; this.kontostand = anfBetr; } public String getEigentuemer() { return eigentuemer; } public int getKontonr() { return kontonr; } public double getKontostand() { return kontostand; } public void einzahlen(double betrag) { kontostand += betrag; } public void abheben(double betrag) { if( (kontostand - betrag) > 0) kontostand -= betrag; } // abgeleitete Klassen sollen den Kontostand direkt // verndern knnen protected void setKontostand(double betrag) { kontostand = betrag; } }

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Vererbung Seite 217

Beachten Sie insbesondere die Definition der protected-Methode setKontostand(), die es abgeleiteten Klassen aus anderen Paketen erlaubt, den Kontostand direkt (statt nur ber die Methoden einzahlen() und abheben()) zu manipulieren. Die abgeleitete Klasse fgt den geerbten Elementen ein neues Feld kreditrahmen hinzu, setzt einen passenden eigenen Konstruktor auf und versieht die geerbte abheben()-Methode mit einer neuen Implementierung (siehe Abschnitt berschreibung):
// aus Girokonto.java public class Girokonto extends banking.Konto { // neues Feld private double kreditrahmen; public Girokonto(String name, int kontonr, double anfBetr) { // ruft Basisklassenkonstruktor auf super(name, kontonr, anfBetr); kreditrahmen = 1000.0; } // passt Implementierung der geerbten Methode an public void abheben(double betrag) { if( (getKontostand() - betrag) > -kreditrahmen) setKontostand(getKontostand() - betrag); } } // aus Programm.java public class Programm { public static void main(String[] args) { Girokonto gk = new Girokonto("Manfred Mustermann", 1002, 100.0); System.out.println("Kontostand: " + gk.getKontostand()); gk.einzahlen(1200); System.out.println("Kontostand: " + gk.getKontostand()); gk.abheben(500);

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Vererbung Seite 218

System.out.println("Kontostand: " + gk.getKontostand()); gk.abheben(2000); System.out.println("Kontostand: " + gk.getKontostand()); } }

Die hier im Compiler-Aufruf verwendete Option -d sorgt dafr, dass die erzeugten .class-Dateien entsprechend ihrer Pakete auf Unterverzeichnisse verteilt werden (betrifft vor allem die Klasse Konto, deren .class-Datei entsprechend ihrem Paket banking in einem Unterverzeichnis banking abgelegt wird). Ansonsten geht der Compiler-Aufruf davon aus, dass die .java-Quelltextdateien alle im aktuellen Verzeichnis zu finden sind. (Siehe auch 4.2.3.)

Icon HINWEIS

9.2

Besonderheiten geerbter Elemente

Bezglich der Programmierung mit geerbten Elementen gibt es einige Besonderheiten zu beachten.

9.2.1 Basisklassenelemente bilden ein Unterobjekt


Ein Punkt, den Sie bei der Vererbung nie aus den Augen verlieren sollten, ist, dass die von der Basisklasse geerbten Elemente in den Objekten der abgeleiteten Klasse Unterobjekte bilden.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Vererbung Seite 219

abgeleitetes Objekt Objekt der Basisklasse

Abbildung 9.1: Abgeleitetes Objekt und Unterobjekt der Basisklasse Dies hat durchaus Konsequenzen fr die Programmierung.
class Basis { public int wert = 0; public void ausgeben() { System.out.println("Wert = " + wert); } } class Abgeleitet extends Basis { public int wert; public void erhoehen() { wert += 10; }

class Demo { public static void main(String[] args) { Abgeleitet obj = new Abgeleitet(); obj.wert = 5; obj.erhoehen();

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Vererbung Seite 220

obj.ausgeben(); } }

Hier definiert die abgeleitete Klasse Abgeleitet ein eigenes Feld mit Namen wert. Die Ausgabe des Programms lautet aber nicht 15, wie man erwarten knnte, sondern 0. Warum? Die Anweisung
obj.wert = 5;

weist dem Feld wert der abgeleiteten Klasse den Wert 5 zu. Die Methode erhoehen() addiert zu diesem Wert noch einmal 10. Die Methode ausgeben() gibt jedoch nicht das in der abgeleiteten Klasse neu definierte Feld wert aus. Da die Methode ausgeben() Teil des in obj enthaltenen anonymen Basisklassenunterobjekts ist, greift sie auf die Elemente dieses Unterobjekts zu, d.h., die Methode ausgeben() gibt den Wert des Felds wert aus dem Basisklassenunterobjekt aus (das mit 0 initialisiert wurde). Geerbte Methoden verwenden immer die Methoden und Felder aus dem Basisklassenunterobjekt selbst dann, wenn gleichnamige Elemente in der abgeleiteten Klasse neu definiert wurden.
Icon MERKSATZ

9.2.2 Der Zugriffsspezifizierer protected


Durch die Vererbung kommt nun endlich ein Zugriffsspezifizierer zur Geltung, den wir bislang berhaupt nicht beachtet haben: protected. Wenn Sie neue Klassen aufsetzen, die als Basisklassen fr anderen Klassen gedacht sind oder von denen Sie annehmen, dass der eine oder andere Programmierer sie vielleicht als Basisklassen nutzen wird, sollten Sie sich berlegen, ob sie nicht einige der private-Elemente der Klasse als protected deklarieren wollen (siehe die Methode setKontostand() der Klasse Konto aus dem Einfhrungsbeispiel). Das Schlsselwort protected bedeutet, dass das so deklarierte Element nicht ber Objekte (im Falle statischer Elemente ber den Klassennamen) aufgerufen, dass man es aber innerhalb der Methoden abgeleiteter Klassen

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Vererbung Seite 221

verwenden kann. Aus Sicht der Auenwelt ist ein solches Element also private, aus Sicht der abgeleiteten Klasse public.

9.2.3 Aufruf des Basisklassenkonstruktors


Dass die geerbten Elemente in den Objekten der abgeleiteten Klasse Unterobjekte bilden, hat auch zur Folge, dass zur Einrichtung der geerbten Elemente ihr eigener Konstruktor aufgerufen wird. Was passiert, wenn Sie ein Objekt der abgeleiteten Klasse Abgeleitet erzeugen?
Abgeleitet obj = new Abgeleitet();

Zuerst wird der Konstruktor der Klasse Abgeleitet aufgerufen. Dieser richtet das Objekt im Speicher ein. Dabei stellt er fest, dass das Objekt der Klasse Abgeleitet ber ein Unterobjekt der Basisklasse Basis verfgt. Zur Einrichtung dieses Unterobjekts ruft er den passenden Konstruktor der Klasse Basis auf. Betrachten wir dazu einmal folgenden Code:
class Basis { protected int wert = 0; public Basis(int n) { wert = n; } public void ausgeben() { System.out.println("Wert = " + wert); } } class Abgeleitet extends Basis { public void erhoehen() { wert += 10; } }

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Vererbung Seite 222

Wenn wir jetzt versuchen, ein Objekt der Klasse Abgeleitet zu erzeugen:
Abgeleitet obj = new Abgeleitet();

ernten wir vom Compiler eine Fehlermeldung, dass er keinen Konstruktor von Basis findet, den er ohne Argument aufrufen kann. Die Erklrung ist nicht schwer: Da die Klasse Basis einen eigenen Konstruktor definiert, erzeugt der Compiler keinen Standardkonstruktor. Zur Einrichtung des Basisklassenunterobjekts im Zuge der Erzeugung des Objekts der abgeleiteten Klasse wird aber ein Konstruktor ohne Argument bentigt. Wir knnen dieses Problem auf zwei Arten beheben: Wir definieren in der Klasse Basis zustzlich zu dem Konstruktor Basis(int n) einen weiteren Konstruktor, der ohne Argument aufgerufen werden kann: Basis(). Wir definieren in der Klasse Abgeleitet einen Konstruktor, der zur Erzeugung des Basisklassenunterobjekts explizit den Basisklassenkonstruktor Basis(int n) aufruft.

class Basis { protected int wert = 0; public Basis(int n) { wert = n; } public void ausgeben() { System.out.println("Wert = " + wert); } } class Abgeleitet extends Basis { public Abgeleitet(int n) { super(n); } public void erhoehen() { wert += 10;

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Vererbung Seite 223

} } class Demo { public static void main(String[] args) { Abgeleitet obj = new Abgeleitet(12); obj.wert = 5; obj.erhoehen(); obj.ausgeben(); } }

Wie man unschwer erkennen kann, wird der Basisklassenkonstruktor ber das Schlsselwort super aufgerufen. Die Argumente, die Sie dem Basisklassenkonstruktor bergeben mchten, hngen Sie einfach wie bei einem normalen Konstruktoraufruf in runden Klammern an das Schlsselwort super an. Wo opportun, knnen Sie wie im obigen Beispiel die zu bergebenden Argumente ber Parameter des abgeleiteten Konstruktors entgegennehmen und an den Basisklassenkonstruktor weiterreichen.

9.3

berschreibung

berschreibung bedeutet, dass die abgeleitete Klasse eine geerbte Methode mit einer eigenen Implementierung versieht. berschreibung ist die Grundlage der Polymorphie (siehe 9.6). berschreibung liegt vor, wenn eine geerbte Methode mit gleicher Signatur in der abgeleiteten Klasse neu definiert wird.
class Basis { void methode() { System.out.println("Dies ist die Basisklasse"); } } class Abgeleitet extends Basis { // berschreibung void methode()

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Vererbung Seite 224

{ System.out.println("Dies ist die abgeleitete Klasse"); } }

Wird spter ein Objekt der Klasse Abgeleitet erzeugt und fr dieses methode() aufgerufen, wird stets die berschreibende Version ausgefhrt.
Abgeleitet obj = new Abgeleitet(); obj.methode(); // Ausgabe: Dies ist die abgeleitete Klasse

Eine berschriebene Methode kann in der abgeleiteten Klasse ber die super-Referenz aufgerufen werden. Meist wird dies genutzt, um die berschreibende Methode mithilfe der berschriebenen zu definieren (vgl. auch Konstruktor aus Einfhrungsbeispiel). Der Zugriffsschutz (private, Standard, protected, public) kann durch die berschreibung gelockert, nicht aber verstrkt werden.
Icon ACHTUNG

9.4

Die Klasse Object

Alle in Java definierten Klassen gehen auf eine oberste Basisklasse zurck: Object aus dem Paket java.lang. Diese Rckfhrung smtlicher Klassen und Arrays auf eine Basisklasse ist von groer Bedeutung fr die Programmierung, und zwar in zweierlei Hinsicht: Erstens kann jeder Klassen- oder Array-Typ in den Typ Object umgewandelt werden. Zweitens erbt jede Klasse und jedes Array die in Object definierten Elemente.

Die Methoden von Object Die Klasse Object definiert zwei Gruppen von Methoden. Die erste Gruppe dient der Thread-Synchronisierung:
void notify() void notifyAll() void wait()

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Vererbung Seite 225

void wait(long timeout) void wait(long timeout, int nanos)

Diese Methoden sind fertig implementiert und knnen nicht berschrieben werden! In der zweiten Gruppe sind die allgemein ntzlichen Methoden zusammengefasst, die abgesehen von getClass() von abgeleiteten Klassen bei Bedarf berschrieben und so klassenspezifisch implementiert werden knnen:
Methode protected Object clone() Beschreibung Erzeugt eine Kopie des aktuellen Objekts und liefert diese zurck.

boolean equals(Object obj)

Testet zwei Objekte auf Gleichheit. Die von Object vorgegebene Implementierung liefert true, wenn die Referenzen auf das aktuelle Objekt und das Argument identisch sind arbeitet also genauso wie der ==-Operator fr Referenzen. Diese Methode wird vom Garbage Collector (Speicherbereinigung) aufgerufen, wenn das Objekt aufgelst wird. Die von Object vorgegebene Implementierung tut nichts. Abgeleitete Klassen knnen diese Methode berschreiben, wenn ihre Objekte irgendwelche Systemressourcen freigeben oder sonstige Aufrumarbeiten verrichten mchten.

protected void finalize()

Class getClass()

Liefert die Laufzeitklasse des Objekts zurck; kann nicht berschrieben werden. Die Java Virtual Machine erzeugt fr jede im Programm verwendete Klasse eine Instanz der Java-Klasse Class. Wenn Sie ber ein Objekt obj die Methode getClass() aufrufen, liefert die Methode eine Referenz auf die ClassInstanz zurck, die den Typ von obj reprsentiert. Da fr ein und dieselbe Klasse immer dieselbe

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Vererbung Seite 226

Referenz zurckgeliefert wird, knnen Sie die Referenzen direkt fr Typvergleiche nutzen: if (obj1.getClass() == obj2.getClass()) Um auch Vergleiche mit Klassennamen durchfhren zu knnen, gibt es eine spezielle Syntax: if (obj1.getClass() == Klassenname.class) int hashCode() Liefert einen Hashcode fr das Objekt zurck, wie er beispielsweise von Objekten verlangt wird, die als Schlssel zu Hashtabellen (Instanzen von java.util.Hashtable oder java.util.HashMap) verwendet werden. Die von Object vorgegebene Implementierung liefert einen fr jedes Objekt eindeutigen IntegerWert (meist wird die Methode so implementiert, dass sie die Speicheradresse des Objekts zurckliefert). String toString() Liefert eine String-Darstellung des Objekts zurck. Die von Object vorgegebene Implementierung setzt den String aus den Rckgabewerten von getClass() und getHashCode() zusammen: getClass().getName() + "@" + Integer.toHexString(hashCode());

Tabelle 9.1: Allgemein ntzliche Methoden aus Object

9.5

bung 7: toString() berschreiben

Aufgabenstellung Kopieren Sie die Quelldateien des Vektorprogramms aus Tutorium 8 und implementieren Sie fr die Klasse Vektor eine passende berschreibung von toString(). ndern Sie anschlieend den Code der Klasse Vektorprogramm, um von der neuen Mglichkeit zur Ausgabe zu profitieren.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Vererbung Seite 227

Falls Sie Schwierigkeiten mit der Lsung haben, blttern Sie noch einmal zurck zu 4.5.2. Dort haben wir schon einmal toString() berschrieben. Lsung
public class Vektor { public double x; public double y; public Vektor() { x = 0; y = 0; } public Vektor(double x, double y) { this.x = x; this.y = y; } public Vektor addieren(Vektor v) { return new Vektor(x + v.x, y + v.y); } public Vektor subtrahieren(Vektor v) { return new Vektor(x - v.x, y - v.y); } public String toString() { return "(" + x + "," + y + ")"; } }

Listing 9.1: Aus Vektor.java


public class Vektorprogramm { public static void main(String[] args) { Vektor v1 = new Vektor(10, 10);

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Vererbung Seite 228

Vektor v2 = new Vektor(5, 5); Vektor v3 = v1.addieren(v2); System.out.println(" v3: " + v3); Vektor v4 = v1.subtrahieren(v2); System.out.println(" v4: " + v4); } }

Listing 9.2: Aus Vektorenprogramm.java

9.6

Polymorphie

Der Begriff stammt aus dem Griechischen und bedeutet soviel wie Vielgestaltigkeit eine Anspielung darauf, dass sich bei der Programmierung mit Polymorphie hinter einem Namen ganz unterschiedliche Umsetzungen des Konzepts verbergen knnen, fr das der Name steht. In Java grndet die Polymorphie auf zwei Konzepten: der berschreibung von Methoden in abgeleiteten Klassen (siehe oben) der Implementierung von Interfaces (siehe Exkurs Schnittstellen)

Im ersten Fall vererbt die Basisklasse eine oder mehrere Verhaltensweisen in Form von Methoden an ihre abgeleiteten Klassen. Diese knnen die geerbten Methoden berschreiben und auf diese Weise klassenspezifisch implementieren. Die Objekte der abgeleiteten Klassen verfgen dann ber die gleichen Verhaltensweisen, jedoch in unterschiedlicher Ausprgung. Im zweiten Fall gibt die Interface-Definition die Verhaltensweisen vor und alle Klassen, die das Interface implementieren, verpflichten sich, diese Verhaltensweisen sinnvoll und klassenspezifisch anzubieten. Das folgende Beispiel leitet zwei Klassen Rechteck und Kreis von einer gemeinsamen Basisklasse ZeichenObjekt ab. Die Klasse ZeichenObjekt vererbt eine Methode zeichnen(), die in den abgeleiteten Klassen berschrieben wird.
class ZeichenObjekt { void zeichnen()

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Vererbung Seite 229

{ System.out.print(" "); } } class Rechteck extends ZeichenObjekt { void zeichnen() { System.out.print("[]"); } } class Kreis extends ZeichenObjekt { void zeichnen() { System.out.print("o"); } } public class PolymorphieDemo { public static void main(String[] args) { Rechteck r1 = new Rechteck(); Kreis k1 = new Kreis(); Rechteck r2 = new Rechteck(); r1.zeichnen(); k1.zeichnen(); r2.zeichnen();

} }

Ausgabe:
[]o[]

Richtig wertvoll wird die Polymorphie fr den Programmierer erst durch die die Speicherung von Objektreferenzen in Variablen von Basisklassen- oder Interface-Typen und die dynamische Bindung (siehe unten).

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Vererbung Seite 230

9.6.1 Dynamische Bindung


In Java knnen Sie die Referenz auf ein Objekt ohne Probleme in einer Variablen vom Typ einer Basisklasse des Objekts oder eines Interfaces, das die Klasse des Objekts implementiert, speichern.
class Basis { void methode() { System.out.println("Dies ist die Basisklasse"); } } class Abgeleitet extends Basis { void methode() { System.out.println("Dies ist die abgeleitete Klasse"); } } //... Basis obj = new Abgeleitet();

berschreibt die abgeleitete Klasse dabei, wie im obigen Beispiel, eine geerbte Methode und wird diese Methode ber die Objektreferenz vom Basisklassentyp aufgerufen, stellt sich die Frage, welche Implementierung der Methode aufgerufen wird: die vom Typ des Objekts (hier Abgeleitet) oder die vom Typ der Objektreferenz (hier Basis). In Java wird in solchen Fllen immer die Methodenimplementierung vom Typ des Objekts ausgefhrt.
obj.methode(); // Ausgabe: Dies ist die abgeleitete Klasse

Der Objekttyp und die aufzurufende Methode werden dabei zur Laufzeit vom Interpreter ermittelt, weswegen man auch von dynamischer Bindung spricht. Zugriff ber Objektreferenzen Der Typ einer Objektreferenz legt fest, auf welche Elemente des Objekts Sie zugreifen knnen. Wenn Sie eine Objektreferenz in einer Variablen eines Basisklassentyps speichern, knnen Sie ber die Objektreferenz nur auf diejenigen

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Vererbung Seite 231

Elemente des Objekts zugreifen, die in der Basisklasse definiert sind so als handelte es sich tatschlich nur um ein Objekt der Basisklasse. Der Typ des Objekts legt fest, welche Implementierung fr polymorphe (berschriebene) Methoden ausgefhrt wird. Wenn Sie ber eine Objektreferenz vom Typ einer Basisklasse eine Methode der Basisklasse aufrufen, die in der (abgeleiteten) Klasse des Objekts berschrieben ist, wird die Implementierung der (abgeleiteten) Klasse des Objekts ausgefhrt.

Arrays von Basisklassenelementen Gegeben sei die auf ZeichenObjekt grndende Klassenhierarchie, die eingangs dieses Unterkapitels vorgestellt wurde:
class ZeichenObjekt { void zeichnen() { System.out.print(" "); } } class Rechteck extends ZeichenObjekt { void zeichnen() { System.out.print("[]"); } } class Kreis extends ZeichenObjekt { void zeichnen() { System.out.print("o"); } }

Objekte dieser Klassen knnen Sie gemeinsam in einem Array von ZeichenObjekt-Elementen verwalten. Sie knnen sogar die einzelnen Objekte zeichnen lassen. Die Definition der Methode zeichnen() in ZeichenObjekt sorgt dafr, dass Sie die Methode ber die

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Vererbung Seite 232

ZeichenObjekt-Referenzen aufrufen knnen, die berschreibung von zeichnen() in den abgeleiteten Klassen sorgt dafr, dass jedes Objekt gem seinem Klassentyp gezeichnet wird.
public class PolymorphieDemo { public static void main(String[] args) { ZeichenObjekt[] elemente = new ZeichenObjekt[3]; elemente[0] = new Rechteck(); elemente[1] = new Kreis(); elemente[2] = new Rechteck(); for (ZeichenObjekt elem : elemente) elem.zeichnen(); System.out.println(); } }

Ausgabe:
[]o[]

Methoden mit Basisklassen- (oder Interface-)Parametern Gegeben sei die oben abgedruckte, auf ZeichenObjekt grndende Klassenhierarchie. Objekte dieser Klassen knnen Sie an jede Methode bergeben, die einen Parameter vom Typ ZeichenObjekt definiert.
public class Basisklassenparameter { static void elementeZeichnen(ZeichenObjekt zo) { zo.zeichnen(); } public static void main(String[] args) { Rechteck r1 = new Rechteck(); Kreis k1 = new Kreis(); Rechteck r2 = new Rechteck(); elementeZeichnen(r1);

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Vererbung Seite 233

elementeZeichnen(k1); elementeZeichnen(r2); System.out.println(); } }

9.6.2 Typidentifizierung zur Laufzeit


Wenn Sie eine Objektreferenz in einer Variablen vom Typ einer Basisklasse (oder einem implementierten Interface) speichern, knnen Sie ber die Objektreferenz nur noch auf die in der Basisklasse definierten Elemente zugreifen (bzw. dem Interface implementierten Elemente). Um wieder auf alle Elemente der Klasse des Objekts zugreifen zu knnen, mssen Sie den Typ der Objektreferenz mittels Casting rckverwandeln.
class Basis { void eineMethode() { ... } } class Abgeleitet extends Basis { void eineMethode() { ... } void andereMethode() { ... } } //... Basis obj = new Abgeleitet(); obj.eineMethode(); obj.andereMethode(); ((Abgeleitet) obj).andereMethode();

// okay // Fehler // okay

Wenn der tatschliche Typ des Objekts erst zur Laufzeit festgestellt werden kann, mssen Sie ihn mithilfe des instanceof-Operators ermitteln. instanceof Klassentyp eines Objekts feststellen
if (OBJEKTREFERENZ instanceof KLASSENNAME)

Der instanceof-Operator verhlt sich so, wie der Versuch einer impliziten oder expliziten Typumwandlung, nur dass die Typumwandlung nicht durchgefhrt, sondern simuliert und ihr Ergebnis als boolescher Wert zurckgeliefert wird. Dies bedeutet im Einzelnen:

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Praxisteil: Vererbung Seite 234

Der Operator liefert true zurck, wann immer eine automatische Typumwandlung vom Typ des Objekts in den angegebenen Klassentyp mglich ist. Mit anderen Worten: Der Operator liefert true, wenn Sie ein Objekt mit seiner eigenen Klasse oder einer seiner Basisklassentypen (Upcast) vergleichen. Der Operator liefert false, wenn nur eine explizite Typumwandlung mglich ist (Downcast), also beispielsweise wenn Sie ein echtes Basisklassenobjekt mit dem Typ einer abgeleiteten Klasse vergleichen. Der Vergleich erzeugt eine Fehlermeldung des Compilers, wenn Vergleiche zwischen Typen durchgefhrt werden, die weder durch Upnoch durch Downcast ineinander umwandelbar sind.

Basis obj = new Abgeleitet(); if (obj instanceof Abgeleitet) // liefert true ((Abgeleitet) obj).andereMethode();

Der instanceof-Operator ist zur Rckumwandlung von polymorphen Objektvariablen immer die erste Wahl. Gelegentlich werden Sie aber auch Typen vergleichen wollen, die sich mit dem instanceof-Operator nicht vergleichen lassen. In diesem Fall knnen Sie auf die in Object definierte Methode getClass() zurckgreifen.

Up- und Downcast Die Umwandlung eines abgeleiteten Klassentyps in einen seiner Basisklassentypen bezeichnet man als Upcast, die umgekehrte Richtung als Downcast.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Collections Seite 235

10 Exkurs: Collections
Unter einer Collection versteht man in der Java-Programmierung einen besonderen Behlter, in dem man Daten in Form von Objekten ablegen und bei Bedarf ber geeignete Methoden wieder darauf zugreifen kann. Je nachdem, wie der Behlter intern die ihm anvertrauten Objekte speichert und verwaltet, hat er besondere Charakteristiken (Zugriffsgeschwindigkeit, Einfgegeschwindigkeit etc.).

10.1 Allgemeines
In der Informatik unterscheidet man blicherweise drei Arten von Containern, die von einer Vielzahl von Klassen im Paket java.util realisiert werden:
Listen

Eine Liste ist eine sequenzielle Anordnung von Elementen mit einer festen Reihenfolge (nmlich so, wie sie eingefgt worden sind). Implementiert werden Listen von den Collection-Klassen ArrayList und LinkedList.
Mengen

Eine Menge enthlt jedes Element nur einmal und es existiert dabei keine bestimmte Reihenfolge. Implementierende Klassen sind TreeSet und HashSet, wobei TreeSet im Widerspruch zur reinen Mengendefinition doch eine Ordnung besitzt: Die Elemente werden nach ihrer natrlichen Ordnung beim Einfgen sortiert; fr Strings bedeutet dies eine lexikographische, fr Zahlen eine aufsteigende Sortierung.
Hashtabellen (Wrterbcher)

Eine Hashtabelle ist eine Menge von Schlssel/Werte-Paaren. Der Schlssel ist dabei typischerweise ein String, der Wert ein Objekt (analog zu einem Wrterbuch mit Stichwrtern als Schlssel und der dazu gehrigen bersetzung als Wert). Alle genannten Container-Klassen implementieren zwei wichtige Interfaces:

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Collections Seite 236

java.util.Collection definiert die allgemeinen Zugriffsmethoden zum Einfgen und Auslesen von Objekten in einen Container java.util.Iterator definiert Methoden zum Durchlaufen aller Objekte in einem Container

Aufgrund dieser Interfaces haben alle Container-Klassen eine Grundmenge an identischen Zugriffsmethoden (und zudem noch containerspezifische Methoden); der wesentliche Unterschied liegt jeweils in der Zugriffsgeschwindigkeit, sodass man sich bei der Wahl eines Containers berlegen muss, welche typischen Operationen das Programm darauf ausfhren soll.

10.2 Container anlegen


Das Anlegen eines Containers erfolgt mit dem entsprechenden Konstruktor unter Angabe des gewnschten Datentyps fr die Objekte, die darin verwaltet werden sollen, z. B.:
LinkedList<String> liste = new LinkedList<String>(); HashMap<String, Date> tab = new HashMap<String, Date>();

Natrlich sind hierbei auch selbst definierte Klassen mglich, z. B. fr eine Klasse Kunde:
TreeSet<Kunde> kunden = new TreeSet<Kunde>(); HashMap<String,String> map; map = new HashMap<String,String>(1000);

Anmerkungen

Grundstzlich haben alle Container eine unbegrenzte Gre und wachsen dynamisch mit, wenn mehr und mehr Objekte abgelegt werden. Fr Container, die intern auf Hashtabellen basieren (z. B. HashMap, HashSet), kann es jedoch Sinn machen, bei der Erzeugung eine Startgre mitzugeben, die ca. 1,5-mal so gro sein sollte wie die zu erwartende Anzahl an Elementen, die man verwalten mchte. Dies erspart zeitaufwndige Vergrerungsoperationen und beschleunigt auch alle Zugriffe, da interne Kollisionen minimiert werden.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Collections Seite 237

10.3 Objekte ablegen und auslesen


Da alle Container-Klassen das Interface Collection implementieren, kann man die Methoden add() zum Hinzufgen eines Objekts sowie remove()zum Lschen voraussetzen; das Auslesen erfolgt mit get(). Auerdem stehen einige Verwaltungsmethoden wie clear() (alle Objekte lschen) und size() (Anzahl der gespeicherten Objekte) zur Verfgung:
LinkedList<String> namen = new LinkedList<String>(); namen.add(Jim); System.out.println(Anzahl: + namen.size()); namen.remove(0); // erstes Element lschen

Je nach Container gibt es ferner spezifische Zugriffsmethoden, beispielsweise addFirst() und getFirst() fr Listen oder put()/get() zum Einfgen/Auslesen eines Schlssel/Werte-Paares in eine Hashtabelle.
LinkedList<String> liste = new LinkedList<String>(); liste.addFirst(Anfang); liste.addLast(Ende); liste.add(1, Mitte); String m = liste.get(1); liste.remove(0); HashMap<String,Integer> map = new HashMap<String,Integer>(); map.put(Start, new Integer(343)); map.put(Ende, 500); // mit Autoboxing int wert = map.get(Start); // Auto-Unboxing

Anmerkungen

Beim Einfgen in einen Container wird lediglich die Referenz auf das entsprechende Objekt bergeben; es wird keine Kopie des Objekts erzeugt.

10.4 Container-Auswahl
Die wichtigste Frage beim Einsatz von Collection-Klassen ist natrlich: Wann soll man welchen Container verwenden? Dies hngt sehr stark vom jeweiligen Problem ab, aber die Erfahrung zeigt, dass HashMap fast immer die ideale Wahl ist, wenn die Reihenfolge der Elemente keine Rolle spielt;

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Collections Seite 238

Einfgen, Lschen und Suchen/Zugriff verlaufen in fast konstanter Zeit und sind extrem schnell. Wenn die Reihenfolge wichtig ist, sollte man vorrangig ArrayList oder LinkedList verwenden. LinkedList ist vorzuziehen, wenn viele Einfge-/Lschoperationen durchgefhrt werden sollen; ArrayList ist besser, wenn mit get(int pos) auf Elemente an einer bestimmten Position zugegriffen werden muss.
Beispiel: Mengen-Container

Das folgende Beispiel zeigt den Einsatz einer TreeSet-Menge, um die Ziehung der Lottozahlen durchzufhren. Die Mengeneigenschaft garantiert dabei, dass keine Zahl doppelt vorkommt (dann schlgt add() fehl). Auerdem speichert TreeSet die Zahlen nach ihrer natrlichen Ordnung, sodass sie automatisch aufsteigend sortiert sind:
TreeSet<Integer> gezogen = new TreeSet<Integer>(); Random zufall = new Random(); while(gezogen.size() != 6) { int z = zufall.nextInt(50); if(z == 0) continue; // zahl speichern boolean status = gezogen.add(z); } System.out.println("Die Lottozahlen:"); for(Integer i : gezogen) System.out.print(i + " ");

10.5 Iteratoren
Ein Iterator ist ein besonderes Objekt, das dazu dient, die Elemente eines Containers nacheinander zu durchlaufen. Man kann die Funktionsweise eines Iterators vereinfacht mit einer normalen for-Schleife vergleichen, mit der man ein Array durchluft: Zu Beginn steht die Schleifenvariable auf der Position mit dem ersten Element, nach der Inkrementierung zeigt sie auf das

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Collections Seite 239

nchste Element, usw. Wichtig ist der Umstand, dass man nur vom Anfang zum Ende laufen kann; Hin- und Herspringen oder mal vorwrts, dann rckwrts laufen ist auer bei Listen nicht mglich. In Java werden Iteratoren durch das Interface java.util.Iterator bereitgestellt. Die wesentlichen Methoden sind: boolean hasNext() liefert true, wenn es noch nicht besuchte Elemente gibt. E next() liefert das nchste Element als Typ E aus dem Container.

Ein Iterator-Objekt kann man nicht selbst anlegen, sondern besorgt es sich mit der iterator()-Methode vom Container-Objekt. Der Iterator ist dabei mit dem gleichen Klassentyp wie der Container parametrisiert.
Beispiel: Collections mit Iteratoren durchlaufen

Im folgenden Beispiel wird per Iterator eine Menge durchlaufen und werden die besuchten Elemente ausgegeben:
HashSet<String> namen = new HashSet<String>(); //...hier Menge fllen // Elemente auslesen Iterator<String> it = namen.iterator(); while(it.hasNext()) { String str = it.next(); System.out.println(str); }

Seit der Java-Version J2SE 1.5 kann auch die for-each-Schleife zum bequemen Durchlaufen eines Containers verwendet werden, was sehr bequem ist und somit in Zukunft den Einsatz von Iterator-Objekten grtenteils berflssig machen drfte:
HashSet<String> namen = new HashSet<String>(); // ...hier Menge fllen // Elemente auslesen for(String str : namen) {

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Collections Seite 240

System.out.println(str); }

Anmerkungen

Hashtabellen bieten keine iterator()-Methode an, da sie zum Durchlaufen nicht gedacht sind. Eine gewisse Abhilfe bietet die Methode keySet(), die alle Schlssel als Menge vom Typ Set zurckliefert und fr die man dann iterator() aufrufen kann. Neben dem Iterator-Interface existiert noch das Interface java.util.Enumeration, die ebenfalls eine einfache IteratorFunktionalitt, basierend auf den Methoden boolean hasMoreElement() E nextElement()

zum Durchwandern der Elemente anbietet.

10.6 Suchen und Sortieren in Containern


Das Paradewerkzeug zum schnellen Suchen von Objekten sind Hashtabellen wie HashMap. Bei ihnen muss man nur den zu suchenden Schlssel einer get()-Methode bergeben und erhlt prompt das zugehrige Objekt. Das Tolle dabei ist, dass eine solche Suche unabhngig von der Gre der Hashtabelle ist, d.h., ob Sie 100 oder 10 000 Eintrge haben, spielt keine merkliche Rolle fr die Suchzeit. Diesen Vorteil erkauft man sich mit dem Nachteil, dass man keine Reihenfolge der abgespeicherten Elemente hat und sie somit auch nicht sortieren kann. Zum Sortieren eignen sich vor allem Listen, also beispielsweise LinkedList und ArrayList. Hierfr stellt die Java-Bibliothek die Klasse java.util.Collections mit entsprechenden statischen Methoden zum Sortieren zur Verfgung. Natrlich kann man in einer Liste auch suchen. Entweder nimmt man die Methode contains(), die sequenziell alle Elemente durchluft und prft (und somit sehr langsam sein kann), oder verwendet die Methode Collections.binarySearch(), die allerdings voraussetzt, dass die Liste sortiert ist.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Collections Seite 241

Beispiel: In Listen suchen


ArrayListe<String> namen = new ArrayList<String>(); // Liste fllen // Liste alphabetisch sortieren Collections.sort(namen); // binr suchen // liefert Position bei Erfolg int pos = Collections.binarySearch(Julia);

Eigene Vergleichskriterien Etwas schwieriger wird das Sortieren einer Liste, wenn Objekte vorliegen, die nicht ohne Weiteres miteinander verglichen werden knnen, z. B. eine Liste von Kunden einer selbst definierten Klasse Kunde. Nach welchem Kriterium soll verglichen werden? Hierzu muss man eine Klasse definieren, welche das Interface java.util.Comparator<E> mit der Methode int compare(E o1, E o2) implementiert. Sie muss fr o1 < o2 einen negativen Wert, fr o1 = o2 den Wert 0 und sonst ein positives Ergebnis liefern (siehe Fortgeschrittenenliteratur).

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Schnittstellen Seite 242

11 Exkurs: Schnittstellen
Bei der normalen Vererbung gibt die Basisklasse sowohl ihre ffentliche Schnittstelle (Name und Signatur der public-Elemente) als auch die Implementierung der vererbten Methoden an die abgeleitete Klasse weiter. Oftmals ist die Schnittstelle aber interessanter als die von der Basisklasse vorgegebene Implementierung. Java kennt daher zwei Techniken, wie allein die Schnittstelle vererbt werden kann: Abstrakte Methoden und Interfaces

11.1 Abstrakte Methoden und Klassen


In Tutorium 9.3 wurde beschrieben, wie der Autor einer abgeleiteten Klasse nicht-private, nicht-statische Methoden nach Bedarf berschreiben und auf diese Weise mit einer eigenen, klassenspezifischen Implementierung verbinden kann. Die Entscheidung, ob eine geerbte Methode berschrieben wird, fllt dabei allein der Autor der abgeleiteten Klasse. Will der Autor der Basisklasse erzwingen, dass eine bestimmte Methode in den abgeleiteten Klassen berschrieben werden muss, deklariert er die Methode als abstract und verzichtet auf die Angabe eines Methodenkrpers:
abstract Rckgabetyp mehtodenname(Parameter)

Die abstract-Deklaration hat allerdings Folgen fr die Klasse selbst: Die Klasse wird zur abstrakten Klasse und muss selbst ebenfalls mit dem Schlsselwort abstract deklariert werden. Die Klasse kann nicht instanziert werden.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Schnittstellen Seite 243

Beispiel: Abstrakte Klassen


abstract class Basis { abstract void methode() { System.out.println("Diese Methode muss berschrieben" + " werden"); } }

Anmerkungen

Eine abgeleitete Klasse, die eine abstrakte Methode erbt und nicht implementiert (berschreibt), wird selbst zur abstrakten Klasse.

11.2 Interfaces
Interfaces entsprechen in etwa abstrakten Klassen, die ausschlielich abstrakte public-Methoden definieren. Dies bedeutet unter anderem, dass von Interfaces keine eigenen Objekte erzeugt werden knnen. Vielmehr sind Interfaces dazu gedacht, von Klassen implementiert zu werden. Objekte einer Klasse, die ein Interface implementiert, knnen aber als Objekte des Interface angesehen werden oder anders ausgedrckt: Einer Variablen vom Typ eines Interface kann jedes Objekt zugewiesen werden, dessen Klasse das Interface implementiert. Interfaces befreien das Konzept der Polymorphie von der Bindung an Vererbungshierarchien. knnen als Vertrag zwischen Autor und Benutzer von Klassen/Methoden fungieren.

11.2.1 Interfaces und Polymorphie


Bei der auf Vererbung und der berschreibung von geerbten Methoden grndenden Polymorphie nutzt man den Umstand, dass Referenzen auf Objekte abgeleiteter Klassen in Variablen vom Typ einer Basisklasse gespeichert werden knnen. Wird ber eine solche Referenz eine berschriebene Methode aufgerufen, wird nicht die Implementierung des Basisklassentyps, sondern des Objekttyps ausgefhrt.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Schnittstellen Seite 244

Analog knnen Sie Referenzen auf Objekte, deren Klasse ein Interface implementiert, in Variablen vom Typ des Interface speichern. Wenn Sie ber eine solche Referenz eine Interface-Methode aufrufen (andere Elemente des Objekts knnen auf diesem Wege nicht aufgerufen werden), wird die Implementierung des Klassentyps des Objekts ausgefhrt.

11.2.2 Interfaces als Vertrge


Angenommen, Sie mchten eine Methode implementieren, die Sie anderen Programmierern zur Verfgung stellen wollen und die (prinzipiell) beliebige Objekte verarbeitet beispielsweise zeichnet. Dabei ergeben sich zwei Probleme: In Variablen/Parametern welchen Typs knnen Sie die Objekte speichern? Wie knnen Sie erreichen, dass die Objekte von der Methode individuell verarbeitet werden? Eine Zeichenmethode knnte beispielsweise berechnen, wo die Objekte gezeichnet werden sollen (im nachfolgenden Beispiel hintereinander durch Leerzeichen getrennt), tte sich aber schwer, das Objekt selbst adquat zu zeichnen insbesondere wenn der Methode spter Objekte bergeben werden, deren Typ dem Autor der Methode berhaupt nicht bekannt war. Polymorphie innerhalb einer Klassenhierarchie wre hier nur eine unbefriedigende Lsung. Zwar knnten dann alle Objekte in Parametern vom Typ der gemeinsamen Basisklasse gespeichert werden und zum korrekten Zeichnen der Objekte knnte die Basisklasse eine Methode zeichnen() vererben, die in den abgeleiteten Klassen berschrieben wird, doch dafr wrde dieses Verfahren Klassen, die nicht von der besagten Basisklasse abgeleitet sind, ausschlieen. Programmierer, die Ihre Methode zum Zeichnen eigener Objekte nutzen mchten, jedoch keine Mglichkeit haben, die Klassen der zu zeichnenden Objekte von der besagten Basisklasse abzuleiten, wren enttuscht. Die Lsung wre die Definition eines Interface-Typs, der eine Methode zeichnen() vorgibt. Die allgemeine Zeichenmethode, nennen wir sie elementeZeichnen(), knnte dann einen Parameter vom Typ des Interface definieren und intern zum individuellen Zeichnen der Objekte die Methode zeichnen() aufrufen. Der Kontrakt, den das Interface

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Schnittstellen Seite 245

reprsentiert, lautet: Jede Klasse, die das Interface implementiert, kann an die Methode elementeZeichnen() bergeben und von ihr gezeichnet werden.
Beispiel: Interfaces
interface Zeichenbar { void zeichnen(); } class Rechteck extends Form implements Zeichenbar { public void zeichnen() { System.out.print("[]"); } } class Schlange extends Reptil implements Zeichenbar { public void zeichnen() { System.out.print("~"); } } public class InterfaceDemo { static void elementeZeichnen(Zeichenbar zo) { zo.zeichnen(); System.out.print(" "); } public static void main(String[] args) { Rechteck r1 = new Rechteck(); Schlange s = new Schlange(); Rechteck r2 = new Rechteck(); elementeZeichnen(r1); elementeZeichnen(s); elementeZeichnen(r2); } }

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Schnittstellen Seite 246

Ausgabe:
[] ~ []

11.2.3 Interfaces definieren


Interfaces werden mit dem Schlsselwort interface definiert. Die allgemeine Syntax sieht wie folgt aus:
ZugriffMod InterfaceMod interface Name { InterfaceElemente } ZugriffMod InterfaceMod interface Name extends InterfaceName { InterfaceElemente } ZugriffMod Eigenstndige Interfaces knnen ohne Zugriffsspezifizierer (Zugriff innerhalb des Pakets) oder mit dem Zugriffsspezifizierer public (uneingeschrnkter Zugriff) definiert werden. Interfaces, die als Teil einer Klassendefinition definiert werden, knnen auch als protected oder private deklariert werden. InterfaceMod Einer oder mehrere der folgenden Modifizierer:

abstract

Standard, muss nicht explizit gesetzt werden. (Interfaces und ihre Methode sind automatisch abstract.)

static strictfp

Nur fr Interfaces, die Elemente einer anderen Typdefinition sind. Legt fest, dass alle Methoden FP-strikt sind und nicht mit hheren Gleitkommagenauigkeiten rechnen als fr float und double vorgesehen.

Name

Der Name ist unter Einhaltung der Regeln zur Namensgebung frei whlbar. Per Konvention beginnen Interface-Namen mit einem Grobuchstaben. Die meisten Interface-Namen drcken zudem eine Fhigkeit oder Eigenschaft aus (Comparable,

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Schnittstellen Seite 247

Zeichenbar etc.).
extends InterfaceName Ein Interface kann von einem oder mehreren Interfaces abgeleitet werden. Die implementierende Klasse muss dann auch die Methoden der Basis-Interfaces implementieren. Mehrere Basis-Interfaces werden, durch Kommata getrennt, mit eigenem Schlsselwort extends aufgefhrt: interface Demo extends B1, B2 InterfaceEleme Ein Interface kann nte

Typdefinitionen (sind automatisch static), static

Konstanten (sind automatisch public final) und

Methoden (sind automatisch public abstract)

definieren.

Beispiel
// aus Eingangsbeispiel interface Zeichenbar { void zeichnen(); }

11.2.4 Interfaces implementieren


Eine Klasse, die ein Interface implementiert, fhrt das Interface mit dem Schlsselwort implements nach dem Klassennamen (bzw. der Basisklasse) auf und verpflichtet sich damit, fr alle Methoden, die in dem Interface aufgefhrt sind, Anweisungsblcke zu definieren.
Zugriffmod Klassenmod class Klassenname extends Basis implements Interface { Klassenelemente }

Implementiert eine Klasse mehrere Interfaces, werden diese in der implements-Klausel durch Kommata getrennt aufgelistet:
Zugriffmod Klassenmod class Klassenname extends Basis implements Interface1, Interface2

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Schnittstellen Seite 248

{ Klassenelemente }

Beispiel
// aus Eingangsbeispiel class Rechteck extends Form implements Zeichenbar { public void zeichnen() { System.out.print("[]"); } }

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Ausnahmen Seite 249

12 Exkurs: Ausnahmen
Unter Exception-Behandlung versteht man eine spezielle Form der Fehlerbehandlung, bei der Fehler nicht an Ort und Stelle behandelt werden, sondern in Form von Exceptions im Aufrufstack immer weiter nach oben gereicht werden, bis sie irgendwo abgefangen und behandelt werden. Die Exception-Behandlung eignet sich nicht fr jeden Fehler. Fr Fehler, die an Ort und Stelle aufgefangen und korrigiert werden sollen, ist die ExceptionBehandlung nur bedingt bis gar nicht geeignet. Ihre eigentliche Strke entfaltet sich, wenn der Fehler an Ort und Stelle lediglich registriert werden soll und die eigentliche Reaktion auf den Fehler anderen berlassen wird: Exceptions ermglichen die rumliche Trennung von Fehlerauslser und Fehlerbehandlung. Eine Bibliotheksmethode braucht ihre Fehler also nicht selbst zu verarbeiten. Stattdessen lst sie eine Exception aus und berlsst die Behandlung des Fehlers dem aufrufenden Programm. Die Weiterreichung der Exception erfolgt nicht ber Rckgabewerte, Parameter oder irgendwelche globale Variablen. Die fr den korrekten Einsatz der Methoden bentigte Schnittstelle (Signatur und Rckgabetyp) wird also nicht belastet oder aufgeblht. (Dies ist besonders wichtig fr Elemente wie zum Beispiel Konstruktoren, die keine Werte zurckliefern knnen.) Schlielich wird der Quellcode bersichtlicher, da der eigentliche Algorithmus und die Fehlerbehandlung getrennt sind.

12.1 Schema einer Exception-Behandlung


1. 2. Eine Exception-Behandlung beginnt mit dem Auftreten eines Fehlers, beispielsweise einer Division durch null. Als Antwort auf den Fehler lst die Methode, in der der Fehler auftrat, eine Exception aus. In Java ist eine Exception ein Objekt einer Klasse, die von Throwable abgeleitet ist (meist ein Objekt der Klasse Exception oder einer abgeleiteten Klasse, siehe unten). In den Feldern des Objekts knnen Informationen ber den Fehler gespeichert werden.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Ausnahmen Seite 250

Die Exception wird mittels des Schlsselwortes throw ausgelst. 3. Danach wird in den umgebenden Blockbereichen (erst der aktuellen Methode, dann der aufrufenden Methoden) nach einem Handler fr die Exception gesucht. Handler werden fr spezielle Exceptions, sprich Exception-Klassentypen, definiert und durch das Schlsselwort catch gekennzeichnet. Der Bereich, fr den der Handler zustndig ist, wird mit dem Schlsselwort try eingeleitet und in geschweifte Klammern gefasst.
Beispiel: Exception-Behandlung
01 import java.io.*; 02 03 public class ExceptionBehandlung { 04 05 public static double division(double zaehler, 06 double nenner) 07 throws Exception { 08 if (nenner == 0.0) 09 throw new Exception("Division durch null!"); 10 else 11 return zaehler/nenner; 12 } 13 14 public static void main(String[] args) { 15 double zaehler = 0; 16 double nenner = 0; 17 double bruch = 0; 18 19 try { 20 zaehler = 21.3; 21 nenner = 3.0; 22 bruch = division(zaehler,nenner); 23 System.out.println(zaehler + " : " 24 + nenner + " = " + bruch ); 25 26 // Aufruf der eine Exception auslst 27 zaehler = 21.3; 28 nenner = 0.0; 29 bruch = division(zaehler,nenner); 30 System.out.println(zaehler + " : " 31 + nenner + " = " + bruch ); 32 33 } catch (Exception e) {

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Ausnahmen Seite 251

34 System.out.println("Exception abgefangen: " 35 + e.getMessage() ); 36 } 37 } 38 }

Ausgabe des Programms:


21.3 : 3.0 = 7.1000000000000005 Exception abgefangen: Division durch null!

Erluterung

In Zeile 29 wird die statische Methode division() mit 0.0 als Nenner aufgerufen. Die Methode division() erkennt den unzulssigen Nenner in Zeile 8. Sie erzeugt daraufhin eine Exception (als Objekt der Klasse Exception) und lst diese mit throw aus. Dem Exception-Konstruktor wird ein Fehlermeldungstext (Division durch null!) bergeben, der in der Exception abgespeichert und spter mit der Exception-Methode getMessage() abgefragt werden kann. Man htte die Methode auch so implementieren knnen, dass sie eine Fehlermeldung ausgibt und nenner einfach auf 1 setzt. Diese Form der Fehlerbehandlung wre dann aber fester Teil der Methode, wodurch sie fr Programmierer, die eine andere Form der Fehlerbehandlung bevorzugen, unbrauchbar wrde. Von diesem Zeitpunkt an ist der normale Programmfluss auer Kraft gesetzt und es wird nach einem Exception-Handler fr die Exception gesucht. Da die Methode division() selbst keinen passenden catch-Handler enthlt, wird die Exception an die aufrufende Methode weitergeleitet: hier main(). In main() liegt der Aufruf von division() in einem try-Block mit einem catch-Handler, der Exceptions des Typs Exception abfngt (Zeilen 3336). Da die aktuelle Exception ebenfalls von diesem Typ ist, wird sie abgefangen und der catch-Handler wird ausgefhrt.

12.2 Exceptions auslsen


Am Anfang einer Exception-Behandlung steht immer die Auslsung einer Exception. Meist passiert dies unsichtbar fr Sie in Methoden von

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Ausnahmen Seite 252

Bibliotheksklassen, die Sie einsetzen. Sie knnen aber natrlich auch in eigenen Methoden Exceptions auslsen:
throw Exception; Exception Objekt einer Klasse, die von Throwable abgeleitet ist (meist ein Objekt der Klasse Exception oder einer abgeleiteten Klasse, siehe Abschnitt Exception-Klassen).

Grundstzlich besteht die Auslsung einer Exception aus drei Schritten: 1. 2. Die Exception erzeugen.
Exception e = new Exception();

In der Exception Informationen ber den Fehler speichern. Die Implementierung von Throwable, von der in Java alle ExceptionKlassen abgeleitet sind, sorgt automatisch dafr, dass in allen Exceptions der aktuelle Stack-Trace (d.h. die Abfolge der Methoden, die aktuell aufgerufen sind) gespeichert wird. ber den Konstruktor knnen Sie einen Fehlermeldungstext und einen Verweis auf eine auslsende Exception (falls die aktuelle Exception als Antwort auf eine andere Exception ausgelst wird, siehe unten) speichern. Wenn Sie eigene Exception-Klassen definieren, knnen Sie diese mit weiteren Feldern und Methoden ausstatten, ber die Sie weitere Informationen speichern knnen.
Exception e = new Exception("Schwerer Fehler");

3.

Die Exception auslsen.


throw e;

Wenn Sie Exceptions der in der Java-Standardbibliothek definierten Exception-Klassen auslsen, werden die Informationen automatisch (Stack-Trace) oder ber den Konstruktor (Meldungstext) gesetzt. Die obigen drei Schritte knnen daher bequem in einer Anweisung untergebracht werden:
throw new Exception("Schwerer Fehler");

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Ausnahmen Seite 253

Exceptions erneut auslsen Manchmal ist es interessant, eine Exception abzufangen, ohne sie wirklich adquat zu behandeln (beispielsweise zum Debuggen eines Programms). In solchen Fllen fangen Sie die Exception ab, fhren den lokalen Behandlungscode aus und lsen die Exception erneut mit throw aus:
try { // Code, der eine Exception auslsen kann } catch (Exception e) { System.out.println("Exception in Methode X"); System.out.println(e.toString()); throw e; // Neu auslsen }

Anmerkungen

Verwenden Sie diese Konstruktion nicht, um vor dem unerwarteten Verlassen einer Methode noch dringende Aufrumarbeiten zu erledigen. Dafr gibt es in Java die finally-Klausel (siehe Abschnitt finallyKlausel). Exceptions knnen durch Weiterleitung nicht an nachfolgende catchHandler zum gleichen try-Block bergeben werden.

12.3 Exceptions abfangen


Der Abfangmechanismus fr Exceptions beruht auf den Schlsselwrtern try und catch. Mit try wird ein Block definiert, der auf Exceptions hin berwacht wird. An den try-Block angehngt folgen die catch-Blcke, wobei jeder catch-Block eine Fehlerbehandlung fr einen bestimmten Typ von Exception definiert.
try { // Anweisungen, die berwacht werden; } catch(ExceptionTyp e) { // Fehlerbehandlung; }

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Ausnahmen Seite 254

ExceptionTyp Der Exception-Typ des catch-Handlers. Ein catch-Block oder -Handler wird nur fr diejenigen Exceptions ausgefhrt, die in dem darber liegenden try-Block auftreten und deren Datentypen mit der Typenangabe des catch-Handlers bereinstimmen (implizite Typumwandlungen werden bercksichtigt). e Der Exception-Parameter, in dem die Referenz auf das aktuell abgefangene Exception-Objekt gespeichert wird. ber diesen Parameter knnen Sie auf die Methoden des ExceptionObjekts zugreifen und Informationen ber den aufgetretenen Fehler abfragen.

Anmerkungen

Jede Exception liefert zwei Arten von Informationen: die Art des Fehlers, die durch den Typ der Exception angezeigt wird (dabei sagen die spezielleren, abgeleiteten Exception-Klassen wie ArithmeticException oder FileNotFoundException natrlich mehr ber die Art des Fehlers aus als die allgemeine Exception-Klasse Exception.), die Informationen, die im Exception-Objekt abgespeichert sind. Fr die vordefinierten Exception-Typen aus der Java-Standardbibliothek sind dies der Stack-Trace und sofern vom Auslser gesetzt ein Meldungstext und eine Ursachen-Exception, die mithilfe der Methoden printStackTrace(), getMessage() und getCause() abgefragt werden knnen.

Mit der Methode toString()knnen Sie Typ und Meldungstext einer Exception ausgeben. Wenn Sie eigene Exception-Klassen definieren, steht es Ihnen natrlich frei, weitere Informationen ber den auslsenden Fehler und seine Umstnde in die Exception-Objekte zu packen.

Mehrere catch-Handler Unter einem try-Block knnen Sie mehrere catch-Handler definieren.
try { ... } catch (EinExceptionTyp e) { ...

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Ausnahmen Seite 255

} catch (AndererExceptionTyp e) { ... } catch (NochEinExceptionTyp e) { ... }

Anmerkungen

Achten Sie darauf, die typenspezifischeren catch-Handler immer vor den allgemeineren Handlern zu definieren, sonst fangen die allgemeinen Handler auch die spezielleren Exceptions ab und der Compiler straft Sie mit Fehlermeldungen, dass es keine abzufangenden Exceptions mehr gibt.

12.4 Exceptions und Methodendeklaration


Java unterscheidet zwei Kategorien von Exceptions: checked und unchecked. Zu den unchecked-Exceptions gehren alle von RuntimeException und Error abstammenden Exceptions. Diese Exceptions mssen nicht zwangsweise behandelt werden. Alle anderen Exceptions gehren zu den checked-Exceptions, fr die der Compiler sicherstellt, dass sie behandelt werden. Das heit, der Compiler prft fr jede Methode, ob diese Code enthlt, der zur Auslsung einer checked-Exception fhren kann (throw-Anweisungen, Aufrufe anderer Methoden). Wenn ja, erwartet der Compiler, dass diese Exceptions von der Methode behandelt werden, indem die Methode die Exception entweder mit try-catch abfngt und behandelt oder in ihrer throws-Klausel auflistet, um anzuzeigen, dass die Exception an die aufrufende Methode weitergereicht wird.

Weiterleitung mit throws checked-Exceptions, die in der Methode ausgelst, aber nicht abgefangen und behandelt werden, mssen im Kopf der Methodendefinition in der throws-Klausel aufgelistet werden:
rueckgabetyp methodenname() throws Exceptions { } Exceptions Durch Kommata getrennte Liste von Exception-Klassen.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Ausnahmen Seite 256

Fr die checked-Exceptions, die weitergeleitet werden sollen, knnen die tatschlichen Klassentypen oder Basisklassentypen angegeben werden.

12.5 Exception-Klassen
Technisch gesehen sind Exceptions Objekte von Klassen, die von der Basisklasse Exception abstammen. Die Funktionalitt, die Exceptions auszeichnet, stammt aber nicht von Exception selbst, sondern von der Klasse Throwable. Nur Objekte dieser Klasse (und ihrer abgeleiteten Klassen) knnen mit throw ausgelst oder mit einem catch-Handler abgefangen werden. Die Klasse Throwable definiert einige interessante Elemente, die sich auch in allen abgeleiteten Exception-Klassen wiederfinden:
Klassenelement Throwable() Throwable(String meldung) Throwable getCause() Beschreibung Standardkonstruktor Erzeugt ein Exception-Objekt spezifischen Fehlermeldung. mit einer

Zum Verketten von Exceptions (wenn eine Exception eine andere Exception als Ursache hat), siehe Abschnitt Exceptions verketten. Liefert den Meldungstext der Exception zurck. Gibt eine Beschreibung der Exception (vgl. dem Stack befindlichen Methoden aus.

String getMessage() void printStackTrace()

toString()) und darunter eine Liste der auf


Liefert eine Beschreibung der Exception zurck, bestehend aus:

String toString()

Klassenname der Exception Klassenname der verketteten Exception (siehe getCause()) Meldungstext.

Tabelle 12.1: Ausgesuchte Elemente der Klasse Throwable Von Throwable sind zwei Klassen abgeleitet: Error und Exception.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Ausnahmen Seite 257

Error reprsentiert schwerwiegende Fehler, die in der Regel in Zusammenhang mit der Arbeit der Virtual Machine stehen. Sie werden nur in Ausnahmefllen vom Programm behandelt. Exception ist die Basisklasse fr die eigentlichen Ausnahmen, die in den Programmen abgefangen und behandelt werden sollen (und mssen). Zu Exception wiederum gibt es eine ganze Reihe von direkt abgeleiteten Klassen Eigene Exceptions Wenn Sie Exceptions auslsen mchten, zu denen es keine passenden Exception-Klassen in der Java-Standardbibliothek gibt, knnen Sie eine eigene Exception-Klasse definieren.
class NullDivisionException extends Exception { private double zaehler; public NullDivisionException() { } public NullDivisionException(String meldung) { super(meldung); } public NullDivisionException(String meldung, double zaehler) { super(meldung); this.zaehler = zaehler; } public double getZaehler() { return zaehler; } }

12.6 finally-Klausel
Wird eine Exception ausgelst, wird der normale Ablauf des Programms unterbrochen und das Programm dort fortgesetzt, wo die Exception abgefangen wird also in einem catch-Handler, der dem Datentyp der Exception entspricht.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Ausnahmen Seite 258

Wie drastisch dabei in den normalen Programmablauf eingegriffen wird, hngt davon ab, wie schnell ein passender Handler gefunden wird. Wird eine Exception ausgelst, wird zuerst berprft, ob die throwAnweisung innerhalb eines try-Blocks liegt. Ist dies der Fall, wird berprft, ob es unter dem try-Block einen passenden catch-Handler gibt. Gibt es keinen try-Block oder keinen passenden Handler, wird die Exception an den umliegenden Block weitergereicht. Gibt es keinen umliegenden Block, der die Exception abfngt, wird die aktuelle Methode verlassen und die Exception an die aufrufende Methode weitergereicht. In dieser wird nun nach dem gleichen Schema nach einem passenden Handler Ausschau gehalten. So schreitet die Suche voran, bis ein Handler gefunden wurde, oder die Exception nach erfolglosem Durchsuchen der main()Methode schlielich zur Behandlung an die Java Virtual Machine weitergereicht wird. Die Art und Weise, in der der Handler zu einer Exception gesucht wird, fhrt nicht selten dazu, dass die aktuell in Ausfhrung befindlichen Methoden abrupt beendet und ihre Stackrahmen aufgelst werden (Stackauflsung oder Stack Unwinding). Das abrupte Beenden der Methoden im Zuge der Stackauflsung kann dazu fhren, dass wichtige Abschlussarbeiten, die am Ende der Methodendefinitionen stehen (wie das Schlieen von Dateien, die Freigabe von Ressourcen oder die Speicherung lokaler Objektreferenzen in Feldern der Klasse) nicht mehr ausgefhrt werden. Aus diesem Grunde bietet Ihnen Java die Mglichkeit, an einen try- oder try-catch-Block einen finally-Block anzuhngen, der auf jeden Fall ausgefhrt wird unabhngig davon, ob im try-Block eine Exception auftrat oder nicht.
try { // Code, der eine Exception auslsen kann } catch (EineException e) { // Behandlungscode } finally { // Code, der immer ausgefhrt wird }

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Ausnahmen Seite 259

Anmerkungen

Ressourcen, die von lokal erzeugten Objekten reserviert werden, knnen Sie auch implizit ber die Speicherbereinigung freigeben lassen. Vorausgesetzt, die Objekte verfgen ber eine finalize()-Methode, die Code zur Freigabe der Ressourcen enthlt.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Anonyme Objekte Seite 260

13 Exkurs: Anonyme Objekte


Die hufigste Art der Objekterzeugung ist der Aufruf des Konstruktors mit new und das Abspeichern des zurckgelieferten Objektverweises in einer Variablen:
Demo obj = new Demo();

Im weiteren Code kann dann berall, wo die Variable gltig ist, auf das Objekt zugegriffen werden. Manchmal wird ein Objekt aber auch nur fr eine einmalige bergabe an eine Methode bentigt. Fr solche Flle lohnt es sich im Grunde nicht, den Objektverweis in einer Variablen zu speichern. Statt
Demo obj = new Demo(); irgeneineMethode(obj);

knnen Sie dann auch schreiben:


irgeneineMethode(new Demo());

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Innere Klassen Seite 261

14 Exkurs: Innere Klassen


Da Klassendefinitionen (ebenso wie Interface-Definitionen) innerhalb einer Klasse erlaubt sind, kann eine Klasse in einer anderen Klasse definiert werden.

14.1 Innere Klassen


class Aussen { class Innen { ... } ... }

Innere und uere Klassen knnen wechselseitig, ohne Einschrnkung durch gesetzte Zugriffsmodifizierer auf ihre Klassenelemente zugreifen. Die innere Klasse kann die Elemente der ueren Klasse direkt verwenden, die uere Klasse muss ein Objekt der inneren Klasse erzeugen. Ist die innere Klasse als static definiert, kann die uere Klasse natrlich keine Objekte der inneren Klasse erzeugen. Dafr darf sie auf die statischen Elemente der Klasse zugreifen.

14.2 Lokale Klassen


Eine lokale Klasse ist eine Klasse, die in einem Anweisungsblock (meist dem Anweisungsblock einer Methode) definiert wird:
void Methode() { class Lokal { ... } ... }

Der Gltigkeitsbereich der Klasse ist der umschlieende Block. Meist ist dies der Anweisungsblock einer Methode und es gilt: Die Methode kann ein Objekt der lokalen Klasse erzeugen und ohne Einschrnkung durch gesetzte Zugriffsmodifizierer auf deren Klassenelemente zugreifen. Die lokale Klasse kann auf lokale Variablen und Parameter der umgebenden Methode nur dann zugreifen, wenn diese als final deklariert sind.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Innere Klassen Seite 262

public, protected, private und static sind fr lokale Klassen nicht erlaubt.

14.3 Anonyme Klassen


Eine anonyme Klasse ist eine Klasse, die ohne Name definiert wird blicherweise im Zuge einer Objekterzeugung mittels new:
new AnonymeKlasse() { ... }

Anonyme Klassen drfen weder abstract noch static sein, haben keinen explizit definierten Konstruktor und knnen nicht als Basisklassen auftauchen.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Threads Seite 263

15 Exkurs: Threads
Threads (Fden) kann man sich als Ausfhrungsfden oder untergeordnete Teilprogramme vorstellen, die innerhalb eines Hauptprogramms (auch Prozess genannt) ablaufen. Standardmig besteht ein Programm aus einem einzigen Thread, dem Hauptthread. Wenn dieser Hauptthread bei seiner Arbeit auf etwas warten muss (z. B. eine Tastatureingabe), dann wartet somit das ganze Programm, auch wenn in der Zwischenzeit vielleicht etwas Sinnvolles getan werden knnte, beispielsweise das Laden von bentigten Dateien. Hier bietet es sich an, einen zustzlichen Thread anzulegen, der auf die Tastatureingabe wartet und verarbeitet, sodass der bisherige Hauptthread weiterarbeiten kann und nicht blockiert.

15.1 Die Klasse Thread


Threads werden in einem laufenden Java-Programm durch Objekte vom Typ java.lang.Thread reprsentiert. Die Klasse Thread definiert unter anderem die folgenden wichtigen Methoden, ber die jeder Thread verfgen muss: public void start() zum Starten des Threads, sowie public void run() mit dem auszufhrenden Code

Die run()-Methode eines Thread-Objekts ist dabei gewissermaen seine main()-Methode, sie wird allerdings nie direkt von einem Programm aus aufgerufen (dies kann man zwar machen, aber es bewirkt dann keine Erzeugung eines Threads, sondern die bloe Abarbeitung der Methode innerhalb des aktuellen Threads).

15.1.1 Threads erzeugen


Um einen richtigen Thread, d.h. einen zum bisherigen (Haupt-)Thread parallel weiter arbeitenden Arbeitsstrang, zu erzeugen, gehen Sie wie folgt vor: 1. Sie leiten eine eigene Klasse von der Basisklasse Thread ab und berschreiben die run()-Methode.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Threads Seite 264

In run() setzen Sie den Code auf, den der Thread ausfhren soll. 2. Sie erzeugen ein Objekt Ihrer Thread-Klasse und rufen dessen start()-Methode auf. Die start()-Methode ruft dann intern die run()-Methode auf.
Beispiel: Threads erzeugen
class MeinThread extends Thread { public void run() { System.out.print("Hier ist " + getName()); System.out.println(" mit ID: " + getId()); } } public class ThreadDemo { public static void main(String[] args) { MeinThread mt = new MeinThread(); mt.setName("MeinThread"); mt.start(); System.out.println("Hier ist die main-Methode"); } }

Hier wird eine selbst definierte Klasse MeinThread dazu verwendet, eine Meldung auszugeben. Wenn Sie das Programm ausprobieren, werden Sie sehr wahrscheinlich sehen, dass die Meldung Hier ist MeinThread mit ID xyz nach der Meldung des Hauptthreads Hier ist die main-Methode auf dem Bildschirm auftaucht. Dies liegt daran, dass das Erzeugen und Anstoen eines Threads durch die start()-Methode einige Zeit in Anspruch nimmt. Der aufrufende Hauptthread kehrt jedoch unverzglich aus seinem Aufruf von start() zurck und kann seine Meldung ausgeben. Thread-IDs Jeder Thread erhlt bei seiner Erzeugung von der Java Virtual Machine eine eindeutige Nummer zugewiesen, seine Thread-ID, die mit der Methode getId() ermittelt werden kann. Wer gerne anschauliche Namen bevorzugt, kann mit setName() und getName() auch beliebige Strings als Bezeichner verwenden.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Threads Seite 265

Threads beenden Der Thread endet automatisch, wenn seine run()-Methode endet. Will man Threads erstellen, die lngere Zeit laufen und sich erst auf Kommando beenden, implementiert man meist eine while-Schleife, die so lange ausgefhrt wird, wie eine eigens definierte booleschen Instanzvariable true ist. Erst wenn die Variable auf false gesetzt wird, wird die Schleife und damit run() beendet. Zum Setzen der Variablen definiert man eine geeignete Methode, z. B. stoppen():
class MeinThread extends Thread { private boolean weiter = true; public void run() { while(weiter) { System.out.println("Hier ist MeinThread!"); try { sleep(2000); // 2s warten } catch(InterruptedException e) { } } } public void stoppen() { weiter = false; } }

Wenn ein Thread nicht ununterbrochen arbeiten soll, empfiehlt es sich, in seiner zentralen Schleife eine kurze Unterbrechung einzubauen, whrenddessen er sich schlafen legt. Wenn ein Thread sich schlafen legt, gibt er den Prozessor frei, der somit andere Threads mit seiner Rechenzeit beglcken kann. Hierzu dient die Thread-Methode sleep(), der man die gewnschte Anzahl an Millisekunden bergibt. Der Aufruf muss mit trycatch gesichert sein, da eine InterruptedException ausgeworfen werden knnte. Sie wird ausgelst, wenn die Thread-Methode interrupt() eines schlafenden Thread-Objekts aufgerufen wird.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Threads Seite 266

Eine andere hufiger bentigte Form des Wartens realisiert die Methode join(), mit der ein Thread auf das Ende eines anderen Threads warten kann.
MeinThread t = new MeinThread(); t.start(); ... try { // auf das Ende von t warten t.join(); } catch(InterruptedException e) {}

Anmerkungen

Mit sleep() kann sich ein Thread immer nur selbst schlafen legen. Es ist nicht mglich, ber eine vorhandene Referenz einen anderen Thread schlafen zu lassen, z. B.:
MeinThread t = new MeinThread(); t.start(); ... t.sleep(); // legt Aufrufer schlafen!

Als Alternative zu sleep() existiert die Methode yield(): Hiermit gibt der Thread den Prozessor freiwillig ab und schlft so lange, bis er vom Betriebssystem wieder den Prozessor erhlt und ausgefhrt wird. Der Aufruf von interrupt() bewirkt das Setzen eines besonderen Flags (Interrupt-Flag) im Thread und ggf. eine InterruptedException, falls er gerade am Schlafen war. Es existieren veraltete (deprecated) Thread-Methoden stop(), suspend() und resume() zum Beenden und Anhalten, die nicht mehr verwendet werden sollten. Sollen Threads nur einmal vor dem Beenden der Virtual Machine gestartet werden, kann man sie mit System.addShutdownHook() anmelden.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Threads Seite 267

15.2 Das Runnable-Interface


Etwas lstig bei der Definition von eigenen Thread-Klassen ist der Umstand, dass man sie von Thread ableiten muss und somit nicht mehr die Freiheit hat, von anderen (eventuell selbst erstellten) Klassen abzuleiten. Fr solche Flle kann man einen anderen Weg whlen, und zwar mithilfe des Interface java.lang.Runnable.
Beispiel
public MeinThread implements Runnable { //... public void run() { // hier Thread-Rumpf definieren } }

Dieses Interface schreibt lediglich die run()-Methode vor, in der man wie bei der Ableitung von Thread den gewnschten Code implementiert. Das Erzeugen des Threads erfolgt dann durch Instanzieren der Klasse Thread, wobei man dem Konstruktor die Referenz des Objekts mitgibt, welches das Runnable-Interface implementiert, d.h., man sagt dem Thread, wo er seine run()-Methode finden kann. Sehr hufig erzeugt man den Thread in einer Methode der Klasse, die Runnable implementiert, selbst, sodass man this bergibt:
// Starten innerhalb von MeinThread Thread t = new Thread(this); t.start();

Das Starten erfolgt dann wie gewohnt mit der Methode start().

15.3 Thread-Synchronisierung
Die Verteilung von Arbeiten auf mehrere Threads ist zwar hufig sehr ntzlich fr die Funktionalitt eines Programms, aber man handelt sich dabei auch mglicherweise Probleme ein, die daraus resultieren, dass mehrere Threads gleichzeitig auf die gleichen Variablen oder Objekte schreibend

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Threads Seite 268

zugreifen wollen. Dabei knnen undefinierte Zustnde der Daten eintreten, die das ganze Programm zum Scheitern verurteilen. Der schwierige Teil bei der Thread-Programmierung ist deswegen nicht das Erzeugen oder Beenden von Threads, sondern vielmehr die Koordination ihrer Zugriffe auf gemeinsame Daten, die so genannte Synchronisierung. Bei erfolgreich beachteter Synchronisierung sagt man auch, dass eine Klasse bzw. Methode threadsicher (englisch thread-safe) ist, also gefahrlos von mehreren Threads gleichzeitig durchlaufen werden kann.
Beispiel

Ein ganz simples Beispiel fr die Notwendigkeit von Synchronisierung ist das Hochzhlen einer Variablen, z. B. eine statische Klassenvariable einer Thread-Klasse, die von jedem Thread hochgezhlt wird:
public MeinThread extends Thread { static long anzahl; public void run() { anzahl++; } }

Das Inkrementieren von anzahl ist keine atomare, d.h. unteilbare, Operation. Sie besteht aus einer Sequenz von mehreren BytecodeAnweisungen und irgendwo mittendrin knnte der abarbeitende Thread unterbrochen werden, weil ihm der Prozessor entzogen wird und nun ein anderer Thread an der Reihe ist, der ebenfalls anzahl ndert. Dadurch kann es zu seltsamen und falschen Werten in anzahl kommen. Glcklicherweise bietet die Sprache Java geeignete Mittel, um ThreadZugriffe auf gemeinsam genutzte Variablen zu synchronisieren. Die wichtigsten Mglichkeiten sind so genannte synchronized-Abschnitte und die Methoden wait()/notify(). (Auf letztere werden wir hier aber nicht weiter eingehen.) synchronized Mit dem Schlsselwort synchronized lassen sich Code-Abschnitte oder ganze Methoden derart sichern, dass sich immer nur ein Thread in diesem

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Threads Seite 269

Abschnitt aufhalten kann. Selbst wenn diesem Thread vom Betriebssystem gerade der Prozessor entzogen wird, kann kein anderer Thread, der nun den Prozessor erhlt, den synchronized-Abschnitt ausfhren (falls er das mchte, muss er den Prozessor gleich wieder abgeben und warten, bis der andere Thread den Abschnitt abgearbeitet und wieder freigegeben hat). Synchronisierte Abschnitte beziehen sich immer auf ein bestimmtes Objekt, d.h., wem gehrt dieser Abschnitt. Hufig nimmt man die aktuelle Instanz selbst (also this), es kann aber auch ein vllig anderes Objekt sein. Das Sichern erfolgt durch das Schlsselwort synchronized, gefolgt von der Objektreferenz und einem Anweisungsblock:
synchronized(this) { anzahl++; }

Eine andere Mglichkeit ist das Schtzen einer kompletten Methode durch das Voranstellen von synchronized vor den Methodennamen, z. B.:
class Beispiel { synchronized void kritischeMethode() { } }

Als Ergnzung zum Mechanismus der gesicherten synchronizedAbschnitte bietet Java noch eine weitere Synchronisierungsuntersttzung an.
Anmerkungen

Atomare Inkrement-/Dekrement-Operationen bieten ab J2SE 5 die Klassen des Pakets java.util.concurrent.atomic an, z. B. AtomicInteger, AtomicLong. Collection-Klassen (z. B. LinkedList, HashMap) sind nicht synchronisiert, d.h. nicht thread-sicher. Man muss also ggf. selbst mit synchronized arbeiten, die synchronisierten Varianten java.util.Vector und java.util.Hashtable verwenden oder die neuen effizienten und dennoch threads-sicheren Varianten (z. B. ConcurrentHashMap) aus dem Paket java.util.concurrent verwenden.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Ereignis-Listener Seite 270

16 Exkurs: Ereignis-Listener
Die groe Zeit der Konsolenanwendungen ist lange vorbei, heute beherrschen GUI-Programme mit grafischen Benutzeroberflchen den Markt. Grafische Benutzeroberflchen seien dies nun die Fenster einer WindowsAnwendung oder die Bildschirmseiten einer Smartphone-App bestehen blicherweise aus Container-Komponenten und darin eingebetteten speziellen Oberflchenelementen, mit denen der Anwender interagieren kann. Letztere werden auch als Steuerelemente oder Widgets bezeichnet und umfassen so allgemein bekannte Elemente wie Schaltflchen, Optionsfelder, Eingabefelder etc. Grafikbibliotheken, mit deren Hilfe Sie grafische Benutzeroberflchen erstellen knnen, untersttzen Sie in der Regel mit einem Satz vordefinierter Steuerelemente einer vereinfachten Mglichkeit der Ereignisbehandlung

Beispiele fr solche Grafikbibliotheken sind z.B. die Swing-Klassen der Java-Standardbibliothek, mit deren Hilfe Sie Windows-GUI-Anwendungen schreiben knnen, oder die View- und Widget-Klassen der AndroidBibliothek, mit deren Hilfe Sie die Bildschirmseiten von Apps aufbauen knnen. Beide Bibliotheken, Swing wie Android, arbeiten mit einem vereinfachten Ereignisbehandlungsmodell, das auf der Implementierung von ListenerInterfaces basiert.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Ereignis-Listener Seite 271

registrieren

Ereignisquelle

senden

Ereignis empfangen

Ereignisempfnger

Abbildung 16.1: Java-Ereignismodell Ausgangspunkt ist, dass ein bestimmtes Ereignis in einem Oberflchenelement auftritt. Ein solches Ereignis kann die vom Betriebssystem vermittelte Benachrichtigung ber eine Benutzeraktion auf dem Oberflchenelement sein (beispielsweise ein Klick auf das Oberflchenelement), es kann sich aber auch um eine nderung im Zustand des Oberflchenelements handeln (der Wert eines Feldes wurde gendert). Wie auch immer, das Oberflchenelement mchte dem Programmierer die Gelegenheit geben, auf dieses Ereignis zu reagieren. Dazu tritt sie selbst als Ereignisquelle auf und sendet allen interessierten Ereignisempfngern ein Ereignisobjekt, das ber das eigentliche Ereignis informiert. Der Begriff senden stammt aus der traditionellen objektorientierten Terminologie und sollte nicht zu wrtlich genommen werden. Tatschlich ist es so, dass sich die Ereignisempfnger bei der Ereignisquelle registrieren (die passenden Registrierungsmethoden definiert die Klasse der Ereignisquelle). Zudem muss der Ereignisempfnger ein Listener-Interface implementieren, in dem spezielle Methoden zur Behandlung des Ereignisses definiert sind. Tritt dann ein Ereignis auf, ruft die Ereignisquelle fr alle bei ihr registrierten Ereignisempfnger die passende Ereignisbehandlungsmethode auf mit dem Ereignisobjekt als Argument. Unter dem Senden des Ereignisobjekts ist also der Aufruf der registrierten Methode mit dem Ereignisobjekt als Argument zu verstehen.
Beispiel aus der Swing-Programmierung

In java.awt.event gibt es eine Ereignisklasse ActionEvent. Diese Klasse ist fr kein spezielles Ereignis gedacht, sondern einfach fr die typische Aktion, die der Anwender auf einem Oberflchenelement ausfhrt. Passend zu dem Ereignis definiert Java noch ein Interface ActionListener. Dieses deklariert die Methode

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Ereignis-Listener Seite 272

actionPerformed(ActionEvent e), die zur Behandlung von ActionEvent-Ereignissen implementiert werden soll. Die typische Aktion fr Schaltflchen ist das Anklicken. Es liegt daher nahe, dass Swing-Schaltflchen das ActionEvent-Ereignis auslsen und dem Programmierer erlauben, Empfnger fr dieses Ereignis zu registrieren. Die Klasse AbstractButton, die abstrakte Basisklasse aller SwingSchaltflchen, definiert zu diesem Zweck eine Registrierungsmethode addActionListener(ActionListener l) und erzeugt beim Anklicken der Schaltflche ein ActionEvent-Objekt und bergibt dieses fr alle registrierten Ereignisempfnger an die Methode actionPerformed().

Angenommen, der Programmierer einer Swing-GUI-Anwendung hat eine Schaltflche erzeugt (als Instanz der von AbstractButton abgeleiteten Swing-Klasse JButton) und mchte nun auf das Anklicken der Schaltflche reagieren. Dann muss er lediglich ein Objekt erzeugen, das das Interface ActionListener implementiert, in actionPerformed() den gewnschten Ereignisbehandlungscode einfgen und dann das Objekt mit addActionListener() bei der JButton-Schaltflche registrieren:
public class GUI extends JFrame { JButton btn; public GUI() { btn = new JButton("Klick mich"); btn.addActionListener(new SchalterLauscher()); getContentPane().add(btn); } class SchalterLauscher implements ActionListener { public void actionPerformed(ActionEvent e) { btn.setText("Noch einmal!"); } }

Anmerkungen

In Java gibt es viele verschiedene Mglichkeiten, eine ListenerEreignisbehandlung aufzubauen.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Ereignis-Listener Seite 273

Sie knnen, wie oben gezeigt, innere Klassen zur Ereignisbehandlung definieren. Sie knnen anonyme Klassen zur Ereignisbehandlung definieren:
public class GUI extends JFrame { JButton btn; public GUI() { btn = new Button("Schalter"); btn.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { btn.setEnabled(false); } }); } }

Sie knnen die bergeordnete Klasse Ereignisse behandeln lassen:


public class GUI extends JFrame implements ComponentListener { JButton btn1; JButton btn2; public GUI() { ... btn1.addComponentListener(this); btn2.addComponentListener(this); } void void void void } ComponentHidden(ComponentEvent e) {...} ComponentMoved(ComponentEvent e) {...} ComponentResized(ComponentEvent e) {...} ComponentShown(ComponentEvent e) {...}

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Java Generics Seite 274

17 Exkurs: Java Generics


Als Generics oder generische Typen werden in Java Klassen (oder Interfaces) bezeichnet, die mit Typen-Platzhaltern arbeiten. Das Konzept der Platzhalter der Generics-Typen ist mit dem Konzept der Parameter von Methoden vergleichbar: Parameter erlauben dem Autor einer Methode, im Anweisungsteil der Methode mit Werten zu arbeiten, die der Benutzer (Aufrufer) der Methode festlegt (indem er sie an die Parameter der Methode bergibt). Analog erlauben die Generics-Platzhalter dem Autor einer Klasse (oder eines Interface), mit Typen zu arbeiten, die erst der Benutzer der Klasse festlegt (im Zuge der Instanzierung).

Die folgende Klasse dient z.B. der Verwaltung von Prchen. Die einzelnen Partner werden vom Konstruktor entgegengenommen und in private Feldern gespeichert. ber passende Get-Methoden knnen sie abgefragt werden. Der Datentyp der einzelnen Partner wird nicht explizit angegeben, sondern durch einen Platzhalter, T, reprsentiert.
class Paar<T> { private T partnerA; private T partnerB; Paar(T a, T b) { partnerA = a; partnerB = b; } T getPartnerA() { return partnerA; } T getPartnerB() { return partnerB;

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Java Generics Seite 275

} }

Programmierer, die diese Klasse verwenden mchten, erzeugen eine oder mehrere Instanzen der Klasse. Fr jede Instanz geben Sie an, welchen Datentyp T reprsentiert.
Paar<String> p1 = new Paar<String>("gut", "boese"); System.out.println(p1.getPartnerA()); System.out.println(p1.getPartnerB()); Teilnehmer udo = new Teilnehmer(); Teilnehmer monika = new Teilnehmer(); Paar<Teilnehmer> p2 = new Paar<Teilnehmer>(udo, monika); System.out.println(p2.getPartnerA()); System.out.println(p2.getPartnerB());

17.1 Syntax
Java erlaubt die Definition von generischen Klassen, Interfaces und Methoden.

17.1.1 Generische Klassen


Die Platzhalter werden in spitzen Klammern an den Namen der Klasse angehngt. Wenn Sie verschiedene Typen durch Platzhalter reprsentieren mchten, mssen Sie fr jeden Typ einen eigenen Platzhalter definieren. Die Platzhalter werden bei der Auflistung in den spitzen Klammern durch Kommata getrennt.
class Demo<T, E> { int feld1; T feld2; void methode(T param, int param2) { ... } }

Bei der Instanzbildung muss fr jeden Platzhalter ein Typ angegeben werden:
Demo<String, Integer> obj = new Demo<String, Integer>();

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Java Generics Seite 276

17.1.2 Generische Interfaces


Interfaces knnen ebenfalls mit Platzhaltern definiert werden:
interface Demo<T> { T methode(T obj); }

Eine Klasse, die ein Interface mit Platzhaltern implementiert, muss die Platzhalter des Interface in die eigene Platzhalterliste aufnehmen:
class Paar<S, T> implements Test<T> { ... public T methode(T obj) { return obj; } }

17.1.3 Generische Methoden


Methoden knnen nicht nur die Platzhalter ihrer Klasse verwenden, sie knnen auch eigene Platzhalter definieren. In diesem Fall taucht der Typ-Parameter in der Signatur der jeweiligen Methode auf in spitzen Klammern vor dem Rckgabetyp. Danach kann der Platzhalter fr Rckgabetyp, Parameterdefinition und die Anweisungen im Methodenkrper verwendet werden. Er sollte aber auf jeden Fall als Parametertyp auftauchen.
class EineKlasse { ... <T> void methode(T param) { ... } }

Methoden mit Platzhaltern werden ohne explizite Typangaben aufgerufen. Der Compiler bestimmt die Typen fr die Platzhalter aus den Typen der Argumente.
EineKlasse obj = new EineKlasse(); obj.methode("String");

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Java Generics Seite 277

17.1.4 Eingeschrnkte Platzhalter


Uneingeschrnkte Platzhalter, wie bisher gesehen, knnen bei der Instanzierung der Klasse durch jeden beliebigen Referenztyp ersetzt werden. Ist dies nicht erwnscht, kann der Platzhalter mit extends auf Typen eingeschrnkt werden, die von einer bestimmten Basisklasse abstammen oder eine oder mehrere spezielle Interfaces implementieren.
class Demo<T extends BasisKlasse, E> {

Anmerkungen

Platzhalter knnen nur Referenztypen vertreten, also keine elementaren Datentypen wie int, float, usw. In der Wahl der Platzhalterbezeichner sind Sie frei; gerne verwendet werden T oder E. Verwechseln Sie Generics-Methoden nicht mit Methoden, die mit Platzhaltern ihrer Klasse definiert sind. Letztere bernehmen die Platzhalter der Klasse. Generics-Methoden hingegen definieren eigene Platzhalter.

17.2 Parameter und Variablen von generischen Typen


Wenn Sie Parameter, oder allgemein Variablen, vom Typ einer generischen Klasse (oder Interface) definieren, geben Sie grundstzlich den Namen der generischen Klasse (Interface) samt den Typen fr die Platzhalter an:
void eineMethode(GenerKlasse<String> p)

In einem solchen Parameter knnen Sie nur Referenzen auf Objekte speichern, die fr den entsprechenden Typ instanziert wurden.
eineMethode(new GenerKlasse<String>()); eineMethode(new GenerKlasse<Integer>()); // okay // Fehler

Wenn Sie einen Parameter definieren mchten, dem beliebige Instanzen einer generischen Klasse zugewiesen werden knnen, ersetzen Sie den (oder die) Platzhalter statt durch echte Typen durch das Wildcard-Symbol ?:
void eineMethode(GenerKlasse<?> p) ...

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Java Generics Seite 278

eineMethode(new GenerKlasse<String>()); eineMethode(new GenerKlasse<Integer>());

// okay // okay

Anmerkungen

Wenn eine Klasse A von Klasse B abgeleitet ist, und wenn ferner eine generische Klasse G definiert ist, dann gilt NICHT, dass G<A> ein abgeleiteter Typ von G<B> ist. Aus diesem Grunde knnen Sie GenerKlasse<Object> nur Instanzen von GenerKlasse zuweisen, die fr Object erzeugt wurden!

Eingeschrnkte Wildcards Wildcard-Typ-Parameter akzeptieren uneingeschrnkt jedwede typisierte Form der zugehrigen generischen Klasse. Ist dies nicht gewollt, knnen Sie durch eine extends-Klausel festlegen, dass sich die Typangabe nur auf Klassen bezieht, die von einer bestimmten Basisklasse abgeleitet sind oder ein bestimmtes Interface implementieren.
? extends KlassenName ? extends InterfaceName ? extends KlassenName & InterfaceName_1 & InterfaceName_2

Whrend extends obere Grenzen definiert, kann mit super eine untere Grenze festgelegt werden:
? super KlassenName

Eine solche Definition definiert als Typ alle Klassen, die eine Basisklasse der angegebenen abgeleiteten Klasse sind. Typidentifizierung und -umwandlung Mit instanceof knnen Sie prfen, ob ein Objekt einer generischen Klasse angehrt, nicht aber, ob es fr einen bestimmten Typ typisiert wurde:
if (obj instanceof Schachtel) // korrekt if (obj instanceof Schachtel<INTEGER>) // Compiler-Fehler

getClass() liefert fr alle Objekte einer generischen Klasse dieselbe Referenz zurck kann also ebenfalls nicht zur Unterscheidung von Typisierungen verwendet werden. Die Typisierung eines Objekts kann nicht durch Casten gendert werden:

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Java Generics Seite 279

obj1 = (Schachtel<Integer>) obj2;

// Compiler-Fehler

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Exkurs: Zufallszahlen Seite 280

18 Exkurs: Zufallszahlen
Java stellt gleich zwei Mglichkeiten zur Erzeugung von (Pseudo)Zufallszahlen bereit: die statische Methode java.lang.Math.random() die Klasse java.util.Random

Whrend Math.random() eine double-Zahl aus dem Bereich [0;1) (also 1 exklusive) erzeugt, z. B.:
double zufall = Math.random();

bietet die Klasse java.util.Random deutlich mehr Mglichkeiten. Neben der Wahl zwischen Gleitkomma- und ganzzahligen Zufallszahlen kann man zustzlich auch den Bereich festlegen, aus dem sie stammen sollen. Der Einsatz von Random erfolgt durch Anlage einer Instanz, gefolgt von nextInt() oder nextFloat() usw.
Random zufall = new Random(); for(int i = 0; i < 5; i++) { // 5 Zahlen aus Bereich [0;100) System.out.println("Zahl " + zufall.nextInt(100)); }

Anmerkungen

Dem Konstruktor Random() kann auch ein long-Startwert bergeben werden. Gleiche Startwerte fhren bei jeder Programmausfhrung zur identischen Folge an erzeugten Zufallszahlen, was fr Testzwecke sehr ntzlich sein kann. Normalverteilte Zufallszahlen (Erwartungswert 0, Standardabweichung 1) gem der Gauschen Normalverteilung knnen mit nextGaussian() erzeugt werden:
double w = zufall.nextGaussian();

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Ein- und Ausgabe Seite 281

19 Ein- und Ausgabe


Jedes Programm muss mit der Auenwelt kommunizieren, sei es, um Daten einzulesen oder um Resultate auszugeben. Die wichtigsten Kommunikationskanle, die einem Java-Programm hierfr zur Verfgung stehen, sind Dateien, Tastatur, Bildschirm und Netzwerkverbindungen zu anderen Rechnern/Programmen.

19.1 Dateien
Fr die Arbeit mit Dateien gibt es in Java die Klasse java.io.File und das Interface java.io.FileFilter.

19.1.1 File
Eine Instanz dieser Klasse dient als Mittelsmann zwischen dem JavaProgramm und dem Betriebssystem. Beim Anlegen einer Instanz von File bergibt man einfach den gewnschten Dateinamen:
File d1 = new File(namen.dat); File d2 = new File(c:\\Daten\\namen.dat); File d3 = new File(c:\\Daten);

Der Name kann einfach sein (wie bei d1) und ist dann relativ zum Arbeitsverzeichnis des Java-Programms, d. h. von wo das Programm aus gestartet worden ist. Man kann natrlich auch einen ganzen Pfad mitgeben. Etwas berraschend ist vielleicht der Umstand, dass File auch ein Verzeichnis reprsentieren kann; es gibt hierfr keine eigene Klasse Directory o.. Beachten Sie, dass fr Microsoft Windows in den Pfadangaben der Backslash \ doppelt stehen muss.
Icon HINWEIS

Informationen ber Dateien und Verzeichnisse abfragen Mit einer File-Instanz kann man nun diverse Informationen ber die zugrunde liegende Datei erhalten, z. B. den relativen und vollen Namen und

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Ein- und Ausgabe Seite 282

ob es sich um eine Datei oder ein Verzeichnis handelt. Im Falle von Verzeichnissen kann man sich dann auch eine Liste der darin enthaltenen Dateien/Unterverzeichnisse geben lassen.
try { System.out.println(d1.getName()); System.out.println(d1.getCanonicalPath()); if(d1.isDirectory() == true) { System.out.println("ist ein Verzeichnis"); File[] dateien = d1.listFiles() // alle Dateien darin for(File f : dateien) System.out.println(f.getName()); // ausgeben } else System.out.println(" ist eine Datei"); } catch(IOException e) { System.out.println(e); } // Name // Pfad

Dateien und Verzeichnisse anlegen, lschen, umbenennen Das Anlegen einer File-Instanz hat noch keinerlei Auswirkungen auf das Dateisystem. Man kann aber natrlich durch den Einsatz geeigneter Methoden auch neue Dateien und Verzeichnisse anlegen bzw. vorhandene lschen und umbenennen:
File d1 File d2 File d3 File d4 boolean = new File(c:\\Daten\\werte.txt); = new File(c:\\Daten\\namen.dat); = new File(c:\\Daten\\namen_alt.dat); = new File(c:\\Backup\\Daten); status;

try { status = d1.createNewFile(); // Datei erzeugen st = d2.delete(); // Datei lschen st = d3.renameTo(d2); // d3 umbenennen in namen.dat st = d4.mkdirs(); // legt Verzeichnis an } catch (IOException e) { }

Diese Methoden liefern dabei immer einen boolean-Wert zurck, der ber Erfolg oder Misserfolg Auskunft gibt; beispielsweise liefert createNewFile()ein false zurck, wenn es schon eine Datei mit dem

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Ein- und Ausgabe Seite 283

gewnschten Namen gibt, und delete() gibt false zurck, wenn die Datei nicht gelscht werden konnte. Beachten Sie auerdem: Das Anlegen, Umbenennen und Lschen von Dateien (Verzeichnissen) setzt entsprechende Benutzerrechte voraus. Zugriffe auf ein File-Objekt knnen eine Exception vom Typ IOException auslsen. Die Anweisungen mssen daher mit einer try-catch -Klausel gesichert werden (oder die Methode muss eine entsprechende throws-Klausel enthalten, siehe Abschnitt Exceptions und Methodendeklaration im Exkurs Ausnahmen). Das Anlegen der File-Instanz selbst kann keine Exception auslsen, da dies eine rein Java-interne Angelegenheit ist.

19.2 Ein- und Ausgabestrme (Streams)


Das grundlegende logische Modell, um mit der Auenwelt zu kommunizieren, ist bei allen modernen Programmiersprachen und somit auch bei Java das I/O-Stream-Modell. Hierbei geht man davon aus, dass die Daten in Form eines sequenziellen Bytes-Stroms zwischen einem Sender (Quelle) und einem Empfnger flieen. Aus der Sicht eines Programms knnen somit Daten hineinflieen (Eingabestrom, Input-Stream) oder herausflieen (Ausgabe-Strom, Output-Stream). Dieses Modell kommt fr smtliche Einund Ausgabenarten (Datei, Tastatur, Bildschirm, usw.) zum Einsatz. In Java gibt es bei Ein- und Ausgabestrmen zwei Grundtypen: Byteorientierte Streams Zeichenorientierte Streams

Ein byteorientierter Stream operiert auf einzelnen Bytes (Datentyp byte), whrend der zeichenorientierte als kleinste Einheit 16-Bit-Unicode-Zeichen verwendet (also auf dem Datentyp char arbeitet). Fr das Verarbeiten von Binrdaten muss die byteorientierte Variante zum Einsatz kommen, bei Textinhalten kann man eventuell whlen, ob der byteorientierte oder der zeichenorientierte Weg praktischer ist. Die meisten Zugriffe auf Ein-/Ausgabestreams (inklusive Instanzbildung) knnen im Fehlerfalle Exceptions vom Typ IOException auswerfen. Die
Icon HINWEIS

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Ein- und Ausgabe Seite 284

Anweisungen mssen daher mit einer try-catch -Klausel gesichert werden (oder die Methode muss eine entsprechende throws-Klausel enthalten).

19.3 Byteorientierte Dateiein-/ausgabe


In Java dienen die Klassen java.io.InputStream und java.io.OutputStream als Basisklassen fr alle byteorientierten Ein/Ausgabestreams. Diese Klassen sind jedoch abstrakt und knnen somit nicht instanziert werden. Erst die nachfolgend vorgestellten, abgeleiteten Klassen knnen direkt benutzt werden. Alle InputStream-Klassen definieren die Methode read() zum Lesen von einem oder mehreren Bytes. Analog definieren alle OutputStreamKlassen die Methode write() zum Schreiben von einem oder mehreren Bytes.

19.3.1 FileInputStream/FileOutputStream
Der typische Weg zum byteorientierten Zugriff auf Dateien erfolgt mit dem Paar FileInputStream und FileOutputStream. Diese Klassen bieten die Methoden read() zum Lesen von einzelnen Bytes bzw. write() zum Schreiben. Man legt sich einfach entsprechende Instanzen an und bergibt dabei dem Konstruktor den gewnschten Dateinamen oder ein entsprechendes File-Objekt. Dann knnen die Zugriffe mit read()/write() erfolgen und zuletzt sollte mit close() der jeweilige Ein-/Ausgabestream geschlossen werden, sodass damit verbundene Betriebssystemressourcen freigegeben werden. Das folgende Codefragment demonstriert das byteweise Kopieren einer Datei:
try { FileInputStream ein = new FileInputStream(datei.txt); FileOutputStream aus = new FileOutputStream(neu.txt); int b; // gelesenes Byte while( (b = ein.read()) != -1) { aus.write(b); }

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Ein- und Ausgabe Seite 285

ein.close(); aus.close(); } catch(IOException e) { System.out.println(e); }

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Ein- und Ausgabe Seite 286

Beachten Sie: read() liest zwar ein einzelnes Byte, gibt es aber nicht als byte, sondern als Typ int zurck. Das Ende eines Eingabestreams erkennt man daran, dass die read()Methode den negativen Wert -1 zurckgibt. Eine bessere Performance erreicht man mithilfe der Methoden int read(byte[] b) und void write(byte[] b), die ein ganzes byte-Array lesen bzw. schreiben. Der Rckgabewert von read() ist dabei die Anzahl von gelesenen Bytes oder -1 bei Stream-Ende. Tipp: Die optimale Verbindung von Programmierbarkeit und Performance bieten die Klassen BufferedInputStream und BufferedOutputStream fr gepufferte Ein- und Ausgaben, siehe unten.

19.3.2 BufferedInputStream/BufferedOutputStream
Hufig mchte man nicht einzelne oder ein paar tausend Bytes aus einer Datei lesen oder in sie schreiben, sondern sehr viel mehr. Viele einzelne Aufrufe von read()/write() sind jedoch recht zeitaufwndig. Daher bietet Java spezielle Klassen BufferedInputStream und BufferedOutputStream an, die eine automatische Zwischenspeicherung (Puffer) verwenden: Mehrere Lesezugriffe per read() fhren dann nicht zwangslufig zu mehreren read()-Aufrufen auf der Dateiebene (d. h. auf Betriebssystemebene), sondern sie werden zu einem einzigen Aufruf gebndelt. Fr den Programmierer ist dies transparent, d.h., er bekommt davon nichts mit. BufferedInputStream und BufferedOutputStream sogenannte Wrapper-Klassen, d.h. sie werden um vorhandene /Ausgabestreams herumgewickelt. Ihre Konstruktoren erwarten Parameter eine Instanz eines Ein- bzw. Ausgabestreams, z.B. FileInputStream. sind Einals von

Das folgende Beispiel zeigt das byteweise Dateikopieren in einer gepufferten und somit schnelleren Version.
try { FileInputStream ein = new FileInputStream(datei.txt); FileOutputStream aus = new FileOutputStream(neu.txt);

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Ein- und Ausgabe Seite 287

BufferedInputStream eingabe = new BufferedInputStream(ein); BufferedOutputStream ausgabe = new BufferedOutputStream(aus); int b; while( (b = eingabe.read()) != -1) { ausgabe.write(b); } eingabe.close(); ausgabe.close(); } catch(IOException e) { System.out.println(e); }

19.4 Zeichenorientierte Ein-/Ausgabe


In Java dienen die Klassen java.io.Reader und java.io.Writer als Basisklassen fr alle zeichenorientierten Ein-/Ausgabestreams. Diese Klassen sind jedoch abstrakt und knnen somit nicht instanziert werden. Erst die nachfolgend vorgestellten, abgeleiteten Klassen knnen direkt benutzt werden. Alle Reader-Klassen definieren die Methode read() zum Lesen von einem oder mehreren Zeichen. Analog definieren alle Writer-Klassen die Methode write() zum Schreiben von einem oder mehreren Zeichen.

19.4.1 FileReader/FileWriter
Die Ein- bzw. Ausgabe von Texten in Dateien erfolgt typischerweise mit dem Klassenpaar java.io.FileWriter zum Schreiben und java.io.FileReader zum Einlesen. Sie bilden das Gegenstck zu den byteorientierten Klassen FileInputStream und FileOutputStream. Wie bei diesen Klassen sind die elementaren Methoden int read() und void write(int b) zum Lesen bzw. Schreiben eines einzelnen Zeichens vorhanden, sowie int read(char[] b) und void write(char[] b) fr das Lesen und Schreiben eines ganzen Arrays. Nachfolgend sehen Sie, wie aus einer Textdatei die ersten 20 Zeichen eingelesen und in ein String-Objekt konvertiert werden:

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Ein- und Ausgabe Seite 288

try { FileReader ein = new FileReader("Test.txt"); char[] b = new char[20]; ein.read(b); String text = new String(b); } catch(IOException e) { System.out.println(e); }

FileWriter bietet noch eine Methode void write(String s) zum direkten Schreiben aus einem String heraus an; der Umweg ber ein char-Array wie beim obigen Einlesen ist nicht notwendig.

Icon HINWEIS

19.4.2 InputStreamReader/OutputStreamWriter
Die im vorangehenden Abschnitt genannten Klassen verwenden die fr das zugrunde liegende Betriebssystem eingestellte Zeichenkodierung, also meistens ISO-8859-1. Recht hufig wird aber eine andere Kodierung bentigt, z.B. UTF-8. Hierfr greift man auf die Klassen InputStreamReader bzw. OutputStreamWriter zurck. Sie besitzen Konstruktoren, die neben einem Ein-/Ausgabestream noch die Festlegung der gewnschten Kodierung ermglichen. Zum Lesen und Schreiben dienen die blichen read()- und write()-Methoden. Das nachfolgende Beispiel liest eine Datei mit der Kodierung ISO-8859-1 ein und schreibt sie als UTF-8.
try { InputStreamReader ein; ein = new InputStreamReader(new FileInputStream( "iso8859_1.txt"),"ISO-8859-1"); OutputStreamWriter aus; aus = new OutputStreamWriter( new FileOutputStream("utf8.txt"),"UTF-8"); int c; while( (c = ein.read()) != -1) { aus.write(c); } ein.close(); aus.close();

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Ein- und Ausgabe Seite 289

} catch(IOException e) { System.out.println(e); }

Der erste Parameter der Konstruktoren muss ein byteorientierter Ein/Ausgabestream sein, also keine Instanz vom Typ Reader/Writer. Den Konstruktoren kann die gewnschte Kodierung als String oder als Instanz von java.nio.Charset mitgegeben werden. Zur Auswahl stehen u.a. "US-ASCII", "ISO-8859-1", "UTF-8".

19.4.3 BufferedReader/BufferedWriter
Zum Lesen bzw. Schreiben von groen Textmengen gibt es wie bei den byteorientierten Ein-/Ausgabestreams auch die gepufferten Klassen java.io.BufferedReader und java.io.BufferedWriter, die intern Daten von read()- oder write()-Aufrufen sammeln und dann gebndelt an das Dateisystem weitergeben und dadurch das Lesen oder Schreiben um mehrere Faktoren beschleunigen knnen. Instanzen dieser Klassen werden um einen bestehenden zeichenorientierten Ein-/Ausgabestream gewickelt, indem man ihren Konstruktoren einen entsprechenden Stream bergibt, z.B. vom Typ FileReader oder auch InputStreamReader. Das folgende Codefragment zeigt das Beispiel aus dem vorangehenden Abschnitt unter Verwendung der gepufferten Klassen:
try { InputStreamReader ein; ein = new InputStreamReader(new FileInputStream( "iso8859_1.txt"),"ISO-8859-1"); OutputStreamWriter aus; aus = new OutputStreamWriter( new FileOutputStream("utf8.txt"),"UTF-8"); BufferedReader eingabe = new BufferedReader(ein); BufferedWriter ausgabe = new BufferedWriter(aus); int c; while( (c = ein.read()) != -1) { aus.write(c); } ein.close(); aus.close();

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Ein- und Ausgabe Seite 290

} catch(IOException e) { System.out.println(e); }

BufferedReader bietet noch eine Methode readLine() zum zeilenweisen Auslesen in Form von String-Objekten aus (ohne das Zeilenumbruchzeichen). Bei Erreichen des Dateiendes wird null zurckgeliefert, z. B.:
BufferedReader ein = ... String zeile; while( (zeile = ein.readLine()) != null) { ... }

Icon HINWEIS

Es gibt zu readLine() kein Analogon writeLine() in BufferedWriter, sondern lediglich eine Methode newLine() zum Schreiben eines neuen Zeilenumbruchzeichens.

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Schlsselwrter Seite 291

20 Schlsselwrter
Die mit * markierten Schlsselwrter sind fr zuknftige Erweiterungen reserviert oder entstammen anderen Programmiersprachen und wurden in die Liste aufgenommen, damit der Java-Compiler ihre Vorkommen leichter erkennen und als Fehler markieren kann. Die Schlsselwrter false, true und null sind Literale und knnen daher ebenfalls nicht fr eigene Variablennamen verwendet werden. abstract do assert boolean break byte case cast* catch char class const* default double else enum extends final finally float for future* implements protected import inner* int interface long native new null operator* package private public rest* short static strictfp super switch synchronized this throw throws transient true try var* void volatile while

instanceof return

byvalue* false

generic* outer* if

continue goto*

Tabelle 20.1: Schlsselwrter von Java

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Stichwortverzeichnis Seite 292

Stichwortverzeichnis
- 130 -- 131 ! 138 != 134 % 130 && 135 () 138 (Escape-Zeichen) 142 * 130 , 138 . 138 / 130 [] 138 \n (Zeilenumbruch) 105, 143 \t (Tabulator) 105, 143 ^ 137 || 136 + (Addition) 130 + (Strings) 144 ++ 131 < 134 <= 134 == 134 > 134 >= 134 Abbruchbefehle 169 abs() (Math) 139 abstrakte Klassen 237 acos() (Math) 139 ActionEvent (Klasse) 267 ActionListener (Interface) 267 actionPerformed() (ActionListener) 268 add() (Collection) 232 Allgemeine Programmiergrundlagen Register 22 Anweisungen 35 API Klassen FileInputStream 280 FileOutputStream 280 Methoden createNewFile() (File) 278 delete() (File) 279 Argumente 188

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Stichwortverzeichnis Seite 293

Array 115 Arrays 113 Arrays (Klasse) 115 asin() (Math) 139 Assembler 23 atan() (Math) 139 atan2() (Math) 139 Aufruf von Methoden 188 Aufzhlungen 115 Ausgabe 78 Ausnahmen 244 Autoboxing 123 Backslash-Zeichen 105 Basisklassenkonstruktor 216 Basisklassenunterobjekt 213 Bedingungen 29, 156 Bezeichner 69 Bezeichner, voll qualifizierte 69 Bibliotheken 44 Bildschirmausgaben 27 Bogenma 141 Boolean 120 break 159, 169 BufferedInputStream 282 BufferedOutputStream 282 (Klasse) (Klasse)

BufferedWriter (Klasse) 285 Byte 120 case 159 catch 245, 248 cbrt() (Math) 139 ceil() (Math) 139 Character 120 charAt() (String) 146 class 74, 175 clear() (Collection) 232 clone() (Object) 220 Collections 230 Collections (Klasse) 235 compareTo() (String) 145, 147 compareToIgnoreCase() (String) 147 Compiler 7, 25 concat() (String) 147 Container 230 contains() (String) 147 continue 169 cos() (Math) 139 cosh() (Math) 139 createNewFile() (File) 278 Dateien 277, 280 lesen (Bytes) 280 schreiben (Bytes) 280

BufferedReader (Klasse) 285

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Stichwortverzeichnis Seite 294

Verzeichnisse 277 Datentypen 34, 97, 102 default 159 Deklaration 36 Dekrement 131 delete() (File) 279 Divide-and-Conquer 52 Double 120 do-while 167 Downcast 229 dynamische Bindung 225 Ein- und Ausgabe 277 Dateien 280 Einbettung 210 Eingabe 78 Eintrittspunkt 42 else 157 Endlosschleifen 166 endsWith() (String) 145, 147 enum 115 Enumeration (Interface) 235 equals() (Object) 220 equals() (String) 145, 147 Ereignisse 266 Error (Klasse) 250, 252 Escape-Sequenzen 105, 142 Exception (Klasse) 252

Exception-Behandlung 244 exp() (Math) 139 expm1() (Math) 139 extends 210, 274 Felder 49, 177 File 277 FileInputStream (Klasse) 280 FileOutputStream (Klasse) 280 FileReader (Klasse) 283 FileWriter (Klasse) 283 final 190 final (fr Variablen) 96 finalize() (Object) 220 finally 252 Float 120 floor() (Math) 139 for 167 Funktionen 40 Generics 270 getCause() (Throwable) 251 getClass() 229 getClass() (Object) 220 getMessage() (Throwable) 251 Gleitkommazahlen 34 Gro- und Kleinschreibung 87 Grundgerst 9 16,

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Stichwortverzeichnis Seite 295

Gltigkeitsbereich 101 hashCode() (Object) 221 if 155 Import-Anweisung 68 indexOf() (String) 147 Indizierung 114 Information hiding 110 Initialisierung 100 Inkrement 131 InputStream (Klasse) 280 InputStreamReader (Klasse) 284 instanceof 228, 274 Instanzbildung 55, 109 Instanzen 49 Instanzierung 55 Integer 34, 120 interface 241 Interfaces 112, 238 Interpreter 7, 25 InterruptedException 261 Iteration 164 Iteratoren 233 java 12 javac 11 join() (Thread) 261 JRE 8 (Klasse)

Kapselung 110 KEdit 10 Klammern (in Ausdrcken) 128 Klassen 45, 107 Klassen, anonyme 257 Klassen, innere 256 Klassen, lokale 256 Kommentare 27, 66 Kompilierzeit 35 Konkatenation 144 Konsole 27 Konsolenanwendungen 9 Konstanten 94 Konstruktoren 58, 197 Kontrollstrukturen 29, 154 lastIndexOf() (String) 147 Laufzeit 35 Laufzeitumgebung (JRE) 8 leere Anweisung 157 length() (String) 147 Linker 25 Literale 27, 94 log() (Math) 139 log10() (Math) 140 Long 120 main() 75 matches() (String) 147

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Stichwortverzeichnis Seite 296

Math (Klasse) 138 max() (Math) 140 Methoden 51, 183 Methodenaufruf 193 min() (Math) 140 Modularisierung 40 Namen 69 Namen, voll qualifizierte 69 Namensgebung 86 Namespaces 69 Neue Zeile-Zeichen 105, 143 new 106 Notepad++-Editor 10 Notepad-Editor 10 Object (Klasse) 219 Objekte 49 Objekte, anonyme 255 Objektorientierte Programmierung 45 Objektvariablen 49 ffentliche Schnittstelle 110 Operatoren 27, 127 OutputStream (Klasse) 280 OutputStreamWriter 284 Parameter 186 Parameter 42 Polymorphie 223 (Klasse)

pow() (Math) 140 printStackTrace() 251 private 181 Programmerstellung 10 Prompt 28 protected 181, 215 Prozessor 22 public 180 RAM 96 Random (Klasse) 276 random() (Math) 140 Referenztypen 55, 106 Register 22 remove() (Collection) 232 replace() (String) 148 replaceAll() (String) 148 return 169, 192 round() (Math) 140 Rckgabewert 42 Rckgabewerte 190 run() (Thread) 258 Runnable (Interface) 262 RuntimeException (Klasse) 250 Schleifen 31, 163 Schleifenvariable 31, 164 Schlsselwrter 36, 287 (Throwable)

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Stichwortverzeichnis Seite 297

Semikolon 157, 167 Short 120 Signatur 76 signum() (Math) 140 sin() (Math) 140 sinh() (Math) 140 size() (Collection) 232 sleep() (Thread) 260 Sortieren 235 Speicherbereinigung 107 sqrt() (Math) 140 Standardkonstruktor 198 start() (Thread) 258 startsWith() (String) 148 static 181 statische Klassenelemente 61 Stil 87 Streams 279 String 18 Strings 23, 117, 141 Stringvergleiche 144 substring() (String) 148 Suche 235 super 218, 274 switch 158 Symbole 138 Synchronisierung (Threads) 263

synchronized 263 Tabulatorzeichen 105, 143 tan() (Math) 140 tanh() (Math) 140 this 194 Thread (Klasse) 258 Threads 258 throw 245, 246 Throwable (Klasse) 251 throws 250 toDegrees() (Math) 140 toLowerCase() (String) 148 toRadians() (Math) 140 toString() (Object) 146, 221 toString() (Throwable) 249, 251 toUpperCase() (String) 148 Trigonometrische 141 trim() (String) 148 try 245, 248 Typidentifizierung 228 Typisierung 33 Typumwandlung 39, 118, 146 berladung 58, 195 berschreibung 218 Upcast 229 valueOf() (String) 146, 148 Funktionen

Tutorium zu Jetzt lerne ich Android 4-Programmierung


ISBN 978-3-8272-4818-3 Stichwortverzeichnis Seite 298

Variablen 25, 96 Vektoren 173 Vererbung 63, 112, 209 Vergleich, lexikographisch 145 Vergleiche 30 Verzeichnisse 277 Verzweigungen 31, 155 vi 10

Virtual Machine 8 while 164 Wrapper-Klassen 120 Zeichenketten 141 Zeichenkodierung 284 Zufallszahlen 276 Zugriffsspezifizierer 60, 180, 201 Zuweisung 99, 131