Übungsblatt 11

Werbung
LehrstuhlfürBioinformatik
EinführungindieProgrammierungfürBioinformatiker
Prof.B.Rost,Dr.L.Richter
Blatt11
16.1.2017
Interfaces,GenericsundExceptions
Aufgabe11.1.ErweiterunggeometrischeFiguren
IndieserAufgabesollendieKlassendergeometrischenFormenvondenbeiden
vorherigenAufgabenblätternerweitertwerden.
• DieKlassenvomTypPrismaundGrundflaechesollenuntereinander
vergleich-bargemachtwerden,indemdieKlassendasInterface
Comparable<Prisma>bzw.Comparable<Grundflaeche>
implementieren(https://docs.oracle.com/javase/7/docs/api/java/lang/
Comparable.html)
•
o PrismenwerdennachGrößedesVolumensverglichen;
o GrundflaechenwerdennachGrößederFlächeverglichen.
o Zur Vereinfachung ignorieren wir Abweichungen durch
Gleitkommaarithmetik und gehen davon aus, dass solche nicht
vorkommen. D.h. die Flächen zweier Grundflächen sind gleich,
wenndieDifferenzexakt0ist.DiegleicheAnnahmetreffenwirfür
dasVolumenvonPrismen.
ImplementierenSiedazudieMethodepublic int
compareTo(Prisma o)bzw.public int
compareTo(Grundflaeche o) inderKlassePrismabzw.
Grundflaeche.HaltenSiesichdabeiandieVorgabenderJava
DokumentationfürdasInterfaceComparable<T>unter
https://docs.oracle.com/javase/7/docs/api/java/lang/Comparable.html.
BeachtenSieinsbesondere,dassggf.eineNullPointerException
geworfenwird.
•
TestenSiedieImplementierung,indemSiejeweilseineLinkedList
mitGrundflaeche-ObjektenundeineLinkedListmitPrismaObjektenmittelsCollections.sort(List<T> list)
sortieren.Beispiel:List<Prisma> pf = new
LinkedList<Prisma>(); Collections.sort(pf);
•
AlszweitenSchrittsollendieMethodenistQuadratundzuQuadrat
ineinInterfaceQuadrierbarausgelagertwerden,welchesnurvon
solchenGrundflaechenimplementiertwerdensoll,dieauchein
Quadratdarstellenkönnen.
•
ZuletzterstellenwireinweiteresInterfacePolygonmitnureiner
Methodeint getEckenAnzahl(),welchedieZahlderineiner
GrundflächeenthaltenenEckenzurückgibt.ImplementierenSiedas
InterfacePolygonfüralleGrundflächen,dieeineendlicheAnzahlvon
Eckenbesitzen.
•
TestenSieQuadrierbarundPolygon,indemSieübereine
LinkedListdesTypenComparable,dieverschiedenePrisma-und
Grundflaeche-Objekteenthält,iterierenundmittelsinstanceof die
VerfügbarkeitderbeiderInterfacesabfragenund,fallsvorhanden,dieaus
diesenInterfacesermittelbarenInformationenausgeben.
•
DeklarierenSiealleObjektvariablenalsfinal,wodasmöglichist.
Hinweis:ZurVerwendungdergenanntenKlassenundMethodenausderJavaStandardbibliothekbenötigenSiediefolgendenImports.
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
Aufgabe11.2.Typischgenerisch
Generics(zudeutsch:GenerischeProgrammierung)sindeinKonzeptinJava,
welcheserstinVersion1.5hinzugekommenist.D.h.dieIdeedahinterwarnie
TeilderinitialienImplementierungderSprache.Diesmerkenwiran
verschiedenstenStellen.Umabwärts-kompatibelzusein,alsogenerischenJavaCodeabVersion1.5mitnichtgenerischemJava-CodevonVersionen1.4und
früherzuverknüpfen,hatmansichentschieden,generi-scheDatentypenzur
Compile-ZeitdurchnichtgenerischeDatentypenzuersetzen.DieserVorgang
wirdi.A.als„typeerasure“(zudeutsch:Typlöschung)bezeichnet.Schauenwir
unsdasaneinemBeispielan:
public class A<T> {
public void foo(T x) { }
}
public class B extends A<String> {
public void foo(String x) { }
}
InderabgeleitetenKlasseBschränkenwirdengenerischenDatentypTaufden
konkretenTypStringein.DesWeiterenüberschreibenwirdieMethodefoo,die
jetzteinenStringerwartet.BetrachtenSienunfolgendesCodefragment:
B b = new B();
b.foo("Hello Student!");
A a = b;
a.foo(42);
DasCodefragmenttyptkorrektundlässtsichohneProbleme(Warnungen/
Fehler)vomCompilerübersetzen.FührenwirdenCodeaus,dannerhaltenwir
eineClassCastException.Wieso?SchauenwirunsdazumaldenCodean,
dernachder„typeerasure“entsteht:
public class A {
public void foo(Object x) { } // T wird durch Object
// automatisch vom
// Compiler ersetzt
}
public class B extends A {
// <String> wurde
// entfernt
public void foo(String x) { } // ...
}
DerCompilerhatdenTypTdurchObjectinderKlasseAersetzt.Dasbedeutet
abernun,dassdieMethodefooausderKlasseBnichtmehrdieMethodefoo
aus der Klasse A überschreibt, da die Methodensignaturen nicht mehr
übereinstimmen.Damitnachder„typeerasure“dieMethodefoowiederinder
Klasse B überschrieben wird, fügt der Compiler automatisch eine weitere
Methodefoohinzu.DerCodesiehtschlussendlichwiefolgtaus:
public class B extends A {
// <String> wurde entfernt
public void foo(String x) { }
public void foo(Object x) {
foo((String) x);
}
// diese Methode wird
// automatisch vom
// Compiler erstellt
}
Damit die Methode foo aus der Klasse A in der Klasse B wieder überschrieben
wird,fügtderCompilereinesogenannte„bridge“Methodeein.Indieserwirdein
Castvorgenommen.D.h.dasProgrammtyptkorrektliefertaberzurLaufzeiteine
ClassCastException, da ein Integer-Objekt nicht in ein String-Objekt
gecastetwerdenkann.
Aufgrundder„typeerasure“könnenwirinderKlasseAauchkeineMethode
foo(Object x)definieren,d.h.folgenderCodecompiliertnicht:
public class A<T> {
public void foo(T x) { }
public void foo(Object x) { } // compiliert nicht }
Denn nach der „type erasure“ würden ansonsten zwei Methoden mit der
gleichenSignaturexistieren.
DieoffizielleDokumentation(https://docs.oracle.com/javase/tutorial/java/
generics/erasure.html)sagtdazufolgendes:
GenericswereintroducedtotheJavalanguagetoprovidetightertypechecksat
compile time and to support generic programming. To implement generics, the
Javacompilerappliestypeerasureto:
• ReplacealltypeparametersingenerictypeswiththeirboundsorObject
ifthetypeparametersareunbounded.Theproducedbytecode,therefore,
containsonlyordinaryclasses,interfaces,andmethods.
• Inserttypecastsifnecessarytopreservetypesafety.
• Generatebridgemethodstopreservepolymorphisminextendedgeneric
types.
Typeerasureensuresthatnonewclassesarecreatedforparameterizedtypes;
consequently,genericsincurnoruntimeoverhead.
Wir wissen nun, dass zur Kompilezeit alle generischen Datentypen ersetzt
werden.GibtesweitereFallstricke?
A<Integer> a1 = new A<Integer>(); A<String> a2 = new
A<String>();
if (a1 instanceof A && a2 instanceof A)
System.out.println("instanceof: yes");
if (a1.getClass() == a2.getClass())
System.out.println("getClass(): yes");
InbeidenFällenevaluierendieAusdrückezutrue. Diesistinsofernunschön,
dasswirzurLaufzeitnichtmehrzwischenverschiedenengenerischenTypenvon
der selben Klasse unterscheiden können. Das fällt uns besonderns negativ auf,
wennwireine equals-Methodeimplementierenwollen.Hierkönnenwirzum
BeispielnichtmehrzwischeneinerListevonStringsundeinerListevonIntegern
unterscheiden. D.h. LinkedList<String> und LinkedList<Integer>
haben zur Laufzeit den gleichen Typ, nämlich LinkedList. Im Javasprech
werden solche Typen auch rawtypes(https://docs.oracle.com/javase/tutorial/
java/generics/rawTypes.html)genannt.
Quintessenz: All diese Probleme sind Folgen der Designentscheidung, dass
AbwärtskompatibilitätsowichtigfürdieSprachdesignerwar.
Aufgabe11.3.Exceptions
BetrachtenSiefolgendenAusschnittausderKlassenhierarchievonExceptionsin
JavaundfolgendeJava-ImplementierungderKlasseExceptionTest:
import java.io.*;
public class ExceptionTest {
public static void main (String[] args) {
try {
// ...
}
catch (EOFException e) {
System.out.println("EOFException");
}
catch (IOException e) {
System.out.println("IOException");
}
catch (Exception e) {
System.out.println("Exception");
}
System.out.println("ENDE");
}
}
}
1) An der durch „...“ gekennzeichneten Stelle im try-Block stehe ein
Programmstück, durch das Exceptions vom Typ EOFException,
IOException oder FileNotFoundException geworfen werden
können.
Was wird bei Ausführung der main-Methode ausgegeben, falls dabei im
try-Block
i.
alsersteseineAusnahmevomTypEOFExceptiongeworfen
wird,
ii.
alsersteseineAusnahmevomTypFileNotFoundException
geworfenwird,oder
iii.
garkeineAusnahmegeworfenwird?
2) WaswirdbeiAusführungdermain-Methodeausgegeben,fallsdabeiim
try-BlockalsersteAusnahmeeineDivisiondurch0auftritt?
Aufgabe11.4.ResistenteMengen
VerwendenSiefürdieseAufgabenurdieerlaubtenJava-Methoden.
ImplementierenSieeineunveränderlicheDatenstruktur,diedasVerhalteneiner
Mengeabbildet.Unveränderlichbedeutet,dassjedeMembervariablefinalsein
muss. Möchte man also ein Element e der Menge E hinzufügen, so darf/kann
nicht die Menge E selber verändert werden, sondern es muss ein neues Objekt
E’ erzeugt werden, welches das neue Element e beinhaltet sowie alle alten
Element der Menge E, i.e. E’ = E ∪ {e}. Um die Elemente einer Menge zu
repräsentieren, verwenden wir eine Liste. Da wir gefordert hatten, dass die
Menge unveränderlich sein muss, fordern wir auch, dass die Liste un-
veränderlichseinmuss.D.h.alleMembervariablenderListemüssenfinalsein.
Für die Listenimplementierung dürfen Sie sich an Ihren eigenen
Listenimplementierungen sowie an den Lösungsvorschlägen aus vorherigen
Aufgaben orientieren. Die Menge selber soll Elemente von einem generischen
TypTenthaltenundsomitnatürlichauchdieListe.
ImFolgendenseiseinSet-ObjektvoneinemgenerischenTypT:
•
DerparameterloseKonstruktorerstellteinObjektwelcheseineleere
Mengerepräsentiert
•
DieMethodes.add(T e)gibteinSet-Objektzurück,dassdasElemente
enthältsowiealleElemente,dieinsenthaltensind.IstdasElemente
schoninsenthalten,dannsollszurückgegebenwerden.Istegleich
null,dannsolleineNullPointerExceptiongeworfenwerden.
•
DieMethodes.remove(T e)gibteinSet-Objektzurück,dasalle
Elementvonsenthält,außerdemElemente.Istegleichnull,dannsoll
eineNullPointerExceptiongeworfenwerden.
•
DieMethodes.contains(T e)gibttruezurückwenndasElemente
inderMengeenthaltenistundandernfallsfalse.
•
DieMethodesizegibtdieKardinalitätderMengezurück.
•
DieMethodes.equals(Object o)erfülltdieüblichenEigenschaften,
diederJava-Standardfordert.DesWeiterenwirdtruezurückgegeben,
wenndieMengensundodiegleichenElementeenthält.Andernfallswird
falsezurückgegeben.BeachtenSiedieüblichenEigenschafteneiner
Mengewiez.B.e∈E⇒E=E∪{e}odere∉E⇒E=E\{e}.
•
DieMethodes.toString()gibteinenStringderForm{x1,...,xn}
zurück,wenndieMengesdieElementexi,1≤i≤nenthältundndie
KardinalitätderMengeist.DerzurückgegebenStringenthältalsoeine
String-RepräsentationallerenthaltenerElementederMenge.
Herunterladen