Höhere Programmierkonzepte Testklausur



Ähnliche Dokumente
Einführung in die Programmierung

Javakurs zu Informatik I. Henning Heitkötter

Programmierkurs Java

Programmieren in Java

Java: Vererbung. Teil 3: super()

Institut für Programmierung und Reaktive Systeme 25. August Programmier-Labor Übungsblatt. int binarysearch(int[] a, int x),

Verhindert, dass eine Methode überschrieben wird. public final int holekontostand() {...} public final class Girokonto extends Konto {...

Fachgebiet Informationssysteme Prof. Dr.-Ing. N. Fuhr. Programmierung Prof. Dr.-Ing. Nobert Fuhr. Übungsblatt Nr. 6

Java Reflection. Meta-Programmierung mit der java.lang.reflection API. Prof. Dr. Nikolaus Wulff

Javadoc. Programmiermethodik. Eva Zangerle Universität Innsbruck

Objektorientierte Programmierung

Große Übung Praktische Informatik 1

Objektorientierte Programmierung. Kapitel 12: Interfaces

Das Typsystem von Scala. L. Piepmeyer: Funktionale Programmierung - Das Typsystem von Scala

SEP 114. Design by Contract

Prof. Dr. Uwe Schmidt. 21. August Aufgaben zur Klausur Objektorientierte Programmierung im SS 2007 (IA 252)

Die Java Stream API. Funktionale Programmierung mit der Stream API des JDK 1.8. Prof. Dr. Nikolaus Wulff

Übungen zu Einführung in die Informatik: Programmierung und Software-Entwicklung: Lösungsvorschlag

Einfache Arrays. Annabelle Klarl. Einführung in die Informatik Programmierung und Softwareentwicklung

Java Einführung Abstrakte Klassen und Interfaces

4. AuD Tafelübung T-C3

Testen mit JUnit. Motivation

Einführung in die Java- Programmierung

Java Einführung Collections

Prinzipien Objektorientierter Programmierung

Objektorientierte Programmierung

5. Abstrakte Klassen. Beispiel (3) Abstrakte Klasse. Beispiel (2) Angenommen, wir wollen die folgende Klassenhierarchie implementieren:

5 DATEN Variablen. Variablen können beliebige Werte zugewiesen und im Gegensatz zu

Software Engineering. Zur Architektur der Applikation Data Repository. Franz-Josef Elmer, Universität Basel, HS 2015

Typumwandlungen bei Referenztypen

5. Tutorium zu Programmieren

Programmieren in C. Macros, Funktionen und modulare Programmstruktur. Prof. Dr. Nikolaus Wulff

Themen. Web Service - Clients. Kommunikation zw. Web Services

5. Abstrakte Klassen

Delegatesund Ereignisse

Tutorium 5 - Programmieren

Java Einführung Umsetzung von Beziehungen zwischen Klassen. Kapitel 7

Der lokale und verteilte Fall

Der Aufruf von DM_in_Euro 1.40 sollte die Ausgabe 1.40 DM = Euro ergeben.

Testklausur 1 zur Vorlesung. Modellierung und Programmierung I. Dr. Monika Meiler Zeit: 60 Minuten

WebService in Java SE und EE

Klausur WS 2006/07 Programmiersprache Java Objektorientierte Programmierung II 15. März 2007

Übung Grundlagen der Programmierung. Übung 03: Schleifen. Testplan Testergebnisse

Objektbasierte Entwicklung

Folge 18 - Vererbung

Vererbung & Schnittstellen in C#

Factory Method (Virtual Constructor)

U08 Entwurfsmuster (II)

Algorithmen und Datenstrukturen

Einführung in die objektorientierte Programmierung mit Java. Klausur am 19. Oktober 2005

Institut für Programmierung und Reaktive Systeme 26. April Programmieren II. 10. Übungsblatt

3 Objektorientierte Konzepte in Java

Einführung in Javadoc

Rundung und Casting von Zahlen

Klausur zur Einführung in die objektorientierte Programmierung mit Java

Graphic Coding. Klausur. 9. Februar Kurs A

Java Kurs für Anfänger Einheit 4 Klassen und Objekte

Das erste Programm soll einen Text zum Bildschirm schicken. Es kann mit jedem beliebigen Texteditor erstellt werden.

Java Kurs für Anfänger Einheit 5 Methoden

EndTermTest PROGALGO WS1516 A

Whitepaper. Produkt: combit Relationship Manager 7. combit Relationship Manager -rückläufer Script. combit GmbH Untere Laube Konstanz

Client-Server-Beziehungen

Computeranwendung und Programmierung (CuP)

Probeklausur: Programmierung WS04/05

Übungsblatt 3: Algorithmen in Java & Grammatiken

Applet Firewall und Freigabe der Objekte

Dokumentation. Black- und Whitelists. Absenderadressen auf eine Blacklist oder eine Whitelist setzen. Zugriff per Webbrowser

Technische Hochschule Georg Agricola WORKSHOP TEIL 3. IKT (Informations- und Kommunikationstechnik) an einer MorseApp erklärt

Kapitel 6. Vererbung

Studentische Lösung zum Übungsblatt Nr. 7

Klausur in Programmieren

1 Polymorphie (Vielgestaltigkeit)

Anleitung. Ein einfaches RMI-Beispiel. (ab Java 5.0) c Y. Pfeifer. (Juni 2014)

Java 7. Elmar Fuchs Grundlagen Programmierung. 1. Ausgabe, Dezember 2011 JAV7

Musterlösungen zur Klausur Informatik 3

Objektorientierte Programmierung für Anfänger am Beispiel PHP

Dieses Tutorial gibt eine Übersicht der Form Klassen von Struts, welche Besonderheiten und Unterschiede diese aufweisen.

Design by Contract with JML

Funktionale Programmierung mit Haskell

Lösungsvorschläge. zu den Aufgaben im Kapitel 4

1. Einführung Erstellung einer Teillieferung Erstellung einer Teilrechnung 6

Remote Method Invocation

Erweiterung der Aufgabe. Die Notenberechnung soll nicht nur für einen Schüler, sondern für bis zu 35 Schüler gehen:

Melde- und Veröffentlichungsplattform Portal (MVP Portal) Hochladen einer XML-Datei

Übung Grundlagen der Programmierung. Übung 05: Arrays. Abgabetermin: xx.xx.xxxx. Java-Programm Testplan Testergebnisse

Word 2010 Schnellbausteine

Grundlagen Programmierung

Abteilung Informatik, JFC/Swing 2004 Diego Schmidlin V2.2

Einführung in die Java- Programmierung

5.2 Neue Projekte erstellen

Gebundene Typparameter

Grundkonstrukte der Objektorientierung in Java, C# und C++

Abschnitt 9: Schnittstellen: Interfaces

Stammdatenanlage über den Einrichtungsassistenten

Lehrer: Einschreibemethoden

Hilfedatei der Oden$-Börse Stand Juni 2014

Lineargleichungssysteme: Additions-/ Subtraktionsverfahren

Binäre Bäume. 1. Allgemeines. 2. Funktionsweise. 2.1 Eintragen

Deutsches Rotes Kreuz. Kopfschmerztagebuch von:

WPF Steuerelemente Listbox, ComboBox, ListView,

Transkript:

Höhere Programmierkonzepte Testklausur Prof. Dr. Nikolaus Wulff Zum 15. Januar 2016 1 Ein Google-Map Algorithmus (5 Punkte) 1 2 typedef void X; 3 typedef void Y; 4 5 void map(unsigned int n / tuple length /, 6 X x / X tuple pointer /, 7 size t sizeof X / sizeof (x [0]) /, 8 Y y / Y tuple pointer /, 9 size t sizeof Y / sizeof (y[0]) /, 10 void ( f)(x, Y ) / f : X > Y fct pointer / 11 ); Listing 1: Protypdeklartion für den Map-Algorithmus in C. Zur Verarbeitung von großen Datenmengen (BigData) hat Google den sogenannten MapReduce-Algorithmus patentieren lassen. Diese beinhaltet in einer vereinfachten Form den Map-Teil. Zu einem gegebenen Eingabetupel [x 1,..., x n ] X n berechnet der Map-Algorithmus komponentenweise für eine beliebige unäre Funktion f : X Y das Ausgabetupel [y 1,..., y n ] Y n als: [y 1,..., y n ] := map(f)([x 1,..., x n ]) [f(x 1 ),..., f(x n )]. Hierbei sind X und Y beliebige Datentypen, so dass sich dieser Algorithmus recht einfach mit Java Generics implementieren lässt aber auch einer C Implementierung mit geeignet allgemein definierten Datentypen steht nichts im Wege. Das Listing (1) zeigt die allgemeine Deklartion eines solchen Map-Algorithmus. Die Elemente aus X und Y sind als strukturlose void* Zeiger modelliert worden. Um eine sinnvolle Schleife über alle Tupelelemente ausführen zu können wird daher die jeweilige Größe eines der Elemente im zugehörigen sizeof_ Parameter an die Funktion übergeben, ebenfalls die Länge der Tupel, sowie die Tupel selber, welche vom Aufrufenden vorher geeignet alloziert sein müssen. 1. Implementieren Sie den Map Algorithmus in C passend zur Prototypdelaration (1). Beachten Sie insbesondere den richtigen Einsatz von Zeigern und wie sich void*-zeiger inkrementieren lassen. 2. Geben Sie eine generische Java Schnittstelle für die unäre Funktion f an. 0

3. Geben Sie eine generische Implementierung des Map Algorithmus in Java an unter Einbeziehung der Schnittstelle aus Teilaufgabe 2). Beachten Sie, dass sich die Signatur der Map-Methode in Java erheblich von der C Deklaration unterscheiden wird, da z.b. die Tupel-Länge nicht mehr erforderlich ist (Java Arrays kennen ihre Länge) etc. 2 Java Generics Contest (5 Punkte) class Vehicle { } class Car extends Vehicle { } class Boat extends Vehicle { } Die obige Vererbungshierarchie dient als Ausgangspunk für die Beantwortung der folgenden Fragen zu Java Generics Ist alles Ok mit den nachfolgenden Codefragmenten bzw. in welchen Zeilen gibt es einen Compiler Error (E), eine Compiler Warnung (W) oder einen Runtime Fehler (R)? Tragen Sie dann bitte die Zeilennummer in den Feldern ein oder kreuzen Sie Ok an. Falls mehrere (verdeckte) Runtime Fehler hintereinander auftreten (würden) so tragen Sie bitte alle zugehörigen Zeilennummern ein. I 1 List v0 = new ArrayList(); 2 List v1 = new ArrayList<Vehicle>(); 3 List<Vehicle> v2 = new ArrayList<Vehicle>(); 4 List<Car> v3 = new ArrayList<Vehicle>(); 5 List<Vehicle> v4 = new ArrayList<Car>(); 6 List<?> v5 = new ArrayList<Car>(); 7 List<Car> v6 = new ArrayList<?>(); II 1 List<Vehicle> v = new ArrayList<Vehicle>(); 2 v.add(new Boat()); 3 v.add(new Car()); 4 Boat b = (Boat) v.get(0); 5 Vehicle c = v.get(1); 1

III 1 List<?> v = new ArrayList<Vehicle>(); 2 v.add(new Boat()); 3 v.add(new Car()); 4 Boat b = (Boat) v.get(0); 5 Car c = (Car) v.get(1) ; IV 1 List<? extends Vehicle> v1 = new ArrayList<Vehicle>(); 2 List<? super Vehicle> v2 = new ArrayList<Vehicle>(); 3 v1.add(new Boat()); 4 v2.add(new Car()); 5 Vehicle b = v1.get(0); 6 Car c = (Car) v2.get(0); V 1 Vehicle [] v1 = new Vehicle[10]; 2 Vehicle [] v2 = new Car[10]; 3 4 v1[0] = new Boat(); 5 v1[1] = new Car(); 6 Vehicle b1 = v1 [0]; 7 Car c1 = (Car) v1 [1]; 8 9 v2[0] = new Boat(); 10 v2[1] = new Car(); 11 12 Boat b2 = (Boat) v2[0]; 13 Car c2 = (Car) v2 [1]; Tip Die entscheidene Überlegung bei dieser ist, kann der Compiler im jeweiligen konkreten Fall die erforderliche Typsicherheit zusichern und kann es eventuell zur Laufzeit zu unangenehmen Überraschungen kommen? Beachten Sie das unterschiedliche Verhalten bezüglich der Beschreib- und Lesbarkeit der jeweiligen Container bei kovarianten und kontravarianten Wildcards. 2

3 Generische Prototyp Fabrik (5 Punkte) 1 / 2 Marker interface for IPrototype classes with default constructor. 3 / 4 interface IPrototype { } 5 / 6 Factory to create prototype instances. 7 / 8 public class Factory { 9 / 10 Create a list filled with n fresh instances of the given prototype. 11 / 12 public List create(iprototype prototype, int n) throws Exception { 13 ArrayList list = new ArrayList(); 14 for(int j=0; j<n; j++) list.add(create(prototype)); 15 return list ; 16 } 17 / 18 Create a new instance of the given prototype. 19 / 20 public IPrototype create(iprototype prototype) throws Exception { 21 Class type = prototype.getclass(); 22 return create(type); 23 } 24 / 25 Create a new instance of the given type. 26 / 27 public IPrototype create(class type) throws Exception { 28 IPrototype obj = (IPrototype ) type.newinstance(); 29 return obj; 30 } 31 } Listing 2: Implementierung einer Fabrik zur Erzeugung von Prototyp Instanzen. Im Listing (2) wird die Implementierung einer Prototyp Fabrik gezeigt. Diese Fabrik erzeugt beliebig viele neue Instanzen eines an die create Methode übergebenen Objekts. Das Objekt muß das Markerinterface IPrototype erweitern und einen public Konstruktor ohne Argumente besitzen, damit die Fabrik weitere Instanzen dieser Klasse erzeugen kann. Ob es sich um Instanzen von IPrototyp handelt, wird in den ersten beiden create Methoden durch die Signatur erzwungen und vom Compiler überprüft. In der dritten create Methode ist diese Bedingung nicht mehr erkennbar und der Compiler kann nicht sicherstellen, dass das übergebene Class Objekt auf implementierende Klassen vom Typ IPrototyp abzielt. Diese Implementierung einer Fabrik entspricht dem Programmierstil vor der Einführung von Java Generics und garantiert noch keine Typsicherheit. Dies ist auch in dem illustrierenden Anwendungsbeispiel (3) erkennbar: Eine einzige Fabrik ist in der Lage beliebig viele Instanzen von beliebig vielen unterschiedlichen IPrototyp Klassen zu erzeugen. Im Beispiel sind dies die Klassen Foo und Bar, der Typ der Foo Instanz wird per Cast erzwungen, dass sich in der Liste Bar Objekte befinden sollen ist nicht mehr ersichtlich. 3

Das die Fabrik noch nicht mittels Generics arbeitet ist an dem Cast des Rückgabewertes der Fabrik und innerhalb der Implementierung zu erkennen. Seit der Einführung der Java Generics gehören solche Casts und Inkonsistenzen der Vergangenheit an. 1 class Bar implements IPrototype { 2 public Bar() {} 3 } 4 class Foo implements IPrototype { 5 public Foo() {} 6 } 7 8 public class Example { 9 public static void main(string[] args) throws Exception { 10 Factory factory = new Factory(); 11 12 Foo prototype1 = new Foo(); 13 Bar prototype2 = new Bar(); 14 15 Foo inst = (Foo) factory.create(prototype1); // one Foo instance 16 List list = factory.create(prototype2,10); // ten Bars in List 17 18 // do something with Foo and Bar... 19 } 20 } Listing 3: Verwendung der Prototyp Fabrik. Die Prototyp Fabrik soll mit Java Generics realisiert werden. Hierzu müssen sowohl die IPrototyp Schnittstelle, als auch die Signaturen der Fabrik Methoden neu definiert und ausimplementiert werden. Tip 1. (1 Punkt) Definieren Sie das Prototyp Markerinterface mit Hilfe von Generics typsicher als IPrototyp<...> neu, so dass der Datentyp und die Vererbungshierarchie für den Compiler überprüfbar ist. 2. (3 Punkte) Schreiben Sie eine neue Implementierung der Fabrik, passend zur neuen IPrototyp Schnittstelle. 3. (1 Punkt) Schreiben Sie das Beispiel (3) angepasst für Generics neu. Die Methoden selber sind nur 2 3 Zeiler, sie brauchen daher die Kommentare des Quelltexts nicht mit abschreiben. Die Klausur soll nicht in Schreibarbeit ausarten. Achten Sie bei der Definition der neuen IPrototyp<...> Schnittstelle darauf, dass der generische Typ auch selber die IPrototyp Schnittstelle erweitert, damit so etwas wie IPrototyp<String> oder IPrototyp<Object> nicht möglich ist und bereits vom Compiler als Fehler verworfen wird. 4

4 Test einer generischen Operation (5 Punkte) 1 interface Operation<A, R, E extends Exception> { 2 R operate(a...args) throws E; 3 } Listing 4: Generische Operation-Schnittstelle. Die Schnittstelle (4) definiert eine generische Operation, mit ihren Argument(en) vom Typ A als Varargs, einem Ergebnistyp R und einer möglichen geworfenen Ausnahme vom Typ E. Passend zur Schnittstelle (4) ist der generische JUnit Test (5) entwickelt worden. Überprüft werden das Verhalten bei richtigen, bei illegalen und bei fehlenden Argument(en). Die drei finalen Testmethoden definieren die minimalen Anforderung zur Überprüfung einer Operation-Implementierung. Konkrete Testklassen müssen die drei abstrakten create-methoden zum setup des Tests und zwei Validierungsmethoden für das Ergebnis und für geworfene Ausnahmen zur Verfügung stellen. Die Validierungsmethoden liefern ein true zurück, falls das Ergebnis bzw. die Ausnahme der Testerwartung entsprechen, andernfalls false. Ein Entwickler kann sich unter Verwendung dieses Basistests auf weitere fachliche Tests konzentrieren. Tip 1. (2 Punkte) Implementieren sie die Klasse SquareRoot, die obige Operation Schnittstelle implementiert. SquareRoot liefert die Wurzel einer reelen, positiven Zahl (Typ Double in Groß!) und wirft eine IllegalArgumentException falls das Argument negativ ist oder nicht genau ein Double als Vararg übergeben wird. 2. (2 Punkte) Schreiben Sie die Klasse SquareRootTest und implementieren Sie die fehlenden abstrakten Methoden als Erweiterung von OperationTest, so dass die Klasse SquareRoot sinnvoll getestet wird. 3. (1 Punkt) Es gibt mehr als nur eine Möglichkeit illegale Argumente an die Operation zu übergeben. Es ist daher noch eine weitere Testmethode notwendig, so dass Sie sowohl den Fall eines negativen Arguments, als auch den Fall von mehr als einem Varargs-Argument testen können. Sehen Sie daher noch eine weitere Testmethode vor, die den jeweils fehlenden dieser zwei Fälle zusätzlich überprüft. Damit Sie nicht seitenlange JUnit Klassen schreiben müssen bietet Ihnen das Listing (5) eine Vorlage und Anleitung, für Ihre eigene Testklasse. Sie müssen nur die fünf abstrakten Methoden und eine zusätzliche Testmethode implementieren. Sie müssen OperationTest nicht abschreiben, sondern nur sinnvoll erweitern. 5

1 public abstract class OperationTest<A,R,E extends Exception> { 2 protected Operation<A,R,E> undertest; 3 protected A[] validargs; 4 protected A[] invalidargs; 5 6 / Helper method to validate the return of the test. / 7 protected abstract boolean validatereturn(r r); 8 / Helper method to validate an exception of the test. / 9 protected abstract boolean validateerror(exception e); 10 / Helper method to create the operation under test. / 11 protected abstract Operation<A,R,E> createoperation(); 12 / Helper method to create valid test arguments. / 13 protected abstract A[] createargs(); 14 / Helper method to create invalid test arguments. / 15 protected abstract A[] createinvalidargs() ; 16 17 / 18 Setup of the test case(s). 19 / 20 @Before public final void setup() throws Exception { 21 undertest = createoperation(); 22 invalidargs = createinvalidargs(); 23 validargs = createargs(); 24 } 25 / 26 Test with legal arguments, validating the return value. 27 / 28 @Test public final void testvalidargs() throws Exception { 29 R retvalue = undertest.operate(validargs); 30 asserttrue( wrong result: +retvalue, validatereturn(retvalue)); 31 } 32 / 33 Test with illegal arguments, validating the exception. 34 / 35 @Test public final void testinvalidargs() throws Exception { 36 try { 37 undertest.operate(invalidargs); 38 fail ( invalid arguments not detected ); 39 } catch(exception error) { 40 asserttrue( wrong error: +error, validateerror( error)); 41 } 42 } 43 / 44 Test for a NullPointer as argument. 45 / 46 @Test(expected=NullPointerException.class) 47 public final void testnullargs() throws Exception { 48 A[] nullargs = null; 49 undertest.operate(nullargs); 50 } 51 } Listing 5: Generischer JUnit Test für eine Operation. 6