Klausur zur Lehrveranstaltung
"Programmierkurs Java"
WS 1996/97
FB Informatik
D. Boles
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 !
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:
Implementieren Sie die Klasse Menge, indem Sie die Klasse Container nutzen!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);
}
(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:
Dabei gilt: 1 Fuß = 0.304 Meter und 1 Elle = 0.66 Meter.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
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;Aufgabe 4 (Programmieraufgabe) 35 Punkteint zaehler = 1;
do {
sum += zaehler++;
} while (zaehler < 10);
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.
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;
}
}
}
Lehrveranstaltung
"Programmierkurs Java"
WS 1996/97
FB Informatik
D. Boles
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