Lösningsförslag till tentamen i OOP, HI1027 Fredag 21 oktober 2011 Text inom [] avser kommentarer till rättningen, ofta sådant som många missuppfattat eller gjort fel på. Del A. Teoriuppgifter 1. Återanvändning: Välskrivna klasser kan återanvändas i andra applikationer som samma roll förekommer (detta förutsätter att klassen har en väl avgränsad roll, ett väl genomtänkt publikt gränssnitt och få beroenden till andra klasser). Inkapsling: Hide the implementation ; för användaren av en klass är endast klassens publika gränssnitt av intresse. Implementationen är dold, speciellt datamedlemmarna genom att synligheten är satt till private eller protected. Arv: I objektorienterade språk kan man skapa nya klasser, som specialiseringar utifrån redan existerande klasser. Arv används då en klass Sub kan beskrivas vara en specialisering av klassen Super. Subklassen ärver alla datamedlemmar och (icke privata) metoder. Nya datamedlemmar och metoder kan läggas till i subklassen och ärvda metoder kan omdefinieras. 2. En abstrakt klass kan inte instansieras, d.v.s. man kan inte skapa objekt av abstrakt typ. En abstrakt klass kan innehålla deklarationer av metoder (utan implementation), s.k. abstrakta metoder. Ett interface får innehålla endast publika, abstrakta metoder och klasskonstanter. Skillnaden mellan en abstrakt klass och ett interface är att den abstrakta klassen får innehålla datamedlemmar, konstruktorer och (implementerade) metoder, vilket inte är tillåtet i ett interface. Vidare får en klass bara ärva från en superklass (abstrakt eller icke abstrakt), medan samma klass får implementera ett godtyckligt antal interface. 3. a) i try-blocket exekveras i sin helhet, alla catch-block hoppas över och slutligen exekveras finally-blocket. ii - try-blocket exekveras fram till den punkt där FileNotFoundException kastas, catch-blocket märkt FileNotFoundException exekveras och slutligen exekveras finally-blocket. iii - try-blocket exekveras fram till den punkt där IOException kastas, catch-blocket märkt Exception (som är supertyp till IOException) exekveras och slutligen exekveras finally-blocket. b) Notera att vi inte skriver catch-block i denna metod eftersom exception inte ska fångas i denna utan kastas vidare till anropande metod. Metoden märks med throws IOException. public void readfile(string filename) throws IOException { BufferedReader fin = null; try { fin = new BufferedReader(new FileReader(filename)); String line; line = fin.readline(); 1
finally { if(fin!= null) filescan.close(); 4. a) Metoden returnerar en referens, d.v.s. adress, till privat data. Anropande kod får direkt tillgång till den (nu inte längre så) privata listan och kan modifiera denna. b) Metoden bör returnera en kopia av listan, genom att skapa ett nytt objekt med lika innehåll som det privata objektet, t.ex. genom att anropa metoden clone för listan. 5. a) Omdefiniering innebär att en ärv metod i en subklass kan ges en ny implementation. Funktionaliteten finns fortfarande i subklassen (samma metodnamn, argumentlista och returtyp), men operationen utförs på ett nytt sätt, specifikt för subklassen. b) Polymorfism = många former. I OOP syftar detta oftast på när en omdefinierad metod anropas från en superreferens. Det framgår då inte av källkoden vilken version av den omdefinierade metoden som kommer att exekveras (det beror ju på vilken typ av objekt som refereras vid exekveringen). Exempel: Bastypen Shape deklarerar metoden paint som har olika implementationer i sub klasser som Line och Circle. Shape[] shapes = new Shapes[sz]; // Skapa objekt av olika subtyper for(shape s: shapes { s.paint(g); // Polymorf kod c) De ärvda datamedlemmarna kanske ska uppfylla vissa villkor (kontrakt) och det sköts via metoder i superklassen. Om data är protected kan subklasser manipulera data så att villkoren inte uppfylls. 6. a) Kod som manipulerar och/eller avläser ändringsbart data bör synkroniseras för att undvika s.k. race conditions. public class Account { private double balance; synchronized public double getbalance() { return balance; synchronized public void deposit(double amount) { if(amount > 0.0) balance = balance + amount; synchronized public void withdraw(double amount) { I detta exempel är monitorn this, d.v.s. objektet självt. b) Då en tråd itererar genom listan får inte andra trådar manipulera listan. Lägg koden för iterationen i ett synkroniserat kodblock (en förutsättning här är att list refererar till en synkroniserad lista): synchronized(list) { for(object o: list) { // Do something with o 2
7. 8. I Model-View-Controller separeras klasserna i nedanstående grupper. Model klasser som representerar datat i applikationen (och som ska presenteras), samt funktionalitet för att manipulera dessa data. Modellen ska inte ha något beroende till vyn. View klasser för att presentera datat. View hämtar information om det ska presenteras från modellen. Controller hanterar händelser, t.ex. input från användaren, som sedan resulterar i uppdatering av datat. Poänger med MVC: - Olika roller i ett problemområde bör alltid modelleras i separata klasser/grupper av klasser, med så få beroenden som möjligt. Detta gör det lättare att skriva koden och testa denna. I detta fall kan klasserna i model testas innan view och controller existerar. - Modellen blir helt oberoende av vyn. Det går alltså att byta ut vyn utan att detta påverkar modellen och att det går att presentera flera vyer av samma modell. 3
Del B. Programmeringsuppgifter Uppgift 1, Vårdcentralen 0.1 public class Person { public Person(String name, String ssn) { this.name = name; this.ssn = ssn; public String getname() { return name; public String getssn() { return ssn; public String tostring() { String info = name + ", SSN " + ssn; return info; private String name; private String ssn; // Social Security Number public class Physician extends Person { public Physician(String name, String ssn, String speciality) { super(name, ssn); this.speciality = speciality; public String getspeciality() { return speciality; public String tostring() { String info = super.tostring(); info += ", " + speciality; return info; private String speciality; 4
import java.util.date; public class JournalNote { public JournalNote(String text, Physician physician) { this.text = text; this.date = new Date(); this.physician = physician; public String gettext() { return text; public Date getdate() { return (Date) date.clone(); public Physician getphysician() { return physician; public String tostring() { String info = date + ", " + physician.tostring(); info += "\n" + text; return info; private String text; private Date date; private Physician physician; import java.util.arraylist; public class Uppgift1 { public static void main(string[] args) { Physician ph1 = new Physician("Sweeny Todd","111-111","kirurgi"); Physician ph2 = new Physician("Lisa Larsson","222-222","medicin"); ArrayList<JournalNote> journal = new ArrayList<JournalNote>(); journal.add(new JournalNote("Höger ben måste amputeras.", ph1)); journal.add(new JournalNote("Vaccinerad mot influensa.", ph2)); journal.add(new JournalNote("Hoppsan, fel ben.", ph1)); for(journalnote note: journal) { System.out.println(note.toString()); 5
Uppgift 2, Vårdcentralen 0.2 import java.util.arraylist; public class Patient extends Person { public Patient(String name, String ssn) { super(name, ssn); journal = new ArrayList<JournalNote>(); /** * Returns a copy of the journal. This is to make sure the * caller can not change the private journal via the copy * returned. */ @SuppressWarnings("unchecked") public ArrayList<JournalNote> getjournal() { return (ArrayList<JournalNote>) journal.clone(); public void addnote(string text, Physician physician) { JournalNote note = new JournalNote(text, physician); journal.add(note); public String tostring() { StringBuffer buffer = new StringBuffer(); buffer.append("patient " + super.tostring()); for(journalnote note: journal) { buffer.append("\n" + note); return buffer.tostring(); private ArrayList<JournalNote> journal; public class Uppgift2 { public static void main(string[] args) { Physician ph1 = new Physician("Sweeny Todd","111-111","kirurgi"); Physician ph2 = new Physician("Lisa Larsson","222-222","medicin"); Patient patient = new Patient("Anders Lindström", "333-333"); patient.addnote("höger ben måste amputeras.", ph1); patient.addnote("vaccinerad mot influensa.", ph2); patient.addnote("hoppsan, fel ben.", ph1); System.out.println(patient.toString()); 6
Uppgift 3, Min egen lista Metoden clone är här skriven enligt anvisningarna i Javas API. Detta är dock inte nödvändigt, lösningar som inte använder sig av Object s clone-metod är ok (om de utför uppdraget korrekt). Denna klass innehåller även delar av lösningen till uppgift 4 (metoden iterator). import java.util.iterator; import java.util.nosuchelementexception; public class SList implements Cloneable, Iterable<String> { // To allow cloning public SList(int capacity) { thelist = new String[capacity]; noofelements = 0; public SList() { this(10); // Call to previous constructor public int size() { return noofelements; public String get(int index) { checkindex(index); return thelist[index]; public void add(string s) { if(noofelements >= thelist.length) { resize(); thelist[noofelements] = s; noofelements++; public void clear() { noofelements = 0; public boolean equals(slist other) { if(this == other) return true; if(this.noofelements!= other.noofelements) return false; for(int i = 0; i < noofelements; i++) { if(!this.thelist[i].equals(other.thelist[i])) { return false; return true; public SList clone() { try { SList newlist = (SList) super.clone(); // The clone has a reference to this.thelist. // Create a copy of the array! newlist.thelist = this.thelist.clone(); return newlist; 7
catch(clonenotsupportedexception cnse) { // This should never happen (if Cloneable is implemented) return null; public String remove(int index) { checkindex(index); String removed = thelist[index]; pack(index); return removed; public Iterator<String> iterator() { return new SListIterator(this); public String tostring() { StringBuffer buffer = new StringBuffer(); buffer.append("["); for(int i = 0; i < noofelements; i++) { buffer.append(thelist[i] + ", "); buffer.append("]"); return buffer.tostring(); private void checkindex(int index) { if(index < 0 index >= noofelements) { throw new IndexOutOfBoundsException("index = " + index); private void resize() { // Double the capacity String[] templist = new String[theList.length*2]; for(int i = 0; i < noofelements; i++) { templist[i] = thelist[i]; thelist = templist; private void pack(int index) { for(int i = index+1; i < noofelements; i++) { thelist[i-1] = thelist[i]; noofelements--; private String[] thelist; private int noofelements; 8
public class Uppgift3 { public static void main(string[] args) { SList list = new SList(); list.add("java"); list.add("c#"); list.add("c++"); list.add("objective-c"); System.out.println(list.toString()); String s = list.remove(1); System.out.println("Removed: " + s); System.out.println(list.toString()); // Check whether we get a copy/clone or not SList copy = list.clone(); copy.remove(0); System.out.println("Original list: " + list.tostring()); System.out.println("The copy: " + copy.tostring()); 9
Uppgift 4, Iterator Denna klass definieras lämpligen i samma fil som SList, med synligheten package. class SListIterator implements Iterator<String> { SListIterator(SList list) { this.list = list; currentposition = -1; public boolean hasnext() { // NB: if current position is last element, there's no next element return currentposition < list.size()-1; public String next() { if(!this.hasnext()) throw new NoSuchElementException(); currentposition++; return list.get(currentposition); public void remove() { throw new UnsupportedOperationException("SListIterator.remove()"); private SList list; private int currentposition; import java.util.iterator; public class Uppgift4 { public static void main(string[] args) { SList list = new SList(); list.add("java"); list.add("c#"); list.add("c++"); list.add("objective-c"); // Test the iterator (should also work with the "for each" loop Iterator<String> it = list.iterator(); String s; while(it.hasnext()) { s = it.next(); System.out.println(s); // At this point, this should cause an exception s = it.next(); 10