1 (9) TENTAMEN: Objektorienterad programmering Läs detta! Uppgifterna är inte ordnade efter svårighetsgrad. Börja varje hel uppgift på ett nytt blad. Skriv inte i tesen. Ordna bladen i uppgiftsordning. Skriv din tentamenskod på varje blad (så att vi inte slarvar bort dem). Skriv rent dina svar. Oläsliga svar r ä t t a s e j! Programkod som finns i tentamenstesen behöver ej upprepas. Programkod skall skrivas i Java 5, eller senare version, och vara indenterad och renskriven. Onödigt komplicerade lösningar ger poängavdrag. Givna deklarationer, parameterlistor etc. får ej ändras. Läs igenom tentamenstesen och förbered ev. frågor. I en uppgift som består av flera delar får du använda dig av metoder klasser etc. från tidigare deluppgifter, även om du inte löst dessa. Lycka till!
2 (9) Uppgift 1 Välj ett alternativ för varje fråga! Garderingar ger noll poäng. Inga motiveringar krävs. Varje korrekt svar ger två poäng. Besvara delfrågorna 1.1-1.5 på ett blad. 1. Para ihop begreppen med varandra! A. Dynamisk typ 1. Typkontroll B. Datainkapsling 2. Alias C. Statisk typ 3. Informationsgömning D. Referenstyp 4. Polymorfism a. A1, B2, C3, D4 b. A1, B3, C4, D2 c. A4, B2, C3, D1 d. A4, B3, C1, D2 e. A3, B1, C2, D4 2. Nedanstående kod har minst en allvarlig brist, vilken? Bortse från utelämnad kod ( ). public static int f(int[] keys,hashmap<integer,string> table) { int totallength = 0; for ( int k : keys ) totallength += table.get(k).length(); return totallength; public static void main(string[] arg) { HashMap<Integer,String> m = new HashMap<Integer,String>();... int[] arr = new int[100];... System.out.println(f(arr,m)); a. kompilatorn rapporterar ett syntaxfel b. kompilatorn rapporterar ett typfel c. ett exekveringsfel kan inträffa d. inget onormalt inträffar, koden är felfri 3. Vilken av klasserna C1 C4 har lägst koppling till andra klasser? public interface A { public class B implements A { public class C implements A { a. C1 b. C2 c. C3 d. C4 public class C1 { public A f(linkedlist<a> l) { public A g(arraylist<a> l) { public class C3 { public A f(list<b> l) { public A g(list<c> l) { public class C2 { public A f(list<a> l) { public A g(list<a> l) { public class C4 { public B f(arraylist<c> l) { public C g(linkedlist<b> l) {
3 (9) 4. I vilket av fallen a d sker ett otillåtet metodanrop? public class A { public void f1() { f3(); // a public void f2(a obj) { obj.f3(); // b public static void f3() { f1(); // c public static void f4(a obj) { obj.f1(); // d 5. Studera följande två lösningar till problemet att räkna antalet bokstäver i den längsta strängen i en lista av strängar. // Implementering 1 public static int countlettersinlongeststring1(list<string> l) { return countletters(findlongeststring(l)); public static String findlongeststring(list<string> l) { String longeststring = ""; for ( String s : l ) { if ( s.length() > longeststring.length() ) longeststring = s; return longeststring; public static int countletters(string s) { int n = 0; for ( int i = 0; i < s.length(); i++ ) { if ( Character.isLetter(s.charAt(i)) ) n++; return n; // Implementering 2 public static int countlettersinlongeststring2(list<string> l) { String longeststring = ""; for ( String s : l ) { if ( s.length() > longeststring.length() ) longeststring = s; int n = 0; for ( int i = 0; i < longeststring.length(); i++ ) { if ( Character.isLetter(longestString.charAt(i)) ) n++; return n; Vilken av implementationerna har högst metodkohesion? a. den första b. den andra c. ingen av dem, kohesionsbegreppet är enbart tillämpbart på klasser (10 p)
4 (9) Uppgift 2 Antag att vi vill konstruera klasser för att representera uppgifter om studenter och anställda på ett företag. Som grund för det hela finns denna klass för personuppgifter: public class PersonalData { private String name; private String pnr; private String address; public PersonalData(String name,string pnr,string address) { this.name = name; this.pnr = pnr; this.address = address; public String getname() { return name; public String getpnr() { return pnr; public String getaddress() { return address; public void setaddress(string address) { this.address = address; Vi vill nu ha ytterligare två klasser för att lagra information som är specifik för studenter och anställda. En student är inskriven på ett program ett visst år och har poäng, medan en anställd tillhör en avdelning och har en viss lön. En lösning skulle kunna vara att definiera de två klasserna StudentData och EmployeeData som subklasser till PersonalData. Denna lösning är inte optimal, t.ex. kan en student bli anställd under studietiden och skulle då representeras av ett objekt av varje subklass. Då kommer personuppgifterna att lagras på två ställen vilket leder till uppenbara problem, t.ex. måste en adressändring utföras i två objekt. En bättre lösning är att låta StudentData och EmployeeData använda ett gemensamt objekt av typen PersonalData: a) Implementera StudentData i Java. Klassens konstruktor skall ta ett personuppgiftsobjekt, samt utbildningsprogrammets namn (t.ex. TIDAL ) som parametrar. Inför lämpliga instansvariabler med ledning av klassdiagrammet ovan. Inskrivningsåret sätts till aktuellt år och kan beräknas med uttrycket Calendar.getInstance().get(Calendar.YEAR). Klassen skall ha två klasskonstanter: NORMAL_STUDY_YEARS med värdet 3 samt PROGRAM_CREDITS med värdet 180. (EmployeeData är ganska likartad och den behöver du ej skriva. Klassdiagrammet ger tillräcklig information för att kunna använda den i kommande deluppgifter.)
5 (9) b) Konstruera klassen Company för att lagra information om anställda vid ett företag. Varje anställd representeras förstås av ett objekt av klassen EmployeeData. Lagra objekten i en lista. Klassen skall ha metoden public void employ(collection<studentdata> students) Eftersom vi är speciellt intresserade av IT-företag kan vi anta att alla de studenter i students som går på programmet TIDAL skall anställas, men inga andra. Grundlönen skall sättas till 40000 (per månad) men de som har minst 180 poäng får en extra bonus om 5000 kr per månad. De nyanställda skall placeras på Software department. (6 p) c) Skriv ett kodavsnitt som skapar ett företagsobjekt, samt nödvändiga objekt för några studenter samt anropar metoden ovan för att anställa studenterna på företaget. (3 p) d) klassen Company saknar ett sätt för användaren att ta del av information om de anställda. Man skulle kunna införa en metod som returnerar listan av anställda, men det är olämpligt av säkerhetsskäl. Bättre är att låta användaren titta i listan via en iterator. Gör klassen itererbar, så att man t.ex. kan skriva Company itgurus;... for ( EmployeeData d : itgurus ) { // Use d for whatever... Tips: Gränssnitten Iterable och Iterator finns i bilagan.
6 (9) Uppgift 3 En multimängd är en osorterad datasamling. Till skillnad från t.ex. HashSet behöver inte elementen i en multimängd vara unika. I denna uppgift skall du komplettera en klass för multimängder av strängar. Klassen lagrar elementen i en lista. public class Multiset { private ArrayList<String> elements; public Multiset() { creates an empty multiset public void add(string s) { adds s to this multiset public int size() { returns the number of elements in this multiset public boolean isempty() { determines if this multiset is empty public boolean contains(string s) { returns true if this multiset contains s and false otherwise public int count(string s) { returns the number of occurrences of s in this multiset clone equals hashcode Ex. Multiset a = new Multiset(); a.add("x"); a.add("y"); a.add("z"); a.add("x"); a.size(); 4 a.isempty(); false a.count( Q ); 0 a.count( x ); 2 a.count( z ); 1 Uppgifterna nedan skall förstås lösas enligt de principer som lärts ut i kursen. Ett tips: För uppgifterna b och c kan det löna sig att studera klassen Collections i API. a) Implementera metoden clone i Multiset. b) Implementera metoden equals i MultiSet. Två multimängder är lika om de innehåller lika många element och lika många av varje element. Ex. Multiset b = new Multiset(); b.add("z"); b.add("x"); b.add("x"); b.add("y"); a.equals(b); true c) Implementera metoden hashcode i MultiSet. (2 p)
7 (9) Uppgift 4 a) Under vilka omständigheter kan ett anrop av foo orsaka att texten foo catched E2 skrivs ut? Konstruera ett exempel som demonstrerar ett sådant fall! Den givna koden nedan får ej ändras i ditt exempel. public class E1 extends Exception { public class E2 extends E1 { public class A { public void f() throws E1 { throw new E1(); public void foo(a obj) { try { obj.f(); catch (E2 e) { System.out.println("foo catched E2"); catch (E1 e) { System.out.println("foo catched E1"); (3 p) b) Antag att Int definieras: public interface Int { int f(); double g(float x); String h(); En eller flera av C1 C4 ger kompileringsfel. Vilka klasser? Vilka är felen? Motivera ditt svar. public abstract class C1 implements Int { public String h() { return "Wohoo!"; public class C3 extends C1 { @Override public int f() { return 2016; @Override public double g(float y) { return 1.0/y; @Override public String h(string s) { return s+"!"; public class C2 extends C1 implements Int { public int f() { return 42; public double g(float y) { return 2*y; public class C4 implements Int { public int f() { return 128; public double g(double y) { return y*y; public String h() { return "foo"; (6 p)
8 (9) Uppgift 5 En ackumulator är ett objekt som tar emot heltalsvärden, ett i taget, och gör en beräkning med värdena. Under processens gång kan man fråga objektet efter ett delresultat. T.ex. kan vi tänka oss en Adder som räknar ut och håller reda på summan av talen den tar emot. Andra exempel är Multiplier och MaxFinder, se nedan. Gränsnittet Accumulator definieras: public interface Accumulator { void accumulate(int x); boolean hasvalue(); int getvalue() throws IllegalStateException; void forget(); Ex. Antag att Adder, Multiplier samt MaxFinder implementerar Accumulator och betrakta följande sekvens: Adder adder = new Adder(); adder.hasvalue(); false adder.accumulate(2); adder.hasvalue(); true adder.getvalue(); 2 adder.accumulate(7); adder.getvalue(); 9 adder.accumulate(4); adder.getvalue(); 13 (*) adder.forget(); adder.hasvalue(); false adder.getvalue(); IllegalStateException Motsvarande steg med en Multiplier och en MaxFinder ger slutvärdena (*) 56 respektive 7. Metoden forget återställer objektet till sitt ursprungstillstånd, i vilket det inte lagrar något värde. Om getvalue anropas före första anropet av accumulate eller efter forget kastas undantaget IllegalStateException. a) Addera till din nya klass MyUtilities en klassmetod som låter en ackumulator få sina indata från en lista: public static void accumulate(list<integer> l,accumulator a) Ex. Antag att listan someintegers innehåller talen 1,2,3,4,5,6,7,8,9,10. Accumulator m = new Multiplier(); MyUtilities.accumulate(someIntegers,m); m.getvalue(); 3628800 (10!) (2 p) forts.
9 (9) Om klasserna Adder, Multiplier eller MaxFinder skulle implementeras var för sig som subklasser till Accumulator så kommer de att innehålla överlappande kod, och kodduplicering vill vi undvika. En lösning är att, som i en av kursens laborationer, samla gemensam funktionalitet i en abstrakt basklass. Denna basklass får sedan implementera Accumulator. b) Konstruera klassen AbstractAccumulator. En av metoderna i Accumulator skall vara abstrakt i denna klass. Lägg till metoden setvalue(int x). Den får vara synlig i subklasser, men inte utåt för användare av subklasserna. Inför lämpliga instansvariabler (med privat synlighet). (8 p) c) Implementera en av klasserna Adder, Multiplier eller MaxFinder, valfritt vilken.