Sie sind auf Seite 1von 12

Plattformunabhängigkeit

- Ein Applet läuft auf allen gängigen Rechnern und


Betriebssystemen (PC, Workstation, UNIX, Windows...)
- Entsprechend auch: Graphische Interfaces (GUI)
- Zeit- / Kostenersparnis in der Softwareindustrie
- Hier aber noch gewisse Probleme mit den APIs

Einführung in das Java-Source


Programmieren
Java-
mit Java Compiler

Java- Maschinensprache einer


Praktikum zur Vorlesung Verteilte Systeme Bytecode virtuellen Maschine (VM)

Browser mit Betriebssy- VM in speziel-


integrierter VM stem mit VM lem VLSI-Chip

Network- Spiel-
Computer Console Handy Waschmaschine

- VM ist ein Bytecode-Interpreter


- programmierter Simulator der virtuellen Maschine
- relativ einfach für verschiedene Plattformen realisierbar

- Effizienzverlust durch Interpretation?


- ggf. in Zielsprache (weiter-) übersetzen

- Prinzip an sich ist nicht neu (vgl. Pascal-P-Maschine)


Java-Einführung, 0 Java-Einführung, 1

Hello World Java-Programmstruktur


- Das "Programm" (eine Klasse!): import ... - Mit import werden anderweitig vorhandene
Pakete von Klassen verfügbar gemacht
class A {
class Hallo {
Klassenkörper - Der Klassenkörper enthält
// Mein erstes Java-Programm!!
- statische Klassenvariablen ("Attribute")
public static void main (String args[]) {
- benannte Konstanten
System.out.println("Hello Java-World!"); Konstruktor {
... - klassenbezogene Methoden
} }
} ein ’;’ beendet jede Anweis- - Konstruktoren sind spezielle Methoden
ung und jede Deklaration
Method_M1 { - Methoden können bestehen aus
- Unix Shell: ... - Parametern
}
%ls - lokalen Variablen
Hallo.java - Anweisungen
Method_M2
... ...
%javac Hallo.java - Bei eigenständigen Programmen
(=/= Applets) muß es eine "main"-
} Methode geben, die so aussieht:
%ls
Hallo.java Hallo.class public static void
class B { main (String args[]){...
%java Hallo
Hello Java-World! - Jede Klasse kann eine (einzige) solche
... ... main-Methode enthalten; sie wird ausge-
führt, wenn der entsprechende Klassen-
- Datei sollte gleich wie die Klasse heißen name beim "java"-Kommando genannt wird

- Klassen können getrennt übersetzt werden


- Kommentare:
// bis Zeilenende - Es gibt keine globalen Variablen etc.
/* oder
so über mehrere
Zeilen */

Java-Einführung, 2 Java-Einführung, 3
"Removed from C/C++" Einfache Datentypen
You know you've achieved perfection in design,
Not when you have nothing more to add, Integer (Zahlen im 2er-Komplement):
But when you have nothing more to take away. byte (8 Bits)
Antoine de Saint Exupery short (16 Bits)
int (32 Bits)
long (64 Bits)
- Strukturen, union (statt dessen: Klassen)
- Zeigerarithmetik, malloc (aber: arrays und new) Floating Point, IEEE 754-Standard
- Funktionen (statt dessen: Methoden) float (32 Bits)
- Mehrfachvererbung (statt dessen: interfaces) double (64 Bits)

- Präprozessor: #define, #include, #ifdef, ...


Zeichen (Unicode! --> "Internationalisierung")
- #DEFINE (statt dessen: final static)
char (16 Bits)
- Überladen von Operatoren
- goto (statt dessen: break/continue, exceptions) Wahrheitswerte (nicht mit Integer kompatibel!)
- .h-Dateien (aber: Pakete) boolean (true/false)
- Destruktoren, free (aber: Garbage-Collecor; finalize)
- Implizite Typkonvertierung Referenzen auf Objekte ("Zeiger")

Außerdem neu gegenüber C++ - Es gibt natürlich auch arrays und strings (--> später)
- Komplexere Datentypen lassen sich mit Klassen bilden
- Threads in der Sprache (als Objekte) - alle nicht-einfachen Datentypen sind Objekte (als Instanzen
- Datentyp "boolean" von vorgegebenen oder eigenen Klassen)
- Character im 16-Bit-Unicode ("Internationalisierung") - auch einfache Datentypen können in Klassen gepackt werden
Java-Einführung, 4 Java-Einführung, 5

Variablen, Bezeichner, Deklaration Typkonvertierung


- Bezeichner müssen sich von keywords unterscheiden
- es gibt ca. 50 keywords (int, class, while,...) - Java ist eine streng typisierte Sprache
- es gibt Standardklassen und -methoden (z.B. String, File, Stack...) --> Compiler kann viele Typfehler entdecken
- Sonderzeichen (Umlaute etc.) sind in Namen zulässig
- Gelegentlich muß dies jedoch durchbrochen werden
- Konvention: --> Typecast (to cast --> hier: "formen"; "in Form bringen")
- Variablen und Methoden beginnen mit einem Kleinbuchstaben
- Klassennamen beginnen mit einem Großbuchstaben
- benannte Konstanten ganz mit Großbuchstaben
- So geht es nicht (-->Fehlermeldung durch Compiler):
int myInt;
- Beispiele für Deklarationen: double myFloat = 3.14159;
int j;
myInt = myFloat;
int i = 1; // mit Initialisierung
float x_koordinate, y_koordinate;
String s = "Hallo"; - Statt dessen explizite Typumwandlung:
Person p = new Person ("Hans Dampf", 1974);
float [][] matrix; // 2-dimensionales array int myInt;
double myFloat = 3.14159;
- Namensräume; einige "grobe" Regeln: myInt = (int)myFloat;
- zwei im gleichen Namensraum deklarierte Variablen
müssen verschieden heißen
- Umwandlung hin zu einem größeren Wertebereich
- typische Namensräume: Methoden und Klassenrümpfe
(z.B. int --> float) geht auch implizit
- mit {...} wird kein neuer Namensraum festgelegt (aber: for-Schleife etc!)
- lokal deklarierte Bezeichner können andere Bezeichner
verdecken (z.B. ererbte Attribute, importierte Typen) - Typumwandlung ist gelegentlich bei Referenzen sinnvoll:
- Deklarationen müssen nicht am Anfang stehen, sondern Hund h; Tier fiffi;
können mit Anweisungen "gemischt" werden ...
- es gibt keine (absolut) globalen Variablen etc. if (fiffi instanceof Hund)
h = (Hund)fiffi;
- "voll qualifizierte" Namen: Paketname.Klassenname.Attributname
Java-Einführung, 6 Java-Einführung, 7
Operatoren Priorität der Operatoren
- Binäre arithmetische Operatoren postfix operators [] . (params) expr++ expr--
+ op1 + op2 (auch für Stringkonkatenation!) unary operators ++expr --expr +expr -expr ~
- op1 - op2 creation or cast new (type)expr
* op1 * op2 multiplicative * / %
/ op1 / op2 + -
% op1 % op2 (Rest bei Division) additive
shift << >> >>>
- Shortcut ++ und -- (Inkrementieren / Dekrementieren) relational < > <= >= instanceof
equality == !=
op++ (Wert vor Inkrementierung auswerten)
++op (..nach...) bitwise AND &
op-- bitwise exclusive OR ^
--op |
bitwise inclusive OR
- weitere Abkürzungen: i = i+7 ersetzen durch i += 7 etc. logical AND &&
logical OR ||
- Relationale Operatoren ? :
conditional
> op1 > op2 ("true", wenn op1 größer als op2) assignment = += -= *= /= %= ^= &= ...
>= op1 >= op2
< op1 < op2
<= op1 <= op2 - Ansonsten (und in Zweifelsfällen) Klammern verwenden!
== op1 == op2 (gleich)
!= op1 != op2 (ungleich)
- Auswertungsreihenfolge von links nach rechts
- Logische Operatoren
- es werden alle Operanden vor Ausführung der Operation ausgewertet
&& op1 && op2 ("und") - Ausnahme bei && und | | :
|| op1 || op2 ("oder")
if((count > NUM_ENTRIES) &&
! !op (Negation)
(System.in.read() != -1))...
- Bit-Operatoren: & | ^ ~ >> << >>> Java-Einführung, 8
hier wird der zweite Operator von && ggf. nicht ausgewertet! Java-Einführung, 9

Kontrollstrukturen Switch
class CompNum { so werden benannte
static final int last=100; Konstanten definiert int monat;
. . .
//... switch (monat) {
/* Zusammengesetzte for-Kontrolltripel: Initialisierung,
Terminierung, Inkrement case 1: System.out.print("Jan"); break;
Zahlen in 1..last*/ case 2: System.out.print("Feb"); break;
for(int i=2; i <= last; i++) case 3: System.out.print("März"); break;
{ int j=2; i und j dürfen außerhalb des for- . . .
Test: Blockes nicht (schon) deklariert sein default: System.out.print("Fehler"); break;
while (j*j <= i) { }
Anweisungsblöcke in {...}
if (i%j == 0) {
System.out.println(i); . . .
break Test; break ohne label beendet den innersten switch (monat) { ohne break wird mit dem näch-
} sten case-Zweig fortgefahren
Kontrollblock (for, while, switch...) case 1:
else case 3:
else-Teil ist natürlich optional case 5:
j++;
} case 7:
case 8:
} case 10:
// Hier sind i und j nicht mehr sichtbar case 12:
//... numDays = 31;
break;
- Weitere Kontrollkonstrukte: case 4:
- switch . . .
- return (Methode beenden; ggf. mitRückgabewert) }
- continue (Sprung an das Ende einer ggf. benannten Schleife)
- exception-handling
- do-while (Auswertung erst am Ende der Schleife; Schleifen-
körper wird mindestens ein Mal ausgeführt)
do {
statements
} while (booleanExpression);
Java-Einführung, 10 Java-Einführung, 11
Ein- und Ausgabe Einlesen von Zahlen
int count = 0; in diesem Paket stehen die Ein-Ausgabe-
while (System.in.read() != -1) import java.io.* ; Methoden (innerhalb von "Dateiklassen")
count++; class X {
System.out.println("Eingabe hat " +
count + " Zeichen."); public static void main (String args[])
throws java.io.IOException die auftretbaren exceptions
{ müssen nach throws am
int i = 0; String Zeile; Anfang einer Methode
- System.in: DataInputStream ein = genannt werden
- System ist eine Klasse mit Schnittstellenmethoden zum new DataInputStream(System.in);
ausführenden System (Betriebssystem, Rechner) Der InputStream muß beim Aufruf des
while(true) Konstruktors angegeben werden
- System.in ist der Standard-Eingabestrom (vom Typ InputStream) {
- read liest ein einzelnes Zeichen; liefert -1 bei Dateiende,
Zeile = ein.readLine();
ansonsten einen Wert zwischen 0 und 255 für das Zeichen i += Integer.valueOf(Zeile).intValue();
System.out.println(i);
- es gibt noch einige weitere Methoden (skip, close...) } man könnte hier auch
- erst abgeleitete Typen von InputStream enthalten Methoden, ... "readLine()" für "Zeile"
um ganze Zeilen etc. zu lesen (z.B.Klasse DataInputStream) substituieren

- Die Klasse DataInputStream enthält die Methode


- System.out: Standard-Ausgabestrom readLine, welche alle Zeichen bis Zeilenende liest
- print gibt das übergebene Argument aus und daraus einen String konstruiert
- println erzeugt zusätzlich noch ein newline
- es können u.a. int, float, string, boolean... ausgegeben werden - "Integer" ist eine Wrapper-Klasse, welche Konver-
tierungsroutinen etc. enthält
- "valueOf" ist eine Methode von Integer, die einen
String nach Integer konvertiert
- "intValue" ist eine Methode, die aus einem Integer-Objekt
den int-Wert "herausholt"

- Entsprechend kann man floating-point-Zahlen


Java-Einführung, 12 etc. einlesen Java-Einführung, 13

Objektorientiertes Programmieren Klassen


Weltsicht: Die Welt besteht aus verschiedenen inter- - können zu Objekten "instanziiert" werden
agierenden "Dingen", welche sich klassifizieren lassen. - sind daher Schablonen, Prototypen, Muster, templates...
- stellen den Typ der daraus erzeugten Objekte dar
Ding 1
Typ B Ding 4 - realisieren abstrakte Datentypen
Ding 2 Typ A
Typ B - enthalten Variablen ("Attribute")
machen den Zustand der zugehörigen Objekte aus
sichtbare ("public") / verborgene ("private") Variablen

Ding 3 - enthalten Methoden als Anweisungskomponenten


Typ A Ding 5
Typ B realisieren die Funktionalität der Objekte
sichtbare / verborgene Methoden

Ziel: Betrachteten Weltausschnitt strukturkonsistent mit - sind hierarchisch (= baumartig) organisiert


kommunizierenden Objekten abbilden und modellieren. Spezialisierung, Verallgemeinerung, Vererbung ==> Klassenhierarchie
Simulationssprache SIMULA war die erste
objektorientierte Programmiersprache (1967)
Objektorientiertes Programmieren =
Objekte:
- Strukturierung der Problemlösung in eine Menge
- sind autonome gekapselte Einheiten (= Module) kooperierender Objekte
- haben einen eigenen Zustand (= lokale Variablen)
- besitzen ein Verhalten (wenn sie aktiviert werden) - Entwurf der Objekttypen (= Klassen)
- bieten anderen Objekten Dienstleistungen an - Herausfaktorisierung gemeinsamer Aspekte verschie-
dener Klassen ==> Hierarchie, Klassenbibliothek
- Durchführung von Berechnungen
- Änderungen des lokalen Zustandes - Festlegung der einzelnen Dienstleistungen
- Zurückliefern von Variablenwerten oder Berechnungsergebnissen - Entwurf der Objektbeziehungen ("Protokoll")
- Allgemein: "Reaktion" auf Aufruf einer "Methode"
- Feinplanung der einzelnen Methoden, Festlegung
- besitzen eine Identität der Klassenattribute etc.
- sind von einem bestimmten Typ - Strukturierung und Implementierung der Methoden
(= "Klasse" gleichartiger Objekte) Java-Einführung, 14 Java-Einführung, 15
Eine Beispiel-Klasse in Java Verwendung von Klassen
class Datum Der Name der Klasse Diese 3 Attribute - Zugriff auf Methoden und Variablen ("Attribute")
sind von außerhalb eines Objektes mit Punktnotation
{ private int Tag, Monat, Jahr; nicht sichtbar
hier wird der erste Konstruktor aufgerufen
Eine Metode mit dem gleichen Namen wie class Beispiel
die Klasse selbst stellt einen "Konstruktor" dar.
Er wird bei Erzeugen eines Objektes auto- { public static void main (String args[])
matisch aufgerufen; man kann (nur) damit die
neuen Objekte (deren Variablen) initialisieren. { Datum Ostermontag = new Datum();
public Datum() /* Datum mit Wert 0.0.0. gegründet */
{ System.out.println("Datum mit Ostermontag.Drucken(); liefert 0.0.0
Wert 0.0.0. gegründet"); Ostermontag.Setzen(31,03,97);
};
Diese Klasse hat einen zweiten Konstruktor Ostermontag.Drucken();
liefert 31.3.97
mit einer unterschiedlichen Signatur. Welcher }
Konstruktor genommen wird, richtet sich
nach der Signatur beim new-Aufruf. }

public Datum(int T, int M, int J) - "Ostermontag" ist eine Variable vom Typ "Datum".
{ Tag = T; Monat = M; Jahr = J; }; - genauer: eine Referenz, die auf Datum-Objekte zeigen kann
- alle Referenzen haben den Defaultwert null
public void Drucken()
{ System.out.println(Tag + "." + - Objekte werden mit new erzeugt, dabei wird eine Referenz
Monat + "." + Jahr); } auf das neu erzeugte Objekt zurückgeliefert

Dies sind zwei Methoden - Eigentlich sollte "Setzen" zumindest einen Plausi-
bilitätstest machen (Monat ≤ 12, Tag ≤ 31 etc.).
public void Setzen (int T, int M, int J)
{ Tag = T; Monat = M; Jahr = J; }; - Datenstrukturen mit zugehörigen Operationen
}; --> abstrakte Datentypen
- Klassen können also abstrakte Datentypen implementieren
Java-Einführung, 16 Java-Einführung, 17

Statische Klassenvariablen Methoden mit Parameter


static-Variablen existieren
für alle Instanzen einer - Bei Aufruf von Methoden kan man Parameter übergeben
Klasse nur ein einziges Mal!
class Datum { - Wertübergabesemantik ("by value")
public static int Zahl =0; - Auch Referenzen "by value" - referenzierte Objekte damit "by reference"
private int Tag, Monat, Jahr;
public Datum() {... Zahl++;} hier wird der class Datum d ist ein formaler Para-
... andere Konstruk- meter vom Typ "Datum"
wie vorhin tor verwendet { ...
class Beispiel { ... boolean frueher_als(Datum d)
Datum Geburtstag = new Datum(23,03,56); { return Jahr<d.Jahr ||
Geburtstag.Drucken(); liefert 23.3.56 Jahr==d.Jahr && Monat<d.Monat ||
Datum Glueckstag; Jahr==d.Jahr && Monat==d.Monat
Glueckstag = Geburtstag; Zuweisung von Referenzen && Tag<d.Tag;
Glueckstag.Drucken(); liefert 23.3.56 }; Methode liefert einen Boole’schen
} Wert zurück; ist also nicht void
Datum[] Januar = new Datum[32];
for (int i=1; i<=31; i++) class Beispiel
{ Januar[i] = new Datum(i,01,97); { ...
Datum d1 = new Datum(23,03,56);
Januar[i].Drucken();
Datum d2 = new Datum(27,03,56);
} System.out.println(d1.frueher_als(d2));
System.out.println("Es gibt " + /* true */
liefert 32
Datum.Zahl + " Datum-Objekte"); System.out.println(d2.frueher_als(d1));
... Statt Datum hätte man auch "Geburtstag" /* false */
oder "Glueckstag" schreiben können } Hier wird die Funktion "frueher_als" aus dem Objekt
d2 aufgerufen, und zwar mit Objekt d1 als Parameter.

- Statische Variablen in Klassen wirken also ähnlich wie "globale Durch diese in der Klasse "Datum" definierten Operationen kann man
Variablen" in anderen Sprachen. Alle Objekte einer Klasse sehen nun also Datum-Objekte bezüglich früher / später vergleichen - ganz
immer den gleichen Wert ==> Kann zur Kommunikation zwischen analog, wie man beispielsweise ganze Zahlen ("int-Objekte") mit dem
diesen Objekten benutzt werden.
Operator ’<’ vergleichen kann!
Java-Einführung, 18 Java-Einführung, 19
Gleichheit und "this" Vererbung ("inheritance")
- Gleichheit ist keine "natürlich gegebene" Eigenschaft. - Idee: Vorhandene Klasse zur Definition einer
Sie muß erst geeignet definiert werden (Abstraktion!) neuen "ähnlichen" Klasse verwenden
Erweitert oder angepaßt an spezifi-
d1 27 27 d4 12 Objekt sche Bedürfnisse ("Spezialisierung")
3 3 d3 Referenz- 3
d2 56 56 name 56

- welche der Paare von Referenzen sollen als gleich gelten?


- was würde ein Vergleich mit dem Operator "==" bringen? Klassenhierarchie:
Basisklasse (auch:
class Datum... “Oberklasse”)
Fahrzeug
boolean frueher_als(Datum d)... abgeleitete Klassen
boolean gleich(Datum d) von "Fahrzeug" (auch:
{ return !frueher_als(d) && Fahrrad Auto
“Unterklassen” oder
!d.frueher_als(this) ; }; “erweiterte Klassen”)
...
Hier wird die Funktion "frueher_als" aus dem Objekt d PKW LKW
aufgerufen, und zwar mit "einem selbst" als Parameter! Entwurf eines Klassen-
baumes ist wichtige
class Beispiel ... Aufgabe der Entwurfs-
Datum d1 = new Datum(23,03,56); VW Ford
phase beim objektorien-
Datum d2 = new Datum(27,03,56); tierten Programmieren!
System.out.println(d1.gleich(d2));/*false*/
"is-a"-Relation
Datum d3 = new Datum(23,03,56);
System.out.println(d1.gleich(d3));/*true*/ - Ein VW ist ein PKW ist ein Auto ist ein Fahrzeug
- Eine Trompete ist ein Blasinstrument ist ein Musikinstrument
- Beachte: "this" ist ein Schlüsselwort, mit dem stets
ein Zeiger auf das aktuelle Objekt zurückgeliefert wird - Ein Fahrzeug hat Räder ==> ein PKW hat Räder

- "gleich" ließe sich natürlich auch direkter, ohne Eigenschaften werden ("von oben nach
Rückgriff auf "frueher_als" realisieren unten") an abgeleitete Klassen vererbt!
Java-Einführung, 20 Java-Einführung, 21

Abgeleitete Klassen Ein Beispiel in Java


class Fahrzeug
- Eine abgeleitete Klasse besitzt automatisch alle { public int Radzahl };
Eigenschaften der zugehörigen Basisklasse(n). Erweiterung der Klasse
class Auto extends Fahrzeug "Fahrzeug": Alles, was
- Konkret: Sie besitzt alle "Attribute" und { public int PS; in "Fahrzeug" dekla-
alle "Methoden" der Basisklassen. riert ist, gehört damit
public float Hubraum;}; auch zu "Auto" (sowohl
Attribute als auch
- Außer: Es werden einige davon unsichtbar gemacht class PKW extends Auto Methoden) - mit gewis-
oder einige Methoden redefiniert. { public int Beifahrerzahl; sen Einschränkungen
(--> später)
void print()
Heißen noch genauso, {System.out.println("Radzahl: "+ Radzahl
tun aber etwas anderes!
+ Beifahrerzahl: " + Beifahrerzahl);}
};
- Eine abgeleitete Klasse kann zusätzliche Attribute Auf "weiter oben"
definierte Attribute
und Methoden definieren. class LKW extends Auto kann ohne weiteres
{ public float Zuladung; }; zugegriffen werden -
diese sind Teil der
Fahrzeug: Auto: PKW: class Beispiel { abgeleiteten Klasse!
- Radzahl - Radzahl - Radzahl public static void main (String args[]) {
- km-Stand - km-Stand - km-Stand Fahrzeug f = new Fahrzeug();
- PS - PS Auto a = new Auto(); Hier werden Instanzen (also
"Fahrzeugteil" - Hubraum - Hubraum PKW p = new PKW(); Objekte) der verschiedensten
eines Autos - Anzahl LKW l = new LKW(); Hierarchiestufen erzeugt.
"Autoteil"
eines PKW Beifahrer
p.Beifahrerzahl = 5;
p.PS = 70; Zugriff auf Variablen
p.Hubraum = 1794; und Methoden des
- Eine Methode "Berechne_KFZ_Steuer" läßt sich p.Radzahl = 4; mit ’p’ bezeichneten
PKW-Objektes.
nicht für alle Fahrzeuge gleichermaßen definieren. p.print();
==> Man würde z.B. in "Auto" eine Standardmethode Idee: Gemeinsame Aspekte heraus-
vorsehen (Benutzung von "Hubraum"), jedoch für p.Zuladung geht faktorisieren und in eine überge-
spezielle Fahrzeuge (z.B. Elektroautos) diese natürlich nicht!
ordnete Klasse einbringen.
Methode anders definieren. Java-Einführung, 22 Java-Einführung, 23
Zuweisungskompatibilität Ein Java-Beispiel
- Objekte von abgeleiteten Klassen können an Variab- class Fahrzeug {... int Radzahl;}
len vom Typ der Basisklasse zugewiesen werden. class Auto extends Fahrzeug {...float Hubraum;}
class PKW extends Auto ...
- Fahrzeug f; Auto a; ... f = a; Fahrzeug
Fahrzeug f; Auto a; PKW p; Radzahl
- Variable f kann Fahrzeugobjekte speichern. ... new ...
- Ein Auto ist ein Fahrzeug. p.Hubraum = 1702; Ein PKW ist ein Auto
- Daher kann f auch Autoobjekte speichern. Auto
p.Radzahl = 4; und ein Fahrzeug
Hubraum
a = p;
- Die Umkehrung gilt jedoch nicht! f = p; Eine Fahrzeug-Variable darf PKW-
f = a; Objekte und Auto-Objekte speichern PKW
- a = f; ist verboten! /* a = f; */
- Variable a kann Autoobjekte speichern. /* incompatible types for =... */
- Ein Fahrzeug ist aber kein Auto!
Andersherum geht es nicht!
a.Radzahl = 3;
a.Hubraum = 1100;
"Gleichnis" zur Zuweisungskompatibilität: Auf einem Parkplatz für f = a; Es wurde zwar Radzahl und Hub-
Fahrzeuge dürfen Autos, PKWs, Fahrräder... abgestellt werden. Auf raum zugewiesen; auf Hubraum
System.out.println ist aber über f nicht zugreifbar!
einem Parkplatz für Fahrräder jedoch keine beliebigen Fahrzeuge!
(f.Radzahl);
/* System.out.println(f.Hubraum); */;
/* No variable Hubraum defined in Fahrzeug */
genauer: Zeiger
- Merke also: auf Basisklasse
- f.Hubraum ist aus gutem Grund verboten: Auf f könnte
Eine Variable vom Typ "Basisklasse" darf ja zufällig ein Fahrrad (ohne Hubraum!) "parken"!
! auch auf ein Objekt der abgeleiteten Klasse zeigen!
- Durch Umtypen kommt man aber notfalls auch über f an den Hubraum
des Auto-Objektes: System.out.println(((Auto)f).Hubraum);
Man nennt diese Eigenschaft auch Polymorphismus, da - Aber wenn dort "gerade" kein Auto (sondern ein Fahrrad) parkt?
ein Zeiger auf Objekte verschiedenen Typs zeigen kann. Dann gibt es einen Laufzeitfehler "ClassCastException"!
(Bzw. eine Variable Werte untersch. Typs haben kann.) - Dem kann man wie folgt vorbeugen:
if (f instanceof Auto)
Beispiel: Eine Variable vom Typ "Zeiger auf Fahrzeug" kann System.out.println(((Auto)f).Hubraum);
zur Laufzeit sowohl zeitweise auf PKW-Objekte, else System.out.println("kein Auto, kein Hubraum!");
als auch zeitweise auf LKW-Objekte zeigen.
Java-Einführung, 24 Java-Einführung, 25

PKW/LKW-Beispiel (1) PKW/LKW-Beispiel (2)


class AUTO {
int i, j; Zuweisung von den "temporären"
AUTO(int ii) { Variablen des Konstruktors an
i = ii; j = ii+1; "permanente" Variablen Ein_Auto Ein_PKW Ein_LKW
}
void Meldung() {
System.out.println("AUTO: "
Auto Auto Auto
+ i + " " + j);
} die Variable "i" existiert i= i= i=
} auf allen Ebenen! j= j= j=
PKW LKW
class PKW extends AUTO { i= i=
int i, k; k= m=
PKW(int ii) { hier wird der Konstruktor Anderes_Auto
super(ii*2); der Oberklasse aufgerufen Für Methoden, die in einer Unterklasse
i = ii; k = ii+1; (hier: PKW bzw. LKW) definiert sind,
} ist eine überdefinierte Variable (hier: i)
void Meldung() { verdeckt und nicht direkt zugreifbar.
System.out.println("PKW: "
+ i + " " + j + " " + k); Allerdings kann mit "super.i" die obere
Variable aus PKW und LKW erreicht werden
}
}
class LKW extends AUTO {
int i, m;
LKW(int ii) { LKW ganz analog zu PKW
super(ii*2); (Variable "m" statt "k")
i = ii; m = ii+1;
}
void Meldung() {
System.out.println("LKW: "
+ i + " " + j + " " + m);
}
}
Java-Einführung, 26 Java-Einführung, 27
PKW/LKW-Beispiel (3) Felder (arrays)
AUTO Ein_AUTO, Anderes_AUTO; int [] x; // array of int
PKW Ein_PKW, Anderer_PKW; x = new int[7]; // Länge 7 (Indexbereich 0..6)
Ein_AUTO = new AUTO(5); for (int i=0; i < x.length; i++) x[i]=17;
System.out.println(Ein_AUTO.i); /* 5 */
System.out.println(Ein_AUTO.j); /* 6 */ int [] w = new int[7]; // so geht es auch
/* System.out.println(Ein_AUTO.k); */
/* No variable k defined in class AUTO */ y = x; // y zeigt auf das gleiche Objekt
Ein_AUTO.Meldung(); /* AUTO: 5 6 */ y[3] = 9; // x[3] ist daher jetzt auch 9
Ein_PKW = new PKW(22);
null
System.out.println(Ein_PKW.i); /* 22 */
System.out.println(Ein_PKW.j); /* 45 */ 03 01 1996 Datum[1]

Januar
System.out.println(Ein_PKW.k); /* 23 */
Ein_PKW.Meldung(); /* PKW: 22 45 23 */ 07 01 1996 Datum[2]
null
durch "casting" ("Typkonversion") kann auf die null
verdeckte Variable "i" dennoch zugegriffen werden
Datum[] Januar = new Datum[32];
System.out.println(((AUTO)Ein_PKW).i); /* 44*/
System.out.println(((AUTO)Ein_PKW).j); /* 45*/ // Damit wird ein array mit 32 Verweisen
// auf potentielle Datum-Objekte angelegt.
Anderes_AUTO = Ein_AUTO; // Die Verweise sind zunächst null.
Ein_AUTO.i = 2; // Erst so zeigen sie auf ein Datum-Objekt:
System.out.println(Anderes_AUTO.i); /* 2 */
Anderes_AUTO.Meldung(); /* AUTO: 2 6 */ Januar[1] = new Datum(01,01,1996);
Januar[2] = new Datum(02,01,1996);
...
LKW Ein_LKW = new LKW(333); Januar[31]= new Datum(31,01,1996);
Ein_LKW.Meldung(); /* LKW: 333 667 334 */ // Zugriff: ... Januar[27].Jahr ...
/* Ein_LKW = Ein_PKW ; */
/* Incompatible type. Can't convert PKW to LKW */
Java-Einführung, 28 Java-Einführung, 29

Zeichenketten (Strings) Noch mehr Strings...


- Zeichenketten sind durch 2 Standardklassen realisiert: - Vergleich von Strings:
- String : Zeichenkette selbst kann nicht verändert werden - Vergleich mit == ist oft nicht sinnvoll (Referenzvergleich)
- StringBuffer : veränderbare Zeichenketten
- Statt dessen Wertevergleich: s1.equals(s2)
- Lexikographische Anordnung mit s1.compareTo(s2)
String msg = "Die"; // String-Objekt wird (liefert einen int <0, =0, oder >0)
int i = 7; // automatisch erzeugt
msg = new String("Die"); // So ginge es auch
msg = msg + " " + i; // Konkatenation - Es gibt eine Vielzahl von Methoden und Konstruktoren
msg = msg + " Zwerge";
System.out.println(msg); // Die 7 Zwerge - Teilstrings
System.out.println(msg.length()); // 12 - Umwandlung von Zeichen (z.B. Groß- / Kleinschreibung)
- Umwandlung von anderen Datentypen in Strings (und umgekehrt)
String b = msg;
- Umwandlung von char- und byte-Felder in Strings
msg = null;
System.out.println(b); // Die 7 Zwerge - ...

class ReverseString { - Mehr dazu in der API-Beschreibung zu java.lang


String reverseIt(String source) {
int i, len = source.length(); - Gibt es online an verschiedenen Stellen und in Büchern, z.B.:
StringBuffer dest = new StringBuffer(len);
http://java.sun.com/products/jdk/1.2/
for (i = (len - 1); i >= 0; i--) { docs/api/overview-summary.html
dest.append(source.charAt(i));
}
return dest.toString(); es gibt eine Vielzahl
} von hübschen Methoden
}

Java-Einführung, 30 Java-Einführung, 31
Auszug aus der API-Beschreibung (1) Auszug aus der API-Beschreibung (2)
Class String
compareTo
public final class java.lang.String
extends java.lang.Object public int compareTo(String anotherString)
{
// Constructors Compares two strings lexicographically.
public String();
public String(byte ascii[], int hibyte); Parameters:
public String(byte ascii[], int hibyte, anotherString - the String to be compared
int offset, int count); Returns:
public String(char value[]); The value 0 if the argument string is equal to this string; a value
public String(char value[], int offset, int count); less than 0 if this string is lexicographically less than the string
public String(String value); string argument; and a value greater than 0 if this string is
public String(StringBuffer buffer); lexicographically greater than the string argument.
// Methods
public char charAt(int index); concat
public int compareTo(String anotherString);
public String concat(String str); public String concat(String str)
public static String copyValueOf(char data[]);
public static String Concatenates the string argument to the end of this string. If the
copyValueOf(char data[], int offset, int count); length of the argument string is zero, then this object is returned.
public boolean endsWith(String suffix);
public boolean equals(Object anObject); Parameters:
public boolean equalsIgnoreCase(String anotherString); str - the String which is concatenated to the end of this String
public void getBytes(int srcBegin, int srcEnd, Returns:
byte dst[], int dstBegin); A string that represents the concatenation of this object's characters
public void getChars(int srcBegin, int srcEnd, followed by the string argument's characters.
char dst[], int dstBegin);
public int hashCode();
public int indexOf(int ch);
public int indexOf(int ch, int fromIndex); copyValueOf
public int indexOf(String str);
public int indexOf(String str, int fromIndex); public static String copyValueOf(char data[])
public String intern();
public int lastIndexOf(int ch); Returns:
public int lastIndexOf(int ch, int fromIndex); a String that contains the characters of the character array.
public int lastIndexOf(String str); Parameters:
public int lastIndexOf(String str, int fromIndex); data - the character array
public int length();
... Java-Einführung, 32 Java-Einführung, 33

Abstrakte Methoden und Klassen Überladen von Methoden


- Gleicher Methodenname bei unterschiedlicher
abstract class Sort { Signatur (=Typ und Anzahl der Parameter) möglich
abstract boolean kleiner (Sort y); - wenn sich mehrere Methoden qualifizieren, wird die speziellste genommen
- auch Konstruktoren können überladen werden
static void sort(Sort[] Tab) { wieso static?
for (int i=0; i<Tab.length; i++) class Auto {...
for (int j=i+1; j<Tab.length; j++) class Bus extends Auto {...
if (Tab[i].kleiner(Tab[j])) { class Zug {...
Sort swap = Tab[i];
Tab[i] = Tab[j]; Achtung: Es wird class Test {
Tab[j] = swap; absteigend sortiert! int f(int x){ return 1; }
} int f(double y) { return 2; }
} int f(char z) { return 3; }
} Das einfache Sortierverfahren ("deletion sort") ist ineffizient! // char f(char z) { return 4; }
// ERROR: Methods can't be redefined
- Wir fordern, daß die zu sortierenden Objekte vom Typ // with a different return type
einer von Sort abgeleiteten Klasse sind. int f(Object x) {return 5; }
int f(Auto x) { return 6; }
- In der abgeleiteten Klasse muß außerdem Als totale Ord- short f(int x, double y){ return 7; };
nungsrelation
die Funktion "kleiner" realisiert werden. auf den Objekten! ...
class Beispiel {... Alle Klassen erweitern (direkt oder
- Unabhängig davon, wie die Relation "kleiner" int i; int j = 0; indirekt) die Standardklasse Object
definiert ist, funktioniert unser Sortierverfahren! Test t = ...
Object o = ...; Auto a = ...;
- Das Sortierverfahren kann also bereits implementiert Bus b = ...; Zug z = ...;
(und getestet) werde, bevor überhaupt die Daten
2, wenn es kein f(int x) gibt!
selbst bekannt sind! i=t.f(i); // 1
i=t.f(3.14); // 2 Fehler, wenn es kein
- Einmal entwickelt, kann man den Algorithmus auch i=t.f('c'); // 3 f(double x) gibt!
zum Sortieren anderer Datentypen verwenden! i=t.f(o); // 5
(int, float, Brüche als rationale Zahlen, Zeichenketten...) i=t.f(a); // 6 1, wenn es kein f(char x) gibt!
i=t.f(b); // 6
- Sort ist eine abstrakte Klasse (von solchen können i=t.f(z); // 5
keine Objekte erzeugt werden, sie dienen nur i=t.f(5, 3.14); // 7
dazu, hiervon abgeleitete Klassen zu definieren). ...
Java-Einführung, 34 Java-Einführung, 35
Schnittstellen ("Interfaces") Mehrfachvererbung
- Interface = (abstrakte) Klasse, die alle Methoden - Klassen können nicht von mehreren Eltern erben
nur deklariert, aber nicht implementiert - Interfaces dienen als (teilweise!) Ersatz dafür
- enthält also nur (implizit) abstrakte Methoden (und Konstanten)
- das sogen. "diamond inheritance problem" so manchmal lösbar:
- Bsp: interface Menge {
int cardinal();
void insert (Object x); W
void remove (Object x); interface W {...}
} interface X extends W {...}
X Y class Y implements W {...}
- Interface muß von anderen Klassen implementiert werden class Z extends Y implements X {...}
- Bsp: class S implements Menge { Z
...
public int cardinal(); { - die von Z ererbten Attribute und Methodenimplementierungen
... können nur aus Y (und nicht indirekt doppelt aus W stammen)
while ... i++ ...
return i;
} - Namenskonflikte beim Erben von mehreren Eltern müssen allerdings
gelöst werden...
- Der Typ des Interfaces (hier: "Menge") kann mit
seinen Methoden anderswo benutzt werden
- Bsp: Menge M;
M.insert(...);

- Interfaces können mehrere andere erweitern


- Bsp: interface I extends A, B {
int M();
}

- I "enthält" alle Methoden von A und B (und zusätzlich M)


- eine Klasse dagegen kann nur eine einzige Klasse erweitern

Java-Einführung, 36 Java-Einführung, 37

Pakete Die Java-Umgebung


- Paket = (zusammengehörige) Menge von Klassen
(API, Standard-Pakete)
- und Interfaces und Unterpakete
java.lang
- Hierarchischer Aufbau Package that contains essential Java classes, including numerics,
strings, objects, compiler, runtime, security, and threads. This is the only
- "lang" im Paket "java" --> "java.lang" package that is automatically imported into every Java program.
- spiegelt sich in der Verzeichnishierarchie wieder
java.io
- Wichtig für Strukturierung und Zugriffskontrolle Package that provides classes to manage input and output streams to
read data from and write data to files, strings, and other sources.
- Klassen und Attribute von Klassen (z.B. Methoden) sind ohne
weitere Angaben nur im eigenen Paket sichtbar / zugreifbar
java.util
- Klassen befinden sich immer in Paketen Package that contains miscellaneous utility classes, including generic data
structures, bit sets, time, date, string manipulation, random number genera-
- Paketdeklaration direkt am Anfang einer Quelldatei, z.B. tion, system properties, notification, and enumeration of data structures.
package abc;
- Falls package-Deklaration fehlt: "unnamed package" java.net
Package that provides classes for network support, including URLs,
- Attribute / Methoden von Klassen können vollquali- TCP sockets, UDP sockets, IP addresses...
fiziert (d.h. mit dem Paketnamen) benannt werden
java.awt
- z.B.: java.lang.String.substring Package that provides an integrated set of classes to manage user interface
components such as windows, dialog boxes, buttons, checkboxes, lists,
Paket Klasse Methode menus, scrollbars, and text fields. (AWT = Abstract Window Toolkit.)

- Importieren von Klassen (als Namensabkürzung) java.awt.image


- z.B. import java.util.Random Package that provides classes for managing image data, including
(es wird diese Klasse importiert und kann als "Random" benutzt werden) color models, cropping, color filtering, setting pixel values, and grabbing
- oder import java.util.* snapshots.
(es wird alles aus diesem Paket importiert)
java.applet
Package that enables the creation of applets through the Applet class.

Java-Einführung, 38 Java-Einführung, 39
java.util Zugriffsmodifikatoren
- Das Paket "java.util" enthält einige interessante - Reihenfolge der einzelnen Modifikatoren beliebig
Klassen zur Verwaltung von Daten: - Durch Modifikatoren wird i.w. der Zugriff (d.h.
Sichtbarkeit des Namens) geregelt
Class BitSet - leider etwas verwirrend
This class implements a vector of bits that grows as needed. Indi- - es gibt Tabellen, in denen man die anzugebenden Modifikatoren
vidual bits can be examined, set, or cleared. je nach gewünschter Situation nachsehen kann

Class Hashtable
This class implements a hash table, which maps keys to values. Any
Class Modifiers:
non-null object can be used as a key or as a value. (Methods: put, get, final: no sub-classes
remove, contains, size...) public: usable from other packages
abstract: no instances, only sub-classes
Class Properties (extends Hashtable)
The Properties class represents a persistent set of properties. The Variable Modifiers:
Properties can be saved to a stream or loaded from a stream. Each key final: constant
and and its corresponding value in the property list is a string. static: class variable
private: use only inside class
Class Stack
(no modifier): + in Package
Methods: push, pop, peek, empty...
protected: + sub-classes
Class Vector public: anywhere
Like an array, it contains components that can be accessed using an
integer index. However, the size of a Vector can grow or shrink as Method Modifiers:
needed to accommodate adding and removing items after the Vector final: no overriding
has been created. static: class method
abstract: implement in subclass
native: implemented in C
private, public, protected: like variables.
- Einige Standardpakete (z.B. java.awt*) sind komplex
- Vielzahl von Methoden etc.
- "private protected": nur in Unterklassen (und eigener Klasse) sichtbar
- nicht einfach zu benutzen
- es gibt weitere Modifikatoren: synchronized, volatile (beide bei Threads)
und transient (bei persistenten Objekten, derzeit noch nicht benutzt)
Java-Einführung, 40 Java-Einführung, 41

Ausnahmen (Exceptions) Ausnahmen - ein E/A-Beispiel


- Ausnahmen sind Fehlerereignisse import java.io.*;
- werden oft vom System ausgelöst ("throw") public class EA_Beispiel Da wir Fehler selbst
abfangen, können
- können aber auch explizit im Programm ausgelöst werden // Prints "Hello World" to a file wir auf "throws..."
// specified by the first parameter. verzichten!
- können abgefangen und behandelt werden ("catch") {
public static void main(String args[])
{
- Bessere Strukturierung durch "try" und "catch": FileOutputStream out = null;

void readFile() { // Attempt to open the file, if we


try { // can't display error and quit
// open the file; try
{
// determine its size; out = new FileOutputStream(args[0]);
// allocate that much memory; }
// read the file into memory; Diese Fehlerklasse ganz
// close the file; catch (Throwable e) oben in der Hierarchie und
{ fängt damit alles ab
} catch (fileOpenFailed) {
// doSomething; System.out.println("Error in opening file");
} catch (sizeDeterminationFailed) { System.exit(1);
// doSomething; } Z.B.: Zugriffsrechte "falsch"
} catch (memoryAllocationFailed) {
PrintStream ps = new PrintStream(out);
// doSomething;
} catch (readFailed) { try Fehler hierbei würden nicht abgefangen!
// doSomething; {
} catch (fileCloseFailed) { ps.println("Hello World");
// doSomething; out.close();
} } Über diese Variable kann man
} catch(IOException e) mehr über den Fehler erfahren
{
- Fehlerbehandlung muß auf diese Weise nicht mit dem "normalen" System.out.println("I/O Error");
Programmcode verwoben werden System.exit(1);
}
} Shortcut zum Verlassen des Programms
}

Java-Einführung, 42 Java-Einführung, 43
Fehlerarten Fehlerbehandlung
- Typische Situationen, in denen Ausnahmen - Fehlerbehandlung ist nicht immer einfach
auftreten können: - Meldung an den Benutzer (wenn es einen gibt...), aber was dann?
- Ein- / Ausgabe (IOException) - Oft ist es dann ratsam, reservierte Ressourcen wieder freizugeben
- Sockets, URL-Verbindungen (z.B.MalformedURLException) - Die oberste Fehlerklasse "Throwable" stellt einige sinnvolle
- Erzeugen von Objekten mit "new" Methoden zur Verfügung, z.B. printStackTrace oder getMessage
(letzteres für genauere Fehlermeldungen):
- Typkonvertierung (z.B. NumberFormatException)
try { ... }
catch (Exception e) {
- Wichtige Fehlerklasse: Laufzeitfehler System.err.println("Fehler: "
+ e.getMessage());
- können, müssen aber nicht abgefangen werden
- Beispiele: Zugriff über Null-Referenz; int / 0; Indexfehler bei arrays
- Suche eines passenden "error handlers"
try {
value = value / x; - Laufzeitsystem durchsucht den Laufzeitkeller (rückwärts)
} - sucht den nächsten passenden handler
catch(ArithmeticException e){ - "passend" entsprechend der Hierarchie der Fehlerklassen
System.out.println("Division durch 0?");
}
- Hierarchie der Fehlerklassen (Auszug):
- Alle anderen Fehlerarten müssen behandelt werden
NoSuchMethodError ArithmeticException
- entweder durch try / catch in der Methode Error
- oder durch Angabe, daß die Methode diese Ausnahme selbst Throwable IndexOutOfBoundsException
RuntimeException
wieder auslöst (und damit weiterreicht), z.B.: EOFException
Exception
import java.io.*; FileNotFoundException
IOException
public Eine_Methode (...)
throws java.io.IOException SocketException
{... read ...}

Java-Einführung, 44 Java-Einführung, 45

Definieren eigener Ausnahmen


- Ausnahmen sind Objekte!
- was auch sonst...

- Eigener Ausnahmetyp muß von java.lang.Throwable


(indirekt) abgeleitet sein
- Kann dann mit "throw" ausgelöst werden

class IllegalesDatum extends Throwable {


IllegalesDatum (int Tag,int Monat,int Jahr)
{
super ("Fehlerhaftes Datum ist:" +
Tag + "." + Monat + "." + Jahr);
// und E-mail an den Boss schicken...
} Der Konstruktor von Throwable erwartet einen String, der
} als Fehlermeldung (mit dem Stack-Trace) ausgegeben wird
class Datum
...
void Setzen (int T, int M, int J)
throws IllegalesDatum {
Tag = T; Monat = M; Jahr = J; ;
if (Tag > 31) throw new
IllegalesDatum (Tag, Monat, Jahr);
}
class Beispiel ...
d.Setzen(47,03,97); // Zeile 49 in der Datei
...
Fehlerhaftes Datum ist:47.3.97
at Datum.Setzen(Datum.java:27)
at Beispiel.main(Datum.java:49)
Java-Einführung, 46