Praktische Informatik 2, Sommersemester 2002 - Goethe

Werbung
Unterlagen: Praktische Informatik 2,
Sommersemester 2002
Prof. Dr. Manfred Schmidt-Schauß
Fachbereich Informatik
Johann Wolfgang Goethe-Universität
Postfach 11 19 32
D-60054 Frankfurt
E-mail:[email protected]
URL: http://www.ki.informatik.uni-frankfurt.de/
Tel: 069 / 798 28597 o. 28213
Fax: 069/ 798 28919
25. April 2002
Kapitel 1
WWW, OO und Java
1.1
Internet + WWW
Das Internet ist ein weltweiter Verbund von elektronischen Geräten
(Computer,
Router,
Gateways,
Drucker,. . . )
(Knoten),
die
mit
Standleitungen,Telefonleitungen, Funkverbindungen, . . . verbunden sind
und über Internetprotokolle kommunizieren.
Der Datenaustausch ist paketvermittelt: Daten werden in Pakete zerlegt, mit
Absender und Empfängeradresse versehen, dann von Sender zum Empfänger
übertragen und beim Empfänger wieder zusammengesetzt.
Sogenannte Intranets sind lokale Netzwerke (auch globale firmeninterne),
die (logisch) getrennt vom Internet arbeiten, aber evtl die gleichen Methoden
verwenden.
Etwas Geschichte:
• ca. 1970: Ursprünge des Netzes sind Projekte des amerikanischen
Verteidigungsministeriums zur Vernetzung von Rechnern und
Ausfallsicherheit.
• 1983: ARPANet, danach verschiedene andere Netze (NSFNET).
TCP / IP wird als Standard verwendet. Starke Nutzung
Forschungseinrichtungen und Universitäten (E-Mail)
in
• 1988 Internet Wurm.
• 1991 / 1993 Mosaic, Gopher, WWW. Die Anfänge gehen wesentlich auf
Konzepte zurück, die am CERN (Conseil Europèen pour la Recherche
Nuclèaire) entwickelt wurden.
• 1996: 3 Millionen europäische Knoten
• 2002: ca. 90 Millionen Knoten.
1
Praktische Informatik 2, SS 2002, Kapitel 1
2
Die Knotenadressen (IP-Adressen) sind von der Form n.n.n.n, wobei n eine
Zahl zwischen 1 und 255 sein kann. Z.B. ist 141.2.10.1 die Adresse des Rechners
der KI. Es sind nicht alle kombinatorisch möglichen Adressen zulässig. Manche
haben feste Bedeutung: 127.0.0.1. (localhost, bzw. loopback.device), ist
immer ein Rückverweis auf den eigenen Rechner. Die IP-Adresse setzt sich
aus Netzwerk-Adresse und Rechneradresse zusammen. Es gibt drei Arten von
Netzwerken, die sich nur durch die Größe des Netzwerks und der Adresse
unterscheiden. 1) Netzwerkadresse ist ein Byte, aber nur zwischen 1 und 126.
Die Rechner haben dann drei Byte zur Adressierung. 2) Netzwerkadresse sind
zwei Byte, das erste Byte ist zwischen 128 und 191. 3. kleine Netzwerke, deren
Adresse aus drei Bytes zusammengesetzt ist.
Die Adressen 192.168.n.n werden als lokale IP-Nummern verwendet. Zum
Teil werden diese Nummern dynamisch vergeben, um den knappen Raum der
IP-Adressen besser zu nutzen. Es gibt Vereinbarungen, diesen Adressraum in
Zukunft zu erweitern.
Domain Name System (DNS)
Rechner (Knoten) haben i.a. eine textuelle Adresse “hera.informatik.unifrankfurt.de“, die von verschiedenen zentralen Rechnern (Namens-Server) in
eine Knotenadresse umgesetzt werden können. Als Standard wird das letzte
Kürzel dem Land bzw. einem anderen Bereich zugeordnet.
ISO Ländercodes: Z.B.
de = Deutschland,
fr
= Frankreich,
at = Österreich,
au = Australien ,
jp = Japan
Andere Kürzel, die ursprünglich nur Knoten in den USA bezeichneten:
com (commercial) Industrie, Firmen, usw.
org
nicht kommerzielle Organisationen (DV-bezogen)
net
(Netz bezogen)
edu (Universitäten, Schulen, ... )
mil
(Militär, USA)
gov (Regierung, USA)
eu
(Europa)
...
Weitere
Die wesentlichen Aktivitäten (bzw. Dienste) des Internets sind:
• Email elektronische Post (E-mail, verschiedene Protokolle).
Versenden und Empfangen von elektronischen Texten/Nachrichten/
Information. Einseitig, asynchron.
I.a. wird das Protokoll SMTP (simple mail transport protocol) verwendet.
Dies funktioniert analog zum Prinzip der Briefpost: Briefe (mit Absender
und Empfänger-Adresse und Daten) werden von einer Poststelle zum
Praktische Informatik 2, SS 2002, Kapitel 1
3
Verteiler gesendet, evtl. zwischengelagert, und landen im Briefkasten des
Empfängers. Dieses Protokoll kann i.a. nur 7-Bit ASCII-Texte behandeln,
d.h. das 8te Bit wird ignoriert, bzw. abgeschnitten. Um damit Binärdaten
zu versenden. müssen diese erst umkodiert werden (Z.B. uuencode,
uudecode). Ein anderes Protokoll zum Versenden von Daten ist MIME
(Multipurpose Internet Mail Extension), das mehr Dateitypen kennt und
deren Kodierung und Dekodierung übernimmt (Typen sind: text,message,
application,image, audio, video; es gibt noch Untertypen).
Ein Problem ist unerwünschte Post (Reklame, sogenannte spam). Die
könnte im Extrem das ganze System zusammenbrechen lassen. Szenario:
alle Firmen senden mit einem Klick ihre Reklame an viele (alle)
Mailadressen. Heute gibt es viele Filter und Vermeidungsstrategien,
die unerwünschte und/oder kommerzielle Reklamepost weitgehend
ausschalten.
• nntp News
Elektronisches Analog zu schwarzen Brettern. Alle können es lesen, wenn
sie zum schwarzen Brett gehen und davor stehen. Man kann auch selbst
einen Zettel festmachen. Nach einer gewissen Zeit werden alte Nachrichten
entfernt. Es gibt viele sogenannte Newsgruppen zu den verschiedensten
Themen. Zu unmoderierten Newsgruppen kann jeder unkontrolliert etwas
beitragen. Moderierte Newsgruppen zensieren die Zettel (Nachrichten)
vorher.
• ssh secure shell
Hier wird die Kommunikation verschlüsselt durchgeführt. Insbesondere
werden die Passwörter nicht unverschlüsselt übertragen. Allerdings ist bei
der ersten Kontaktaufnahme die Vereinbarung eines Schlüssels notwendig,
was ein Schwachpunkt sein kann. Dies ist im Gegensatz zu telnet, das alles
unverschlüsselt überträgt.
• File-Transfer (ftp = file transfer protocol)
Zum direkten Versenden “upload“ (put) und Holen “download“ (get) von
Daten/Dateien/Files vom eigenen Rechner zum entfernten Rechner. Die
Verbindung ist synchron. Meist wird dies genutzt unter Verwendung der
Kennung anonymous, die nur eingeschränkte Berechtigungen hat.
• Einwählen in andere Rechner (Telnet, remote login)
Dabei dient der eigene Rechner als Bildschirm, die Ausführung der
Programme geschieht auf dem entfernten Rechner. Damit kann man z.B.
seine elektronische Post auf dem Fachbereichsrechner von den USA her
lesen: Zunächst mit telnet in Frankfurt sich anmelden, dann die Post lesen.
• WWW (World Wide Web), (http = hyper text transport protocol)
Es gibt eine Organisation als Verbund von Firmen/ Forschungsinstituten,
die sich um Normierungen von Werkzeugen und Sprachen im Internet
kümmert (siehe www. w3c.org).
Praktische Informatik 2, SS 2002, Kapitel 1
4
WWW ist ein virtuelles Netzwerk innerhalb des physikalischen Internets.
Dies ist mittlerweile sehr populär geworden. Die Arbeitsweise kann man
sich folgendermaßen vorstellen: Jeder Teilnehmer stellt auf seinem Rechner
(bzw. seinem ihm zugeordneten Knoten) gewisse Daten (i.a. HTML
(hyper text markup language)-Dokumente) zur Verfügung, die andere
sich von außerhalb anschauen dürfen. Diese Daten sind i.a. als Einheiten
strukturiert, die über Adressen ( Links) verbunden sind und eine eigene
weltweit eindeutige Adresse haben (URL). Der Benutzer (die Surferin)
holt sich die Daten, wobei i.a. ein sogenannter Browser (z.B. NetScape
Communicator, Internet Explorer) verwendet wird, der die Daten in Form
von Seiten (graphisch gestaltet) anzeigt. Diese Seiten sind i.a. in HTML
geschrieben mit evtl. eingebetteten weiteren Aufrufen. Eine Erweiterung,
die aktuell diskutiert wird, ist XML. Um die graphische Gestaltung
sehr flexibel zu gestalten, wurde Java (von Sun) entwickelt. Java ist
eine Programmiersprache, bei deren Design die Prioritäten entsprechend
gesetzt wurden: Portabilität, Sicherheit, Objektorientiert, in HTML leicht
verwendbar. ( Wir werden Java noch behandeln. )
Jede Seite (Datenpaket) hat eine eindeutige Adresse und wird unter
Angabe dieser Adresse geladen. Man kann das WWW als großes
und offenes Hypertextsystem ansehen: Als System von vernetzten
Dokumenten.
Das Auffinden von Information bzw. Adressen mit interessanten Inhalten
kann per “Mund-zu-Mund“ Propaganda geschehen, oder man sammelt
solche Adressen. Suchmaschinen (google, yahoo, ...), die allen zugänglich
sind, versuchen Adressen zu filtern und bereit zu stellen, die bestimmte
Suchkriterien erfüllen.
Man kann sich fragen, woher die Popularität des WWW kommt. Dazu
beigetragen hat:
– Einfache Bedienbarkeit, Robustheit gegenüber Fehlern.
– Analogie zu bekannten Medien wie Zeitungen, gelbe Seiten,
– Kostenfreie Dienste
Im Internet/WWW gibt es noch viele ungeklärte (juristische, finanzielle,
soziale,...) Probleme: kriminelle Aktivitäten (Kinderpornographie),
politisch extreme Agitation, Copyright-Probleme, Datenschutzaspekte,
nicht
einheitliche
Gesetzgebung
in
verschiedenen
Ländern,
Verschlüsselung, ...)
Weitere aktuelle Fragen: Wann werden Gebühren für welchen Dienst
erhoben?, Reklame auf WWW-Seiten?, Besteuerung von WWWDienstleistungen?; Wer ist verantwortlich für die Inhalte?
• (ntp: network time protocol) Zeitsynchronisation:
Hiermit kann ein Rechner über Netz einen Zeit-Server befragen, wieviel
Uhr es jetzt ist. Da man Laufzeiten (Netz, Funk, Programm) zu
Praktische Informatik 2, SS 2002, Kapitel 1
5
berücksichtigen hat, ist es nicht ganz einfach, hieraus mit genügender
Genauigkeit die aktuelle Zeit zu errechnen.
• Telekonferenzen; direkte Übertragung von Video-, Audio Daten (Telefon)
Dies war ursprünglich ein (fast) synchroner Austausch von Text:
eine schriftliche Unterhaltung war möglich. Es gibt auch Software,
die Telefonieren (Audiodaten) in Realzeit überträgt, sofern man die
Übertragungskapazität hat (quality of service).
• Bestellen, Bezahlen, finanzielle Transaktionen, Kreditkartenbezahlung
Auch dies wird z.T. über Netzdienste abgewickelt.
6
Praktische Informatik 2, SS 2002, Kapitel 1
1.2
1.2.1
Objektorientierte
Beispiel von Java
Programmierung
am
Was hat Java mit dem WWW zu tun?
Java ist explizit dafür entworfen worden, um Anwendungen im WWW
zu implementieren. Unterstützt wird: die Verwendung graphischer
Benutzeroberflächen, WWW-Netzzugriffe; Verwendung in einem Browser;
beweglicher Code: Applets, Portabilität.
Wenn man nur statische Dokumente hat, dann kann ein Browser auch nur die
statischen Hypertextdokumente sichtbar machen. Ein solches Dokument kann
über viele Ordner und auch Rechner verteilt sein. Man kann mit diesen Mitteln
auch blinkende Felder u.ä. einem Betrachter bieten.
Clients
Server
Internet
Eine Entlastung des Servers mittels Verlagerung von Berechnung auf den
Client und eine Erhöhung der Flexibilität erhält man erst, wenn die betrachtete
Seite auf dem Rechner des Betrachters (clients) die (fast) vollen Möglichkeiten
einer Programmiersprache hat. Dies wird bei Java-Applets erreicht, indem die
vom Server bereitgestellte Seite den Byte-Code eines Applets enthält, der vom
Browser auf den lokalen Rechner geladen wird, und dort interpretiert wird. Dazu
muss der Browser nur den entsprechenden Interpreter bereitstellen. Die Vorteile
dieses Verfahrens sind: der Server muss nichts über die Art (Betriebssystem,
Browser, usw.) des Clients wissen; geringe Belastung des Servers und des Netzes
durch die Bytecode-Übertragung.
Die Sicherheitsprobleme sind nicht zu vernachlässigen, da dies analog zur
Praktische Informatik 2, SS 2002, Kapitel 1
7
Ausführung eines unbekannten, von irgendwoher geladenen Programms ist. Dies
wird abgeblockt durch eingeschränkte Rechte eines Applets (kein Dateizugriff
usw.), und durch eine Validierung des Bytecodes vor der Ausführung.
Hier hat Microsoft einen eigenen Sicherheitsansatz entwickelt, der signierte
Programme vorsieht
Mit Java kann man auch eigenständige Anwendungen programmieren. Java
ist auch kompilierbar, allerdings ist die Programmierung von Applets die
wesentlichste Verwendung.
Eine andere Variante HTML-Seiten flexibler zu gestalten, ist die Verwendung
von z.B. Javascript. Bei dieser Technik wird ebenfalls nur ein Interpreter auf der
Clientseite benötigt, der die entsprechenden Programme interpretiert. Allerdings
wird hierbei das ganze Programm über das Internet von Server zum Client
transportiert.
Dialoganwendung Eine weitergehende Problematik ist die Erweiterung
einer Web-Seite zu einer Dialog-Anwendung, die Daten bzw. Anfragen zwischen
Server und Client austauscht. Hierzu kann man das sogenannte CGIs verwenden
(common gateway interface). Z.B. war die Praktikumsanmeldung über das
WWW mittels CGI und eines dahintersteckenden Haskell-Programms realisiert.
Die Datenübertragung wird hier meist durch eine spezielle Codierung in der
zurückgesendeten URL durchgeführt. Die Programmiersprache, die auf dem
Server dahintersteckt, ist nicht festgelegt. Von Java wird diese Form der
Anwendungen unterstützt durch die Programmiermöglichkeit von Servlets.
1.2.2
Versionen und Kompatibilität mit Browsern
In der Entwicklung von Java sind bisher die Hauptversionen Java 1.0 (1995),
Java 1.1 (1997) und Java 2 (1999) erschienen. Dazu wurden von Sun
Microsystems auch die entsprechenden Entwicklungsumgebungen veröffentlicht.
Bis einschließlich Version 1.1 trugen diesen den Namen JDK1 . Ab JDKVersion 1.2 fand ein Namenswechsel statt, die Versionen heißen Java 2 und
die entsprechenden Entwicklungsumgebungen Java SDK2 . Die aktuelle Version
ist Java 2 SDK 1.4 (2002).
Die Wahl der Version, mit der man arbeitet, hängt vom Anwendungsfall ab.
Version 1.0 wird von jedem Java-fähigen Browser unterstützt. Ab JDK 1.02 ist
das Ereignismodell 1.02 integriert, wobei in diesem Modell sämtliche Ereignisse,
die während des Programmablaufs stattfinden, durch das Programm fließen und
von einer Methode namens handleEvent() behandelt werden.
Mit JDK 1.1 wurde das Ereignismodell grundlegend geändert. Das
Ereignismodell 1.1 verwendet das Konzept der Event-Listener. Die
verschiedenen Listener sind verantwortlich für die Behandlung einer bestimmten
Art von Ereignissen (z.B. Mouse-Listener für Mausereignisse, Key-Listener
für Tastaturereignisse, etc.). Durch das Programm werden nur jene Ereignisse
geleitet, für die vorher im Quelltext Listener vorgesehen wurden. So lässt sich
1 Java
Development Kit
Development Kit
2 Software
Praktische Informatik 2, SS 2002, Kapitel 1
8
der Verarbeitungsvorgang effizienter gestalten, da nicht mehr alle Ereignisse
geprüft werden, die stattfinden.
Applets, die mit JDK 1.1 erstellt sind, können mit moderneren WWWBrowsern (MS IE 4.0 bis 5.x, Netscape ab 4.07) ausgeführt werden.
Mit Version 1.2 (bzw. Java 2) wurden die JFC3 -Bibliotheken ins SDK
integriert, die insbesondere das Swing-Paket enthalten, das die Möglichkeiten
der Programmierung von graphischen Benutzeroberflächen erweitert. Außerdem
wurde die Arbeitsumgebung mit Java 2 durch sogenannte Just-in-TimeCompiler verbessert, die die Übersetzung von Java-Programmen erheblich
beschleunigen.
Die meisten WWW-Browser unterstützen Java 2 nicht mehr durch eine
integrierte VM, allerdings können die Applets durch Installation eines Browser
Plug-Ins (z.B. von Sun das JRE4 ) ausgeführt werden (Netscape 4.7 unterstützt
Java 1.4 mit JRE-Plug-In, Netscape 6 unterstützt Java 1.3.0 mit integriertem
Plug-In, MS IE 5.5 unterstützt Java 1.1.5 integriert, und Java 1.4 mit JREPlug-In, MS IE 6 hat keine integrierte VM und Plug-In und benötigt deswegen
die Installation eines Plug-Ins zum Ausführen von Java-Programmen, z.B. JRE
1.4).
1.2.3
Objektorientierte Programmierung
am Beispiel Java
Im folgenden werden die Beispiele konform zur Syntax der objektorientierten
Programmiersprache Java (von Sun) notiert, die selbst eine an C++ angelehnte
Syntax hat. Allerdings erfährt Java wie jede Programmiersprache Änderungen
und Erweiterungen, so dass man für genauere Informationen das entsprechende
Handbuch konsultieren sollte. Mittlerweile gibt es Java 2, das teilweise in diesem
Skript verwendet wird.
Die zentrale Idee der Objektorientierten Programmiersprachen (OOP) ist
die des Objekts als Strukturierungskonzept.
Objekte sind zusammengesetzte (Daten-)Einheiten, die auch als
Einheit ansprechbar sind. Die Objekte kommunizieren miteinander durch
Senden/Empfangen von Nachrichten. Veränderungen von Objekten werden
stets mittels der sogenannten Methoden durchgeführt.
Jedes Objekte gehört zu einer Klasse. Klassen werden in der OOProgrammiersprache definiert. Klassen enthalten die Definition der Struktur
der zugehörigen Objekte und auch die Definition der Methoden, die auf Objekte
dieser Klasse anwendbar sind.
Klassen kann man in einer (Baum-) Hierarchie anordnen. Diese
Klassenhierarchie wird i.a. verwendet, um allgemeine Aspekte von Objekten
in einer Oberklasse zu definieren, und dann in Unterklassen die spezielleren
Eigenschaften zu definieren bzw. implementieren.
3 JavaFoundationClasses
4 JavaRuntimeEnviroment
Praktische Informatik 2, SS 2002, Kapitel 1
9
Wenn wir mit Haskell vergleichen: Eine Klasse entspricht in etwa einem Typ
bzw. einer Typklasse, ein Objekt entspricht einem konstruierten Datenobjekt.
Das Senden von Nachrichten entspricht einem Funktionsaufruf. Allerdings gibt
es in OO-Sprachen, auch in Java, Seiteneffekte, (im Gegensatz zu Haskell),
z.B. kann ein Objekt verändert werden, auch wenn verschiedene Verweise darauf
existieren (sogenanntes Aliasing).
In Java sind elementare Datentypen wie Zahlen keine Objekte, allerdings gibt
es OOP, in denen auch elementare Datentypen als Objekte behandelt werden.
In Java kann man die elementaren Datentypen durch Einpacken ebenfalls zu
Objekten machen, falls dies notwendig ist.
1.2.4
Objekte
Ein Objekt besteht aus Daten und Methoden. Von außen ist das Innere (die
Daten und Methoden) eines Objektes nicht direkt sichtbar. Nur über erlaubte
Zugriffe und Schnittstellen ist das Innere des Objektes (seine Attribute) sichtbar
und änderbar.
Jedes Objekt gehört zu einer Klasse: man sagt auch: ist (direkte) Instanz einer
Klasse.
Betrachtet man nur die Daten, ist ein Objekt analog zu einem Record, bei
dem die einzelnen Attribute mit Attributnamen ansprechbar sind. Eine analoge
Struktur ist ein Satz (Verbund) in einer Datenbank, bestehend aus Attributen.
In Haskell wäre es ein n-Tupel, bestehend aus verschiedenen Daten, wobei
auch durch geeignete Definition eines Typs die Komponenten wie Attribute
angesprochen werden können.
Beispiel 1.2.1 Ein Auto kann man als Klasse Auto modellieren mit den
mögliche Attributen: Marke, Farbe, Kennzeichen, Besitzer, Baujahr, Leistung
in kW, Höchstgeschwindigkeit, Treibstoffverbrauch, km-Stand.
Methoden:
• Erzeuge neues Objekt vom Typ Auto mit den folgenden Attributwerten:
...
• Ändere den Besitzer
• Ändere das Kennzeichen
• Ermittle das Alter des Autos
• ...
1.2.5
Nachrichten; Methodenaufruf
Die Anwendung von Methoden auf Objekte wird durch den Mechanismus des
Sendens von Nachrichten durchgeführt.
Verwendet wird i.a. die sogenannte Dot-Notation.
Syntaktisch: obj.meth(para1, para2,...).
10
Praktische Informatik 2, SS 2002, Kapitel 1
Hier wird dem Objekt obj die Nachricht meth gesendet, mit den Parametern
para1, para2,...).
Dies ist analog zur Anwendung einer Funktion f meth auf ein Argument,
wobei das erste Argument der Funktion stets das Objekt ist, dem die
Nachricht gesendet wird, und die weiteren Argumente den Parametern para1,
para2,...) entsprechen.
D.h. als Funktionsanwendung sieht obiger Beispielaufruf so aus:
f meth(obj,para1,para2,...).
Das Abfragen von Attributen wird ebenfalls durch Senden einer Nachricht
durchgeführt, wobei der Attributname verwendet wird; der Wert des Attributes
wird als Wert der Anwendung zurückgegeben. D.h. eine Methode kann einen
Seiteneffekt bewirken, und auch einen Wert (per return) zurückgegeben. Der
Seiteneffekt kann darin bestehen, in dem angesprochenen Objekt, oder eventuell
in anderen Objekten die Werte von Attributen zu verändern.
Beispiel 1.2.2 Gegeben sei ein Rechteck durch die Koordinaten eines
Eckpunktes und der Höhe und Breite. Wir nehmen an, dass es auf dem
Bildschirm dargestellt wird, und die Koordinatenangaben in Pixeln erfolgt. Das
Bewegen auf dem Bildschirm könnte man durchführen mittels folgender Sequenz
von Anweisungen, die in einer Methode als Programmcode stehen könnte:
if (obj.left < 20)
{ obj.erase();
obj.move(20,0);
obj.paint();
}
//
//
//
Loeschen des Bildes
Verschieben des Rechtecks (der Koordinaten)
Zeichnen
Die Nachrichten sind jeweils left, erase(), move(20,0), paint().
1.2.6
Klassen
Klassen fassen gleichartige Objekte zusammen, wobei die Gleichartigkeit sich
auch daraus ergibt, ob diese von der Implementierung gleich behandelt werden
sollen. Klassen verhalten sich zu Objekten wie der Begriff (die Klasse) “Auto“
zu einem konkreten Auto mit dem KZ “B-SE-1“. Das konkrete Auto ist dann
eine “Instanz“ (Ausprägung, Element) der Klasse.
In OOP besteht das Programmieren aus dem Definieren von Klassen, d.h.
Attribute, Methoden, Hierarchie. Die Methodenprogrammierung entspricht der
“normalen“ Programmierung.
Klassen können hierarchisch angeordnet werden. D.h. es gibt Oberklassen
und Unterklassen. Die hierarchische Anordnung soll dazu dienen, in der
Oberklasse die gemeinsamen Methoden und Attribute zu definieren, die für alle
Unterklassen gelten. (Statt Unterklassen sagt man auch abgeleitete Klasse).
Beispiel 1.2.3 Die Klasse Fahrzeug kann man als Oberklasse von Auto
definieren mit den Attributen Hoechstgeschwindigkeit, Besitzer. Als
Praktische Informatik 2, SS 2002, Kapitel 1
11
weitere Unterklassen von Fahrzeug kann man LKW, Bus, Motorrad definieren.
Bei LKW kämen als Attribute hinzu: zul. Gesamtgewicht, Art der Güter, ...
Bei einem Bus: maximale Anzahl Passagiere, Ausstattung, ...
Fahrzeug
KKSSS
rr
KK SSSS
r
r
KK SSS
r
r
KK
SSS
r
r
K%
SSS
yrr
) ...
Auto
LKW
Bus
class Fahrzeug {
public double Hoechstgeschwindigkeit;
private String Eigentuemer;
private static long Anzahl;
.......
}
class Auto extends Fahrzeug {
public String Autokennzeichen;
......
}
class Boot extends Fahrzeug {
public double Tiefgang;
........
}
Beispiel 1.2.4 Rechteck mit oberer Eck-Koordinate, Breite und Höhe:
class Rechteck {
int x,y,b,h;
// x,y Koordinaten, b,h, Breite und Hoehe
void paint (Graphics g) {
//Methode zum Zeichnen
g.drawRect (x, y, b, h); // Aufruf einer Bibliotheksfunktion drawRect
}
}
1.2.7
Methoden
In einer Klasse werden sowohl die Attribute als auch die darauf möglichen
Operationen definiert. Diese Operationen nennt man Methoden. Deren
Definition ist innerhalb einer Klassendefinition.
Beispiel 1.2.5
class Rechteck {
Praktische Informatik 2, SS 2002, Kapitel 1
12
int x,y,b,h;
//x,y Koordinaten, b,h, Breite und Hoehe
void paint (Graphics g) { // Methode zum Zeichnen
g.drawRect (x, y, b, h); // Aufruf einer Bibliotheksfunktion drawRect
}
void move (int xd; int yd) {
this.x = x + xd;
this.y = y + yd;
}
}
Die Methode move verändert die Eck-Koordinate des Rechtecks um die
Differenz xd,yd.
Wenn einem Rechteck r die Nachricht move gesendet wird in der Form
r.move(20,0), dann wird die Anfangskoordinate des Rechtecks entsprechend
der Argumente verändert.
Die Verwendung von this bezieht sich immer auf das Objekt, an das die
Nachricht gesendet wird. In anderen OOP-Sprachen wird dies z.T. auch als
self bezeichnet.
Sucht man die Analogie in Haskell, so würde man r.move(20,0) etwa als
move r 20 0 schreiben. Das Schlüsselwort this entspricht dann der Variablen
x in einer Definition von move x y z = ....
Beachte, dass die Argumente der Nachrichten nicht nur elementare
Datentypen sind, sondern auch Objekte sein können.
Typen bzw. Klassenangaben müssen in Java für alle Methoden, deren
Argumente und deren Ergebnis gemacht werden. void steht für den Ergebnistyp
einer Methode, die keinen Rückgabewert hat.
void move (int xd; int yd)
bedeutet, dass move keinen Ergebnistyp hat, nur einen Seiteneffekt bewirkt, und
dass die Argumenttypen int sein müssen.
1.2.8
Klassen und Vererbung
Klassen werden, wenn möglich und von der Implementierung her sinnvoll,
hierarchisch strukturiert. D.h. man versucht diese so zu strukturieren, dass man
zunächst eine möglichst allgemeine Klasse definiert, z.B. geometrischesObjekt:
abstract class geometrischesObjekt {
String Name;
geometrischesObjekt (String Name) {this.Name = Name;}
void paint (Graphics g);
}
Die Klasse Rechteck, Gerade, Kreis, Dreieck, usw kann man dann als
Unterklassen definieren, die mehr Methoden und mehr Eigenschaften haben,
also spezieller sind:
13
Praktische Informatik 2, SS 2002, Kapitel 1
class Rechteck extends geometrischesObjekt {
int x,y,b,h;
// x,y Koordinaten, b,h,
void paint (Graphics g) {
g.drawRect (x, y, b, h);
}
void move (int xd; int yd) {
this.x = x + xd;
this.y = y + yd;
}
}
//
Beispielaufruf:
Breite und Hoehe
re.move(2,-3)
Eine weitere Unterklasse von Rechteck könnte ein farbiges Rechteck oder ein
mit einem Muster gefülltes Rechteck sein.
class farbigesRechteck extends Rechteck {
Color farbe;
....
}
Hierbei erben die Unterklassen die Attribute und Methoden der Oberklasse.
Es ist möglich, neue hinzuzufügen. Die Unterklasse hat dann die Vereinigung
der Attribute und Methoden der Oberklasse und der in der Klasse definierten
entsprechenden Komponenten.
Es ist auch möglich, die Methoden der Oberklasse in der Unterklasse zu
überschreiben. Allerdings nur für die Nutzung in dieser Unterklasse (und deren
Unterklassen). Dies ist notwendig, da für spezialisiertere Klassen die Methoden
ebenfalls weiter spezialisiert werden müssen. Z.B. Die Methode paint wird
bei einem Rechteck nur die Linien des Rechtecks zeichnen, bei einem farbigen
Rechteck die Linien und zusätzlich die Farbe. Es ist nicht möglich, Attribute
oder Methoden zu entfernen.
Zur Laufzeit kann man mit dem Operator instanceof feststellen, ob ein
Objekt zu einer Klasse gehört: re instanceof Rechteck;.
Oft definiert man eine Oberklasse als abstrakte Klasse mit dem
Zugriffsrecht abstract. Es ist dann nicht möglich, Objekte zu erzeugen, die
genau zu dieser Klasse gehören. Dies geht nur für “konkrete“ Unterklassen.
1.2.9
Wesentliche Eigenschaften der objektorientierten
Programmierung
Das Programm besteht aus einer Menge von Klassendefinitionen, die
aus Erklärungen von Attributen und Definitionen von Methoden (und
Schnittstellenbeschreibungen ) bestehen. Die Verwendung von Methoden
geschieht wie eine Funktionsanwendung in Attributnotation. D.h. Klassen und
Methoden sind das eigentliche Programm.
Praktische Informatik 2, SS 2002, Kapitel 1
14
Objekte gibt es nur zur Ausführungszeit des Programms. Diese werden
innerhalb eines Methodenaufrufs zur Laufzeit (mittels new) erzeugt. Das Senden
und Empfangen von Nachrichten ist ebenfalls eine Aktion zur Laufzeit.
Vererbung Klassen erben von Superklassen Methoden und Attribute. Dies
gilt damit auch für die Objekte: auf diese kann man alle Methoden einer
Superklasse anwenden. Man kann den Methoden in Unterklassen eine
andere (spezifischere) Implementierung geben.
Polymorphie Variablen müssen getypt sein (der Typ ist die Klasse), d.h.
Variablen können nur Objekte einer Klasse referenzieren. Allerdings sind
dann auch Objekte erlaubt, die zu Unterklassen gehören. Welchen Typ
das Objekt hat, kann man erst zur Laufzeit ermitteln. Hat man z.B.
eine Variable Fahrzeug fahrzeug, und Fahrzeug hat die Unterklassen
Auto, Bus, Schiff, dann kann man auf die Methode Eigentuemer
anwenden: fahrzeug.Eigentuemer. Es wäre auch möglich, dass die
Methode in der Unterklassendefinition überschrieben wird. In diesem Fall
wird die spezifischere Methode verwendet.
Damit kann man Programmteile allgemein formulieren. Falls Unterklassen
zum Programm noch hinzugefügt werden, ist es nicht notwendig, die
bereits verwendeten Methodenaufrufe zu ändern.
Dynamische Bindung (late binding) Das ist der oben beschriebene
Methodenaufruf, der jeweils die spezifischste Methode für ein Objekt
nimmt. Gleiche Operationen (gleicher Name, gleiche Anzahl von
Argumenten, gleiche Intension) die auf Objekte verschiedener Klassen
angewendet werden, können verschieden programmiert sein. An der
Stelle der Verwendung muss man keine Rücksicht auf die Klasse
nehmen. “Dynamisch“ deswegen, da man nicht immer während der
Kompilierung herausfinden kann, welche Klasse das Objekt hat, d.h.
welche implementierte Variante der Methode angewendet werden muss.
Man nennt diese Art der Auswahl der korrekten Implementierung einer
Methode nach dem Typ eines aktuellen Arguments auch single dispatching.
Es gibt Programmiersprachen (z.B. Dylan), die auch sogenanntes multiple
dispatching durchführen: Auswahl der Methode nach den Typen von
mehreren Argumenten. Dies erfordert eine mehrdimensionale Tabelle
der Zuordnung von Typen zur richtigen Methode. Java hat keine
Unterstützung des multiple dispatching.
Statische Bindung (early binding) Im Gegensatz dazu ist die statische
Bindung, die (vom Compiler) verwendet werden kann, wenn der
Methodenaufruf zur Compilierzeit eindeutig ermittelbar ist, (genauer: die
Implementierung der Methode).
Das gibt es in Java nicht:
Praktische Informatik 2, SS 2002, Kapitel 1
15
Mehrfachvererbung (von Attributen), D.h. eine Klasse kann nicht
Unterklasse von zwei anderen unabhängigen Klassen sein. Dies vereinfacht
die Kompilierung und macht die Vererbung eindeutiger. Allerdings
sind Hierarchien in Anwendungsbereichen nicht immer baumförmig,
so dass diese Beschränkung manchmal zu streng ist. Das Verbot der
multiplen Vererbung kann Kopieren von Klassen und Methoden, oder eine
etwas unnatürliche Klassenhierarchie erzwingen. In Java kann man zwar
keine Attribute, dafür aber Methodennamen über Mehrfachvererbung
weitergeben durch Verwendung von Interfaces.
generischen Klassen Dies sind Klassen, die selbst Typ-Parameter haben
können. Damit kann man z.B. Listen von Zahlen als Klasse definieren.
Diese Konstruktion wäre nur dann sinnvoll, wenn ein Typcheckalgorithmus
in der OOP analog zum Milner- Typcheck verwendet würde. In Java kann
man Listen von Objekten definieren, d.h. das sind eher heterogene Listen,
wobei die Objekte in der Liste zu einer Unterklassen einer gemeinsamen
Oberklasse gehören müssen.
Pointer und Adressrechnung .
1.2.10
Programmierhinweise
Die Erstellung eines Programms in einer OOP erfordert zunächst, die
Anwendung gedanklich so zu strukturieren, dass man die Klassenstruktur
festlegen kann. Diese Klassenstruktur sollte natürlich den Bereich der
Anwendung möglichst gut modellieren, da man nur dann erwarten kann,
dass das Programm sich robust bei Veränderungen verhält. D.h. auch bei
Erweiterungen sollte die Klassenstruktur nur wenig geändert werden müssen.
Die Methoden und Attribute, die man in einem Programm benötigt, ergeben
sich dann aus der benötigten Funktionalität.
Die Superklassen haben wenig Attribute und Methoden, die in der Hierarchie
weiter unten stehenden Klassen haben mehr Attribute und Methoden.
1.2.11
Eigenschaften von Java
Automatische Speicherverwaltung Für neu zu erzeugende Objekte wird
automatisch Speicher bereitgestellt. Objekte, auf die es keine Referenz
mehr gibt, werden automatisch (irgendwann) freigegeben (garbage
collection). Dies im Gegensatz zu z.B. C, C++, aber genauso wie in Haskell
und Python.
Typsicherheit Der Kompiler überprüft die Klassenangaben der Variablen auf
Konsistenz mit den Aufrufen
API: Application Programming Interface Das ist die Menge an bereits
vordefinierten Klassen, die Java im Compiler und in der Laufzeitumgebung
bereitstellt
(java.lang, java.util, java.awt. java.applet,....
Praktische Informatik 2, SS 2002, Kapitel 1
16
Java (SDK bzw. alt: JDK) hat eine Vielzahl von Sun mitgelieferten
Bibliotheken, die die Programmierung erleichtern, aber auch für
einige Funktionalitäten notwendig sind. Applets kann man z.B. nur
programmieren, wenn die entsprechenden Bibliotheken per import
dazugeladen werden.
Portabilität Es wird Wert darauf gelegt, dass die Ausführung der
Programme auf allen Rechner und Rechnertypen gleichartig abläuft. Die
nichtportablen Teile sind auf den jeweiligen Rechner installiert. In der
Programmiersprache selbst erfordert das, dass es keine rechnerspezifischen
Konstrukte in der Programmiersprache gibt: z.B. Adressrechnungen, oder
Systemzugriffe, die Betriebssystem-abhängig sind, o. ä. Dies erfordert auch
die Angabe eine operationalen Semantik, die unabhängig vom benutzten
Rechner ist und die es ermöglicht, die Ergebnisse eines Programms
eindeutig vorherzusagen.
Bytecode Der Kompiler erzeugt kein lauffähiges Programm, sondern einen
interpretierbaren String: den “Bytecode“. Dieser wird dann von einem
entsprechenden Interpreter ausgeführt. Dieser Bytecode ist portabel,
d.h. auf allen Maschinen ablauffähig, vorausgesetzt, der entsprechende
Interpreter (JVM, Java Virtual Machine) ist dort installiert. Der
Interpreter ist i.a. nicht portabel. Zwar entsteht durch das Interpretieren
ein Geschwindigkeitsnachteil gegenüber anderen Methoden, dies ist jedoch
kein Nachteil für die Anwendungen, für die Java entwickelt wurde, nämlich
solche mit hohem Anteil an Netzwerk-Kommunikation und graphischer
Benutzerinteraktion.
WWW Java ist u.a. konzipiert zur Programmierung von graphischen,
interaktiven Programmstücken (sogenannten Applets), die von einem
WWW-Browser auf der Client-Seite geladen und ausgeführt werden
können (der Bytecode des Applets). Man kann allerdings auch
normale Programme (applications) damit schreiben, die dann von einem
Interpreter ausgeführt werden können.
C++ - Ähnlichkeit Die Syntax von Java ist der von C++ sehr ähnlich,
auch wenn bei der Entwicklung von Java darauf geachtet wurde, solche
Eigenschaften zu vermeiden, die immer wieder Probleme verursacht
haben. So gibt es keine Operationen zum expliziten Referenzieren oder
Dereferenzieren von Objekten oder Daten: primitive Daten werden immer
dereferenziert verwendet und Objekte und Felder immer referenziert. D.h.,
die sogenannte Adressrechnung ist in Java verboten
Sicherheit Das Fehlen von Referenzen und Zeigern, die vom Programm
beliebig manipuliert werden können, sowie die Einschränkung der
Zugriffsrechte für Applets, die über das Netzwerk kommen, tragen zur
Sicherheit von Java bei.
Praktische Informatik 2, SS 2002, Kapitel 1
17
Browser; Versionen Da Applets vom Server zum Client gesendet werden
und auf dessen Rechner bzw. in dessen Browser ablauffähig sein sollen,
kommt es häufig dazu, dass Applets “zu modern“ sind, und auf dem alten
Browser nicht lauffähig sind. In diesem Falle kommt es i.a. nicht zu Fehlern,
sondern es passiert einfach nichts, d.h. man sieht kein Applet. Hier gibt es
teilweise unterschiedliches Verhalten in Microsofts Internet Explorer und
dem Netscape Communicator.
1.3
Programmierung in Java
Primitive Datentypen
Die primitiven Datentypen von Java sind:
boolean entweder true oder false
byte
Zahlen von −128 bis 127 (8 Bit)
char
16-Bit (2 Byte) Unicode-Zeichen
short
Zahlen von −32768 bis 32767 (16 Bit)
int
Zahlen von −231 bis 231 − 1 (32 Bit)
long
Zahlen von −263 bis 263 − 1 (64 Bit)
float
Fließkommazahlen
double
Fließkommazahlen mit doppelter Genauigkeit
Die Klasse String ist nicht elementar, sondern eine vordefinierte Klasse.
Es gibt verschiedene Methoden für Strings:
+
zum
Zusammenhängen
(append),
length(),
charAt(int),
substring(anfangsindex, endindex), equals(String other). Die equalsMethode sollte man zum Testen der Gleichheit von Strings verwenden.
Umlaute und Sonderzeichen und ihre Unicode-Darstellung:
ä \u00E4
ö \u00F6
ü \u00FC
ß \u00DF
Ä \u00C4
Ö \u00D6
Ü \u00DC
18
Praktische Informatik 2, SS 2002, Kapitel 1
1.3.1
Operatoren
∗, /, +, −
%
++
-<, <=, >, >=, ==, ! =
!
&, |
&&, ||
^
+=
op=
arithmetische Infix Ops (z.T. auch für andere Typen)
modulo-Rechnung 7%3 ergibt 1
addiere 1 , i++ (erst verwende i; addiere 1)
++i (addiere 1; verwende i )
subtrahiere 1 i-- (verwende i; subtrahiere 1)
--i (subtrahiere 1; verwende i )
arithmetische Infix Vergleiche
Negation
striktes und, oder für Boolesch
(werden auch für bitweise Operation verwendet)
lazy und, oder
exklusives oder
x += y entspricht x = x + y
(Allgemein:)
Abkürzung: x op= a entspricht x = x op a
Es gibt noch weitere Operationen, die analog zu Registeroperationen sind:
bitweises und, oder, Negation, Shift, ...
1.3.2
Ausdrücke
Ausdrücke sind, analog zu Haskell, Programmstücke, die bei Ausführung
einen Wert haben. Diese können syntaktisch dort stehen, wo man auch einen
entsprechenden Wert hinschreiben kann.
Beispielsweise arithmetische Ausdrücke oder Boolesche Ausdrücke. Es ist
aber auch möglich, Funktionen (bzw. Methoden) zu verwenden. Diese Methoden
müssen dann mit einem entsprechenden Rückgabetyp definiert werden und
mittels return den Wert zurückgeben.
Der Auswahloperator: a ? b : c kann verwendet werden, um
Fallunterscheidungen bei der Rückgabe von Werten leicht zu machen.
Dies wirkt analog zum if. Der Auswahloperator erzeugt einen Ausdruck, keine
Anweisungsfolge. Der Unterschied wirkt sich so aus, dass b,c in a ? b : c
keine Anweisungen sein dürfen, sondern Ausdrücke sein müssen. (In Haskell
gibt es diesen Unterschied nicht).
1.3.3
Anweisungen
if
Syntax:
if (h Ausdruck i) h Anweisung i else h Anweisung i
Hinter if muss ein Boolescher Ausdruck stehen. Mehrere Anweisungen, mit
{ und } geklammert, zählen als eine Anweisung. Das else kann weggelassen
werden.
Praktische Informatik 2, SS 2002, Kapitel 1
19
Beispiel 1.3.1 für Boolesche Ausdrücke:
(a == b), (a != b), (a > b).
Man kann auch zusammengesetzte Boolesche Ausdrücke verwenden:
(a > 0 && a <= 10)
(3*a +5 < 20 || b == c)
switch
Syntax:
switch (h Ausdruck i) {
case h Konstante i: h Anweisungen i break ;
...
case h Konstante i: h Anweisungen i break ;
default: h Anweisungen i
}
Analog zu C: Der Ausdruck muss eine ganze Zahl sein, die Konstanten
müssen zur Kompilierzeit bekannt sein. Die break’s sollten jeden Fall
abschließen, können aber weggelassen werden.
while
Syntax:
while (h Ausdruck i) h Anweisung i
Der Rumpf der Schleife wird ausgeführt, solange der Ausdruck den Wert
true hat. Man kann mit der continue Anweisung ans Ende des Rumpfes
springen.
do-while
Syntax:
do h Anweisung i while (h Ausdruck i)
Der Rumpf der Schleife wird ausgeführt, bis der Ausdruck den Wert true
hat. Der Rumpf wird auf jeden Fall einmal ausgeführt.
for
Syntax:
for (h Init i; h Bedingung i; h Ausdruck i) h Anweisung i
Der Rumpf der for-Schleife wird ausgeführt, solange der Ausdruck den
Wert true hat. Man kann mit der continue Anweisung ans Ende des Rumpfes
springen.
Beispiel 1.3.2 for (int i = 0; i <= 10; i++) <Anweisung>;
Diese Schleife wird für i = 0, . . . 10 durchlaufen. Alternativ zum Ausdruck
i++ kann man auch i = i+1 oder i += 1 schreiben.
20
Praktische Informatik 2, SS 2002, Kapitel 1
Markierungen
Anweisungen kann man mit einer Marke (Label) versehen:
marke1:
while (i < 0)
i--;
Diese Markierung kann benutzt werden, wenn man geschachtelte Schleifen
hat, und diese entweder mit break Marke1 beenden will, oder mit continue
Marke1 ans Ende springen will.
Konstruktoren
Die Konstruktion eines neuen Objektes mittels new erfordert bei der
Klassendefinition eine spezielle Methode, den sogenannten Konstruktor, der den
gleichen Namen wie die Klasse hat (Es kann verschiedene Konstruktoren geben,
die Auswahl erfolgt abhängig von der Anzahl der Argumente). Wenn Attribute
sowohl in der Oberklasse als auch zusätzliche in der Unterklasse definiert sind,
dann ist im Konstruktor der Zugriff auf den Konstruktor der Oberklasse mit
super. möglich.
Felder
Felder (arrays) sind Folgen von Objekten gleichen Typs, die mit Index
angesprochen werden können. Diese können mehrdimensional (d.h. mit
mehreren Indizes) definiert und benutzt werden. Wir betrachten zunächst
eindimensionale Felder.
Beispiel 1.3.3
int [] a;
//
a = new int [10] ;
integer feld a ist erkl\"art
// integer feld a ist jetzt ansprechbar
// und hat 10 Eintraege: von 0 bis 9
for (int i = 0; i < a.length; i++) a [i] = i
Man sieht, dass Felder vor Benutzung erst angelegt werden müssen und dass
auf Felder die Methode length anwendbar ist, die die Länge zurückliefert.
Ein einfaches Beispiel für ein zweidimensionales Feld und dessen direkte
Initialisierung ist:
String[][] matrix = {
{"AA","AB","AC","AD"},
{"BA","BB","BC","BD"},
{"CA","CB","CC","CD"}
};
Praktische Informatik 2, SS 2002, Kapitel 1
1.3.4
21
Kommentare
Es gibt drei Arten von Kommentaren:
• Kommentar bis Zeilenende //
• Kommentare zwischen /* und */
• Kommentare zwischen /** und */ Die letzeren können mit javadoc
extrahiert und bearbeiten werden.
Kommentare der letzten Art werden vom Programm javadoc aus dem
Programmtext extrahiert, um zur Dokumentation der Klassen zu dienen.
1.3.5
Klassenkonversion, Typkonversion, cast
Die Syntax des cast-Operators ist:
(neue Klasse) Objekt
Damit kann man beispielsweise schreiben:
varfloat = (float) vardouble
Die umgekehrte Zuweisung kann Java automatisch richtig umsetzen, da keine
Information verlorengeht.
vardouble = (float) varfloat ist erlaubt.
Das gleiche kann man auch für Klassen verwenden: Wenn geoObj Oberklasse
von Rechteck ist, dann ist die Zuweisung
vargeoobj = varrechteck erlaubt, der Inhalt wird nicht verändert.
Die Zuweisung
varechteck = vargeoobj
ist verboten, denn es könnte z.B. ein Kreisobjekt der Variablen vargeoobj
zugeordnet sein.
Erlaubt ist: var rechteck = (Rechteck) var geoobj . Hier kann es zu
einer Ausnahme zur Laufzeit kommen, wenn das Objekt ein Kreis ist.
Diese Typkonversion bei Klassen dient im wesentlichen dazu, die Methoden
von Oberklassen verwendbar zu machen. Umgekehrt erlaubt es diese
Typkonversion, Objekte verschiedener Klassen zusammenzufassen z.B. in einem
Vector.
1.3.6
Ausnahmen, Exceptions
Java hat eine Behandlung von Exceptions (Ausnahmen), wie Fehler bei externen
Aufrufen, Division durch 0 usw.. Die zugehörigen Schlüsselwörter um mit
Exceptions umzugehen sind try, catch, throw. Fehler, die normalerweise zum
Abbruch führen, kann man Abfangen mit catch, nachdem man die Anweisung,
die Fehler liefern könnte, mit try eingepackt hat. throw dient zum Erzeugen von
programmierten Ausnahmen. Ein Abbruch wird erst dann erzeugt, wenn es eine
Ausnahmebedingung gibt, für die keine Ausnahmebehandlung programmiert ist.
Praktische Informatik 2, SS 2002, Kapitel 1
22
Wenn eine Methode selbst Ausnahmen erzeugen soll, dann muss dies
in der Definition der Schnittstelle angezeigt werden, und zwar mit throws
Exception1, ....
Die Verwendung von try und catch: Einem try-Block der Form try
Ausdruck folgen catch-Blöcke: catch (Exception exception) Anweisung .
1.3.7
Zugriffsrechte
Die wichtigsten sind public und private. Z.B. schreibt man normalerweise:
....
class Rechteck extends geometrischesObjekt {
private int x, y, b, h;
public void move (int xd; int yd) {
this.x = x + xd;
this.y = y + yd;
}
• public bedeutet hier, dass die Methode move von außerhalb benutzt
werden darf. d.h. die Nachricht move(10,10) kann an ein Objekt der
Klasse Rechteck gesendet werden.
• private bedeutet, dass die Attribute x,y,b,h nicht direkt geändert werden
dürfen, und außerdem auch nicht abgefragt werden können. d.h. r.b ist
nicht zulässig.
Weitere Zugriffsrechte gibt es im Zusammenhang mit packages, die ein Paket
von Klassen sind.
1.3.8
Modifikatoren
• static: Ein als statisch gekennzeichnetes Attribut existiert in allen
Objekten der ganzen Klasse nur einmal. Für Attribute wirkt dies wie
die Erklärung zu einer globalen Variable für diese Klasse. Hier kann man
z.B. die Anzahl aller Objekte sich merken, oder eine Liste aller Objekte
mitführen. Allerdings ist das in Konkurrenz zum Garbage Collector, der
nichtreferenzierte Objekte löschen darf. Durch die pure Anwesenheit in
dieser Liste werden die Objekte dann referenziert. Diese Klassen-Attribute
kann man ansprechen, ohne dass ein Objekt erzeugt wurde.
Statische Methoden kann man als “Klassenmethoden“ ansehen, die man
benutzen kann, ohne dass ein Objekt vorhanden ist, d.h. die Variable this
kann darin nicht verwendet werden. Die zugehörigen Methoden können
benutzt werden, ohne dass ein Objekt existiert, indem man diese aufruft
mit: Klassenname. Methodenname.
Z.B. ist main in einer Java-Applikation stets eine Klassenmethode.
Diese erfährt allerdings eine Sonderbehandlung, denn sie wird in einer
Applikation automatisch aufgerufen, in einem Applet jedoch nicht.
Praktische Informatik 2, SS 2002, Kapitel 1
23
• final: Bewirkt, angewandt auf eine Datenkomponente, dass deren Wert
als nicht überschreibbar angesehen wird. Damit kann Java einerseits feste
Konstanten definieren, andererseits Oberklassen und Methoden, die nicht
durch Unterklassen verändert (erweitert) werden dürfen.
Beispiel 1.3.4 Dieses Beispiel zeigt einige Möglichkeiten, Klassen zu
definieren und deren Instanzen zu erzeugen. Allerdings ist dies kein Applet,
sondern ein eigenständiges Programm.
// abgewandeltes Beispiel aus Hannover Skript
class Fahrt {
private double Geschwindigkeit;
public String Fahrtrichtung;
private Fahrzeug Benfahrzeug;
public Fahrt (double Geschwindigkeit, String Fahrtrichtung,
Fahrzeug Benfahrzeug) {
this.Geschwindigkeit = Geschwindigkeit;
this.Fahrtrichtung = Fahrtrichtung;
this.Benfahrzeug = Benfahrzeug;
}
public double beschleunigt_5() {
Geschwindigkeit = Geschwindigkeit +5;
return Geschwindigkeit;
}
public double Geschwindigkeit () {
return this.Geschwindigkeit ;
}
}
class Fahrzeug {
public double Hoechstgeschwindigkeit;
private String Eigentuemer;
private static long Anzahl;
static {
Anzahl = 0;
}
Praktische Informatik 2, SS 2002, Kapitel 1
//
//
//
//
//
Folgendes scheint nicht mehr unterst"utzt zu werden:
protected void finalize () throws Throwable {
super.finalize();
Anzahl--;
}
public static long Anzahl() {
return Anzahl;
}
public Fahrzeug() {
Anzahl = Anzahl + 1;
}
public Fahrzeug(double Hoechstgeschwindigkeit,
String Eigentuemer) {
Anzahl = Anzahl +1;
this.Eigentuemer = Eigentuemer;
this.Hoechstgeschwindigkeit = Hoechstgeschwindigkeit;
}
public double Hoechstgeschwindigkeit () {
return Hoechstgeschwindigkeit ;
}
public void loesche_Fahrzeug() {
Anzahl = Anzahl - 1;
}
public String Eigentuemer () {
return Eigentuemer;
}
}
class Auto extends Fahrzeug {
public String Autokennzeichen;
public Auto(double Hoechstgeschwindigkeit,
String Eigentuemer, String kennzeichen) {
24
Praktische Informatik 2, SS 2002, Kapitel 1
25
super(Hoechstgeschwindigkeit, Eigentuemer);
this.Hoechstgeschwindigkeit = Hoechstgeschwindigkeit;
this.Autokennzeichen = kennzeichen;
}
}
class Boot extends Fahrzeug {
public double Tiefgang;
public Boot(double Hoechstgeschwindigkeit,
String Eigentuemer, double tiefgang) {
super(Hoechstgeschwindigkeit, Eigentuemer);
this.Hoechstgeschwindigkeit = Hoechstgeschwindigkeit;
this.Tiefgang = tiefgang;
}
}
class FahrzeugProg2 {
public static void main(String[] args) {
System.out.println("Anzahl Args: " + args.length);
for (int i = 0; i < args.length; i=i+1)
System.out.println(args[i] + " ");
System.out.println();
System.out.println("Anzahl Fahrzeuge: " + Fahrzeug.Anzahl());
Auto MeinGolf = new Auto(180.0, "myself","B-SE-1");
System.out.println("Neues Auto, maxkm:" + MeinGolf.Hoechstgeschwindigkeit
+ " Besitzer:" +
MeinGolf.Eigentuemer() + " AutoKZ:" + MeinGolf.Autokennzeichen) ;
Boot boot = new Boot(20.0,"Gaby",2.5);
System.out.println("Neues Boot, maxkm:" + boot.Hoechstgeschwindigkeit
+ " Besitzer:" +
boot.Eigentuemer() + " Tiefgang:" + boot.Tiefgang ) ;
System.out.println("Anzahl Fahrzeuge nach 2 X new: " + Fahrzeug.Anzahl());
Fahrt bootsfahrt = new Fahrt(12.0,"Norden",boot);
System.out.println("Geschwindigkeit(boot): " +
bootsfahrt.Geschwindigkeit());
System.out.println("Richtung(boot): " +
Praktische Informatik 2, SS 2002, Kapitel 1
26
bootsfahrt.Fahrtrichtung);
bootsfahrt.beschleunigt_5();
System.out.println("Geschwindigkeit(boot): " +
bootsfahrt.Geschwindigkeit());
System.out.println("MaximalGeschwindigkeit (MeinGolf): " +
MeinGolf.Hoechstgeschwindigkeit());
System.out.println("Eigent\u00FCmer (boot): " +
boot.Eigentuemer());
bootsfahrt = null;
boot.loesche_Fahrzeug();
boot = null;
MeinGolf.loesche_Fahrzeug();
MeinGolf = null;
System.out.println();
System.out.println("Anzahl Fahrzeuge nach L\u00F6schen: "
+ Fahrzeug.Anzahl());
}
}
1.3.9
Applets und Applikationen
In Java kann man zwei verschiedene Arten von lauffähigen Anwendungen
schreiben:
Applets Dazu muss im Programmcode die import-Anweisung import
java.applet.*; stehen. Der Name der Datei und der definierten
Klasse, die die ausgeführte Klasse des Applets ist, sollten
übereinstimmen. Diese ausgezeichnete Klasse muss eine Unterklasse
von Applet sein. d.h. die Klasse wird definiert durch z.B.
public class geoobjtest extends Applet { .... Hierdurch sind
automatisch zwei Methoden definiert, die für die Klasse überschrieben
werden sollten: init(), paint (Graphics g) (Bezieht sich auf
Ereignismodell 1.0). Das Applet kann dann in einer HTML-Datei
aufgerufen werden mit dem Schlüsselwort applet (man kann auch embed
oder objectverwenden, siehe Java bzw. HTML-Dokumentation.) Bei
Aufruf der Hauptklasse werden diese aufgerufen und erzeugen dann eine
27
Praktische Informatik 2, SS 2002, Kapitel 1
entsprechende Zeichnung bzw. interaktive graphische Anwendung. Wie
oben schon erwähnt, hat ein Applet normalerweise Beschränkungen beim
Zugriff auf Files der Festplatte des Klienten.
Zur Laufzeit ist das Applet jeweils in einen Kontext eingebunden, der
plattformabhängig ist und den dort installierten Teil des Laufzeit-API
verwendet.
Applikationen Diese haben in der Hauptklasse eine Methode main:
public static void main (String [] args) { ... die bei Aufruf der
Klasse dann ausgeführt wird. Deren Argument ist standardmäßig ein Feld
von Strings: Dies sind Text-Parameter, die beim Aufruf übergeben werden.
Beispiel 1.3.5 // ebene geometrische Objekte
//
erster File:
Punkt.java
public class Punkt {
int x,y;
Punkt (int x, int y) {
this.x = x; this.y = y;
}
}
//
zweiter File:
geoobjtest.java
import java.applet.*;
import java.awt.*;
public class geoobjtest extends Applet {
GeoObjekt [] geos;
Punkt p1,p2,p3,p4,m1;
GeoObjekt lin;
public void init () {
p1 = new Punkt (10,10);
p2 = new Punkt (50,50);
p3 = new Punkt (100,10);
p4 = new Punkt (80,120);
lin = new Linie (p1,p4);
m1 = new Punkt (50,70);
geos = new GeoObjekt[3];
geos[0] = new Kreis (30, m1);
geos[1] = lin;
geos[2] = new Dreieck (p1,p2,p3);
}
public void paint (Graphics g) {
Praktische Informatik 2, SS 2002, Kapitel 1
28
for (int i = 0;i < geos.length;i++)
geos[i].zeichne(g);
}
}
abstract class GeoObjekt {
public abstract void zeichne (Graphics g);
public abstract boolean innen (Punkt p);
}
class Rechteck extends GeoObjekt {
public Punkt lu;
public int b,h;
// x,y Koord , b,h, Breite,Hoehe
Rechteck (Punkt p,int b, int h) {
this.lu = p; this.b = b; this.h = h;
}
public void zeichne (Graphics g) { // Methode zum Zeichnen
g.drawRect (lu.x, lu.y, b, h);
// Aufruf Bibfu drawRect
}
public boolean innen (Punkt p) {
return this.lu.x <= p.x && p.x <= this.lu.x+b &&
this.lu.y <= p.y && p.y <= this.lu.y+h;
}
}
class Kreis extends GeoObjekt {
public int r;
// Radius
public Punkt m;
// Mittelpunkts
Kreis (int r, Punkt m) {
this.m = m; this.r = r;
}
public void zeichne (Graphics g) {
g.drawArc (m.x-r, m.y-r, 2*r, 2*r, 0, 360);
// Aufruf der Bib fu drawArc
}
public boolean innen (Punkt p) {
return (m.x-p.x)*(m.x-p.x) +
(m.y-p.y)*(m.y-p.y) <= r*r;
}
}
class Linie extends GeoObjekt {
public Punkt a,b;
Linie (Punkt a, Punkt b) {
this.a = a; this.b = b;
}
public void zeichne (Graphics g) {
29
Praktische Informatik 2, SS 2002, Kapitel 1
g.drawLine (a.x, a.y, b.x, b.y);
}
public boolean innen (Punkt p) {
Dreieck dr;
dr = new Dreieck (p,this.a, this.b);
return (p == this.a || p == this.b ||
dr.entartet() && (b.x-p.x)*(p.x-a.x) > 0
&& (b.y-p.y)*(p.y-a.y) > 0);
}
}
class Dreieck extends GeoObjekt {
public Punkt p1,p2,p3;
// Koordinaten der Ecken
Dreieck (Punkt p1, Punkt p2, Punkt p3) {
this.p1 = p1; this.p2 = p2; this.p3 = p3;
}
public void zeichne (Graphics g) {
g.drawLine (p1.x, p1.y, p2.x, p2.y);
g.drawLine (p2.x, p2.y, p3.x, p3.y);
g.drawLine (p3.x, p3.y, p1.x, p1.y);
}
public boolean entartet () {
return (p3.x-p1.x)*(p2.y-p1.y)
== (p2.x-p1.x)*(p3.y-p1.y);
}
public boolean innen (Punkt r) {
return true;
}
}
1.3.10
Schnittstellen
Die Möglichkeit der multiplen Vererbung auf der Methodenebene bieten
sogenannte “Interfaces“. Diese bindet man in die Definition der Klasse
mittels extends ....
implements interface1, interface2, ... ein.
Damit kann man z.B. eine nebenläufige Berechnung erzeugen (bzw. einen
eigenständigen Prozess erzeugen, sog. Thread), indem man die vordefinierte
Schnittstelle Runnable verwendet. Diese Schnittstelle hat die Methode run().
Man kann auch Interfaces selbst definieren mittels
public interface MeinInterface
methode1 (...);
{
30
Praktische Informatik 2, SS 2002, Kapitel 1
}
Hierbei darf die Methode nicht implementiert werden. Nur die Namen werden
vereinbart.
Beispiel 1.3.6 Die
Ordnungsbeziehung.
Schnittstelle
Comparable
definiert
eine
totale
... implements Comparable {
public int compareTo(Object other) {
Fahrzeug anderesfz = (Fahrzeug)other;
if (this.hoechstgeschindigkeit
< anderesfz.hoechstgeschindigkeit) return -1;
if (this.hoechstgeschindigkeit
> anderesfz.hoechstgeschindigkeit) return 1;
return 0
}
Dies ist analog zu Haskells Typklasse Ord, die es erlaubt, Ausdrücke
bestimmter Typen mit <, ≤, >, ≥ zu vergleichen.
1.3.11
Klassenbibliotheken in Java
Java strukturiert vordefinierte Mengen von Klassen in Pakete. Diese gehören
zum application programming interface (API).
java.lang Basispaket, das z.B. Zahlen implementiert.
java.util Einige extra Basisfunktionalitäten: Hashtabellen, Datum, Random,
Vector, enumeration (Liste)
java. applet Erzeugt sogenannte Applets. Eine Anwendung, die ein Applet
werden soll, muss als Unterklasse von applet definiert sein.
java.awt Abstract window toolkit:
java.swing Erweiterung von java.awt zur komfortableren Implementierung von
GUIs.
java.io Dient zur Verarbeitung (Lesen, Schreiben) von Files, Puffern, Pipes,
Druckern, usw.
java.net Verarbeitung von Netzzugriffen, Verbindungen, Lesen, Laden von
Ressourcen (URLs).
Praktische Informatik 2, SS 2002, Kapitel 1
1.3.12
31
Mathematische Bibliothek
public final class Math
Die Klasse Math kann keine Unterklassen haben, und somit kann keine
Methode überschrieben werden. Alle Methoden und Variablen sind static.
Die Ausnahmebehandlung wie Überlauf, Division durch 0, usw. werden auf
verschiedenen Plattformen möglicherweise verschieden gehandhabt (d.h. nicht
portabel).
Es gibt folgende Konstante / Funktionen / Methoden:
E,PI
ceil(x), floor(x), rint(x), round(x) ganzzahliger Anteil, bzw. Rundungen
cos(x), sin(x), tan(x)
trigonometrische Funktionen
acos(x), asin(x), atan(x)
Umkehrfunktionen
exp(x), log(x), sqrt(x), pow(x,y)
Einige mathematische Funktionen
max(x,y), min(x,y), abs(x)
mathematische Funktionen
random()
Ergibt eine Zufallszahl zwischen 0.0 und 1.0
1.3.13
Collections, Vektoren, Listen
Java hat mehrere vordefinierte Möglichkeiten, Listen, Mengen oder
Multimengen von Objekten zu verwalten. Logisch gesehen kann man
unterscheiden zwischen: Listen, Mengen, Multimengen, Assoziationslisten
Listen entspricht einer Liste: Es gibt eine Reihenfolge der Objekte und es ist
erlaubt, dass Elemente mehrfach vorkommen.
Mengen Es gibt keine Reihenfolge, Duplikate sind verboten.
Multi-Mengen Es gibt keine Reihenfolge, aber Duplikate sind erlaubt.
Assoziationslisten (map) Ist wie eine Funktion bzw. eine indizierte
Datenbank. Es entspricht einer Liste von Paaren aus Schlüsseln und Daten,
wobei die Schlüssel eindeutig sein müssen.
Es gibt Methoden zum Einfügen, Löschen, Vergleichen, indiziertem Zugriff,
. . . und auch zum Iterieren.
Die Klasse Collection kann Objekte unterschiedlichen Typs enthalten. In
diesem Fall muss man bei der Verarbeitung eine Fallunterscheidung über Typen
machen. Einige Funktionen sind:
boolean add(Object o)
Hinzufügen
void clear()
Löschen
boolean contains(Object o)
boolean equals(Object o)
Vergleich von collections
boolean isEmpty()
Iterator iterator()
Die Klasse Vector kann verwendet werden wie eine Liste von Objekten. Da
man aber keine elementaren Datentypen in Vektoren einfügen kann, benötigt
man zur Verwendung von Vektoren von Zahlen (beispielsweise), eine Verpackung
Praktische Informatik 2, SS 2002, Kapitel 1
32
dieser Zahlen in ein Objekt. Dazu dienen sogenannten Wrapper-Klassen.
Short,Byte, Integer, Long, Float, Double, Character, Boolean
sind
Wrapperklassen.
Einpacken
kann
man
Zahlen
mittels
Double x = new Double(3.14);, Auspacken mittels x.DoubleValue();.
Iterator
Ein Iterator behandelt eine Menge von Objekten, die in einem Array, Liste,
Collection usw abgelegt sind, die eine Folge bilden (analog zu einem File mit
Sätzen). Man kann damit die Folge von vorne nach hinten abarbeiten.
Das
Interface
Iterator
hat
die
Methoden:
boolean hasNext()
Object next()
Liefert das nächste Objekt.
void remove()
Typische Verwendung in einem Programm:
...
Iterator it = col.iterator();
while (it.hasNext())
...println(it.next());
1.3.14
Nebenläufige Berechnung: Threads
In Java kann man Unterprozesse anstoßen, sogenannte Threads
(Berechnungsfäden), die logisch parallel arbeiten. Diese kann man definieren als
Klasse, die Unterklasse von Thread ist, oder mittels der Schnittstelle Runnable.
Die einzige Methode dieser Schnittstelle ist run(). Einige Methoden zu Threads
sind:
start()
startet einen Thread, falls als Unterklasse von
Thread definiert. Nach dem Start des Threads
laufen zwei Programmteile parallel. Die Anweisungen
des Threads werden ausgeführt. Ebenso wird mit
der nächsten Anweisung, die dem start(); folgt,
fortgefahren.
sleep(int ms) Pause für die angegebene Zeit (in ms).
join()
Wartet auf die Beendigung eines (anderen) Threads.
Die Angabe einer operationellen Semantik für Threads muss ein Konzept
von unabhängig ablaufenden Evaluatoren (Prozessen) einführen. Die Semantik
des Befehls sleep() beispielsweise kann nur dann deterministisch sein, wenn
man festlegen würde, wieviel Ausführungsschritte jeder Befehl braucht, und wie
die parallele Auswertung zeitlich genau ablaufen soll. So eine Festlegung wäre
Unsinn, denn die parallelen Auswertungen sollen auch logisch unabhängig sein.
Beispiel 1.3.7 Eine einfaches Beispiel, bei dem man die Aktionen der Threads
im Konsolenfenster der JVM sehen kann ist:
class Zaehlthread extends Thread {
Praktische Informatik 2, SS 2002, Kapitel 1
33
int thnr,pause;
Zaehlthread(int thnr, int pause) {
this.thnr = thnr;
this.pause = pause;
}
public void run () {
int n = 0;
while (n < 100) {
System.out.println("Thread: " + thnr + " : " + (n++));
try {
sleep(pause);
}
catch(InterruptedException e) {
System.out.println("Thread: " + thnr + " InterruptedException ");
}
}
}
}
public class ThreadDemo1 {
public static void main(String[] args) {
Thread t1 = new Zaehlthread(1,100);
Thread t2 = new Zaehlthread(2,70);
t1.start();
t2.start();
}
}
Die Ausgabe könnte so aussehen. Beachte, dass diese nicht ganz
deterministisch ist.
Thread:
Thread:
Thread:
Thread:
Thread:
Thread:
Thread:
Thread:
Thread:
Thread:
Thread:
Thread:
Thread:
Thread:
Thread:
Thread:
2
1
2
1
2
1
2
2
1
2
2
1
2
1
2
1
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
0
0
1
1
2
2
3
4
3
5
6
4
7
5
8
6
Praktische Informatik 2, SS 2002, Kapitel 1
Thread:
Thread:
Thread:
Thread:
Thread:
Thread:
Thread:
Thread:
Thread:
Thread:
Thread:
Thread:
Thread:
.......
1.4
1
2
1
2
1
2
1
2
2
1
2
2
1
:
:
:
:
:
:
:
:
:
:
:
:
:
34
7
9
8
10
9
11
10
12
13
11
14
15
12
Graphische
Programmierung
graphical user interfaces)
(GUIs:
Da Java eine (relativ) einfache Möglichkeit bereitstellt, graphische Benutzeroberflächen zu programmieren, können wir kurz in die Programmierung und
Handhabung von graphischen Benutzeroberflächen (in Applets) einführen.
Da die Benutzung eines Computers heute die Verwendung einer graphischen
Benutzeroberfläche fast zwangsläufig zur Folge hat, ist jeder schon mal Benutzer
gewesen. Diese Oberflächen zeichnen sich durch die Präsentation von Fenstern
aus, die verschiedenen Anwendungen zugeordnet sind. Fenster können aktiv
oder inaktiv sein, und visuell im Hintergrund oder im Vordergrund sein. Ein
weiteres Kennzeichen von GUIs ist die parallele Verwendung verschiedener
Eingabekanäle: Eingabekanäle von Benutzerseite sind meist die Tastatur und
eine Maus mit 1,2 oder 3 Tasten, manchmal noch weitere wie Touchscreen,
Joystick, usw.
Es gibt eine Vielzahl von graphischen Elementen, die verwendet
werden können: Fenster mit Schiebeleisten, waagrechte/senkrechte Menüs,
Radioknöpfe, Symbole zum Anklicken (Icons), Textfelder usw.
Die Verbreitung von GUIs startete vor ca. 20 Jahren. Zu diesem Zeitpunkt
war die Verwendung von zeichenbasierten Bildschirmen und Interaktion
mit Kommandoeingabe in eine Kommandozeile vorherrschend. Auch jetzt
gibt es diesen Modus der Interaktion noch als Basis, z.B. bei PC als
DOS Kommandozeile, oder als Kommandozeile bei Unix. Bei Großrechnern
(Mainframes) ist dies noch der interne Standard, obwohl auch hier graphische
Benutzeroberflächen in vielen Fällen zur Interaktion mit dem Rechner verwendet
werden.
Die große Akzeptanz der GUIs beim Benutzer kommt durch die einfache
Bedienbarkeit, bei der man sich keine (textuellen) Kommandosequenzen und
Syntax merken muss. Zudem kommt die graphische Oberfläche der menschlichen
Praktische Informatik 2, SS 2002, Kapitel 1
35
Wahrnehmung entgegen, die eher an Bildern orientiert ist.
Möglich wurden die graphischen Oberflächen erst durch schnelle Rechner
und größere Speicher, die eine schnelle Verarbeitung und Darstellung
ermöglichten. Vorgänger waren Großrechner mit teilweise mehr als 1000
Bildschirme an einem Zentralrechner, die weitgehend passiv waren. In dieser
Konstellation sind graphische Benutzeroberflächen so gut wie unmöglich,
da die Rechenkapazität zur Steuerung einer graphischen Benutzeroberfläche
nicht lokal ist und evtl. von zu vielen Benutzern in Anspruch genommen
wird. Heutige Standardkonstellation ist Anschluss an ein Netzwerk (Internet)
und lokale (Rechen+Speicher)- Kapazität zur Steuerung der graphische
Benutzeroberfläche.
1.4.1
Programmierung, Ereignissteuerung
Im Gegensatz zur Verwendung einer Kommandozeile, bei der ein entsprechendes
Programm genau den Inhalt (einen String) der Kommandozeile sieht
und entsprechend verarbeitet, muss eine programmierte graphische
Benutzeroberfläche und entsprechend die Anwendungsprogramme mit einer
Mehrzahl von Interaktionen und auch Eingabemöglichkeiten umgehen können.
Z.B. muss ein Textverarbeitungsprogramm unter GUI i.a. die Markierung
eines Textstückes ermöglichen. Dazu notwendig sind: Das Programm muss
wissen, was im Moment sichtbar ist, es muss herausfinden, wo die Maustaste
gedrückt wurde, wohin sie gezogen wurde und wo die Maustaste wieder
losgelassen wurde.
Die interne Methode der Mitteilung an das zugehörige Programm geschieht
über einen Strom von Ereignissen, die vom System, Betriebssystem oder dem
GUI-System erzeugt werden und an das Benutzerprogramm gesendet werden.
Dieser Strom ist nach der zeitlichen Reihenfolge des Auftretens der Ereignisse
geordnet, wird aber teilweise gefiltert.
Das Prinzip der Portabilität hier einzuhalten ist nicht ganz unproblematisch,
da die verschiedenen GUIs und Systeme bezüglich der erzeugten Ereignisse nicht
ganz identisch sind. In der neueren Version von Java-Swing ist die Plattformunabhängigkeit vollständig gewährleistet.
1.4.2
GUIs in Java (Ereignismodell 1.0
Betrachten wir jetzt mal die Möglichkeiten in Java. Normalerweise ist die
graphische Anwendung ein Applet, das durch eine Klasse definiert wird, die
zur Unterklasse von applet erklärt wird.
Das Bild, das der Benutzer sieht, stellen wir uns vor als einen flachen,
graphischen und farbigen Bildschirm, der aus ca. 1000 X 1000 Bildpunkten,
sogenannten Pixeln besteht. Dies ergibt in natürlicher Weise ein Cartesisches
Koordinatensystem, das jeden Punkt in der Form (x,y) ansprechbar macht.
Normalerweise gibt es einen Cursor, das ist eine aktuelle Position der Tastatur
und einer Mausposition, die sich innerhalb der Fläche befinden.
36
Praktische Informatik 2, SS 2002, Kapitel 1
Es gibt eine reichliche Anzahl vordefinierter Fenstertypen und graphischer
Elemente:
Oberste Klasse ist Component.
Unterklassen sind:
Button Ein Knopf zum Anklicken.
Canvas Ein Zeichenfläche.
Checkbox Ein Text und ein Kästchen zum Ankreuzen.
Choice Ein Auswahlmenü mit Kurztexten.
Container abstrakte Klasse, mit der hierarchisch ein Fenster in Unterfenster
gegliedert werden kann. Die Unterklassen sind:
Panel Fenster ohne irgendwelche Rahmenobjekte.
Window mit Unterklassen Frame, Dialog
Label Textanzeigefeld
List Senkrechte anklickbare Menüleiste.
Scrollbar Schiebeleiste
Textcomponent Textanzeige
Applet ist Unterklasse von Panel, was nur bedeutet, dass deren Methoden einem
Applet sofort zur Verfügung stehen.
Zur Klasse Component gibt es eine Menge von Methoden, die verschiedene
Aspekte handhaben: Einige Beispiele seien hier aufgeführt.
Layout Die Art der Verteilung von Subkomponenten kann gesteuert werden.
Je nach Layout Spezifikation mittels der entsprechenden Klasse:
Borderlayout
North, South, Center, East, West
GridLayout(...) Komponenten sind matrixartig angeordnet
FlowLayout
Komponenten sind untereinander angeordnet.
CardLayout
Komponenten sind wie in einem Kartenstapel
hintereinander angeordnet.
Die aktuelle Größe und Position kann ermittelt und verändert werden.
bounds(), inside(), location(), move(), size(), ...
Farbe des
Hintergrunds,
setForeground(), . . . .
Vordergrunds:
getBackground(),
Ereignisse Ermitteln und Handhabung der durch den Benutzer verursachten
Ereignisse
action(), gotFocus(), keyDown(), mouseDown(),
mouseEnter(), mouseUp(), handleEvent(), postEvent(), ....
Praktische Informatik 2, SS 2002, Kapitel 1
37
Zeichnen innerhalb der Komponente, Neuzeichnen des Bildes. paint(),
repaint(), update()
Status Feststellen, ob Komponente aktiv, usw.
Bei Definition einer Unterklasse können bzw. müssen bestimmte Methoden in
diesen Klasse überschrieben werden.
Bemerkungen
Die Klasse Container hat die Methode add, mit der man neue Komponenten
hinzufügen kann. Diese werden normalerweise vom zugehörigen Layout-manager
an bestimmte, vordefinierte Positionen plaziert: Bei BoderLayout sind möglich:
North, West, South, East, Center, null.
Die Ereignisse, die vom Benutzer und System generiert werden, werden in
der Objekthierarchie von unten nach oben durchgereicht, bis es eine Methode
handle event gibt, die diese einfängt. Diese Methode kann das Ereignis auch
abweisen (bzw. weiterreichen, indem false zurückgegeben wird.
Programmierhinweise: Generell gilt: Man muss das an der Oberfläche
sichtbare als Modell möglichst vollständig in Datenstrukturen ablegen, damit
das sichtbare Bild rekonstruierbar ist und damit der Benutzer und das
Programm die gleiche Sicht der Dinge haben.
Ist die zu programmierende Anwendung komplex, so ist die Handhabung
und das Verarbeiten aller möglichen Ereignisfolgen eine ebenfalls komplexe und
schwierige Aufgabe, da man mit allem rechnen muss und auf jedes relevante
Ereignis eine sinnvolle Aktion gestartet werden soll.
Um eine komplexere (gute, professionelle) Anwendung (Applet) in Java zu
schreiben, ist ein aktuelles Handbuch notwendig. Denn man muss eine Unzahl
von Klassen, die Hierarchie, deren Methoden, die richtige Verwendung und auch
die zu behandelnden Ausnahmen kennen. Eine Einarbeitung und Orientierung
wird meist erleichtert durch vorgegebene Beispiele im SDK (bzw. JDK oder
auch aus anderen Quellen).
Eine Anwendung sollte anwenderfreundlich sein und einfach und zuverlässig
wirken und dies auch sein. Das erfordert oft etwas Nachdenken und
gutes Strukturieren. Zum Beispiel ist im nachfolgenden Zeichenprogramm
extra Aufwand getrieben worden, um während des Zeichnens die
aktuelle Strecke(Ellipse) sichtbar zu machen. Analog verhält es sich mit
Fehlermeldungen. Um diese richtig zuzuordnen und zu formulieren, sollte man
sich in die Rolle eines Benutzer versetzen, der keine Ahnung von der internen
Verarbeitung hat, und der nicht abgeschreckt werden soll.
Beispiel 1.4.1 (Ereignismodell 1.0) Dieses Beispiel ist ein Applet, das eine
Zeichenfläche realisiert, auf der man Strecken und Ellipsen zeichnen kann. Es
gibt einen Schalter, der mit choice realisiert ist, mit dem man von Strecke auf
Ellipse umschalten kann.
Während des Zeichenvorgangs wird das jeweils aktuelle Objekt gezeichnet,
bis es durch Loslassen der Maustaste bestätigt wird.
Praktische Informatik 2, SS 2002, Kapitel 1
//
//
veraenderte Version eines JDK Beispiels
(alte Version der Ereignissteuerung)
import java.awt.*;
import java.applet.*;
import java.util.Vector;
public class DrawTestRechteck extends Applet {
public void init() {
setLayout(new BorderLayout());
DrawPanel dp = new DrawPanel();
add("Center", dp);
add("South", new SKWahl(dp));
dp.init();
}
public boolean handleEvent(Event e) {
switch (e.id) {
case Event.WINDOW_DESTROY:
System.exit(0);
return true;
default:
return false;
}
}
public static void main(String args[]) {
Frame f = new Frame("DrawTest");
System.out.println("Main laeuft");
DrawTestRechteck drawTest = new DrawTestRechteck();
drawTest.init();
drawTest.start();
f.add("Center", drawTest);
f.resize(300, 300);
f.show();
}
}
class DrawPanel extends Panel {
Vector lines = new Vector();
Vector streckeOderKreis = new Vector();
int x1,y1;
boolean ziehen;
38
39
Praktische Informatik 2, SS 2002, Kapitel 1
int strecke;
int x2,y2;
//
0 = strecke, 1 = kreis, 2 = Rechteck
public void init() {
ziehen = false;
strecke = 0;
}
public DrawPanel() {
setBackground(Color.white);
}
public void setStrecke() {
strecke = 0;
}
public void setRechteck() {
strecke = 2;
}
public void setKreis() {
strecke = 1;
}
public boolean handleEvent(Event e) {
switch (e.id) {
case Event.MOUSE_DOWN:
x1 = x2 = e.x;
y1 = y2 = e.y;
ziehen = true;
return true;
case Event.MOUSE_UP:
lines.addElement(new Rectangle(x1, y1, e.x, e.y));
// leichter Missbrauch von rectangle
streckeOderKreis.addElement(new Rectangle(strecke,0,0,0));
ziehen = false;
repaint();
return true;
case Event.MOUSE_DRAG:
x2 = e.x;
y2 = e.y;
repaint();
return true;
case Event.WINDOW_DESTROY:
System.exit(0);
return true;
default:
return false;
Praktische Informatik 2, SS 2002, Kapitel 1
40
}
}
public void paint(Graphics g) {
int np = lines.size();
int streckei;
/* Zeichne alle Strecken und Ellipsen */
for (int i=0; i < np; i++) {
Rectangle streckeip = (Rectangle)streckeOderKreis.elementAt(i);
streckei = streckeip.x;
Rectangle p = (Rectangle)lines.elementAt(i);
if (streckei == 0)
g.drawLine(p.x, p.y, p.width, p.height);
else {
if (streckei == 1) {
if (p.height > p.y)
g.drawOval(p.x, p.y, p.width-p.x, p.height-p.y);
else
g.drawOval(p.x, p.height, p.width-p.x, p.y-p.height);
}
else
if (streckei == 2) {
if (p.height > p.y)
g.drawRect(p.x, p.y, p.width-p.x, p.height-p.y);
else
g.drawRect(p.x, p.height, p.width-p.x, p.y-p.height);
}
}
}
if (ziehen) {
if (strecke == 0)
{g.drawLine(x1, y1, x2, y2);}
else {
if (strecke == 1) {
if (y2 > y1)
g.drawOval(x1,y1,x2-x1,y2-y1);
else
g.drawOval(x1,y2,x2-x1,y1-y2);
}
else {
if (y2 > y1)
g.drawRect(x1, y1, x2-x1, y2-y1);
else
Praktische Informatik 2, SS 2002, Kapitel 1
g.drawRect(x1, y2, x2-x1, y1-y2);
}
}
}
}
}
class SKWahl extends Panel {
DrawPanel target;
public SKWahl(DrawPanel target) {
this.target = target;
setLayout(new FlowLayout());
Choice SoderK = new Choice();
SoderK.addItem("Strecke");
SoderK.addItem("Ellipse");
SoderK.addItem("Rechteck");
SoderK.setBackground(Color.lightGray);
add(SoderK);
}
public void paint(Graphics g) {
Rectangle r = bounds();
g.setColor(Color.lightGray);
g.draw3DRect(0, 0, r.width, r.height, false);
}
public boolean action(Event e, Object arg) {
if (e.target instanceof Choice) {
String choice = (String)arg;
if (choice.equals("Strecke")) {
target.setStrecke();
} else if (choice.equals("Ellipse")) {
target.setKreis();
} else if (choice.equals("Rechteck")) {
target.setRechteck();
}
}
return true;
}
}
41
Praktische Informatik 2, SS 2002, Kapitel 1
1.4.3
42
Ereignissteuerung nach dem Java Ereignis-Modell
1.1
Die neuere Methode der Ereignisverarbeitung hat die Modellvorstellung der
Ereignisse und somit zwangsläufig auch die Bibliotheken, das API, und und die
Programmierung verändert.
Die Modelle 1.0 und 1.1 sind leider nicht ganz kompatibel, so dass
Programme von Hand umgestellt werden müssen. Die Strukturierung im
Ereignis-Modell 1.1 funktioniert zeitlich so:
1. Ein Ereignis tritt bei einem Objekt auf (z.B. Button, Menü, . . . ).
2. Dieses Ereignis wird in ein Ereignisobjekt verpackt und an einen
Beobachter gesendet (Listener).
3. Dieser Beobachter (Methode) enthält die Programmierung, was nach
Eintreten dieses Ereignisses zu verfahren ist.
Die Programmierung erfolgt so, dass an bestimmte Quell-Objekte einen
Listener eingetragen wird, der selbst zu definieren ist. Statt handleEvent gibt
es für jedes Ereignis eine eigene Methode.
Das neue Modell erlaubt auch andere Programmierprinzipien wie innere
Klassen, um die Beobachter (Listener) geschickter programmieren zu können.
(Siehe hierzu Java Handbücher).
Vorteile des neuen Modells sind optimierte Verteilung der Ereignisse.
Im Modell 1.0 wurden (werden) die Ereignisse relativ ungezielt an die
Anwendungsprogramme weitergegeben (Gießkannenprinzip), während im neuen
Modell diese Verteilung programmgesteuert ist. Nachteil des neuen Modells ist
die Verwirrung durch die zeitweise Koexistenz zweier Standards, wobei der neue
Standard in Browsern nur abhängig von der Version und den richtigen Plugins
funktioniert (siehe Paragraph 1.2.2.
Beispiel 1.4.2 // Beispiel aus Java2-Handbuch
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
public class KlickKlack extends Applet {
Button klickButton = new Button("KlickKlack");
boolean geklickt = true;
Color klick = new Color(255,255,0);
Color klack = new Color(0,0,255);
public void init() {
add(klickButton);
klickButton.addMouseListener(
new MouseAdapter () {
43
Praktische Informatik 2, SS 2002, Kapitel 1
public void mouseClicked(MouseEvent e) {
Graphics g = getGraphics();
if (geklickt) g.setColor(klick);
else
g.setColor(klack);
g.fillOval(0,0,200,200);
// das original war g.fillOval(0,0,getWidth,getHeight);
geklickt = !geklickt;
}
});
}
}
1.5
Kritikpunkte an
Programmierung
der
objektorientierten
(siehe Artikel von M. Broy, Informatik Spektrum, Februar 2002)
Einige Kritikpunkte:
• “OO-Sprachen kennen keine Komposition von Klassen“
Allgemeiner: Es gibt keine Operatoren, die Klassen zu neuen Klassen
verbinden. Es gibt nur die Vererbungsbeziehung zwischen Klassen.
Man kann manche Kompositions-Konzepte mittels multipler Vererbung
implementieren.
• “Das OO-Ausführungsmodell ist sequentiell“
Hierbei gibt es die Problematik der Seiteneffekte. Es ist schwierig und
komplex, aufgrund von lokalen Eigenschaften der Programme (Methoden)
deren Wirkung zu beschreiben. Parallelisierung der Ausführung wird
durch Sequentialität stark behindert. z.B. kann man in a.methode1;
b.methode2 die Methoden nicht parallel auswerten, auch wenn a,b, und
die beiden Methoden verschieden sind, da es darauf ankommen könnte,
dass die Effekte in einer bestimmten Reihenfolge durchgeführt werden.
Es gibt allerdings Programmteile, z.B. Threads, die direkt durch die Art
der Programmierung im Prinzip parallel ausführbar sind.
• “Die Objektorientierung sagt uns nicht, wie wir das Verhalten von
Schnittstellen definieren sollen“
Mit Schnittstellen sind hier nicht Interfaces gemeint. Sagen wir mal
Methodenaufruf. Hier eine operationale Semantik anzugeben erfordert i.a.,
den ganzen Zustandsraum (d.h. alle Objekte und deren innere Zustände)
des aktuellen Programmlaufs zu berücksichtigen. Dies ist nicht modular
und auch nicht lokal.
• “Vererbung verletzt das Geheimnisprinzip“
Nur wenn ausdrücklich programmiert, gibt es unsichtbare Attribute.
Praktische Informatik 2, SS 2002, Kapitel 1
44
• “Letzlich gibt es nur eine einzige, syntaktische Annahme: (die Unterklasse)
hat mindestens dieselben Attribute und Methoden wie die Oberklasse“
Da ist was dran: da es keine Verhaltensbeschreibung der Methoden gibt,
und man überschreiben darf, weiss man a priori nichts außer dass die
Methoden vorhanden sind, aber kann ihr Verhalten nicht in der Oberklasse
irgendwie festlegen.
In Haskell kann man zumindest den Typ festlegen. In Java auch, aber der
Typ ist nicht so aussagekräftig wie in Haskell.
• (sinngemäß:) “neue Projekte werden sich i.a. eine eigene Klassenhierarchie
schaffen, nicht auf eine bereits vorhandene Klassenhierarchie aufbauen“.
Der einfache Grund ist: das bereits vorhandene System funktioniert,
aber das neue müsste Änderungen in der bestehenden Hierarchie, den
Attributen, Methoden durchführen. Diese bewirkt aber möglicherweise
Fehler im vorhandenen System, muss also sehr vorsichtig gemacht werden,
und ist somit viel aufwendiger als das Kopieren und Modifizieren, d.h.
Neu-erstellen der Klassen für die Zwecke des neuen Projekts.
• “Multiple Dispatching“ fehlt
Die aufgerufene Methodenimplementierung hängt ab vom Typ zweier
Argumente.
Dies erfordert in OO-Programmierung, dass in jeder Klasse (Typ des
Argument1) die Implementierung (bzw. ein entsprechender Aufruf) für
jeden möglichen Typ von Argument2 vorhanden ist.
• statische Analyse der Fernwirkung von Methodenaufrufen ist so gut wie
unmöglich“
Wenn man versucht, statisch (d.h. aufgrund des Programmtextes)
vorherzusagen, welche Auswirkung x.methode(..) auf andere Objekte hat,
dann stellt man fest, dass dies
1. aufgrund der Seiteneffekte i.a. nur durch vollständiges formales
Testen möglich ist.
2. wieder einen Methodenaufruf auf das gleiche Objekt x erfordert
könnte. Dies ist analog zur Rekursion. Hier kann es im
Extremfall bedeuten, dass man nicht davon ausgehen kann,
dass Methodenaufrufe auf Objekte immer auf Objekte in einem
konsistenten Zustand passieren, sondern dass es auch unerwartete
Zwischenzustände geben kann.
Herunterladen