Teil 1: Grundeigenschaften von Rechnern und Software [10P]
Aufgabe 1.1 - Programmieren Lernen [5P] 0,5P pro richtigem Feld Klassifizieren Sie die folgenden Aussagen als richtig oder falsch
Beim Programmieren lernen… Richtig Falsch
…muss man eine neue Art zu denken lernen [X] [ ]
…geht es darum, möglichst viel auswendig zu lernen [ ] [X]
…geht es darum, möglichst viel zu üben und zu verstehen [X] [ ]
…braucht man Geduld und Durchhaltevermögen für die Anfangshürde [X] [ ]
…ist eine Geisteshaltung wie beim Rätseln nützlich. Dann macht es Spass! [X] [ ]
Aufgabe 1.2 - Programmierung in der Praxis [5P] 0,5P pro richtigem Feld Klassifizieren Sie die folgenden Aussagen als richtig oder falsch
Beim Programmieren… Richtig Falsch
…ist der Compiler eher lästig als hilfreich weil er so viele Fehler anzeigt [ ] [X]
…muss man viele Programme schreiben. Programme lesen hält nur auf [ ] [X]
…sind Laufzeitfehler schlimmer als Syntaxfehler [X] [ ]
…hat man die besten Ideen unter Zeitdruck, z.B. Donnerstag nachts [ ] [X]
…kommt es nur auf die Funktion an, die Form eines Programms ist egal [ ] [X]
Teil 2: Grundlagen der Kodierung von Informationen [10P]
Aufgabe 2.1 - Zahlensysteme [5P] 1P pro Antwort mit Rechenweg, sonst -0,5P Rechnen Sie die folgenden Zahlen in das jeweils angegebene Zahlensystem um Hinweis: Der Rechenweg muss erkennbar sein!
Bin: 10111101 --> Hex: 1011 1101 = 0xBD (hex) 1 Hexziffer = 4 Bit
Hex: 4BA --> Dez: 0100 1011 1010 = 1024 + 176 + 10 = 1210 x256 x16 x1
NICHT: 4=4 + B=11 +A=10 => 25 %$§&!
Dez: 169 --> Okt: 251 (Restwertalgorithmus oder "Basteln") 169 => 21 R1 => 2 R5 => 0 R2
Probe: 2x64 + 5x8 + 1 = 169
Okt: 666 --> Bin: 6x64 + 6x8 + 6 = 438 = 110 110 110 (Restwert oder je 3Bit)
Bin: 11101111 --> Dez (mit Vorzeichen!): 11101111 (vorne 1, negativ) => 00010000 (Komplement) => 00010001 (+1)
=> -17
Aufgabe 2.2 Berechnungen in anderen Zahlensystemen [5P]
Berechnen Sie im jeweiligen Zahlensystem:
Dezimal: 7384 Binär: 10011010 +154 1P + 1631 1P + 01010110 + 86 1100 00111100 110 9015 11110000 +240
Oktal: 123 83 Hex: ABE9 44009 1,5P + 456 +302 1,5P + 0FEE 04078 110 000 1110 00010 601 385 (0)BBD7 48087
Teil 3: Elementare Programmbestandteile [40P]
Aufgabe 3.1 - Datentypen [5P] je 1P Beantworten Sie die folgenden Fragen:
Welche Eigenschaften (einer Variablen) charakterisiert ein Datentyp NICHT (durchstreichen)?
[Wertebereich] [Lebensdauer] [Speicherbedarf] [Speicherort] [Gültige Operationen]
XXXXXXX XXXXXXX
Was passiert, wenn Sie eine Variable mit Referenztyp einer anderen Variablen zuweisen?
Es wird nur die Referenz kopiert, das zugehörige Objekt wird jetzt gemeinsam verwendet.
Was passiert, wenn man auf den char Wert 'a' den ++Operator anwendet?
JA DAS GEHT WIRKLICH, VGL. ÜBUNG ZUM THEMA DATENTYPEN!!!
Der interne Wert des Zeichens 'a' =65 wird um 1 erhöht (0,5P). Damit ergibt sich ein 'b'=66 (0,5P).
Welchen Datentyp ist am Besten zur Darstellung einer Telefon-Nr. geeignet?
Der Datentyp String (wg. Trennzeichen etc.; 0,5P für long) Welcher Datentyp wird in Java für Wahrheitswerte verwendet?
Der Datentyp boolean
Aufgabe 3.2 - Literale [5P]
Beantworten Sie die folgende Fragen:
Was versteht man unter einem Literal? 1P
Ein Literal ist ein Wert, den man direkt hinschreiben kann.
Geben Sie für folgende Datentypen jeweils ein korrektes Literal an? 4 x 1 = 4P
int 1 Ganzzahl ohne Komma
float 1.0f Kommazahl mit Zusatz f
String "Text" Text in Anführungszeichen
char-Array { 'a', 'b', 'c'} char-Werte in { }
Aufgabe 3.3 - Variablen [5P]
Beantworten Sie die folgenden Frage:
Was ist versteht man unter einen LValue? Nennen Sie ein Beispiel? 1P
Ein LValue ist ein Ausdruck, der auf der linken Seite einer Zuweisung stehen darf, d.h. er muss für einen Speicherplatz stehen, dem man etwas zuweisen kann, z.B. eine Variable o. ein Array-Feld.
Welche Art von Variablen hat die gleiche Lebensdauer wie ein Java Programm? 1P
Klassenvariablen (statische Variablen, mit static) sind Teil des Bauplans und immer vorhanden.
Dasselbe gilt im Prinzip für lokale Variablen in der main()-Methhode (später mit GUI nicht mehr!) Welche Art von Variablen hat die gleiche Lebensdauer wie ein Methodenaufruf? 1P
Parameter und lokale Variablen liegen auf dem Stack und verschwinden beim Rücksprung
Skizzieren Sie Struktur und Wertebelegung der folgenden Array-Variablen im Speicher 2P
int[] shapeArray = new int[3];
shapeArray[0] = 1;
shapeArray[1] = 7;
int[3] shapeArray --> int 1 falls “Anzahl” Subelemente statt „Wert“ nur 0,5P
int 7
int 0 -0,5P für null;
Aufgabe 3.4 - Ausdrücke [10P] 2 x 5 x 1 = 10P Beantworten Sie die folgenden Fragen
Geben Sie den Datentyp der folgenden Ausdrücke an (mit i=int-Variable, d=double-Variable)
d * i Antwort: double (gemischte Multiplikation)
i > 0 Antwort: boolean (Vergleichsoperator)
d – i < 0.01 Antwort: boolean (Vergleichsoperator)
0x24 & 0x04 Antwort: int (Bit-Operation)
1534L++ Antwort: long (Inkrement von long-Literal)
Berechnen Sie den Wert der folgenden Ausdrücke
21 << 2 Antwort: 84 bzw. 1010100
020 + 0x08 Antwort: 16 + 8 = 24
3/2 <= 1 Antwort: true, da 3/2 in int = 1
2 * 5.5+3 * 1.5 Antwort: 15.5 (Punkt-vor-Strich)
0x01 | 0x02 Antwort: 0x03 da 00000001 | 00000010 = 00000011
Aufgabe 3.5 - Kontrollstrukturen [10P]
Geben Sie für folgende Aufgaben jeweils eine geeignetes Programmstück an.
a) Erzeugung der folgenden Bildschirmausgabe (mit einer echten Zufallszahl zwischen 0 und 9!) Sequenz, Folge von Anweisungen mit ?: bzw. if:
int z = (int)(Math.random()*10);
Meine neue Zufallszahl ist 9 System.out.println( "Text " + z);
Ist diese Zahl gerade? false System.out.println( "Text? " + (z%2==0));
b) Ausgabe von "Quadratzahl" wenn die Wurzel einer gegebenen Variablen z eine glatte Zahl ist.
Selektion mit if-else (2P = Verzweigung + Ausdrücke) IF-IST-KEINE-SCHLEIFE !!!!!
int r = (int)Math.sqrt( z);
if ( r*r==z) { // genauer: Math.abs( r*r-z) < 1e-5 System.out.println( "Quadratzahl");
}
c) Berechnung folgender Zahlenreihe. Abbruch und Ausgabe beim ersten Glied mit Wert > 100
1 2 4 7 11 16 22 29…
while-Schleife (2P = Schleife + Schrittweite + Berechnung) int s = 1; int s = 1;
int n = 1;
while ( s<100) { for ( int n=1; s<100; ++n) { s += n; s += n;
n++;
} }
System.out.println( "s=" + s); System.out.println( "s=" + s);
System.out.println( "n=" + n); System.out.println( "n=" + n);
d) Berechnung und Ausgabe der Zeilensummen in dem 2-dimensionalen int-Array matrix.
Geschachtelte Schleifen (neue for-Schleife oder alte Schleifen mit i und j (4P = 2 Schleifen + Vars) for ( int row=0; row<matrix.length; ++row) {
int summe = 0;
int[] numbers = matrix[row];
for ( int number : numbers) { summe += number;
}
System.out.println( row + "te Zeile=" + summe);
}
Aufgabe 3.6 - Funktionen [5P]
Beantworten Sie die folgenden Fragen
Ordnen Sie die folgenden Methoden den richtigen Aufrufen in der main()-Methode zu.
public class Klausur {
String semester;
int jahr = 0;
public Klausur( String semester, int jahr) { // (a) this.semester = semester;
this.jahr = jahr;
}
public Klausur( int jahr, String semester) { // (b) this.semester = semester;
this.jahr = jahr;
}
public void aufgabe( float f) { // (c) // Aufgabe am Bildschirm anzeigen
}
public void aufgabe( double d) { // (d) // Aufgabe am Bildschirm anzeigen
}
public void aufgabe( int i, float f) { // (e) // Aufgabe am Bildschirm anzeigen
}
public void aufgabe( boolean b) { // (f) // Aufgabe am Bildschirm anzeigen
}
public void aufgabe( String text) { // (g) // Aufgabe am Bildschirm anzeigen
}
public static void main( String[] args) {
Klausur k = new Klausur("WS", 2010); // (a)
k.aufgabe( 5,9f); // (e)
k.aufgabe( 'a'<'b'); // (f)
k.aufgabe( Math.PI); // (d)
k.aufgabe( new Object().toString()); // (g) }
}
je 1P pro richtiger Antwort
Teil 4: Objektorientierte Konzepte [10P]
Aufgabe 4.1 - Kapselung [5P] + 1ZP je 1P pro Antwort inkl. Begründung In Java gibt es verschiedene Möglichkeit, den Zugriff auf Variablen und Methoden zu verbieten. Nennen Sie jeweils die Elemente der Klasse Duck welche für die Klasse Mouse im gleichen Paket sowie die Klasse Panzerknacker im Paket entenhausen.gauner nicht zugänglich sind.
// Datei: Duck.java package entenhausen;
public class Duck {
private static Duck dagobert = new Duck( "Dagobert", 1e9);
private static Duck donald = new Duck( "Donald", 0);
String name;
private double money;
private Duck( String name, double money) { this.name = name;
this.money = money;
}
public String getName() { return name;
}
public static Duck getDagobert() { return dagobert;
}
public static Duck getDonald() { return donald;
} }
Mouse hat keinen Zugriff auf
- Konstruktor – ist private (andere Klasse) - money – ist private (andere Klasse)
Panzerknacker hat keinen Zugriff auf
- Konstruktor – ist private (andere Klasse) - money – ist private (andere Klasse)
- name – ist default (anderes Paket)
Die statische Variablen sind indirekt zugänglich über die get-Methoden()
Zusatzfrage: Warum ist der Konstruktor private? Wieviele Ducks gibt es maximal? (1P) Der private Konstruktor verhindert die Erzeugung neuer Instanzen. Es gibt also genau 2.
Aufgabe 4.2 - Vererbung [5P] + 1ZP 1P pro Stichwort / Begründung Beantworten Sie die folgenden Fragen
Wieviele Wurzeln hat die Vererbungshierarchie aller Java Klassen? (1P) genau eine, die Klasse Object
In der folgenden Vererbungshierarchie wird die Vererbung falsch eingesetzt. Benennen Sie die fehlerhafte(n) Stelle(n) und machen Sie wenn möglich entsprechende Korrekturvorschläge.
Gesellschaftsspiel name : String einsatz: double
Würfelspiel wuerfelzahl : int augenzahl : int ohrenzahl : int
Kniffel punktzahl : int
Brettspiel figuren : String[]
Kartenspiel spielerZahl : int karten : String[]
Poker regelVariante :String
Zimmern holzsorte : String
Die spielerZahl ist allgemein und gehört in die Klasse Gesellschaftsspiel Der Einsatz gehört ggf. in die Klasse Poker bzw. Kartenspiel
Zimmern ist kein Brettspiel sondern ein Handwerk Die Ohrenzahl im Würfelspiel ist Quatsch
Zusatzfrage: Wo/wie würden Sie das Spiel "Mensch ärgere Dich nicht!" einordnen? (1P) Das ist schwierig, weil man nicht von Würfel- und Brettspiel erben kann! Letzteres passt besser.
Teil 5: Angewandte Programmierung [30P]
Aufgabe 5.1 [10P] je 2P pro richtiger Diagnose bzw. Korrektur
Interpretieren Sie die folgenden Code-Beispiele sowie die zugehörigen Fehlermeldungen und machen Sie jeweils einen Korrekturvorschlag Quellcode
public class Dice {
int sides;
public Dice( int sides) { this.sides=sides;
}
public int roll() {
return Math.random()*sides+1;
}
public static void main( String[] args) { Dice d = new Dice( 6);
for ( int i=1; i<=3; ++i) {
System.out.println( i + "ter Wurf=" + d.roll());
} } }
Fehlermeldung (zur Laufzeit)
Dice.java:11: possible loss of precision found : double
required: int
return Math.random()*sides+1;
^ 1 error
Problem/Lösung
Math.random() liefert double. Der Rückgabewert von roll() ist ein int (1P).
Daher muss das Rechenergebnis noch nach int gecasted werden. Die Zeile muss also lauten:
'return (int)( Math.random()*sides+1);' (1P)
Hinweis: double erbt nicht von int oder umgekehrt; es handelt sich also um keinen up- oder downcast, bei dem ein Objekt anders interpretiert wird sondern um eine echte Typkonvertierung.
Quellcode
public class Trial {
public boolean dangerousTask() throws Exception { // ...
}
public static void main( String[] args) { boolean successful = false;
try {
successful = dangerousTask();
} while (!successful);
} }
Fehlermeldung
Trial.java:10: 'try' without 'catch' or 'finally' try {
^ 1 error
Problem/Lösung
In dem Programm wurde die Kontrollstruktur do-while und das Konstrukt try-catch vermischt.
Richtig wäre, eine do-while-Schleife zu implementieren in deren Rumpf ein try-catch-Konstrukt den Aufruf von dangerousTask() schützt.
Quellcode
public class Vehicle { String model;
public Vehicle( String model) { model = model;
}
public String getModel() { return model;
}
public static void main( String[] args) { Vehicle v = new Vehicle( "Batmobil");
System.out.println( v.getModel());
} }
Ausgabe:
null
Problem/Lösung
Die Zuweisung im Konstruktor ist eine Selbstreferenz der lokalen Variablen. Die Instanzvariable 'model' wird nicht initialisiert. Richtig wäre 'this.model = model;'
Quellcode
public class Calculator {
public static void main( String[] args) { CommandLine cl = new CommandLine();
double d = cl.readFloat( "Welche Wurzel soll ich ziehen? ");
System.out.println( "Die Wurzel von " + d + " ist " + Math.squareRoot(d));
} }
Fehlermeldung
Calculator.java:7: cannot find symbol symbol : method squareRoot(double) location: class java.lang.Math
System.out.println( "Die Wurzel von " + d + " ist " + Math.squareRoot(d));
^ 1 error
Problem/Lösung
Die Methode in der Klasse Math heißt nicht squareRoot() sondern sqrt().
Quellcode
public class PeopleTest {
public static void main( String[] args) {
// Anmerkung: Die Klasse 'Engineer' erbt von der Klasse 'Person' Person p1 = new Person(), p2 = new Engineer();
Engineer helper;
int problem = (int)(Math.random()*100);
if ( problem<30) {
helper = (Engineer)p1;
} else {
helper = (Engineer)p2;
}
System.out.println( helper + " will fix the problem");
} }
Ausgabe:
Meistens erscheint eine Ausgabe wie
Engineer@de6ced will fix the problem
Manchmal jedoch erscheint stattdessen
Exception in thread "main" java.lang.ClassCastException: Person cannot be cast to Engineer at PeopleTest.main(PeopleTest.java:11)
Problem/Lösung
Durch die Zufallsfunktion wird gelegentlich auch die echte 'Person' p1 ausgewählt. Diese kann aber einer Variablen vom Typ 'Engineer' nicht zugewiesen werden (fehlerhafter downcast!). Die Variable 'helper' muss daher vom Typ 'Person' sein.
Aufgabe 5.2 - Programme lesen [10P]
Analysieren Sie das folgende Programm, beschreiben Sie die Bedeutung der einzelnen Variablen/Schritte und geben sie die Ausgabe des Programms an.
public class Mystery {
public static void main( String[] args) { double K = 1000; // investiertes Kapital
double[] pa = { 0.02, 0.03, 0.04}; // Zinsstufen
int n=0; // Zähler für Jahre for ( double p : pa) {
System.out.println( n + ": K = " + K); // Ausgabe für Jahr n K *= (1+p); // Berechnung der Verzinsung
n++;
}
System.out.println( n + ": K = " + K); // Ausgabe Endwert }
}
Funktion:
Berechnung einer mehrjährigen Stufenzinsanleihe (z.B. Bundesschatzbrief Typ B) mit Zinseszins.
Ausgabe:
0: K = 1000.0 1: K = 1020.0
2: K = 1050.6000000000001 3: K = 1092.6240000000003
Aufgabe 5.3 - Programme schreiben [10P] + 3 ZP
Das folgende Programm dient zum kürzen von Brüchen Ergänzen Sie die fehlenden Stellen!
Hintergrundinformation:
Die Bestimmung des größten gemeinsamen Teilers mit Hilfe von Primfaktoren ist sehr aufwändig.
Beim euklidischen Algorithmus wird in aufeinanderfolgenden Schritten jeweils eine Division mit Rest durchgeführt, wobei der Rest im nächsten Schritt zum neuen Divisor wird. Der Divisor, bei dem sich Rest 0 ergibt, ist der größte gemeinsame Teiler der Ausgangszahlen.
Beispiel:
1071 : 1029 = 1 Rest 42 1029 : 42 = 24 Rest 21 42 : 21 = 2 Rest 0
Somit ist 21 der größte gemeinsame Teiler von 1071 und 1029.
Quellcode:
public class Fraction {
int nominator, denominator;
public Fraction( int nominator) { this( nominator, 1);
}
public Fraction( int nominator, int denominator) { this.nominator = nominator;
this.denominator = denominator;
}
public int getNominator() { return nominator;
}
public int getDenominator() { return denominator;
}
public Fraction multiply( Fraction other) { int n = this.nominator * other.nominator;
int d = this.denominator * other.denominator;
return new Fraction( n, d);
}
public Fraction divide( Fraction other) { int n = this.nominator * other.denominator;
int d = this.denominator * other.nominator;
return new Fraction( n, d);
}
public Fraction add( Fraction other) {
if ( this.denominator==other.denominator) { int n = this.nominator + other.nominator;
return new Fraction( n, denominator);
} else {
int d = this.denominator * other.denominator;
int n1 = this.nominator * other.denominator;
int n2 = other.nominator * this.denominator;
return new Fraction( n1+n2, d);
} }
public Fraction subtract( Fraction other) { if ( this.denominator==other.denominator) { int n = this.nominator - other.nominator;
return new Fraction( n, denominator);
} else {
int d = this.denominator * other.denominator;
int n1 = this.nominator * other.denominator;
int n2 = other.nominator * this.denominator;
return new Fraction( n1-n2, d);
} }
// hier sollen Zähler und Nenner mit dem ggT gekürzt werden!
public void simplify() {
int z1 = nominator, z2 = denominator;
int r;
do {
r = z1 % z2; // hier Berechnung ergänzen z1 = z2; // hier Berechnung ergänzen z2 = r; // hier Berechnung ergänzen } while ( r>0);
nominator /= z1;
denominator /= z1;
}
@Override
public String toString() {
return super.toString() + " " + nominator
+ (denominator>1 ? "/" + denominator : "");
}
public static void main( String[] args) { Fraction f1 = new Fraction( 2);
Fraction f2 = new Fraction( 1, 2);
Fraction f3 = f1.multiply( f2);
Fraction f4 = f3.add( f2);
Fraction f5 = f4.divide( f2);
Fraction f6 = f5.subtract( f2);
System.out.println( f1); // Ausgabe (s.u.): 2
System.out.println( f2); // Ausgabe (s.u.): 1/2
System.out.println( f3); // Ausgabe (s.u.): 2/2
System.out.println( f4); // Ausgabe (s.u.): 3/2
System.out.println( f5); // Ausgabe (s.u.): 6/2
System.out.println( f6); // Ausgabe (s.u.): 5/2
System.out.println( f5);
f5.simplify();
System.out.println( f5); // Ausgabe (s.u.): 3 }
}
Zusatzfrage: Geben Sie die Ausgaben der println()-Aufrufe in der main()-Methode an (3P) Siehe Kommentare oben