Klausur
Musterlösung
Ergebnisse

Klausur

Klausur zur Lehrveranstaltung

"Programmierkurs Java"

WS 1996/97

FB Informatik

D. Boles


Klausur

Termin: 21.02.1997, 14-16 Uhr

Nachname: Vorname:

Matrikelnr.:

Fachbereich:

Verschaffen Sie sich einen kurzen Überblick über die Aufgaben. Beginnen Sie mit den Aufgaben, die Ihnen ein Erfolgserlebnis bringen.

Sie können 100 Punkte erreichen. 50 Punkte reichen zum Bestehen.

Kennzeichnen Sie jedes Lösungsblatt mit Namen und Matrikelnummer.

Legen Sie Ihren Personalausweis und Ihren Studentenausweis neben sich.

Bei Verständnisfragen heben Sie bitte den Arm; das "Aufsichtspersonal" bemüht sich dann um eine Klärung.

Bei Täuschungsversuchen wird Ihre Klausur sofort eingezogen und mit 0 Punkten als nicht bestanden gewertet!

Schreiben Sie leserlich! Nicht lesbare oder unklare Teile werden mit 0 Punkten bewertet.

Denken Sie bei allen Aufgaben - sofern nicht anders angegeben - an die Berücksichtigung von Fehlerfällen, an aussagekräftige Bezeichner und an die Dokumentation komplexer Sachverhalte. Eine Dokumentation gemäß der javadoc-Dokumentationsrichtlinien ist nur bei Aufgabe 1 (a) erforderlich.

Die Fragen beziehen sich immer auf die Programmiersprache Java wie sie in der Vorlesung vorgestellt wurde!

Viel Erfolg !

1
2
3
4
(5)
_
Bestanden:
 
Ja Nein

Aufgabe 1 (Imperative Programmierung): 21 Punkte

(a) 7 Punkte

Schreiben Sie eine Funktion, die als Parameter einen char-Wert erhält und einen boolean-Wert liefert. Die Funktion soll genau dann true liefern, wenn der Parameter eine Ziffer (0-9) darstellt. Dokumentieren Sie die Funktion gemäß der javadoc-Dokumentationsrichtlinien.

(b) 7 Punkte

Schreiben Sie eine Funktion, die ein Array mit int-Werten als Parameter übergeben bekommt und die die Summe aller dieser int-Werte zurückliefert.

(c) 7 Punkte

Schreiben Sie eine Prozedur, die die Werte eines als Parameter übergebenen Stack-Objektes in umgekehrter Reihenfolge auf den Bildschirm ausgibt, d.h. das ganz oben auf dem Stack liegende Objekt wird als letztes ausgegeben.

Die Klasse Stack habe folgendes Protokoll mit der in der Vorlesung besprochenen Semantik:

public class Stack {

public void push(Object element);

public Object pop() throws EmptyStackException;

public boolean empty();

}

Aufgabe 2 (Objektorientierte Programmierung) 24 Punkte

(a) 8 Punkte

Stellen Sie sich vor, Sie benötigen eine Klasse, die eine Menge repräsentiert, d.h. Objekte dieser Klasse sollen eine bestimmte Anzahl von int-Werten speichern können, jeden int-Wert maximal einmal. Sie durchsuchen die Klassenbibliothek und finden eine Klasse Container, die genau das von Ihnen gewünschte Protokoll definiert. Ein Unterschied zu Ihrer Menge-Klasse - und das ist der einzige Unterschied - besteht darin, daß Container-Objekte int-Werte auch mehrfach speichern können. Die Klasse Container habe folgendes Protokoll:

public class Container {

// initialisiert ein Container-Objekt, das max. size Werte speichern kann

public Container(int size);

// speichert value ab, auch wenn der Wert bereits gespeichert ist

public void addElement(int value) throws FullException;

// entfernt alle Vorkommen von value aus dem Speicher

public void removeElement(int value) throws NotExistException;

// ueberprueft, ob value bereits gespeichert ist

public boolean existsElement(int value);

}

Implementieren Sie die Klasse Menge, indem Sie die Klasse Container nutzen!

(b) 8 Punkte

Implementieren Sie eine Klasse Student. Die Klasse soll eine Methode immatrikulieren haben, der das Alter eines Studenten als Parameter übergeben wird, sowie eine Methode exmatrikulieren, sowie eine dritte Methode, die bei ihrem Aufruf den Altersdurchschnitt aller gerade immatrikulierten Studenten liefert.

(c) 8 Punkte

Implementieren Sie Klassen, die es erlauben, beliebige Längenmaße miteinander addieren zu können. Konkret sollen die Klassen so definiert werden, daß sich folgendes Programm übersetzen und mit dem angegebenen Ergebnis ausführen lassen kann:

Meter meter = new Meter(2);

meter.print(); // Ausgabe: 2.0 Meter

Fuss fuss = new Fuss(4);

fuss.print(); // Ausgabe: 4.0 Fuss

Elle elle = new Elle(6);

elle.print(); // Ausgabe: 6.0 Ellen

meter.addiere(fuss); // 2.0 Meter + 4.0 Fuss

meter.print(); // Ausgabe: 3.216 Meter

elle.addiere(meter); // 6.0 Ellen + 3.216 Meter

elle.print(); // 10.872726 Ellen

Dabei gilt: 1 Fuß = 0.304 Meter und 1 Elle = 0.66 Meter.

Achten Sie auf Erweiterbarkeit, d.h. es soll möglich sein, weitere Längenmaßklassen wie bspw. Landmeilen oder Yards zu definieren und ins Hauptprogramm zu integrieren, ohne die existierenden Klassen ändern zu müssen!

Aufgabe 3 (Java und OO Details) 20 Punkte

(a) 5 Punkte

Erläutern Sie den Unterschied zwischen dem Überladen von Methoden (overload) und dem Überschreiben von Methoden (overwrite)!

(b) 5 Punkte

Wo und mit welcher Bedeutung kann in Java das Schlüsselwort final alles eingesetzt werden?

(c) 5 Punkte

Stellen Sie sich vor, daß eine Funktion implementiert werden soll, die ein Array mit int-Werten als Parameter übergeben bekommt und die gleichzeitig die Summe und das Produkt aller dieser int-Werte zurückliefern soll. Geht das so direkt in Java? Was ist zu tun?

(d) 5 Punkte

Formen Sie die folgende do-while-Schleife in eine äquivalente for-Schleife um:

int sum = 0;

int zaehler = 1;

do {

sum += zaehler++;

} while (zaehler < 10);

Aufgabe 4 (Programmieraufgabe) 35 Punkte

In einem Programm soll ein abstrakter Datentyp Bruch verwendet werden. Dieser soll es ermöglichen, mit Brüchen zu rechnen.

Schreiben sie eine Klasse, welche diesen ADT implementiert.

Auf dem Datentypen Bruch sollen folgende Funktionen möglich sein:

a) Erzeugen eines neuen Bruches. Werte für Nenner und Zähler werden als Parameter angegeben.

b) Clonieren eines Bruches, d.h. Erzeugen eines neuen Bruches aus einem alten (Überschreiben der von der Klasse Object geerbten Methode clone).

c) Konvertieren eines Bruches in ein String-Objekt (Überschreiben der von der Klasse Object geerbten Methode toString).

d) Überprüfen auf Gleichheit zweier Brüche Objekt (Überschreiben der von der Klasse Object geerbten Methode equals).

e) Addieren zweier Brüche und Lieferung des berechneten Bruches.

f) Multiplizieren zweier Brüche und Lieferung des berechneten Bruches.

g) Addieren eines Bruches zu einem anderen.

h) Multiplizieren eines Bruches zu einem anderen.

i) Vergleich zweier Brüche auf KleinerGleich-Beziehung.

j) Konvertierung eines Bruches in einen double-Wert.

Überlegen Sie sich, wie Ihre Methoden in Fehlerfällen reagieren sollen. Denken Sie ans Kürzen. Achten Sie auf Lesbarkeit, leichte Änderbarkeit und Erweiterbarkeit Ihrer Klasse. Dokumentieren Sie schwer verständliche Stellen. Achtung: Sie brauchen nicht jede Methode mittels der javadoc-Dokumentationsrichtlinien zu dokumentieren.

Aufgabe 5 (Test) max. 5 Bonuspunkte

Schreiben Sie ein Testprogramm für die in Aufgabe 4 entworfene Klasse Bruch: Addieren Sie zwei Brüche. Lassen Sie die beiden Brüche und das Ergebnis der Addition auf dem Bildschirm ausgeben.

Musterlösung

public class A1a {

/**
* ueberprueft den uebergebenen Charakter, ob er eine Ziffer darstellt
* (Alternative 1)
* @param ch der zu ueberpruefende Charakter
* @return true, falls der uebergebene Parameter eine Ziffer darstellt,
* ansonsten false
*/
public static boolean checkDigit1(char ch) {
return (ch >= '0') && (ch <= '9');
}

/**
* ueberprueft den uebergebenen Charakter, ob er eine Ziffer darstellt
* (Alternative 2)
* @param ch der zu ueberpruefende Charakter
* @return true, falls der uebergebene Parameter eine Ziffer darstellt,
* ansonsten false
*/
public static boolean checkDigit2(char ch) {
switch (ch) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9': return true;
default: return false;
}
}

/**
* ueberprueft den uebergebenen Charakter, ob er eine Ziffer darstellt
* (Alternative 3)
* @param ch der zu ueberpruefende Charakter
* @return true, falls der uebergebene Parameter eine Ziffer darstellt,
* ansonsten false
*/
public static boolean checkDigit3(char ch) {
return ((int)ch) - ((int)'0') >= 0 &&
((int)ch) - ((int)'0') <= 9;
}

public static void main(String[] args) {

if (checkDigit3('1')) {
System.out.println("ziffer");
} else {
System.out.println("keine ziffer");
}

}

}


public class A1b {

public static int sum(int[] elements) {
int sum = 0;
for (int i=0; i sum += elements[i];
return sum;
}

public static void main(String[] args) {

int[] array = {2, 4, 5};
System.out.println(sum(array));
}

}


import java.util.*;

public class A1c {

// Alternative 1 (mit Speicher-Stackobjekt)
public static void umgekehrte_ausgabe(Stack stack) {
try {
Stack speicher = new Stack();
while (!stack.empty())
speicher.push(stack.pop());
while (!speicher.empty()) {
Object help = speicher.pop();
System.out.println(help);
stack.push(help); // wichtig, damit stack unveraendert bleibt
}
} catch (EmptyStackException e) {
System.out.println("Fehler bei pop!");
}
}

// Alternative 2 (rekursiv)
public static void umgekehrte_ausgabe2(Stack stack) {
if (stack.isEmpty()) return;
try {
Object help = stack.pop();
umgekehrte_ausgabe2(stack);
System.out.println(help);
stack.push(help); // wichtig, damit stack unveraendert bleibt
} catch (EmptyStackException e) {
System.out.println("Fehler bei pop!");
}
}

public static void main(String[] args) {

Stack stack = new Stack();
stack.push(new Integer(2));
stack.push(new Integer(3));
stack.push(new Integer(5));
stack.push(new Integer(4));
umgekehrte_ausgabe2(stack);

}

}


public class FullException extends Exception { }
public class NotExistException extends Exception { }

public class Container {
private int[] speicher;
public Container(int size) { }
public void addElement(int value) throws FullException {}
public void removeElement(int value) throws NotExistException {}
public boolean existsElement(int value) {return true;}
}

public class Menge extends Container {
public Menge(int size) {
super(size);
}
public void addElement(int value) throws FullException {
if (!existsElement(value))
super.addElement(value);
}
}

public class A2a {

public static void main(String[] args) {

Menge m = new Menge(10);

}

}


public class Student {

protected int alter;
protected boolean immatrikuliert;

static protected int anzahl_immatrikulierte_studenten = 0;
static protected int summe_alter = 0;

public void Student() {
this.immatrikuliert = false;
}

public void immatrikulieren(int alter) {
if (!this.immatrikuliert) {
this.alter = alter;
summe_alter += this.alter;
anzahl_immatrikulierte_studenten++;
this.immatrikuliert = true;
}
}

public void exmatrikulieren() {
if (this.immatrikuliert) {
summe_alter -= this.alter;
anzahl_immatrikulierte_studenten--;
this.immatrikuliert = false;
}
}

public static float altersdurchschnitt() {
if (anzahl_immatrikulierte_studenten == 0)
return 0.0f;
else
return (float)summe_alter/(float)anzahl_immatrikulierte_studenten;
}


}

public class A2b {

public static void main(String[] args) {

Student s1 = new Student();
s1.immatrikulieren(20);
Student s2 = new Student();
s2.immatrikulieren(23);

System.out.println(Student.altersdurchschnitt());
}

}


public abstract class Laengenmass {

protected float cm;

public Laengenmass(int anzahl, float faktor) {
this.cm = anzahl * faktor;
}

public Laengenmass addiere(Laengenmass mass_objekt) {
this.cm += mass_objekt.cm;
return this;
}

public abstract void print();
}

public class Meter extends Laengenmass {

private static final float UMRECHNUNGSFAKTOR = 100.0f;

public Meter(int anzahl) {
super(anzahl, UMRECHNUNGSFAKTOR);
}

public void print() {
System.out.println(this.cm / UMRECHNUNGSFAKTOR + " Meter");
}
}

public class Fuss extends Laengenmass {

private static final float UMRECHNUNGSFAKTOR = 30.4f;

public Fuss(int anzahl) {
super(anzahl, UMRECHNUNGSFAKTOR);
}

public void print() {
System.out.println(this.cm / UMRECHNUNGSFAKTOR + " Fuss");
}
}

public class Elle extends Laengenmass {

private static final float UMRECHNUNGSFAKTOR = 66.0f;

public Elle(int anzahl) {
super(anzahl, UMRECHNUNGSFAKTOR);
}

public void print() {
System.out.println(this.cm / UMRECHNUNGSFAKTOR + " Ellen");
}
}

public class A2c {

public static void main(String[] args) {

Meter meter = new Meter(2);
meter.print(); // 2.0 Meter

Fuss fuss = new Fuss(4);
fuss.print(); // 4.0 Fuss

Elle elle = new Elle(6);
elle.print(); // 6.0 Ellen

meter.addiere(fuss); // 2.0 Meter + 4.0 Fuss
meter.print(); // 3.216 Meter

elle.addiere(meter); // 3.216 Meter + 6.0 Ellen
elle.print(); // 10.872726 Ellen

}

}


A3a:
----

- Ueberladen:
Methoden einer Klasse mit demselben Bezeichner aber
unterschiedlichen Parametern

- Ueberschreiben:
Ersetzung der Implementierung einer Methode der Oberklasse
durch eine neue Implementierung.
Die Methoden muessen identische Signaturen haben.

A3b:
----

- vor Klassen: nicht weiter ableitbar
- vor Methoden: in abgeleiteten Klassen nicht ueberschreibbar
- vor Variablen: Wert nicht mehr aenderbar (Konstanten)

A3c:
----

Funktionen duerfen nur einen Wert liefern!

1. Realisierungsmoeglichkeit:

Es muss eine neue Klasse definiert werden:

public class Ergebnis {
public int summe;
public int produkt;
}

Die Funktion muss ein Ergebnis-Objekt erzeugen, fuellen und
zurueckliefern.

public Ergebnis berechne(int[] elements) {
Ergebnis ergebnis = new Ergebnis();
ergebnis.sum = 0;
ergebnis.produkt = 1;
for (int i=0; i ergebnis.sum += elements[i];
ergebnis.produkt *= elements[i];
}
return ergebnis;
}

2. Realisierungsmoeglichkeit:

Die Funktion liefert ein Array:

public int[] berechne(int[] elements) {
int[] ergebnis = new int[2];
ergebnis[0] = 0;
ergebnis[1] = 1;
for (int i=0; i ergebnis[0] += elements[i];
ergebnis[1] *= elements[i];
}
return ergebnis;
}

3. Realisierungsmoeglichkeit:

Eins der beiden Teilergebnisse wird ueber ein Objekt als Referenz-Parameter
geliefert:

public class Int {
protected int value;
public Int(int v) {value = v;}
public int get() {return value;}
public void set(int v) {value = v;}
}

public int berechne(int[] elements, Int produkt) {
int sum = 0;
produkt.set(1);
for (int i=0; i sum += elements[i];
produkt.set(produkt.get() * elements[i]);
}
return sum;
}



A3d:
----

int sum = 0;
for (int zaehler=1; zaehler<10; zaehler++) {
sum += zaehler;
}


public class NullNennerException extends Exception {}

public class Bruch {

protected int zaehler;
protected int nenner;

protected static int abs(int zahl) {
if (zahl >= 0) return zahl;
return -1 * zahl;
}

protected static int ggt(int zahl1, int zahl2) {
if (zahl1 >= zahl2) {
if (zahl1 % zahl2 == 0)
return zahl2;
else
return ggt(zahl2, zahl1-zahl2);
} else
return ggt(zahl2, zahl1);
}

protected void kuerzen() {
if (this.zaehler == 0) {
this.nenner = 1;
return;
}
int kuerz_faktor = ggt(abs(this.zaehler), abs(this.nenner));
this.zaehler /= kuerz_faktor;
this.nenner /= kuerz_faktor;
if (this.zaehler < 0) {
this.zaehler = -this.zaehler;
this.nenner = -this.nenner;
}
}

protected static boolean isBruchClass(Object obj) {
// ueberprueft, ob obj ein Objekt der Klasse Bruch oder einer
// von Bruch abgeleiteten Klasse ist!

// fuer die Klausur irrelevant!
Class class_obj = obj.getClass();
while (!class_obj.getName().equals("Bruch") &&
!class_obj.getName().equals("java.lang.Object")) {
class_obj = class_obj.getSuperclass();
}
return (class_obj.getName().equals("Bruch"));
}

public Bruch(int zaehler, int nenner) throws NullNennerException {
this.zaehler = zaehler;
this.nenner = nenner;
if (this.nenner == 0) throw new NullNennerException();
this.kuerzen();
}

protected Object clone()
throws CloneNotSupportedException, OutOfMemoryError {
try {
return new Bruch((this.zaehler, this.nenner);
} catch (NullNennerException e) {
System.out.println("InternalError");
return null;
}
}

public String toString() {
return new Double((double)this.zaehler/(double)this.nenner).toString();
// oder
//return "this.zaehler" + "/" + "this.nenner";
}

public boolean equals(Object bruch) {
if (!isBruchClass(bruch)) throw new ClassCastException();
return this.zaehler == ((Bruch)bruch).zaehler &&
this.nenner == ((Bruch)bruch).nenner;
}

public static Bruch addiere(Bruch bruch1, Bruch bruch2) {
try {
return
new Bruch(bruch1.zaehler*bruch2.nenner + bruch2.zaehler*bruch1.nenner,
bruch1.nenner*bruch2.nenner);
} catch (NullNennerException e) {
System.out.println("InternalError");
return null;
}
}

public static Bruch multipliziere(Bruch bruch1, Bruch bruch2) {
try {
return
new Bruch(bruch1.zaehler*bruch2.zaehler,
bruch1.nenner*bruch2.nenner);
} catch (NullNennerException e) {
System.out.println("InternalError");
return null;
}
}

public Bruch addiere(Bruch bruch) {
this.zaehler = this.zaehler*bruch.nenner + bruch.zaehler*this.nenner;
this.nenner = this.nenner*bruch.nenner;
this.kuerzen();
return this;
}

public Bruch multipliziere(Bruch bruch) {
this.zaehler = this.zaehler*bruch.zaehler;
this.nenner = this.nenner*bruch.nenner;
this.kuerzen();
return this;
}

public boolean kleinerGleich(Bruch bruch) {
return this.toDouble() <= bruch.toDouble();
}

public double toDouble() {
return (double)this.zaehler / (double)this.nenner;
}

}


public class A4 {


public static void main(String[] args) {

try {
Bruch bruch1 = new Bruch(-4, 8);
Bruch bruch2 = new Bruch(4, -2);
Bruch bruch3 = Bruch.addiere(bruch1, bruch2);

System.out.println(bruch1);
System.out.println(bruch2);
System.out.println(bruch3);

} catch (NullNennerException e) {
System.out.println("Nenner ist null!");
return;
}
}
}

Ergebnisse

Lehrveranstaltung

"Programmierkurs Java"

WS 1996/97

FB Informatik

D. Boles


Klausur-Ergebnisse

Die Klausur gilt als bestanden, wenn 50 Punkte oder mehr erreicht wurden. Die Scheine können ab Beginn des Sommersemesters 97 im Sekretariat bei Frau Martsfeld (OFFIS, Raum 0 48) abgeholt werden. Einblick in die eigene Klausur ist am Dienstag, den 25.02.97, zwischen 13 und 17 Uhr möglich. Die Nachklausur wird am Freitag, den 04.04.1997, von 10-12 Uhr im Hörsaal G stattfinden.

Matrikelnummer Punktzahl

6434670 71

6500100 51

6435770 Kalah-Schein

6560690 71

6435640 unentschuldigt gefehlt

6483940 77,5

6418120 44,5

6418250 84,5

6412230 17

6417860 64

5624090 unentschuldigt gefehlt

5654800 0

6550020 42,5

6420280 0

6503790 Kalah-Schein

6472690 76,5

6502270 92

6573300 36,5

6432760 64

6208750 79,5

6432500 59

6505280 48,5

6433570 33

4158150 34

6432470 84,5

5941340 48

6535700 3,5

6512840 0

6551380 26,5

6549480 83

6488860 74,5

6433150 57

6554710 69

6501460 71

6434700 31

6484460 28

6420600 67

6161190 42,5

6423030 62

6548540 77

6503400 28

6150130 0

5653830 11,5

6505310 46

6435190 73

6299310 0

6372950 53,5

5682960 4

6473080 54,5

6434540 74,5

6483100 65

6505570 50,5

6558240 48

6546500 20,5

6435220 krank

6435060 69

5507830 48,5

6418670 84,5

Statistik

Scheine: 30

Keine Scheine: 27

Krank: 1