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.
Vi kommer att hjälpa till med flera handgrepp i programmeringen, men det är som tidigare viktigt att ni inte genomför dem "mekaniskt" utan reflekterar över varför ni gör som ni gör.
Deadlines och krav
Labben examineras via demonstration utan kodinlämning senast vid deadline.
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 som översätter källkoden (.java-fil) till en intern representation (.class-fil). IDEA kompilerar automatiskt innan ett program startas, men ibland vill man kompilera utan att köra, t.ex. för att dubbelkolla att inga syntaxfel finns kvar. Detta görs genom:
Build | Make Project Ctrl-F9, som kompilerar "det som behövs" men behåller det som inte ändrats
Build | Rebuild project, som kompilerar allt.
Ö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
-
Tidigare klasser låg i paketet
se.liu.ida.dinadress.tddd78.lab1
. Högerklickasrc
, välj New | Package och skapase.liu.ida.dinadress.tddd78.lab2
. Detta ska hamna på samma nivå som lab1 i klassträdet. -
Skapa klassen
Slump
i paketetlab2
.
Bakgrund 2.1.2: Slumptal
Vi ska nu skapa slumptal med en (pseudo-)slumptalsgenerator.
En slumptalsgenerator initialiseras normalt med ett "frö" och ger sedan en sekvens av slumptal. Samma frö ger alltid samma sekvens av slumptal (som ska vara svår att förutse och därmed efterlikna "äkta slump"), 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
-
Skapa en
main()
-metod iSlump
. -
Vi skall nu skapa ett första objekt. Objekt skapas med hjälp av operatorn
new
. Vi skriver därförRandom 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 inRandom
vill IDEA därför veta vilken Random du menar. Den ger då en popup som föreslår import avjava.util.Random
, den endaRandom
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 namnetrnd
. Vi skickar inte med några initialiseringsparametrar till konstruktorn utan är nöjda med defaultbeteendet hosRandom
.
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. Dokumentationen för Javas standardklasser finns så klart färdigindexerad på nätet.
Uppgift 2.1.3: Visa Javadoc
Prova att placera markören i t.ex. Random()
och trycka
Ctrl-Q. Detta visar javadoc i en liten popup-ruta så
att du snabbt får fram information utan att behöva lämna
utvecklingsmiljön och navigera genom HTML-filerna.
Så småningom ska du skriva Javadoc-kommentarer även för din egen kod. Även där fungerar Ctrl-Q för att snabbt få fram information.
Exempel från fältet "out" i System.out
:
Bakgrund 2.1.4: Auto-komplettering
IDEAs autokomplettering visar vilka valmöjligheter som finns för fortsatt kodskrivning och kan vara mycket användbar.
Uppgift 2.1.4: Använda autokomplettering
Testa att skriva "rnd.
" på raden under new
Random();
. Beroende på dina inställningar kanske
rutan med möjliga fortsättningar kommer automatiskt, eller så får du ta fram den själv med Ctrl-Space.
Eftersom IDEA vet vilken typ variabeln har vet den exakt vad som
kan stå efter "rnd.
", vilket är ett väldigt bra sätt
att lära sig mer om tillgänglig funktionalitet.
Du kan välja ett alternativ i listan eller fortsätta skriva. Om
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. Man kan också trycka Ctrl-Q vilket 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
-
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. -
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, 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: Personklassen
Vi tänker oss att vi skall arbeta med olika personer i en applikation. Då är det naturligt att samla information och funktionalitet som rör en person i en klass.
För att kunna konstruera olika objekt av typen Person
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: Personklassen
-
Skapa klassen
Person
. -
Addera ett privat fält med namn
name
av typenString
som skall användas för att lagra personens namn. Eftersom varje person har sitt eget namn (som lagras i personobjektet) ska fältet inte varastatic
. -
Addera ett privat fält
birthDay
av typenLocalDate
som skall användas för att lagra personens födelsedatum. NärLocalDate
matas in kommer IDEA inte att känna till denna klass, men föreslå att den importeras av personklassen så att den känns igen och kan användas. Skulle man trycka bort möjligheten att låta IDEA importeraLocalDate
kommer IDEA att rödmarkera namnet. Ställer man markören i namnet kommer en röd lampa att tändas där man åter kan välja att IDEA skall importera klassenLocalDate
.Här finns mer information om
LocalDate
för den som är intresserad. -
Lägg till en konstruktor som tar en
String
och enLocalDate
som inparametrar och lagrar dessa värde i objektets "privata" fält. IDEA kan snabbt skapa en konstruktor via Alt+Insert->Constructor. -
Ett
LocalDate
-objekt som representerar ett datum kan t.ex. skapas med hjälp av anropetLocalDate.of(1990, 6, 1)
om man vill skapa ett datum som representerar den 1:a juni 1990. Skapa en main()-metod (snabbast genom att skriva psvm och därefter trycka CTRL+Space eller CTRL-J och välja att ni vill ha en main() metod). I main()-metoden kan du skapa en person som motsvarar dig själv.Kör ditt testprogram och se att det inte kraschar!
Bakgrund 2.2.2: Tidsperioder
Vi skall nu utöka vår personklass med en metod för att beräkna hans/hennes ålder. Till vår hjälp har vi redan sett att LocalDate
kan användas för att representera ett datum. För att få nuvarande tid använder vi LocalDate.now()
som returnerar ett LocalDate
objekt som representerar dagens datum.
Om vi vill räkna ut en persons ålder behöver vi vet hur lång tid det är mellan dess födelse och dagens datum. Vi kan räkna ut hur lång tidsperiod det är mellan två datum med hjälp av klassen Period
. Om man anropar Period.between(start,slut)
där start och slut är av typen LocalDate
får man ett Period
-objekt. Man kan ta reda på hur många år som perioden består av genom metoden getYears()
.
Uppgift 2.2.2: Tidsperioder
-
Implementera metoden
getAge()
som returnerar personens ålder. Eftersom varje person har sin egen ålder (som lagras i personobjektet) ska metoden inte varastatic
. -
Testa att metoden fungerar genom att skriva ut åldern på den person med dina data som skapats i
main()
-metoden.
Bakgrund 2.2.3: Utskrifter
Vi vill kunna skriva ut våra personer på ett läsligt format. Först
provar vi vad som händer när vi skriver ut ett Person
-objekt.
Uppgift 2.2.3: Utskrifter
Se till att main()
skriver ut minst ett Person
-objekt med
System.out.println()
. Testkör. Får du ett underligt resultat, i
stil med "Person@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 för personklassen som den ser ut just nu. Som standard 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 "Person{name='namn', birthDay=1990-06-01}". I vår applikation är det viktigt att snabbt kunna se åldern på personer och därför gör vi på ett annat sätt.
(Avancerat: Alla klasser har egentligen redan en toString()
-metod.
Implementerar man ingen egen ärvs en ned från superklassen.
Superklassen till Person
ä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()
-
Tryck Alt+Insert och välj Override. Välj sedan
toString()
. -
Vi sätter nu ihop en sträng som får representera vår person. Man kan sätta ihop två strängar med hjälp av "+"-operatorn. Om man sätter ihop en sträng med något som inte är en sträng kommer Java att konvertera det andra objektet till en sträng. Låt
toString()
returnera värdetname+" "+getAge()
. -
Skapa några personer till och skriv ut var och en på sin egen rad.
Funktionsargument och Smart Completion
IDEA har flera hjälpsamma funktioner. T.ex. så kommer en funktion
som inte får inparametrar av rätt typ att rödmarkeras av IDEA,
något som inte skulle fungera i Python där parametrar inte har
typer. Om man sätter markören över får man reda på varför anropet
inte fungerar. Testa att anropa konstruktorn till Person
men med
ett heltal istället för en sträng på namnpositionen. IDEA kommer
då visa att man skickar med ett heltal när konstruktorn kräver en
sträng. Det sparar mycket tid att man får reda på fel innan
kompilering. Dessutom får man reda på vad som är rätt också!
Om du deklarerar String namn = "Anders Andersson";
och sedan någonstans längre ner i programmet skall skapa en person
med detta namn kan IDEA hjälpa till genom "Smart Completion". Man
kommer åt denna hjälp genom att
trycka CTRL-Shift-Space. Skulle man stå på ett ställe
där en String
förväntas kommer IDEA att föreslå
variabler som matchar. Om du gör ett anrop till
Person
-konstruktorn och
trycker CTRL-Shift-Space när det är dags att ange
name
-parametern kommer IDEA föreslå att du skickar
med namn
-variabeln.
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 klassenMonth
. 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 typenMonth
. Detta tar också bort många anrop tillensure()
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
-
Skapa klassen
Month
med fälten:- name - månadens namn ("January")
- number - månadens nummer (1)
- days - antal dagar i månaden (31)
-
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. -
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 Getters och Setters och kan genereras automatiskt av IDEA. Fördelen med ett metodgränssnitt mot fälten är bland annat 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.
Bakgrund 2.3.2: Månadsdata
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
-
Skapa i klassen
Month
metodernagetMonthNumber(String name)
ochgetMonthDays(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åtdefault:
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.
I just detta fall vill vi använda statiska metoder (deklarerade
static
). Då behöver vi inte skapa ettMonth
-objekt för att kunna ta reda på antal dagar i en månad, utan anropar metoderna direkt i klassen istället. Metoderna anropas därmed somMonth.getMonthNumber(...)
. Mer om detta kommer på senare föreläsningar.
Bakgrund 2.3.3: Tid och Datum
Uppgift 2.3.3: Tid och Datum
-
Skapa klassen
Date
med fältenyear
(int),month
(Month
) ochday
(int). Lägg till en konstruktor som tar in dessa som parametrar. Lägg också till getters för dem. Skriv entoString()
-metod presenterar ett datum i ett format som du tycker är lämpligt. -
Skapa klassen
TimePoint
som innehåller ett klockslag för att representera start/slut på en aktivitet. Klassen skall ha fältentime
(String
),hour
ochminute
. Generera getters förhour
ochminute
. Låt IDEA generera en konstruktor som endast tartime
som inparameter.I konstruktorn skall
hour
ochminute
tilldelas värden. Liksom i Python-almanackan kräver att enTimePoint
skapas med en sträng i formatet "hh:mm". Detta bryter vi upp i konstruktorn med hjälp av anropetString[] 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) ochparts[1]
minuterna. Detta kan sedan konverteras till heltal medInteger.parseInt(...)
, precis som i labb 1.De fält och metoder vi skapar nu ska anropas i ett objekt, inte i en klass. De ska alltså inte vara statiska! Vi frågar till exempel ett specifikt
Date
-objekt, inte datumklassen, vilket år det har.Extra information för den intresserade: Typen
String[]
är en array av strängar. Arrayer liknar listor, men kan aldrig ändra storlek efter att de har skapats. Vi kan få ut antalet element i arrayen medparts.length
. Mer om arrayer kommer senare under kursen. -
Skriv en
toString()
-metod som endast returnerartime
. Klassen harhour
ochminute
som kan användas för att beräkna varaktigheter på aktiviteter samt att sortera dessa medantime
ger oss en färdig sträng att skriva ut.Överkurs: Skapa en
int compareTo(TimePoint other)
-metod som returnerar -1 om den aktuellaTimePoint
kommer före other, 0 om de representerar samma tid och 1 omother
kommer före. -
Skapa till sist klassen
TimeSpan
. Den behöver två fält av typenTimePoint
,start
ochend
. Gör getters och en konstruktor som tar in dessa. Skriv sedan entoString()
-metod som skapar utskrifter av typen "12:15 - 13:15". Detta görs bland annat genom anrop tilltoString()
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 olika listklasser med olika
egenskaper. 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<Integer> myList = new ArrayList<Integer>();
Vi kan därefter stoppa in och plocka ut element:
myList.add(10); // Lägg till sist i listan
int x = myList.get(0); // Hämta första elementet
int 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<Integer> myList = new ArrayList<Integer>();
Bakgrund 2.3.4: Möten och kalendern
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
-
Skapa klassen
Appointment
med tre fält,subject
(String
),date
(typ Date) ochtimeSpan
(typTimeSpan
). Skapa getters och en konstruktor som tar samtliga som parametrar. Skapa även entoString()
-metod som använder sig avDate.toString()
ochTimeSpan.toString()
för att formattera en fin utskrift. -
Skapa klassen
Calendar
. Den skall ha en privat lista av appointments som realiseras av enArrayList
, vilket är en collection som implementerar list-gränssnittet, i en konstruktor utan inparametrar. Detta sker genom raderna
i klassen ochprivate List<Appointment> appointments;
i konstruktorn.appointments = new ArrayList<>();
-
Implementera metoden
show()
som går igenom listan och skriver ut alla appointments. Detta kan med fördel göras genom att använda 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)". -
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()
iTimePoint
för att kontrollera attstart
är föreend
.
Om någon av parametrarna är fel ska detta signaleras till anroparen. Detta gör man normalt med exceptions, "undantag". Exakt hur detta fungerar kommer vi att gå genom i en senare del av kursen. För tillfället räcker det med att ni vet att ett
IllegalArgumentException
ska kastas, och att 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ånstart
/end
. Dessa två används sedan för att skapa ettTimeSpan
och slutligen ettAppointment
som läggs till i listan. -
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 har 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 Person
som element.
I en kö 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, något som ska diskuteras ingående
under en senare del av kursen. Som vi ska se under en föreläsning
är detta inte det bästa valet i denna situation. Istället vill vi
använda sammansättning (composition). Det betyder
helt enkelt att vi låter vår Stack
ha
och använda en ArrayList
istället för
att vara en.
Uppgift 2.4.1: Stack och kö
-
Skapa klassen
Queue
. -
Skapa ett privat fält
List<Person> elements
och initialisera detta till en nyArrayList<Person>
. Eftersom varjeQueue
har sina egna element får detta fält inte vara statiskt. -
Det finns metoder i
ArrayList
som vi vill göra tillgängliga för användaren avQueue
.size()
är en sådan metod. Eftersomelements
håller koll på antalet element den innehåller, skriver vi helt enkelt bara ensize()
-metod iQueue
som returnerar resultatet avelements.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 metodernaisEmpty()
,clear()
ochcontains()
på precis samma sätt, genom att ha en metod som direkt anropar och returnerar svaret från motsvarande metod ielements
.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.
-
Vi behöver även några "egna" metoder. Lägg till:
enqueue()
, som tar en person som parameter och lägger till den sist i kön, och-
dequeue()
, som hämtar personen som är först i kön, tar bort den ur kön (listan), och returnerar den.
Dessa skall använda sig av metoderna
elements.add()
ochelements.remove(int index)
för att ta ut första elementet i elements och stoppa in ett element sist i listan.Tänk på att t.ex.
enqueue
ska lägga till ett element i en specifik kö (ett specifiktQueue
-objekt), inte i kö-klassen i sin helhet. Metoderna du skriver här ska alltså inte vara statiska. -
Nu är
Queue
färdig och det är dags att skapaStack
. Klasserna ä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 namnetStack
så skapas en ny klass som ser precis ut somQueue
. Byt namn påenqueue/dequeue
tillpush/pop
och ändra koden i dem så attStack
beter sig som en stack. -
Slutligen, skriv ett testprogram.
Skapa en stack, lägg i tur och ordning in 5 olika personer i denna, och plocka sedan ut och skriv ut element i den ordning de kommer. Vi kunde använda en
for
-loop, men vi har egentligen inget behov av att veta vilken position vi är på – bara om det finns fler element kvar eller inte. Därför använder vi istället enwhile
-loop som itererar så länge stacken inte ä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–2015.
Sidansvarig: Jonas Kvarnström
Senast uppdaterad: 2015-01-30