Göm menyn

Labb 2: Intro till objektorientering i Java

Syfte

I denna labb ser vi hur man skapar och använder objekt och klasser. Vi återkopplar också till labbar från Python-kursen för att kontrastera mot andra sätt att programmera. Laborationen utförs enskilt.

Vi kommer att hjälpa till med flera handgrepp i programmeringen. Det är dock viktigt att ni reflekterar över varför ni gör som ni gör.

Deadlines och krav

  1. Labb 2 examineras via redovisning utan kodinlämning.

  2. Labb 2 ska redovisas senast 140214. Därefter ges en ny chans vid projektdemo i maj/augusti.

Om IDEA

Innan vi påbörjar övningarna är det några punkter som kan vara intressanta att känna till.

Info: Kompilering av projekt i IDEA

Till skillnad från språk som Python har Java ett separat kompileringssteg. IDEA utför detta automatiskt innan ett program startas, men ibland vill man kompilera utan att köra, t.ex. för att dubbelkolla att inga fel finns kvar. Detta görs genom Build | Make Project (Ctrl-F9), eller Build | Rebuild project för att kompilera om allt, även det IDEA tror inte behöver kompileras.

Info: Konfigurera program i IDEA

Vi har redan kört program den snabba vägen (högerklicka, "run"). Ibland vill man konfigurera körningen noggrannare och då krävs att man sätter upp en körkonfiguration. En ny sådan skapas genom Run | Edit Configurations. Det ger följande dialog:

I dialogfönstret trycker man sedan "+" och väljer "application". Därefter väljer man ett namn på konfigurationen och anger vilken klass den skall starta. Trycker du "..." får du välja bland alla klasser som har en main()-metod.

  • "VM options" behöver oftast inte ändras. Dessa är parametrar till Javas virtuella maskin. Här kan man specificera sådana saker som t.ex. den minnesmängd som ett Java program får använda.

  • "Program arguments" anger kommandoradsparametrar. Dessa skickas in i main() så att ditt program kan använda dem.

  • "Working directory" är katalogen där programmet startar. Detta är bara viktigt om programmet öppnar filer relativt nuvarande sökväg, vilket oftast inte ska göras.

  • Övriga inställningar behöver inte ändras.

Avsluta med att trycka  OK .

Info: Hitta en definition i IDEA

En mycket användbar funktion i IDEA är Hoppa till definition: Om man står med markören på en klass, metod eller ett fält och trycker Ctrl+B kommer IDEA att hoppa till definitionen för det element man står på. Testa gärna i ditt projekt från labb 1, t.ex. med System, out, och println.

Övning 2.1: Ett första objekt + operatorn new

Syfte: Komma igång med objekt!

Nu ska ni snabbast möjligt komma igång och skapa egna objekt med "new". Vi skapar därför objekt av en redan existerande klass från Javas klassbibliotek.

Bakgrund 2.1.1: Skapa paket och klass

Vi fortsätter i samma projekt, men skapar ett nytt paket för labb 2 för att hålla isär de olika övningarna bättre. Vi skapar oftast en ny klass för varje övning.

Uppgift 2.1.1: Skapa paket och klass

  1. Tidigare klasser låg i paketet se.liu.ida.dinadress.tddd78.lab1. Högerklicka paketet tddd78, välj New | Package och skapa lab2. Detta ska hamna på samma nivå som lab1 i klassträdet.

  2. Skapa klassen Slump i paketet lab2.

Bakgrund 2.1.2: Slumptal

Vi ska nu skapa slumptal med en slumptalsgenerator.

En slumptalsgenerator initialiseras normalt med ett "frö" och ger sedan en sekvens av slumptal. Samma frö ger alltid samma sekvens av slumptal, medan olika frön förhoppningsvis ger olika sekvenser.

Slumptalsgeneratorn måste alltså hålla reda på (bland annat) sitt frö – den har ett eget tillstånd (state). Den har också ett beteende, en funktionalitet: Den kan lämna ut nästa slumptal. Med både tillstånd och beteende passar det att modellera den som ett objekt.

Så är det också i Java: Slumptalsgeneratorer är objekt av klassen Random. Vi ska nu testa denna klass.

Uppgift 2.1.2: Slumptal

  1. Skapa en main()-metod i Slump.

  2. Vi skall nu skapa ett första objekt. Objekt skapas med hjälp av operatorn new. Vi skriver därför

       Random rnd = new Random();

    Som alla klasser i Java ligger Random i ett paket. Flera paket kan ha klasser med samma namn. När du skriver in Random vill IDEA därför veta vilken Random du menar. Den ger då en popup som föreslår import av java.util.Random, den enda Random som hittas just nu. Tryck Alt+Enter för att acceptera detta.

    Koden deklarerar att vi vill ha ett objekt av typen Random som vi kommer att referera till med namnet rnd. Vi skickar inte med några initialiseringsparametrar till konstruktorn utan är nöjda med defaultbeteendet hos Random.

Bakgrund 2.1.3: Javadoc

Javadoc är Javas standardiserade dokumentationsformat. Det byggs av speciella kommentarer som skrivs omedelbart före en klass, metod eller fält. Javadoc-verktyget gör om detta till indexerade HTML-filer.

Uppgift 2.1.3: Visa Javadoc

Prova att placera markören i t.ex. Random() och trycka Ctrl+Q. Detta ger snabbtillgång till javadoc dokumentation, så man slipper öppna HTML-filerna och själv navigera rätt.

Bakgrund 2.1.4: Auto-komplettering

IDEAs autokomplettering som visar vilka valmöjligheter som finns för fortsatt kodskrivning och kan vara mycket användbar. Rutan med valmöjligheter kan triggas med Ctrl+Space, och triggas också automatiskt i vissa lägen.

Uppgift 2.1.4: Använda autokomplettering

Testa att skriva "rnd." på raden under new Random();. Detta triggar autokomplettering. Du kan välja ett alternativ i listan eller fortsätta skriva. När du fortsätter skriva kommer IDEA att filtrera listan och försöka hitta rätt metod utifrån det som skrivs. Skriver du t.ex. "on" kommer IDEA att föreslå "nextLong()".

Man kan navigera i alternativlistan med pil upp/ner. Ctrl+Q tar fram javadoc-information för den entitet man just har markerat.

Bakgrund 2.1.5: Generera slumptal

Vi ska nu skapa och skriva ut slumptal med en hjälp av Random.

Uppgift 2.1.5: Generera slumptal

  1. Låt main()-metoden skriva ut 25 slumptal på varsin rad. Använd valfri typ av loop för att iterera 25 gånger. Använd t.ex. nextInt(100) för att generera ett slumptal mellan 0 och 99.

  2. Testa programmet.

Sammanfattning

Vi kan nu skapa objekt och anropa deras metoder. I övningen har vi använt en klass som är implementerad i Javas util-paket. I nästa övning skall vi skriva vår egen första "fullständiga" klass.

Övning 2.2: En egen "fullständig" klass

Syfte: Skapa egna objekt!

Vi ska nu gå vidare med skillnaderna mellan objektorienterad och icke objektorienterad programmering. Detta görs genom att vi skapar vår första mycket enkla "fullständiga" klass: Vår egen klass som har både internt tillstånd (som lagras i fält), beteende (som anges av metoder), och en egen konstruktor.

Vi går även vidare med utskrifter och ser hur vi ger en klass en egen anpassad utskriftsmetod.

Bakgrund 2.2.1: Heltalsklassen

Vi tänker oss att vi skall arbeta med olika typer av tal. Då är det naturligt att samla funktionalitet för en viss typ av tal i en klass. Här fokuserar vi på heltal.

För att kunna konstruera olika objekt av typen heltal behöver vi en konstruktor, en metod som initialiserar varje nytt objekt. Den heter alltid samma som klassen, har ingen returtyp, och tar noll eller flera parametrar. Den kan bland annat sätta värden på alla fält i det objekt som den skapar, t.ex. genom att "spara undan" värden som den har fått som parametrar.

Uppgift 2.2.1: Heltalsklassen

  1. Skapa klassen Heltal.

  2. Addera ett privat fält av typen int som skall användas för att hålla koll på vilket heltal objektet representerar.

  3. Lägg till en konstruktor som tar en int som inparameter och lagrar dess värde i objektets "privata" int-fält. IDEA kan snabbt skapa en konstruktor via Alt+Insert->Constructor.

Resultatet av detta ska bli att ett anrop till t.ex. new Heltal(14) returnerar ett Heltal-objekt där det privata fältet har värdet 14.

Bakgrund 2.2.2: Primtalsegenskapen

I förra labben testade vi om ett tal var primtal. Detta är en intressant egenskap hos heltal, och är något som heltalsobjekten själva skulle kunna testa. Med andra ord, istället för att fråga en annan klass om ett tal är ett heltal, vill vi fråga talet om det är ett primtal. Detta illustrerar skillnaderna mellan OO- och icke-OO-programmering.

Normalt skulle man bara ha ett sätt att testa primtal – ingen duplicerad kod! I denna övning nöjer vi oss dock med att "kopiera" funktionalitet från tidigare primtalstestare istället för att flytta den helt.

Tanken är alltså att om mittTal är ett Heltal, kan vi få reda på om detta är ett primtal genom att anropa mittTal.isPrime().

Uppgift 2.2.2: Primtalsegenskapen

  1. Skapa en isPrime()-metod i Heltal, som testar om detta Heltal är ett primtal. Metoden ska returnera sant eller falskt, och har alltså returtypen boolean.

    Huvuddelen av koden kan kopieras från labb 1. Den nya metoden får dock inte längre vara static, och ska inte heller ta något tal som parameter, eftersom den ska anropas för ett specifikt heltalsobjekt och kontrolla om detta objekts värde är ett primtal.

  2. Skriv en main()-metod som skapar ett Heltal med värdet 7, testar om detta är ett primtal, och skriver ut resultatet. Testkör programmet.

Bakgrund 2.2.3: Utskrifter

Vi vill kunna skriva ut våra Heltal på ett läsligt format. Först provar vi vad som händer när vi skriver ut ett heltalsobjekt.

Uppgift 2.2.3: Utskrifter

Se till att main() skriver ut minst ett Heltal-objekt med System.out.println(). Testkör. Får du ett underligt resultat, i stil med "Heltal@28cd724"? Då är allt rätt.

Bakgrund 2.2.4: Utskrifter och toString()

Till skillnad från t.ex. listor finns det inget bra standardiserat sätt att skriva ut objekt. Att bara visa värdet på alla fält t.ex. är ofta inte det bästa sättet, även om det hade fungerat just för Heltal. Som default skriver Java därför ut objekt på formen "klassnamn@objektID", där objektID är olika för varje objekt.

För att ändra detta implementerar man metoden public String toString() i sin klass. Vid ett anrop såsom System.out.println(mittObjekt) anropas då (indirekt och automatiskt) mittObjekt.toString(), och det är den returnerade strängen som skrivs ut istället för "klassnamn@objektID". Nu ska vi implementera en sådan metod.

IDEA kan själv skapa en toString() via Alt+Insert / toString(). Detta kan vara användbart när man snabbt vill generera en toString() för användning i debuggning (debuggern visar varje objekts toString() för att identifiera det). Den skulle dock generera ett resultat av typen "Heltal{value=14}" vilket vi inte vill ha här. Vi gör därför på ett annat sätt.

En int x kan konverteras till en sträng med String.valueOf(x).

(Avancerat: Alla klasser har egentligen redan en toString()-metod. Implementerar man ingen egen ärvs en ned från superklassen. Superklassen till Heltal är Object, och dess toString() har detta standardbeteende. Detta kommer att diskuteras när vi har gått genom arv.)

Uppgift 2.2.4: Utskrifter och toString()

  1. Tryck Alt+Insert och välj Override. Välj sedan toString().

  2. Låt toString() returnera värdet (konverterat till sträng enligt ovan), följt av en parentes som visar p om talet är ett primtal och np om det inte är ett primtal (t.ex. "12(np)" och "7(p)" ).

  3. Låt main() iterera 25 gånger. I varje iteration ska den skapa ett slumpmässigt int-värde mellan 0 och 100, skapa ett Heltal-objekt av detta int-värde, och skriva ut objektet. Testa programmet.

Sammanfattning

Vi kan nu skapa egna objekt och vet hur man konsturerar en strängrepresentation av dessa. Vi har sett hur man definierar klasser och initialiserar objekt då de skapas. Detta skiljer sig från programmering i icke objektorienterade språk.

Övning 2.3: Kalender

Syfte

Nu ska vi prova på att skapa en större sammanhängande uppsättning klasser för att lösa en specifik uppgift. Detta görs genom en almanacksuppgift som låter oss kontrastera de olika stegen mot den icke objektorienterade och "icke-typade" Python-programmering ni gjort i tidigare kurs. Vi går dock inte lika långt som tidigare – bara tillräckligt för att se kontrasterna i modellering.

Bakgrund 2.3.1: Typad OO-programmering

Vi skall nu skapa en klass Month som har motsvarande funktionalitet som i Python-almanackan.

I Python-almanackan behövde många funktioner programmeras explicit för varje typ, t.ex. för månader. Detta orsakades delvis av att programmet inte använde klasser, där man får mycket av detta "gratis" eller i alla fall "billigare".

  • is_month: objekt -> sanningsvärde testade om en lista var en månad med hjälp av get_tag(). Nu ska vi istället skapa klassen Month. Kräver en metod ett månadsobjekt behöver vi inte testa i efterhand om det var en månad som skickades – vi deklarerar helt enkelt en parameter av typen Month. Detta tar också bort många anrop till ensure() från implementationen.

  • new_month: sträng -> month, som skapar en månad av en textsträng som "january", blir en konstruktor. Detta använde attach_tag(), som inte längre behövs.

Funktioner som month_name(), month_number() och number_of_days() blir nu metoder i Month.

Uppgift 2.3.1: Objektorientering

  1. Skapa klassen Month med fälten:

    • name - månadens namn ("January")
    • number - månadens nummer (1)
    • days - antal dagar i månaden (31)
    Eftersom vi inte vill att någon skall ändra dessa värden utifrån lägger vi attributet "private" framför deklarationerna.

  2. Använd IDEA för att skapa en konstruktor som initialiserar Month åt dig. Tryck Alt+Insert och välj Constructor. I detta fall ska alla fält anges som parametrar till konstruktorn, så markera alla fält innan du trycker OK.

  3. Info: Getters/Setters

    Eftersom man oftast vill förhindra andra klasser att direkt använda fält i en klass är det vanligt att man skapar metoder för att läsa och ändra fält. Dessa kallas Setters och Getters och kan genereras automatisk av IDEA. Fördelen med ett metodgränssnitt mot fälten är att den interna representationen kan ändras utan att någon utanför behöver modifiera sin kod.

    Tryck Alt+Insert och välj Getter, klicka i alla tre fälten och sedan Ok. Nu genererar IDEA funktioner så att andra klasser kan få ut informationen men inte ändra den.

Vi har nu alla funktioner som fanns i Python-month.

Bakgrund 2.3.2: Månadsdata

Enligt ovan associeras en månad med ett namn, ett månadsnummer, samt antal dagar. I nuläget kan man skapa en månad med vilka parametrar som helst. Detta är inte vad vi vill uppnå. Vi vill ha en klart definierad månad som beter sig så som vi förväntar oss. Därför behövs mer information kring månader. Vi måste kunna testa om en sträng motsvarar ett månadsnamn samt kunna fråga hur många dagar det finns i en månad med ett visst namn. Detta är information som är specifik för månader och den bör alltså ligga i klassen Month.

Vi kommer att bortse från skottår då det inte tillför något av värde ur objektorienteringssynpunkt!

Uppgift 2.3.2: Månadsdata

  1. Skapa i klassen Month de statiska (static) metoderna getMonthNumber(String name) och getMonthDays(String name) som med hjälp av switch-satser (se labb 1) rapporterar månadsnummer och antal dagar i en månad utifrån det givna månadsnamnet. Låt default returnera -1. Då kan vi använda någon av funktionerna för att testa om en sträng faktiskt representerar en existerande månad.

    Detta ska motsvara MONTH_NUMBERS och MONTH_DAYS i Python-almanackan, men vi implementerar det som en metod istället för en dictionary.

    Statiska metoder används för att man inte ska behöva skapa ett Month-objekt för att kunna ta reda på antal dagar i en månad. Metoderna anropas därmed som Month.getMonthNumber(...). Mer om detta kommer på senare föreläsningar.

Bakgrund 2.3.3: Tid och Datum

Vi kommer inte att skapa speciella typer för timmar, minuter och dagar. Eftersom vi inte ska gå vidare och ge dessa tidsenheter mer funktionalitet än att just innehålla ett heltal, använder vi i denna labb helt enkelt int för att representera dessa. Däremot behöver vi representera datum som är sammansatta av år, dag och månad. Vi kommer också att behöva representera tidpunkter samt tidsintervall.

Uppgift 2.3.3: Tid och Datum

  1. Skapa klassen Date med fälten year (int), month (Month) och day (int). Lägg till en konstruktor som tar in dessa som parametrar. Lägg också till getters för dem. Skriv en toString()-metod presenterar ett datum i ett format som du tycker är lämpligt.

  2. Skapa klassen TimePoint som innehåller ett klockslag för att representera start/slut på en aktivitet. Klassen skall ha fälten time (String), hour och minute. Generera getters för hour och minute. Låt IDEA generera en konstruktor som endast tar time som inparameter.

    I konstruktorn skall hour och minute tilldelas värden. Liksom i Python-almanackan kräver att en TimePoint skapas med en sträng i formatet "hh:mm". Detta bryter vi upp i konstruktorn med hjälp av anropet

     String[] parts = time.split(":");

    som skapar en substräng för varje del som delas av med ett kolon. Nu är parts[0] timmen (som sträng) och parts[1] minuterna. Detta kan sedan konverteras till heltal med Integer.parseInt(...), precis som i labb 1.

  3. Skriv en toString()-metod som endast returnerar time. Klassen har hour och minute som kan användas för att beräkna varaktigheter på aktiviteter samt att sortera dessa medan time ger oss en färdig sträng att skriva ut.

    Överkurs: Skapa en int compareTo(TimePoint other)-metod som returnerar -1 om den aktuella TimePoint kommer före other, 0 om de representerar samma tid och 1 om other kommer före.

  4. Skapa till sist klassen TimeSpan. Den behöver två fält av typen TimePoint, start och end. Gör getters och en konstruktor som tar in dessa. Skriv sedan en toString()-metod som skapar utskrifter av typen "12:15 - 13:15". Detta görs bland annat genom anrop till toString() i start och end. På detta sätt bygger man rekursivt upp en textrepresentation av ett sammansatt objekt.

Info: Listor

Java har ingen egen syntax för listor. Istället är de klasser som alla andra, och det finns flera typer av listor. Den vanligaste och mest använda är ArrayList.

Listklasserna är generiska typer. Detta innebär helt enkelt att man kan ange en parameter som talar om vilken typ av element de innehåller, så att kompilatorn kan utföra bättre typkontroller. Om vi vill ha en lista som bara innehåller Heltal:

   ArrayList<Heltal> myList = new ArrayList<Heltal>();

Vi kan därefter stoppa in och plocka ut element:

   myList.add(new Heltal(10));  // Lägg till sist i listan
   Heltal x = myList.get(0);    // Hämta första elementet
   Heltal y = myList.get(3);    // Hämta fjärde elementet
   int antal = myList.size();   // Antal element i listan

Överkurs: Skriver ni som ovan kan det hända att IDEA klagar lite. ArrayList är nämligen ett specialfall av den mer generella typen List, och IDEA tycker att man ska skriva skriva så här istället. Detta förklaras senare i kursen.

   List<Heltal> myList = new ArrayList<Heltal>();

Bakgrund 2.3.4: Möten och kalendern

Allt som återstår nu är att lägga till en klass för möten och att skapa själva kalendern. Vi skapar en simpel kalender där alla möten lagras i en lista. En stor del av koden i metoden book() som används för att lägga möten i kalendern utgörs av parameterkontroll. Att kontrollera användarens inparametrar är ofta största delen av den kod som ligger i ett API. Vi kommer att generera ett undantag om man försöker skapa ett otillåtet möte.

Uppgift 2.3.4: Möten och kalendern

  1. Skapa klassen Appointment med tre fält, subject (String), date (typ Date) och timeSpan (typ TimeSpan). Skapa getters och en konstruktor som tar samtliga som parametrar. Skapa även en toString()-metod som använder sig av Date.toString() och TimeSpan.toString() för att formattera en fin utskrift.

  2. Skapa klassen Calendar. Den skall ha en privat lista av appointments som realiseras av en ArrayList, en collection som implementerar list-gränssnittet, i en konstruktor utan inparametrar. Detta sker genom raderna

       private List<Appointment> appointments;
    i klassen och

       appointments = new ArrayList<>();
    i konstruktorn.

  3. Implementera metoden show() som går igenom listan och skriver ut alla appointments. Detta kan med fördel göras genom att använde Live-Template (Ctrl+J) iter som leder till en så kallad for-each-loop där varje element i t.ex. en lista besöks. Denna loop har formatet "for (element : behållare)".
  4. Implementera metoden

       public void book(int year, String month, int day, 
            String start, String end, String subject)

    Notera att vi här tar in ett månadsnamn som en sträng. Att skapa ett Date-objekt kräver däremot att vi har ett månadsobjekt. Det är upp till book() att anropa lämpliga statiska metoder i Month för att ta reda på bl.a. vilket nummer månaden har och sedan skapa ett lämpligt månadsobjekt.

    Metoden skall skall kontrollera alla inparametrar. Detta betyder att

    • year > 2013
    • start/end skall konverteras och kontrolleras så att 0 <= hour <= 23 och 0 <= minute <= 59
    • month skall vara ett namn som motsvarar en existerande månad
    • månaden skall ha tillräckligt många dagar för att day skall vara tillåten
    • Överkurs: Använd compareTo() i TimePoint för att kontrollera att start är före end.

    Om någon av parametrarna är fel skall ett IllegalArgumentException kastas för att informera användaren om detta. Detta görs med:

       throw new IllegalArgumentException("felmeddelande");

    När parametrarna är kontrollerade skall ett Date objekt skapas utifrån datuminformationen och två TimePoint objekt skapas utifrån start/end. Dessa två används sedan för att skapa ett TimeSpan och slutligen ett Appointment som läggs till i listan.

  5. Kalendern är nu färdig och du skall skriva ett testprogram som skapar en kalender, bokar 5-10 appointments och sedan skriver ut kalendern.

    Överkurs: Skriv ut appointments i sorterad ordning.

Sammanfattning

Du har nu byggt ett objektorienterat program med flera klasser. Du är bekväm med Setters/Getters, har testat for-each och listor i Java, inklusive generics, samt kastat Exceptions.

Övning 2.4: Delegering

Syfte

Ett vanligt sätt att återanvända funktionalitet i existerande klasser i OO-programmering är ärvning, vilket vi inte har diskuterat än. Det finns dock andra sätt att åstadkomma något liknande – t.ex. komposition med delegering. Vi ska nu prova dessa tekniker.

Bakgrund 2.4.1: Stack och Kö

Vi skall nu skapa två enkla datastrukturer: kö och stack. För enkelhets skull går vi inte in närmare på generiska typer, utan håller oss till Heltal som element.

I en kan man bara lägga till element längst bak (enqueue) och ta bort längst fram (dequeue). Detta är enligt mottot "först in, först ut" (FIFO):

I en stack ("trave") däremot påverkar man alltid det översta elementet, med metoderna push och pop. Mottot är här "sist in, först ut" (LIFO):

Vi kommer att behöva någonstans att lagra de element som skall ligga i datastrukturerna. För att göra det enkelt för oss använder vi en redan existerande datastruktur, ArrayList från förra övningen. På så vis lämnar vi t.ex. över problemet att allokera lagom mycket lagringsutrymme till denna färdiga klass.

Men hur skall vi använda en ArrayList för att implementera detta?

Ett sätt är genom arv. Vi skulle då göra t.ex. Stack till en underklass till ArrayList. Genom arv skulle våra klasser få alla metoder från ArrayList. Men detta är en datastruktur som kan modifieras på "fel" sätt. Till exempel kan man i en lista lägga till och ta bort element var som helst, inte bara i början som vi vill med en stack. Detta går delvis att arbeta sig runt, men det finns bättre alternativ. Det är ju inte så att en Stack är en ArrayList med extra funktionalitet, utan den har faktiskt mindre funktionalitet!

Lösningen är att använda sammansättning (composition) och låta vår Stack ha och använda en ArrayList istället för att vara en.

Uppgift 2.4.1: Stack och Kö

  1. Skapa klassen Queue.

  2. Skapa ett privat fält List<Heltal> elements och initialisera detta till en ny ArrayList<Heltal>.

  3. Det finns metoder i ArrayList som vi vill göra tillgängliga för användaren av Queue. size() är en sådan metod. Eftersom elements håller koll på antalet element den innehåller, skriver vi helt enkelt bara en size()-metod i Queue som returnerar resultatet av elements.size(). Vi delegerar alltså det egentliga arbetet till elements-listan. (IDEA kan hjälpa till – läs vidare!)

    Vi delegerar arbetet till elements även för metoderna isEmpty(), clear() och contains() på precis samma sätt, genom att ha en metod som direkt anropar och returnerar svaret från motsvarande metod i elements.

    Delegering är så pass vanligt att IDEA kan automatisera det åt oss. Genom att välja Code | Delegate Methods och sedan välja elements kan man därefter välja precis vilka metoder man vill delegera.

  4. Vi behöver även några "egna" metoder. Lägg till metoderna dequeue() och enqueue(). Dessa skall använda sig av metoderna elements.add() och elements.remove(int index) för att ta ut första elementet i elements och stoppa in ett element sist i listan.

  5. Nu är Queue färdig och det är dags att skapa Stack. Stack och Queue är lika på alla punkter utom var objekt läggs till/tas ut. Därför kan man använda IDEAs funktion clone class som man kommer åt genom att trycka F5 när markören står i klassnamnet. Ange bara namnet Stack så skapas en ny klass som ser precis ut som Queue. Byt namn på enqueue/dequeue till push/pop och ändra koden i dem så att Stack beter sig som en stack.

  6. Slutligen, skriv ett testprogram.

    Skapa en stack, lägg i tur och ordning in talen 1 till 10 i denna, och plocka sedan ut och skriv ut element i den ordning de kommer. Använd en while-loop som itererar till stacken är tom.

    Gör även samma sak med en kö.

Avslutning

Här slutar andra laborationen. Visa slutresultatet för din handledare och passa på att fråga om det är något du undrar över. Skulle handledaren vara upptagen går det bra att börja med laboration 3.

Labb av Mikael Nilsson, Jonas Kvarnström 2014.


Sidansvarig: Jonas Kvarnström
Senast uppdaterad: 2015-11-09