Programmierung und Programmiersprachen Dr. Claudia Leopold Institut für Informatik Abt. Parallelverarbeitung und Komplexe Systeme [email protected] Hauptgebäude, Zi. 2-40 Webseite zur Vorlesung (über Lernserver erreichbar): http://www.informatik.uni-leipzig.de/~leopold/grundPS.html Organisatorisches Übungsbeginn: 17.4. (B-Woche) bzw. 23.4. (A-Woche) Erstes Übungsblatt: 11.4. im Netz (Lernserver) Abgabe der Lösungen jeweils 2 Wochen nach Ausgabe, 5 Minuten vor der Vorlesung Ausnahme: erste Abgabe erst am 2.5. Übungsschein: mindestens 60% der erreichbaren Punkte Prüfungsklausur im Juli, Termin wird noch bekannt gegeben Zulassungsbedingungen: (1) Übungsschein ´Digitale Informationsverarbeitung´ und (2) Übungsschein ´Programmierung und Programmiersprachen´ Übungen Mo (A/B) 11.15 - 12.45 SR 3-11 Herr Dr. Richter Mo (A/B) 13.15 - 14.45 SR 3-11 Herr Dr. Richter Mo (A/B) 15.15 - 16.45 SR 3-11 Herr Dr. Richter Di (A/B) 9.15 - 10.45 SR 3-05 Herr Dr. Richter Mi (A/B) 7.30 - 9.00 HS 8 Herr Wittig Fr (A/B) 7.30 - 9.00 SR 3-11 Herr Wittig Fr (A/B) 7.30 - 9.00 SR 3-01 Herr Dr. Gräbe Verbindliche Anmeldung durch Eintragen in die Liste. Adressen der Übungsleiter: [email protected] bzw. wittig@... Inhalt (Plan) Fortsetzung des in der Vorlesung ´Digitale Informationsverarbeitung´ begonnenen Überblicks zu Programmiersprachen 1. Objektorientierte Programmierung und Modellierung -> Hauptteil 2. Parallele und verteilte Programmierung 3. Skriptsprachen 4. Maschinennahe Programmierung einschl. Aspekte der Implementierung höherer Programmiersprachen 5. Zusammenfassender Überblick zu Programmiersprachen Literatur Wolfgang Küchlin, Andreas Weber: Einführung in die Informatik: Objektorientiert mit Java, Springer-Verlag, 2000, Kapitel 3,7,8. Bernd Oesterreich: Objektorientierte Softwareentwicklung: Analyse und Design mit der Unified Modeling Language, 4. Auflage, Oldenbourg Verlag, 1999. Bert W. Sebesta: Concepts of Programming Languages, 4. Auflage, Addison-Wesley, 1999. Java-Lehrbuch, zum Beispiel: Guido Krüger: Go to Java 2, 2. Auflage, Addison-Wesley, 1999. Stefan Middendorf, Reiner Singer: Java: Programmierhandbuch und Referenz, 2. Auflage, dpunkt-Verlag, 1999. James Gosling et al.: The Java Language Specification, 2. Auflage, Sun Press, 2000, online verfügbar. Weitere Literatur wird im Laufe der Vorlesung genannt. 1. Objektorientierte Programmierung und Modellierung Gliederung 1.1. Grundlegende Konzepte der Objektorientierung 1.2. Objektorientierte Modellierung (UML) 1.3. Einführung in Java 1.4. Objektorientierte Programmierung in Java 1.5. Weitere Aspekte der Java-Programmierung Ausnahmen Generisches Programmieren Programmierung und Modellierung Programmierung Softwareentwicklung Planmäßiges, systematisches Vorgehen Arbeitsteilige Entwicklung Umfangreiche Programme Analyse/Design vor eigentlicher Implementierung Objektorientierung wurde besonders für die Entwicklung komplexer Softwaresysteme konzipiert -> Modellierung und Programmierung bilden Einheit Vorteile OO (vs. imperativ, funktional, logisch): Beschreibung komplexer, dynamischer Systeme Erweiterte Möglichkeiten zur Strukturierung von Programmen 1.1. Grundlegende Konzepte der Objektorientierung Objektorientierung OO modelliert die reale Welt als System interagierender Objekte Objekt = gedankliche oder reale Einheit in der Umwelt und/oder in Software Grundlegende Konzepte: Datenkapselung Nachrichtenaustausch Bilden von Klassen Vererbung Polymorphie Dynamisches Binden Datenkapselung Objekt umfaßt Attribute (Zustandsvariablen, Felder, Daten) und Methoden (Operationen, Funktionen) Abstrakter Datentyp Zusammenfassung von Daten und Operationen über diesen Daten Implementierung der Datenstrukturen und Operationen ist außerhalb des Objektes nicht sichtbar Zugriff auf Daten nur über Operationen (get, set und andere) Konzept existiert auch in nicht-objektorientierten Sprachen (z.B. Modula-2) Beispiel: Objekt rectangle1 Attribute: Methoden: x y width height 10 20 120 75 draw() delete() move() Modifikatoren: private, public Vorteile der Datenkapselung Klar definierte Schnittstellen unterstützen arbeitsteilige Programmentwicklung (Programmieren im Großen) Implementierungsdetails nur innerhalb des Objektes sichtbar -> Implementierung kann ohne Anpassung der übrigen Programmteile geändert werden (bei gleicher Signatur) Erleichtert Debugging, da Fehler besser lokalisierbar Nachrichtenaustausch Objekte Nachrichten Nachrichten Aufbau einer Nachricht Empfänger Methodenname Argumente Beispiele: rect.move(20,0), rect.delete() Senden einer Nachricht bewirkt Aufruf der entsprechenden Methode des Zielobjektes Nachrichtenaustausch dient Übermittlung von Informationen Inanspruchnahme von Diensten (Client/Server) Klasse = Zusammenfassung gleichartiger Objekte gleiche Attribute, aber unterschiedliche Attributwerte gleiche Methoden Osterei Klasse Objekte Klasse umfaßt Attribute, aber keine Attributwerte Methoden (Ausnahme: Klassenvariablen) Beispiel: Klasse class Rectangle { private int x, y, width, height; public void move(int dx, int dy) { x = x + dx; y = y + dy; } public void draw() {...} public void delete() {...} } Instanzierung Vorgehen bei objektorientierter Programmierung: 1. Definition einer Klasse einschließlich Implementierung der Methoden 2. Instanzierung = ´Ableiten´ von Objekten aus der Klasse Attribute werden angelegt und initialisiert (zum Beispiel mit default-Werten) Methoden (einschließlich Implementierung)werden aus Klassendefinition übernommen Objekte heißen Exemplar oder Instanz der Klasse Klasse beschreibt Typ des Objekts. Vererbung Bei der Definition von Klassen kann man bereits definierte Klassen als Basis verwenden. Vorteile: Wiederverwendung von Programmcode, hierarchische Strukturierung von Programmen, Erweiterbarkeit Beispiel: class coloredRectangle extends Rectangle { ink: Color; public void refill(newInk:Color) { ink = newInk; } } Oberklasse (Superklasse, Basisklasse): Rectangle Unterklasse (Subklasse, abgeleitete Klasse): coloredRectangle Beispiel: Vererbung blaues Rechteck Attribute: x y width height ink Methoden: 10 20 120 75 blue draw() delete() move() refill() Überschreiben von Methoden In der Oberklasse bereits implementierte Methoden können in der Unterklasse mit einer neuen Implementierung überschrieben werden (engl.: override). Beide Methoden haben dann den gleichen Namen und die gleiche Signatur. Beispiel: Reimplementierung der Methode draw in coloredRectangle Aufruf der Methode bewirkt: Für Objekte der Oberklasse wird die Methode der Oberklasse ausgeführt. Für Objekte der Unterklasse wird die Methode der Unterklasse ausgeführt. Überladen von Methoden = Definition von Methoden mit gleichem Namen, aber unterschiedlicher Signatur Beispiel: public void scale(factor: float) { x = x * factor; y = y * factor; } public void scale(factorX: float, factorY: float) { x = x * factorX; y = y * factorY; } Aufruf bewirkt Ausführung der Methode mit den passenden Parametern scale(1.3) vs. scale(1.2, 3.7) Polymorphie (Vielgestaltigkeit) = Methode (gegeben durch Name) kann sich an Kontext anpassen Unterscheiden: statische Polymorphie (Überladen) auch in nicht-objektorientierten Sprachen, z.B. ´/´ für int und float dynamische Polymorphie (Überschreiben) Verhalten der Methode sollte nur angepaßt, aber nicht grundsätzlich geändert werden (Gefahr von Programmierfehlern) Dynamische Polymorphie Variable kann für Objekte verschiedener Klassen stehen, sofern eine - eventuell mehrstufige Vererbungsbeziehung besteht . Beispiel: rect: Rectangle; rect := new Rectangle(); rect.draw(); - Aufruf der Methode aus Klasse Rectangle rect := new coloredRectangle(); rect.draw(); - Aufruf der Methode aus Klasse coloredRectangle Dynamische Bindung = Verknüpfung zwischen Methodenaufruf und auszuführendem Programmcode erfolgt erst zur Laufzeit Statische Bindung = Verknüpfung erfolgt zur Übersetzungszeit, durch den Compiler Vorteil statische Bindung: Geschwindigkeit (schnellere Programmausführung) Vorteil dynamische Bindung: Keine Fallunterscheidung nötig -> bessere Lesbarkeit Programm leichter zu modifizieren Art der Bindung ist durch Programmiersprache festgelegt, evtl. mit Einflußmöglichkeit durch Programmierer Arbeiten mit Objekten Allgemeine Operationen für Objekte: Erzeugen Vergleich Zuweisung evtl. Löschen (z.B. in C++) Erzeugenvon Objekten: durch Konstruktor = spezielle Methode der jeweiligen Klasse eventuell überladen in Java existiert impliziter Konstruktor Zuweisung von Objekten An Variablen mit Typ der Oberklasse können Objekte der Unterklasse zugewiesen werden, aber nicht umgekehrt Beispiel: rect: Rectangle := new Rectangle(); cRect: coloredRectangle := new coloredRectangle(); rect := cRect; cRect := rect; - zulässig - verboten Unterscheiden: deklarierter Typ - tatsächlicher Typ einer Variablen Objektidentität vs. Objektgleichheit rect1: Rectangle := new Rectangle(); rect2: Rectangle := new Rectangle(); rect1 o Rectangle rect12 o Rectangle Objektgleichheit (gleiche Initialisierung oder kopieren der Attr.) rect1 := rect2; rect1 o Rectangle Objektidentität rect12 o Rectangle (zuweisen) Abstrakte Klassen Enthalten deklarierte, aber noch nicht implementierte Methoden Instanzierung nicht möglich Deklarierte Methoden müssen in jeder Unterklasse vorhanden sein, werden aber unterschiedlich implementiert Vorteile: einheitliche Schnittstelle, Client kann unabhängig von Server programmiert werden Beispiel: Geometrische Figur berechneFläche Kreis Rechteck Dreieck Vorteile OO Strukturierung der Programme sehr gut unterstützt Wiederverwendung, Erweiterbarkeit siehe auch: abstrakter Datentyp, dynamische Bindung, abstrakte Klasse Nachteile OO Hoher Einarbeitungsaufwand (OO-Denkweise, Klassenbibliotheken) Wegen dynamischer Speicherverwaltung oft höherer Speicherbedarf und längere Laufzeit 1.2. Objektorientierte Modellierung PPS 1.2-1 Vom Problem zum Programm Analyse Einarbeitung in Anwendungsgebiet Beschreiben von Anwendungsfällen Erstellen eines objektorientierten Modells der realen Welt Spezifikation der Funktionalität des künftigen Softwaresystems Annahme einer perfekten Technik Entwurf Übertragung des Modells der realen Welt in die Welt der Software Berücksichtigung der vorhandenen Technik und Programmiersprache Algorithmische Beschreibung der Funktionalität Implementierung Software-Architektur wird zum realen Programm PPS 1.2-2 Unified Modeling Language (UML) Sprache und grafische Notation zur Spezifikation, Visualisierung, Konstruktion und Dokumentation von (Software)systemen Durchgängige Unterstützung für Analyse und Design durch aufeinander abgestimmte Modelltypen Anwendungsfalldiagramm Klassendiagramm Kollaborationsdiagramm Sequenzdiagramm und andere Geeignet für objektorientierte Softwareentwicklung UML ist keine Programmiersprache! Aber ex. Werkzeuge, die automatische Codeerzeugung unterstützen Vorgehensmodell ist nicht Bestandteil der UML PPS 1.2-3 Geschichte der UML Ca. 1989-1994 Forschungsarbeiten zu objektorientierten Modellierungsansätzen Darauf aufbauend ab 1994/95 Entwicklung der UML durch Grady Booch, Jim Rumbaughund Ivar Jacobson (Firma: Rational Software) Seit 1995 Unterstützung durch Object Management Group (OMG) - Entwicklung eines Standards 1996: Version 0.9 Aktuell: Version 1.3 1997: Version 1.0 In Arbeit: Version 2.0 OMG umfaßt >800 Firmen -> UML ist weit verbreitet PPS 1.2-4 Klassendiagramm Beschreibt Klassen und ihre statischen Beziehungen untereinander Beziehungen zwischen Klassen stehen stellvertretend für Beziehungen zwischen Objekten Darstellung von Klassen kann unterschiedlich detailliert erfolgen (evtl. Angabe von Typ, Initialwert, Zusicherungen): Rechteck Rechteck Rechteck anzeigen() verschieben() löschen() Rechteck x: int = 0 x y width breite: int {breite>0} höhe: int {höhe<=breite} anzeigen() verschieben(dx:int, dy:int) löschen() Objekte Mitunter werden in Klassendiagrammen auch Objekte dargestellt. Zur Unterscheidung von Klassennamen werden Objektnamen unterstrichen. Evtl. Angabe von zugehöriger Klasse und Attributwerten Beispiele: rect: Rechteck rect Rechteck x=0 y=0 :Rechteck << instance of >> rect PPS 1.2-6 Assoziationen Person Firma Firma besitzt 1 0..* beschäftigt 0..1 arbeitgeber 0..* Person arbeitnehmer beschäftigt arbeitet bei 0..1 Schrank 0..* Person Assoziationen beschreiben allgemeine Beziehungen zwischen Objekten werden auch Benutzt-Beziehungen genannt möglich: ungerichtete, bidirektionale Beziehungen PPS 1.2-7 Aggregation auch: Teil-Ganzes-Beziehung, Hat-Beziehung Eine Aggregation ist die Zusammensetzung eines Objektes aus einer Menge von Teilobjekten ist Spezialfall der Assoziation Unternehmen besteht aus 1 1..* Abteilung besteht aus 1 besteht aus Abteilung 1..* arbeitet für 1..* Mitarbeiter Mitarbeiter 1..* PPS 1.2-8 Komposition Spezialfall der Aggregation, bei dem die Einzelteile vom Aggregat existenzabhängig sind Markierung durch ausgefüllte Raute Vorderseite 1 hat Zettel 1 1 hat Rückseite 1 PPS 1.2-9 Methodenaufrufe bei Aggregationen Typische Programmstruktur: Methoden zur Zusammenarbeit mit anderen (´fremden´) Objekten werden vom Gesamtobjekt zur Verfügung gestellt Der Aufruf einer solchen Methode bewirkt den Aufruf geeigneter Methoden der Teilobjekte. Dazu enthält die Implementierung der Methode des Gesamtobjekts entsprechende Methodenaufrufe an die (im Klassendiagramm nicht sichtbar) Teilobjekte. Beispiel: Der Warenwert eines Einkaufskorbes berechnet sich als Summe der Einzelpreise. PPS 1.2-10 Rekursive Assoziation Direkte Rekursion: Mitarbeiter name zimmernummer manager sachbearbeiter * 1 führt Indirekte Rekursion: hat 1 * Patient familienangehöriger Person PPS 1.2-11 Mehrgliedrige Assoziation Zug datum zugnummer Reservierung Platz 1..* 1 wagennr platznr 1..* Fahrgast name Assoziationen zwischen > 3 Klassen analog Gleiche Klasse kann mehrfach an einer Assoziation beteiligt sein PPS 1.2-12 Implementierung von Assoziationen meist mittels Attributen in den beteiligten Klassen häufig: Attributname = Rollenname in der Assoziation gegebenenfalls Verwendung von Arrays oder anderen Sammlungsklassen Person 1 besitzt eigentümer class Person { ... Schrank[] einrichtung; ... } 0..* einrichtung Schrank class Schrank { ... Person eigentümer; ... } PPS 1.2-13 Attributierte Assoziation Assoziation, der Eigenschaften zugeordnet sind diese Eigenschaften charakterisieren weder die eine noch die andere Klasse, sondern die Assoziation selbst Modellierung durch Assoziationsklasse Unternehmen 1..* name anschrift 1..* Mitarbeiter name anschrift Arbeitsverhältnis von: Datum bis: Datum PPS 1.2-14 Vererbung auch: Ist-Beziehung Unterklasse ist Spezialisierung der Oberklasse Objekte abgeleiteter Klassen sollen jederzeit anstelle von Objekten ihrer Basisklasse eingesetzt werden können Oberklasse ist Generalisierung der Unterklasse Unterscheidungsmerkmal zwischen Ober- und Unterklasse: Diskriminator Diskriminator ist ´virtuelles Attribut´ (durch Zugehörigkeit zur einen oder anderen Unterklasse wird eine Eigenschaft des Objekts beschrieben) Zuordnung der Attribute und Methoden zur Ober- oder Unterklasse sollte nach inhaltlichen Gesichtspunkten erfolgen (nicht: maximale Wiederverwendung) PPS 1.2-15 Vererbung - Notation Diskriminator1 Oberklasse Diskriminator3 Unterklasse1 Unterklasse5 Diskriminator2 Unterklasse2 Unterklasse3 Unterklasse4 Diskriminator muss nicht angegeben werden auch bei gleichem Diskriminator sind Einzelpfeile zulässig PPS 1.2-16 Vererbung - Beispiel GeomFigur {abstrakt} x,y: int sichtbar: bool anzeigen() {abstrakt} entfernen() {abstrakt} verschiebeZu(nx,ny) Figurenform Kreis Rechteck Dreieck radius {radius > 0} a {a>0} b {b>0} a {0<a<b+c} b {0<b<a+c} c {0<c<a+b} setRadius(r) anzeigen() entfernen() setKanten(a,b) anzeigen() entfernen() setKanten(a,b,c) anzeigen() entfernen() PPS 1.2-17 Quadrat/Rechteck-Problem I Rechteck a {a>0} b {b>0} setKanten(na,nb) anzeigen() entfernen() Quadrat {a=b} Nachteile: Redundanz (b ist überflüssig) Zusicherung verwendet Attribute der Oberklasse -> Einhaltung durch Methoden der Oberklasse nicht garantiert (Zusicherung dort nicht bekannt) PPS 1.2-18 Quadrat/Rechteck-Problem II Quadrat a {a>0} setA(na) anzeigen() entfernen() Nachteile: ex. kein Diskriminator Zuweisung q=r ist zulässig, aber inhaltlich nicht sinnvoll Rechteck b {b>0} setB(nb) anzeigen() entfernen() -> fehleranfällig ->Ungeeignete Modellierung PPS 1.2-19 Quadrat/Rechteck-Problem III Rechteck a {a>0} b {b>0} setKanten(a,b) anzeigen() entfernen() isQuadrat():bool Beste Variante, hat trotzdem Nachteil der Redundanz Günstig: Keine Unterscheidung zwischen Rechtecken, die aufgrund ihrer Kantenlänge ´zufällig´ Quadrate sind und ´richtigen´ (entsprechend klassifizierten) Quadraten PPS 1.2-20 Klassenhierarchien GeomFigur Strecke Kreis 2dimGeomFigur Rechteck Dreieck Kugel 3dimGeomFigur Quader abstrakte Klasse konkrete Klasse PPS 1.2-21 Mehrfachvererbung Klasse kann mehr als eine Oberklasse besitzen Einfachvererbung - Klassenhierarchie, Mehrfachvererbung - azyklischer Graph Fahrzeug name Wasserfahrzeug Windgetriebenes Fahrzeug Segelboot Mehrfachvererbung ist problematisch PPS 1.2-22 Klassenattribute Beschreiben Eigenschaft der Klasse Alle Objekte der Klasse haben Zugriff auf dieses Attribut (lesen den gleichen Wert) weiterhin ex. Klassenmethoden Haus anzHäuser adresse getAnzHäuser() getAdresse PPS 1.2-23 Vom Problem zum Modell 1) Grammatikalische Inspektion der Spezifikation Substantive - Klassen, Objekte Verben - Methoden ´hat ein´, ´besteht aus´ - Aggregationen ´ist ein´ - Vererbungsbeziehungen 2) CRC-Karten Class-Responsibilities-Collaborators = Klasse - Verantwortlichkeiten - Beteiligte 3) Analyse von Anwendungsfällen engl.: use case PPS 1.2-24 Anwendungsfall beschreibt externes Systemverhalten in begrenzter Arbeitssituation beschreibt was das System leisten soll, aber nicht wie Anwendungsfall umfaßt meist mehrere Varianten, die als Szenarien bezeichnet werden Anwendungsfall wird durch Akteur (häufig Nutzer in bestimmter Rolle) initiiert und führt zu außerhalb des Systems sichtbarem Ergebnis Einsatz in Analysephase: Erfassen der Aufgabenstellung und Abstimmung mit dem Auftraggeber PPS 1.2-25 Beschreibung eines Anwendungsfalls Umfaßt (teils optional): Akteure Vor- und Nachbedingungen, Invarianten Nicht-funktionale Anforderungen (z.B. Antwortzeit, Priorität) Ablaufbeschreibung (wichtigster Teil, stets vorhanden) Ausnahmen, Fehlersituationen Variationen Dienste (notwendige Klassen, Methoden - für späteres Design) Verfasser, verwendete Materialien Offene Fragen, Alternativen, Entwurfsentscheidungen Verweise auf verwandte Diagramme PPS 1.2-26 Anwendungsfall - Beispiel Af2 Vertrag schließen und Kfz-Übergabe Akteure: Kunde, Kundenbetreuer Auslöser: Kunde möchte sein reserviertes Kfz abholen Ablauf: 1. Reservierung identifizieren 2. Vertrag erstellen 3. Kfz übergeben PPS 1.2-27 Anwendungsfalldiagramm Übersicht zu den verschiedenen Anwendungsfällen beschreibt Beziehungen zwischen Akteuren und Anwendungsfällen Buchausleihe ( .| . verlängern .| . ( Nutzer ausleihen .| . ( Bibliothekar registrieren Besucher recherchieren PPS 1.2-28 Verhaltensdiagramme beschreiben zeitabhängiges Verhalten des Systems unterscheiden: Zustandsdiagramm Zustände und Zustandsübergänge des einzelnen Objekts Aktivitätsdiagramm Beschreibung von Abläufen in verschiedenem Kontext Kollaborationsdiagramm Zusammenarbeit zwischen Objekten, Betonung Beziehungen Sequenzdiagramm Zusammenarbeit zwischen Objekten, Betonung Zeit PPS 1.2-29 Zustandsdiagramm zeigt für ein Objekt die Folge der möglichen Zustände und Zustandsübergänge Beschreibung durch endlichen Automat . Beispiel: Objekt = Ticket Benutzt ausgeben abgelaufen Verfügbar reserv. Reserviert kaufen Verkauft absagen zurückgeben PPS 1.2-30 Aktivitätsdiagramm zur Beschreibung von Abläufen in verschiedenem Kontext beschreibt Ausführungsreihenfolge von Aktivitäten parallel oder sequentiell nächste Aktivität kann vom Ergebnis der vorherigen abhängen Aktivitäten können Methoden oder komplexere Operationen sein eventuell Zuordnung der Aktivitäten zur ausführenden Klasse PPS 1.2-31 Kollaborationsdiagramm beschreibt Zusammenarbeit zwischen Objekten in begrenzter Situation (z.B. Anwendungsfall) beschreibt Nachrichtenaustausch einschließlich Datenaustausch (Argumente der Methoden) im Gegensatz zum Sequenzdiagramm stehen die Beziehungen zwischen den Objekten und nicht der zeitliche Verlauf im Vordergrund für den Nachrichtenaustausch benötigt der Sender einen Verweis auf den Empfänger : Assoziation vom Sender zum Empfänger Verweis wird durch Nachrichtenaustausch übermittelt Empfänger ist neu erzeugtes Objekt Empfänger = Sender PPS 1.2-32 Kollaborationsdiagramm - Beispiel << parameter >> b :Bestellung 1.1.*[i=1..*]: bpos:=gibBestellPos() ... 1:reserviere(b) :Reservierung 1.1.3: bpos:=reserviere(artikel,anzahl) 1.1.1: artikel:=gibArtikel() 1.1.2: anzahl:=gibAnzahl() :Lager << local >> bpos :Bestellposition PPS 1.2-33 Kollaborationsdiagramm - Notation Syntax der Nachrichtenbezeichnung: [vorgängerBedingung /][sequenzausdruck] : [antwort :=] methodenname (parameterliste) sequenzausdruck beschreibt Reihenfolge der Nachrichten Nachrichten, die während der Bearbeitung der Nachricht Nummer x gesendet werden, erhalten Nummern x.1, x.2 usw. vorgängerBedingung ist Aufzählung der Nachrichten, die vorher gesendet werden müssen (Bsp. 2.3, 3.1/ 4.2:) ´*´ bezeichnet wiederholtes Senden der gleichen Nachricht Paralleles Senden: 1.2.*||[i:=1..n]: Bedingtes Senden: 1.2.* [i>5]: PPS 1.2-34 Sequenzdiagramm stellt gleiche Information wie Kollaborationsdiagramm dar, aber mit Betonung des zeitlichen Ablaufs objekt 1 Selbstdelegation new() objekt 2 objekt 1 nachricht() antwort delete() PPS 1.2-35 Sequenzdiagramm - Beispiel :Reservierung reserviere(b) b:Bestellung bpos:Bestellposition :Lager * gibBestellPos() bpos * gibArtikel() artikel * gibAnzahl() anzahl reserviere(artikel, anzahl) PPS 1.2-36 Formen des Nachrichtenaustauschs Synchronmit Rückantwort (auch: sequentiell, Normalfall in Sender wartet, bis Methodenausführung beendet objektorientierter Programmierung): Synchron ohne Rückantwort: Sender wartet, bis Empfänger die Nachricht angenommen hat Asynchron: Nachricht wird an Warteschlange des Empfängers geschickt, Sender arbeitet sofort weiter Eingeschränkt: Abbruch, falls der Empfänger die Nachricht nicht sofort annimmt Zeitabhängig: Abbruch, falls der Empfänger die Nachricht nicht innerhalb einer vorgegebenen Zeit annimmt PPS 1.2-37 Zusammenfassung Modellierung wird überwiegend in Analyse/Design-Phasen eingesetzt objektorientierte Modellierung ist eine Form der Modellierung Modelle sind abstrakte Beschreibungen der realen Welt existierender Software zu konstruierender Software verschiedene Modelltypen beschreiben verschiedene Aspekte des Systems und ergänzen einander Vorgehensmodell bestimmt, welche Modelltypen in welcher Reihenfolge wie detailliert erstellt werden (nicht Bestandteil der UML) PPS 1.2-38 1.3. Einführung in Java PPS 1.3-1 Objektorientierte Programmiersprachen erste Ideen gehen zurück auf Simula 67 (Datenabstraktion, Klassen) erste und rein objektorientierte Sprache: Smalltalk 80 C++: Erweiterung von C um objektorientierte Konstrukte, erste Version 1984 (danach weiterentwickelt), umfangreiche Sprache, weit verbreitet Eiffel (ca. 1990): integriert Zusicherungen, einfacher als C++, relativ geringe praktische Bedeutung CLOS (1988): integriert objektorientiertes und funktionales Programmieren Weitere Sprachen: Ada 95, Oberon, Modula-3, ... PPS 1.3-2 Entwicklung von Java 1991-1992 Green-Projekt (James Gosling, Patrick Naughton), Ziel: Entwicklung von Hard-/Software für Konsumelektronik -> Interpreter Oak 1992 Firmengründung zur Vermarktung des Prototyps Star Seven (*7) -> erfolglos 1994 Web Browser HotJava, verwendet Oak 1995 Umbenennung von Oak in Java, Integration in Netscape Navigator 1996 Java Development Kit 1.0, Gründung von JavaSoft rasantes Wachstum des Interesses an Java 1998 JDK 1.2, neue Bezeichnung Java 2 Platform 2000 JDK 1.3 (Kestrel-Projekt), Geschwindigkeitsgewinn PPS 1.3-3 Vorteile von Java Portabilität Java Virtual Machine JVM, Java Bytecode alle Datentypen in Java sind exakt festgelegt Unterstützung für Code-Mobilität (Applets) Objektorientierung C-ähnliche Syntax (keine Zeiger, aber Verweise) Robustheit Garbage Collection, Ausnahmebehandlung Einschränkung automatischer Typkonvertierung Sicherheitskonzept Unterstützung für Nebenläufigkeit (Threads) Unterstützung für grafische Oberflächen Umfangreiche Klassenbibliothek PPS 1.3-4 Das JVM-Konzept Programm Compiler (javac) Bytecode Interpreter (java) Interpreter Just-In-Time Compiler Rechner (JIT Compiler) Rechner PPS 1.3-5 Beispiel: Hello World Erstellen der Datei Hello.java public class Hello { public static void main(String args[]) { System.out.println("Hello World!"); } } Übersetzen des Quelltextes javac Hello.java -> Hello.class Ausführen des Programms java Hello PPS 1.3-6 Lexikalische Elemente 1 Unicode Zeichen werden in 2 Byte kodiert Kompatibel zu ASCII-Zeichensatz char/String-Konstanten sowie Bezeichner im Programm dürfen Umlaute und Sonderzeichen enthalten Bsp.: übertrag und \u00FCbertrag sind identisch Bezeichner sollten mit Buchstabe, dürfen auch mit ´_´ oder ´$´ beginnen Schlüsselwörter sind nicht zulässig Klassennamen groß, z.B. EineKlasse Variablen-, Attribut- und Methodennamen klein, z.B. eineMethode Konstantennamen vollständig groß, z.B. LIMIT PPS 1.3-7 Lexikalische Elemente 2 Kommentare // Einzeiliger Kommentar bis Zeilenende /* MehrzeiligeKommentare dürfen nicht geschachtelt werden */ /** * Dokumentationskommentare für javadoc * beschreiben Methoden etc. verbal und kennzeichnen * Parameter und Rückgabewerte. * <i> HTML </i> ist zulässig. */ Weitere Unterschiede zu C: Kein Präprozessor -> kein #define, #include, #ifdef Zeilen können nicht mit \ verkettet werden PPS 1.3-8 Primitive Datentypen boolean 1 bit true, false char 16 bits Unicode-Zeichen byte 8 bits ganze Zahl m. Vorz. short 16 bits -"- int 32 bits -"- long 64 bits -"- float 32 bits Fließkommazahl double 64 bits -"- Variablen haben stets einen definierten Wert: Attribute werden mit 0 (bzw. 0.0 etc.) initialisiert Lokale Variablen -> Datenflußanalyse durch Compiler PPS 1.3-9 C- vs Java-Datentypen in Java nicht vorhanden: Zeiger Aufzählungstypen (enum) Verbundtypen (struct und union) Bitfelder Typdefinitionen sizeof-Operator unsigned, short int, long int Neu in Java boolean NaN = Not A Number (undefiniert, entsteht bei Division durch 0) POSITIVE_INFINITY, NEGATIVE_INFINITY PPS 1.3-10 Arrays Arrays sind spezielle Objekte -> werden zur Laufzeit mit new erzeugt Länge wird beim Erzeugen (zur Laufzeit!) festgelegt und kann danach nicht mehr verändert werden Zur Laufzeit geprüft: 0 <= indexausdruck < array.length Automatische Initialisierung Bilden von Unterklassen nicht möglich Indextyp ist int Bsp. 1: int[] a; a = new int[100]; //Deklaration // Erzeugung Bsp. 2: boolean[][] b; b = new boolean[n][m]; Bsp. 3: int[] a = {5,9,2,3}; int[][] b= { {0}, {1,2}, {1,2,3} } PPS 1.3-11 Zeichenketten Zeichenketten sind Objekte der Klassen java.lang.String - konstante Zeichenketten, oder java.lang.StringBuffer - veränderliche Zeichenketten Bsp.: String s1 = "Meine "; // oder: new String("Meine "); StringBuffer s2 = new StringBuffer("Zeichenkette"); Verkettung und Automatische Konvertierung: for (int i=1; i<10; i++) System.out.println(s1+i+"-te"+s2); Methoden für String: length(), charAt(), equals(), etc. Methoden für StringBuffer: length(), append(), insert(), etc. PPS 1.3-12 Typkonvertierung Erweiternde Konvertierungen: byte short int long float double char Erweiternde Konvertierung erfolgt automatisch bei: Zuweisungen arithmetischen Operationen Methodenaufruf (aktuelle vs formale Parameter) Einschränkende Konvertierung erfordert explizites Casting: double x=3.0, y=2.0; int i = (int) (x/y); PPS 1.3-13 Ausdrücke und Operatoren Ähnlich C: Arithmetische Operatoren Vergleichsoperatoren (Ergebnistyp boolean, auch für Objekte) Logische Operatoren (für boolean) && bzw. || stehen für Kurzschlußauswertung & bzw. | stehen für vollständige Auswertung Bitoperatoren Zuweisungsoperatoren (=, += etc., erzeugen Ergebnis) Bedingter Ausdruck (a>0 ? b=a : b=-a) Operatoren für Objekte: instanceof, new, Zugriff (.) PPS 1.3-14 Anweisungen Ähnlich C: Block Variablendeklaration Ausdruck (nur: ++, --, Zuweisung, Methodenaufruf,new) if, switch (nur boolesche Bedingungen) while, do-while (nur boolesche Bedingungen) for Variablendeklarationen, Komma-Operator zulässig nur boolesche Bedingungen break, continue (auch mit Label) return (Compiler prüft Vorhandensein) PPS 1.3-15 Blöcke und Variablendeklarationen Unterscheiden: Instanzvariablen (Attribute) Klassenvariablen (Klassenattribute) Lokale Variablen, Parameter Jede Variable hat einen (statischen) Typ Lokale Variablen dürfen in Blöcken deklariert werden Lokale Variablen dürfen sich nicht gegenseitig verdecken! Das Verdecken von Instanz-/Klassenvariablen durch lokale Variablen und Parameter ist dagegen zulässig Konstanten werden durch das Schlüsselwort final gekennzeichnet, z.B. final int LIMIT = 100; PPS 1.3-16 1.4. Objektorientierte Programmierung in Java PPS 1.4-1 Definition von Klassen [public] class Klassenname { Attribut- und Methodendefinitionen } mit public: Filename = Klassenname.java ohne public: Zugriff nur innerhalb des Files (Pakets) möglich Beispiel: class Point { int x, y, color; void moveTo(int newX, int newY) { x=newX; y=newY; } } PPS 1.4-2 Erzeugen von Objekten Erforderlich: 1) Klassendefinition 2) Objektdeklaration (analog Variablendekl.) 3) Objekterzeugung (new) Beispiel: //Klassendeklaration siehe vorige Folie Point punktA; //Objektdeklaration punktA = new Point(); //Objekterzeugung Objekterzeugung bewirkt: Allokierung von Speicherplatz Rückgabe eines Verweises Aufruf eines Konstruktors zur Initialisierung des Objekts PPS 1.4-3 Programmstruktur Betrachten im weiteren Anwendungen (Applikationen); daneben existieren Applets Ein (einfaches) Java-Quellprogramm umfaßt mehrere java-Dateien, die jeweils in class-Dateien übersetzt werden (z.B. javac *.java) In einer Datei (z.B. in Start.java) muß eine Methode mit der Signatur public static void main(String[] args) deklariert sein Bei Aufruf von java Start wird diese Methode aktiviert main kann dann Objekte anderer Klassen erzeugen und durch Senden von Nachrichten in die Berechnung einbeziehen PPS 1.4-4 Instanzvariablen und -methoden Zur Unterscheidung von Klassenvariablen/-methoden werden Attribute in Java häufig als Instanzvariablen und Methoden als Instanzmethoden bezeichnet Zugriff auf Instanzvariablen und -methoden erfolgt durch Anwendung des Punkt-Operators auf das Objekt, z.B. punktA.color, punktA.moveTo(3,4) In Java können nur Methoden Programmcode enthalten; globale Funktionen (wie in C) gibt es nicht Im Gegensatz zu Funktionen beziehen sich Instanzmethoden stets auf ein Objekt und damit auf aktuelle Attributwerte PPS 1.4-5 Parameterübergabe Java verwendet call-by-value (Wertübergabe) Primitive Datentypen können nicht verändert werden bei Objekten können nur Attribute verändert werden, nicht das Objekt selbst Lokale Zuweisungen können durch final verboten werden void beispiel (int number, final int number2, Point punkt) { number = 7;// außerhalb der Methode nicht geändert number2 = 8; // Fehlermeldung punkt.x = 3; // Änderung auch außerhalb punkt = new Point(); // außerhalb keine Änderung punkt.x = 5;// außerhalb keine Änderung } PPS 1.4-6 Arrays als Parameter Bei formalen Parametern kann die Länge des Arrays offen gelassen werden: int sum(int[] a) { int erg = 0; for (int i=0; i<a.length; i++) erg += a[i]; return erg; } int [] myFeld; myFeld = new int[10]; int sum = sum(myFeld); PPS 1.4-7 Konstruktoren Konstruktoren haben den gleichen Namen wie die Klasse Konstruktoren haben keinen Ergebnistyp In einer Klasse können mehrere (überladene) Konstruktoren definiert sein Falls ein Konstruktor einen anderen Konstruktor aufruft, so muß dieser Aufruf die erste Anweisung des Konstruktors sein Ist für eine Klasse kein Konstruktor definiert, so wird ein impliziter Konstruktor verwendet PPS 1.4-8 Das Schlüsselwort this this ist einVerweis auf das aktuelle Objekt Verwendung: Aufruf einer Methode mit dem aktuellen Objekt als Parameter, z.B. anderesObjekt.dessenMethode(this) Zugriff auf überdeckte Variablen, z.B. void moveTo(int x, int y) { this.x = x; this.y = y; } Zugriff auf andere Konstruktoren einer Klasse this(x,y) PPS 1.4-9 Beispiel: Konstruktoren class Point { int x, y, color; Point(int x, int y) { this.x = x; this.y = y; color = 0; } Point(int x, int y, int color) { this(x,y); this.color = color; } } PPS 1.4-10 Klassenvariablen und -methoden werden durch das Schlüsselwort static gekennzeichnet Zugriff durch Klasse.variable bzw. Klasse.methode(..) Gültigkeitsbereich Klassenvariablen = gesamtes Programm Klassenvariablen werden nur einmal für die Klasse, nicht für jedes einzelne Objekt angelegt Anwendung Klassenvariablen: Definition von Konstanten static final double PI = 3.14; Klassenmethoden können nicht auf Instanzvariablen und -methoden ihrer Klasse zugreifen Anwendung Klassenmethoden: Berechnung mathematischer Funktionen PPS 1.4-11 Beispiel: Klassenvariablen public Kunde { static private int anzKunden = 0; String name; Kunde(String name) { this.name = name; anzKunden++; } static int gibAnzKunden() { return anzKunden; } } PPS 1.4-12 Initialisierung von Klassenvariablen Klassenvariablen werden bei der Deklaration oder durch statische Konstruktoren initialisiert In beiden Fällen erfolgt die Wertzuweisung beim Laden der Klasse Initialisierungen werden in textueller Reihenfolge ausgeführt class Beispiel { static int i=3; static int j; static { j=3*i; } PPS 1.4-13 Vererbung nur Einfachvererbung möglich Kennzeichnung durch Schlüsselwort extends alle Klassen sind Nachfahren der Klasse java.lang.Object Zugriff auf Oberklasse durch Schlüsselwort super (Zugriff auf Konstruktoren und überschriebene Methoden) public class BlinkingPoint extends Point { boolean blinkt; public void blinkenAus() {blinkt = false;} public BlinkingPoint(int x, int y) { super(x,y); this.blinkt = false; } } PPS 1.4-14 Vererbung und Konstruktoren 1) Anlegen des Speicherbereiches, Initialisieren mit 0 2) Aufruf des passenden Konstruktors, dabei rekursive Anwendung der folgenden Regeln: a) Falls der Konstruktor mit einem Aufruf von super (oder this) beginnt, zunächst Aufruf des entsprechenden Konstruktors b) Falls a) nicht zutrifft und die Oberklasse keinen expliziten Konstruktor enthält, Aufruf des Default-Konstruktors der Oberklasse c) Falls a), b) nicht zutrifft und die Oberklasse einen parameterlosen Konstruktor enthält, Aufruf dieses Konstruktors d) Falls a), b), c) nicht zutrifft -> Fehlermeldung 3) Initialisierung der Attribute und lokalen Variablen des Konstruktors, falls Deklaration mit Zuweisung verbunden 4) Ausführung der Anweisungen des Konstruktors PPS 1.4-15 Vererbung und Überladen Überladene Methoden müssen sich in den Parametern (nicht nur im Ergebnistyp) voneinander unterscheiden Die Auswahl der Methode erfolgt zur Übersetzungszeit Falls eindeutig bestimmt, wird die Methode mit den passenden Parametern (Anzahl, Typ) ausgewählt Falls die Parameter verschiedener Methoden in Vererbungsbeziehung zueinander stehen oder anderweitig eine Typkonvertierung möglich ist, wird die Methode mit den speziellsten Parametern ausgewählt // Son sei Unterklasse von Father Son son = new Son(); public void test (Father father) {...}; public void test (Son son) {...}; test(son); // bewirkt Aufruf der Son-Variante PPS 1.4-16 Beispiel 1 zum Überladen public class Aufrufer { public void test(Son son) {...} // Son-Variante public void test(Father father) {...} // Father-Variante } public class Bsp { public static void main(String args[]) { Son son = new Son(); // Son sei Unterklasse von Father Father father = son; Aufrufer aufrufer = new Aufrufer(); aufrufer.test(father); } } Auswahl der Methode zur Übersetzungszeit -> Auswahl nach statischem Typ -> Es wird die Father-Variante von test aufgerufen PPS 1.4-17 Beispiel 2 zum Überladen public class Aufrufer { public void test(Father father) {...} // Bei nachträglichem Hinzufügen ohne Neuübersetzung von // Bsp.java nicht berücksichtigt: public void test(Son son) {...} } public class Bsp { public static void main(String args[]) { Son son = new Son(); Aufrufer aufrufer = new Aufrufer(); aufrufer.test(son); } } PPS 1.4-18 Überdecken von Variablen Vererbung kann zum Überdecken von Instanzvariablen führen class Point { int x, y, color; ... } class RealPoint extends Point { float x, y, color; ... } Überdeckte Variablen sind lebendig, aber nicht sichtbar Zugriff durch super möglich Auswahl erfolgt zur Übersetzungszeit (laut statischem Typ) Überdecken von Variablen sollte vermieden werden PPS 1.4-19 Beispiele zum Überdecken Bsp.1 class Point { int x, y, color; ... } class RealPoint extends Point { float x, y, color; int i = super.x; ... } Bsp.2 RealPoint rp = new RealPoint(); Point p = rp; float f = rp.x; int i = p.x; // Auswahl laut statischem Typ PPS 1.4-20 Typkonvertierung für Objekte Änderung des für den Compiler relevanten Typs RealPoint rp = new RealPoint(); Point p = rp; RealPoint rp2 = p; // Fehlermeldung des Compilers RealPoint rp2 = (RealPoint) p; Voraussetzung: neuer Typ = dynamischer Typ oder neuer Typ = Oberklasse des dynamischen Typs Andernfalls wird zur Laufzeit eine Ausnahme ausgelöst Dieser Fall sollte durch Verwendung von instanceof vermieden werden if (p instanceof RealPoint) RealPoint rp2 = (RealPoint) p; PPS 1.4-21 Beispiel 1 zur Typkonvertierung Zugriff auf Methoden und Attribute, die nur in der Unterklasse definiert sind class BlinkingPoint extends Point { boolean blinkt; public void blinkenAus() {...} } ... BlinkingPoint bp = new BlinkingPoint(); Point p = bp; if (((BlinkingPoint) p).blinkt) ((BlinkingPoint) p).blinkenAus(); PPS 1.4-22 Beispiel 2 zur Typkonvertierung Zugriff auf überdeckte Variablen class Point { int x, y, color; ... } class RealPoint extends Point { float x, y, color; ... } ... RealPoint rp = new RealPoint(); Point p = rp; int i = ((Point) rp).x; float f = ((RealPoint) p).x; PPS 1.4-23 Überschreiben, Überladen und Überdecken Überschreiben und Überladen beziehen sich auf Methoden; Überdecken bezieht sich auf Attribute beim Überschreiben haben alle Parameter den gleichen Typ, beim Überladen gibt es Unterschiede gleiche Parametertypen, aber unterschiedlicher Ergebnistyp -> Fehlermeldung durch Compiler überschriebene Methoden werden dynamisch gebunden, überdeckte Attribute werden statisch gebunden Konsequenz: bei Methoden ist kein Typcast nötig, falls neuer Typ = dynamischer Typ Klassenmethoden werden nicht überschrieben, sondern neu definiert Klassen- und Instanzmethoden mit gleicher Signatur sind nicht zulässig PPS 1.4-24 Beispiel zum Überschreiben, -laden, -decken class Point { int x = 0, y = 0; void move(int dx, int dy) { x += dx; y += dy; } int color; } class RealPoint extends Point { float x = 0.0f, y = 0.0f; void move(int dx, int dy) { move((float) dx, (float) dy); } void move(float dx, float dy) { x += dx; y += dy; } } PPS 1.4-25 Wrapper-Klassen Jedem primitiven Typ ist eine Wrapper-Klasse zugeordnet: int - Integer, float - Float etc. Nutzen: Die Wrapperklassen sind Unterklassen von Object und stellen zusätzliche Methoden zur Verfügung float f = 1.23f; String s = Float.toString(f) Viele Methoden (z.B. der Klasse Vector) verlangen als Parameter Objekte Keine automatische Konvertierung myVector.addElement(new Integer(7)); PPS 1.4-26 Das Schlüsselwort final bei Instanzvariablen, Klassenvariablen, lokalen Variablen: Definition von Konstanten Sicherstellen einer nur einmaligen Wertzuweisung bei Parametern: Verbot lokaler Zuweisungen bei Klassen: Verbot der Bildung von Unterklassen bei Methoden: Verbot des Überschreibens Nutzen (bei Klassen und Methoden): Vermeiden von Fehlern (versehentliches Überschreiben) Effizientere Implementierung (da statische Bindung möglich) PPS 1.4-27 Pakete Kennzeichnung durch package paketname; als erste Anweisung in allen Klassen des Pakets Nutzen: Strukturierung des Programms: Gruppieren von Quellfiles getrennte Namensräume Pakete können Klassen und/oder Unterpakete enthalten Paketstruktur entspricht Verzeichnisstruktur Paketname = Verzeichnisname Bezeichnung für Unterpakete: grossesPaket.unterpaket Klassen ohne package-Anweisung gehören alle zur gleichen (namenlosen) Klasse Pakete können archiviert werden (jar) PPS 1.4-28 Import-Anweisung Import aller Klassen eines Paketes durch import paketname.* (als erste Anweisung hinter package, sofern vorhanden) Import einer bestimmten Klasse durch import paketname.Klassenname Import eines Paketes impliziert nicht den Import der Unterpakete auch ohne Import-Anweisung kann über paketname.Klassenname.methode() auf fremde Klassen zugegriffen werden Import kann Datenkapselung nicht aufheben java.lang.* wird automatisch importiert PPS 1.4-29 Datenkapselung für Methoden und Attribute: private, public, protected, default Klasse Unterklasse Paket default X (gl. Paket) X private X protected X X X public X X X Welt X für Klassen: public, default default - nur innerhalb des Pakets sichtbar public - überall sichtbar Klasse nicht sichtbar -> Attribute/Methoden nicht sichtbar (unabhängig von deren Modifikator) PPS 1.4-30 Datenkapselung - private Als private gekennzeichnete Attribute / Methoden sind für Objekte anderer Klassen nicht sichtbar Trotzdem können die verschiedenen Objekte der gleichen Klasse gegenseitig auf ihre privaten Attribute/ Methoden zugreifen Als private gekennzeichnete Attribute / Methoden werden nicht vererbt Falls in der Unterklasse Attribute/Methoden mit gleichem Namen definiert werden, so handelt es sich um eine Neudefinition (kein Überschreiben, Überladen, Überdecken) PPS 1.4-31 Datenkapselung - public package paketA; package paketB; public class One { import paketA.One; public int a; public class Four extends One { } ... = a ... public class Two extends One { } ... public class Five { } ... = one.a ... public class Three { } ... } PPS 1.4-32 Datenkapselung - protected package paketA; package paketB; public class One { import paketA.One; public int a; public class Four extends One { } ... = a ... public class Two extends One { } ... public class Five { } ... = one.a ... public class Three { } ... } PPS 1.4-33 Datenkapselung - default package paketA; package paketB; public class One { import paketA.One; public int a; public class Four extends One { } ... = a ... public class Two extends One { } ... public class Five { } ... = one.a ... public class Three { } ... } PPS 1.4-34 Datenkapselung und Vererbung Beim Überschreiben ist es meist sinnvoll, die Zugriffsklasse beizubehalten. Falls doch Änderung, darf die Unterklasse die Sichtbarkeit erweitern, aber nicht einschränken, d.h. Oberklasse public -> Unterklasse public Oberklasse protected -> Unterklasse protected oder public Oberklasse default -> Unterklasse default, public oder protected Bei Überladen, Überdecken und Neudefinition gibt es keine solchen Einschränkungen PPS 1.4-35 Abstrakte Klassen Klassen müssen als abstract gekennzeichnet werden, wenn sie mindestens eine abstrakte Methode definieren oder erben Abstrakte Methoden beschreiben Schnittstellen (Signatur) Abstrakte Methoden müssen in Unterklassen überschrieben (implementiert) werden, erst dann ist Instanzierung möglich Konsequenz: abstract kann nicht mit final, static, private kombiniert werden abstract class Fahrzeug() { ... abstract void starte(); } class Fahrrad extends Fahrzeug { void starte() { steigeAuf(); } } PPS 1.4-36 Interfaces auch: Schnittstelle, Schnittstellenklasse Interfaces sind spezielle Klassen, die nur abstrakte Methoden und Konstanten enthalten explizite Kennzeichnung als public abstract beziehungsweise public final static kann entfallen möglich: public, default falls public: Filename = Name des Interfaces .java public interface KannBlinken { void blinkenEin(); void blinkenAus(); } public interface KannVerschieben { int GRENZE = 100; boolean move(int dx, int dy); } PPS 1.4-37 Implementierung von Interfaces Eine Klasse kann ein oder mehrere Interfaces implementieren Dazu muß sie die Interfaces unter implements aufführen und alle Methoden der Interfaces überschreiben (falls nur einige überschrieben werden, bleibt die Klasse abstrakt) Interfaces ermöglichen also Mehrfachvererbung für den wichtigen Spezialfall abstrakter Methoden Bei Namenskonflikten erhalten beide abstrakten Methoden die gleiche Implementierung - für sinnvolle Verwendung ist der Programmierer verantwortlich PPS 1.4-38 Beispiel: Interfaces public class BlinkingPoint extends GeomFigur implements KannBlinken, KannVerschieben { boolean blinkt; int x, y; public void blinkenEin() { blinkt = true; } public void blinkenAus() { blinkt = false; } public boolean move(int dx, int dy) { x+=dx; y+=dy; if (x > GRENZE || y > GRENZE ) return false; else return true; } PPS 1.4-39 Verwendung von Interfaces und abstrakten Klassen Möglich: Deklaration von Variablen mit dem Typ eines Interfaces/einer abstrakten Klasse Diesen Variablen können Objekte aller Klassen zugewiesen werden, die das Interface implementieren Der Compiler akzeptiert dann den Aufruf der Methoden des Interfaces Analog: Interfaces/abstrakte Klassen als Elementtyp von Feldern bzw. Typ formaler Parameter Typcast, instanceof sind anwendbar KannBlinken leuchtObjekt; if (...) leuchtObjekt = new BlinkingPoint(); else leuchtObjekt = new BlinkingArrow(); leuchtObjekt.blinkenEin(); // Nicht zulässig ist leuchtObjekt.move(3,4); PPS 1.4-40 Interfaces und Vererbung Bei implementierenden Klassen: Die Eigenschaft, ein Interface zu implementieren, wird vererbt, muß also in Unterklassen nicht erneut deklariert werden Zwischen Interfaces: Interfaces können Unterklasse von ein oder mehreren anderen Interfaces sein (hierarchisch) Für diese Form der Vererbung wird das Schlüsselwort extends verwendet PPS 1.4-41 Generisches Programmieren Programmieren auf hohem Abstraktionsniveau Programmiertechnik, die in Java mit bereits bekannten Mitteln (Interfaces, Überschreiben) realisiert wird Nutzen: Wiederverwendung von Programmcode Generische Datentypen (z.B. Liste, Stack) verwenden als Elementtyp Object (oder anderen abstrakten Typ) Einfügen etc. kann unabhängig vom konkreten Elementtyp ("generisch") programmiert werden Generische Methoden verwenden als Parametertyp Object (oder anderen abstrakten Typ) und sind damit auf Objekte beliebiger Klassen anwendbar intern häufig Aufruf abstrakter Methoden, die in den Unterklassen überschrieben sind Verwendung spezieller Methoden erfordert Typcast PPS 1.4-42 Speicherfreigabe Der vom Programm benutzte Speicher gliedert sich in Stack: Lokale Variablen und Parameter der in Ausführung befindlichen Methoden Halde (Heap): Objekte Speicher auf dem Stack wird nach Verlassen der Methode freigegeben (C und Java) In C wird Haldenspeicher mit malloc angefordert und mit free freigegeben -> fehleranfällig In Java wird Haldenspeicher mit new angefordert und automatisch freigegeben -> vereinfacht Programmierung PPS 1.4-43 Garbage Collector niedrigpriorisierter Hintergrundprozeß zur automatischen Freigabe unerreichbarer Objekte Objekt ist unerreichbar, wenn es keine Verweiskette vom Stack auf das Objekt mehr gibt Objekt kann unerreichbar werden durch Verlassen eines Blocks -> Entfernen Variablen vom Stack Zuweisungen: p = null oder p = p2 Unerreichbarkeit eines Vorgängerobjekts (z.B. Liste) GC ruft vor Freigabe die Methode protected void finalize() auf, falls vorhanden (Destruktor) expliziter Aufruf des Garbage Collectors durch System.gc() PPS 1.4-44 1.5. Ausnahmebehandlung PPS 1.5-1 Ausnahmen und Fehler Ausnahmen (Exceptions) sind "leichte" Fehler, nach denen eine Programmfortsetzung sinnvoll ist oder sein kann Fehler (Errors) führen zu Programmabbruch Throwable Exception RuntimeException NullPointerException Error IOException OutOfMemoryError FileNotFoundException PPS 1.5-2 Konzept der Ausnahmebehandlung Ausnahmen werden häufig von vordefinierten Java-Methoden ausgelöst und müssen vom Programmierer behandelt (abgefangen) werden weiterhin kann der Nutzer eigene Ausnahmen definieren Abfangen von Ausnahmen durch try-catch möglich: mehrere catch-Blöcke, finally try { // Anweisungsblock, der eine Ausnahme auslösen kann } catch (Exception e) { // Anweisungen zur Behandlung der Ausnahme } PPS 1.5-3 Weiterleiten von Ausnahmen 1. Fall: IOException (und eigene Ausnahmen) in Methode nicht behandelte Ausnahmen müssen unter throws deklariert werden, sonst Fehlermeldung durch Compiler void myMethod() throws ArrayOutOfBoundsException, MeineException {...} 2. Fall: RuntimeException können abgefangen werden, müssen aber nicht Auflistung unter throws kann entfallen Generell Ausnahmen wandern die Aufrufhierarchie hinauf bis sie abgefangen werden außen angekommen -> Java-Interpreter stoppt PPS 1.5-4 Beispiel: Abfangen von Ausnahmen int a, b, c; // Einlesen von b und c try { a = b / c; } catch (ArithmeticException e) { System.out.println("Bitte neuen Divisor eingeben: "); // erneutes Einlesen von c } PPS 1.5-5 Ausnahmen als Objekte Ausnahmen sind Objekte (enthalten Attribute, Methoden) alle Ausnahmeklassen sind von Throwable abgeleitet Klassen charakterisieren die Art der Ausnahme, Objekte die konkret im Programm aufgetretene Fehlersituation catch (BspAusnahme e) fängt alle Ausnahmen der Klasse BspAusnahme und ihrer Unterklassen ab für alle Ausnahmeklassen definiert: Konstruktor mit Übergabe einer Fehlermeldung Konstruktor ohne Übergabe einer Fehlermeldung Methode getMessage Definition eigener Ausnahmeklassen durch Bilden einer Unterklasse von Exception PPS 1.5-6 Auslösen von Ausnahmen erfolgt durch throws-Anweisung Integer value; public void setValue(Integer value) { if (value==null) throw new IllegalArgumentException("null übergeben"); this.value = value; } throws wird häufig in catch verwendet, um verschiedene Ausnahmesituationen zusammenzufassen beim Überschreiben von Methoden dürfen der throws-Klausel keine neuen Ausnahmen hinzugefügt werden; Weglassen von Ausnahmen ist zulässig PPS 1.5-7 2. Parallele, verteilte und nebenläufige Programmierung PPS 2.1-1 Gliederung 2.1. Überblick Begriffe, Architekturen, Programmiermodelle 2.2. Threadprogrammierung in Java 2.3. Applets 2.4. Remote Method Invocation Literatur zu 2.1.: C. Leopold: Parallel and Distributed Computing: A Survey of Models, Paradigms, and Approaches, Wiley, 2000 Literatur zu 2.2-2.4: Java-Lehrbücher PPS 2.1-2 2.1. Überblick Nebenläufige Programmierung Kennzeichen: mehrere Programmfäden befinden sich gleichzeitig in Abarbeitung Konsequenz: es existieren mehrere Programmzähler Ausführungsreihenfolge von Operationen aus verschiedenen Programmfäden ist dem Programmierer nicht bekannt kennt nur partielle Ordnung innerhalb eines Programmfadens Ausführung auf einem Prozessor (Pseudoparallelität) oder mehreren Prozessoren (Parallelität) möglich Motivation: Beschreiben probleminhärenter Parallelität (z.B. Simulationsaufgaben) PPS 2.1-3 Nebenläufigkeit - Probleme Programm muß für jede Ausführungsreihenfolge korrekt arbeiten Zeitkritischer Ablauf (engl.: race condition): Gleiches Programm kann auf gleicher Eingabe verschiedene Ausgaben erzeugen -> vermeiden Programmfäden nutzen gemeinsame Ressourcen (z.B. gemeinsame Variablen) Verklemmung(engl.: deadlock): gegenseitiges Warten auf Ressourcenfreigabe verhindert Weiterarbeit des Programms -> vermeiden PPS 2.1-4 Paralleles Rechnen Kennzeichen: gleichzeitige Ausführung von Berechnungen mit Ziel Geschwindigkeitsgewinn Einsatz mehrerer Prozessoren, die durch Netzwerk verbunden sind und zur Lösung der Aufgabe kooperieren parallele Architekturen sind meist homogen, haben oft gemeinsamen Speicher Konzentration auf eine Anwendung, d.h., parallele Operationen sind Teil des gleichen Programms Kommunikationsstruktur kann häufig statisch geplant oder zumindest abgeschätzt werden parallele Programme sind meist nebenläufig Typisches Anwendungsgebiet: wissenschaftliches Rechnen PPS 2.1-5 Verteiltes Rechnen Kennzeichen: räumliche Verteilung von Berechnungen auf verschiedene Rechner eines Netzwerkes, zwecks Nutzung entfernter Ressourcen Hard- und Softwareressourcen, z.B. Parallelrechner, Drucker, Datenbanken Architekturen sind meist heterogen und dynamisch, haben keinen gemeinsamen Speicher betrachtet System aus mehreren, getrennt entwickelten, Anwendungen, die gemeinsame Ressourcen nutzen und eventuell kooperieren => Paralleles, verteiltes und nebenläufiges Rechnen sind verwandte Gebiete mit vielen Überschneidungen und Gemeinsamkeiten PPS 2.1-6 Architektur 1: Feldrechner Steuerrechner PPS 2.1-7 Architektur 2: Parallelrechner mit gemeinsamem Speicher Gemeinsamer Speicher P P P P P P M M M M M M PPS 2.1-8 Architektur 3: Parallelrechner mit verteiltem Speicher P P P M M M P P P M M M P P P M M M PPS 2.1-9 Architektur 4: Verteiltes System PPS 2.1-10 Datenparallelität paralleles Programmiermodell Grundidee: parallele Anwendung der gleichen Operation auf verschiedene Daten Daten werden auf Prozessoren (Speicher) verteilt Einfache Variante (Feldrechner): Operationen sind elementar -> nur ein Programmzähler Erweiterte Variante (Parallelrechner): Operationen sind komplex, aber unabhängig voneinander keine Kommunikation während der Ausführung einer Operation nach Operationsausführung Synchronisation Sprachen: High Performance Fortran, HPF-2, C*, HPJava PPS 2.1-11 Datenparallelität - Beispiel !HPF$ INDEPENDENT Begin FORALL (I=1:3) a(I) = b(I) b(1) b(2) b(3) a(1) a(2) a(3) d(1) d(2) d(3) c(1) c(2) c(3) c(I) = d(I) END FORALL End PPS 2.1-12 Gemeinsamer Speicher (Programmiermodell) Thread Thread Thread Thread Gemeinsamer Speicher Thread Thread Programmfäden (Threads) kommunizieren indirekt durch Lesen/Schreiben gemeinsamer Variablen Zeitkritische Abläufe und Deadlocks müssen durch Synchronisation vermieden werden Gemeinsamer Speicher kann physisch existieren oder durch Software nachgebildet werden für nebenläufige und parallele Programmierung PPS 2.1-13 Gemeinsamer Speicher - Formen Thread-Programmierung (z.B. Pthreads, Java Threads): explizite Erzeugung der Threads und Zuweisung von Aufgaben durch den Programmierer Sprachkonstrukte zur Synchronisation und Beeinflussung des Scheduling Scheduling = räumliche und zeitliche Zuordnung der Threads zu Prozessoren Direktivenbasierte Programmierung (z.B. OpenMP): Compiler übernimmt Threaderzeugung und Aufgabenverteilung Programmierer beschreibt Parallelitätspotential und notwendige Synchronisationen problemnah (z.B. durch parallele Schleifen) PPS 2.1-14 Nachrichtenaustausch engl.: message passing Begriff hat andere Bedeutung als im OO-Programmieren! Prozesse kommunizieren durch Senden und Empfangen von Nachrichten, es existiert kein gemeinsamer Speicher Kommunikation kommt nur zustande, wenn passende Sende- und Empfangsoperationen ausgelöst wurden Kommunikation erfolgt zwischen 2 Prozessen, muß statisch geplant werden und impliziert Synchronisation wichtigstes Modell der parallelen Programmierung Bibliotheken: Message Passing Interface, MPI-2, PVM PPS 2.1-15 Nachrichtenaustausch - Beispiel char msg[20]; int me, total, tag; MPI_Status status; ... MPI_Comm_rank(MPI_COMM_WORLD, &me); MPI_Comm_size(MPI_COMM_WORLD, &total); if (me==0) { strcpy(msg, "Gruesse von Prozess 0"); MPI_Send(msg, strlen(msg)+1, MPI_CHAR, 1, tag, MPI_COMM_WORLD); } else if (me==1) { MPI_Recv(msg, 20, MPI_CHAR, 0, tag, MPI_COMM_WORLD, &status); ... } PPS 2.1-16 Client/Server wichtigstes Paradigma des verteilten Rechnens beschreibt asymmetrische Beziehung zwischen Prozessen Netzwerk Client Server Ressource Klienten können auf Ressource nur über die vom Server angebotenen Dienste zugreifen Server ist passiver Dienstanbieter Client ist aktive Seite, löst Interaktion aus während Ausführung des Dienstes wartet Client PPS 2.1-17 Client/Server 2 Client und Server können getrennt entwickelt werden meist existieren mehrere Klienten pro Server -> Diese können unter Verwendung von Threads gleichzeitig bedient werden! möglich: hierarchische Anordnung: Server nutzt während der Dienstausführung Dienste eines anderen Servers gleicher Rechner übernimmt (je nach Kontext) Rolle des Clients oder Servers - > Peer-to-Peer Programmierung mittels Sockets, Remote Procedure Call, Remote Method Invocation PPS 2.1-18 Mobiler Code Gegenstück zum Datenaustausch zwischen Prozessen Analogie: Versenden von Briefen vs. Reisen Hauptproblem: Sicherheit Varianten: Austausch von Programmtexten Migration in Abarbeitung befindlicher Prozesse Einsatzgebiete: Erweiterungen des Client/Server-Modells Mobile Agenten Parallele Mobile Agenten Automatische Migration PPS 2.1-19 Mobiler Code - Einsatzgebiete Erweiterungen des Client/Server-Modells: Remote Evaluation: Code wird zur Laufzeit vom Client zum Server geschickt (z.B. Übermittlung einer Funktion zwecks Berechnung durch leistungsfähigen Server) Code on Demand: Server verwaltet Datenbank mit Programmtexten und versendet sie bei Bedarf an die Klienten (Beispiel: Applets in Webseite) Mobile Agenten: Programm wandert während seiner Ausführung durch Netzwerk zwecks Nutzung entfernter Ressourcen; Programm entscheidet selbst, wann und wohin es migriert Agenten können kooperieren PPS 2.1-20 Messaging auch: Message-Oriented Middleware (MOM), z.B. Java Message Service API Verteilte Prozesse kommunizieren über gemeinsamen Speicher -> ermöglicht zeitliche Entkopplung von Sender und Empfänger Varianten: Message Queuing: Als gemeinsamer Speicher dienen Schlangen (Queues), in die Nachrichten eingefügt bzw. aus denen Nachrichten entnommen werden können im System existieren meist mehrere Schlangen mit unterschiedlichen Zugriffsrechten Publish-and-Subscribe: Produzenten stellen Klassen von Informationen zur Verfügung, Konsumenten können diese abonnieren (vergleichbar Mailinglisten) PPS 2.1-21 Verteilte Objekte Verteiltes Programmiermodell - betrachten Objekte, die sich auf verschiedenen Rechnern befinden (-> getrennte Adreßräume) Konzept: verbinden mit jedem Objekt einen eigenen Prozeß (Unterschied zu sequentiellem Java und Threads!) Prozeß verwaltet das Objekt im Sinne eines Servers andere Prozesse können den Programmcode nicht selbst ausführen, sondern müssen dazu die Dienste des Servers in Anspruch nehmen -> RMI = Remote Method Invocation = entfernter Methodenaufruf Systeme: CORBA, Java RMI, DCOM PPS 2.1-22 2.2. Java Threads Besonderheit Java: Threadprogrammierung ist in die Sprache integriert Motivation: Unterstützung nebenläufiger (nur sekundär paralleler) Programmierung Ein Programm (d.h., ein Prozeß des Betriebssystems) kann mehrere Threads umfassen Die Threads eines Programmes verfügen über gemeinsamen Speicher daneben existieren lokale Variablen der Threads Alle Threads arbeiten mit dem gleichen Programmtext, aber unterschiedlichen Programmzählern - > typisch: Verschiedene Threads bearbeiten verschiedene Methoden PPS 2.1-23 Threaderzeugung mittels Thread Die Klasse Thread des Pakets java.lang definiert Methoden zur Arbeit mit Threads: run, start, etc. Threaderzeugung mittels Thread: Bilden einer Unterklasse von Thread Überschreiben der vordefinierten Methode run mit der gewünschten Funktionalität des Threads Aufruf der von Thread geerbten Methode start -> bewirkt Start des Threads und impliziten Aufruf von run PPS 2.1-24 Beispiel 1 zur Threaderzeugung public class BspThread extends Thread { ... public void run() { System.out.println("Gruesse vom erzeugten Thread"); } } public class Bsp { public static void main(String[] args) { BspThread t = new BspThread(); t.start(); System.out.println("Gruesse vom Hauptprogramm"); } } PPS 2.1-25 Threaderzeugung mittels Runnable Da Java nur Einfachvererbung erlaubt, schließt die vorige Methode Vererbung nach inhaltlichen Aspekten aus Threaderzeugung mittels Runnable ist flexibler (aber etwas komplizierter): Runnable ist vordefiniertes Interface, enthält nur eine Methode: void run() Aufrufende Klasse erzeugt zwei Objekte: Nutzer-Thread einer eigenen Klasse und Hilfs-Thread der Klasse Thread Klasse des Nutzer-Threads implementiert Runnable Bei Erzeugung des Hilfs-Threads Übergabe des Nutzerobjekts als Argument des Konstruktors Aufruf der Methode start des Thread-Objekts PPS 2.1-26 Beispiel 2 zur Threaderzeugung public class NutzerThread extends ... implements Runnable { public void run() { System.out.println("Gruesse vom erzeugten Thread"); } } public class Bsp { public static void main(String[] args) { NutzerThread nutzerThread = new NutzerThread(); Thread hilfsThread = new Thread(nutzerThread); hilfsThread.start(); System.out.println("Gruesse vom Hauptprogramm"); } } PPS 2.1-27 Beenden von Threads 1 automatisch am Ende der run-Methode Direkter Abbruch (stop) durch andere Threads soll in JDK 1.3 nicht mehr verwendet werden (Problem: Ressourcenfreigabe) Andere Threads können durch Aufruf der Methode public void interrupt() zum Abbruch auffordern Thread kann durch public boolean isInterrupted() feststellen, ob er zum Abbruch aufgefordert wurde und gegebenenfalls die run-Methode beenden PPS 2.1-28 Beenden von Threads 2 Mit join() kann ein Thread auf die Beendigung eines anderen Threads warten: public final void join() throws InterruptedException Threadprogramme sind unstrukturiert: jeder Thread darf jeden zum Abbruch auffordern Threads leben eventuell länger als das Hauptprogramm Abbruch aller Threads durch System.exit(0) statt 0 Angabe eines Fehlercodes möglich System.exit(0) kann in Hauptprogramm oder erzeugtem Thread aufgerufen werden PPS 2.1-29 Unterbrechen von Threads erfolgt mittels der Methode public static void sleep(long milllis) Bei Eingang einer Abbruchanforderung während des Schlafes wird eine Ausnahme ausgelöst und der Thread sofort geweckt -> Ausnahme abfangen Aufruf : Thread.sleep(100) - bezieht sich auf den aktuellen Thread, kann auch das Hauptprogramm sein Mit public final boolean isAlive() kann abgefragt werden, ob ein Thread noch läuft, z.B. if (t.isAlive()) t.interrupt(); PPS 2.1-30 Beispiel zum Unterbrechen public class BspThread extends Thread { public void run() { while (true) { if (isInterrupted()) break; System.out.println("Hallo"); try { Thread.sleep(100); } catch (InterruptedException e) { interrupt(); } } } } public class Bsp {... BspThread t = new BspThread(); t.interrupt(); } PPS 2.1-31 Synchronisation Kritischer Bereich: Abschnitt des Programms, in dem Zugriff auf gemeinsame Ressourcen erfolgt darf nicht durch andere Prozesse, die die gleiche Ressource nutzen, unterbrochen werden Java-Threads basieren auf dem Monitor-Konzept: jedem Objekt ist ein Schlüssel (Lock) zugeordnet Programmierer markiert kritische Bereiche mit dem Schlüsselwort synchronized Java-System stellt sicher, daß sich zu einem Zeitpunkt nur ein Thread in einem kritischen Bereich des gleichen Objektes befindet PPS 2.1-32 Locks und Objekte in Java besteht eine 1:1-Beziehung zwischen Lock und Objekt Sinn: gemeinsame Ressourcen sind in Java-Programmen Attribute und damit einem Objekt zugeordnet Alle Ressourcen des Objekts werden durch den gleichen Lock geschützt Markierung mit synchronized ist möglich für Methode- es wird der Lock des aktuellen Objekts angefordert Anweisungsblock - Programmierer legt explizit fest, von welchem Objekt der Lock angefordert wird PPS 2.1-33 Ausschließlicher Zugriff wird durch das Monitor-Konzept realisiert Nach Erzeugen eines Objekts ist dessen Lock verfügbar. Sobald ein Thread einen kritischen Bereich erreicht, wird automatisch der dazugehörige Lock angefordert. Falls verfügbar, wird der Lock dem aufrufenden Thread zugeordnet und ist dann für andere Threads nicht mehr verfügbar. Andernfalls wird der Thread in die Warteliste des angeforderten Locks eingetragen. Bei Verlassen des kritischen Bereichs wird der Lock automatisch freigegeben. Falls Threads warten, erhält einer von ihnen den Lock (welcher ist nicht festgelegt). PPS 2.1-34 Beispiel: Monitor public class Konto { int kontostand = 0; synchronized void einzahlen(int betrag) {kontostand+=betrag; } synchronized void abheben(int betrag) {kontostand-=betrag; } } public class Kontoinhaber extends Thread { public void run() { einzahlen(200); abheben(50); } } public class Bsp { Konto unserKonto = new Konto(); Kontoinhaber susi = new Kontoinhaber(unserKonto); Kontoinhaber fritz = new Kontoinhaber(unserKonto); susi.start(); fritz.start(); } PPS 2.1-35 Parallelität und Serialisierung Java Threads werden gegenwärtig meist pseudoparallel ausgeführt ("green threads") Parallelausführung ist möglich falls der Rechner mehrere Prozessoren enthält und die Java-Implementierung die Parallelausführung unterstützt ("native threads") Serialisierung = durch Warten auf Lock bedingte sequentielle Ausführung der Threads Unnötige Serialisierung vermeiden (auch bei pseudokritische Abschnitte kurz halten paralleler Ausführung)-> PPS 2.1-36 wait und notify Weiterer Synchronisationsmechanismus - eignet sich für Synchronisation zwischen Produzenten und Konsumenten (Anwendung Monitor: ausschließlicher Zugriff) Durch Aufruf wait() gibt der Besitzer des Locks diesen freiwillig ab und begibt sich in einen zweiten Warteraum ("Schlafsaal") zum Objekt wait() kann nur in kritischem Bereich aufgerufen werden Durch Aufruf von notify() wird ein (willkürlich ausgewählter) Thread des Schlafsaals in den Warteraum des Locks geschickt Nutzen wait/notify: Vermeidung aktiven Wartens PPS 2.1-37 Anwendung von wait /notify Konsument Produzent Konsument Konsument Lager Alle Zugriffe geschützt durch synchronized nach Produktion einer Einheit: notify(); if (Lager leer) wait(); PPS 2.1-38 Thread Scheduling Threads können sich in 4 Zuständen befinden aktiv - in Ausführung, d.h. läuft auf Prozessor rechenbereit - wartet auf Zuweisung eines Prozessors wartend - wartet auf Lock oder notify() beendet Algorithmus zur Prozessorzuordnung (Scheduling) ist implementierungsabhängig -> Programme sollten in jedem Fall korrekt laufen meist: Zeitscheiben, Prioritäten Programmierer kann Scheduling beeinflussen, z.B. durch Setzen von Prioritäten PPS 2.1-39 2.3. Applets Java-Programme, deren Ausführung typischerweise von einem Web-Browser gesteuert wird Statt main() ruft der Browser situationsabhängig (eventuell überschriebene) Methoden der Klasse Applet auf: init(), start(), stop() und andere Als mobiler Code unterliegen Applets sicherheitsbedingten Einschränkungen, z.B. Verbot des Zugriffs auf Files Ausnahme: signierte Applets Bytecode-Verifizierer überprüft nach dem Laden sicherheitsrelevante Eigenschaften des Codes zum Applet gehörige Klassen werden nach Bedarf geladen Alternative: jar-Archiv Applet-Programmierung ist grafik- und ereignisorientiert PPS 2.1-40 Beispiel: Applets import java.applet.*; import java.awt.*; public class Bsp extends Applet { public void paint(Graphics g) { g.drawString("Hello World",10, 20); g.drawLine(10,22,80,22); } } <html> <body> <applet code="Bsp.class" width=300 height=200> </applet> </body> </html> PPS 2.1-41 2.4. Remote Method Invocation auch: entfernter Methodenaufruf, RMI objektorientiertes Konzept zur Realisierung des Client/Server-Paradigmas Kennzeichen: Nachrichtenaustausch über Rechnergrenzen hinweg Objekte verbleiben auf ihrem Rechner RMI kann durch Code-Mobilität ergänzt werden; diese ist jedoch nicht Bestandteil des Konzepts PPS 2.1-42 Funktionsweise RMI Client Server Stub Skeleton Netzwerkverbindung Client = Prozeß, der aufrufendes Objekt ausführt Server = Prozeß, der dienstanbietendes Objekt ausführt PPS 2.1-43 Stub und Skeleton Stub: lokale Methode auf Client-Seite, wird vom Client stellvertretend für die entfernte Methode aufgerufen Skeleton analog, aber auf Server-Seite Stub und Skeleton werden mit Hilfe eines Werkzeugs erzeugt Stub und Skeleton enthalten Programmcode zur Realisierung der Kommunikation -> ist transparent für das Anwendungsprogramm PPS 2.1-44 Datenübertragung Zulässige Parameter: (1) Werte primitiver Typen (2) serialisierbare Objekte (3) Verweise auf RMI-Objekte Stub/Skeleton packen/entpacken Parameter und Ergebnis erfolgt bei (2) mittels Serialisierung PPS 2.1-45 Serialisierung Abspeichern des Objektzustandes in einem zur Datenübertragung geeigneten Format (Folge von Bits) Abgespeichert werden die Werte aller eigenen und geerbten Attribute, außer static, transient für Attribute, die Objekte sind, rekursiv auch deren Attribute (bei zyklischen Verweisen nur einmal) Verweis auf zugehörige Klasse (Programmtext, Version) Objekte können nur serialisiert werden, wenn sie das (leere) Interface Serializable implementieren Weitere Anwendung: Sichern in Files (Persistenz) PPS 2.1-46 Praktische Umsetzung mit Java RMI 1) Definition eines Remote Interface für die Serverklasse Unterklasse von java.rmi.Remote jede Methode muß throws RemoteException deklarieren 2) Erstellen einer Klasse A, die das Interface implementiert 3) Erzeugen von Stub und Skeleton mit Hilfe des Werkzeugs rmic 4) Starten der RMI-Registry als Hintergrundprozeß auf dem Server-Rechner 5) Starten des Serverprozesses - darin Erzeugen eines Objekts der Klasse A und Anmelden dieses Objekts unter einem Namen xyz bei der RMI-Registry (mittels Naming.bind) Serverprozeß läuft auch nach Beendigung von main() weiter PPS 2.1-47 Praktische Umsetzung 2 6) Kopieren des Stub auf den Client-Rechner (ins Arbeitsverzeichnis) 7) Client-Programm muß kennen: Name des Zielrechners (z.B. paral.informatik.uni-leipzig.de) frei gewählten Namen des Servers (d.h.: xyz) Erhält dann durch Aufruf von Naming.lookup(daten) vom RMI Registry des Server-Rechners einen Verweis fernesObjekt auf das Server-Objekt 8) Dieser Verweis ermöglicht Aufruf von Server-Methoden mit der üblichen Syntax, z.B. fernesObjekt.m() PPS 2.1-48 3. Skriptsprachen Literatur für dieses Kapitel: D. Barron: The World of Scripting Languages, Wiley, 2000. PPS 3-1 Merkmale werden häufig nicht zu den Programmiersprachen gezählt einfache Sprachen leicht zu erlernen (zumindest Sprachkonzept) schnelle Entwicklung von Programmen pragmatisch einfaches Typsystem, dynamische Typisierung werden interpretiert oder implizit kompiliert -> direkter Aufruf des Programms ohne vorherige Übersetzung große praktische Bedeutung PPS 3-2 Anwendungsgebiete und Sprachen Systemadministration , Steuerung von Anwendungen Betriebssysteme, Netzwerke, Datenbanken Unix Shells, Perl, Tcl Zusammensetzen von Komponenten Tk, Visual Basic Anwendungen, bei denen schnelle Programmentwicklung wichtiger ist als schnelle Programmausführung (Prototyp) Visual Basic Web-Programmierung auf Client- und Serverseite JavaScript, VBScript, Perl =>Skriptsprachen sind auf ein (eventuell breites) Anwendungsgebiet spezialisiert PPS 3-3 Perl - Einführung Perl = Practical Extraction and Report Language Ende 80-er Jahre eingeführt, danach weiterentwickelt zunächst Unix, jetzt alle wichtigen Betriebssysteme Spezialisierung: Textverarbeitung, Extraktion von Informationen aus Files Befehle des Betriebssystems (auch zur Netzwerkprogrammierung) sind in Perl-Skripts direkt verfügbar Syntax erlaubt Varianten des gleichen Befehls - Prinzip: fehlende Informationen werden sinnvoll ergänzt Beispiel: Variablen können, müssen aber nicht deklariert werden günstig für ungeübten Programmierer PPS 3-4 Beispiele: Perl Schreiben in File Bsp.pl: #!/usr/bin/perl print "Hello World\n" #!/usr/bin/perl while (<STDIN>) { print if /wichtig/ }; Ausführung in Unix durch: >Bsp Ausführung in Windows durch: > perl Bsp #!/usr/bin/perl $word = shift; while (<>) {print if /$word/}; Aufruf durch: Bsp xyz File1 File2 PPS 3-5 Datentypen in Perl Typ von Variablen wird im Bezeichner kodiert: Skalare Daten: $name Arrays: @name Hashes: %name Funktionen: &name Skalare Datentypen: String, Zahl Dynamisch-typisierte Sprache: System kennt den aktuellen Typ der Variablen und konvertiert wo nötig Operatoren: arithmetisch, logisch, bitweise, Vergleich, bedingter Ausdruck, Zeichenreihen z.B. $a = "Hallo" x 3; $b = "Ein $a"; $b .= $a; ++$a; PPS 3-6 Zusammengesetzte Datentypen Liste z.B. ("rot", "blau", "gruen"), qw(rot blau gruen), (1..8) Vertauschen von Daten: ($a, $b) = ($b, $a); Array z.B. @bsp = (0, "nichts", 0.0); -> $bsp[0] enthält 0 etc. Zuweisung der Feldlänge: $laenge = @bsp; Hash = inhaltsadressiertes Feld, assoziatives Feld z.B. $myHash{baum} = "tree"; ... %myHash = (baum => "tree", apfel => apple, ...); Liste der Schlüssel/Werte: keys %myHash; values %myHash; PPS 3-7 Steuerstruktur Blöcke bedingte Anweisungen if ($n>20) { print "gross" } else { print "klein" } print "gross" if (n>20); print "klein" unless (n>20); Schleifen z.B. $a += 2 while $a < $b; $a += 2 until $a > $b; foreach $i reverse (1..10) { print $i }; for ($i=1; $i<10; $i++) { print $i }; auch: Objekte, Pakete etc. PPS 3-8 Reguläre Ausdrücke Beschreiben Muster in Zeichenreihen unter Verwendung von Symbolen: ^ - Zeilenanfang, $ - Zeilenende . - beliebiges Zeichen [] - Zeichen aus Liste, z.B. /[aeiou]/ - - abgekürzte Aufzählung, z.B. /[0..9]/ [^]- Zeichen außer angegebenen, z.B. /^[ou]/ *, +, ?- Wiederholung (* für >=0, + für >=1, ? für 0,1) | - Alternative, z.B. /From: | To:/ ()- Gruppenbildung {n,m}- gezählte Wiederholung, z.B. /([0..9]{1,3}\.){3}/ und andere PPS 3-9 4. Maschinennahe Programmierung Literatur für dieses Kapitel: H.-P. Gumm, M. Sommer: Einführung in die Informatik, Oldenbourg-Verlag, 2000, Abschnitte 5.4-5.6 PPS 4-1 Was ist Assembler Abstraktionsebene oberhalb von Maschinenbefehlen Beispiel: MOV DX, 0 vs. 101110100000000000000000 Maschinenbefehle sind eventuell durch Folge von Mikrobefehlen realisiert Zwei Bedeutungen des Begriffs: Sprache, die Maschinenbefehle verständlich kodiert und einfache Möglichkeiten zur Programmstrukturierung bereitstellt Programm, das Assemblerprogramme in Maschinenprogramme umwandelt Informationen zu konkreten Assemblersprachen findet man z.B. in der Dokumentation des jeweiligen Prozessors PPS 4-2 Bedeutung Assembler Wozu beschäftigen wir uns mit Assembler? Zielsprache im Compilerbau Verständnis für Performance von Programmen Zusammenspiel Programmierer - Compiler in sehr seltenen Ausnahmefällen Performance-kritische Programmabschnitte in Assembler schreiben Programmierung von Basisfunktionen des Betriebssystems (Zugriff auf periphere Geräte) Geschichte von Programmiersprachen Wozu nicht? Programmierung von Anwendungsprogrammen PPS 4-3 Eigenschaften von Assembler Maschinenabhängig -> Assemblerprogramme sind nicht portabel evtl. Abwärtskompatibilität innerhalb einer Prozessorfamilie betrachten hier typische und grundlegende Befehlsklassen Assemblersprachen sind minimalistisch enthalten (fast) nur die vom Prozessor unterstützten Grundbefehle Komplexere Operationen müssen im Programm aus Grundbefehlen zusammengesetzt werden Verwendung Assembler: Assembler als Teil des Compilers, z.B. gcc -S myprog.c, gcc myprog.s Assembler als eigenständiges Programm Einfügen von Assemblercode in Hochsprachprogramme PPS 4-4 Rechnermodell betrachten von-Neumann Rechner Speicher unterteilt in Register und (Haupt-)speicher unterscheiden Mehrzweckregister R1, R2,... Spezialregister, z.B. Programmzähler PC, Stackzeiger SP Statusregister (FLAGS) Registerbreite architekturabhängig, z.B. 4 Byte Operationen verlangen evtl. bestimmtes Register fassen Speicher als Array der Länge MAX_ADDRESS auf, mit Indizes = Adressen Speicher enthält (in verschiedenen Segmenten) Programmtext und Daten des Programms PPS 4-5 Speicherzugriff und Adressierung bei RISC-Architekturen können nur explizite Lese- und Schreibbefehle auf den Speicher zugreifen arithmetische Operationen erwarten die Operanden in Registern Adressierungsarten: Direktoperand, z.B. MOV R1,14 Registerzugriff, z.B. MOV R1, R2 direkte Adressierung, z.B. MOV R1, [12] indizierte Addressierung, z.B. MOV R1, R2[R3] indirekte Adressierung, z.B. MOV R1, (R2) PPS 4-6 Datentypen unterscheiden Byte = 8 Bit, Wort = 16 Bit, Doppelwort = 32 Bit u.a. Bitfolgen werden von verschiedenen Operationen als int mit/ohne Vorzeichen, float etc. interpretiert betrachten byteadressierten Speicher (z.B. Intel Pentium): 3AH 4H Wort auf 1H enthält 12E2H BCH 3H 12H 2H Doppelwort auf 0H enthält BC12E201H E2H 1H Byte auf 4H enthält 3AH 01H 0H für effizienten Zugriff müssen Daten korrekt ausgerichtet sein, z.B. Doppelwort an durch 4 teilbarer Byteadresse PPS 4-7 Adreßformen unterscheiden Einadreßform: op Quelle Zweiadreßform: Ziel = Ziel op Quelle, Dreiadreßform: Ziel = Quelle1 op Quelle2 Beispiel zur Zweiadreßform: Berechnung von a=(a+b)-(7-c) MOV R1, a MOV R2, b ADD R1, R2 MOV R3, 7 MOV R4, c SUB R3, R4 SUB R1, R3 MOV a, R1 PPS 4-8 Flags Flag = einzelnes Bit des Registers FLAGS unterscheiden Status-, Steuer- und Systemflags Statusflags werden automatisch durch die ALU gesetzt und enthalten Informationen zur letzten Operation welche Flags aktualisiert werden, hängt von der konkreten Operation ab Beispiele: Z (Zero) - Ergebnis der letzten Operation war 0 C (Carry) - Überlauf bei vorzeichenlosen ganzen Zahlen O (Overflow) - Überlauf bei ganzen Zahlen mit Vorzeichen S (Sign) - Ergebnis war negativ PPS 4-9 Beispiel: Flags (im Intel Pentium sind AL , BL Register der Breite 1 Byte) MOV AL, -3 MOV BL, -1 ADD AL, BL AL FDH AL FCH Ergebnis = -4 Gültig, da O=0 MOV AL, 253 MOV BL, 255 ADD AL, BL BL FFH FLAGS 1 C 0 O Ergebnis = 252 Ungültig, da C=1 PPS 4-10 Operationen Arithmetische Operationen: ADD, SUB, MUL, DIV Register für Produkt bzw. Dividend müssen doppelte Breite haben Beispiel Intel Pentium: MOV AL, 17 MOV DL, 30 MUL DL ; AX := AL * DL Vergleiche: CMP Logische Operationen: AND, OR, XOR, NOT können für Bitoperationen verwendet werden, z.B. OR AL, 0100 0010B Schiebebefehle, z.B. SHR AL, 1 Anwendung: Multiplikation, Division mit Zweierpotenzen Bit- und Byteoperationen, u.a. PPS 4-11 Sprungbefehle bewirken Laden des Programmzählers mit neuem Wert unterscheiden unbedingte und bedingte Sprünge Beispiel: Berechnung von AX = 1+2+ ... +CX MOV AX, 0 nochmal: CMP CX, 0 JZ ende ; bedingter Sprung (Jump on Zero) ADD AX, CX DEC CX JMP nochmal ; unbedingter Sprung ende: ... bedingte Sprünge beziehen sich auf Flags der vorigen Operation; existiert Vielzahl bedingter Sprungbefehle PPS 4-12 Speichersegmente Speicher ist unterteilt in Daten-, Code- und Stacksegment Segmente sind verschiebbar, aktuelle Startadressen der Segmente stehen in Spezialregistern DS, CS, SS bei Datenzugriffen gilt: physische Adresse = 16 * DS + angegebene Adresse beim Laden von Befehlen gilt: Adresse nächster Befehl = 16 * CS + PC Segmente können sich überlappen Größe/Überlappung der Segmente kann im Programm festgelegt werden, z.B. . stack 100H PPS 4-13 Symbolische Adressen (im Codesegment: Sprungmarken) im Datensegment: symbolische Datenadressen werden am Anfang des Assemblerprogramms deklariert und eventuell initialisiert können später statt expliziter Adressen verwendet werden DB = Define Byte, DW = Define Word Beispiel: Alter DB 0 Name DB 15 DUP(0) Groesse DW ? Effekt: Es wird Speicherplatz reserviert, z.B. Alter: DS:04, Name: DS:05 ... DS:0E, Groesse: DS:0F und DS:10 PPS 4-14 Unterprogramme meineFunktion: Befehl 1 ... Befehl n RET main: ... CALL meineFunktion ... END main Prozedurdeklaration Prozeduraufruf Es dürfen beliebig viele Unterprogramme deklariert werden Rekursive Aufrufe sind zulässig Hauptprogramm ist durch ´END´ gekennzeichnet PPS 4-15 Verwendung des Stack Stack = durch SS adressiertes Segment des Speichers Zugriff erfolgt mittels PUSH, POP wird für Implementierung von Unterprogrammaufrufen verwendet, insbesondere Parameterübergabe CALL meineFunktion bewirkt PUSH PC ; alten Programmzähler sichern JMP meineFunktion ; unbedingter Sprung RET bewirkt POP PC ; wieder alten Programmzähler laden innerhalb des Unterprogramms benötigte Register sollten zu Beginn gerettet und am Ende wiederhergestellt werden PPS 4-16 Parameterübergabe Übergabe in Registern welche Register, ist Konvention zwischen Aufrufer und aufgerufenem Unterprogramm geeignet für wenige / kurze Parameter Übergabe auf Stack Übergabe mittels PUSH Entfernen mittels RET k (k Byte entfernen, RET) Zugriff über Spezialregister SP (Stack Pointer) und BP (Base Pointer) z.B. MOV BP, SP MOV AX, [BP+4] PPS 4-17 Parameterübergabe auf Stack SS Lokale Variablen des Aufrufers Datenrahmen des Unterprogramms (Frame) Übergebene Parameter PC BP Lokale Variable Stack wächst hier nach unten: SP PUSH POP PPS 4-18 5. Zusammenfassender Überblick Unterscheiden vier grundlegende Paradigmen: Imperative Programmierung Objektorientierte Programmierung Funktionale Programmierung Logikprogrammierung Weitere Sprachklassen: Parallele, verteilte, nebenläufige Programmierung Skriptsprachen Maschinennahe Programmierung PPS 5-1