Lektion 5: Enkla klasser. Obligatorisk redovisning 2
Moment: | Enkla klasser: instansvariabler, konstruktorer, metoder. |
Begrepp som introduceras: |
Instansvariabler, konstruktorer, get-metoder,
set-metoder, toString -metoden.
|
Arbetssätt: |
Arbeta gärna tillsammans med någon men skriv egen kod. Diskutera med varandra! Följ kodningsreglerna! |
Uppskattad arbetstid: | 4 timmar. Notera gärna hur lång tid du själv behöver och framför det vid redovisningen! |
Redovisning: |
Obligatorisk redovisning för lärare/handledare enligt tiderna på
kurssidan.
Frågor utan svar ska besvaras vid redovisningen. Fråga handledaren om du inte förstår svaren på frågor med givna svar! |
Något om klasser och objekt
Begreppen klass och objekt är bland de mest centrala begreppen i objektorienterad programmering.
En klass är en allmän beskrivning, en modell eller mall,
av en viss typ av objekt som sedan ett program kan skapa och använda för att utföra en uppgift.
Klassen (beskrivningen) finns sparad i en textfil med typen .java
.
Från klassen kan man sedan skapa ett eller flera objekt.
T ex skapade du t1
och t2
som refererar till två objekt som är
skapade enligt beskrivningen i klassen Turtle
.
De klasser vi hittills har sett är Turtle
, World
, String
(och Math
som dock är av liten annan karaktär än de först nämnda).
Andra tänkbara exempel på klasser är Person
, Bankkonto
, Fordon
,
Ljussignal
, Vektor
, Boll
, Spelplan
, ComplexNumber
, ...
helt beroende på vad programmet skall handla om.
Observera att alla exempel är substantiv! Detta är signifikativt!
När man skall designa en klass väljer man vilka egenskaper man vill att objekten skall ha.
Objekt ur klassen Turtle
har egenskaper som position (x- och y-koordinater) i världen,
färg, storlek, namn, ...
Egenskaperna representeras av instansvariabler.
Man skall också bestämma vad man vill kunna göra med objekten.
Turtle
-objekten skall kunna flyttas, vändas, byta färg, ...
Sådana operationer definieras av metoder
För att skapa objekt ur en klass använder man så kallade konstruktorer.
En konstruktor ser ut som en metod men den har samma namn som klassen och ingen typangivelse
(alternativt uttryckt har den bara en typangivelse (klassnamnet) och inget namn).
Exempel på konstruktorer som du redan har använt:
public World(int x, int y) { ... } |
En konstruktor i World -klassen. Parametrarna anger höjd och bredd. |
public World() { ... } |
En annan konstruktor i World -klassen.Skapar värld av "standardstorlek". |
public Turtle(World w) { ... } | En konstruktor i Turtle -klassen. |
Objekt skapas med operatorn new
följt av klassnamnet samt eventuella parametrar inom parentes.
Fråga: Vilka av konstruktorerna används i nedanstående satser?
World w = new World(1000,200); | Skapar en värld. |
World v = new World(20,20); | En till, mycket liten, värld |
Turtle t = new Turtle(w); | En padda i den stora vida världen |
Turtle s = new Turtle(v); | och en i den lilla världen |
Turtle u = new Turtle(new World()); | och en i en ny (skön) värld. |
(Observera hur vi på den sista raden anropar konstruktorn för världen
i parametern till paddan. Vi skapar alltså en värld utan att själva behålla en referens till den.
I detta fall vet vi från föregående lektioner att det går att får tag i en referens med anropet
u.getWorld()
.)
Vi har i tidigare lektioner kompletterat klassen Turtle
med några metoder utan att
egentligen gå in på hela klassens innehåll.
Nu skall vi titta på närmare på hur klasser är uppbyggda.
Klassens allmänna struktur:
public class klassnamn { | ||
instansvariabler | beskriver egenskaper hos ett objekt | |
konstruktorer | definierar vad som sker när objektet skapas | |
metoder | definierar vad man kan göra med objektet | |
}
|
Uppgift 1: Klassen Rectangle
Antag att vi vill representera rektanglar i ett program. Två fundamentala egenskaper hos rektanglar är bredd och höjd.
Från dessa kan andra egenskaper beräknas (t ex yta och omkrets). Sådana egenskaper kallas härledda.
Rektanglar kan även ha andra egenskaper som t ex färg och position beroende på vad man vill göra med dem men i detta exempel begränsar vi oss till ovan nämnda egenskaper.
I detta lilla exempel ska man kunna skapa rektanglar med olika värden på bredd och höjd, fråga en rektangel om dess egenskaper och ändra vissa egenskaper.
public class Rectangle { | Första raden definierar klassens namn. |
private double width; private double height; | Klassen har två instansvariabler ("egenskaper"). |
public Rectangle() { width = 1; height = 1; } | En parameterlös konstruktor som konstruerar en "enhetsrektangel". |
public Rectangle(double width, double height) { this.width = width; this.height = height; } |
En konstruktor där man anger bredd och höjd. Se nedan för betydelsen av this .
|
public double getWidth() { return width; } public double getHeight() { return height; } public double getArea() { return width*height; } |
Metoder för att hämta egenskaper. En av egenskaperna ( getArea ) är härledd.
|
public void setWidth(double width) { this.width = width; } public void setHeight(double height) { this.height = height; } | Två set-metoder för att ändra egenskaperna. |
public String toString() { return "Rectangle(" + width + "x" + height + ")"; } | En metod som returnerar en text-representation av objektet. |
public static void main(String[] arg) { Rectangle rec1 = new Rectangle(); rec1.setWidth(4); rec1.setHeight(5); System.out.print(rec1.toString()); System.out.println(" has the area " + rec1.getArea()); Rectangle rec2 = new Rectangle(3, 2); System.out.print(rec2.toString()); System.out.println(" area " + rec2.getArea()); } } |
En main-metod som demonstrerar användningen av klassen.
Observera att det går bra att dela upp långa satser på flera rader! |
Några allmänna observationer och kommentarer
- Klassers namn ska börja på stor och metoders namn på liten bokstav (konvention).
- Klassnamn är substantiv och metoders namn verb (konvention).
-
toString
är en standardmetod som systemet använder för att få en strängrepresentation av objekt. Den används automatiskt t ex i satsenSystem.out.println(rec1)
.
Det hade dock gått lika bra att skrivaSystem.out.println(rec1.toString())
.Observera att metodens namn faktiskt avviker från konventionen - den borde heta något i stil med
getStringRepresentation
. -
Namn på metoder som används för att fråga om egenskaper börjar på
get
oavsett om det är en lagrad eller härledd egenskap (konvention). -
Namn på metoder som sätter egenskaper utifrån ett parametervärde börjar med
set
(konvention). -
I konstruktorn med parametrar har dessa samma namn som instansvariablerna.
Om man där bara skriver t ex
width
så är det parametern som avses. För att referera instansvariabeln använder manthis.
framför namnet. Samma sak gäller iset
-metoderna.Eftersom
get
-metoderna inte har någon parameter (eller lokal variabel) med samma namn som instansvariablerna så behövs intethis
där. Det är dock tillåtet och betraktas som god stil att faktiskt alltid användathis
när man refererar instansvariabler.Om man väljer andra namn på parametrarna (t ex
w
ochh
) behöver man inte användathis
men de valda namnen fungerar som dokumentation av betydelsen. - Koden ovan kan kritiseras för att den inte kontrollerar att parametrarnas värden är rimliga. Det går t ex bra att ge rektanglar negativa bredd och/eller höjd. Anledningen till att vi inte gjort kontrollen är dels att vi vill hålla storleken på exemplet nere och dels att vi ännu har något bra sätt att slå larm om värdena är felaktiga.
Gör följande
- Välj i DrJava-menyn för att få en tom definitionsruta. Hämta koden och klistra in den i definitionsrutan.
- Kompilera.
-
Eftersom
main
-metoden ligger i klassen kan man köra den med på klassen. Prova! Studera utskrifterna! -
Notera ordningen på klassens delar.
Vad händer om man byter plats på metoderna
setHeight
ochgetArea
? Vad händer om man flyttar instansvariablerna sist i klassen? Varför har man en viss ordning på delarna i klassen? -
Skriv en ny metod
getCircumference
i klassenRectangle
som beräknar och returnerar omkretsen av rektangeln. Metoden ska inte skriva ut något. Kompilera. -
Lägg till kod i
main
som beräknar och skriver ut rektanglarnas omkrets.
Frågor
-
Vilka instansvariabler har klassen?
width
ochheight
-
Vilka lokala variabler finns i koden?
Endast
rec1
ochrec2
imain
-metoden. -
Vilka formella parametrar finns i koden?
width
ochheight
är formella parametrar till den ena konstruktorn. MetodensetWith
harwidth
, metodensetHeight
harheight
och metodenmain
hararg
som formell parameter. -
Vilka aktuella parametrar finns i koden?
Aktuella parametrar är de som anges när en metod anropas. I detta exempel är det endast
main
-metoden som anropar metoder. Aktuell parametrar där är4
tillsetWidth
5
tillsetHeight
rec1.toString()
tillSystem.out.print
"has the area " + rec1.getArea()
tillSystem.out.println
osv. -
Vilken del av klassen används när första satsen i
main
-metoden körs (exekveras)?Den parameterlösa konstruktorn i klassenRectangle
anropas och utförs. Rektangelns bredd och höjd sätts till 1. En referens till den konstruerade rektangeln lagras i variabelnrec1
. -
Vilken del av klassen används när andra satsen i
main
-metoden körs?MetodensetWidth
anropas. Metoden ändrar bredden på det nyss skapade rektangelobjektet från 1 till 4. -
Vad händer när en konstruktor anropas?
Ett objekt skapas dvs det reserveras utrymme i minnet för instansvariablerna och dessa tilldelas värden enligt koden i konstruktorn (eller enligt de standardregler som gäller).
-
Varför behöver metoden
setWidth
en parameter men inte metodengetArea
?Parametrar används för att överföra information från anroparen till metoden.setWidth
behöver information om vad bredden ska sättas till.
getArea
behöver inget från anroparen utan ska bara lämna ut information om objektet. -
Varför har metoden
getArea
returtypdouble
och intevoid
som vissa andra metoder?getArea
ska returnera information till anroparen men det ska intesetWidth
. -
Vad händer om man tar bort
this
från metodensetWidth
? Testkör och förklara! -
Vad händer om man flyttar
this
till högersidan av tilldelningen dvs skriver
width = this.width
i metodensetWidth
? Testkör och förklara! -
Kommentera bort definitionen av
toString
-metoden, kompilera och kör. Vad händer? Varför? -
Vad händer om man tar bort anropet till
toString()
-metoden vid anropen tillprintln
imain
dvs skriverSystem.out.println(rec1);Testkör och förklara! -
Läs kodningsreglerna
och kritisera nedanstående rader:
int i = 0; //antal vinster nollställs //nu ska vi öka i med 1 i++; System.out.println(i); //Nu skriver vi ut antalet vinsterHur bör koden skrivas?Svar:
Dåligt variabelnamn,
konstigt sätt att sätta i till 1,
dålig indentering,
onödig blankrad,
totalt onödiga kommentarer,
användande av nationella bokstäver,
kommentarerna stör läsbarheten av koden,
ingen förklaring vad utskriften betyder.
Så här bör det vara:
int lotteryWin = 1; System.out.println("Antal vinster: " + lotteryWin)
Uppgift 2: Klassen Person
Skriv en ny klassPerson
. Följande privata instansvariabler ska finnas (välj lämpliga datatyper själv):
name
address
age
Klassen ska även innehålla:
-
En parameterlös konstruktor som skapar ett
Person
-objekt med namnet "NoName" och åldern 0, - en konstruktor där alla instansvariablerna får värden från parametrar,
-
en metod
getAge
som returnerar personens ålder, -
en metod
getName
som returnerar personens namn, -
en metod
increaseAge
som ökar åldern med 1, -
en metod
getDays
som returnerar antal dagar som personen levt (ålder * 365) och -
en metod
toString
som returnerar en sträng med information om personen.
Observera att ingen av ovanstående metoder ska ge någon utskrift!
Skriv slutligen en main
-metod i en annan ny klass som testar metoderna i klassen Person
.
Frågor:
-
Vilken/vilka av ovanstående metoder kan skrivas som
void
-metoder?increaseAge
ochmain
-
Vilken/vilka av ovanstående metoder måste skrivas som
void
-metoder?Endastmain
. Man kan t ex låtaincreaseAge
returnera den nya åldern. -
Vad får
address
-variabeln för värde när den parameterlösa konstruktorn använts?En instansvariabel av typenString
får, liksom alla referensvariabler, värdetnull
som default.
Uppgift 3: Klasserna Dice och PairOfDice
Klassen Dice
- Tag en egen kopia av klassen Dice.java
- Kompilera
-
Klassen innehåller en
main
-metod som använder klassen. Testkörmain
-metoden. -
Lägg till en metod
public int roll(int n)
som slår tärningenn
gånger och returnerar summan av poängen. Använd metoder som redan finns i klassenDice
istället för att upprepa kod!
Testa metoden i interaktionsfönstret. -
Lägg in anrop av metoden
roll(int n)
sist imain
-metoden. Testkör!
Frågor
-
Hur fungerar metoden
roll()
? -
Beskriv sats för sats vad som händer när
main
-metoden körs. (Läs minilektionen om minilektionen omfor
-satsen om du inte känner till den!) -
Vad händer när man exekverar följande satser?
Dice d = new Dice(1); Dice e = new Dice(8);
Klassen PairOfDice
Skriv en ny klass PairOfDice
som representerar ett tärningspar (två tärningar).
Klassen skall bygga på klassen Dice
vilket betyder att man skall
använda Dice
-objekt och deras metoder.
Klassen PairOfDice
skall alltså ha två instansvariabler som av typen Dice
.
Klassen skall innehålla
-
En konstruktor utan parametrar (
PairOfDice()
) som skapar ett par av 6-sidiga tärningar samt en konstruktor där man ger antalet sidor (PairOfDice(int nSides)
). Båda tärningarna förutsätts ha samma antal sidor. - En metod för att slå tärningsparet.
- En metod (eller två?) metod(er) för att returnera tärningarnas värden.
-
En metod
boolean isPair()
som returnerartrue
om båda tärningarna har samma värde, annarsfalse
.
(Läs minilektionen om boolska (logiska) uttryck om du är osäker på dessa.) -
En
toString
-metod. Denna metod ska användaDice
-klassenstoString
-metod! -
En
main
-metod i en annan ny klass som testar metoderna ovan.Exempel på en testkörning av main
-metoden där man slår paret och användertoString
ochisPair
ett upprepat antal gånger:> run PairOfDice {Dice(6, 5), Dice(6, 2)} {Dice(6, 3), Dice(6, 5)} {Dice(6, 2), Dice(6, 6)} {Dice(6, 2), Dice(6, 6)} {Dice(6, 6), Dice(6, 6)} Pair! {Dice(6, 4), Dice(6, 6)} {Dice(6, 1), Dice(6, 3)} {Dice(6, 5), Dice(6, 6)} {Dice(6, 6), Dice(6, 4)} {Dice(6, 3), Dice(6, 3)} Pair! {Dice(6, 3), Dice(6, 4)} {Dice(6, 6), Dice(6, 5)} {Dice(6, 5), Dice(6, 5)} Pair! {Dice(6, 3), Dice(6, 2)} {Dice(6, 5), Dice(6, 1)}
Uppgift 4: Klassen Car (Behöver ej redovisas)
Skapa klassenCar
( i DrJava-menyn). Klistra in skelettkoden som finns här. Fyll i där det står punkter (...). Se main
-metoden som står sist i klassen för tips hur man skriver klassen.
Fråga
Hur många timmar har du hittills arbetat vid dator med just denna lektion?
Gå till nästa lektion eller gå tillbaka
Dölj style3dev.css för att bli av med annoteringarna!