1 (6) Objektsamlingar i Java Objektorienterad programmering 3 Syfte Att ge träning i att använda objektsamlingar i Java. Mål Efter övningen skall du kunna använda objektsamlingsklasserna ArrayList och LinkedList. hantera objektsamlingar med iteratorobjekt av typen Iterator. Hitta information om standardklasser i Java API Specification. Utvecklingsmiljö BlueJ på valfri plattform. Java version 7 eller 8. Litteratur Kursboken kap 1-4. Färdig programkod Given programkod finns på kursens hemsida i er->programkod för labbarna->club.zip. Labbgrupper Arbetet genomförs och redovisas i grupper om två personer. Redovisning Senaste redovisningsdag, se kurs-pm samt Fire. Ladda upp filerna Membership.java och Club.java med dina lösningar i, samt README.txt med svar på frågor (markerade med ), i Fire. Glöm inte att trycka på SUBMIT i Fire!
2 (6) Inledning Medlemskap i en klubb representeras med en instans (ett objekt) av klassen Membership. Varje objekt av klassen innehåller detaljer om en medlems namn och e-postadress, samt vilken månad och år medlemskapet startade. E-postadressen identifierar varje klubbmedlem unikt. Många sajter på Internet använder just e-postadressen som användar-id. I klubben får alltså inte två olika medlemsobjekt ha samma e-postadress. Uppgift 1 I den givna koden saknas hantering av epostadress i klassen Membership. Lägg till detta! Inför lämplig instansvariabel, accessmetod, samt modifiera konstruktorn och metoden tostring på lämpligt sätt. Uppgift 2 Börja med att göra en första enkel version av klassen Club. Ett skelett till klassen finns i projektet club. För att klara detta bör du ha läst fram t.o.m. avsnitt 4.7. Lämplig arbetsgång Utvecklingen av koden bör ske i små steg. Kompilera och TESTA efter varje steg för att verifiera att dina ändringar och tillägg är korrekta! Stegen behöver ej redovisas, bara slutresultatet. Det är förstås tillåtet och lämpligt att använda en eller flera av klassens metoder i en annan metod om det förenklar koden. Leta upp klassen LinkedList i API Specification. 1 Den finns i paketet java.util. Enklaste sättet att nå API Specification är via Help->Java Class Libraries i BlueJ, eller googla! Om en äldre version än 7 kommer upp så byt X till 7 eller 8 i webläsarens adressfält: http://docs.oracle.com/javase/x/docs/api/ 2 Klassen skall lagra medlemsobjekt i en länkad lista. Använd en lämplig import deklaration för listklassen i början av filen. Deklarera en privat instansvariabel av typen LinkedList<Membership>. Deklarera en parameterlös konstruktor som skapar listobjektet. Ett nytt medlemsobjekt adderas till ett klubbobjekt med metoden join, som skall ha följande beskrivning och signatur: * Add a new member to this club's collection of members. * @param member The member object to be added. * @return true if member was added, false ow. public boolean join(membership member) Du får anta att medlemsobjektet som skickas som parameter redan har skapats och är korrekt initierat. Låt tills vidare metoden alltid returnera true (vi skall ändra detta senare). 1 API = Aplication Programming Interface. 2 I princip spelar det ingen roll om du använder Java version 7 eller 8. Vi kommer dock troligen inte att använda nyheterna i version 8 i årets upplaga av kursen. Version 8 finns installerad i datorerna i datasalarna.
3 (6) Klassen Club skall även ha en metod som returnerar antalet medlemmar. Den har följande beskrivning och signatur: * Calculate the number of members in this club. * @return The number of stored Membership objects. public int numberofmembers() Tips: Utnyttja lämplig metod i listklassen. Klassen skall ha en metod för att skriva ut information om medlemmarna: * Print membership info about all members in this club. public void printallmembers() Utskriften skall ske med en textrad per medlem. Använd javas for-each-loop i denna metod (se förel. 4). Tips: Utnyttja att Membership har en tostring-metod. Testning Att lägga till medlemsobjekt till ett klubbobjekt från objektbänken i BlueJ kan göras på två sätt: i. Skapa ett klubbobjekt och ett medlemsobjekt på objektbänken, anropa metoden join för klubbobjektet, och ange den aktuella parametern till join genom att klicka på medlemsobjektet. Eller: ii. Anropa join för klubbobjektet och skriv in: new Membership("medlemens namn","e-postadress",månad,år) i dialogrutan för join-metodens parameter. När du har lagt in en ny medlem skall du anropa numberofmembers och printallmembers för att kontrollera att join verkligen lagt in ett nytt objekt i listan. Testa med noll, en, samt flera medlemmar.
4 (6) Uppgift 3 För att klara detta bör du ha läst fram t.o.m. avsnitt 4.12. Leta upp Iterator i API Specification. Den finns i paketet java.util under rubriken Interfaces. Förbättra metoden join så att den returnerar false om inparametern member är null. Dessutom skall den kontrollera så att den nya medlemmen inte redan är medlem i klubben. I så fall skall det nya medlemsobjektet inte läggas in i listan och false returneras. För att kunna avgöra om medlemmen finns i listan eller ej måste du undersöka samtliga element i den. Använd i denna metod ett iteratorobjekt av typen Iterator<Membership> och lämplig loop-konstruktion. Leta upp Iterator i API Specification. Den finns i paketet java.util under rubriken Interfaces. Det kommer att behövas iteratorobjekt i flera av klassens metoder. Bör dessa skapas lokalt i resp. metod, eller räcker det med ett gemensamt iteratorobjekt i klassen som kan användas i de olika metoderna? Skulle det fungera? Bör variabler av typen Iterator deklareras som instansvariabler eller som lokala variabler? Besvara frågorna i README! Definiera en metod i klassen Club med följande beskrivning och signatur: * Return how many members joined in the given month. * @param month The month we are interested in. * @param year The year of the Membership. * @return How many members joined in the given month. public int joinedinmonth(int month,int year) Om month har ett värde utanför det giltiga intervallet 1..12 skall metoden skriva ut ett felmeddelande samt returnera 0. Använd javas for-each-loop i denna metod. Definiera metoden findmember: * Search for a member with a given email address. * @param email the email address of the searched member. * @return A matching membership object if found, * null otherwise. public Membership findmember(string email) Använd javas for-each-loop i denna metod. Har du redan löst det här problemet i en tidigare metod? Kan den ena utnyttjas i den andra? Gör det i så fall, eller förklara varför det inte går! Definiera metoden getemailaddresses: * Return the email addresses of all the club members. * @return A comma separated string of email addresses. public String getemailadresses() (se nästa sida)
5 (6) För att skapa texten som skall returneras kan vi deklarera en lokal variabel i metoden av typen String String s = ; // Börja med en tom sträng Eftersom String ej är muterbar kan vi inte ändra strängen som s refererar till, utan måste för varje ny e-postadress som skall läggas till, skapa ett helt nytt strängobjekt (+) som sedan tilldelas till s: s = s + e-postadress Detta blir ganska ineffektivt. Istället kan vi använda en strängbuffert av klassen StringBuilder. Studera den i API spec. Objekt av StringBuilder är muterbara, till skillnad från String. Om en strängbuffert blir full allokeras automatiskt mer plats. Om vi deklarerar StringBuilder sb = new StringBuilder(256); // startkapacitet 256 så kan vi addera text utan att skapa nya objekt vid varje addition: sb.append( TEXT ); sb.append( mertext ); String s = sb.tostring(); // s innehåller nu TEXTmertext I denna metod bör du använda en iteratorloop så att du kan identifiera när sista varvet nåtts, då skall nämligen inget kommatecken adderas till strängen. Klassen Club skall också ha en metod för att ta bort en medlem ur klubben: * Delete a member from the club. * @param email The email address of the member to be deleted. * @return true if the specified membership was deleted, false ow. public boolean delete(string email) Om email är null eller en tom sträng skall metoden returnera false. I denna metod måste du använda en iteratorloop. I både listklassen och iteratorklassen finns metoden remove. Läs om dem i API specification. Vilken bör du använda? Vad skulle kunna hända om du använder den andra? Besvara frågorna i README! Definiera nu en metod i klassen Club med följande beskrivning och signatur: * Remove from the club's collection all members who joined * in the given month, and return them stored in a separate * collection object. * @param month The month of the Membership. * @param year The year of the Membership. public ArrayList<Membership> purge(int month,int year) Om parametern month har ett värde utanför det giltiga intervallet 1..12, eller om year är negativ skall metoden skriva ut ett felmeddelande samt returnera null. Leta upp klassen ArrayList i API Specification. Även i denna metod måste du använda en iteratorloop.
6 (6) I de återstående metoderna kan du använda en for-each-loop eller en iteratorloop. Prova gärna båda varianterna för att se skillnaden. En metod kan mycket väl ha ett annat objekt av den aktuella klassen som parameter, t.ex. följande som listar de som är medlemmar i två klubbar: * Print membership info about all members in this club * who also joined the other club. * @param other The other club. public void intersect(club other) Om other är null skall ingenting skrivas ut. Tips: Här kan du utnyttja en annan metod i klassen för att få en mycket enkel lösning. (Operationen påminner om snittet mellan två mängder, därav namnet.) För att kunna slå ihop två klubbar till en skall klassen Club ha metoden: * Move members of the other club to this club. * Only members who are not already in this club will be moved. * On return, the other club will be empty. * @param other The club whose members will be added. * @return the number of members added. public int transferall(club other) Vad skulle hända om c är ett objekt av typen Club och du gör anropet c.transferall(c)? Det är knappast en meningsfull operation! Därför skall metoden börja med att göra ett s.k. aliastest vilket innebär att man undersöker om inparametern (other) refererar till samma objekt som det anropande objektet (this). Om det är så skall en felutskrift göras och noll returneras. Testet skrivs: if ( this == other) o.s.v. Två tips: Eftersom parametern other hör till klassen får metoden komma åt privata instansvariabler även i det objektet. Har listklassen någon lämplig metod för att tömma en lista på sitt innehåll? Lycka Till! och glöm inte S-U-B-M-I-T