Klausur zum Kurs 1618

Werbung
Lehrgebiet Programmiersysteme
Prof. Dr. Friedrich Steimann
_________________________________________________________
(Name, Vorname)
_________________________________________________________
_________________________________________________________
(Straße, Nr.)
______________
(PLZ)
________________________________________
(Wohnort)
_________________________________________________________
(Land, falls außerhalb Deutschlands)
Kurs 01618
Einführung in die
objektorientierte Programmierung
(Kursdurchführung des Sommersemester 2016)
Nachklausur am 18.03.2017
Zweistündige Klausur
(10.00 – 12.00 Uhr)
Lesen Sie zuerst die Hinweise auf der folgenden Seite!
Matrikelnummer:
Geburtsdatum:
.
.
Klausurort: _________________________
Aufgabe
1
2
3
4
5
6
7
8
Summe
10
10
10
10
10
10
10
10
80
habe bearbeitet
maximal
erreicht
Korrektur
○ Herzlichen Glückwunsch, Sie haben die Klausur bestanden. Note: ..........
○ Sie haben die Klausur leider nicht bestanden. Für den nächsten Versuch wünschen wir Ihnen
MUSTERLÖSUNG
viel Erfolg. Die nächste Klausur findet im Sommersemester 2017 statt.
Hagen, den 29.03.2017
Im Auftrag
© 2016 FernUniversität in Hagen
Nachklausur zum Kurs 01618 im Sommersemester 2016
Lehrgebiet Programmiersysteme
Prof. Dr. Friedrich Steimann
Hinweise zur Bearbeitung
1. Prüfen Sie die Vollständigkeit Ihrer Unterlagen. Die Klausur umfasst auf insgesamt 18 Seiten:
 1 Deckblatt
 Diese Hinweise zur Bearbeitung
 Eine Bescheinigung zur Vorlage beim Finanzamt auf Seite 3
 8 Aufgaben auf Seite 4-16
 Zwei zusätzliche Seiten 17 und 18 für weitere Lösungen
2. Füllen Sie jetzt bitte zuerst das Deckblatt und (sofern gewünscht) die Bescheinigung zur Vorlage
beim Finanzamt aus:
 Name, Vorname und Adresse
 Matrikelnummer, Geburtsdatum und Klausurort
3. Schreiben Sie Ihre Lösungen mit Kugelschreiber oder Füllfederhalter (kein Bleistift) direkt in den bei
den jeweiligen Aufgaben gegebenen, umrahmten Leerraum. Benutzen Sie auf keinen Fall die
Rückseiten der Aufgabenblätter. Versuchen Sie, mit dem vorhandenen Platz auszukommen; Sie
dürfen auch stichwortartig antworten. Sollten Sie wider Erwarten nicht mit dem vorgegebenen
Platz auskommen, benutzen Sie bitte die beiden dieser Klausur angefügten Leerseiten. Es werden
nur Aufgaben gewertet, die sich auf dem offiziellen Klausurpapier befinden. Eigenes Papier ist nur für Ihre persönlichen Notizen erlaubt.
4. Kreuzen Sie die bearbeiteten Aufgaben auf dem Deckblatt an. Schreiben Sie unbedingt auf jedes
Blatt Ihrer Klausur Ihren Namen und Ihre Matrikelnummer, auf die Zusatzblätter auch die Nummer
der Aufgabe.
5. Geben Sie die gesamte Klausur ab. Lösen Sie die Blätter nicht voneinander.
6. Es sind keine Hilfsmittel zugelassen.
7. Lesen Sie vor der Bearbeitung einer Aufgabe den gesamten Aufgabentext sorgfältig durch.
8. Es sind maximal 80 Punkte erreichbar. Wenn Sie mindestens 40 Punkte erreichen, haben Sie die
Klausur bestanden.
9. Sie erhalten die korrigierte Klausur zurück, zusammen mit einer Bescheinigung für das Finanzamt
und ggf. dem Übungsschein.
10. Legen Sie jetzt noch Ihren Studierendenausweis und einen amtlichen Lichtbildausweis bereit, dann
kann die Arbeit beginnen. Viel Erfolg!
Seite 2 von 18
Nachklausur zum Kurs 01618 im Sommersemester 2016
Lehrgebiet Programmiersysteme
Prof. Dr. Friedrich Steimann
BESCHEINIGUNG
(zur Vorlage beim Finanzamt)
Herr / Frau
________________________________________________
Matrikelnummer
________________________________________________
geboren am
________________________________________________
hat am
18. März 2017
in
________________________________________________
an der Klausur zur Lehrveranstaltung „Einführung in die objektorientierte Programmierung“ (01618)
teilgenommen.
gez. Sarah Lang
Seite 3 von 18
Nachklausur zum Kurs 01618 im Sommersemester 2016
Lehrgebiet Programmiersysteme
Prof. Dr. Friedrich Steimann
Aufgabe 1: Klassenimplementierung
(10 Punkte)
Gegeben sei das folgende Programmfragment:
public class UniDemo {
public static void main(String[] args) {
Universitaet fernUni = new Universitaet("Hagen", 3);
Mitarbeiter max = new Mitarbeiter("Max");
Mitarbeiter martina = new Mitarbeiter("Martina");
Kurs derKurs = new Kurs(1234);
derKurs.betreutDurch(max);
derKurs.geschriebenVon(martina);
fernUni.kursAnbieten(0, derKurs);
}
}
Geben Sie Implementierungen für die Klassen Universitaet, Mitarbeiter und Kurs an, sodass dieses
Programmfragment kompiliert und bei Terminierung der main(.)-Methode das folgende Objektgeflecht erzeugt und im Speicher abgelegt wurde. Die Belegungen der Attribute sollen hierbei selbstverständlich durch die oben gezeigten Methodenaufrufe vorgenommen werden.
(Fortsetzung der Aufgabe auf der folgenden Seite)
Seite 4 von 18
Nachklausur zum Kurs 01618 im Sommersemester 2016
Lehrgebiet Programmiersysteme
Prof. Dr. Friedrich Steimann
(Fortsetzung von Aufgabe 1)
class Universitaet{
private String ort;
private Kurs[] kursangebot;
Universitaet (String ort, int kursangebotsGroesse){
this.ort = ort;
this.kursangebot = new Kurs[kursangebotsGroesse];
}
public void kursAnbieten(int kursPosition, Kurs kurs) {
this.kursangebot[kursPosition] = kurs;
}
}
class Kurs {
private int nummer;
private Mitarbeiter betreuer;
private Mitarbeiter autor;
Kurs(int nummer){
this.nummer = nummer;
}
void betreutDurch(Mitarbeiter betreuer){
this.betreuer = betreuer;
}
void geschriebenVon(Mitarbeiter autor){
this.autor = autor;
}
}
class Mitarbeiter {
private String name;
Mitarbeiter (String name){
this.name = name;
}
}
Seite 5 von 18
Lehrgebiet Programmiersysteme
Prof. Dr. Friedrich Steimann
Nachklausur zum Kurs 01618 im Sommersemester 2016
Aufgabe 2: Kontrollstrukturen
(10 Punkte)
Vervollständigen Sie das folgende Java Programm, sodass bei Terminierung der main-Methode die folgenden Zeilen auf der Konsole ausgegeben werden:
Hänschen
Hänschen
Hänschen
Hänschen
klein
klein
klein
klein
Implementieren
ging
ging
ging
ging
Sie
allein...
allein...
allein...
allein...
dazu
vier
verschiedene
Schleifen,
die
innerhalb
der
Methode
schreiben(List<String> liste) über die Elemente des Parameters liste iterieren, und zwar:


jeweils einmal mit den beiden Varianten einer for-Schleife und
jeweils einmal mit den beiden Varianten einer while-Schleife.
Hinweis: Jeweils eine Variante der beiden Schleifenimplementierungen nutzt aus, dass das Interface
List<T> einen indizierten Zugriff ermöglicht, während die andere Variante ausnutzt, dass das Interface
List<T> das Interface Iterable<T> erweitert (also Iterable<T> ein Supertyp von List<T> ist.).
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class SchleifenDemo {
public static void main(String[] args) {
List<String> eineListe = new ArrayList<String>();
eineListe.add("Hänschen");
eineListe.add("klein");
eineListe.add("ging");
eineListe.add("allein");
eineListe.add("...");
schreiben(eineListe);
}
static void schreiben(List<String> liste) {
// for-Schleife mit indiziertem Zugriff auf die Elemente.
(2,5 Punkte)
for (int i = 0; i < liste.size(); i++) {
System.out.print(liste.get(i) + " ");
}
System.out.println();
(Fortsetzung der Aufgabe auf folgender Seite)
Seite 6 von 18
Nachklausur zum Kurs 01618 im Sommersemester 2016
Lehrgebiet Programmiersysteme
Prof. Dr. Friedrich Steimann
(Fortsetzung von Aufgabe 2)
// for-Schleife, die Iterable<String> ausnutzt.
(2,5 Punkte)
for (String s : liste) {
System.out.print(s + " ");
}
System.out.println();
// while-Schleife mit indiziertem Zugriff auf die Elemente.
(2,5 Punkte)
int i = 0;
while (i < liste.size()) {
System.out.print(liste.get(i++) + " ");
}
System.out.println();
// while-Schleife, die Iterable<String> ausnutzt.
(2,5 Punkte)
Iterator<String> iterator = liste.iterator();
while (iterator.hasNext()) {
System.out.print(iterator.next() + " ");
}
}
}
Seite 7 von 18
Nachklausur zum Kurs 01618 im Sommersemester 2016
Lehrgebiet Programmiersysteme
Prof. Dr. Friedrich Steimann
Aufgabe 3: Überladen und Überschreiben
(10 Punkte)
Gegeben sei das folgende Java-Programm:
class Ort {}
class Weg {}
class Trampelpfad extends Weg {}
abstract class Sportler {
void sportTreiben(Weg weg) {
System.out.println("Sportler treibt Sport auf Weg.");
}
void gemeinsamSportTreiben(Weg weg, Läufer nachbar) {
System.out.println("Sportler und Läufer treiben Sport auf Weg.");
}
void gemeinsamSportTreiben(Trampelpfad ort, Fahrradfahrer nachbar) {
System.out.println("Sportler und Fahrradfahrer treiben Sport auf Trampelpfad."); }
}
class Fahrradfahrer extends Sportler {
void sportTreiben(Trampelpfad pfad) {
System.out.println("Fahrradfahrer treibt Sport auf Trampelpfad.");
}
}
class Mountainbiker extends Fahrradfahrer {
void sportTreiben(Trampelpfad weg) {
System.out.println("Mountainbiker treibt Sport auf Trampelpfad.");
void gemeinsamSportTreiben(Weg weg, Läufer nachbar) {
System.out.println("Mountainbiker und Läufer treiben Sport auf Weg.");
}
}
}
class Läufer extends Sportler {
void gemeinsamSportTreiben(Trampelpfad weg, Sportler nachbar) {
System.out.println("Läufer und Sportler treiben Sport auf Trampelpfad.");
}
class Sprinter extends Läufer {
void sportTreiben(Trampelpfad weg) {
System.out.println("Sprinter treibt Sport auf Trampelpfad.");
}
}
}
public class VonSportlern {
public static void main(String[] args) {
Mountainbiker mountainbiker = new Mountainbiker();
Sprinter sprinter = new Sprinter();
Fahrradfahrer fahrradfahrer = mountainbiker;
Läufer läufer = sprinter;
Trampelpfad pfad = new Trampelpfad();
Weg weg = pfad;
/* [1] */
}
}
(Fortsetzung der Aufgabe auf folgender Seite)
Seite 8 von 18
Nachklausur zum Kurs 01618 im Sommersemester 2016
Lehrgebiet Programmiersysteme
Prof. Dr. Friedrich Steimann
(Fortsetzung von Aufgabe 3)
An der mit /* [1] */ markierten Stelle werden nun (einzeln und nacheinander) die folgenden Befehle
eingefügt. Kann das Programm nun kompiliert werden? Wenn ja, geben Sie die durch diese Anweisung ausgegebene Zeile an; wenn nein: Warum nicht?
mountainbiker.sportTreiben(pfad);
(1 Punkt)
Das Programm kann kompiliert werden; die folgende Zeile wird ausgegeben:
Mountainbiker treibt Sport auf Trampelpfad.
fahrradfahrer.sportTreiben(pfad);
(1 Punkt)
Das Programm kann kompiliert werden; die folgende Zeile wird ausgegeben:
Mountainbiker treibt Sport auf Trampelpfad.
läufer.sportTreiben(pfad);
(1 Punkt)
Das Programm kann kompiliert werden; die folgende Zeile wird ausgegeben:
Sportler treibt Sport auf Weg.
fahrradfahrer.gemeinsamSportTreiben(pfad, fahrradfahrer);
(1 Punkt)
Das Programm kann kompiliert werden; die folgende Zeile wird ausgegeben:
Sportler und Fahrradfahrer treiben Sport auf Trampelpfad.
mountainbiker.gemeinsamSportTreiben(weg, läufer);
(1 Punkt)
Das Programm kann kompiliert werden; die folgende Zeile wird ausgegeben:
Mountainbiker und Läufer treiben Sport auf Weg.
sprinter.gemeinsamSportTreiben(weg, läufer);
(2 Punkte)
Das Programm kann kompiliert werden; die folgende Zeile wird ausgegeben:
Sportler und Läufer treiben Sport auf Weg.
läufer.gemeinsamSportTreiben(pfad, läufer);
(3 Punkte)
Dieser Methodenaufruf kann durch den Most-Specific-Algorithmus nicht eindeutig aufgelöst werden. Die deklarierten Typen der aktuellen Parameter pfad und läufer sind Trampelpfad und Läufer. Die
Überladung der Methode gemeinsamSportTreiben in der Klasse Läufer (mit den Parametertypen
Trampelpfad und Sportler) sowie die Überladung in der Klasse Sportler mit den Parametertypen Weg
und Läufer haben mit diesen Typen kompatible Parametertypen.
Unter diesen beiden Methodendeklarationen kann eine speziellere Methode nicht eindeutig identifiziert werden: gemeinsamSportTreiben(Trampelpfad weg, Sportler nachbar) ist in Bezug auf den ersten Parameter vom Typ Trampelpfad die speziellere; gemeinsamSportTreiben(Weg weg, Läufer
nachbar) ist in Bezug auf den zweiten Parameter vom Typ Läufer die speziellere. Der Compiler meldet
daher, dass der Methodenaufruf gemeinsamSportTreiben(pfad, läufer) mehrdeutig ist.
Seite 9 von 18
Nachklausur zum Kurs 01618 im Sommersemester 2016
Lehrgebiet Programmiersysteme
Prof. Dr. Friedrich Steimann
Aufgabe 4: (Beschränkt) Parametrische Polymorphie(10 Punkte)
Gegeben sei die Implementierung der folgenden main-Methode:
public class TupelDemo {
public static void main(String[] args) {
Tupel<String, Long> t1 = new Tupel<String, Long>("Zeichenkette", 42L);
System.out.println(t1.toString()); // Liefert „(Zeichenkette, 42)“.
String t1ErsterWert = t1.ersterWert();
Long t1ZweiterWert = t1.zweiterWert();
Tupel<Character, Boolean> t2 = new Tupel<Character, Boolean>('?', true);
System.out.println(t2.toString()); // Liefert „(?, true)“.
Character t2ErsterWert = t2.ersterWert();
Boolean t2ZweiterWert = t2.zweiterWert();
}
}
Geben Sie eine Implementierung für die Klasse Tuple<S, T> an, sodass diese Implementierung kompiliert werden kann und durch die System.out.println(…)-Aufrufe die in den Kommentaren angegebenen Zeichenketten auf die Konsole geschrieben werden.
(5 Punkte)
class Tupel<S, T> {
S erster;
T zweiter;
public Tupel(S erster, T zweiter) {
super();
this.erster = erster;
this.zweiter = zweiter;
}
public S ersterWert() {
return erster;
}
public T zweiterWert() {
return zweiter;
}
public String toString() {
return "(" + erster + ", " + zweiter + ")";
}
}
(Fortsetzung der Aufgabe auf der folgenden Seite)
Seite 10 von 18
Nachklausur zum Kurs 01618 im Sommersemester 2016
Lehrgebiet Programmiersysteme
Prof. Dr. Friedrich Steimann
(Fortsetzung von Aufgabe 4)
Die Klasse Tupel soll nun so verändert werden, dass
1. der erste und der zweite Wert des Tupels vom selben Typ sind;
2. die Objekte dieses Typs sortierbar sind (also miteinander verglichen werden können);
3. die in den Kommentaren angedeuteten Aufrufe der toString()-Methode die angegebenen
Rückgaben erzeugen würden.
(Die Kommentare sind so zu verstehen, dass ein Aufruf von ti.toString() nach der Initialisierung der
Variablen ti bzw. nach dem Aufruf von ti.sortiere() die angegebene Zeichenkette zurückgäbe.)
public static void main(String[] args) {
Tupel<Long> t1 = new Tupel<Long>(1L, 2L);
// t1.toString() gäbe „(1, 2)“
t1.sortiere();
// t1.toString() gäbe „(1, 2)“
Tupel<Long> t2 = new Tupel<Long>(4711L, 42L); // t2.toString() gäbe „(4711, 42)“
t2.sortiere();
// t2.toString() gäbe „(42, 4711)“
Tupel<String> t3 = new Tupel<String>("xy", "ab"); // t3.toString() gäbe „(xy, ab)“
t3.sortiere();
// t3.toString() gäbe „(ab, xy)“
}
Hinweis: Verwenden Sie das Interface java.lang.Comparable:
public interface Comparable<T> {
/** Compares this object with the specified object for order. Returns a negative
integer, zero, or a positive integer as this object is less than, equal to, or
greater than the specified object. */
public int compareTo(T o);
}
(5 Punkte)
class Tupel<S extends Comparable<S>> {
S erster;
S zweiter;
public Tupel(S erster, S zweiter) {
super();
this.erster = erster;
this.zweiter = zweiter;
}
public void sortiere() {
if (erster.compareTo(zweiter) > 0) {
S tmp = erster;
erster = zweiter;
zweiter = tmp;
}
}
public String toString() {
return "(" + erster + ", " + zweiter + ")";
}
}
Seite 11 von 18
Nachklausur zum Kurs 01618 im Sommersemester 2016
Aufgabe 5: Polymorphie
Lehrgebiet Programmiersysteme
Prof. Dr. Friedrich Steimann
(10 Punkte)
Welche vier Arten von Polymorphie kennen Sie?




(2 Punkte)
Subtyp-Polymorphie
parametrische Polymorphie
beschränkt parametrische Polymorphie
(hierbei handelt es sich um eine spezielle Form der parametrischen Polymorphie)
Ad-hoc Polymorphie
Charakterisieren Sie jede Art kurz!
(jeweils 2 Punkte)
Subtyp-Polymorphie wird durch Subtyping erreicht. Das bedeutet, dass an den Stellen, an denen ein
Objekt vom Typ Typ erwartet wird, auch solche Objekte stehen dürfen, die Instanzen von einem Subtyp von Typ sind.
Parametrische Polymorphie wird dadurch realisiert, dass bestimmte Konstrukte einer Programmiersprache – z.B. Methoden oder Klassen – durch Typparameter parametrisiert werden. Bei der Verwendung eines so parametrisierten Konstrukts wird der Typparameter durch einen konkreten Typen ersetzt. So ist es möglich, eine generische Implementierung einer Funktionalität anzugeben, die in verschiedenen Kon-texten typsicher genutzt werden kann.
Die beschränkt parametrische Polymorphie begegnet dem Problem der (einfachen) parametrischen
Polymorphie, dass innerhalb der generischen Klasse keine Informationen über den Typen, mit dem der
Typparameter belegt wird, zur Verfügung stehen. Hierin können so ohne eine explizite Typkonvertierung (Type Casts) keine spezifischen Methoden verwendet werden. Durch die Angabe einer Schranke
zu dem Typparameter kann nun hingegen festgelegt werden, dass dieser lediglich durch Subtypen der
Schranke belegt werden kann. So kann auch ohne Typkonvertierung (Type Cast) innerhalb der generischen Implementierung auf die durch die Schranke deklarierte Schnittstelle zugegriffen werden.
Als Ad-hoc Polymorphie wird das Überladen von Operatoren bzw. Methodennamen bezeichnet. Für
identifizierte Operationen können so für unterschiedliche Argumenttypen jeweils optimierte Implementie-rungen angegeben werden.
Seite 12 von 18
Nachklausur zum Kurs 01618 im Sommersemester 2016
Lehrgebiet Programmiersysteme
Prof. Dr. Friedrich Steimann
Aufgabe 6: Lokale und anonyme Klassen
(10 Punkte)
Geben Sie eine kompilierbare Java-Klasse an, in der eine lokale Klasse deklariert, eine Instanz von ihr
erzeugt und diese einer Variablen zugewiesen wird.
(2 Punkte)
public class DemoLokaleKlasse {
void jetztKommtEineLokaleKlasse() {
class LokaleKlasse { }
LokaleKlasse l = new LokaleKlasse();
}
}
Geben Sie eine kompilierbare Java-Klasse an, in der eine Instanz einer anonymen Klasse erzeugt und
einer Variablen zugewiesen wird.
(2 Punkte)
public class LokalUndAnonym {
void jetztKommtEineAnonymeKlasse() {
LokalUndAnonym a = new LokalUndAnonym() { };
}
}
In welchem Kontext werden anonyme Klassen in Java häufig verwendet? Warum eignen sie sich hier
besonders gut?
(2 Punkte)
Anonyme Klassen werden oft im Rahmen der Entwicklung von grafischen Benutzeroberflächen verwendet, z.B. um Beobachter-Objekte an Bedienelementen zu registrieren.
Hierzu eignen sie sich besonders gut, da von einem Beobachter-Objekt, welches ein spezifisches Verhalten implementiert, in der Regel nur ein einziges Objekt benötigt wird.
Welche Gemeinsamkeiten und welche wesentlichen Unterschiede bestehen zwischen einer lokalen und
einer anonymen Klasse?
(4 Punkte)
Sowohl lokale als auch anonyme Klassen können nur in Anweisungsblöcken, also z.B. im Rumpf einer
Methode, deklariert werden. Beide sind damit auch innere Klassen, die Komponenten einer umschließenden Klasse darstellen.
Gegenüber einer anonymen Klasse hat eine „einfache“ lokale Klasse einen Namen, sodass von ihr
mehrere Instanzen erzeugt werden können. Aus gleichem Grund können auch Variablen mit ihr typisiert werden, was einen Aufruf neu deklarierter Methoden von außen erlaubt.
Seite 13 von 18
Lehrgebiet Programmiersysteme
Prof. Dr. Friedrich Steimann
Nachklausur zum Kurs 01618 im Sommersemester 2016
Aufgabe 7: Threads
(10 Punkte)
Gegeben sei folgendes Java-Programm.
import java.util.LinkedList;
public class ThreadDemo {
public static void main(String[] args) {
Kühlschrank kühlschrank = new Kühlschrank();
kühlschrank.hineinlegen("Joghurt");
kühlschrank.hineinlegen("Käse");
kühlschrank.hineinlegen("Milch");
kühlschrank.hineinlegen("Butter");
Verbraucher
Verbraucher
Verbraucher
Verbraucher
v1
v2
v3
v4
=
=
=
=
new
new
new
new
Verbraucher(kühlschrank);
Verbraucher(kühlschrank);
Verbraucher(kühlschrank);
Verbraucher(kühlschrank);
v1.start();
v2.start();
v3.start();
v4.start();
}
}
class Kühlschrank {
LinkedList<Object> inhalt = new LinkedList<Object>();
public Object entnehmen() {
Object letztes = inhalt.getLast();
inhalt.removeLast();
return letztes;
}
public void hineinlegen(Object gegenstand) {
inhalt.addLast(gegenstand);
}
}
class Verbraucher extends Thread {
Kühlschrank kühlschrank;
Verbraucher(Kühlschrank kühlschrank){
this.kühlschrank = kühlschrank;
}
public void run() {
Object gegenstand = kühlschrank.entnehmen();
System.out.println(gegenstand);
}
}
(Fortsetzung der Aufgabe auf folgender Seite)
Seite 14 von 18
Nachklausur zum Kurs 01618 im Sommersemester 2016
Lehrgebiet Programmiersysteme
Prof. Dr. Friedrich Steimann
(Fortsetzung von Aufgabe 7)
Nach einer Ausführung des Programms erscheinen die folgenden Zeilen auf der Konsole.
Butter
Butter
Käse
Joghurt
Erläutern Sie, wie es hierzu gekommen ist.
Hinweis: Beachten Sie, dass in der Ausgabe Butter zwei Mal, Milch hingegen gar nicht ausgegeben
wird.
(5 Punkte)
Zunächst nimmt einer der vier Threads 𝑡 seine Arbeit auf. Durch die erste Anweisung in der run()Methode der Klasse Verbraucher wird die Methode entnehmen() auf dem durch das Feld inhalt referenzierten Objekt der Klasse Kühlschrank aufgerufen, in welcher zunächst eine Referenz auf das letzte
Element (Butter) der List inhalt geholt und in der lokalen Variable letztes gespeichert wird. Noch
bevor dieses letzte Element in der folgenden Anweisung aus der Liste inhalt entfernt wird, wird nun
die Ausführung des Threads durch den Scheduler unterbrochen und die Ausführung eines anderen
Threads 𝑡 ′ begonnen (oder fortgesetzt). Erreicht dieser Thread nun ebenfalls die erste Zeile der Methode entnehmen(), wird eine weitere Referenz auf Butter geholt und anschließend durch 𝑡 ′ Butter aus
der Liste inhalt des Kühlschranks entfernt.
Nun wird die Ausführung von 𝑡 forgesetzt. In der folgenden Anweisung wird das letzte Element der
Liste entfernt; welches nun jedoch Milch ist, obwohl die lokale Variable letztes den Butter referenziert. Während Butter also durch zwei Threads behandelt wird, wird Milch aus der Liste inhalt entfernt, ohne jemals eine Behandlung erfahren zu haben.
An welcher Stelle im Programmcode liegt das Problem?
(3 Punkte)
In der Methode entnehmen findet ein nicht synchronisierter Zugriff auf die gemeinsam genutzte Ressource (die Liste inhalt) statt. Mindestens die Aufrufe inhalt.getLast() und inhalt.removeLast()
müssen in einem synchronisierten Code-Block liegen, was aber nicht der Fall ist.
Geben Sie eine alternative Implementierung an, die dieses Problem vermeidet.
(2 Punkte)
public synchronized Object entnehmen() {
Object letztes = inhalt.getLast();
inhalt.removeLast();
return letztes;
}
Seite 15 von 18
Nachklausur zum Kurs 01618 im Sommersemester 2016
Lehrgebiet Programmiersysteme
Prof. Dr. Friedrich Steimann
Aufgabe 8: Programmgerüste
(10 Punkte)
Wodurch zeichnen sich Programmgerüste aus? Nennen Sie die wesentlichen Merkmale und erläutern
Sie sie anhand eines Ihnen bekannten Beispiels.
(Abs. 5.1) Ein Programmgerüst ist ein erweiterbares und anpassbares System von Klassen, das für
einen allgemeinen, übergeordneten Aufgabenbereich eine Kernfunktionalität mit entsprechenden Bausteinen bereitstellt.
Beispiel: Java AWT zur Gestaltung von Benutzeroberflächen (vgl. Abs. 5.2.2.5)





„anpassbar“
Das AWT erlaubt die Anpassung der vordefinierten Komponenten, um z.B. die Darstellung auf
dem Display des Benutzers oder das Verhalten der Komponenten anzupassen.
„erweiterbar“
Das AWT erlaubt die Definition eigener Komponenten, die selbst bei der Implementierung verschiedener Benutzeroberflächen wiederverwendet werden können.
„System von Klassen“
Die einzelnen Klassen des AWT sind eng miteinander gekoppelt. Um ihre eigene Aufgabe zu
erledigen, müssen sie in der Regel viele Nachrichten mit Instanzen anderer Klassen austauschen, da sie von ihren Funktionalitäten abhängig sind.
„allgemeiner, übergeordneter Aufgabenbereich“
Das AWT unterstützt die Implementierung von Benutzeroberflächen im Allgemeinen, ohne Details, z.B. zu ihrem Aufbau, festzulegen.
„Kernfunktionalität“
Das AWT selbst bietet keine vordefinierte Benutzeroberfläche an, sondern lediglich die Bestandteile, um Elemente zu definieren, zu positionieren oder die Interaktion der Elemente festzulegen. Erst durch eine individuelle Konfiguration von Instanzen verschiedener Klassen entsteht eine darstellbare Benutzerschnittstelle.
Seite 16 von 18
Nachklausur zum Kurs 01618 im Sommersemester 2016
Lehrgebiet Programmiersysteme
Prof. Dr. Friedrich Steimann
Zusätzlicher Platz für Ihre Lösungen
Ergänzung zu Aufgabe Nr.
Ergänzung zu Aufgabe Nr.
Seite 17 von 18
Nachklausur zum Kurs 01618 im Sommersemester 2016
Lehrgebiet Programmiersysteme
Prof. Dr. Friedrich Steimann
Zusätzlicher Platz für Ihre Lösungen
Ergänzung zu Aufgabe Nr.
Ergänzung zu Aufgabe Nr.
Seite 18 von 18
Herunterladen