Å lære noe er den største av alle gleder, ikke bare for filosofer, men også
for resten av menneskene, hvor lite deres evne til det enn er.
Aristoteles
set
- og get
-metoderI kapittel 1 ble java karakterisert
som et objektorientert programmeringsspråk. Det ble skrevet at java kan brukes
til å modellere virkeligheten ved å beskrive dens objekter i form av klasser.
Det ble gitt en generell beskrivelse av hvordan en klassedefinisjon ser ut.
I kapittel 2 tok vi for oss noen grunnleggende programelementer og
brukte dem i noen enkle programeksempler. Alle programmene skrev vi i form av
en klasse. Men klassen ble bare brukt som en ramme eller innpakning til
programmet, den hadde ikke som oppgave å gi en modell av noen type objekt.
Alle applikasjonsprogrammer må ha en slik "innpakning" som vi brukte i
programeksemplene i kapittel 2: En klasse som inneholder en
main
-metode. Men det vi vanligvis bruker klasser til i et
javaprogram, og som vi kommer til å gjøre heretter, er nettopp til å modellere
objekter. I dette kapitlet blir det gitt noen innledende eksempler på dette.
Når vi skal skrive et program, vil det ofte være en god hjelp å starte med å lage en skisse av programmet for hånd. Etter hvert som vi får det klarere for oss både hva programmet skal utføre og hva vi må skrive av java-kode for å oppnå det vi ønsker, kan mer og mer av skissen erstattes av java-kode. Når vi er kommet så langt at hele skissen er erstattet av java-kode, kan vi prøve å kompilere og eventuelt kjøre den koden vi har skrevet.
For å skrive skisser, bruker vi det som kalles pseudo-kode. Med pseudo-kode så menes en blanding av java-kode og vanlig språk. Pseudo-kode kan ikke utføres på noen datamaskin, men har bare som hensikt å være til hjelp i utviklingen av et program. For å markere klart hva som er pseudo-kode til forskjell fra rein java-kode, skal vi (vanligvis) bruke en egen skriftfarge for pseudokode. Der det ellers ikke går klart fram av sammenhengen hva som er rein java-kode og hva som er pseudo-kode, skal vi plassere pseudo-kode mellom spissparenteser: < her plasserer vi pseudo-kode >. Spissparentesene er da ikke en del av selve pseudo-koden. De brukes bare til å markere hvor pseudo-koden begynner og slutter.
I kapittel 1 ble den generelle strukturen til en klasse beskrevet. Når vi bruker pseudo-kode, kan vi beskrive strukturen til en klasse på følgende måte:
public class Klassenavn { < datafelter (variable og konstanter) > // for lagring av objektenes data < metoder (operasjoner som skal kunne utføres på objektene som klassen definerer) > }
Vi skal nå bruke denne strukturen på konkrete eksempler.
I læreboka til Deitel & Deitel, 9. utgave, brukes som eksempel en
klasse som er kalt GradeBook
. Klassen skal representere en slags
karakterbok som lærere kan bruke til å holde oversikt over studentenes
prestasjoner i et kurs som de underviser. Vi skal ta for oss eksempler som
er en fornorsket utgave av "karakterbok-klassen" til Deitel & Deitel.
Vi skal kalle klassen for Kursbok
. Denne blir først definert
i en svært enkel versjon, og så blir den etter hvert redefinert i nye versjoner
som blir utstyrt med mer og mer funksjonalitet. I Deitel & Deitels lærebok
har alle de forskjellige versjonene av klassen samme navn: GradeBook
.
Vi skal, for å skille dem fra hverandre, nummerere versjonene med
Kursbok1, Kursbok2, Kursbok3
etc.
I tillegg til den norske tilpasningen av navn og annet innhold, skal vi
endre programmene slik at brukerkommunikasjonen blir foretatt ved hjelp av
dialogbokser, tilsvarende som det
er gjort i programeksemplene i kapittel 2. Slik programmene er skrevet i
Deitel & Deitel, vil all brukerkommunikasjon foregå via konsollvinduet.
Vi skal altså definere en klasse som gir en modell av en kursbok. Av den generelle klassemodellen ovenfor ser vi at vi må definere en klasse som vi i første omgang kan skissere slik (ved bruk av pseudo-kode):
public class Kursbok1 { < Variable for eventuelle data som skal registreres i kursboka > < Definisjon av operasjoner som skal kunne utføres på kursboka > }
I vår første, enkle modell for kursboka skal vi, for enkelhets skyld, ikke kreve at det kan foretas noe registrering av data. Klassen trenger derfor ikke å inneholde noen variable til dette bruk. Den eneste operasjon som skal kunne utføres på kursboka er å vise dens tittel på skjermen. Som tittel kan vi kort og godt bruke "Kursbok". Operasjoner definerer vi i form av det som i java kalles metoder. En metode kan vi tenke på som en navngitt samling av instruksjoner som til sammen skal utføre en bestemt oppgave. I vårt tilfelle trenger vi derfor å definere en metode som inneholder en instruksjon for å vise kursbokas tittel på skjermen. For å kunne definere denne metoden, trenger vi først å vite litt om reglene for å definere metoder. Vi må derfor se litt på disse reglene før vi kan fortsette med eksemplet vårt.
Det er viktig å ha klart for seg skillet mellom det å definere en metode og det å gjøre kall på den (kalle den opp). I definisjonen av en metode skriver vi de instruksjonene som skal utføres når metoden blir kalt opp. Disse instruksjonene blir imidlertid bare utført når metoden blir kalt opp. De blir utført hver gang metoden blir kalt opp, men ellers ikke. Reglene for å gjøre kall på metoder tar vi for oss etter at vi først har sett nærmere på hvordan metoder defineres.
I en metodedefinisjon er det enkelte elementer som det er frivillig å ta med. Men alltid må en metodedefinisjon inneholde følgende deler, uttrykt i pseudokode:
returverditype metodenavn( parameterliste ) { < instruksjon(er) som skal utføres når metoden blir kalt opp > }
Metodenavnet og parameterlista utgjør det som blir kalt metodens signatur. Det er den som identifiserer hvilken metode det dreier seg om. (For å identifisere metoden bruker java dessuten navnet på den klassen som inneholder metodedefinisjonen.) Returverditypen angir datatypen for eventuell verdi som metoden skal returnere når den blir kalt opp. Returverdien kan være av en hvilken som helst datatype. Dersom metoden ikke skal returnere noe, skriver vi nøkkelordet void istedenfor datatype for returverdi. Metodens parameterliste kan være tom eller bestå av en eller flere parametre. Parametrene er variable som brukes inni metoden. For hver parameter må vi angi datatype og navn, med komma mellom hvert slikt par. Parametrene brukes i hovedsak til å gi metoden input når den blir kalt opp, det vil si å 'mate den med verdier'. For metoder som ikke trenger noen input, er parameterlista tom, det vil si metoden har ingen parametre. Men parentesene som omslutter parameterlista er det alltid nødvendig å ta med. Det er de som forteller at det navnet som står foran dem er navnet på en metode.
For øvrig gjelder i java den regel at alle metodedefinisjoner må plasseres i en eller annen klasse.
Vi går nå tilbake til vår klasse Kursbok1
som er skissert
ovenfor. Vi fant ut at vi trengte å definere en metode som når den blir kalt
opp viser kursbokas innhold på skjermen. En instruksjon for dette må derfor
stå inni metoden. Og fra eksemplene i kapittel 2 vet vi hvordan en slik
instruksjon kan se ut. Metoden vår skal ikke utføre noen andre oppgaver og
trenger derfor ikke å inneholde noen andre instruksjoner. Når den blir kalt opp,
trenger den ikke å returnere noen verdi. Som returverditype kan vi derfor bruke
nøkkelordet void. Vi må finne på et navn på metoden vår. Generelt
bør vi i programmene våre bruke det vi kan kalle selvforklarende navn, det vil
si navn som indikerer hvilken rolle det som blir navngitt skal ha i programmet.
I dette tilfellet har metoden som oppgave å vise kursbokas tittel. Et passende
navn på metoden kan derfor være visTittel
. Det er ikke nødvendig
å gi metoden noe input, det vil si tilføre den noe data for at den skal kunne
utføre oppgaven sin, for vi har allerede bestemt oss for at den skal skrive ut
"Kursbok" som tittel på kursboka. Metoden trenger derfor ingen parametre.
Alt i alt kan vi derfor skrive klassen vår Kursbok1
på følgende
måte, med definisjon av metoden visTittel
som eneste innhold:
public class Kursbok1 { public void visTittel() { JOptionPane.showMessageDialog( null, "Kursbok" ); } }
I definisjonen av metoden visTittel
er det, i tillegg til
det som er nevnt ovenfor, lagt inn nøkkelordet public
. En fullgod
forklaring på virkningen av dette har du ikke mulighet til å forstå før du
har lært mer java. Foreløpig kan du oppfatte det som en indikasjon på at
det skal være tillatt for alle å gjøre kall på metoden visTittel
.
Klassen Kursbok1
er i seg selv ikke noe fullstendig
program, og er heller ikke ment å være det. Klassen har som oppgave å definere en bestemt type
objekt. Skal vi ha noen nytte av slike objektdefinisjoner, må vi opprette
objekter av den definerte typen og bruke dem i programmer. Programmer kan vi
lage slik vi lærte det i kapittel 2. Vi skal nå skrive et program som oppretter
et objekt av type Kursbok1
og gjør kall på objektets metode
visTittel
. En skisse for programmet kan vi skrive slik,
uttrykt i pseudo-kode:
public class Kursboktest1 { public static void main( String[] args ) { < Opprett et Kursbok1-objekt > < Gjør kall på objektets visTittel-metode > } }
For å kunne erstatte pseudo-koden med java-kode, trenger vi å vite hvordan vi oppretter objekter og gjør kall på deres metoder. Nedenfor er det forklart hva du trenger å vite om dette i denne omgang.
For å opprette objekter bruker vi nøkkelordet new
sammen med
navnet på klassen som definerer den type objekt som vi vil opprette, samt
et parentespar av vanlig type. (Vi skal seinere se at det mellom parentesene kan
være aktuelt å plassere en eller flere dataverdier.)
For å opprette et Kursbok1
-objekt skriver vi derfor
new Kursbok1()
For å kunne ha noen nytte av slike objekter, trenger vi vanligvis etterpå
å kunne referere til dem. Det kan vi få til ved bruk av variable. Fra kapittel 2
husker vi at når vi deklarerer en variabel, så må vi angi datatypen for
verdiene som vi skal kunne tilordne variabelen. Spørsmålet nå blir derfor hva som er
datatypen til et Kursbok1
-objekt. Her er det faktisk slik at når
vi skriver en klasse, slik vi har gjort med Kursbok1
, så definerer
vi samtidig en ny datatype. Når vi skal referere til et Kursbok1
-objekt,
trenger vi derfor en variabel av type Kursbok1
! Det vanlige er
at samtidig som vi oppretter et objekt ved å bruke nøkkelordet new
,
så bruker vi objektet til å initialisere en variabel av den type som
objektet tilhører. I vårt tilfelle er det derfor aktuelt å skrive slik:
Kursbok1 bok = new Kursbok1();
Som navn på objektet, eller rettere sagt den variabel som refererer til
objektet, er her brukt bok
. Vi kunne selvsagt like godt brukt
et annet navn. Vi bør imidlertid, som nevnt ovenfor, alltid følge regelen om å bruke
selvforklarende navn.
Som nevnt ovenfor, så gjør vi kall på en metode hver gang vi ønsker å få utført
de instruksjonene som vedkommende metode inneholder. Hva som må skrives av
kode for å gjøre et metodekall, avhenger både av hvordan metoden er definert
og hvor kallet skjer. Vi skal ta for oss de forskjellige situasjonene etter hvert som vi får bruk
for dem. For øyeblikket har vi følgende situasjon:
Vi skal gjøre kall på
metoden visTittel
, definert i klassen Kursbok1
, og
kallet skal skje utenfor denne klassen.
For å gjøre kallet, trenger vi da et objekt av type Kursbok1
.
Når vi har opprettet objektet bok
, slik det er gjort ovenfor, kan vi
skrive kallet slik:
bok.visTittel();
Denne instruksjonen kan vi lese som
"bok
sin visTittel
". Når vi bruker et objekt
til å gjøre kall på en av objektets metoder, slik vi har gjort her,
brukes også uttrykksmåten at vi
"sender en melding" til objektet. Vi kan tenke på det som at vi gir objektet
ordre om å utføre en handling, nærmere bestemt utføre instruksjonene i den
metoden som vi spesifiserer.
Vi vet nå hvordan vi skal erstatte pseudo-koden i skissen ovenfor med
rein java-kode og kan
derfor skrive programmet vårt Kursboktest1
på følgende måte:
public class Kursboktest1 { public static void main( String[] args ) { // Oppretter et Kursbok1-objekt: Kursbok1 bok = new Kursbok1(); // Gjør kall på objektets visTittel-metode: bok.visTittel(); } }
Skriv inn klassene Kursbok1
og
Kursboktest1
i TextPad.
I java-fila for Kursbok1
må du importere klassen
JOptionPane
, slik det er gjort i programeksemplene i kapittel 2,
siden den brukes av metoden visTittel
.
Dersom du ikke vil skrive filene selv (det kan for treningens skyld være
lurt å gjøre det), kan du laste dem ned ved å klikke på følgende linker:
Kursbok1.java,
Kursboktest1.java.
For å kjøre programmet, må du kjøre fila Kursboktest1.java
,
siden det er den som inneholder programmets main
-metode.
Når du kjører det, skal du få fram følgende meldingsboks på skjermen:
I programeksemplet ovenfor opprettet vi ett eneste objekt av type
Kursbok1
. Men det er ikke noe i veien for at vi kan opprette
flere objekter av denne typen, faktisk så mange objekter som vi bare vil.
Hver gang vi bruker nøkkelordet new
slik vi har gjort ovenfor,
blir det opprettet et nytt objekt. Vi tenker oss nå at en lærer underviser to
forskjellige kurs, og at læreren ønsker å opprette en kursbok for hvert kurs.
For å kunne holde kursbøkene fra hverandre, er det da ønskelig at den tittel
som skrives ut ikke bare består av navnet "Kursbok", men i tillegg inneholder
navnet på det kurset som det er kursbok for. Metoden visTittel
trenger da å vite hvilket kursnavn den skal skrive ut. Dessuten må den kunne
skrive ut forskjellig kursnavn, avhengig av hvilket kurs vedkommende
kursbokobjekt er kursbok for. Vi har derfor behov for å informere
visTittel
-metoden om hvilket kursnavn den skal skrive ut når den
blir kalt opp. Informasjon til metoder kan vi få gitt ved å bruke parametre.
I den generelle beskrivelsen av en metodedefinisjon som ble gitt
ovenfor, står det nettopp at det skal være en parameterliste.
Når vi ikke har behov for parametre, er parameterlista tom. Det var tilfelle
for vår visTittel
-metode definert ovenfor. Nå skal vi definere
en ny versjon av denne metoden. Den skal ha en parameter som inneholder
navnet på det kurset som klassen vår definerer kursbok for. Når vi endrer
egenskapene til en metode, endrer vi også egenskapene til den klassen som
metoden ligger i. Det er derfor grunn til å gi klassen et nytt navn.
(Vi skal seinere se at vi innenfor én og samme klasse kan definere
flere versjoner av én og samme metode, der versjonene skiller seg
fra hverandre ved at parameterlista er forskjellig, mens metodenavnet er felles.
Men nå foreløpig definerer vi isteden en ny klasse.)
Vi skal kalle den nye klassen Kursbok2
og kan definere den på følgende måte:
public class Kursbok2 { public void visTittel( String kursnavn ) { JOptionPane.showMessageDialog( null, "Kursbok for " + kursnavn ); } }
Legg merke til at vi i utskriftsinstruksjonen refererer til metodeparameteren
kursnavn
.
Husk at instruksjonene som står i en metode ikke blir utført uten at
vi gjør kall på metoden. Vi skal nå lage et program som oppretter et objekt
av type Kursbok2
, leser inn kursnavn fra brukeren, og viser
på skjermen hvilket kurs vi nå har opprettet kursbok for. Det vil da bli forklart
hvordan vi gjør kall på vår nye visTittel
-metode og hvordan
metodens parameter virker.
Vi kan lage følgende skisse for det nye programmet vårt:
public class Kursboktest2 { public static void main( String[] args ) { Kursbok2 bok = new Kursbok2(); < Les inn kursnavn > < Vis hvilket kurs det er opprettet kursbok for > } }
Innlesing av kursnavn kan vi gjøre på tilsvarende måte som vi gjorde i programeksempel 3 i kapittel 2, ved at vi skriver
String navn = JOptionPane.showInputDialog( "Skriv kursnavn:" );
Vi ønsker nå å gjøre kall på visTittel
-metoden til
Kursbok2
-objektet bok
på en slik måte at metoden
bruker det innleste navnet i sin utskrift av kurstittel. Dette får vi til ved
at vi skriver følgende metodekall:
bok.visTittel( navn );
Vi ser at navn
her er den String
-variabel som
vi brukte for å lagre det innleste kursnavnet. Når vi bruker variabelen som
parameter i kallet på metoden visTittel
, slik det er gjort ovenfor,
sier vi at navn
er aktuell parameter i metodekallet.
Definisjonen av metoden visTittel
, som står ovenfor, så
ut slik:
public void visTittel( String kursnavn ) { JOptionPane.showMessageDialog( null, "Kursbok for " + kursnavn ); }
I denne definisjonen kaller vi kursnavn
for en
formell parameter. Når vi gjør kall på metoden, må vi istedenfor den
formelle parameteren bruke en aktuell parameter av samme datatype som den
formelle. (Men legg merke til at i kallet spesifiserer vi ikke datatypen for den aktuelle parameteren,
slik vi gjør for den formelle parameteren i metodedefinisjonen.)
Den aktuelle parameteren kan enten være en konkret dataverdi av
vedkommende datatype, eller det kan være, slik som her, en variabel av vedkommende
datatype. Denne variabelen må da på forhånd ha blitt tilordnet en verdi (av
riktig datatype). I begge tilfeller virker kallet på følgende måte:
Verdien til den aktuelle parameter blir tilordnet som verdi til den variabel
som er formell parameter. Denne verdien brukes når metoden utfører sine
instruksjoner. Resultatet blir derfor at vi via parameteren får tilført metoden
en verdi utenfra. Den tilførte verdien kan selvsagt være forskjellig fra gang
til gang som vi gjør kall på metoden.
Når det gjelder navnene til den formelle parameter og den variabel som
eventuelt brukes som aktuell parameter, så er disse uavhengige av hverandre.
I eksemplet ovenfor er det brukt forskjellige navn (kursnavn
og
navn
). Men det er også tillatt å bruke samme navn. Det avgjørende
er at den aktuelle parameter er av samme datatype som den formelle parameter.
På grunnlag av det vi nå vet, kan vi erstatte programskissen ovenfor med følgende java-kode:
public class Kursboktest2 { public static void main( String[] args ) { Kursbok2 bok = new Kursbok2(); // Leser inn kursnavn: String navn = JOptionPane.showInputDialog( "Skriv kursnavn:" ); // Viser hvilket kurs vi har opprettet kursbok for: bok.visTittel( navn ); } }
I vedkommende java-fil må vi dessuten importere klassen
JOptionPane
. De to bildene nedenfor viser et eksempel på de
dialogboksene vi får når vi kjører programmet og bruker
Programmering
som kursnavn.
Legg inn klassene Kursbok2
og Kursboktest2
i
TextPad.
Du kan få lastet ned filer med de to klassene ved å klikke på følgende linker:
Kursbok2.java,
Kursboktest2.java.
Kjør programmet gjentatte ganger med innlesing av forskjellige kursnavn.
set
- og get
-metoderDe kursbokobjektene vi har definert og opprettet hittil kan ikke være av særlig stor nytte, for det er ikke mulig å lagre noen data i dem. Dette skal vi rette på nå. I første omgang skal vi ta sikte på å lagre selve kursnavnet. Hva som kreves for at objekter skal kunne lagre data er allerede antydet i den skisse som først ble skrevet for kursbokklassen i eksempel 1 ovenfor. De variable som en klasse har for lagring av objektenes data, kan vi kalle klassens datafelter. Det er også vanlig å omtale disse som klassens attributter, mens metodene kalles klassens operasjoner. Som betegnelse for datafeltene brukes også uttrykkene objektvariable og instansvariable, siden et objekt også blir kalt for en instans av vedkommende klasse.
Av nevnte skisse ser vi at vi i vårt tilfelle må utstyre klassen med en variabel som kan inneholde
kursnavnet, det vil si en variabel av type String
. Vi skal også
gjøre noen andre endringer. Hensikten med disse blir forklart nedenfor.
Den nye versjonen av kursbokklassen ser ut som følger:
public class Kursbok3 { private String kursnavn; public void setKursnavn( String navn ) { kursnavn = navn; } public String getKursnavn() { return kursnavn; } public void visTittel() { JOptionPane.showMessageDialog( null, "Kursbok for " + kursnavn ); } }
Variabelen kursnavn
skal altså brukes til å lagre navnet på
kurset som klassen definerer kursbok for. Vi legger merke til at det forrest
i deklarasjonen av denne variabelen står nøkkelordet private
.
Dette har som virkning at variabelen bare vil være tilgjengelig inni klassen
Kursbok3
, det vil si at det bare er der det er mulig å referere
til den slik at vi kan tilordne den en verdi, eller se hvilken verdi den har.
Vi skal imidlertid, som i eksempel 2 ovenfor, bruke et kursbokobjekt i et
program som leser inn kursnavn. Vi vil da være utenfor klassen Kursbok3
.
Spørsmålet blir dermed hvordan vi skal få
overført det innleste navnet til objektet vårt. Det kan vi få gjort ved å
gjøre kall på den nye metoden setKursnavn
, med det innleste navnet
som aktuell parameter. For den metoden overfører til datafeltet
kursnavn
den verdi som dens parameter navn
har når
metoden blir kalt opp. Dersom vi har et kursbokobjekt og vil se på hvilket
kursnavn det inneholder, kan vi gjøre kall på dets metode getKursnavn
.
For den vil returnere verdien til datafeltet kursnavn
til det stedet
der metoden blir kalt opp. For å returnere en verdi fra en metode, bruker vi
nøkkelordet return
. Det har som virkning å avslutte hele metoden,
samtidig som verdien av uttrykket bak return
blir returnert til det
stedet der metoden blir kalt opp. Datatypen for dette uttrykket må angis
som returverditype foran metodenavnet, i dette tilfellet er det datatypen
String
.
Det er vanlig praksis å gi klassenes datafelter såkalt
private
aksess, slik vi har gjort ovenfor. Hvorfor dette er viktig
vil du få mer klart for deg etter hvert som vi tar for oss eksempler som
er bedre egnet til å begrunne det. Alltid når vi har datafelter som har
private
aksess, vil det være behov for å ha såkalte
get
-metoder, tilsvarende som vi har for kursnavn
, for å kunne
lese av deres verdier utenfor klassen. Og dersom det er behov for å endre
deres verdier når vi er utenfor klassen, så behøves tilsvarende
set
-metoder som vi har for kursnavn
. En
set
-metode må ha en parameter av samme datatype som det datafelt
den skal gi verdi til. En get
-metode derimot, trenger ingen parameter.
Du kan legge merke til at visTittel
-metoden er
endret i den nye versjonen av kursbokklassen. Kursnavnet blir nå lagret i et
datafelt i klassen. Metoden kan derfor hente navnet derfra når den skal skrive
ut tittel, den trenger ikke å motta navnet som parameter, slik det ble gjort
i forrige versjon av klassen. Vi kunne også ha definert metoden
visTittel
på følgende måte:
public void visTittel() { JOptionPane.showMessageDialog( null, "Kursbok for " + getKursnavn() ); }
Her gjøres det kall på metoden getKursnavn
for å hente
kursnavnet. Men siden metoden visTittel
blir definert inni klassen
Kursbok3
, kan vi referere direkte til alle klassens datafelter
for å få tak i deres verdier, uavhengig av om de har private
aksess eller ikke. Det vil være mer effektivt enn å gjøre kall på
get
-metoder for å hente deres verdier. Legg for øvrig merke til
at når vi gjør kall på en metode innenfor samme klasse som metoden er definert,
trenger vi ikke noe objekt etterfulgt av punktum for å gjøre kall på metoden.
***
Vi skal nå teste ut det nye kursbokobjektet i følgende program.
1 import javax.swing.JOptionPane; 2 3 public class Kursboktest3 4 { 5 public static void main( String[] args ) 6 { 7 Kursbok3 bok = new Kursbok3(); // oppretter objekt 8 9 // Viser opprinnelig verdi til datafeltet kursnavn: 10 JOptionPane.showMessageDialog( null, "Opprinnelig kursnavn: " + 11 bok.getKursnavn() ); 12 13 // Leser inn kursnavn: 14 String navn = JOptionPane.showInputDialog( "Skriv kursnavn:" ); 15 bok.setKursnavn( navn ); // lagrer innlest navn i objektet 16 17 // Viser den nye verdien til datafeltet kursnavn: 18 JOptionPane.showMessageDialog( null, "Registrert kursnavn: " + 19 bok.getKursnavn() ); 20 // Skriver ut tittel med kursnavn: 21 bok.visTittel(); 22 } 23 }
En kjøring av programmet med innlesing av Programmering
som
kursnavn gir følgende dialogbokser:
Dialogboksen viser resultatet av å hente ut verdien til datafeltet
kursnavn
før vi har gitt det noen verdi. Vi ser at det har
verdien null
.
Innlesing av Programmering
som kursnavn.
Viser verdien som datafeltet kursnavn
nå har fått.
Resultat av kall på metode visTittel
.
Legg inn klassene Kursbok3
og Kurstest3
i TextPad.
Du kan få lastet ned filer med de to klassene ved å klikke på følgende linker:
Kursbok3.java,
Kursboktest3.java.
Kjør programmet gjentatte ganger med innlesing av forskjellige kursnavn.
Vi har sett at når vi tar i bruk en variabel i et program, så må vi
spesifisere en datatype for variabelens verdier. Vi har brukt numeriske
variable av datatypene int
og
double
. I forbindelse
med logiske uttrykk i kapittel 2 ble det nevnt
at vi kan kan ha
logiske variable, av datatype boolean
. For tekst har vi brukt
variable av datatype String
. I programmene i dette kapitlet har
vi brukt variable av de egendefinerte datatypene Kursbok1, Kursbok2
og Kursbok3
. Det er en svært viktig forskjell mellom datatypene
int, double, boolean
og
de andre som er nevnt. Datatypene
int, double, boolean
kalles
primitive datatyper.
En variabel av primitiv datatype kan bare lagre én enkelt dataverdi.
Vi kan oppfatte vedkommende variabel som et navn på den lagrete verdien.
(I tillegg til de nevnte, har vi i javaspråket de primitive datatypene
byte, char, short, long
og
float
. Disse kommer vi
tilbake til etter hvert som vi får bruk for dem.) Alle andre datatyper
som brukes i et javaprogram er definert i form av en klasse, tilsvarende som
vi har gjort med datatypene Kursbok1, Kursbok2
og Kursbok3
i dette kapitlet. (String
er også
definert i form av en klasse. Den finnes i javas klassebibliotek, sammen med
et stort antall andre typer som også er definert i form av klasser.)
Slike datatyper kalles med et fellesnavn for referansetyper eller klassetyper.
En variabel av en slik type kalles en referanse eller en
peker. Grunnen til denne navnebruken er at klassene definerer objekter.
Objekter oppretter vi ved bruk av nøkkelordet new
, slik som vi har
gjort for eksempel i instruksjonen
Kursbok3 bok = new Kursbok3();
Virkningen av dette er at det i maskinens hurtiglager (memory) blir
reservert plass til et nytt objekt av den spesifiserte typen, i dette tilfelle
type Kursbok3
.
Nøkkelordet new
er egentlig en
operator. En operator er noe som
returnerer en verdi. Den returnerte verdien fra new
-operatoren
er en referanse til det stedet i maskinens memory der det nyopprettede objektet
ligger lagret. Denne referansen blir
gitt som verdi til vedkommende variabel, i dette tilfelle variabelen
bok
. Vi sier derfor at denne refererer til eller
peker på objektet, og selve variabelen kaller vi altså en referanse
eller en peker. (Vi kan også tenke på referansen som selve memory-adressen til
objektet.)
Objektet som blir opprettet kan i seg selv inneholde mange dataverdier, like mange som det er antall datafelter i klassen som definerer objektet. Pekeren til objektet vil ikke være navn på noen av disse dataverdiene, den bare refererer til objektet som inneholder dataverdiene.
Når vi oppretter et nytt objekt ved å bruke new
-operatoren,
vil alle datafeltene i klassen som definerer objektet automatisk bli tildelt
startverdier. Dersom det i vedkommende klasse ikke er noen egne instruksjoner
for tildeling av startverdi, blir datafeltene tildelt standardverdier. For
numeriske variable er dette tallverdien 0 (eller 0.0, i tilfelle variabel for
desimaltall). For logiske variable (datatype boolean
) er det
verdien false
, og for alle referansevariable (med datatype definert
i form av en klasse) er det verdien null
, som også er et nøkkelord
i java-språket. Verdien null
indikerer at vedkommende peker ikke
refererer til noe objekt. Ønsker vi å tildele datafeltene andre startverdier
enn de nevnte standardverdiene, har vi flere muligheter for å gjøre det.
En mulighet er å initialisere vedkommende datafelt samtidig som vi deklarerer det.
I klassen Kursbok3
kunne vi for eksempel ha initialisert
datafeltet kursnavn
med verdien "foreløpig uten navn" ved at vi
hadde skrevet klassedefinisjonen slik (uttrykt i pseudo-kode):
public class Kursbok3 { private String kursnavn = "foreløpig uten navn"; < Resten av klassedefinisjonen som før > }
En annen mulighet er å definere en eller flere såkalte konstruktører for
å initialisere datafelter (det vil si tildele dem startverdier). En konstruktør
er kjennetegnet ved at den har samme navn som klassen, samt en parameterliste
mellom vanlige parenteser, tilsvarende som vi har i en metodedefinisjon.
Som i en slik, kan parameterlista være tom. Men i motsetning til en
metodedefinisjon, skal det ikke i en konstruktør være angivelse av noen
returverditype, heller ikke void
.
Nøkkelordet public
er imidlertid (vanligvis) nødvendig. Parametrene kan brukes til å
overføre startverdier til datafelter, på tilsvarende måte som vi gjorde i
Kursbok3
-klassens setKursnavn
-metode. I den
nye versjonen Kursbok4
av kursbokklassen vår, som følger nedenfor
i eksempel 4, er det en
konstruktør som initialiserer kursnavnet på den nevnte måten. En konstruktør
blir utført hver gang vi bruker new
-operatoren, ellers ikke.
Konstruktørens instruksjoner vil da bli utført, i tillegg til at det
reserveres plass til det nye objektet som blir opprettet. Dersom konstruktøren
har parametre, må vi, som i tilfelle metodekall, for hver formell parameter i
konstruktørens definisjon ha en tilsvarende aktuell parameter av riktig datatype
når vi bruker new
-operatoren for å opprette et objekt.
En konstruktør uten parametre blir kalt for default-konstruktøren
til vedkommende klasse. Dersom klassedefinisjonen ikke inneholder noen
konstruktør-definisjon, vil java-systemet automatisk opprette en slik
default-konstruktør når vi bruker new
-operatoren for å opprette
et objekt. Default-konstruktøren vil da initialisere datafeltene med
standardverdier. Det var dette som skjedde i programmet Kursboktest3
ovenfor. Men vi har altså mulighet til selv å definere en default-konstruktør
med annen virkemåte, eller definere en konstruktør med en eller flere parametre.
(Som vi skal se seinere, kan vi for én og samme klasse definere flere
forskjellige konstruktører, med forskjellige parameterlister, slik at det er
mulig å velge mellom flere måter å initialisere objekter på.)
Klassen Kursbok4
er utstyrt med en konstruktør som initialiserer
datafeltet kursnavn
via en konstruktørparameter.
1 import javax.swing.JOptionPane; 2 3 public class Kursbok4 4 { 5 private String kursnavn; 6 7 // Konstruktør som initialiserer datafeltet kursnavn. 8 public Kursbok4( String n ) 9 { 10 kursnavn = n; 11 } 12 13 public void setKursnavn( String navn ) 14 { 15 kursnavn = navn; 16 } 17 18 public String getKursnavn() 19 { 20 return kursnavn; 21 } 22 23 public void visTittel() 24 { 25 JOptionPane.showMessageDialog( null, "Kursbok for " + kursnavn ); 26 } 27 }
Programmet Kursboktest4
som er gjengitt nedenfor deklarerer
to objekter av type Kursbok4
. Kursnavn for den første kursboka blir
innlest fra brukeren. Det innleste navn blir via konstruktørparameter overført
til det objekt som blir opprettet. Programmet spør deretter brukeren om han/hun
ønsker å opprette en kursbok til. Til dette brukes instruksjonen
int svar = JOptionPane.showOptionDialog( null, "Vil du opprette en kursbok til?", "Opprette flere kursbøker?", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, null, null );
Vi ser at det her står en tilordningsinstruksjon. Vi vet at det da er høyre side av denne som utføres først. Det er metodekallet
JOptionPane.showOptionDialog( null, "Vil du opprette en kursbok til?", "Opprette flere kursbøker?", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, null, null );
Det resulterer i at følgende dialogboks vises på skjermen:
Det er her selvsagt meningen at brukeren skal klikke på Yes- eller
No-knappen for å svare på spørsmålet som stilles. Det er også tillatt for
brukeren å klikke på dialogboksens lukkeknapp. Klikk på en av de tre nevnte
knapper vil resultere i at boksen lukker seg og til kallstedet vil det bli
returnert en int
-verdi som er en av følgende forhåndsdefinerte
konstanter, avhengig av hvilken knapp det ble klikket på:
JOptionPane.YES_OPTION, JOptionPane.NO_OPTION, JOptionPane.CLOSED_OPTION
.
Den returnerte verdien blir tilordnet som verdi til int
-variabelen
svar
.
Vi ønsker at programmet skal virke på den måten at dersom det ble klikket på
Yes-knappen, så skal
programmet opprette en kursbok til, ellers ikke. For å oppnå dette, skriver
vi derfor instruksjonen
if ( svar == JOptionPane.YES_OPTION ) { // Leser inn kursnavn: navn = JOptionPane.showInputDialog("Skriv kursnavn:"); bok2 = new Kursbok4(navn); }
Til slutt skriver programmet ut en melding
om hvilke fag det er opprettet kursbøker for. Innholdet av fila
Kursboktest4.java
er gjengitt nedenfor.
1 import javax.swing.JOptionPane; 2 3 public class Kursboktest4 4 { 5 public static void main( String[] args ) 6 { 7 Kursbok4 bok1 = null, bok2 = null; 8 // Leser inn et kursnavn: 9 String navn = JOptionPane.showInputDialog( "Skriv kursnavn:" ); 10 11 bok1 = new Kursbok4( navn ); // oppretter objekt med innlest kursnavn 12 13 int svar = JOptionPane.showOptionDialog( null, 14 "Vil du opprette en kursbok til?", 15 "Opprette flere kursbøker?", JOptionPane.YES_NO_OPTION, 16 JOptionPane.QUESTION_MESSAGE, null, null, null ); 17 18 if ( svar == JOptionPane.YES_OPTION ) 19 { 20 // Leser inn kursnavn: 21 navn = JOptionPane.showInputDialog("Skriv kursnavn:"); 22 bok2 = new Kursbok4(navn); 23 } 24 25 // Viser kursnavn for opprettede kursbøker: 26 String info = "Har opprettet kursbøker for følgende fag:\n"; 27 info = info + bok1.getKursnavn(); 28 if ( bok2 != null ) 29 info = info + "\n" + bok2.getKursnavn(); 30 31 JOptionPane.showMessageDialog( null, info, "Registrert kursnavn", 32 JOptionPane.PLAIN_MESSAGE ); 33 } 34 }
Nedenfor blir det vist dialogbokser fra en kjøring av programmet, der det ble klikket på Yes-knappen i Ja-nei-dialogboksen.
Legg inn klassene Kursbok4
og Kursboktest4
i TextPad.
Du kan få lastet ned filer med de to klassene ved å klikke på følgende linker:
Kursbok4.java,
Kursboktest4.java.
Kjør programmet gjentatte ganger med innlesing av forskjellige kursnavn og
med vekslende bruk av de tre knappene i Ja-nei-dialogboksen.
Copyright © Kjetil Grønning og Eva Hadler Vihovde, revidert 2014