Skript, Programmieren in Java

Werbung
Skript zum Kurs
Programmieren in Java
v1.1/SS98
©’97,98, Stefan Berner, Stefan Joos
Forschungsgruppe Requirements Engineering
Institut für Informatik der Universität Zürich
Programmieren in Java
02.Apr.98
1/120
… I know you believe you
understand what you think
I said, but I am not sure you
realize that what you heard
is not what I meant …
Programmieren in Java
02.Apr.98
2/120
Vorwort
Dies ist die erste überarbeitete Version des Skripts zum Kurs “Programmieren in Java“. Aufgrund einiger konkreter Anregungen im letzten Kurs,
ist nun im Übungsteil ein zusammenhängendes Beispiel hinzugekommen.
Schwerpunkt dieser Veranstaltung ist (und bleibt) die Programmiersprache Java und nicht die Virtuelle Maschine oder die Klassenbibliothek.
Die Beispiele und Übungen sind im Wesentlichen abgestimmt auf Java
1.0.x. Sie in der Kürze der zur Verfügung stehenden Vorbereitungszeit auf
Java 1.1.x umzustellen, war nicht möglich; ist aber auch nicht unbedingt
notwendig, da der Schwerpunkt der Veranstaltung die Programmiersprache Java ist. Hier haben sich von Java Version 1.0.x auf Java Version
1.1.x nur kleinere Änderungen ergeben.
Damit das Skript nicht allzu dick wird, ist der Code oft dichter gesetzt und
spärlicher kommentiert, als es in der Praxis sinnvoll wäre. Das Skript ist
zur Zeit weder vollständig noch fehlerfrei. Syntaktische und orthographische Mängel bitte ich daher zu entschuldigen.
Für kritische oder konstruktive Hinweise bin ich wie immer sehr dankbar.
Stefan Berner
Programmieren in Java
02.Apr.98
3/120
Tips und Vorabbemerkungen zum Kurs
•
aktiv mitarbeiten
•
fragen
•
ausprobieren
•
üben
Programmieren in Java
02.Apr.98
4/120
Inhaltsübersicht
•
Einleitung
•
Variablen, Bezeichner, Typsystem
•
Einfache Datentypen
•
Komplexe Datentypen
•
Variablendeklaration
•
Sichtbarkeit und Lebensdauer
•
Speicherverwaltung
•
Ausdrücke und Operatoren
•
Steueranweisungen
•
Methoden
•
Ausnahmebehandlung
•
Threads und Synchronisation
Programmieren in Java
02.Apr.98
5/120
Einleitung
1
Einleitung
1.1
Die Java Plattform
Die Java Plattform besteht aus drei Komponenten:
•
Programmiersprache
♦ eben eine Programmiersprache
•
Virtuelle Maschine, Ausführungsmodell
♦ ein durch Software simulierter Rechner
♦ eine virtuelle Maschine ist ein Programm, welches einen Rechner
simuliert und auf dem eigentlichen Betriebssystem eines realen
Rechners aufsetzt
•
Klassenbibliothek, Entwicklungsumgebung
♦ eine Klassenbibliothek ist eine Sammlung von Klassen, die
bestimmte (häufig benötigte) Dienste zur Verfügung stellen
♦ vergleichbar den Diensten, welches ein Betriebssystem zur Verfügung stellt
Schwerpunkt in diesem Kurs ist die Programmiersprache Java. Auf die Virtuelle Maschine und das Ausführungsmodell wird nur kurz eingegangen.
Der Inhalt der Klassenbibliothek wird soweit angeschnitten, wie es zum
Verständnis der Sprache (→ Paket java.lang) oder der Beispiele notwendig ist.
Programmieren in Java
02.Apr.98
6/120
Einleitung
1.2
Die Programmiersprache Java
1.2.1
Entwurfsziele von Java
Die Programmiersprache Java ist:
•
einfach, da
→ objektorientiert (siehe Abschnitt 1.3)
→ weniger komplex als C/C++
• keine Typedef-, Define- und Preprocessor Anweisungen
• kein struct und union
• keine Funktionen und Prozeduren, sondern nur Methoden
• keine Mehrfachvererbung, sondern Interfaces
• keine goto’s
• kein Überladen von standard Operatoren
• keine automatische bzw. implizite Typkonversion
• “keine Zeiger”
•
Robust und sicher, da
→ strenge Typung
→ umfangreiche statische Prüfung (z.B. Typverträglichkeit)
→ effiziente dynamische Prüfung (z.B. Arrays)
→ keine “legale“ Zeigerarithmetik
→ Exeptions
→ automatische Speicherverwaltung, Garbage Collection
•
Portabel, da
→ Virtuelle Maschine
→ Basistypen genau definiert
→ standardisierte Klassenbibliothek
•
Multithreaded, da
→ Threads und Synchronisationsprimitiven
Programmieren in Java
02.Apr.98
7/120
Einleitung
1.3
Objektorientierung
( … Wiederholung, Einschub … )
Java ist eine objektorientierte Sprache. Objektorientiert steht hierbei für:
•
Objekte
•
Klassen
•
Nachrichten und Methoden
•
Vererbung
•
Polymorphie/Redefinition
1.3.1
•
Objekte
Modell eines realen oder imaginären Gegenstandes
♦ dieses Modell besteht aus zwei Teilen
• Operationsraum
• Datenraum
→ ein Objekt realisiert eine Datenkapsel
•
ein objektorientiertes Softwaresystem besteht aus Objekten, welche
mittels Nachrichten (s.u.) kommunizieren und so die Aus-/Durchführung von Operationen/Methoden (s.u.) anstossen
1.3.2
•
Klassen
eine Klasse realisiert einen abstrakten Datentyp, d.h. Klassen sind
eine Art “Bauplan“ oder “Fabrik“ für Objekte
→ Von Klassen können beliebig viele Objekte erzeugt werden
•
Klassen definieren die Schnittstelle, die Implementierung der Methoden und den Aufbau des Datenraums von Objekten
•
ein Objekt ist immer Instanz genau einer Klasse und hat genau die
durch die Klasse definierten Eigenschaften
♦ Eigenschaften einer Klasse sind entweder neu oder ererbt oder
redefiniert
Programmieren in Java
02.Apr.98
8/120
Einleitung
1.3.3
•
Nachrichten und Methoden
Nachrichten fordern ein Objekt zur Durchführung einer Methode/Operation auf
Nachricht
passende
Methode
nein
?
ja
Superklasse
ja
?
Weiterreichen an
Superklasse
nein
Fehler(meldung)
Nachricht an
Superklasse
Nachricht
bearbeiten
•
Nachrichten an
andere Objekte
eine Nachricht besteht aus 3 Teilen
♦ Empfänger … ein Objekt
♦ Selektor … der Methoden- bzw. Operationsname
♦ Argumente … Objekte
•
eine Methode/Operation hat entweder lokale Effekte (manipuliert
lokale Daten/ändert Objektzustand), z.B.
aList.sort( “ascending“ );
aTrafficLight.switchToRed();
•
und/oder globale Effekte (d.h. Empfängerobjekt schickt Nachrichten
an andere Objekte). Nachrichten an andere Objekte können deren
Objektzustand ändern, z.B.
aFox.eat( aDuck );
•
die Semantik einer Methode/Operation kann vom Zustand des
Objekts abhängen, z.B.
aList.insert( 3, 4, 5, 6 );
aList.at( 2 );
aList.deleteAll();
aList.at( 2 );
Programmieren in Java
02.Apr.98
9/120
Einleitung
1.3.4
Vererbung
•
Gemeinsame Eigenschaften (Datenattribute und Methoden) von
Objekten sollen nur einmal definiert werden
•
Klassen werden in Beziehung gesetzt:
Unter-/Oberklassen-Beziehung ergibt Klassenhierarchie
•
Klasse »erbt« Attribute und Methoden der Oberklasse
→ transitiv werden Eigenschaften von allen Vorfahren in der Klassenhierarchie übernommen
•
Für jede Klasse in der Hierarchie können zusätzliche Datenattribute
oder Methoden definiert werden
1.3.5
Polymorphie/Redefiniton
•
Ererbte Methoden (oder Attribute) können in der Unterklasse anders
als in der Oberklasse (re-)definiert werden
•
Ermöglicht Anpassung der geerbten Attribute und Methoden auf spezifische Invarianten der Unterklasse
Beispiel:
Geometrisches Element
Kreis
A
B
A ist Unterklasse von B
Programmieren in Java
Vieleck
Dreieck
02.Apr.98
Viereck
10/120
Einleitung
1.4
Ein erstes Java-Beispiel
class Circle
{
double radius;
// Klassendeklaration; Klasse Circle
// Anfang Klassenrumpf
// Instanzvariablendeklaration
Circle( double radius )
{
this.radius = radius;
}
// Konstruktormethode
// Anfang Methodenrumpf
// Zuweisung an Instanzv.
// Ende Methodenrumpf
double area()
// Instanzmethode; berechnet Flächeninhalt
{
return ( Math.pow( radius, 2 ) * Math.PI );
}
}
// Klassendeklaration; Klasse Application
class Application
{
public static void main( String args[] )
{
Circle aCircle = new Circle( 42d );
System.out.println( aCircle.area() );
}
}
Programmieren in Java
02.Apr.98
11/120
Einleitung
•
this referenziert das Objekt selbst
→ this.radius … zugewiesen wird der Instanzvariable radius
und nicht dem Methodenparameter radius
•
Alle Klassen des Pakets java.lang werden automatisch importiert
→ Math wird automatisch importiert, da im Paket java.lang
•
Kommentare
♦ der Inhalt von Kommentaren wird vom Übersetzer ignoriert
♦ drei Varianten:
// Einzeiliger Kommentar
/* Mehrzeiliger Kommentar */
/** JavaDoc Kommentar */
♦ zu den gebräuchlichsten und auch wichtigsten Dokumentationsmitteln für Code zählt der Kommentar. Mitunter tragen Kommentare entscheidend zum schnellen Verständnis von Code und damit
zum einfachen Ändern, Erweitern, Lesen, Portieren, Warten etc.
von Software bei.
•
Wird das Programm ausgeführt (java Application), dann wird die
Methode public static void main( String args[] ) nach
dem Laden der Klasse automatisch aufgerufen
1.4.1
Entwicklungszyklus und Ausführung des Beispiels
1. Java-Quellcodedatei mittels Texteditor (emacs, sniff, textedit etc.) erstellen bzw. ändern
2. Datei übersetzen (z.B. javac Application.java)
3. Nach erfolgreicher Übersetzung die VM starten und zu ladende Startklasse angeben (z.B. java Application)
4. … siehe Schritt 1 …
Programmieren in Java
02.Apr.98
12/120
Einleitung
1.4.2
Programmstruktur
package
ein.paket;
import
import
angabe.der.importe;
…
class EineKlasse
{
static EinTyp EineKlassenVariable;
NochEinTyp eineInstanzVariable;
void eineMethode( … )
{
eineInstanzVariable.einMethodenAufruf( … );
…
}
}
interface EinInterface
{
…
}
Programmieren in Java
02.Apr.98
13/120
Einleitung
Pakete
package ein.paket.etc. … .etc;
•
gliedern eng kooperierende Klassen
•
definieren einen Namensraum/Gültigkeitsbereich für Klassen, Methoden und Variablen(-bezeichner)
•
Paktetangabe dient auch als Pfadinformation für die Ablage übersetzter Klassen (sog. class files)
•
die Klassen des Pakets dürfen auf verschiedene Dateien verteilt sein
Importe
import ein.paket.etc. … .klasse;
♦ “.*” importiert alle Klassen des Pakets
•
geben die benutzten Klassen und Schnittstellen an
•
ähnlich IMPORT in Modula II, with in Ada oder uses in Object Pascal
•
Suchpfad für zu importierende Klassen
Klassen
class EineKlasse …
•
dienen als Schablonen für Objekte
•
definieren die Variablen und Operationen “ihrer“ Objekte
Instanz- und Klassenvariablen
NochEinTyp eineInstanzVariable;
•
repräsentieren die Daten, die das Objekt ausmachen
Methoden
void eineMethode( … )
•
repräsentieren die Operationen, die das Objekt kennt
Programmieren in Java
02.Apr.98
14/120
Einleitung
1.5
Ausführungsmodell
Quellprogramm
<datei>.java
Klassenbibliothek (API)
Übersetzer
javac
Class Loader
Byte Code
Verifyer
Bytecode
wird von Disk
oder über das
Netz geladen
Quellprogramm
<datei>.java
Interpreter
javac
Runtime Code
Generator
Laufzeitsystem
Betriebssystem, Hardware, …
Programmieren in Java
02.Apr.98
15/120
Einleitung
1.5.1
Das Laden einer Klasse im Detail
läuft in drei Phasen ab
•
laden (load)
→ Binärrepräsentation (class file) finden und zur Klassenbibliothek
hinzufügen
→ Arbeitsspeicher (RAM) bereitstellen
→ Zyklenfreiheit der Vererbungshierarchie sicherstellen
•
binden (link)
♦ verifizieren (verification)
→ sicherstellen, dass die Binärrepräsentation der Klasse (Symboltabelle, Methodencode etc.) “korrekt“ ist
♦ vorbereiten (preparation)
→ Klassenvariablen und -Konstanten erzeugen (aber noch nicht
initialisieren)
♦ auflösen von symbolischen Referenzen (resolution)
→ sicherstellen, dass die referenzierten Bezeichner sichtbar sind
und existieren
•
initialisieren (initialize)
→ ausführen des Initialisierungsblocks (static initializer)
→ initialisieren der Klassenvariablen
Programmieren in Java
02.Apr.98
16/120
Einleitung
1.6
•
Die Virtuelle Maschine von Java
Die Virtuelle Maschine (kurz VM) ist eine Stackmaschine mit exakt
definiertem Instruktionssatz und Ausführungsmodell
♦ Stackmaschine → Parameter für Maschineninstruktionen werden
über den Stack und nicht über Register übergeben
♦ Die VM hat zwar Register; diese sind aber nicht direkt über Bytecodes (also durch den Benutzer der VM) manipulierbar
→ Eine Stackmaschine ermöglicht u.a. die einfache Implementierung/Portierung auf Maschinen mit CPUs, die nur wenige oder
operationsgebundene Register haben, wie z.B. Intel486
•
Der Instruktionssatz der VM ist in Form von Bytecodes definiert. Diese
ähneln (in etwa) den Befehlen eines Assemblers
→ nahe genug an Assembler, um sehr schnell nativen/echten
Maschinen-Code während der Laufzeit zu generieren (→ runtime
code generation, just-in-time-compiler (JIT))
•
Die Java VM ist eine “high level“ Maschine; d.h. diese VM ist nicht nur
ein in Software geschriebener Assembler, sie führt z.B. auch:
♦ div. Sicherheitsüberprüfungen durch, wie z.B. primitive Typprüfungen, byte code verification (siehe Kapitel 1.5.1)
♦ die Garbage Collection (siehe Kapitel 7) durch,
♦ die Task-Switches durch (→ verwaltet den Stackpointer eigenständig, kann nicht über Bytecode-Anweisungen gesetzt werden)
Programmieren in Java
02.Apr.98
17/120
Einleitung
1.6.1
Beispiel, Byte-Code der VM
Gegeben sei folgendes Java-Code-Fragment:
public class Application
{
static int foo( int i, int j )
{
// (2)
int k = 1;
return i + j + k;
}
public static void main( String args[] )
{ // (1)
System.out.println( foo( 17, 42 ) );
}
}
Das Beispiel besteht aus einer Klasse (Application) mit zwei Methoden
(foo(…) und main(…)). In der Methode main wird die Methode foo aufgerufen und das Ergebnis ausgegeben. Die Methode foo addiert die beiden Parameter, zählt 1 dazu und gibt das Ergebnis zurück.
Übersetzt in Java-Bytecode ergibt sich folgender Code:
Magic=0xCAFEBABEVersion=45.3Access=public (0x0001)
Class=(#1) "Application"(#36)
SuperClass=(#2)"java/lang/Object"(#28)
Constant Pool Entries=43
#1 Kind=CONSTANT_Class(7)
Name="Application"(#36)
#2 Kind=CONSTANT_Class(7)
Name="java/lang/Object"(#28)
#3 Kind=CONSTANT_Class(7)
Name="java/io/PrintStream"(#19)
#4 Kind=CONSTANT_Class(7)
Name="java/lang/System"(#35)
#5 Kind=CONSTANT_Methodref(10)
Class=(#2) "java/lang/Object"(#28)
NameAndType=(#12)"<init>"(#31)
Programmieren in Java
02.Apr.98
18/120
Einleitung
"()V"(#38)
#6 Kind=CONSTANT_Methodref(10)
Class=(#1) "Application"(#36)
NameAndType=(#11)"foo"(#34)
"(II)I"(#18)
#7 Kind=CONSTANT_Fieldref(9)
Class=(#4) "java/lang/System"(#35)
NameAndType=(#9)"out"(#27)
"Ljava/io/PrintStream;"(#32)
#8 Kind=CONSTANT_Methodref(10)
Class=(#3) "java/io/PrintStream"(#19)
NameAndType=(#10)"println"(#14)
"(I)V"(#15)
#9 Kind=CONSTANT_NameAndType(12)
Name="out"(#27)
Signature="Ljava/io/PrintStream;"(#32)
#10 Kind=CONSTANT_NameAndType(12)
Name="println"(#14)
Signature="(I)V"(#15)
#11 Kind=CONSTANT_NameAndType(12)
Name="foo"(#34)
Signature="(II)I"(#18)
#12 Kind=CONSTANT_NameAndType(12)
Name="<init>"(#31)
Signature="()V"(#38)
#13 Kind=CONSTANT_Utf8(1)Length=4Value="this"
74 68 69 73
#14 Kind=CONSTANT_Utf8(1)Length=7Value="println"
70 72 69 6E 74 6C 6E
#15 Kind=CONSTANT_Utf8(1)Length=4Value="(I)V"
28 49 29 56
#16 Kind=CONSTANT_Utf8(1)Length=13Value="ConstantValue"
43 6F 6E 73 74 61 6E 7456 61 6C 75 65
#17 Kind=CONSTANT_Utf8(1)Length=18Value="LocalVariableTable"
4C 6F 63 61 6C 56 61 7269 61 62 6C 65 54 61 62
6C 65
#18 Kind=CONSTANT_Utf8(1)Length=5Value="(II)I"
28 49 49 29 49
#19 Kind=CONSTANT_Utf8(1)Length=19Value="java/io/PrintStream"
6A 61 76 61 2F 69 6F 2F50 72 69 6E 74 53 74 72
65 61 6D
Programmieren in Java
02.Apr.98
19/120
Einleitung
#20 Kind=CONSTANT_Utf8(1)Length=10Value="Exceptions"
45 78 63 65 70 74 69 6F6E 73
#21 Kind=CONSTANT_Utf8(1)Length=15Value="LineNumberTable"
4C 69 6E 65 4E 75 6D 6265 72 54 61 62 6C 65
#22 Kind=CONSTANT_Utf8(1)Length=1Value="I"
49
#23 Kind=CONSTANT_Utf8(1)Length=10Value="SourceFile"
53 6F 75 72 63 65 46 696C 65
#24 Kind=CONSTANT_Utf8(1)Length=14Value="LocalVariables"
4C 6F 63 61 6C 56 61 7269 61 62 6C 65 73
#25 Kind=CONSTANT_Utf8(1)Length=4Value="Code"
43 6F 64 65
#26 Kind=CONSTANT_Utf8(1)Length=16Value="Application.java"
41 70 70 6C 69 63 61 7469 6F 6E 2E 6A 61 76 61
#27 Kind=CONSTANT_Utf8(1)Length=3Value="out"
6F 75 74
#28 Kind=CONSTANT_Utf8(1)Length=16Value="java/lang/Object"
6A 61 76 61 2F 6C 61 6E67 2F 4F 62 6A 65 63 74
#29 Kind=CONSTANT_Utf8(1)Length=4Value="main"
6D 61 69 6E
#30 Kind=CONSTANT_Utf8(1)Length=22Value="([Ljava/lang/String;)V"
28 5B 4C 6A 61 76 61 2F6C 61 6E 67 2F 53 74 72
69 6E 67 3B 29 56
#31 Kind=CONSTANT_Utf8(1)Length=6Value="<init>"
3C 69 6E 69 74 3E
#32 Kind=CONSTANT_Utf8(1)Length=21Value="Ljava/io/PrintStream;"
4C 6A 61 76 61 2F 69 6F2F 50 72 69 6E 74 53 74
72 65 61 6D 3B
#33 Kind=CONSTANT_Utf8(1)Length=13Value="LApplication;"
4C 41 70 70 6C 69 63 6174 69 6F 6E 3B
#34 Kind=CONSTANT_Utf8(1)Length=3Value="foo"
66 6F 6F
#35 Kind=CONSTANT_Utf8(1)Length=16Value="java/lang/System"
6A 61 76 61 2F 6C 61 6E67 2F 53 79 73 74 65 6D
#36 Kind=CONSTANT_Utf8(1)Length=11Value="Application"
41 70 70 6C 69 63 61 7469 6F 6E
#37 Kind=CONSTANT_Utf8(1)Length=1Value="k"
6B
Programmieren in Java
02.Apr.98
20/120
Einleitung
#38 Kind=CONSTANT_Utf8(1)Length=3Value="()V"
28 29 56
#39 Kind=CONSTANT_Utf8(1)Length=1Value="j"
6A
#40 Kind=CONSTANT_Utf8(1)Length=1Value="i"
69
#41 Kind=CONSTANT_Utf8(1)Length=4Value="args"
61 72 67 73
#42 Kind=CONSTANT_Utf8(1)Length=19Value="[Ljava/lang/String;"
5B 4C 6A 61 76 61 2F 6C61 6E 67 2F 53 74 72 69
6E 67 3B
Interface Table Entries=0
Field Table Entries=0
Method Table Entries=3
AL_CODE: Method 1
Method="Application.foo"(#34)
Signature="(II)I"(#18)
Signature="(II)I"(#18)
Access=static (0x0008)Attribute Count=1
Attribute="Code"(#25)Length=74
Max Stack=2Max Locals=3Code Length=8
0x00000000 04iconst_1
0x00000001 3Distore_2
0x00000002 1Aiload_0
0x00000003 1Biload_1
0x00000004 60iadd
0x00000005 1Ciload_2
0x00000006 60iadd
0x00000007 ACireturn
Exception Handler Entries=0
Attribute="LineNumberTable"(#21)Length=10Entry Count=2
Start=0x00000000Line Number=7
Start=0x00000002Line Number=8
Attribute="LocalVariableTable"(#17)Length=32Entry Count=3
Start=0x00000000Effective Length=8Slot=0
Name="i"(#40)
Signature="I"(#22)
Start=0x00000000Effective Length=8Slot=1
Name="j"(#39)
Signature="I"(#22)
Start=0x00000002Effective Length=6Slot=2
Name="k"(#37)
Signature="I"(#22)
AL_CODE: Method 2
Method="Application.main"(#29)
Signature="([Ljava/lang/String;)V"(#30)
Signature="([Ljava/lang/String;)V"(#30)
Programmieren in Java
02.Apr.98
21/120
Einleitung
Access=public,static (0x0009)Attribute Count=1
Attribute="Code"(#25)Length=56
Max Stack=3Max Locals=1Code Length=14
0x00000000 B20007getstatic (#7) java/lang/System.out
0x00000003 1011bipush
17
0x00000005 102Abipush
42
0x00000007 B80006invokestatic (#6) Application.foo
0x0000000A B60008invokevirtual (#8) java/io/PrintStream.println
0x0000000D B1return
Exception Handler Entries=0
Attribute="LineNumberTable"(#21)Length=6Entry Count=1
Start=0x00000000Line Number=13
Attribute="LocalVariableTable"(#17)Length=12Entry Count=1
Start=0x00000000Effective Length=14Slot=0
Name="args"(#41)
Signature="[Ljava/lang/String;"(#42)
AL_CODE: Method 3
Method="Application.<init>"(#31)
Signature="()V"(#38)
Signature="()V"(#38)
Access=public (0x0001)Attribute Count=1
Attribute="Code"(#25)Length=47
Max Stack=1Max Locals=1Code Length=5
0x00000000 2Aaload_0
0x00000001 B70005invokenonvirtual (#5) java/lang/Object.<init>
0x00000004 B1return
Exception Handler Entries=0
Attribute="LineNumberTable"(#21)Length=6Entry Count=1
Start=0x00000000Line Number=1
Attribute="LocalVariableTable"(#17)Length=12Entry Count=1
Start=0x00000000Effective Length=5Slot=0
Name="this"(#13)
Signature="LApplication;"(#33)
Attribute Table Entries=1
Attribute="SourceFile"(#23)Length=2Source File="Application.java"(#26)
Anmerkung: Dieser Code wird nicht im Detail behandelt, sondern nur der
Code, welcher für zwei ausgewählte Methoden erzeugt wird (siehe nächste Seite).
Programmieren in Java
02.Apr.98
22/120
Einleitung
Für das zuvor gezeigte Java-Code-Fragment (siehe Seite 18) sieht der
Bytecode für die VM nach der Übersetzung folgendermassen aus:
…
getstatic
bipush
bipush
invokestatic
invokevirtual
…
(#5)
17
42
(#6)
(#7)
// Empfänger java/lang/System.out auf Stack
// 1. Parameter auf Stack
// 2. Parameter auf Stack
// Aufruf: Application.foo
// Aufruf: java/io/PrintStream.println
Aufruf der Methode foo von der Methode main aus (1) (siehe Seite 18).
Die aktuellen Parameter werden auf den Stack gelegt und dann die Methode aufgerufen.
…
iconst_1
istore_2
iload_0
iload_1
iadd
iload_2
iadd
…
// Konstante 1 auf Stack
// Speichern in lokaler Variable k
// i auf Stack
// j auf Stack
// Stack.push( add( Stack.pop(), Stack.pop() ) )
// k auf Stack
// Stack.push( add( Stack.pop(), Stack.pop() ) )
Methode foo wird/wurde aufgerufen (2). Die aktuellen Parameter werden
vom Stack geholt und in lokalen Variablen (i, j) zwischengespeichert. Die
lokale Variable k wird initialisiert; dann wird die Addition durchgeführt und
das Ergebnis zurückgegeben.
Programmieren in Java
02.Apr.98
23/120
Einleitung
1.7
Übersicht über die Klassenbibilothek
(API – application programming interface)
Die Klassenbibliothek (API) von Java ist standardisiert und steht “identisch“ auf allen Java-Implementationen zur Verfügung. Gegliedert ist sie in
verschiedene Pakete, welche die diensttragenden Klassen enthalten. Die
wichtigsten Pakete der Java API sind:
java.lang
•
enthält die essentiellen Basisklassen von Java wie beispielsweise
Object, String, Thread
•
einziges Paket, welches automatisch importiert wird
java.io
•
enthält Klassen zur Handhabung von Ein-/Ausgabe-Sequenzen (input/
output streams), um in Dateien, Strings etc. zu schreiben oder von
dort zu lesen
java.net
•
enthält Klassen, um über Netzwerke zu kommunizieren, URLs, TCPSockets, UDP-Sockets, IP-Adressen etc.
java.util
•
viele nützliche Hilfsklassen, wie beispielsweise Hashtabellen, Zufallszahlen, Vektoren, Containerklassen etc.
java.awt
•
enthält Klassen zur Realisierung von grafischen Benutzerschnittstellen, Fenster, Menüs, Knöpfe, Schalter etc.
java.awt.image
•
enthält spezielle Klassen zur Anzeige und Manipulation von (Bitmap-)
Bildern innerhalb von grafischen Benutzeroberflächen
java.applet
•
spezielle Klassen und Interfaces, um Applets zu realisieren
Programmieren in Java
02.Apr.98
24/120
Einleitung
1.8
Übungen
(1) Aus welchen Teilen besteht die Java Plattform?
(2) Tippen Sie das Circle-Beispiel aus Kapitel 1.4 ab, übersetzen Sie
es und führen Sie das übersetzte Java-Programm aus.
(3) Was ist speziell an der Methode public static void main(
String[] args )?
(4) Ändern Sie das Circle-Beispiel (siehe Kapitel 1.4) ab, so dass über
die Kommandozeile der Radius des Kreises eingegeben werden
kann, für welchen dann der Flächeninhalt berechnet wird. Wichtiger
Hinweis: Parameter, welche über die Kommandozeile übergeben
wurden, werden in das String-Array args[] der main-Methode
geschrieben und sind dort abrufbar; mit args[0] erhält man beispielsweise den ersten Parameter, der über die Kommandozeile
übergeben wurde. Zur Umwandlung von Zeichenketten in Fliesskommazahlen können sie die Klasse java.lang.Double (siehe API
Dokumentation) bzw. die dort definierten Methoden verwenden.
Übersetzen Sie das Java-Programm und führen Sie es aus.
(5) Erweitern Sie die Klasse Circle um eine Methode zur Berechnung
des Kreisumfangs und geben Sie (zusätzlich) in der Methode main
in der Klasse Application den Kreisumfang aus.
Übersetzen Sie das Java-Programm und führen Sie es aus.
(6) Welche Vor- und Nachteile hat das Ausführungsmodell von Java?
(7) Beschreiben Sie das Ausführungsmodell von Java!
(8) Warum ist Java (vergleichsweise) plattformunabhängig?
(9) Was ist ein “Byte-Code“?
(10) Was ist eine Stackmaschine?
(11) Warum kann u.a. der Stackpointer in der Java VM nicht über ByteCode-Befehle geändert werden?
(12) Aus welchen (Haupt-)Paketen besteht die Klassenbibliothek von
Java? Was ist die Aufgabe eines jeden Pakets?
(13) Was ist speziell am Paket java.lang?
Programmieren in Java
02.Apr.98
25/120
Einleitung
1.9
Literatur
Arnold, K., J. Gosling (1996): The Java Programming Language; Java Series. N.Y: Addison Wesley, 1996.
Bückner, M. C., J. Geidel, M. F. Lachmann (1993): Objektworks\Smalltalk
für Anfänger. Berlin: Springer Verlag, 1993.
Campione, M., K. Walrath (1996): The Java Tutorial: Object-Oriented Programming for the Internet; Java Series. N.Y: Addison Wesley Inc., 1996.
Flanagan, D. (1996): Java in a Nutshell. Sebastopol CA: O’Reilly & Associates, 1996. (ISBN 1-56592-183-6)
Gosling, J., H. McGilton (1995): The Java Language Environment – A White Paper. Technical report, Sun Microsystems, Mountain View, CA, 1995.
Lindholm, T., F. Yellin (1996): The Java Virtual Machine Specification. Addison Wesley. (ISBN 0-201-63452-X)
Meyer, B. (1988): Object-Oriented Software Construction. London: Prentice Hall International, 1988.
Wegner, P. (1990): Concepts and paradigms of object-oriented programming. Expansion of Oct. 4 OOPSLA-89 Keynote Talk. OOPS Messenger, 1(1), ACM Press, 1990.
Programmieren in Java
02.Apr.98
26/120
Variablen, Bezeichner, Typsystem
2
Variablen, Bezeichner, Typsystem
2.1
Variablen
•
Variablen sind Behälter für Programmdaten während der Laufzeit
eines Programms
•
Der Inhalt von Variablen wird unterschiedlich interpretiert, z.B.
(short) 0000 0000 0100 0001 → 65
(char) 0000 0000 0100 0001 → ‘A’
(Ganzzahl)
(Buchstabe)
♦ Typen teilen dem Übersetzer/Laufzeitsystem mit, wie der Wert/
Inhalt einer Variablen zu interpretieren ist
→ Variablen haben unterschiedliche Typen, z.B. Variablen die Zahlen,
Buchstaben, Zeichenketten, etc. enthalten dürfen/können
•
Der Typ bzw. die Klasse einer Variable “entscheidet“ über deren (sinnvolle) Interpretation, z.B.
(short) … + (short) … ≠ (String) … + (String) …
1
+
1
≠
“1“ + “1“
0000 0000 0000 0010 ≠ 0000 0000 0011 0001 0000 0…
2.2
Bezeichner
•
Ein Bezeichner benennt (bzw. bezeichnet) eine Klasse, ein Interface,
eine Methode, eine Variablen etc.
•
Bezeichner beginnen in Java mit einem:
♦ Buchstaben
♦ "_"
♦ "$"
•
Beispiele:
class Circle …
int area() …
double radius;
Double radius;
Programmieren in Java
// Klassenbezeichner
// Methodenbezeichner
// Variablenbezeichner
02.Apr.98
27/120
Variablen, Bezeichner, Typsystem
2.3
•
Datentypen und Typsystem
Java ist eine streng getypte Sprache
♦ statische Typprüfung/-bindung (aber dynamische Methodenbindung; vorsicht nicht verwechseln)
♦ keine “legale” Zeigerarithmetik (u.a. kein *ptr++ etc.)
♦ Variablen können nur typverträgliche Werte enthalten
♦ Zuweisungen sind nur zwischen typverträglichen Variablen und
Ausdrücken möglich
•
zwei Typen sind gleich, wenn sie den gleichen (voll qualifizierten)
Bezeichner haben (Namensäquivalenz vs. Strukturäquivalenz)
•
Java unterscheidet zwischen sogenannten einfachen Datentypen (primitive data types), wie z.B. int, boolean, char, etc. (siehe Kapitel 3)
und komplexen Datentypen (reference data types), wie z.B. Array,
Objekt, etc. (siehe Kapitel 4)
•
(fast) keine implizite Typkonvertierung
•
keine Typkonvertierung (siehe auch Kapitel 8.5.1) zwischen “unzusammenhängenden” bzw. typunverträglichen Typen
♦ eine Typkonvertierung ist u.a. nicht möglich:
• von einem einfachen in einen komplexen Datentyp (Ausnahme:
Konvertierung nach String, also in eine Zeichenkette)
• von einem komplexen in einen einfachen Datentyp
• vom Typ null in einen einfachen Datentyp
• vom Typ boolean in irgend einen anderen Datentyp oder von
irgend einem anderen Datentyp in den Typ boolean (Ausnahme: Konvertierung nach String)
• von einem Klassentyp S in einen Klassentyp T, wenn nicht S
Unterklasse von T ist
• von einem Klassentyp S in einen Interfacetyp K, wenn S final
attributiert ist und nicht K implementiert
Programmieren in Java
02.Apr.98
28/120
Variablen, Bezeichner, Typsystem
2.4
Übungen
(14) Wozu gibt es Typen?
(15) Welche Bezeichner sind zulässig in Java?
Int, $_ab_$, _$ab$_, a_b, a/b, a§b, a1, 1a, _1a
(16) Implementieren sie eine Klasse LifeForm.
• Für unsere Zwecke soll ein Objekt dieser Klasse eine Farbe
(java.awt.Color) und einen Namen (String) haben. Legen
sie hierfür Instanzvariablen (color und name) an. Denken sie
daran, dass ggf. Klassen aus bestimmten Paketen importiert werden müssen, z.B. Color aus java.awt.
• Legen sie entsprechende Zugriffsmethoden zum Setzen und
Lesen der Instanzvariablen an (siehe unten).
• Implementieren sie ferner in der static public void
main(…)-Methode der Klasse einen Minitest. Übersetzen sie die
Klasse und führen sie den Minitest aus.
class LifeForm extends Object
{
…
// Lesen von color
void color()
…
Color color( Color color ) // Setzen von color
…
// Lesen von age
String name()
…
// Setzen von age
void name( String name)
…
}
Bewahren sie den Quellcode auf, er wird für spätere Übungen noch
benötigt. Hinweis: alle Übungen mit einer fettgedruckten Nummer
bauen aufeinander auf und sollten bevorzugt bearbeitet werden.
(17) Schreiben Sie ein kurzes Programm, welches feststellt, ob verschachtelte Kommentare in Java zulässig sind, d.h. das Programm
soll entweder ausgeben ( System.out.println(…)), dass verschachtelte Kommentare zulässig sind oder dass sie es nicht sind.
Das Programm soll in jedem Fall korrekter Java-Code sein.
Programmieren in Java
02.Apr.98
29/120
Einfache Datentypen (primitive data types)
3
Einfache Datentypen
(primitive data types)
•
Einfache Datentypen repräsentieren Werte ohne eigene Identität
•
Eine Variable eines einfachen Datentyps enthält immer direkt den
Wert der entsprechenden Variable
→ immer Wertsemantik, d.h. Speicherstelle für die
Variable enthält direkt den Wert der Variable
•
i
42
An vordefinierten einfachen Datentypen stehen zur Verfügung:
♦ vier Arten von Ganzzahlen (byte, short, int, long)
♦ zwei Arten von Fliesskommazahlen (double, float)
♦ Zeichen bzw. Buchstaben (char) und
♦ bool’sche Werte (boolean)
•
Es gibt in Java keine benutzerdefinierbaren, einfachen Datentypen
(mit Wertsemantik), wie z.B. Aufzählungstypen (enumeration types)
oder Wertbereichstypen (ranged types) in Ada, Modula2, Pascal, etc.
Programmieren in Java
02.Apr.98
30/120
Einfache Datentypen (primitive data types)
3.1
•
Ganzzahlen
4 Varianten
♦ byte → 8 bit → -( 27 ) bis ( 27 -1 )
♦ short → 16 bit → -( 215 ) bis ( 215 -1 )
♦ int → 32 bit → -( 231 ) bis ( 231 -1 )
♦ long → 64 bit → -( 263 ) bis ( 263 -1 )
•
vorzeichenbehaftet (kein “unsigned”)
•
Zweierkomplement
♦ z.B. (byte) -12810 = 1000 00002, (byte) -12710 = 1000 00012,
(byte) 010 = 0000 00002, byte 12710 = 0111 1112
•
Randbedingung: Ablaufgeschwindigkeit
♦ 1 Anweisung/Operation ≡ Drei-Address-Code
♦ keine automatische Grössenanpassung (Bignums)
wie beispielsweise in Smalltalk
♦ keine Exception/Fehlermeldung/Programmabbruch bei Bereichsüberschreitung, aber bei Division durch 0
→ Beispiel … bei der Konvertierung werden die entsprechenden
Bits “abgeschnitten“
byte e1;
int e2;
byte a = 127;
int b = 1;
e1 = (byte) ( a + b );
System.out.println( e1 );
// -128
e2 = ( a + b );
System.out.println( e2 );
// 128
Programmieren in Java
02.Apr.98
31/120
Einfache Datentypen (primitive data types)
3.2
•
Fliesskommazahlen
2 Varianten mit unterschiedlicher Genauigkeit/Auflösung (Fliesskomma-Arithmetik in Java entspricht dem IEEE754 Standard)
♦ 32 bit Fliesskomma → float
♦ 64 bit Fliesskomma → double
•
auch hier keine Bignums (aber ab Java v1.1 Klasse BigNum)
•
keine Exceptions
♦ da im Standard so definiert und auch sinnvoll
→ manchmal kann nur ein “übergeordnetes“ System entscheiden,
ob eine Operation fehlerhaft war und der Betrieb tatsächlich
abgebrochen werden soll, z.B. Komparator (-Software) für
mehrfach redundant ausgelegten Höhenmesser und nicht der
Höhenmesser selbst
♦ auch bei “Division durch 0” keine Exception
♦ problematische Operationen können nachträglich erkannt werden.
Hierfür die folgenden Ergebniswerte vordefiniert:
POSITIVE_INFINITY, NEGATIVE_INFINITY, “Negative Zero”
und NaN (not a number)
System.out.println( 1.0 / 0.0 );
System.out.println( -1.0 / 0.0 );
System.out.println( 0.0 / 0.0 );
// INF
// -INF
// NaN
♦ Anleihe von funktionalen Sprachen, wo jede Funktion ein Ergebnis
liefert muss (siehe VAL oder SETL)
Programmieren in Java
02.Apr.98
32/120
Einfache Datentypen (primitive data types)
3.3
•
Zeichen und Buchstaben
char
♦ 16 Bit Unicode
→ Sonderzeichen, Umlaute etc. sind zulässig in Bezeichnern
♦ Transparent implementiert, d.h. solange keine Unicode-Zeichen ( >
ASCII(256) ) verwendet werden, ist der Umgang mit Zeichen und
Buchstaben wie gewohnt
• ‘a’, ‘b’, etc.
3.4
•
Bool’sche Werte
boolean
♦ true und false
♦ sind keine “Integers” o.ä.,
z.B. aBoolean = (boolean) 17 wird nicht übersetzt
♦ boolean ist in echter, eigenständiger Typ, welcher nicht mit den
Ganzzahlen “verwandt“ ist.
Programmieren in Java
02.Apr.98
33/120
Einfache Datentypen (primitive data types)
3.5
Übungen
(18) Einige Methoden der Klasse LifeForm (siehe Übung (16), sie erinnern sich) sollen geändert werden, so dass sie immer sinnvolle
Default-Werte liefern.
• Ändern Sie die (Getter-)Methode name() und color() der
Klasse LifeForm so ab, dass die Methode name() für den Fall,
dass kein Name vergeben wurde (d.h. die entsprechende Instanzvariable ist gleich null) mit dem Namen der Klasse des Objekts (
this.getClass().getName()) antwortet.
• Ändern Sie und die (Getter-)Methode color() der Klasse LifeForm so ab, dass für den Fall, dass keine Farbe zugewiesen
wurde, mit der Farbe Schwarz (java.awt.Color.black) antwortet. Beispiel:
LifeForm lifeForm = new LifeForm();
// antwortet nun mit “LifeForm“,
lifeForm.name();
// bisher wurde mit null geantwortet
lifeForm.color();
// antwortet nun mit Color.black, bisher null
lifeForm.name( “Bobby“ );
// antwortet wie bisher mit dem gesetzen Namen
lifeForm.name()
…
(19) Schreiben sie ein kleines Testprogramm (oder erweitern sie den Minitest der static public void main(…)-Methode), welches
Objekte der Klasse LifeForm erzeugt und deren Funktionalität
(Farbe(n) und Name(n) lesen und schreiben) testet.
(20) Wie viele/Welche Testfälle sollten (nachdem die Änderung aus
Übung (18) vollzogen ist) für den Minitest zweckmässigerweise
unterschieden werden?
Programmieren in Java
02.Apr.98
34/120
Komplexe Datentypen (reference data types)
4
Komplexe Datentypen
(reference data types)
•
Komplexe Datentypen repräsentieren Werte mit eigener Identität.
•
Eine Variable eines komplexen Datentyps enthält immer eine Referenz (d.h. einen Zeiger) auf ein Objekt/Datum
→ immer Referenzsemantik, d.h. Speicherstelle
für die Variable enthält “nur“ eine Referenz auf
den eigentlichen Wert der Variable
p
•
An komplexen Datentypen stehen zur Verfügung:
Felder/Arrays sowie Klassen und Interfaces
Point
•
Felder → int[][]… matrix = new int [3][3] …
•
Klassen → class EineKlasse …
•
Schnittstellen → interface EineSchnittstelle …
•
Java kennt keine Records, Structs, Unions etc. (wie beispielsweise die
Programmiersprachen Ada, C, Modula II, Pascal etc.)
42
42
♦ Alternative: (methodenlose) Klassen, z.B.
class Point extends Object
{
double x;
double y;
}
class Rectangle extends Object
{
Point upperLeft;
Point lowerRight;
}
Programmieren in Java
02.Apr.98
35/120
Komplexe Datentypen (reference data types)
4.1
•
Felder (arrays)
ein Feld oder Array repräsentiert eine geordnete Menge von Variablen
eines Typs
♦ über einen Index können die Elemente des Arrays adressiert werden → anIntegerArray[17]
♦ in Java ist der Index des ersten Elements ist immer 0
•
je nach Basistyp des jeweiligen Arrays sind entweder Werte oder
Referenzen abgelegt
anIntegerArray
5
1
0
9
1
2
…
anObjectArray
•
…
Arrays in Java sind (eigentlich) spezielle Objekte
♦ Arrays haben ein Instanzvariable length
•
es können Arrays mit beliebigem Typ deklariert werden
int[] anIntegerArray;
int anotherIntergerArray[];
Object[] anObjectArray;
•
es können “Arrays von Arrays“, also Arrays mit beliebig vielen Dimensionen deklariert werden → mehrdimensionale Arrays
int aMatrix[][] = new int [4][2];
♦ aMatrix.length → 4
♦ aMatrix[0].length → 2
Programmieren in Java
02.Apr.98
36/120
Komplexe Datentypen (reference data types)
A propos
•
String ≠ char[] … Strings sind in Java keine Arrays aus Zeichenketten, sondern ein echter eigenständiger Typ, dessen Realisierung
verborgen ist!
Beispiele für Arrays
•
ein leeres Array:
int intArray[] = new int [400];
•
ein vorinitialisiertes Array:
String colorNames[] = { “rot”, “grün”, “blau” };
•
es ist in Java nicht möglich, die Grösse von Feldern statisch d.h. zur
Übersetzungszeit festzulegen bzw. zu beschränken
boolean word[32]; // wird nicht übersetzt
Programmieren in Java
02.Apr.98
37/120
Komplexe Datentypen (reference data types)
4.2
Klassen
[Attributierung] class Klassenbezeichner
// Klassenkopf
[extends Oberklassenbezeichner]
[implements Interfacebezeichner {, Interfacebezeichner}]
// Klassenrumpf
{
Anweisungssequenz
}
•
Typ/Daten + zugehörige Implementierung
Klassenkopf
•
Attributierung
♦ abstract - abstrakte Klasse
• eine unvollständige Implementierung
• nicht instanzierbar, d.h. von einer abstrakten Klasse können
keine Objekte erzeugt werden
♦ final - es dürfen keine Unterklassen gebildet werden
♦ public - Klasse ist überall sichtbar (siehe Kapitel 6.2)
•
die Einhaltung der durch die Attributierung gegebenen Restriktionen
wird vom Übersetzer überprüft
Klassenrumpf
•
Rumpfblock enthält
♦ Klassen- und Instanzvariablen (siehe Kapitel 4.2.4 – 4.2.6)
♦ Klassen- und Instanzmethoden (siehe Kapitel 10.7 – 10.8)
♦ Konstruktoren (siehe Kapitel 10.9)
♦ lokale Klassen, sogenannte “Inner Classes“ (ab Java 1.1.x)
Programmieren in Java
02.Apr.98
38/120
Komplexe Datentypen (reference data types)
4.2.1
Vererbung
… extends Oberklassenbezeichner implements Schnittstellenbezeichner
•
wenn nicht redefiniert, dann verfügt eine Klasse über die gleichen
Attribute (Klassen- und Instanzvariablen) und Operationen (Klassenund Instanzmethoden) wie ihre Oberklasse
→ Bezeichner werden ggf. von Oberklasse geerbt
→ private-Bezeichner → vorhanden aber nicht sichtbar
→ Redefinierte Bezeichner → sichtbar mit super.identifier …
→ Konstruktoren werden nicht vererbt
•
extends deklariert Oberklasse
♦ Wird extends weggelassen, dann wird Object
als Oberklasse angenommen
•
implements deklariert einzuhaltende Schnittstellen
•
Ausschliesslich Einfachvererbung ... aber ...
•
Klasse kann mehrere Schnittstellen implementieren
•
der Typ des Rückgabewerts einer Methode kann nicht ausschliesslichredefiniert werden
•
Typ des Empfängerobjekts der Methoden wird variiert, d.h. implizite
Variation des Empfängerobjekts, keine Variation der Parameter
♦ Typ anderer Parameter wird nicht variiert
•
Typ der Parameter redefinierter Methoden darf nicht allgemeiner sein
als in der Oberklasse (siehe auch Beispiel in Kapitel 4.2.3)
Programmieren in Java
02.Apr.98
39/120
Komplexe Datentypen (reference data types)
4.2.2
Einschub/Wiederholung Varianz des Typs formaler Parameter bei vererbten Methoden
Grundsätzliche Frage für alle OOPSen, die Vererbung unterstützen:
•
Welche Signatur/Schnittstelle hat eine ererbte Methode?
♦ Welche Signatur hat eine ererbte Methode, wenn Objekte der selben Klasse übergeben werden?
Beispiel
class T
//
{
T add( T b )
//
}
class ST extends T
{ … }
in Parameternotation:
-> add( a, b : T ) return T
Welchen Typ haben die Parameter der ererbten add-Funktion?
ST add( b : ST ); //
T add( b : ST ); //
T add( b : T );
//
//
-> add( a, b : ST ) return ST; Covarianz
-> add( a, b, : ST ) return T; Contravarianz
-> add( a : ST; b : T ) return T; impl. Variation des
Empfängerobj.typs, keine Variation der Parameter
Es gibt generell keine richtige oder falsche Art der Varianz; Beispiel
•
Was wenn: T = Integer und ST = Byte?
•
Was wenn: T = Numerischer Typ und ST = numerische Matrix?
Programmieren in Java
02.Apr.98
40/120
Komplexe Datentypen (reference data types)
4.2.3
Beispiel Vererbung und Redefinition
class Outside
{
}
class Top
{
}
class Middle extends Top
{
void foo( Middle anObject )
{
}
void fooToo( Middle anObject )
{
}
}
class Bottom extends Middle
{
void foo( Outside anObject ) { … } /* neue Methode */
/* illegal - würde nicht übersetzt werden */
void fooToo( Top anObject) */
/* legal */
void fooToo( Bottom anObject ) { … } /* redefiniert fooToo */
}
Programmieren in Java
02.Apr.98
41/120
Komplexe Datentypen (reference data types)
4.2.4
Klassenvariablen
static Typ Bezeichner;
•
Klassenvariablen repräsentieren Daten, die für alle Objekte einer
bestimmten Klasse gleich sind
→ der Inhalt einer Klassenvariable (kurz KV) ist identisch für alle
Objekte der Klasse und alle Objekte ihrer Unterklassen, z.B.
class MyClass
{
static int N = 42;
}
// Deklaration und Initialisierung einer KV
class MySubClass extends MyClass
{}
class Application
{
static void dump( int a, int b, int c, int d )
{System.out.println( a+", "+b+", "+c+", "+d );}
public static void main( String args[] )
{
MyClass mc = new MyClass();
MySubClass msc = new MySubClass();
dump( MyClass.N, MySubClass.N, mc.N, msc.N );
// Änderung der KV
MyClass.N = 17;
dump( MyClass.N, MySubClass.N, mc.N, msc.N );
}
}
•
Klassenvariablen sollten generell sparsam und umsichtig verwendet
werden, da sie dazu führen können, dass Klassen zunehmend kontextabhängig werden und/oder Seiteneffekte verbergen
•
Klassenvariablen können die Änderbarkeit von Klassen erschweren,
da ihr Typ in Unterklassen nicht mehr geändert werden kann/sollte/…
Programmieren in Java
02.Apr.98
42/120
Komplexe Datentypen (reference data types)
4.2.5
Klasseninstanzvariablen
… gibt es nicht (direkt) in Java …
… gibts doch (auf Umwegen) …
•
Klasseninstanzvariablen repräsentieren Daten, die für alle Objekte
genau eines Klassen-Typs gleich sind
→ der Inhalt einer Klasseninstanzvariable (kurz KIV) ist gleich für alle
Objekte einer Klasse (oder besser eines “Klassen-Typs“), aber
nicht zwingend für alle Objekte von Unterklassen dieser Klasse
•
Beispiel für KIVs
♦ eine Klasse Fahrzeug mit der KIV anzahlRaeder hat zwei
Unterklassen. Die Klasse Zweirad und die Klasse Dreirad.
♦ die KIV anzahlRaeder kann nun unterschiedliche Werte für
Zweirad (→ anzahlRaeder=2) und Dreirad (→ anzahlRaeder=3) haben; ist aber für alle Objekte der entsprechenden Unterklassen gleich
♦ ändert sich der Wert der KIV, so betrifft dies alle Objekte des “Klassen-Typs“ aber nicht alle Objekte der Klasse
•
Nachbildung von KIVs in Java
♦ mittels Instanzvariablen und entsprechend unterschiedlicher Initialisierung bei der Objekterzeugung
♦ oder Redefinition einer Klassenvariablen
•
Verwendung von KIV bringt generell ähnliche Probleme wie die Verwendung von Klassenvariablen
•
KIV können zusätzlich problematisch sein, da im Programmcode nicht
ohne weiteres ersichtlich ist, wer/welche Objekte von der Änderung
einer KIV eigentlich betroffen sind (siehe Beispiel)
Programmieren in Java
02.Apr.98
43/120
Komplexe Datentypen (reference data types)
•
(schlechtes) Beispiel: KIV über Redefinition einer Klassenvariablen
class Ke
{
static int W = -1;
}
class BiKe extends Ke
{
static int W = 2;
}
// Deklaration KV, W entspricht anzahlRaeder
// Redefinition der KV der Oberklasse
class TriKe extends Ke
{
// Redefinition der KV der Oberklasse
static int W = 3;
}
class Application
{
public static void main( String args[] )
{
Ke aKe
= new Ke();
BiKe aBiKe
= new BiKe();
BiKe anotherBiKe = new BiKe();
TriKe aTriKe
= new TriKe();
System.out.println(aKe.W+", "+aBiKe.W
+", "+anotherBiKe.W+", "+aTriKe.W);
// Änderung der KIV
aBiKe.W = 42;
// hier ist nicht mehr ohne weiteres erkennbar, was sich eigentlich ändert
// Es müssen ggf. ALLE(!) Klassen der Hierarchie betrachet werden
System.out.println(aKe.W+", "+aBiKe.W
+", "+anotherBiKe.W+", "+aTriKe.W);
}
}
Programmieren in Java
02.Apr.98
44/120
Komplexe Datentypen (reference data types)
4.2.6
Instanzvariablen
Typ Bezeichner;
•
Instanzvariablen repräsentieren Exemplardaten
→ der Inhalt einer Instanzvariable (kurz IV) kann für unterschiedliche
Objekte unterschiedlich sein, z.B.
class MyClass
{
static int N = 42;
int n = 42;
}
// Deklaration und Initialisierung einer KV
// Deklaration und Initialisierung einer IV
class MySubClass extends MyClass
{
}
class Application
{
static void dump( int a, int b, int c, int d )
{
System.out.println( a+", "+b+", "+c+", "+d );
}
public static void main( String args[] )
{
MyClass mc = new MyClass();
MySubClassmsc = new MySubClass();
dump( MyClass.N, MySubClass.N, mc.n, msc.n );
// Änderung der IV
mc.n = 17;
dump( MyClass.N, MySubClass.N, mc.n, msc.n );
// Änderung der KV
MyClass.N = 0;
dump( MyClass.N, MySubClass.N, mc.n, msc.n );
}
}
Programmieren in Java
02.Apr.98
45/120
Komplexe Datentypen (reference data types)
4.3
Interfaces
interface EinInterface
[ extends EinAnderesInterface ]
{ /* Schnittstellenrumpf */
public void eineMethode( … );
public void nochEine();
…
}
•
ein Interface definiert Signaturen für Methoden (Methodenköpfe ohne
Methodenrümpfe, Methodenschnittstellen eben), die von denjenigen
Klassen (und allen ihren Unterklassen) bereitgestellt werden müssen,
welche dieses Interface implementieren,
•
wenn eine Klasse eine Schnittstelle implementiert, dann
♦ ist die Schnittstelle bindend auch für alle Unterklassen
♦ wird deren Einhaltung vom Übersetzer überprüft
•
Schnittstellendeklaration analog zur Klassendeklaration
♦ Schnittstellenmethoden dürfen nicht native, static, synchronized, final, private oder protected attributiert sein
♦ Schnittstellen können von anderen Interfaces erben
•
eine Klasse kann beliebig viele Interfaces implementieren
•
Interfaces erlauben von der Klassenhierarchie und jeweiligen Realisierung unabhängige Protokoll- oder Schnittstellenvereinbarungen
Programmieren in Java
02.Apr.98
46/120
Komplexe Datentypen (reference data types)
4.4
Beispiel Klassen und Interfaces
Das nachfolgende Beispiel zeigt die Anwendung des Interfaces Enumeration Klassen und Interfaces aus dem Paket java.util
public interface Enumeration
{
boolean hasMoreElements();
Object nextElement();
}
das Interface Enumeration (aus dem Paket java.util) dient dazu, sicher (Terminierung der Schleife kann einfach(er) bewiesen werden) und
komfortabel über Containerklassen, wie Dictionary, Vector etc. zu iterieren. Eine Iteration erfolgt folgendermassen:
…
Enumeration e = v.elements(); // Enumerationsobj. erzeugen
while (e.hasMoreElements())
// gibts noch weitere Objekte,
{
//über die zu iterieren wäre
// Element ausgeben und zum weiterschalten
System.out.println(e.nextElement());
}
…
Damit so iteriert werden kann, muss die Klasse (hier Vector) eine Methode
(hier elements()) bereitstellen, welche ein Enumerationsobjekt liefert.
Diese ist folgendermassen implementiert:
…
public final synchronized Enumeration elements()
{
return new VectorEnumerator(this);
}
…
Programmieren in Java
02.Apr.98
47/120
Komplexe Datentypen (reference data types)
Nun muss noch die Enumerationsklasse VectorEnumerator implementiert sein. Die Implementierung dieser Enumerations-Klasse ist folgendermassen realisiert:
final class VectorEnumerator implements Enumeration
{
// Instanzvariablen
Vector vector;
int count;
VectorEnumerator(Vector v)
{
vector = v;
count = 0;
}
// Konstruktor
public boolean hasMoreElements()
{
return count < vector.elementCount;
}
public Object nextElement()
{
synchronized (vector)
{
if (count < vector.elementCount)
{ return vector.elementData[count++]; }
}
… rest wurde ausgelassen …
}
}
Programmieren in Java
02.Apr.98
48/120
Komplexe Datentypen (reference data types)
4.5
Übungen
(21) Erstellen sie nun eine Klasse, welche eine spezielle Lebensform,
nämlich einen Fisch repräsentiert. Implementieren sie hierfür die
Klasse Fish, als eine Unterklasse von LifeForm. Ein Fisch soll
standardmässig, d.h. solange nichts anderes definiert ist (vgl. Übung
(18)), die Farbe Blau (-> java.awt.Color.blue) haben.
(22) Realisieren Sie eine weitere spezielle Lebensform, nämlich eine
Pflanze. Implementieren sie hierfür die Klasse Plant, ebenfalls als
Unterklasse von LifeForm.
Eine Pflanze soll standardmässig, d.h. solange nichts anderes definiert ist, die Farbe Grün (java.awt.Color.green) haben. Implementieren sie die entsprechende Funktionalität.
Ferner soll eine Pflanze einen Standort (java.awt.Point) haben;
d.h. es soll möglich sein, einer Pflanze einen Standort zuzuweisen
und/oder den Standort einer Pflanze zu erfragen. Nachdem einer
Pflanze ein Standort jedoch einmal zugeweisen ist, darf es nicht
mehr möglich sein, diesen zu ändern. Legen sie hierfür geeignete
Instanzvariablen (Point location) und Zugriffsmethoden (Point
location() und void location(Point location)) an.
(23) Erstellen Sie Klasse Animal, welche (was für eine Überraschung)
wieder eine spezielle Lebensform – diesmal ein Tier – repräsentiert.
• Welche Klasse wählen sie zweckmässigerweise als Oberklasse
von Animal?
• Welche Eigenschaften (Attribute und Methoden) erbt Animal?
• Genau wie eine Pflanze soll auch ein Tier seinen eigenen Standort
kennen, jedoch soll es im Gegensatz zur Pflanze (siehe Übung
(22)) jederzeit möglich sein, den Standort eines Tiers wieder zu
ändern. Fügen sie hierfür analog zur Klasse Plant die entsprechende Funktionalität zur Klasse Animal hinzu.
(24) Überlegen sie nun, ob für die Klasse Fish nicht eine andere Oberklasse zweckmässig wäre. Bisher ist die Oberklasse LifeForm.
Wenn sie eine passend(er)e Oberklasse gefunden haben, ändern sie
die Klasse Fish entsprechend ab. Wie sieht die Klassenhierarchie
nun aus? Welche Funktionalität erbt Fish?
Programmieren in Java
02.Apr.98
49/120
Variablendeklaration
5
Variablendeklaration
•
Deklaration à la C
•
Java ist “case sensitive“, d.h. Gross- und Kleinschreibung von
Bezeichnern wird unterschieden → A ≠ a etc.
•
Variablendeklaration kann prinzipiell überall erfolgen (vgl. Algol).
♦ (aber) der Ort und die Attributierung der Variablendeklaration entscheidet jedoch über die Art der Variable
• Klassenrumpf und static attributiert → Klassenvariable
• Klassenrumpf und kein static → Instanzvariable
• Methodenkopf → Methodenparameter
Methodenrumpf → lokale Variable
•
Variablen haben immer einen definierten Wert
→ 0, /u0000, null
♦ immer möglich (ausser bei Methodenparametern): explizite Initialisierung einer Variablen gleichzeitig (oder besser gleichzeilig) mit
Variablendeklaration, z.B.
int max = 17;
•
Syntax generell: Zuerst Attributierung, dann Typ, dann Bezeichner
class Foo
{
static final int AClassConstant = 1;
public static Object AClassVariable;
private boolean anInstanceVariable;
Object anotherInstanceVariable = new Object(…);
…
void static aMethod( float aParameter )
{
char aLocalVariable;
…
}
}
Programmieren in Java
02.Apr.98
50/120
Sichtbarkeit und Lebensdauer
6
Sichtbarkeit und Lebensdauer
6.1
Lebensdauer
•
Ort und Attributierung der Deklaration bestimmen Art der Variable
•
Variablenart regelt Lebensdauer
•
Klassenvariablen
♦ Lebensdauer: solange die Klasse existiert
•
Instanzvariablen
♦ Lebensdauer: solange das Objekt existiert
•
Methodenparameter und lokale Variablen
♦ Lebensdauer: während die Methode betreten ist (Stapel)
Programmieren in Java
02.Apr.98
51/120
Sichtbarkeit und Lebensdauer
6.2
Sichtbarkeit
•
Ort und Attributierung der Bezeichnerdeklaration regelt Sichtbarkeit
bzw. den Gültigkeitsbereich des Bezeichners
•
namensgleiche Bezeichner verdecken Bezeichner der nächst höheren
Sichtbarkeitsebene
♦ namensgleiche Bezeichner für lokale Parameter und Methodenparamenter verdecken Instanzvariablen
♦ eine in einer Unterklasse redefinierte Instanz- oder Klassenvariable verdeckt eine namensgleiche Variable der Oberklasse
•
Sichtbarkeit von Bezeichnern für KV und IV sowie von Methodenbezeichnern (und mit Einschränkung auch von Klassenbezeichnern)
wird über eine entsprechende Attributierung der Bezeichnerdeklaration angegeben.
→ Verbergen von Bezeichnern unterstützt das Geheimnisprinzip
(Information Hiding)
Sichtbarkeit
public
protected
standard
(ohne At.)
private
selbes Paket,
Unterklasse
✔
✔
✔
✘
selbes Paket, andere
Klasse (nicht Unterkl.)
✔
✔
✔
✘
anderes Paket,
Unterklasse
✔
✔✘
✘
✘
anderes Paket, andere
Klasse (nicht Unterkl.)
✔
✘
✘
✘
Programmieren in Java
02.Apr.98
private
protected
ab
Version
1.0 nicht
mehr
unterstützt
52/120
Sichtbarkeit und Lebensdauer
6.3
Beispiel: Sichtbarkeit von Variablen
package foo;
public class Foo
{
public int a;
protected int b;
int c;
private int d;
// muss public sein, sonst kein Export möglich
void doSomethingInFoo( int d )
{
Foo e = new Foo();
a = 1;
b = 2;
e.b = 3;
c = 5;
d = 6;
this.d = 7;
}
}
class Guu
{
void doSomethingInGuu()
{
Foo aFoo = new Foo();
aFoo.a
aFoo.b
aFoo.c
aFoo.d
}
=
=
=
=
1;
2;
5;
6;
// erlaubt, da <a> public
// erlaubt, da gleiches Paket
// erlaubt, da gleiches Paket
// offensichtlich nicht erlaubt
}
Programmieren in Java
02.Apr.98
53/120
Sichtbarkeit und Lebensdauer
package guu;
import foo.Foo;
class SubFoo extends Foo
{
void doSomethingInSubFoo( int d )
{
Foo e = new Foo();
SubFoo f = new SubFoo();
a = 1;
b = 2;
e.b = 3;
f.b = 4;
c = 5;
d = 6;
this.d = 7;
}
// offensichtlich erlaubt
// erlaubt da protected
// nicht erlaubt; protected, aber <Foo> in anderem Paket
// erlaubt; protected und <SubFoo> im gleichen Paket
// offensichtlich nicht erlaubt
// erlaubt; d ist Methodenparamenter und verdeckt IV
// nicht erlaubt; d ist private
}
class Guu
{
void doSomethingInGuu()
{
Foo aFoo = new Foo();
SubFoo aSubFoo = new SubFoo();
// offensichtlich erlaubt, da <a> public
aFoo.a = 1;
aFoo.b = 2;
// nicht erlaubt, da <protected>
aSubFoo.b = 4; // nicht erlaubt, da <Guu> nicht Unterkl. von <Foo>
aFoo.c = 5;
// offensichtlich nicht erlaubt
aFoo.d = 6;
// offensichtlich nicht erlaubt
}
}
Programmieren in Java
02.Apr.98
54/120
Sichtbarkeit und Lebensdauer
6.4
Übungen
(25) Was ist in Java ein einfacher Datentyp (primitive data type) und was
ist ein komplexer Datentyp (complex/reference data type)?
• Worin unterscheiden sich einfache und komplexe Datentypen?
• Was versteht man unter Wertsemantik und was versteht man unter
Referenzsemantik?
(26) Welche vordefinierten Datentypen kennt Java?
(27) Wie und wann können Typen in Java konvertiert werden?
(28) Warum wird folgender Ausdruck nicht übersetzt?
int i = (int) true;
(29) Was sind Klassenvariablen und was sind Klasseninstanzvariablen?
(30) Gibt es Klasseninstanzvariablen in Java?
(31) Wann und weshalb kann die Verwendung von Klassenvariablen und/
oder Klasseninstanzvariablen problematisch sein?
(32) Was sind Instanzvariablen?
(33) Was ist der Unterschied zwischen this und super?
(34) Betrachten Sie wieder die Klassen Animal (siehe Übung (23)) und
Plant (siehe Übung (22)).
• Welche gemeinsamen Eigenschaften besitzen diese Klassen
(Stichwort location)?
• Ist es möglich, gemeinsame Eigenschaften (Attribute, Methoden)
in eine gemeinsame Oberklasse zu verlagern? Wenn ja, tun sie
dies. Übersetzen und testen die neuen bzw. geänderten Klassen.
• Welche Eigenschaften erben Animal, Fish und Plant nun ?
(35) Ändern sie die Klasse LifeForm ab, so dass die Standardfarbe über
eine Klassen- oder Instanzvariable (DefaultColor) vordefiniert
werden kann. Die Standardfarbe ist die Farbe, mit welcher die
Methode color() antwortet, wenn keine Farbe explizit gesetzt ist.
Entscheiden sie selbst, welche Variablenart (KV, IV oder Kombination) sie verwenden wollen. Welche Auswirkung(en) hat diese Modifikation der Klasse LifeForm auf die Funktionalität der Methode
color() in den vorhandenen Unterklassen von LifeForm? Müssen hier Anpassungen vorgenommen werden? Wenn ja, welche?
Programmieren in Java
02.Apr.98
55/120
Speicherverwaltung
7
•
Speicherverwaltung
in Java kann belegter Hauptspeicher nicht explizit (aber implizit, siehe
unten) vom Programmierer freigegeben werden
♦ es gibt kein DISPOSE(), dealloc() etc. wie in Pascal, C/C++
♦ Speicherfreigabe wird automatisch durchgeführt
•
Idee: “Speicherabfall“ ist weniger gefährlich als Zeiger ins Leere bzw.
hängende Referenzen
→ solange Abfall produzieren, bis neue Speicheranforderungen nicht
mehr erfüllt werden können; dann, oder auch parallel zur Programmausführung, Abfall einsammeln
→ Garbage Collection (GC)
♦ VM führt Garbage Collection durch
•
Standardlösung für GC:
♦ Phase 1: Markieren aller erreichbaren Heap-Objekte
♦ Phase 2: Freigabe der nicht markierten Heap-Objekte und evtl.
Zusammenlegung von fragmentierten Speicherbereichen
→ d.h. wenn ein Objekt nirgends mehr referenziert wird, dann wird
der Speicher, welchen es belegt, bei der nächsten Garbage Collection eingesammelt
Beispiel für implizite Speicherfreigabe
String[] hugeArray = new String[100000];
/* tue irgend etwas mit <hugeArray>*/
….doSomething(hugeArray);
/* ab hier wird der Array (aus irgendwelchen Gründen) nicht mehr gebraucht, aber
dafür nochmals viel Arbeitsspeicher, also sind wir nett und geben dem Garbage
Collector die Möglichkeit den Arbeitsspeicher, welchen <hugeArray> belegt,
freizugeben */
hugeArray = null;
Object[] anotherHugeArray = new Object[100000];
Programmieren in Java
02.Apr.98
56/120
Speicherverwaltung
Vorteile der GC
•
weniger Arbeit für den Programmierer (→ weniger Fehler)
•
keine Zeiger ins Leere; d.h. sichere Freigabe
→ Freispeicherliste kann (fast) nicht zerstört werden, siehe Bsp.
p := NEW(…)
q := p;
DISPOSE(p);
q^ := 10;
Nachteile der GC
•
u.U. nichtdeterministische Unterbrechung oder Verzögerung der normalen Programmausführung
→ kann bei wirklich harten Echtzeitanforderungen zu erheblichen
Problemen führen (Lsg. “Echtzeitsubset“ der Sprache und eine
spezielle VM)
Programmieren in Java
02.Apr.98
57/120
Speicherverwaltung
7.1
Übungen
(36) Was ist besonders an der Speicherverwaltung in Java?
(37) Was ist und wie funktioniert eine Garbage Collection?
(38) Welche Vor- und Nachteile bringt eine CG?
(39) Ändern sie (analog zu Übung (35)) die Methode location() der
Klasse LifeForm so ab, dass diese immer einen sinnvollen DefaultWert liefert, und dieser über eine Variable vordefiniert werden kann.
(40) Die künstliche Tier- und Pflanzenwelt soll nun auf dem Bildschirm
visualisiert werden.
• Zuerst ist etwas Vorarbeit notwendig. Ändern sie hierfür die Oberklasse von LifeForm in java.util.Observable (bisher war
die Oberklasse Object) und übersetzen sie ihre Klassen neu.
Hinweis: Diese Änderung hat momentan noch keine direkten Auswirkungen, wir benötigen jedoch die Observer/Observable-Funktionalität später noch, wenn Tiere sich selbständig bewegen sollen.
• Wenn sie bis hierher alles “richtig“ implementiert haben, d.h. LifeForm ist Unterklasse von Observable und ein Objekt der Klasse
LifeForm oder einer ihrer Unterklassen liefert auf die Nachrichten color(), location() und name() hin, sinnvolle Werte
ungleich null, dann kann zur Visualisierung die (bereits vorimplementierte) Klasse Zoo verwendet werden. Objekte, die dieser
Klasse mittels der Methode add(aLifeForm) hinzugefügt werden, werden dann automatisch angezeigt.
• Schreiben sie ein Programm (bzw. eine eigenständige Java-Applikation) in welchem Sie einen Zoo anlegen (analog zum Beispiel
unten) und fügen sie je ein Objekt der Klasse LifeForm, Plant,
Animal und Fish diesem Zoo hinzu.
Zoo zoo = new Zoo();
…
Animal animal1 = new Animal();
…
zoo.add( animal1 );
Programmieren in Java
02.Apr.98
58/120
Ausdrücke und Operatoren
8
Ausdrücke und Operatoren
Ausdrücke
Ein Ausdruck ist eine wohlgeformte, d.h. entsprechend der Syntax der
Sprache aufgebaute Reihe von Variablen, Operatoren und Methodenaufrufen, die bei Ausführung des Programms zu einem Wert evaluieren.
Mittels Ausdrücken werden
•
Werte berechnet
•
Zuweisungen durchgeführt und
•
der Kontrollfluss gesteuert
Beispiele
i++
a + b
c = a + i
System.in.read() != -1
Operatoren
•
Operatoren führen eine Operation mit ihren Operanden durch
•
Operatoren haben entweder ein oder zwei Operanden
•
in Java können vordefinierte Operatoren nicht redefiniert werden
Programmieren in Java
02.Apr.98
59/120
Ausdrücke und Operatoren
8.1
•
Arithmetische Operatoren
arithmetische Operatoren können auf Operanden angewandt werden,
deren Typ numerisch ist, also byte, short, int, long, float und
double
8.1.1
Unäre Arithmetische Operatoren
Operator
Anwendung
Beschreibung
+
+ op
… op * 1
–
- op
Negation von op (op*(-1))
++
++op
Inkrementiert op um 1; Evaluation des
Ausdrucks (d.h. Bestimmung des Wertes des
Ausdrucks) erfolgt nach dem Inkrement
--
--op
Dekrementiert op um 1; Evaluation des
Ausdrucks erfolgt nach dem Dekrement
++
op++
Inkrementiert op um 1; Evaluation des
Ausdrucks erfolgt vor dem Inkrement
--
op--
Dekrementiert op um 1; Evaluation des
Ausdrucks erfolgt vor dem Inkrement
8.1.2
•
Binäre Arithmetische Operatoren
Operator
Anwendung
Beschreibung
+
op1 + op2
Summe von op1 plus op1
–
op1 - op2
Differenz op1 minus op2
*
op1 * op2
Produkt von op1 multipliziert mit op2
/
op1 / op2
ganzzahliger Quotient von op1 dividiert durch
op2
%
op1 % op2
Divisionsrest der Division op1 geteilt durch
op2 (op1 mod 0p2)
Anmerkung: Der binäre Operator + ist überladen und führt nicht nur
Additionen durch, sondern auch String-Konkatenationen, wenn die
beiden Operatoren vom Typ String sind
Programmieren in Java
02.Apr.98
60/120
Ausdrücke und Operatoren
8.2
•
Vergleichsoperatoren
(relational operators)
Vergleichsoperatoren geben in Form eines Wahrheitswertes Auskunft
darüber, ob eine bestimmte Beziehung zwischen den Operanden
besteht oder nicht.
Operator
Anwendung
Beschreibung
>
op1 > op2
Evaluiert zu true, wenn op1
grösser als op2 ist; sonst
false
>=
op1 >= op2
true, wenn op1 grösser oder
gleich op2 ist; sonst false
<
op1 < op2
true, wenn op1 kleiner als
op2 ist; sonst false
op1 <= op2
true, wenn op1 kleiner oder
gleich op2 ist; sonst false
==
op1 == op2
true, wenn op1 gleich op2 ist,
d.h. op1 und op2 enthalten den
gleichen Wert oder referenzieren
beide ein identisches Objekt; sonst
false
!=
op1 != op2
true, wenn op1 ungleich op2
ist; sonst false
op1 instanceof op2
true, wenn op1 instanz der
Klasse op2 (oder einer
Oberkasse von op2 ist)
<=
instanceof
Programmieren in Java
02.Apr.98
61/120
Ausdrücke und Operatoren
8.3
Logische Operatoren
(conditional operators)
•
Logische Operatoren führen logische Operationen auf ihren Operanden durch.
•
Die Operanden werden nur bedingt ausgewertet und müssen zu
einem Wert vom Typ boolean evaluieren.
Operator
Anwendung
Beschreibung
&&
op1 && op2
logisches UND
||
op1 || op2
logisches ODER
!
8.4
Negation
! op
Operatoren zur Bitmanipulation
•
Bitmanipulationsoperatoren führen, wie logische Operatoren auch,
logische Operationen auf ihren Operanden durch. Im Unterschied zu
logischen Operatoren jedoch nicht mit den Wahrheitswerten, zu welchen die Operanden evaluieren, sonder direkt auf den Bits der Operanden.
•
Bitmanipulationsoperatoren werden unbedingt ausgewertet!
Operator
Anwendung
Beschreibung
>>
op1 >> op2
vorzeichensensitive Verschiebung der Bits von
op1 um op2-Stellen nach rechts
<<
op1 << op2
vorzeichensensitive Verschiebung der Bits von
op1 um op2-Stellen nach links
>>>
op1 >>> op2
nicht vorzeichensensitive Verschiebung der Bits
von op1 um op2-Stellen nach rechts
&
op1 & op2
bitw. AND-Verknüpfung von op1 und op2
|
op1 | op2
bitw. OR-Verknüpfung von op1 und op2
^
op1 ^ op2
bitw. XOR-Verknüpfung von op1 und op2
~
~ op
bitweises Invertieren von op
Programmieren in Java
02.Apr.98
62/120
Ausdrücke und Operatoren
8.5
•
Zuweisungsoperatoren
(assignment operators)
Zuweisungsoperatoren werden benutzt, um Variablen (und initial auch
Konstanten) Werte zuzuweisen.
Operator
Anwendung
Beschreibung
=
op1 = op2
Weist op1 den Inhalt (Wert oder
Referenz) von op2 zu
+=
op1 += op2
op1 = op1 + op2
-=
op1 -= op2
op1 = op1 - op2
*=
op1 *= op2
op1 = op1 * op2
/=
op1 /= op2
op1 = op1 / op2
%=
op1 %= op2
op1 = op1 % op2
&=
op1 &= op2
op1 = op1 & op2
|=
op1 |= op2
op1 = op1 | op2
^=
op1 ^= op2
op1 = op1 ^ op2
<<=
op1 <<= op2
op1 = op1 << op2
>>=
op1 >>= op2
op1 = op1 >> op2
>>>=
op1 >>>= op2
op1 = op1 >>> op2
8.5.1
Zuweisbarkeit
e = v … die Variablen e und v mit den Typen Te und Tv sind u.a. zuweisbar, wenn die zugehörigen Typen Te und Tv:
•
gleich sind
•
beide numerische Typen sind und der Wertebereich von Te den von
Tv umfasst
•
beides Klassen sind und Te Oberklasse von Tv ist
•
Te eine Klasse ist, Tv ein Interface ist und Te Tv implementiert
•
Te die Klasse Objekt ist und Tv ein Feldtyp ist
Programmieren in Java
02.Apr.98
63/120
Ausdrücke und Operatoren
8.6
Auswertung von Ausdrücken
•
Ausdrücke werden von links nach rechts ausgewertet
•
Operanden werden vor der eigentlichen Operation ausgewertet
•
Parameterlisten für Methoden werden ebenfalls von links nach rechts
ausgewertet
•
Klammerung und Auswertungsreihenfolge für Operatoren wird grundsätzlich beachtet
Auswertungsreihenfolge
→→→
Postfix
Unär
Obj.-Erz., Konv.
Multiplikative
Additive
↓
[] . (params) expr++ expr-++expr --expr +expr -expr ~ !
new (type)expr
* / %
+ -
logischer Shift
<< >> >>>
Relationale Op.
< > <= >= instanceof
↓
Vergleichsop.
== !=
↓
bitweises UND
&
bitw. Exkl-ODER
^
bitw. Inkl.-ODER
|
logisches UND
&&
log. ODER
||
bed. Op.
? :
Zuweisung
Programmieren in Java
= += -= *= /= %= ^= &= |= <<= >>= >>>=
02.Apr.98
64/120
Ausdrücke und Operatoren
8.7
•
Beispiele Ausdrücke und Operatoren
Welchen Wert hat b?
byte b = (byte) 64;
b <<= 1;
•
Ist dies korrekt?
boolean bool = false;
bool++;
•
Wie lautet die Ausgabe?
i = 0;
j = 1;
System.out.println( i+++j );
System.out.println( i+++i );
•
Was geben die Schleifen aus?
i = 0; while ( i++ <= 3 ) System.out.println( i );
i = 0; while ( ++i <= 3 ) System.out.println( i );
for ( i = 0; i <=3; i++ ) System.out.println( i );
for ( i = 0; i <=3; ++i ) System.out.println( i );
•
Wo kann es hier Probleme geben? (beachten die den verwendeten
Operator und die Auswertungsreihenfolge)
if (( array == null ) | ( array.length == 0 ))
System.out.println( "null or length == 0" );
else
System.out.println( "valid" );
Programmieren in Java
02.Apr.98
65/120
Ausdrücke und Operatoren
8.8
Übungen
(41) Welche Ausgabe macht das folgende Programm? Begründen sie
Ihre Lösung? Ist das Ergebnis offensichtlich oder nicht?
class Application
{
static int confusing( int j, int k )
{
return j+k;
}
public static void main( String[] args )
{
int[] a = { 3, 4, 5 };
int i = 1;
a[i] = i++;
System.out.println(a[0]+", "+a[1]+", "+a[2]);
System.out
.println(i+", "+confusing(i++,i)+", "+i);
}
}
(42) Die Methode reverse hat zwei Arrays als Parameter und soll die
Komponenten des ersten Arrays in umgekehrter Reihenfolge an den
zweiten Parameter zuweisen. Funktioniert reverse unter allen
Umständen korrekt? Korrigieren sie ggf. reverse!
public static void reverse( char[] a, char[] b )
{
for ( int i = 0; i < a.length; i=i+1 )
{
b[i]=a[a.length-1-i];
}
}
Programmieren in Java
02.Apr.98
66/120
Ausdrücke und Operatoren
(43) Vervollständigen Sie die Klasse LinkedList indem Sie die Methoden addLast und remove implementieren. Geben Sie jeweils eine
rekursive und eine iterative Lösung an.
class LinkedList
{
Object element;
LinkedList next;
void addLast( Object elementToAdd )
{
…
}
LinkedList remove( Object elementToRemove )
{
…
}
}
(44) Schreiben Sie ein kleines Testprogramm bzw. einen Testtreiber, um
die von Ihnen implementierte LinkedList zu testen.
(45) Die Klasse Animal soll nun erweitert werden. Für jedes Tier soll ein
Partner zugeweisen werden können. Legen Sie hierfür eine entsprechende Instanzvariable partner vom Typ Animal an. Implementieren sie ferner die Zugriffsmethoden Partner partner() und
void partner(Partner partner). Erstere (der “Getter“) sollte
mit dem aktuell gesetzten Partner antworten. Zweitere (der “Setter“)
sollte einen Partner zuweisen. Beachten sie, dass das Zuweisen
eines neuen Partners zur Folge hat, dass der zuzuweisende Partner
ebenfalls einen Partner bekommt, nämlich genau das Objekt, welchem ein Partner zugewiesen werden soll (-> “hatPartner“ ist eine
symmetrische Relation).
Programmieren in Java
02.Apr.98
67/120
Steueranweisungen
9
Steueranweisungen
9.1
Bedingte Anweisungen
•
if-Anweisung wie in C
♦ b1, b2 müssen vom Typ boolean sein!!!
if ( b1 )
{
…
}
else if ( b2)
{
…
}
…
else
{
…
}
•
switch-Anweisung (leider) wie in C
♦ i darf vom Typ byte, char, short, int, oder long sein
switch ( i )
{
case 1: System.out.println(1);
case 2: System.out.println(2); break;
default:System.out.println(3); break;
}
♦ was gibt die obenstehende switch-Anweisung mit i=0, i=2 und
i=4 aus?
Programmieren in Java
02.Apr.98
68/120
Steueranweisungen
9.2
Iterative Anweisungen
•
For-Schleife:
for (int i; i < n; i++) { … }
•
While-Schleife:
while( B ) { … }
•
Do-While-Schleife:
do { … } while ( B )
♦ wie Repeat-Until-Schleife in Pascal, Modula etc.
Apropos
•
Java kennt keine Prozedurparameter, wie z.B. Modula II oder
parametrisierbare Blöcke, wie z.B. Smalltalk
→ daher ist es umständlich, Iterator-Methoden (z.B. do: oder collect: in ST) zu erstellen.
#( 1 $a ‘einWort’ #einSymbol ) do:
[ :i | Transcript show: i printString]
♦ Als Alternative gibt es sogenannte “Enumerations” (siehe auch
Kapitel 4.4)
Enumeration anEnumeration = aCollection.elements();
while ( aEnumeration.hasMoreElements() )
{
System.out.println( aEnumeration.nextElement() );
}
Programmieren in Java
02.Apr.98
69/120
Steueranweisungen
9.2.1
Beispiel
/** Klasse mit Methoden zur Berechnung der Fakultät */
class Faculty
{
static int recursive( int n )
{
if ( n > 1)
{ return ( n * recursive( n-1 )); }
else
{ return 1; };
}
static int iterative( int n )
{
int result = 1;
for ( int i = 2; i <= n; i = i+1 )
{ result = result * i; }
return result;
}
}
/** Hauptprogramm */
class Application
{
public static void main( String args[] )
{
System.out.println( Faculty.recursive(5) );
System.out.println( Faculty.iterative(5) );
}
}
Programmieren in Java
02.Apr.98
70/120
Steueranweisungen
9.3
Übungen
(46) Schreiben sie die Methode static int iterative( int n )
aus des Beispiels aus Kapitel 9.2.1 um, so dass die Methode immer
noch semantisch das gleiche tut (nämlich die Fakultät berechnen),
aber einmal (a) eine while-Schleife verwendet wird und das andere
mal (b) eine do-while-Schleife verwendet wird.
[Text aus Ludewig, Einführung in die Informatik] Leonardo Fibonacci hat in
seinem 1202 erschienen “Liber abaci“ die Frage gestellt, wieviele Kaninchen-Pärchen es nach n Jahren gebe, wenn man im Jahr 1 mit einem Pärchen beginnt und jedes Pärchen vom zweiten Jahr an ein weiteres
Pärchen Nachwuchs hat. Offenbar entsteht die folgende Zahlenreihe
Jahr
Zahl der Pärchen
1
1
2
1
3
2
4
3
5
5
6
8
7 8 …
13 21 …
Diese Art von Wachstum gibt es auch in vielen anderen Bereichen, so
dass die sog. Fibonacci-Zahlen allgemeine Bedeutung haben. Sie lassen
sich wie folgt definieren
Fibonacci(n) = 1
Fibonacci(n) = Fibonacci(n-1) + Fibonacci(n-2)
für n = 1, 2
für n > 2
(47) Implementieren Sie (analog zur Klasse Faculty in Beispiel 9.2.1)
eine Klasse Fibonacci mit zwei Methoden, von welchen die eine
die Fibonacci-Zahlen rekursiv und die andere die Fibonacci-Zahlen
iterativ berechnet.
class Fibonacci
{
static int recursive( int n )
{
…
}
static int iterative( int n )
{
…
}
}
Programmieren in Java
02.Apr.98
71/120
Methoden
10
Methoden
public … Object aMethod( int aParameter, … )
throws anException, …
{
// Methodenrumpf
}
•
Methoden repräsentieren die Operationen, welche ein Objekt kennt
bzw. auf diesem ausführbar sind
Methodenkopf
•
Im Methodenkopf wird deklariert: Die Attributierung, der Typ des Rückgabewert, der Methodenbezeichner, die Liste der formalen Parameter
und die Exceptions welche in der Methode ausgelöst werden können
•
Bezeichner + Parameter zusammen müssen eindeutig sein
•
Überladen von Methoden ist zulässig, solange Methodenbezeichner
und Parameterliste eindeutig sind
Methodenrumpf
•
im Rumpfblock der Methode steht der eigentliche (Arbeits-)Code der
Methode, also die Deklarationen der lokalen Variablen, Ausdrücke und
Steueranweisungen etc.
Programmieren in Java
02.Apr.98
72/120
Methoden
10.1
Attributierung
public … Object aMethod( int aParameter, … )
throws anException, …
die Attributierung der Methode deklariert: die Methodenart (Klassen- oder
Instanzmethode), die Sichtbarkeit (des Methodenbezeichners), abstrakte
Methoden, die Synchronität von Methodenaufrufen, native Methoden und
nicht redefinierbare Methoden
mögliche Attributierungen
♦ protected, public, private, static wie bei Variablen (siehe
Kapitel 6.2), zusätzlich gibt es noch folgende Attributierungen
♦ abstract → abstrakte Methode, d.h es existiert keine Implementierung → abstrakte Klasse
♦ synchronized → für Threadsynchronisation. Erwirbt exkl. Lock
auf Objekt
♦ native → Methode ist in einer anderen Sprache implementiert
(üblicherweise C oder C++) und wird nicht von der VM interpretiert
♦ final → die Methode kann in einer Unterklasse nicht mehr redefiniert werden
Programmieren in Java
02.Apr.98
73/120
Methoden
10.2
Rückgabeparameter
public … Object aMethod( int aParameter, … )
throws anException, …
•
deklariert den Typ des Ergebnisses bzw. des Ergebniswertes, mit welchem die Methode antwortet
•
die Deklaration des Typs des Rückgabeparameters kann nicht weggelassen werden
♦ Schlüsselwort void wird benutzt, wenn die Methode kein Ergebnis
zurückliefert
♦ eckige Klammern zeigen an, dass ein Array zurückgegeben wird,
z.B. public int[] aMethod() {…}
10.3
Parameterliste, Formale Parameter
public … int add1( int aParameter, … )
throws anException, …
{
aParameter = aParameter + 1;
return aParameter;
}
•
Die Objekte und/oder Methoden, welche an eine Methoden übergeben werden können, werden durch Angabe des Typs des Parameter
und eines Bezeichners (formaler Parameter) deklariert
•
im Methodenrumpf sind formale Parameter wie Variablen ansprechbar
•
es ist ausschliesslich Call-By-Value möglich, d.h. der Wert einer Variablen wird vor dem Aufruf der Methode kopiert. Eine Änderung des
Werts der Variablen betrifft also nur den Methodenrumpf
Programmieren in Java
02.Apr.98
74/120
Methoden
10.4
Deklaration der möglichen Exceptions
public … Object aMethod( int aParameter, … )
throws anException, …
(siehe Kapitel 11)
10.5
Methodenaufruf
anObject.aMethod( actualParameter, … );
es wird immer die Methode aufgerufen die
•
anwendbar und
•
“am speziellsten“ ist
•
anwendbar heisst
♦ gleicher Methodenbezeichner
♦ gleiche Anzahl von Parametern
♦ aktuelle Parameter (Aufruf) sind den formalen Parametern (Methodendeklaration) zuweisbar
•
“am speziellsten“ heisst
♦ die Methode aMethod1 ist spezieller als die Methode aMethod2,
wenn die formalen Parameter der Methode aMethod1 als aktuelle
Parameter der Methode aMethod2 dienen könnten, aber nicht
umgekehrt
Programmieren in Java
02.Apr.98
75/120
Methoden
10.6
Beispiel
class Foo
{
int i = 1;
void doSomething()
{
i = i+1;
}
void doSomething( int i )
{
i = i+1;
}
void doSomething( Foo aFoo )
{
aFoo.i = i+1;
}
}
class Application
{
public static void main( String[] args )
{
Foo aFoo = new Foo();
System.out.println( aFoo.i );
aFoo.doSomething();
System.out.println( aFoo.i );
aFoo.doSomething( 1 );
System.out.println( aFoo.i );
aFoo.doSomething( aFoo );
System.out.println( aFoo.i );
}
}
Programmieren in Java
02.Apr.98
76/120
Methoden
10.7
Instanzmethoden
… Object aMethod( int aParameter, … )
throws anException, …
•
sind Exemplaroperationen
•
wird eine Instanzmethode aufgerufen, so wird implizit eine Referenz
auf das aufrufende Objekt mit übergeben
10.8
Klassenmethoden
static … Object aMethod( int aParameter, … )
throws anException, …
•
sind keine Exemplaroperationen, sondern beziehen sich auf alle
Objekte der Klassen
•
Schlüsselwort static legt fest, dass es sich um eine Klassenmethode handelt
•
in einer Klassenmethode kann
♦ this. … nicht verwendet werden
♦ nicht auf Instanzvariablen zugegriffen werden
♦ keine Instanzmethode aufgerufen werden
Programmieren in Java
02.Apr.98
77/120
Methoden
10.9
Konstruktoren
(constructors)
Erzeugen und Initialisieren von Objekten geschieht in Java über sogenannte Konstruktoren (constructor methods, constructors).
•
Konstruktoren sind spezielle Methoden und dienen
♦ der Objekterzeugung sowie
♦ der Objektinitialisierung
•
Konstruktoren sind immer genau so, wie die zugehörige Klasse
bezeichnet, z.B.
class Foo
{
Foo()
{
// Code zur Initialisierung des Objekts
}
•
// Klassendeklaration
// Konstruktor
mehrere Konstruktoren sind erlaubt, wenn sie sich eindeutig durch die
Signatur unterscheiden, z.B.
Foo( int anInteger )
…
// nicht legal, da gleiche Signatur wie Foo( int anInteger )
Foo( int withOtherIdentifier )
…
// legal, da Typ <anObject> und <anInteger> unterschiedlich
Foo( Object anObject )
…
// eindeutig legal
Foo( int anInteger, Object anObject )
…
•
Konstruktoren bzw. deren Bezeichner werden nicht vererbt
♦ super( … ) ruft Konstruktoren der Oberklasse auf
♦ this( … ) ruft andere Konstruktoren der Klasse auf
Programmieren in Java
02.Apr.98
78/120
Methoden
10.9.1
•
Verkettung von Konstruktoren
(constructor chaining)
bevor ein Konstruktor ausgeführt wird, werden immer erst die Konstruktoren der Oberklasse ausgeführt
♦ wenn nichts anderes angegeben wird, dann wird der Standardkonstruktor Klassenname() aufgerufen
Beispiel
class Foo
{
Foo()
{
System.out.println( "Foo()" );
}
}
class FooSub extends Foo
{
FooSub()
{
System.out.println( "FooSub()" );
}
}
→ Ausgabe
Foo()
FooSub()
•
Ist super( arg1, arg2 … argn ) die erste Anweisung im Rumpfblock eines Konstruktors, dann wird der entsprechende n-wertige Konstruktor der Oberklasse aufgerufen, ohne dass zusätzlich der
Standardkonstruktor aufgerufen wird
Programmieren in Java
02.Apr.98
79/120
Methoden
10.10
Initialisierung von Klassen
(class initializer/static initializer)
class Foo
{
static int[] smallArray = { 1, 2, 3 };
static int[] hugeArray = new int[1000];
static
{
for ( int i = 0, i < hugeArray.length, i++ )
{
hugeArray[i] = i;
}
}
…
}
•
ein class initializer oder static initializer ist ein spezieller Code-Block
(oder eine spezielle Methode) zur initialisierung einer Klasse
♦ keine Name
♦ keine Parameter können übergeben werden (von wo auch?!)
♦ kein Rückgabewert
•
wenn eine Klasse zum ersten mal von der VM geladen wird (siehe
Kapitel 1.5.1), dann werden sämtliche Initialsierungen (Variableninitialisierung und class initializer) in der Reihenfolge, in welcher sie im
Code erscheinen, aufgerufen.
Programmieren in Java
02.Apr.98
80/120
Methoden
10.11
Finalizer
protected void finalize()
…
•
ein “Finalizer“ ist eine spezielle Methode, wie main(…) auch,
•
Finalizer dienen dazu, “aufzuräumen“
•
werden vor der Garbage Collection – d.h. bevor das Objekt zerstört
und der belegte Speicher freigegeben wird – genau einmal aufgerufen
•
im Gegensatz zu Konstruktoren (siehe Kapitel 10.9) wird nicht automatisch auch der Finalizer der Oberklasse aufgerufen; dies muss ggf.
mittels super.finalize() vom Programmierer selbst getan werden
•
der genaue Aufrufzeitpunkt ist nicht determiniert, d.h. der exakte Zeitpunkt des Finalizer-Aufrufs ist nicht garantiert
•
alle nicht behandelten Exceptions werden ignoriert
Beispiel
protected void finalize()
{
try
{
myStream.close();
}
catch ( IOException e )
{
System.err.println
(“Stream konnte nicht geschlossen werden”);
}
}
Programmieren in Java
02.Apr.98
81/120
Methoden
10.12
Übungen
(48) Beschreiben sie den Parameterübergabemechanismus der Sprache
Java. Welche Eigenheiten/Probleme gibt es dabei und wie kann man
sie ggf. umgehen?
(49) Wie würde die Ausgabe des Programms des Beispiels in Kapitel 10.6
lauten, wenn die Methode doSomething( int i ) folgendermassen geändert würde? Begründen Sie Ihr Ergebnis!
void doSomething( int i )
{ this.i = this.i+i; }
(50) Würde die Ausgabe des Programms des Beispiels in Kapitel 10.6
anders lauten, wenn folgende Methode hinzugefügt würde? Begründen Sie Ihr Ergebnis!
void doSomething( Object i )
{ this.i = this.i+25; }
(51) Was ist eine Klassenmethode und was ist eine Instanzmethode? Wie
unterscheiden sich Klassen- und Instanzmethoden?
(52) Welchen Restriktionen bestehen bezüglich der Verwendung von
Variablen und Methoden bei Klassenmethoden? Warum bestehen
diese Restriktionen?
(53) Für die Klasse LinkedList (Objekte dieser Klasse repräsentieren
eine verkettete Liste) soll eine Methode sortieren(…) implementiert werden.
• Würden Sie diese Methode als Klassen- oder als Instanzmethode realisieren? Begründen Sie Ihre Entscheidung!
(54) Für die Klasse Teilnehmer (Objekte dieser Klasse repräsentieren
bestimmte Teilnehmerdaten – wie Name, Legi-Nr. etc. – für Teilnehmer des Java Kurses) soll eine Methode neuenTeilnehmerAnlegen(…) implementiert werden.
• Würden Sie diese Methode als Klassen- oder als Instanzmethode realisieren? Begründen Sie Ihre Entscheidung!
Programmieren in Java
02.Apr.98
82/120
Methoden
(55) Erstellen sie selbst (d.h. ohne eine solche Klasse aus einem Java
Paket zu importieren) eine Klasse Stack, welche einen Stack mit
den Operationen push(…) und pop(…) realisiert. Hinweis: Verwenden, ändern und/oder erweitern sie hierzu, die in Aufgabe (43)
erstellte LinkedList Übersetzen und testen Sie Ihr Programm.
(56) Was ist ein “Finalizer“ und wozu dient er?
(57) Welche Ausgabe macht das folgende Programm? Warum ist das so?
Begründen Sie Ihre Lösung (bitte nicht nur abtippen, übersetzen und
ausführen ohne weitere Herleitung)
class Foo
{
Foo()
{ init(); }
void init()
{ System.out.println( "Foo.init()" ); }
}
class FooSub extends Foo
{
FooSub()
{ init(); }
void init()
{ System.out.println( "FooSub.init()" ); }
}
class Application
{
public static void main( String[] args )
{
new FooSub();
}
}
Programmieren in Java
02.Apr.98
83/120
Methoden
(58) Welche Ausgabe macht das folgende Programm? Warum ist das so?
Begründen Sie Ihre Lösung (bitte nicht nur abtippen, übersetzen und
ausführen ohne weitere Herleitung)
class Foo
{
Foo()
{ this("called from Foo()"); }
Foo( String aString )
{ System.out.println("Foo(String)"+aString); }
}
class FooSub1 extends Foo
{
FooSub1( String aString )
{
super("called from FooSub1(String)");
System.out.println("FooSub1(String)"+aString);
}
}
class FooSub2 extends Foo
{
FooSub2( String aString )
{
System.out.println("FooSub2(String)"+aString);
}
}
class Application
{
public static void main( String[] args )
{
new FooSub1( "called from main(String[])" );
new FooSub2( "called from main(String[])" );
}
}
Programmieren in Java
02.Apr.98
84/120
Methoden
(59) Wieder soll die Klasse Animal erweitert werden. In Übung (45)
wurde eine Funktionalität implementiert, welche es erlaubt jedem
Tier einen Partner zuzuweisen und den aktuellen Partner eines Tieres abzufragen. In dieser Übung geht es darum, dass ein Tier einen
eventuell vorhandenen Partner benachrichtigt, wenn es sich bewegt.
Der Partner kann anhand dieser Benachrichtigung erkennen, dass
sich sein Partner bewegt hat und ggf. nachziehen (wenn er das will).
Um diese Funktionalität zu realisieren, sollen neue Methoden angelegt werden. Zum einen ist dies die Methode void moveTo(Point
newLocation) und die Methode void partnerMoved().
Die Methode moveTo(…) soll ein Tier an den mittels newLocation
angegebenen Ort bewegen (mittels this.location(…)) und
anschliessend einen eventuell vorhandenen Partner benachrichtigen
(mittels partner().partnerMoved()).
Die Methode partnerMoved() wird vom Partner aufgerufen wenn
er sich bewegt hat und dient – wie bereits erwähnt – dazu, zu signalisieren, dass sich der Partner bewegt hat. Als Reaktion auf die Bewegung des Partners soll ein Tier sich mit 75% Wahrscheinlichkeit an
den Ort bewegen, welcher jeweils 15 Pixel rechts und unterhalb des
Ortes liegt, an welchen sich der Partner hinbewegt hat; d.h. in drei
von vier Fällen “trottet“ ein Tier hinterher, wenn sich sein Partner
bewegt hat.
Hinweis zur Realisierung: Ein Objekt der Klasse java.util.Random dient der Generierung von Zufallszahlen und kann verwendet
werden, um die 75% “Hinterherzugswahrscheinlichkeit“ zu realisieren
(random.nextFloat() < 0.75).
class Animal extends LifeForm
{
…
/** Bewegt das Tier und benachrichtigt ggf. den Partner. */
void moveTo( Point newLocation )
{
…
}
/** Wird vom Partner aufgerufen, wenn er sich bewegt hat. Mit
einer Wahrscheinlichkeit von 75% bewegt sich das Tier dann auch
Programmieren in Java
02.Apr.98
85/120
Methoden
ungefähr dort hin wo der Partner ist. */
void partnerMoved()
{
…
}
}
(60) Als nächstes soll für die Klasse Animal eine Methode moveRandom() hinzugefügt werden. Wird diese Methode aufgerufen, dann
soll sich das Tier auf eine zufällig ausgewählte Position (x,y) mit
0≤x≤190 und 0≤y≤310 bewegen. Auch soll ein ggf. vorhandener Partner benachrichtigt werden, wenn sich das Tier bewegt hat; sie können also auf die in Übung (59) implementierte Methode moveTo(…)
zurückgreifen.
Hinweis zur Realisierung: Um die neue, zufällige Position des Tiers
zu berechnen, können sie wieder ein Objekt der Klasse Random verwenden. Eine mögliche x-Position berechnet sich dann folgendermassen: newX = (int) (random.nextFloat()*310). Noch
ein Hinweis zur Realisierung: Vielleicht haben sie ja in Übung (59)
bereits eine entsprechende Instanzvariable zur Generierung von
Zufallszahlen angelegt, welche sie nun wieder verwenden können.
Programmieren in Java
02.Apr.98
86/120
Ausnahmebehandlung (exceptions & errors)
11
•
Ausnahmebehandlung
(exceptions & errors)
in Java ist eine speziell Ausnahme- bzw. Fehlerbehandlung eng in die
Programmiersprache integriert, d.h. es müssen beispielsweise keine
speziellen Rückgabewerte (z.B. -1) vereinbart werden, um Fehler zu
erkennen
Idee: Beim Eintritt einer bestimmten Ausnahmesituation (exception) wird
automatisch zu einem geeigneten Programmteil (exception handler) verzweigt, welcher die Situation (hoffentlich) bereinigt. Danach wird das Programm von einem definierten Punkt an fortgesetzt
•
die Ausnahmebehandlung in Java hat “Recovery-Semantik“ (im
Gegensatz zur “Resume-Semantik“ z.B. in PL/I), d.h. nachdem eine
Exception behandelt wurde, fährt die Programmsteuerung am Ende
des umschliessenden Konstrukts fort (und nicht am Ende derjenigen
Anweisung, welche die Exception ausgelöst hat)
•
wird eine Exception nicht abgefangen und behandelt so wird sie entsprechend der lexikalischen/statischen Blockstruktur “nach oben“ propagiert, bis ein entsprechender Exception Handler gefunden wird
•
wird kein Exception Handler gefunden, d.h. wird die Exception nirgendwo abgefangen und behandelt, so bricht das Programm bzw. der
Thread mit einem Laufzeitfehler ab
Eine Exception in Java muss entweder
♦ behandelt, d.h. abgefangen werden oder
♦ es muss (zumindest) im Methodenkopf explizit deklariert werden,
dass dies nicht geschieht
→ “catch or declare”-Regel
Programmieren in Java
02.Apr.98
87/120
Ausnahmebehandlung (exceptions & errors)
11.1
Auslösen, Weiterleiten und Abfangen
Auslösen von Exceptions
(raising/throwing exceptions)
•
throw anException … löst eine Exception aus, z.B.
throw new EOFException();
Propagieren, d.h. “nicht-abfangen“ und weiterleiten von Exceptions
(exception propagation)
•
throws AnException, AnotherException, … deklariert die
Exceptions, welche eine Methode auslösen kann und die nicht von der
Methode selbst abgefangen und behandelt werden, z.B.
public int read() throws IOException
Abfangen und behandeln von Exceptions
(exception handling)
•
mittels der try/catch/finally-Anweisungen werden Exceptions in
Java abgefangen und behandelt
try
{
// der Block, in welchem eine Exception auftreten kann
}
catch ( AnException e )
{
// der Block, in welchem eine Exception vom Typ <AnException> behandelt wird
}
catch ( AnotherException e )
…
finally
{
// der Code in diesem Block wird IMMER ausgeführt, egal wie der try-Block
// verlassen wurde
}
Programmieren in Java
02.Apr.98
88/120
Ausnahmebehandlung (exceptions & errors)
11.2
Beispiel Exceptions
Die Entscheidung, was bei einer Exception zu tun ist, kann nicht immer lokal entschieden werden, sondern ist problembereichsabhängig und muss
von übergeordneten Systemkomponenten vorgenommen werden (z.B ein
Sensor kann aufgrund von Erschütterungen/Turbulenzen keine korrekten
Daten liefern. Nur der Sensor kann diesen Zustand erkennen und eine Exception “werfen“).
…
while (true)
{
try
{
data = sensor.getData();
airplane.control( Data );
}
catch ( … )
{
lass den Zyklus aus, aber “keep flying“
}
}
…
vs.
…
try
{
while (true)
{
data = sensor.getData();
NuclearPowerPlant.control( Data );
}
}
catch ( … )
{
shut down
}
Programmieren in Java
02.Apr.98
89/120
Ausnahmebehandlung (exceptions & errors)
11.3
Exceptions & Errors
•
eine Exception in Java zeigt eine Ausnahmesituation an, die im regulären Programmbetrieb nicht vorgesehen ist und besonderer Behandlung bedarf, damit das Programm weiterlaufen kann
•
ein Error in Java zeigt einen schwerwiegenden Fehler oder ein
Systemversagen an, welches in den allermeisten Fällen dazu führt,
dass eine Programmausführung abgebrochen werden muss
→ Errors sollten – auch wenn dies möglich ist – nicht abgefangen
werden, da sich das System in einem undefinierten Zustand befinden kann
11.4
•
Realisierung
jede Exception und jeder Error wird in Java durch ein Objekt irgend
einer Unterklasse der Klasse java.lang.Throwable repräsentiert
♦ standardmässig hat die Klasse Throwable zwei Unterklassen.
Die Klasse Exception und die Klasse Error (siehe Kapitel 11.3)
•
wird eine Exception ausgelöst, so wird das in der throw-Anweisung
referenzierte Objekt benutzt, um nach einer passenden catch-Anweisung zu suchen
♦ gesucht wird anhand der lexikalischen Blockstruktur von “unten
nach oben“. Wird auf einer Ebene keine passende catch-Anweisung gefunden so wird die Exception “nach oben“ propagiert.
♦ eine catch-Anweisung ist passend, wenn der instanceof-Operator angewandt auf das Exception-Object und die Klasse des formalen Parameters einer catch-Anweisung true ergibt.
•
wird eine passende catch-Anweisung gefunden, so wird der entsprechende Rumpfblock ausgeführt. Anschliessend fährt die Programmsteuerung am Ende der entsprechenden try/catch/finalizeAnweisung fort
•
wird keine passende catch-Anweisung gefunden so bricht das Programm oder der betroffene Thread mit einem Laufzeitfehler ab
Programmieren in Java
02.Apr.98
90/120
Ausnahmebehandlung (exceptions & errors)
11.5
•
Anwendung von Exceptions
mittels Exceptions und Exception Handlern soll(t)en unerwartete –
nicht aber unvorhersehbare – Bedingungen/Fehler/Situationen/
Zustände, so abgefangen/behandelt werden, dass ein Programm
möglichst nicht abbricht, sondern ab einem definierten Wiedereinstiegspunkt weiterlaufen kann.
♦ Code für Fehlerbehandlung wird separiert vom Code für regulären
Programmablauf
→ Code wird besser verständlich
•
Exceptions sind nicht dazu da, Bedingungen/Situationen/Zustände zu
behandeln, die bei jedem regulären Programmablauf zu erwarten sind
♦ Code für Fehlerbehandlung würde nun nicht separiert vom Code
für regulären Programmablauf
→ in diesem Fall bieten Exceptions keine Vorteile gegenüber verschachtelten if-Anweisungen
→ Code wird zunehmend schwierig(er) zu verstehen, da der
jeweilige Kontext schlechter zu erfassen ist
→ effiziente Optimierung des Übersetzers ist (fast) nicht mehr
möglich, da nun zwei “reguläre“ Kontroll- und Datenflüsse
bestehen würden
schlechtes Beispiel:
int[] anArray = { 3, 1, 2, 5, 4 };
int sum = 0;
try
{
for( int i = 0; i<Integer.MAX_VALUE; i = i+1 )
{
sum = sum + anArray[i];
}
}
catch( ArrayIndexOutOfBoundsException e )
{}
Programmieren in Java
02.Apr.98
91/120
Ausnahmebehandlung (exceptions & errors)
11.6
Übungen
(61) Was ist eine Exception in Java?
(62) Was versteht man in Java unter einem Error?
(63) Wie wird eine Exception in Java ausgelöst bzw. geworfen?
(64) Wie kann man Exceptions in Java abfangen?
(65) Was sagt die “catch or declare“-Regel aus?
(66) Ändern sie die Methode reverse aus Übung (42) so ab, dass bei
einer Eingabe, bei welcher die Methode nicht mehr korrekt funktionieren kann (z.B. identische Arrays werden übergeben) entsprechende Exceptions geworfen werden.
(67) Warum ist folgende Verwendung des “Java-Exception-Handlings“
zumindest schlechter Stil?
try
{
FileInputStream input;
input = new FileInputStream("duesentrieb.txt");
while (true)
{
int aValue = input.read();
if ( aValue == -1 )
{
System.out.println();
throw ( new EOFException() );
}
else
System.out.print( (char) aValue );
}
}
catch ( IOException e )
{
}
Programmieren in Java
02.Apr.98
92/120
Threads und Synchronisation
12
Threads und Synchronisation
Threads
•
Threads sind eigenständig ablaufende (Sub-)Prozesse
•
Threads
→ haben einen separaten Kontrollfluss
→ haben eine eigene Lebendauer
→ konnen mit anderen Prozessen kommunizieren und Daten
gemeinsam mit anderen Prozessen nutzen
→ werden “ge-schedult“ (preemptiv oder kooperativ)
Synchronisation
•
Regelt den Zugriff mehrerer Prozesse auf gemeinsam genutzte (kritische) Datenbereiche
•
In Java kann ein kritischer Code-Bereich geschützt werden, so dass
nur ein Thread diesen betreten kann
•
Ist eine Methode synchronized attributiert, dann
♦ wird automatisch vor dem Methodenaufruf der Monitor für das
zugehörige Objekt erworben bzw. belegt
♦ wird nach dem Methodenaufruf der Monitor wieder freigegeben
♦ werden andere Threads ggf. “schlafen geschickt” bis Monitor wieder frei ist
♦ können mittels wait() und notify()/notifyAll() Threads
“schlafen geschickt“ und “geweckt” werden
Programmieren in Java
02.Apr.98
93/120
Threads und Synchronisation
12.1
Erzeugen von Threads
1. Schritt: Programmieren des Threads
•
Schreiben einer Klasse mit einer Methode run()
•
Die Klasse muss entweder Unterklasse der Klasse Thread sein oder
das Interface Runnable implementieren
•
wenn einem Objekt dieser Klasse die Nachricht start() geschickt
wird, dann wird die Methode run() als separater Kontrollfluss ausgeführt
2. Schritt: Starten des Threads
•
erzeugen eines Objekts
♦ mit new <Unterklasse>, wenn die Klasse Unterklasse der
Klasse Thread ist
♦ mit new Thread( … ), wenn die Klasse das Interface Runnable
implementiert
•
diesem Objekt die Nachricht start() schicken
Programmieren in Java
02.Apr.98
94/120
Threads und Synchronisation
Beispiel
class Foo extends Thread
{
public void run()
{
while (true) {
System.out.println( getName() );
yield();
}
}
}
class Application
{
public static void
{
Thread t1 = new
Thread t2 = new
Thread t3 = new
main( String args[] )
Foo();
Foo();
Foo();
System.out.println( "Starting Threads ..." );
t1.start();
t2.start();
t3.start();
System.out.println( "... Threads started!" );
try { t3.join(5); }
catch ( InterruptedException e ) { }
System.out.println( "Stopping Threads ..." );
t1.stop();
t2.stop();
t3.stop();
System.out.println( "... Threads stopped!" );
}
}
Programmieren in Java
02.Apr.98
95/120
Threads und Synchronisation
12.2
Synchronisation
•
am Beispiel Reader/Writer-Problem
•
Zeigt u.a. recht gut: Threads und Synchronisationsprimitiven
Reader/Writer-Problem
•
Ein gemeinsam genutzter Speicher
•
Zwei Arten von Threads (aber beliebig viele Threads)
•
Eine Art produziert Werte (Writer) die andere “konsumiert” diese
(Reader)
•
Produzierte Werte werden im gemeinsam genutzten Speicher abgelegt
•
Zu konsumierende Werte werden beim gemeinsam genutzten
Speicher abgeholt
•
Es kann nur konsumiert werden wenn zuvor produziert wurde
und umgekehrt …
→ Zwang zur Synchronisation von Reader und Writer
Programmieren in Java
02.Apr.98
96/120
Threads und Synchronisation
12.2.1
Beispiel Synchronisation
class SharedStorage
{
private Object content;
private boolean isEmpty()
{ return ( content == null ); }
public synchronized Object content()
{
Object temp;
while ( isEmpty() )
{
try { wait(); }
catch ( InterruptedException anException ) {}
}
temp = content;
content = null;
notifyAll();
return temp;
}
public synchronized void content(Object aContent)
{
while ( ! isEmpty() )
{
try { wait(); }
catch ( InterruptedException anException ) {}
}
content = aContent;
notifyAll();
}
}
Programmieren in Java
02.Apr.98
97/120
Threads und Synchronisation
class Reader extends Thread
{
private SharedStorage toReadFrom;
public Reader( SharedStorage toReadFrom )
{
this.toReadFrom = toReadFrom;
}
public void run()
{
Object anObject;
for ( int i = 0; i < 8; i++ )
{
anObject = toReadFrom.content();
Transcript.show( "Reader[" + getName()
+ "] got: " + anObject.toString());
yield();
}
Transcript.show( "*** Reader[" + getName()
+ "] terminates" );
}
}
Programmieren in Java
02.Apr.98
98/120
Threads und Synchronisation
import java.util.Random;
class Writer extends Thread
{
private SharedStorage toWriteTo;
private Random rndGen = new Random();
public Writer( SharedStorage toWriteTo )
{
this.toWriteTo = toWriteTo;
}
public void run()
{
Integer anInteger;
for ( int i = 0; i < 12; i++ )
{
anInteger = new Integer( rndGend.nextInt() );
toWriteTo.content( anInteger );
Transcript.show( "Writer[" + getName()
+ "] put: " + anInteger.toString() );
yield();
}
Transcript.show( "*** Writer[" + getName()
+ "] terminates" );
}
}
Programmieren in Java
02.Apr.98
99/120
Threads und Synchronisation
public class ReaderWriter
{
public static void main( String args[] )
{
SharedStorage shared = new SharedStorage();
Reader firstReader = new Reader( shared );
Reader secondReader = new Reader( shared );
Reader thirdReader = new Reader( shared );
Writer firstWriter = new Writer( shared );
Writer secondWriter = new Writer( shared );
firstReader.start();
secondReader.start();
thirdReader.start();
firstWriter.start();
secondWriter.start();
}
}
Programmieren in Java
02.Apr.98
100/120
Threads und Synchronisation
12.3
•
Monitore
Monitore in Java sind reentrant, d.h. der Versuch des “Besitzers“ den
Monitor mehrfach zu erwerben bzw. zu belegen, führt nicht zu einer
Verklemmung
class Reentrant
{
public synchronized void a()
{
System.out.println("bin in a(), rufe b() auf");
b();
System.out.println("wieder in a()");
}
public synchronized void b()
{
System.out.println("jetzt bin ich in b()");
}
}
class Application
{
public static void main( String[]
{
new Reentrant().a();
}
}
Programmieren in Java
02.Apr.98
args )
101/120
Threads und Synchronisation
12.4
Übungen
(68) Welche besondere Eigenschaft haben Monitore in Java?
(69) Ändern Sie die main-Methode des Beispiels in Kapitel 12.1, so dass
diese mit folgender Implementierung der Klasse Foo sinngemäss
gleich arbeitet wie o.g. Beispiel. Hinweis: Es geht darum, einen
Thread nicht als Unterklasse von Thread zu implementieren (wie im
Beispiel 12.1), sondern mittels des Interfaces Runnable.
class Foo implements Runnable
{
public void run()
{
while (true) {
System.out.println( this );
Thread.yield();
}
}
}
class Application
{
public static void main( String args[] )
{
// Diese Methode ist zu implementieren
}
}
(70) Wir wollen nun den Tieren im Zoo etwas Leben “einhauchen“ und sie
dazu bringen sich selbständig zu bewegen. Bei der Erzeugung eines
Animal-Objekts soll ein eigener Thread gestartet werden, welcher
das Tier von Zeit zu Zeit auf eine zufällig ausgewählte Position
bewegt.
• Implementieren sie hierfür in der Klasse Animal das Interface
Runnable. Gestalten sie die run()-Methode so, dass sich das
Tier auf eine zufällig ausgewählte Position bewegt (moveRandom()) und anschliessend ca. eine Sekunde wartet
(Thread.sleep(…)).
Programmieren in Java
02.Apr.98
102/120
Threads und Synchronisation
• Implementieren sie ferner für Animal einen Konstruktor, welcher
bei der Objekterzeugung- bzw. Initialisierung den entsprechenden
Thread startet (new Thread( this )).start()).
• Damit der Zoo die Bewegung des Tieres auch mitbekommt und die
Anzeige aktualisieren kann, muss er entsprechend benachrichtigt
werden. Dies erfolgt dadurch, dass in der Setter-Methode location(…) der Klasse LifeForm folgende Codezeilen ans Ende
der Methode location(…) eingefügt werden:
void location( … )
{
…
setChanged();
notifyObservers();
}
(71) Als vorletzte Übung soll nun noch ein spezielles Tier implementiert
werden. Diesmal ein Chamäleon. Ein Chamäleon bewegt sich wie
ein Tier nur seltener und es soll weiterhin die Besonderheit haben,
dass es selbständig von Zeit zu Zeit seine Farbe wechselt. Implementieren sie die entsprechende Funktionalität.
(72) Bauen sie ihren Zoo mit Tieren und Planzen so aus, wie es Ihnen
beliebt.
Programmieren in Java
02.Apr.98
103/120
Threads und Synchronisation
Das wars …
Programmieren in Java
02.Apr.98
104/120
Schlüsselworte
13
Schlüsselworte
Die folgenden Worte sind reservierte Schlüsselworte in Java und können
daher nicht als Bezeichner verwendet werden.
abstract
default
goto
null
synchronized
boolean
do
if
package
this
break
double
implements
private
throw
byte
else
import
protected
throws
case
extends
instanceof
public
transient
catch
false
int
return
true
char
final
interface
short
try
class
finally
long
static
void
const
float
native
super
volatile
continue
for
new
switch
while
Hinweise
•
strenggenommen sind true und false, wie auch null keine reservierten Schlüsselworte sondern Literale
•
Obwohl unbenutzt in Java, sind die Schlüsselworte const und goto
reserviert. Dies ermöglicht es dem Übersetzer, bessere Fehlermeldungen zu produzieren, wenn diese C++ Schlüsselworte irrtümlicherweise in Java-Programmen auftauche
Programmieren in Java
02.Apr.98
105/120
Java 1.0.2 EBNF Grammatik
14
Java 1.0.2 EBNF Grammatik
14.1
Bezeichner
Identifier =
IdentifierChars .
IdentifierChars =
JavaLetter |
IdentifierChars JavaLetterOrDigit .
JavaLetter =
beliebiger Unicode-Buchstabe
JavaLetterOrDigit =
beliebiger Unicode-Buchstabe oder beliebiges Unicode-Zeichen
14.2
Literale
14.2.1
Integer Literale
Literal =
IntegerLiteral |
FloatingPointLiteral |
BooleanLiteral |
CharacterLiteral |
StringLiteral |
NullLiteral .
IntegerLiteral =
DecimalIntegerLiteral |
HexIntegerLiteral |
OctalIntegerLiteral .
DecimalIntegerLiteral =
DecimalNumeral [ IntegerTypeSuffix ] .
HexIntegerLiteral =
HexNumeral [ IntegerTypeSuffix ] .
OctalIntegerLiteral =
OctalNumeral [ IntegerTypeSuffix ] .
Programmieren in Java
02.Apr.98
106/120
Java 1.0.2 EBNF Grammatik
IntegerTypeSuffix =
l|L.
DecimalNumeral =
0 | NonZeroDigits [ Digits ] .
Digits =
Digit | Digits Digit .
Digit =
0 | NonZeroDigit .
NonZeroDigit =
1|2|3|4|5|6|7|8|9.
HexNumeral =
0 x HexDigit |
0 X HexDigit |
HexNumeral HexDigit .
HexDigit =
0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f|A|B|C|D|E|F.
OctalNumeral =
0 x OctalDigit |
0 X OctalDigit |
OctalNumeral OctalDigit .
OctalDigit =
0|1|2|3|4|5|6|7|8.
14.2.2
Boolean Literale
BooleanLiteral =
true | false .
14.2.3
FloatingPoint Literale
FloatingPointLiteral =
Digits . [ Digits ] [ ExponentPart ] [ FloatTypeSuffix ] |
. Digits [ ExponentPart ] [ FloatTypeSuffix ] |
Digits ExponentPart [ FloatTypeSuffix ] |
Digits [ ExponentPart ] FloatTypeSuffix .
ExponentPart =
ExponentIndicator SignedInteger .
Programmieren in Java
02.Apr.98
107/120
Java 1.0.2 EBNF Grammatik
ExponentIndicator =
e|E.
SignedInteger =
[ Sign ] Digits .
Sign =
+|-.
FloatTypeSuffix =
f|F|d|D.
14.2.4
Character und String Literale
CharacterLiteral =
‘ SingleCharacter ‘ |
‘ EscapeSequence ‘ .
SingleCharacter =
InputCharacter aber nicht ‘ oder \
StringLiteral =
“ [ StringCharacters ] “ .
StringCharacters =
StringCharacter |
StringCharacters StringCharacter .
StringCharacter =
InputCharacter aber nicht “ oder \ |
EscapeSequence .
EscapeSequence =
\b|\t|\n|\f|\r|\“|\‘|\\|
OctalEscape .
OctalEscape =
\ OctalDigit |
\ OctalDigit OctalDigit |
\ ZeroToThree OctalDigit OctalDigit .
ZeroToThree =
0|1|2|3.
Programmieren in Java
02.Apr.98
108/120
Java 1.0.2 EBNF Grammatik
14.2.5
Null Literal
NullLiteral =
null .
14.2.6
Separators
Separators =
(|)|{|}|[|]|;|,|..
14.3
Typen
Type =
PrimitiveType | ReferenceType .
PrimitiveType =
NumericType | boolean .
NumericType =
IntegralType | FloatingPointType .
IntegralType =
byte | short | int | long | char .
FloatingPointType =
float | double .
ReferenceType =
ClassOrInterfaceType | ArrayType .
ClassOrInterfaceType =
Name .
ClassType =
ClassOrInterfaceType .
InterfaceType =
ClassOrInterfaceType .
ArrayType =
PrimitiveType [] | Name [] | ArrayType [] .
14.4
Namen
Name =
SimpleName | QualifiedName .
Programmieren in Java
02.Apr.98
109/120
Java 1.0.2 EBNF Grammatik
SimpleName =
Identifier .
QualifiedName =
Name . Identifier .
14.5
Pakete
CompilationUnit =
[ PackageDeclaration ]
[ ImportDeclarations ]
[ TypeDeclarations ] .
ImportDeclarations =
ImportDeclaration |
ImportDeclarations ImportDeclaration .
TypeDeclarations =
TypeDeclaration |
TypeDeclarations TypeDeclaration .
PackageDeclaration =
package Name ; .
ImportDeclaration =
SingleTypeImportDeclaration |
TypeImportOnDemandDeclaration .
SingleTypeImportDeclaration =
import Name ; .
TypeImportOnDemandDeclaration =
import Name . * ; .
TypeDeclaration =
ClassDeclaration | InterfaceDeclaration ; .
14.6
Attributierungen
Modifiers =
Modifier |
Modifiers Modifier .
Programmieren in Java
02.Apr.98
110/120
Java 1.0.2 EBNF Grammatik
Modifier =
public | protected | private |
static |
abstract | final | native |
synchronized | transient | volatile .
14.7
Klassen
14.7.1
Klassen Deklaration
ClassDeclaration =
[ Modifiers ] class Identifier [ Super ] [ Interfaces ]
ClassBody.
Super =
extends ClassType .
Interfaces =
implements InterfaceTypeList .
InterfaceTypeList =
InterfaceType |
InterfaceTypeList , InterfaceType .
ClassBody =
{ ClassBodyDeclarations } .
ClassBodyDeclarations =
ClassBodyDeclaration |
ClassBodyDeclarations ClassBodyDeclaration .
ClassBodyDeclaration =
ClassMemberDeclaration
StaticInitializer
ConstructorDeclaration .
ClassMemberDeclaration =
FieldDeclaration
MethodDeclaration .
14.8
Variablen
FieldDeclaration =
[ Modifiers ] Type VariableDeclarators ; .
Programmieren in Java
02.Apr.98
111/120
Java 1.0.2 EBNF Grammatik
VariableDeclarators =
VariableDeclarator |
VariableDeclarators , VariableDeclarator .
VariableDeclarator =
VariableDeclaratorId |
VariableDeclaratorId = VariableInitializer .
VariableDeclaratorId =
Identifier |
VariableDeclaratorId [] .
VariableInitializer =
Expression |
ArrayInitializer .
14.9
Methoden
MethodDeclaration =
MethodHeader MethodBody .
MethodHeader =
[ Modifiers ] Type MethodDeclarator [ Throws ] |
[ Modifiers ] void MethodDeclarator [ Throws ] .
MethodDeclarator =
Identifier ( [ FormalParameterList ] ) |
MethodDeclarator [] .
FormalParameterList =
FormalParameter |
FormalParameterList , FormalParameter .
FormalParameter =
Type VariableDeclaratorId .
Throws =
throws ClassTypeList .
ClassTypeList =
ClassType |
ClassTypeList , ClassType .
MethodBody =
Block |
;.
Programmieren in Java
02.Apr.98
112/120
Java 1.0.2 EBNF Grammatik
14.10
Static Initializers
StaticInitializer =
static Block .
14.11
Konstruktoren
ConstructorDeclaration =
[ Modifiers ] ConstructorDeclarator [ Throws ] ConstructorBody .
ConstructorDeclarator =
SimpleName ( [ FormalParameterList ] ) .
ConstructorBody =
{ [ ExplicitConstructorInvocation ] [ BlockStatements ] } .
ExplicitConstructorInvocation =
this ( ArgumentListopt ) ; |
super ( ArgumentListopt ) ; .
14.12
Interfaces
14.12.1
Interface Deklaration
InterfaceDeclaration =
[ Modifiers ] interface Identifier [ ExtendsInterfaces ] InterfaceBody .
ExtendsInterfaces =
extends InterfaceType |
ExtendsInterfaces , InterfaceType .
InterfaceBody =
{ [ InterfaceMemberDeclarations ] } .
InterfaceMemberDeclarations =
InterfaceMemberDeclaration |
InterfaceMemberDeclarations InterfaceMemberDeclaration .
InterfaceMemberDeclaration =
ConstantDeclaration |
AbstractMethodDeclaration .
ConstantDeclaration =
FieldDeclaration .
Programmieren in Java
02.Apr.98
113/120
Java 1.0.2 EBNF Grammatik
AbstractMethodDeclaration =
MethodHeader ; .
14.13
Arrays
ArrayInitializer =
{ [ VariableInitializers ] [ , ] } .
VariableInitializers =
VariableInitializer |
VariableInitializers , VariableInitializer .
14.14
Blöcke und Anweisungen
Block =
{ [ BlockStatements ] } .
BlockStatements =
BlockStatement |
BlockStatements BlockStatement .
BlockStatement =
LocalVariableDeclarationStatement |
Statement .
LocalVariableDeclarationStatement =
LocalVariableDeclaration ; .
LocalVariableDeclaration =
Type VariableDeclarators .
Statement =
StatementWithoutTrailingSubstatement |
LabeledStatement |
IfThenStatement |
IfThenElseStatement |
WhileStatement |
ForStatement .
StatementNoShortIf =
StatementWithoutTrailingSubstatement |
LabeledStatementNoShortIf |
IfThenElseStatementNoShortIf |
WhileStatementNoShortIf |
ForStatementNoShortIf .
Programmieren in Java
02.Apr.98
114/120
Java 1.0.2 EBNF Grammatik
StatementWithoutTrailingSubstatement =
Block |
EmptyStatement |
ExpressionStatement |
SwitchStatement |
DoStatement |
BreakStatement |
ContinueStatement |
ReturnStatement |
SynchronizedStatement |
ThrowStatement |
TryStatement .
EmptyStatement =
;
LabeledStatement =
Identifier : Statement .
LabeledStatementNoShortIf =
Identifier : StatementNoShortIf .
ExpressionStatement =
StatementExpression ; .
StatementExpression =
Assignment |
PreIncrementExpression |
PreDecrementExpression |
PostIncrementExpression |
PostDecrementExpression |
MethodInvocation |
ClassInstanceCreationExpression .
IfThenStatement =
if ( Expression ) Statement .
IfThenElseStatement =
if ( Expression ) StatementNoShortIf
else Statement .
IfThenElseStatementNoShortIf =
if ( Expression ) StatementNoShortIf
else StatementNoShortIf .
SwitchStatement =
switch ( Expression ) SwitchBlock .
Programmieren in Java
02.Apr.98
115/120
Java 1.0.2 EBNF Grammatik
SwitchBlock =
{ [ SwitchBlockStatementGroups ] [ SwitchLabels ] } .
SwitchBlockStatementGroups =
SwitchBlockStatementGroup |
SwitchBlockStatementGroups SwitchBlockStatementGroup .
SwitchBlockStatementGroup =
SwitchLabels BlockStatements .
SwitchLabels =
SwitchLabel |
SwitchLabels SwitchLabel .
SwitchLabel =
case ConstantExpression : |
default : .
WhileStatement =
while ( Expression ) Statement .
WhileStatementNoShortIf =
while ( Expression ) StatementNoShortIf .
DoStatement =
do Statement while ( Expression ) ; .
ForStatement =
for ( [ ForInit ] ; [ Expression ] ; [ ForUpdate ] )
Statement .
ForStatementNoShortIf =
for ( [ ForInit ] ; [ Expression ] ; [ ForUpdate ] )
StatementNoShortIf .
ForInit =
StatementExpressionList |
LocalVariableDeclaration .
ForUpdate =
StatementExpressionList .
StatementExpressionList =
StatementExpression |
StatementExpressionList , StatementExpression .
Programmieren in Java
02.Apr.98
116/120
Java 1.0.2 EBNF Grammatik
BreakStatement =
break [ Identifier ] ; .
ContinueStatement =
continue [ Identifier ] ; .
ReturnStatement =
return [ Expression ] ; .
ThrowStatement =
throw Expression ; .
SynchronizedStatement =
synchronized ( Expression ) Block .
TryStatement =
try Block Catches |
try [ Block Catches ] Finally .
Catches =
CatchClause |
Catches CatchClause .
CatchClause =
catch ( FormalParameter ) Block .
Finally =
finally Block .
14.15
Ausdrücke
Primary =
PrimaryNoNewArray |
ArrayCreationExpression .
PrimaryNoNewArray =
Literal |
this |
( Expression ) |
ClassInstanceCreationExpression |
FieldAccess |
MethodInvocation |
ArrayAccess .
ClassInstanceCreationExpression =
new ClassType ( [ ArgumentList ] ) .
Programmieren in Java
02.Apr.98
117/120
Java 1.0.2 EBNF Grammatik
ArgumentList =
Expression |
ArgumentList , Expression .
ArrayCreationExpression =
new PrimitiveType DimExprs [ Dims ] |
new ClassOrInterfaceType DimExprs [ Dims ] .
DimExprs =
DimExpr |
DimExprs DimExpr .
DimExpr =
[ Expression ] .
Dims =
[] |
Dims [] .
FieldAccess =
Primary . Identifier |
super . Identifier .
MethodInvocation =
Name ( [ ArgumentList ] ) |
Primary . Identifier ( [ ArgumentList ] ) |
super . Identifier ( [ ArgumentList ] ) .
ArrayAccess =
Name [ Expression ] |
PrimaryNoNewArray [ Expression ] .
PostfixExpression =
Primary |
Name |
PostIncrementExpression |
PostDecrementExpression .
PostIncrementExpression =
PostfixExpression ++ .
PostDecrementExpression =
PostfixExpression -- .
UnaryExpression =
PreIncrementExpression |
PreDecrementExpression |
Programmieren in Java
02.Apr.98
118/120
Java 1.0.2 EBNF Grammatik
+ UnaryExpression |
- UnaryExpression |
UnaryExpressionNotPlusMinus .
PreIncrementExpression =
++ UnaryExpression .
PreDecrementExpression =
-- UnaryExpression .
UnaryExpressionNotPlusMinus =
PostfixExpression |
~ UnaryExpression |
! UnaryExpression |
CastExpression .
CastExpression =
( PrimitiveType [ Dims ] ) UnaryExpression |
( Expression ) UnaryExpressionNotPlusMinus |
( Name Dims ) UnaryExpressionNotPlusMinus .
MultiplicativeExpression =
UnaryExpression |
MultiplicativeExpression * UnaryExpression |
MultiplicativeExpression / UnaryExpression |
MultiplicativeExpression % UnaryExpression .
AdditiveExpression =
MultiplicativeExpression |
AdditiveExpression + MultiplicativeExpression |
AdditiveExpression - MultiplicativeExpression .
ShiftExpression =
AdditiveExpression |
ShiftExpression << AdditiveExpression |
ShiftExpression >> AdditiveExpression |
ShiftExpression >>> AdditiveExpression .
RelationalExpression =
ShiftExpression |
RelationalExpression < ShiftExpression |
RelationalExpression > ShiftExpression |
RelationalExpression <= ShiftExpression |
RelationalExpression >= ShiftExpression |
RelationalExpression instanceof ReferenceType .
Programmieren in Java
02.Apr.98
119/120
Java 1.0.2 EBNF Grammatik
EqualityExpression =
RelationalExpression |
EqualityExpression == RelationalExpression |
EqualityExpression != RelationalExpression .
AndExpression =
EqualityExpression |
AndExpression & EqualityExpression .
ExclusiveOrExpression =
AndExpression |
ExclusiveOrExpression ^ AndExpression .
InclusiveOrExpression =
ExclusiveOrExpression |
InclusiveOrExpression | ExclusiveOrExpression .
ConditionalAndExpression =
InclusiveOrExpression |
ConditionalAndExpression && InclusiveOrExpression .
ConditionalOrExpression =
ConditionalAndExpression |
ConditionalOrExpression || ConditionalAndExpression .
ConditionalExpression =
ConditionalOrExpression |
ConditionalOrExpression ? Expression : ConditionalExpression .
AssignmentExpression =
ConditionalExpression |
Assignment .
Assignment =
LeftHandSide AssignmentOperator AssignmentExpression .
LeftHandSide =
Name | FieldAccess | ArrayAccess .
AssignmentOperator =
= | *= | /= | %= | += | -= | <<= | >>= | >>>= | &= | ^= | |= .
Expression =
AssignmentExpression .
ConstantExpression =
Expression .
Programmieren in Java
02.Apr.98
120/120
Herunterladen