90
Grunnkurs i objektorientert programmering Hjelpehefte for studenter som tar INF101, Institutt for informatikk, Universitetet i Oslo Oslo, 15. august 2001

Grunnkurs i objektorientert programmering - folk.uio.nofolk.uio.no/inf101/Hjelpehefte-farge-150801.pdf · Noen har sikkert også programmert en kalkulator ved å få kalkulatoren

Embed Size (px)

Citation preview

Grunnkurs i objektorientert

programmering

Hjelpehefte for studenter som tar INF101,

Institutt for informatikk, Universitetet i Oslo

Oslo, 15. august 2001

2

3

Innhold Forord......................................................................................................................................... 5 Kapittel 1 - Hva er programmering? .......................................................................................... 7

Å kommunisere med en datamaskin ...................................................................................... 8 Programmeringsspråk............................................................................................................. 9 Mer informasjon..................................................................................................................... 9

Kapittel 2 - Mitt første javaprogram......................................................................................... 11 Kompilering og kjøring........................................................................................................ 12 Kommentarer........................................................................................................................ 12 Formatering .......................................................................................................................... 13

Kapittel 3 - Variabler og tilordninger ....................................................................................... 15 Hva er en variabel?............................................................................................................... 15 Deklarasjoner og tilordninger............................................................................................... 15 Variabeltyper ........................................................................................................................ 17 Mer om identifikatorer ......................................................................................................... 17

Kapittel 4 - Kontrollsetninger................................................................................................... 19 Booleske uttrykk................................................................................................................... 19 If-setninger ........................................................................................................................... 20 While-setninger .................................................................................................................... 21 For-setninger ........................................................................................................................ 22 do while-setninger ................................................................................................................ 23 Switch-setninger ................................................................................................................... 23

Kapittel 5 - Objekter og klasser................................................................................................ 25 Objekter ................................................................................................................................ 25 Klasser.................................................................................................................................. 25 Referanser (pekere) .............................................................................................................. 26 Klasse/objekt-diagrammer.................................................................................................... 27 Bruk av static........................................................................................................................ 28

Kapittel 6 - Innlesing fra tastatur .............................................................................................. 31 Hvordan lese fra tastatur ....................................................................................................... 31 Inn-klassen............................................................................................................................ 32

Kapittel 7 - Metoder ................................................................................................................. 35 Hvordan bruke metoder........................................................................................................ 35 Hvorfor bruke metoder......................................................................................................... 35 Enkle metoder....................................................................................................................... 36

Kapittel 8 - Arrayer og hashtabeller ......................................................................................... 37 Hva er en array? ................................................................................................................... 37 Hvordan lage en array .......................................................................................................... 37 Hvordan bruker vi en array .................................................................................................. 37 Hvordan gå gjennom en array .............................................................................................. 38 Et eksempel .......................................................................................................................... 38 En spesiell array ................................................................................................................... 39 Arrayer med referanser......................................................................................................... 40 Todimensjonal array............................................................................................................. 41 Hva er en hashtabell? ........................................................................................................... 42 Hvordan bruke en hashtabell................................................................................................ 42 Hvordan gå gjennom alle elementer i en hashtabell (Iterator) ............................................. 44 Et stort eksempel .................................................................................................................. 44

4

Valg mellom bruk av array eller hashtabell ......................................................................... 46 Kapittel 9 – Klasse/objekt-diagrammer.................................................................................... 47 Kapittel 10 - Filbehandling – Inn- og Ut-klassene ................................................................... 51

Skrive til fil........................................................................................................................... 51 Formatering av tall for utskrift ............................................................................................. 52 Lese fra fil ............................................................................................................................ 53 Teste om slutten av filen er nådd.......................................................................................... 53 Om filstruktur ....................................................................................................................... 54 Array og filer ........................................................................................................................ 54 Hashtabell og filer ................................................................................................................ 54

Kapittel 11 - Unntak (exceptions) ............................................................................................ 55 Sende unntaket videre .......................................................................................................... 55 Fange unntaket ..................................................................................................................... 56 Mer enn ett unntak................................................................................................................ 56 Exceptions kompilatoren oppdager ...................................................................................... 57 Exceptions under kjøring...................................................................................................... 58 Inn- og Ut-klassen ................................................................................................................ 58

Kapittel 12 - Mer om metoder.................................................................................................. 59 Hva er parametre? ................................................................................................................ 59 Returverdier.......................................................................................................................... 60 Eksempel på bruk av metoder .............................................................................................. 61 Konstruktører........................................................................................................................ 62 Om public og private ............................................................................................................ 63

Kapittel 13 - Subklasser ........................................................................................................... 65 Hva er subklasser?................................................................................................................ 65 Hvordan lage subklasser....................................................................................................... 65 Referanser og typekonvertering ........................................................................................... 65 Alle klasser er subklasser ..................................................................................................... 67 Hvorfor bruke subklasser ..................................................................................................... 67 Eksempel på bruk av subklasser........................................................................................... 68 Hvordan tegne subklasser..................................................................................................... 69 Feil å unngå .......................................................................................................................... 69 Subklasser og filer ................................................................................................................ 70 Hva slags objekt har vi (instanceof) ..................................................................................... 70

Kapittel 14 - Tekststrenger ....................................................................................................... 73 Hva er strenger?.................................................................................................................... 73 Hvordan bruke strenger ........................................................................................................ 73 Hvordan tegne strenger ........................................................................................................ 73 Operasjoner på strenger ........................................................................................................ 73 Et eksempel .......................................................................................................................... 75

Kapittel 15 - Bruk av Java-pakker og dokumentasjon............................................................. 77 Hva er en pakke og ’import’ ................................................................................................. 77 Bruk av dokumentasjonen.................................................................................................... 78 Hvordan få tak i klassene ’Inn’ og ’Ut’, og classpath.......................................................... 79 Hvordan få tak i klassene ’Inn’ og ’Ut’, og classpath.......................................................... 80

Appendix A: Klassen Inn ......................................................................................................... 81 Appendix B: Klassen Ut........................................................................................................... 87

5

Forord Velkommen til INF101 - grunnkurset i objektorientert programmering ved Institutt for Informatikk ved Universitetet i Oslo. I løpet av kurset skal du lære om programmering, og det programmeringsspråket vi kommer til å benytte oss av heter Java. Hensikten med dette heftet er å gi en kortfattet innføring i endel sentrale begreper i kurset, samt å vise gjennom en rekke eksempler hvordan man kan gjøre ting i Java. Heftet kan forhåpentlig også fungere som et oppslagsverk for endel av de viktigste elementene i Java som undervises i kurset. Heftet er imidlertid ikke ment å være noen fullstendig lærebok, og dekker ikke alle sider av pensum. Det programmeringsspråket vi benytter i kurset - Java 1.3 - kan brukes på alle datamaskinene vi benytter her ved instituttet og kan dessuten installeres på enhver PC (Java 1.3 ligger på Ifi-CD'en som deles ut til alle fjernundervisningsstudentene og som øvrige INF101-studenter kan få på forespørsel; du kan også hente Java 1.3 over nettet fra http://www.javasoft.com/j2se/1.3/). De første versjonene av dette hjelpeheftet ble skrevet av Anders Brunland og Steinar Eliassen som et hjelpemiddel i et tidligere kurs i objektorientert programmering. Det er siden foretatt en omfattende restrukturering og revidering av teksten og nye avsnitt er føyet til. Ferdig blir vi aldri, og kommentarer mottas med takk. Kommentarer kan sendes til epostadressen: [email protected]. August, 2001 Knut Hegna, Arne Maus, Ole Christian Lingjærde

6

7

Kapittel 1 - Hva er programmering? INF101 er et kurs i objektorientert programmering. Et program er et instruksjonssett (en oppskrift) som forteller en datamaskin hva den skal gjøre. Å programmere vil si å lage slike instruksjonssett for å få datamaskinen til å løse oppgaver for oss. Å programmere er noe de fleste av oss gjør fra tid til annen nesten uten å tenke over det, f.eks. når man programmerer en videospiller til å ta opp et bestemt tv-program neste dag, eller når man programmerer en vekkerklokke til å ringe en bestemt tid neste morgen. Noen har sikkert også programmert en kalkulator ved å få kalkulatoren til å huske en hel sekvens av tastetrykk, slik at man senere kan få utført alle tastetrykkene bare ved å trykke på en enkelt knapp. De programmene du skal lære å lage i INF101 skiller seg fra disse eksemplene ved at de ikke skal utføres av f.eks. en videospiller eller en vekkerklokke - de skal istedet utføres av en PC eller liknende (f.eks. en arbeidsstasjon, slik de fleste av maskinene på Institutt for Informatikk er). En PC eller en arbeidsstasjon består typisk av fire komponenter: en skjerm, selve maskinen (en boks som står under eller ved siden av skjermen), et tastatur og et redskap for å peke på skjermen (en "mus"). Ofte refererer vi til alle komponentene under ett som en datamaskin eller (av historiske årsaker) en terminal. Den siste betegnelsen skyldes at datamaskiner veldig ofte er knyttet sammen i store nettverk (dette gjelder også datamaskinene ved Institutt for Informatikk), og da danner hver enkelt datamaskin et endepunkt eller et terminalpunkt i dette nettverket. Personen som bruker datamaskinen kalles ofte brukeren. Det er lett å forstå hvorfor man skal programmere en videospiller (for å ta opp et program) eller en vekkerklokke (for å bli vekket). Men hva kan vi få en datamaskin til å gjøre for oss (det er jo f.eks. ikke særlig praktisk å bruke en datamaskin som vekkerklokke)? Noen eksempler på bruk er å programmere datamaskinen slik at den kan brukes

• som en avansert skrivemaskin (tekstbehandlingsprogram) • som en avansert kalkulator (regnearkprogram) • til å surfe på internett (nettleserprogram = web browser) • for å holde orden på flyavganger og passasjerer (til bruk for et flyselskap) • for å holde orden på kinoforestillinger og solgte/reserverte billetter • for å holde orden på vareutvalg, varebeholdning og priser i en butikk • for å beregne været imorgen (til bruk for meteorologer)

8

I løpet av kurset skal du lære nok om programmering til at du kan gå løs på mange av problemene i listen ovenfor (men mange av problemene forutsetter at du også kan mye annet - f.eks. må du kunne endel om meteorologi for å være i stand til å lage et program som beregner været imorgen med noenlunde presisjon og pålitelighet). Men i virkeligheten vil et godt program for å beregne været imorgen eller for å surfe på internett være mye større enn det vi har mulighet til å rekke i løpet av kurset, og derfor kommer vi i stor utstrekning til å se på problemer av enklere natur eller grove forenklinger av noen av problemene i listen ovenfor. Et eksempel på et veldig enkelt problem er å programmere datamaskinen slik at den

• skriver ut på skjermen følgende: "jeg er et javaprogram". Hvordan programmerer vi datamaskinen til å gjøre noe slikt (ønsker du svaret med en gang kan du gå til kapittel 2)? Vi kunne prøve å skrive setningen ovenfor på tastaturet og håpe det beste, men da oppdager vi fort at datamaskinen ikke forstår norsk (eller andre naturlige språk for den saks skyld). Vi er nødt til å formulere oss i et språk som datamaskinen behersker.

Å kommunisere med en datamaskin For å kunne gjøre noe som helst nyttig med en datamaskin er vi nødt til å kommunisere med den, og en vanlig måte å gjøre dette på er å bruke

• tastaturet og musen når vi skal fortelle datamaskinen noe • skjermen når datamaskinen skal fortelle oss noe

I tillegg er det ofte mulig å kommunisere med en datamaskin via et nettverk, f.eks. via internett, men det ser vi bort fra her. Hvordan kommuniserer vi så med datamaskinen ved hjelp av tastaturet og musen? Hvilke ord og tastetrykk forstår datamaskinen? Faktisk er det ikke noe entydig svar på det - det kommer helt an på hvilket program som kjører på datamaskinen, for:

Når vi kommuniserer med datamaskinen så skjer det alltid via et program som kjører på datamaskinen, og det er dette programmet som bestemmer hvilke tastetrykk og musebevegelser som er meningsfylte og hvilken mening de skal ha.

En datamaskin inneholder vanligvis mange (tusenvis av) forskjellige programmer, og vanligvis er det flere av disse som kjører samtidig. Et program som alltid kjører når datamaskinen er på, er det såkalte operativsystemet. På de fleste maskinene ved Institutt for Informatikk heter dette operativsystem-programmet Unix, mens de fleste hjemme-PC'er har et av operativsystem-programmene Windows (f.eks. Win98) eller Linux. Operativsystemet utfører en rekke oppgaver, og en av de er å gjøre datamaskinen istand til å kommunisere med en bruker via tastatur, mus og skjerm. Enten du sitter ved en av instituttets maskiner eller din egen PC, er operativsystemet typisk det første du kommer i kontakt med når du har logget inn (eller for hjemme-PC: slått på maskinen). Noen av tingene du kan fortelle operativsystemet ved å bruke tastatur eller mus er å:

• starte å kjøre et annet program (kanskje et dataspill, eller et program du har laget selv) • skrive ut noe på en skriver ("printer") • vise fram noe på skjermen • logge ut (eller for hjemme-PC: slå av maskinen)

Hvis vi ønsker mer avansert kommunikasjon med datamaskinen enn dette (f.eks. fortelle datamaskinen nøyaktig hvordan den skal oppføre seg slik at den kan brukes av en kino til å holde orden på kinoforestillinger og solgte/reserverte billetter) så må vi kommunisere med datamaskinen ved hjelp av et programmeringsspråk.

9

Programmeringsspråk Et programmeringsspråk er et språk som kan brukes til å gi datamaskinen detaljerte instruksjoner om hvordan den skal oppføre seg, f.eks. hva den skal vise på skjermen, hva det skal bety når man trykker på bestemte taster, osv. Behersker du et programmeringsspråk kan du i praksis få datamaskinen til å gjøre hva som helst (innenfor rammen av hva datamaskiner kan få til, naturligvis). Programmeringsspråk skiller seg fra naturlige språk (som norsk, engelsk og spansk) ved at de har et veldig lite ordforråd (kanskje 100-200 ord) og en veldig enkel og veldefinert grammatikk. Mens det i naturlige språk er mange ord for å uttrykke f.eks. følelser, har ordene i et programmeringsspråk kun én hensikt: å fortelle datamaskinen hva den skal gjøre. Det finnes mange programmeringsspråk; det som benyttes i INF101 heter Java og er utviklet av firmaet Sun Microsystems (som også har laget endel av de datamaskinene vi bruker på Institutt for Informatikk). Den versjonen av Java vi benytter nå heter Java 1.3. For å kunne benytte Java, må datamaskinen først installere en programpakke som kalles Java 2 SDK Standard Edition, v 1.3. Denne programpakken (som allerede er installert på maskinene på Institutt for Informatikk, og som kan installeres på PC'er fra Ifi-CD'en som du kan få gratis ved å henvende deg i institutt-ekspedisjonen i 2. etg i Informatikkbygningen) inneholder blant annet programmer som må brukes hver gang du har laget et Java-program og ønsker å kjøre (utføre) det på datamaskinen.

Mer informasjon INF101 er i første rekke et kurs i programmering, og vi kommer ikke til å si mer enn nødvendig om hvordan en datamaskin ser ut inni. Dersom du har lyst å lære mer om det, anbefaler vi at du bruker en nettleser (f.eks. netscape eller internet explorer) og går inn på Universitetets Senter for Informasjonsteknologi (USIT) sine informasjonssider om PC'er. Der finner du masse nyttig informasjon om datamaskiner, operativsystemer, internett, osv. Prøv f.eks. adressene

http://www.usit.uio.no/it/pc/pcinfo/indxstrt/indxinnh.htm http://www.usit.uio.no/it/pc/pcinfo/educat/startedu.htm

10

11

Kapittel 2 - Mitt første javaprogram Nedenfor ser du et av de aller enkleste programmer som det er mulig å lage i Java. Vi skal her forklare noen aspekter ved dette programmet, men ikke alle (resten kommer senere i kurset).

class MittProgram { public static void main (String[] argv) { System.out.println("Jeg er et javaprogram"); } }

Når programmet blir kjørt, vil teksten «Jeg er et javaprogram» komme fram på skjermen. Dette programmet kan virke ubegripelig når man nettopp har begynt å lære programmering, men man trenger ikke forstå alle detaljene nå i starten. La oss ta for oss det viktigste. Vi ser først på rammen rundt programmet:

class MittProgram { ...... }

Dette kalles en klassedeklarasjon (hele programmet er altså en klassedeklarasjon i dette tilfellet). Legg merke til at det brukes krøllparenteser her som viser begynnelsen og slutten på programmet. Hva class betyr, kommer vi tilbake til senere i heftet - foreløpig kan du bare tenke på det som en innpakning av programinstruksjonene, hvor innpakningen i dette tilfellet heter MittProgram. Hele programmet omtales derfor noen ganger som «klassen MittProgram». Navnet er valgfritt, men det kan være greit å følge disse normene:

• Ikke bruk de særnorske bokstavene («æ, ø, å») i klassenavn. Bruk av disse kan skape problemer når programmet skal kjøres, selv om programmet blir kompilert uten problemer.

• Bruk gjerne tall, men du kan ikke starte navnet med et tall. • Begynn programnavnet med stor bokstav. Dersom navnet består av flere ord, skiller du

mellom ordene ved å starte hvert ord med en stor bokstav slik som i «MittProgram». Du kan ikke ha mellomrom i programnavnet.

Programmet skal lagres i en fil som heter det samme som programnavnet, og ha «.java» bak seg. Det betyr at programmet vårt skal lagres i en fil med navn «MittProgram.java». Det er viktig å få med seg de store og små bokstavene også i filnavnet. La oss se videre på programmet. Inne i klassen MittProgram ligger

public static void main( String[] argv ) { System.out.println("Jeg er et javaprogram"); }

Ved å skrive

public static void main(String[] argv)

12

lager vi startpunktet for javaprogrammet1. Dette er også en deklarasjon (og er samtidig - som påpekt ovenfor - en del av deklarasjonen av hele klassen). Når vi starter et javaprogram, vil utføringen av programmet begynne her. Hva programmet skal gjøre, skrives mellom krøllparentesene ’{’ og ’}’. System.out.println("Jeg er et javaprogram"); fører til at setningen «Jeg er et javaprogram» skrives ut til skjerm. Denne type setninger kalles for handlingssetninger eller bare setninger. Setninger utføres i den rekkefølgen de står — dvs. ovenfra og nedover. System.out.println er en standard javametode som brukes for å skrive tekst på skjermen. Inne i parentesen finner vi teksten som skal skrives ut på skjerm. Selve teksten står i anførselstegn. I Java avsluttes alle programsetninger med semikolon (’;’). Det gjøres for at kompilatoren (et oversetterprogram, se nedenfor) skal kunne finne hvor en programsetning slutter og den neste begynner. Byggesteinene i et javaprogram er deklarasjoner og setninger. Ved å sette sammen ulike typer deklarasjoner og setninger kan vi få programmet til å gjøre (nesten) hva det skal være. I det første programeksemplet vårt var det to deklarasjoner (class MittProgram og public static void main(String[]argv) ) og én handlingssetning (System.out.println("Jeg er et javaprogram"); ). Foreløpig må du slå deg til ro med de to deklarasjonene. De må være med. I det neste kapitlet skal vi se på andre typer deklarasjoner og lære flere handlingssetninger.

Kompilering og kjøring Før programmet kan kjøres, slik at vi kan se resultatet på skjermen, må det oversettes til et språk som er mer maskinnært. I programspråket Javas tilfelle, til et språk som kan forstås av den kunstige maskinen som kjører java-programmer (Java Virtual Machine, JVM). Denne oversettingen kalles kompilering, og oversetterprogrammet kalles kompilatoren. Kompilering av javaprogrammet over gjøres med kommandoen javac, slik:

> javac MittProgram.java Kommandoen gis til unix, dos eller på annen måte, avhengig av programmerings-omgivelsene. Går kompileringen bra, vil du få en ny fil i filkatalogen : MittProgram.class. Denne filen er klar til å bli kjørt av JVM. Dette gjøres ved kommandoen java :

> java MittProgram Legg merke til at man her ikke tar med filens etternavn (.class). En fullstendig sesjon med kompilering og kjøring vil da se slik ut:

> javac MittProgram.java > java MittProgram Jeg er et javaprogram >

Kommentarer Når vi kompilerer et javaprogram, vil kompilatoren prøve å oversette det vi har skrevet til kode som datamaskinen kan utføre, men ofte vil vi legge inn kommentarer i programkoden som kompilatoren ikke tar hensyn til. Disse kommentarene står der for at koden skal bli enklere å forstå for dem som leser den. Tekst som skrives mellom «/*» og «*/», og tekst som skrives på en linje etter «//» vil ikke bli kompilert, den blir oversett av kompilatoren.

public static void main(String[] argv) {

1 argv er et navn du finner på selv, men det er vanlig å bruke enten argv eller args

13

// Skriv ut en tekst på skjermen. System.out.println("Jeg er et javaprogram"); /* * System.out.println("Denne teksten blir ikke skrevet ut * når programmet kjøres."); */ }

Formatering Kompilatoren bryr seg stort sett ikke om linjeskift og mellomrom. Det er derfor lovlig å skrive programeksemplet vårt slik:

class MittProgram {public static void main(String[] argv) { System.out.println( "Jeg er et javaprogram");}}

Det er imidlertid vanlig å bruke innrykk og linjeskift for å gjøre koden oversiktlig. Emacs gir deg god hjelp til dette. Hvis du trykker tab-tasten vil linjen automatisk få «riktig» innrykk. Har du f.eks. glemt semikolon på slutten av en linje, vil du med en gang se det pga. innrykkene. Firmaet Sun har utarbeidet en standard for hvordan et javaprogram bør se ut2. Noen steder i dette kompendiet avviker vi fra denne standarden. Som oftest er det av plasshensyn. Vi anbefaler på det sterkeste at du benytter deg av denne standarden (eller en annen).

2 http://java.sun.com/docs/codeconv/

14

15

Kapittel 3 - Variabler og tilordninger For at et program skal kunne gjøre noe særlig fornuftig, trenger vi en måte å ta vare på forskjellige verdier. I første omgang skal vi se på verdier som enten er tall eller tekster. For å ta vare på en verdi, må vi ha et navn på verdien. I lærebøker kalles dette navnet for en identifikator. Dette navnet finner du på selv, men det er noen begrensninger på hva du kan kalle den. Disse begrensningene kommer vi tilbake til mot slutten av kapitlet.

Hva er en variabel? Du kan tenke på identifikatoren eller navnet som en adresse til en bestemt lagerplass i maskinens minne. På denne lagerplassen kan vi legge en verdi som vi siden kan hente fram ved å oppgi adressen. Det som er spesielt, er at du på forhånd må si hva slags type verdier du har tenkt å legge på lagerplassen (tall, tekst, e.l.).

1. Den har et navn (identifikator) som du finner på selv. 2. Den har en type. 3. Den har en verdi som stemmer overens med typen. Verdien kan endres underveis i

programmet (derav navnet variabel).

Deklarasjoner og tilordninger Å deklarere en variabel vil si å sette av lagerplass i maskinens minne og gi denne lagerplassen et navn. Typen forteller maskinen hvor mye plass som skal settes av. int er en type som forteller at det skal settes av plass til et heltall. La oss ta et eksempel:

class VariabelEksempel { public static void main(String[] args) { /*Først deklareres en variabel. Den er av typen * int. Vi kaller den for «lengde». */ int lengde; // Så gir vi variabelen «lengde» en verdi (et heltall) lengde = 3; /* Tilslutt skriver vi litt tekst og verdien i * variabelen «lengde» på skjermen. */ System.out.println("Verdien i variabelen lengde er " + lengde); } }

Når vi skal lage en variabel, gjør vi det altså i to skritt:

int lengde; Dette er deklarasjonen. Her sier vi hva navnet på variabelen skal være («lengde»), og hva slags type den er (int).

lengde = 3; Dette er en tilordning. Vi gir variabelen en verdi (lagrer en verdi på lagerplassen). Tegnet for tilordning er altså ’=’. Likhetstegnet betyr altså ikke det samme i Java som vi er vant til fra

16

matematikken. Det må her forstås og leses som "settes lik". Altså : verdien av variabelen lengde settes lik 3. Det er mulig å gjøre både deklarasjonen og en tilordning samtidig:

int lengde = 3; Det er også mulig å gjøre flere deklarasjoner samtidig:

int lengde, bredde;

eller int lengde = 3, bredde;

Når vi ønsker å skrive ut verdien av innholdet i en variabel, gjør vi det på samme måte som vi skriver ut tekst:

System.out.println(lengde); For enkelhets skyld sier vi at vi «skriver ut (variabelen) lengde». For å skjøte tekst sammen med annen tekst eller variabler brukes ’+’-operatoren. Når denne står i sammenheng med tekst, får den betydningen: «Slå sammen og lag en tekst.». Til nå har vi vist deg et eksempel der vi deklarerte en variabel og gjorde én tilordning, men det er mulig å gjøre flere tilordninger til samme variabel i løpet av programmet, dvs. at det legges en ny verdi på lagerplassen med den bestemte adressen (variabelnavnet). Den gamle verdien blir borte.

class VariabelEksempel2 { public static void main(String[] args) { int lengde; lengde = 3; // tilordning nr. 1 System.out.println("Verdien i variabelen lengde er " + lengde); lengde = 7; // tilordning nr. 2 System.out.println("Nå er verdien " + lengde); lengde = lengde - 2; // tilordning nr. 3 System.out.println("Den siste verdien av lengde er " + lengde); } }

Den andre tilordningen skulle være grei å forstå. Hvis du tenker tilbake på lagerplassen, så putter vi nå tallet 7 der. Den gamle verdien som lå der, blir borte. La oss nå se på den tredje tilordningen:

lengde = lengde – 2;

Når denne utføres, regner maskinen først ut høyresiden

lengde – 2

Variabelen lengde har verdien 7 (fra forrige tilordning). Dermed regnes det ut hva 7 –2 er. Neste skritt er tilordningen:

lengde =

Her legges resultatet av regnestykket på høyre side av ’=’ inn som ny verdi av variabelen på venstre side (som i dette tilfellet er lengde). Resultatet blir at verdien 5 tilordnes variabelen lengde.

17

Variabeltyper Som sagt må man bestemme hvilken type en variabel skal ha. Hittil har vi sett på heltall, men det finnes mange flere typer. Her kommer en liste over noen av de vanligste typene:

int Eks: int i = 5;

Brukes til å lagre etheltall (fra -2147483648 tom 2147483647).

char Eks: char tegn = ’A’;

Brukes til å lagre et enkelt tegn.

double Eks: double pi = 3.1415;

Brukes til å lagre et desimaltall (flytende tall).

String Eks: String tekst = "To be or not to be";

Brukes til å lagre en tekst3. Legg merke til den store S-en i String.

boolean Eks: boolean ferdig = true;

Brukes til å lagre en sannhetsverdi. Kan enten ha verdien sann (true) eller usann (false).

Mer om identifikatorer Vi har sagt at du selv velger navn på variabler, og at disse navnene kalles identifikatorer. Selv om du velger navnet selv, er ikke alle navn tillatt. De viktigste begrensningene kommer her:

• variabelnavn kan ikke begynne med et tall • variabelnavn kan ikke inneholde andre tegn enn bokstaver og tall4

Det er også noen ord som har en spesiell betydning i Java, vi har allerede vært borti noen av dem (int, boolean, osv.). Disse ordene kan du heller ikke bruke som identifikatorer. Her kommer hele listen over de reserverte ordene:

abstract default goto new synchronized boolean do if package this break double implements private throw byte else import protected throws case extends instanceof public transient catch false int return true char final interface short try class finally long static void const float native super volatile continue for null switch while

Tabell 2.1: Reserverte ord i Java

3 Egentlig er ikke String en type i Java, men siden den er så vanlig og brukes så ofte, har vi tatt den med her likevel. 4 I tillegg kan man bruke enkelte spesialtegn.

18

Hva slags navn bør du velge Selv om vi nå har sagt at du står (nesten) fritt til å velge navn på variabler, er det likevel noen retningslinjer du bør merke deg.

• navn på variabler bør begynne med liten bokstav. • navnet bør si noe om hva variabelen brukes til i programmet. Hvis variabelen bare brukes

midlertidig, får den ofte et kort navn (f.eks. ni, x). • dersom navnet består av flere ord, skiller du ordene ved bruk av stor bokstav på andre, tredje

osv., ord — slik som i «minVariabel». Dette er vanlig på engelsk som ikke har noen språklig tradisjon for å sette sammen ord. På norsk bør man ikke overdrive dette. Vi kan sette sammen ord helt naturlig: brannbil, ikke brannBil.

• navn på klasser skal alltid begynne med stor bokstav.

19

Kapittel 4 - Kontrollsetninger I dette kapitlet skal vi fortelle deg hvordan du kan kontrollere programflyten, f.eks. hvordan du kan hoppe over, eller gjenta, enkelte linjer i programmet. Før vi begynner å se på de enkelte kontrollsetningene må du kjenne til noe som heter booleske uttrykk5.

Booleske uttrykk Som du husker fra kapittelet om typer og variable finnes det en type som heter boolean. Det er en type som kan ha to verdier: sann eller usann (true eller false). Som du kanskje allerede har gjettet, likner booleske uttrykk svært på booleske typer. Et boolesk uttrykk er et utsagn ( en påstand eller en betingelse) som enten er sant eller usant (true eller false). For å finne ut om et gitt utsagn er sant eller usant, må det beregnes. Til denne type regning trenger vi noen operatorer: < og > «mindre» og «større enn» <= og >= «mindre eller lik» og «større eller lik» == «er lik» != «er ulik» Legg merke til ’==’ - operatoren. I Java (og mange andre språk) har denne betydningen ’er lik’. Grunnen til at det ikke brukes et enkelt likhetstegn, er at det betyr noe annet i Java (nemlig tilordning). La oss se på noen eksempler:

int i, j; char c; i < 5 // i er mindre enn 5 c == ’B’ // c inneholder tegnet ’B’ j != 5 // j er forskjellig fra 5;

Felles for disse uttrykkene er at de enten er sanne eller usanne. Det er enten sant eller usant at i er mindre enn 5. Typen på høyre side av operatoren må stemme overens med typen på venstre. Det er ikke mulig å sammenlikne f.eks. en double med en int. Ofte vil det være behov for å teste flere betingelser. Det gjør man ved å slå sammen de enkelte betingelsene. Til dette har vi følgende operatorer6

: && «OG» (på engelsk: «AND»). Hvis uttrykkene på høyre og venstre side av tegnet begge er

sanne, blir verdien sann. Dvs uttrykket

betingelse1 && betingelse2

er sant hvis både betingelse1 og betingelse2 er sanne. Hvis derimot minst én av dem er usann, får hele uttrykket ovenfor verdien usant.

|| «ELLER» («OR») Hvis minst ett av uttrykkene på høyre og venstre side er sanne, blir verdien sann. Dvs uttrykket

betingelse1 || betingelse2

5 George Boole (1815-64), engelsk matematiker som grunnla utsagnsregning som matematisk disiplin. 6 Det finnes flere, men i dette kurset klarer du deg med disse.

20

er sant hvis minst en av betingelse1 og betingelse2 er sann. Hvis derimot begge betingelser er usanne, får hele uttrykket verdien usant.

Så langt har vi vist deg operatorer som trenger to verdier for å virke — en på høyre og venstre side. Tilslutt bør du kjenne til ’!’-operatoren («not»). Den skiller seg fra de andre ved at den kun tar en verdi på høyre side. Resultatet er den motsatte verdien av verdien som beregnes. Altså:

!true //gir verdien usann. !false //gir verdien sann.

If-setninger En if-setning brukes til å utføre en eller flere setninger under gitte betingelser. Formen på setningen er som følger:

if ( betingelse ){ Setninger som utføres hvis betingelsen er sann.... ; }

Her er betingelse et boolesk uttrykk (en påstand), eller en boolesk variabel, som kan beregnes til sant eller usant. Slik bruker du if-setningen:

class Hvis { public static void main(String[] args) { Inn stdin = new Inn ( ); // Innlesing fra tastatur int i = stdin.inInt( ); // forklares nærmere i kap.5 if (i < 5 ) { // Skrives ut hvis i «er mindre enn» 5 System.out.println("Tallet er mindre enn 5"); } System.out.println("Takk for nå."); } }

Setningen «Tallet er mindre enn 5» skal bare skrives ut hvis det er sant. Det avgjøres av hvilken verdi brukeren oppgir til programmet.

if else Ofte vil man ha behov for å gjøre én ting hvis betingelsen er sann og noe annet hvis den er usann. Til det brukes setningskonstruksjonen if else. Formen er som følger:

if ( betingelse ){ gjør noe; } else { gjør noe annet; }

Det vil også være situasjoner hvor man har behov for å gjøre en ny if-test hvis den foregående if-testen var usann.

if ( betingelse1 ){ gjør ditt ; } else if ( betingelse2 ){ gjør datt ; } else if ( betingelse3 ){

21

gjør dette.... ; } else if ...

Et eksempel

class Hvis { public static void main(String[] args) { Inn stdin = new Inn ( ); int i = stdin.inInt ( ); if (i < 5) { System.out.println("Tallet er mindre enn 5"); } else if (i == 5) { System.out.println("Tallet er 5"); } else { System.out.println("Tallet er større enn 5"); } } }

Dette programmet har følgende algoritme:

1. Hvis i er mindre enn fem så... 2. Skriv ut «Tallet er mindre enn 5» og hopp til nr. 6 3. Hvis i er lik 5 så... 4. Skriv ut «Tallet er 5» og hopp til nr. 6 5. Skriv ut «Tallet er større enn 5» 6. Ferdig med testen - fortsett videre i programmet.

Resultatet er avhengig av hva brukeren oppgir.

While-setninger Vi kan få maskinen til å repetere en handling så mange ganger vi vil. Ofte kan vi ikke vite hvor mange ganger vi ønsker å repetere en eller flere setninger. Derimot vet vi at den skal repeteres så lenge en betingelse er sann. Til dette brukes en while-løkke. En while-løkke har følgende form:

while ( betingelse ){ setninger; }

betingelse er et boolesk uttrykk eller en boolesk variabel som er true eller false. setninger er den eller de setningene du ønsker utført så lenge betingelsen er sann. Det er viktig å oppdatere betingelsen inne i løkka. Hvis vi glemmer dette, vil betingelsen alltid være sann og programmet havner i en evig løkke. Hvis det skjer, må du avbryte programmet ved å trykke ctrl-c. Et eksempel på bruk av en while-løkke:

class Kvadrattall { public static void main(String[] args) { int i = 1; int kvadrat = i * i;

22

while ( kvadrat < 1000 ){ System.out.println("Kvadratet av " + i + " er " + kvadrat ); i = i + 1; kvadrat = i * i; } System.out.println("Takk for nå."); } }

Dette programmet beregner alle kvadrattall under 1000, fra 1 og oppover. Vi vet i utgangspunktet ikke hvor hvor langt vi må gå med variablen i. Vi setter bare betingelsen at vi skal stoppe når kvadratet av i er blitt 1000 eller mer.

For-setninger En for-løkke brukes når du ønsker å repetere en eller flere setninger et bestemt antall ganger. Formen på en for-løkke er:

for ( startpunkt for teller ; betingelse; økning/minskning ){ setninger; }

La oss ta et eksempel som skriver ut kvadrattallene fra 1 tom 50 (jfr. eksemplet på while-løkke ovenfor):

class Kvadrat { public static void main(String[] args) { for (int n=1; n<=50; n = n + 1) {

int kvadrat = n * n; System.out.println("Kvadratet av " + n + " er " + kvadrat);

} } }

For-setningen består av tre deler atskilt med ’;’. La oss ta dem en for en.

int n = 1; Dette er initialiseringsdelen av for-løkken. Her deklarerer vi et heltall n og tilordner det verdien 1. n fungerer som teller i løkken.

n <= 50; Denne delen kalles en betingelse. Den kan du lese som: «Hvis n er mindre eller lik 50 så...».

n = n + 1 Denne delen utføres helt til slutt i løkken, og forteller at vi skal øke telleren med 1 for hvert gjennomløp. Hvis vi skulle si for-løkken med ord, ville vi altså få:

1) La en teller, kalt n, være lik 1 2) Hvis n er mindre eller lik 50 så 3) Beregn kvadratet av n og skriv ut verdien av kvadrat 4) Øk n med 1 5) Gå tilbake til punkt 2

23

Det er også mulig å øke telleren med mer enn 1 eller vi kan velge at den skal minke for hvert gjennomløp. Om vi, f.eks. ville beregne kvadratet av alle ulike tall (1, 3, 5, ...), måtte vi skrive n=n+2 i for-setningen.

do while-setninger Om vi vet at vi skal gjennomløpe en løkke minst én gang, kan vi velge å bruke do - while setningen. Formen på do - while løkken er:

do { setninger ; } while ( betingelse );

do - while løkken likner altså svært på en while-løkke. Forskjellen ligger i at innholdet i løkken utføres før betingelsen regnes ut og testes. Hvis betingelsen er sann, utføres løkken en gang til. Husk at betingelsen må oppdateres i do-delen ellers kan du få en evig løkke. Legg også merke til semikolonet på siste linje. Denne konstruksjonen brukes ofte i sammenheng med innlesing fra tastatur. Her er et eksempel:

import inf101.*; class Repetisjon2 { public static void main(String[] args){ Inn stdin = new Inn( ); int n; do { System.out.println("Skriv inn heltall. "); System.out.println("Avslutt med et negativt tall."); n = stdin.inInt( ); System.out.println("Du skrev: " + n); } while (n >= 0); // end do while System.out.println("Takk for nå."); } }

Switch-setninger Vi har tidligere sett på if og if-else setningen. Hvis vi for et gitt uttrykk har mange mulige handlinger, kan vi isteden bruke switch-setningen. Formen på switch-setningen er:

switch ( uttrykk ){ case verdi1 : 1. setninger ; break; // valgfritt case verdi2 : 2. setninger; // break utelatt case ...; default: setninger.... ; break; }

Først beregnes verdien av uttrykket. Verdien som beregnes, må være av typen int eller char.

case verdi: Så prøver programmet å «matche» verdien av uttrykket med en av verdiene etter case. Ved det tilfellet (case) hvor verdien av uttrykket stemmer, begynner programmet å utføre de setningene som følger.

break;

24

Setningene utføres fram til programmet kommer til break.Da er switch-setningen ferdig. Hvis et tilfelle (case) ikke avsluttes med en break vil setningene i de påfølgende tilfellene også bli utført fram til første break. Hvis break utelates bør du skrive en kommentar.

default Hvis verdien av uttrykk ikke er listet opp som en av mulighetene, blir setningene etter default utført. Denne delen er valgfri, men bør i regelen være med.

Et eksempel Switch-setningen er særlig anvendelig når brukeren av programmet taster inn et valg, og eksemplet under kan brukes som en mal for dette.

import inf101.*; class Meny { public static void main(String[] args) { Inn stdin = new Inn( ); char valg; // brukers valg lagres her. do { System.out.print("Skriv inn en bokstav. Avslutt med ’x’: "); valg = stdin.inChar( ); switch (Character.toLowerCase(valg)) { case ’a’: System.out.println("Du skrev tegnet ’a’"); System.out.println("Det er første bokstav i alfabetet."); break; case ’b’: System.out.println("Du skrev tegnet ’b’"); System.out.println("Det er andre bokstav i alfabetet."); break; case ’c’: System.out.println("Du skrev tegnet ’c’"); // ikke stopp her, men utfør neste setning også. default: System.out.println("Det kommer etter ’b’ i alfabetet."); break; } // slutt switch } while (valg != ’x’); // slutt do while } slutt main }

I eksemplet over er break utelatt i det siste tilfellet (case ’c’). Hvis brukeren av programmet taster inn ’c’, vil altså følgende bli skrevet ut:

Du skrev tegnet ’c’ Det kommer etter ’b’ i alfabetet.

Det er svært fort gjort å få uventede resultater når man utelater break. Derfor anbefales det ikke.

25

Kapittel 5 - Objekter og klasser Ett av ordene som brukes, når man skal beskrive programmeringspråket Java, er objektorientert. I dette kapitlet skal vi se på hva som skjuler seg bak begrepet, og du vil få vite hva nøkkelordene class og static betyr.

Objekter Vi har allerede vært inne på at en variabel kan tenkes på som en lagerplass - for eksempel kan en variabel av typen double tenkes på som en lagerplass for et desimaltall. Når vi lager store programmer er det ofte veldig mange variable (ofte tusenvis), og i mange tilfeller er det naturlig å tenke på hver variabel som tilhørende et objekt. Hvis vi f.eks. lager et program for universitetet som skal holde orden på opplysninger om alle studentene, så ønsker vi kanskje å lagre f.eks. navn, fødselsnummer og studentnummer for hver enkelt student (i tillegg til mange andre ting). Det kunne vi få til ved å bruke tre variable for hver student:

String navn; int fnr; int studnr;

Det er naturlig å gruppere sammen disse tre variablene siden de tilhører samme student. Vi kan tenke på hver student som et objekt med visse karakteristika, i vårt tilfelle begrenset til navn, fødselsnummer og studentnummer (virkelige studenter har naturligvis et utall forskjellige karakteristika som skiller dem fra andre studenter!). Allerede som små barn lærer vi å tenke på verden som bestående av atskilte objekter (selv om vi kanskje ikke kaller dem for det): hver bil, hver bok, hver person, hvert hus osv er et eget objekt. Hvert objekt har visse karakteristika; f.eks. har en bok en tittel, en eller flere forfattere, osv, mens en bil har et merke, et registreringsnummer, osv. Noe av filosofien bak objektorientert programmering går ut på at man i programmering kan dra nytte av at verden for oss mennesker oppfattes som bestående av atskilte objekter. Dersom vi lager et program som skal holde orden på opplysninger om biler, så er det naturlig at vi også i programmet (og ikke bare i det virkelige liv) tenker på hver bil som et objekt. Det kan vi få til ved å holde samlet alle dataene om en bil ett sted i programmet, dvs ved å legge alle dataene om en bil i samme objekt. Men hva mener vi med et objekt i Java? Når vi i Java snakker om et objekt så mener vi rett og slett en samling av variabler og metoder7 som vi har bestemt skal høre sammen i en enhet. Det er helt opp til oss som programmerere å bestemme hvilke variable og metoder som skal høre sammen - her har vi full frihet. Vi vil imidlertid nesten alltid forsøke å lage disse enhetene slik at de avspeiler best mulig de virkelige objektene som vi prøver å modellere/representere i datamaskinen. For å forklare hvordan man lager objekter i Java, må vi først innom et annet begrep: klasser.

Klasser Hvordan forteller vi Java at visse variable skal høre sammen i en enhet, f.eks. at variablene navn, fnr og studnr i eksemplet ovenfor skal danne en enhet? Svaret er at vi gjør det ved å deklarere en klasse som inneholder de tre variabeldeklarasjonene:

class Student { String navn; int fnr;

7 metoder blir forklart i kap.6 og kap.11

26

int studnr; }

Navnet på klassen (i dette tilfellet: Student) er et navn vi selv velger. En klasse er en angivelse av (dvs en oppskrift for) hvordan en bestemt type objekter skal se ut. Klassen Student vil derfor inneholde variablene vi trenger for å lagre data om hver enkelt student, og metodene som beskriver hva slags operasjoner student-objektet kan gjøre. Det er viktig å få med seg at klassen Student ikke i seg selv utgjør et student-objekt; den beskriver bare hvordan student-objekter skal se ut i datamaskinen. For å få laget et objekt av typen (klassen) Student må vi skrive

new Student(); Det som skjer når denne setningen eksekveres er at det settes av lagerplass i datamaskinen til tre nye variable som heter navn, fnr og studnr (det skjer også en ting til: Java gir tilbake adressen til det stedet i hukommelsen hvor objektet ligger; se neste seksjon). I den virkelige verden vil du som regel finne flere objekter av samme type. Det finnes mange studenter og mange biler. Vi kan tenke oss at alle studenter er del av en samlebetegnelse: Student. Denne samlebetegnelsen er det vi kaller en klasse. Vi sier at «studenter er objekter av klassen Student». Alle studentene har samme mulige handlinger og samme type data, men innholdet i dataene skiller dem fra hverandre. Klassen Student beskriver altså egenskaper og handlinger for alle studenter. For å lage flere objekter at klassen Student kan vi bruke new flere ganger:

new Student(); new Student();

Når disse eksekveres settes det av lagerplass til to objekter som hver holder tre variable som heter navn, fnr og studnr. Normalt ønsker vi å ta vare på adressen til objektene vi lager (ellers kan vi ikke få tak i variabler og eventuelle metoder inne i objektene); vi skal nå se hvordan det gjøres.

Referanser (pekere) Dersom vi ikke tar vare på adressen til et objekt vi har laget, har vi for alltid mistet kontakten med objektet (dvs muligheten til å få tak i variabler og kalle på eventuelle metoder inne i objektet). Adressen kan vi få tak i når objektet blir til, f.eks. ved å skrive

Student stud = new Student(); Det som skjer her er først at det lages et objekt av klassen Student, og deretter settes variabelen stud lik adressen til det nye objektet. Variable av denne typen kalles referanser eller pekere i Java. Når vi først har en referanse til et objekt, kan vi lett få tak i variablene og metodene inne i objektet, f.eks.

stud.navn = "Nina Alsgård"; stud.fnr = 15108357744; stud.studnr = 236393956; System.out.println("Studentens navn er " + stud.navn);

Punktumet etter stud uttales «sin» eller «sitt», slik at første linje ovenfor uttales «student sitt navn settes lik Nina Alsgård». Med stud.navn mener vi altså den variabelen navn som ligger inni det objektet som stud refererer til. Vi kan godt ha flere referanser til samme objekt, slik som i følgende eksempel:

Student stud2 = stud;

27

Nå refererer (peker) både stud og stud2 på samme objekt av klassen Student. Derfor gir følgende to setninger nøyaktig samme resultat:

System.out.println("Studentens navn er " + stud.navn); System.out.println("Studentens navn er " + stud2.navn);

Vi deklarerer referanser akkurat på samme måte som vi deklarerer variabler, men i stedet for typen (f.eks. int), skriver vi klassenavnet (f.eks. Student). En referanse kan ikke peke på et objekt av en annen klasse enn den er deklarert til å peke på. Retningslinjene for navn på referanser er de samme som for navn på variable. I alle objekter er det en svært nyttig peker som refererer til objektet selv. Denne pekeren heter this og er innebygd i objektet; denne pekeren trenger ikke (og skal ikke) deklareres av deg (du kan tenke deg at Java gjør det automatisk, bak kulissene).

Klasse/objekt-diagrammer En sentral del av det å lage et program er å danne seg en mental modell for hva som skal skje når programmet eksekverer. Man kan tenke seg forskjellige detaljnivåer på en slik mental modell; i INF101 konsentrerer vi oss om såkalte klasse/objekt-diagrammer som viser grafisk hvilke klasser programmet består av, hvilke objekter vi har, og hvilke objekter som refererer til hvilke objekter (vi sier at et objekt refererer til et annet objekt dersom det første objektet inneholder en referansevariabel som peker på det andre objektet). Slike diagrammer kan være svært nyttige når vi prøver å forstå hva et komplisert program med mange klasser og objekter gjør, og ikke minst når vi holder på å lage et slikt program. La oss se på et eksempel. Anta at vi har følgende program:

class BilRegister { public static void main (String [] args) { Bil bil1, bil2, bil3; bil1 = new Bil(); bil2 = new Bil(); bil3 = new Bil(); bil1.chassisnr = 436457877223; bil1.årsmodell = 95; .... } } class Bil { int chassisnr; int årsmodell;

} Dette (ufullstendige) programmet består av to klasser: class BilRegister og class Bil. I klassen BilRegister er metoden main deklarert, og inne i denne metoden er det først deklarert tre referanser til objekter av klassen Bil. Deretter lager vi tre objekter av klassen Bil og gir deretter verdier til variablene i disse objektene. Et klasse/objekt-diagram for dette programmet vil se ut som i figur 6.1.

28

Figur 6.1: Mental modell (=klasse/objekt-diagram) for BilRegister-programmet. Mange vil nok føle seg fristet til å «hoppe over» modelleringen og gå rett på programmeringen, men hensikten med tegningen er å lage en modell som danner grunnlag for programmet. Derfor skal tegningen lages før programmeringen tar til. Når man lager større programmer, opplever man fort at man har mange objekter som alle inneholder flere metoder og variabler. Hvis man i tillegg har mange pekere, blir tegningen fort uoversiktlig, og virker ikke etter hensikten. Hvis det er tilfellet, kan det være lurt å dele tegningen opp i flere deler. En del kan vise forholdene mellom objektene, en annen del kan vise innholdet i de forskjellige objektene.

Bruk av static I de fleste tilfeller ønsker vi at variable og metoder skal tilhøre det enkelte objekt av en klasse. Det at en metode tilhører objektet betyr at metoden har direkte adgang til alle variable og metoder i objektet. For å få tak i slike variabler og metoder i et objekt, må vi enten befinne oss i objektet eller vi må bruke en sin-konstruksjon med en peker som peker på objektet (p.metode( ) ). Innimellom vil det være behov for å ha data som ikke er knyttet til de enkelte objektene, men til hele klassen. F.eks. er det unødvendig å lagre data om antall gir på biler i hvert enkelt bil-objekt. Dette er ikke data som skiller biler fra hverandre (vi later som om det bare er en type bil i hele verden), men data som beskriver egenskaper felles for alle biler. Hvis vi skulle ønske å forandre antall gir, vil vi at dette skal kunne gjøres ett sted og virke for alle objekter. Slike variabler kalles klassevariable (eng. fields) og har modifikatoren static. En static metode har bare tilgang til static variable og andre static metoder i klassen. dersom en static metode forsøker å få tilgang til en variabel eller metode som tilhører et objekt, får vi følgende feilmelding når vi kompilerer:

Can’t make a static reference to nonstatic variable <var. navn> in class klassenavn.

Denne feilen oppstår fordi man prøver å få tilgang til en variabel eller metode som tilhører et objekt uten å ha laget objektet. Vanligvis er det i tilknytning til klassen som inneholder main-metoden at

bil1

bil2

bil3

BilRegistermain

Bil

chassisnr

årsmodell

chassisnr

årsmodell

chassisnr

årsmodell

29

feilen oppstår. En måte å løse problemet på er å lage et objekt av klassen. Når du lager objekter, får du tilgang til alle variable og metoder, og feilmeldingen blir borte. Mer om dette senere.

30

31

Kapittel 6 - Innlesing fra tastatur I svært mange programmer skal brukeren av programmet gi opplysninger som programmet deretter behandler. Normalt foregår denne kommunikasjonen via tastaturet. Når programmet forventer «input» fra brukeren, venter programmet på dette helt til brukeren taster [Enter]. Da først overføres det brukeren skrev, til programmet, som så fortsetter med behandlingen av teksten som brukeren skrev inn.

Hvordan lese fra tastatur Siden innlesning fra tastatur er ganske tungvint i Java, har vi laget en egen verktøykasse for skriving og lesing, som er enklere i bruk: For å lese fra tastatur er det noen få kommandoer som må gjøres hver gang. La oss ta et eksempel:

import inf101.*; class Innlesning { public static void main(String[] args) { Inn stdin = new Inn( ); int i; System.out.print("Skriv et tall: "); i = stdin.inInt( ); System.out.println("Du skrev: " + i); } }

For å lese fra tastatur må følgende være med: import inf101.*;

Denne linja importerer verktøyet (eller hjelpeprogrammene) vi bruker i innlesingen.

Inn stdin = new Inn( );

Her lages koplingen (eller referansen) til tastaturet som en peker til et objekt av klassen Inn. Koplingen kalles for stdin. Dette navnet velger du selv, men det er vanlig å kalle den for stdin (Standard in), eller bare in. Senere i programmet, når vi skal lese fra tastaturet, er det denne referansen vi bruker. Selve innlesingen skjer på linjen

i = stdin.inInt( ); Som du ser, er det en tilordning. Vi leser inn et tall og tilordner verdien til variabelen med navnet i. Hvis brukeren skulle taste noe annet enn et heltall, får hun automatisk en feilmelding fra Inn-objektet. Legg også merke til at det må være samsvar mellom hva vi leser inn, og tilordningen til variabelen der vi tar vare på den innleste verdien. Variabelen i må altså være av typen heltall (int).

32

Inn-klassen Verktøyene som importeres (inf101.*) er ikke en del av standardpakken til Java, men er laget ved IFI. Pakken inneholder bl.a. klassen Inn som bl.a. har følgende metoder for innlesing8: inInt( ) - brukes for å lese inn et heltall. inDouble( ) - brukes for å lese inn et desimaltall. inChar( ) - brukes for å lese inn et enkelt tegn. inString( ) - brukes for å lese inn et ord. Et ord, i denne sammenhengen, er en gruppe tegn uten blanke tegn mellom. Det er altså mulig å lese inn tall med denne metoden, men tallet er da representert som tekst (String), og må tilordnes til en String-variabel. Felles for disse metodene er at de hører til en kopling mot tastaturet (eller som vi senere skal se — en fil). Denne koplingen oppnår vi ved å skrive navnet på koplingen, stdin, etterfulgt av punktum og tilslutt navnet på metoden. Hvis vi skal lese ett tegn, skriver vi altså:

stdin.inChar( ); inStringln( ) Denne metoden vil lese en hel linje, eller resten av linja dersom noe av den allerede er lest med noen av de andre metodene. Et eksempel der vi har bruk for å lese både hele linjer med mange ord og linjer med enkeltopplysninger (f.eks. et tall), kan se slik ut:

import inf101.*; class Hei { public static void main(String[] args) { Inn stdin = new Inn( ); String navn; int alder; System.out.print("Skriv inn hele navnet ditt: "); navn = stdin.inStringln( ); System.out.print("Skriv inn alder: "); alder = stdin.inInt( ); System.out.println("Hei " + navn + ". Du er " + alder + " år gammel"); } }

Inn-klassen kan også brukes til å lese fra filer. Det kommer vi tilbake til.

Store og små bokstaver Ved innlesning fra tastatur vil det ofte være behov for å gjøre om fra store til små bokstaver (eller omvendt). Slik gjøres det for tegn:

char u =’A’;

8 En fullstendig beskrivelse av alle metodene til klassen Inn, fins bakerst i dette heftet.

33

char l = Character.toLowerCase(u);

Dette vil føre til at variabelen l inneholder ’a’. Hvis man ønsker det motsatte:

char l =’a’; char u = Character.toUpperCase(l);

For tekster er notasjonen en litt annen:

String low = "navn"; String up = low.toUpperCase( );

Vil føre til at teksten up inneholder «NAVN». Hvis man ønsker det motsatte:

String up = "NAVN"; String low = up.toLowerCase( );

34

35

Kapittel 7 - Metoder En metode er en del av et program som er gitt et eget navn. Metoden kan være stor, med mange programsetninger, og når vi et annet sted i programmet ønsker utført alle programsetningene i metoden, er det tilstrekkelig å oppgi dens navn. Vi sier at metoden kalles i andre deler av programmet.

Hvordan bruke metoder Når vi skal bruke en metode, må vi må skille mellom to ting, deklarasjon av metoden og kallet på metoden. main( ), som vi har sett på i tidligere eksempler, er en metode som må deklareres i alle javaprogrammer. Denne metoden blir automatisk kalt når javaprogrammet starter.

Deklarasjonen av en metode er det stedet hvor metoden lages. Det gjøres ved å skrive:

modifikatorer metodenavn( ){ kroppen til metoden }

Modikatorene kommer vi grundigere tilbake til i kapittel 11. Kroppen til metoden er alle programsetningene som metoden består av. Metoden kalles ved å skrive :

metodenavn( ); Vi skal i dette kapitlet gå gjennom hvordan vi bruker metoder. Seinere skal vi se på hvordan vi kan sende verdier til metodene (parametre) og hvordan metodene kan levere tilbake resultater av sin utførelse (returverdier). Dersom vi ønsker å kalle en metode fra main( ) må metoden deklareres som static. Det gjøres ved å skrive static først i metodedeklarasjonen. Se mer om static i kapitlet om klasser og objekter.

Hvorfor bruke metoder Det er to viktige grunner til å benytte metoder når vi programmerer.

• metoder egner seg for setningsgrupper som kommer til å bli utført ofte i programmet. Istedenfor å gjenta den samme koden flere steder i programmet, legger vi den i en metode og nøyer oss med å kalle på metoden.

• Vi benytter også metoder for å få bedre oversikt over programmet vårt.

Dersom all kode blir skrevet i en stor «klump», vil programmet bli uoversiktlig. Ved å legge deler av programmet som løser en spesiell oppgave i en metode, blir det enklere å ha oversikt over programmet, enklere å finne feil og enklere å utvikle programmet. Likevel er det først ved egen erfaring, etter å ha skrevet noen programmer, at vi forstår hvor nyttige metoder kan være. I dette kapitlet skal vi lage en metode — kalkulator, som beskriver en del av de forskjellige egenskapene til metoder. Vanligvis er det ikke nødvendig å lage en metode som beregner summen av to tall, men det er gjort her for å vise hvordan man bruker metoder. Vi kan tenke oss følgende ramme for eksemplene:

36

import inf101.*; class Kalkulator { /* Her legges metoden main */ /* Her legges metoden kalkulator */ }

Enkle metoder Dette eksemplet viser hvordan vi deklarerer, og kaller på, kalkulatormetoden:

public static void main(String[] argv) { kalkulator( ); } static void kalkulator( ) { Inn stdin = new Inn( ); int talla, tallb; int sum; System.out.print ("Oppgi x : "); talla = stdin.inInt(in); System.out.print ("Oppgi y : "); tallb = stdin.inInt(in); sum = talla + tallb; System.out.println("Summen av " + talla + "og" + tallb + "er :" + sum); }

Vi ser nærmere på de enkelte delene i metoden:

static void kalkulator( ) { programkode.... }

Dette er deklarasjonen av metoden. Her oppgir vi navnet på metoden, og skriver programkoden som skal utføres når metoden blir kalt. Ettersom vi skal kalle denne metoden fra main, som er static, må vi skrive static foran metoden. void betyr at metoden ikke sender noen returverdi fra seg (returverdier skal vi se på seinere). De tomme parentesene (etter «kalkulator») betyr at metoden ikke har noen parametre. Hva parametre er, vil også bli forklart senere.

Hva skjer når metoden blir kalt Kallet på metoden er linja

kalkulator( ); som står i main. Dette heter «kallstedet». Når programutføringen kommer til denne linja, «hopper» programutføringen til begynnelsen på metoden, og programkoden som står inne i metoden blir utført. Etter at programkoden som står i metoden er utført, «hopper» programmet tilbake til linja etter kallstedet, og programkoden der utføres videre.

37

Kapittel 8 - Arrayer og hashtabeller Vi har til nå sett på muligheten for å lagre tall i variabler, ha referanser til objekter, og for å lagre tekststrenger. Mengden informasjon vi har tatt vare på har vært veldig begrenset, men hva om vi ønsker å lagre større mengder informasjon — f.eks. 100 tall eller 1000 objektreferanser? I dette kapitlet skal vi se på to typer tabeller som finnes i Java: først ser vi på arrayer, og deretter på hashtabeller. Både arrayer og hashtabeller brukes til å lagre større mengder data. Det er derfor viktig å forstå forskjellen, slik at man vet når man skal benytte den ene og når man skal benytte den andre.

Hva er en array? En array er ikke annet enn en samling variable av samme type (f.eks. int) som er nummerert fra 0 og oppover (vi skal senere se på arrayer hvor nummereringen er litt annerledes). Hvis vi tenker på en enkel variabel som en enkelt skuff, så svarer altså en array til en hel kommode med nummererte skuffer. Bruk av arrayer gjør det mulig å håndtere flere lagerplasser i maskinens minne under samme navn. Den enkelte lagerplass har en identifisert med en indeks i tillegg til dette navnet. Indeksen angis i hakeparenteser etter navnet.

Hvordan lage en array Når vi oppretter en array, gjør vi det i to steg. Først lager vi en referanse til et arrayobjekt, siden oppretter vi dette objektet. Det er to måter å deklarere referansen på (resultatet blir nøyaktig det samme i de to tilfellene, forskjellen er plasseringen av hakeparentesene):

// Enten int register[] // eller int[] register;

Her lager vi en referanse til en array, som kan inneholde verdier av type int.

register = new int[10]; Her lager vi en array med plass til 10 elementer av typen int. Man kan som før, slå sammen disse to skrittene:

int register[] = new int[10];

Hvordan bruker vi en array En array blir altså en «rekke» med variabler. Disse variablene bruker vi på akkurat samme måte som vanlige variabler. Det eneste vi må huske på nå, er å ta med indeksen. Indeksen kan være et heltall, en variabel av typen int, eller et uttrykk der resultatet er et heltall. Siden indekseringen av arrayer alltid starter på null, blir indeksen et tall mellom mellom 0 og antall elementer i arrayen minus en. Hvis det er 10 elementer i arrayen går altså indeksen fra 0 til 9. Eksempel på bruk av indekseringen:

register[4] = 23; // legger verdien 23 i den 5. ’boksen’ int x = 3; register[x] = in.inInt(); // et tall fra tastatur legges i boks 4 System.out.println(register[x-2]); // skriver innholdet av boks 2

38

Hvordan gå gjennom en array Dersom vi ønsker å behandle alle elementene i en array i rekkefølge, bruker vi som regel en for-løkke. Her kommer et eksempel på gjennomløp av register-arrayen:

for ( int i = 0; i < 10; i++) { System.out.println ( register [ i ] ); }

.

Vi kan alltid få vite hvor mange elementer en array har plass til. Hvis vi skriver

int l = register.length;

vil l inneholde verdien 10. Eksemplet over kunne derfor også sett slik ut:

for ( int i = 0; i < register.length; i++) { System.out.println ( register [ i ] ); }

.

Et eksempel La oss se på et eksempel. Et museum ønsker å lagre hvor mange personer som besøker deres museum per måned. De ønsker bare å lagre informasjon for ett år. Vi kan tenke oss en løsning der vi har en variabel for hver eneste måned, og lar innholdet i denne variablen være besøkende den måneden.

class Museum { // Dette er ikke en god løsning. int antallBesøkendeIJanuar; int antallBesøkendeIFebruar; // ... int antallBesøkendeIDesember; }

Dette blir kronglete. Vi vet at alle måneder har et nummer, og kan bruke dette til å lage en array, der posisjonen i listen er månedsnummeret, og innholdet i denne posisjonen er antall besøkende den måneden.

import inf101.*; class MuseumMain { public static void main(String[] argv) { new Museum( ); } } class Museum { // Her setter vi av plass til 12 int variabler. int antallBesøkende[] = new int[12]; Inn stdin; // Konstruktør Museum( ) { int valg; stdin = new Inn( ); // Åpne for innlesning fra tastatur. do {

39

System.out.println("1) Legge inn antall besøkende for en måned"); System.out.println("2) Skrive ut antall besøkende for hele året"); System.out.println("3) Avslutt"); System.out.print("Gi ditt valg : "); valg = stdin.inInt( ); if (valg == 1) { lesInnBesøkende( ); } else if (valg == 2) { skrivBesøkende( ); } } while( valg!=3 ); // end do while } // end konstruktør void lesInnBesøkende( ) { int i,ant; do { System.out.print("Oppgi månedsnummer (1-12) "); i = stdin.inInt( ); } while((i <1) ||(i >12)); // end do while System.out.print("Oppgi antall besøkende for denne måneden : "); antallBesøkende[i-1] = stdin.inInt( ); } void skrivBesøkende( ) { /* Når vi skal gå igjennom en array, er det vanlig å bruke en * for løkke. Dette fordi vi vet nøyaktig hvor mange ganger vi * skal gå i løkka før vi starter den, nemlig antall elementer * i arrayen. */ for(int i = 1; i <= 12; i++) { System.out.println("Måneds nummer " +i+" hadde " + antallBesøkende[i-1] + " besøkende"); /* For hvert månedsnummer slår vi opp i arrayen, og skriver ut * den månedens verdi. */ } } // end skrivBesøkende. }

En spesiell array Vi har muligheten til å lage en liste, der innholdet i listen er gitt på forhånd. Dette kan ha flere bruksområder, for eksempel når vi ønsker å oversette fra et tall til en tekst som dette tallet representerer. La oss se på et eksempel. Vi har 12 måneder i året. I et program bruker vi normalt månedsnummeret til å representere de forskjellige månedene. For eksempel kunne antall besøkende til et museum per måned lagres i en array der månedsnummeret er posisjonen i arrayen. Men, når vi skriver ut på skjerm, ønsker vi ofte å skrive ut det tallet representerer, ikke selve tallet. I dette eksemplet betyr det at vi skriver ut månedsnavnet i steden for månedsnummeret. Vi lager en ny versjon av metoden skrivBesøkende fra det første eksemplet.

void skrivBesøkende( ) { String måneder[] = {"Januar", "Februar", "Mars", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Desember"}; for (int i = 1; i <= 12; i++) {

40

System.out.println(måneder[i-1] + " hadde " + antallBesøkende[i-1] + " besøkende"); /* I steden for månedsnummeret skriver vi ut det * som ligger i måneder arrayen på denne posisjonen, det vil si * månedsnavnet. */ } // slutt for løkke } // slutt skrivBesøkende( ).

Arrayer med referanser Vi har så langt bare sett på arrayer som inneholder tall. For eksempel vil «int liste[] = new int[12]» gi oss plass til 12 heltall, indeksert fra 0 til 11. Vi kan tenke oss at vi isteden for å sette av plass til 12 tall, ønsker en array med referanser til 12 objekter. Vi ser på et nytt eksempel:

import inf101.*; class Museum { // Steg en, vi oppretter en referanse til en array. Besoeksdata besoekende []; Inn stdin = new Inn( ); String måneder[] = {"Januar", "Februar", "Mars", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Desember"}; public static void main(String[] argv) { Museum m = new Museum(); } Museum () { // Steg to, vi oppretter arrayobjektet. besoekende = new Besoeksdata[12]; int valg; do { System.out.println("1) Legge inn antall besøkende for en måned"); System.out.println("2) Skrive ut antall besøkende for hele året"); System.out.println("3) Avslutt"); System.out.print("Gi ditt valg : "); valg = stdin.inInt( ); if (valg == 1) { lesInnBesøkende( ); } else if (valg == 2) { skrivBesøkende( ); } } while(valg!=3); // end do while } void lesInnBesøkende( ) { int i, ant; do { System.out.print("Oppgi månedsnummber (1-12) "); i = stdin.inInt( ) - 1; } while((i <0) ||(i >11)); // end do while besoekende[i] = new Besoeksdata(stdin, måneder[i]); } void skrivBesøkende( ) { for (int i = 0; i <12; i++) {

41

if(besoekende[i] != null) { besoekende[i].skrivData(); } } } // end skrivBesøkende. } class Besoeksdata { int antallBarn; int antallVoksne; int antallIskremSolgt; String mnd; public Besoeksdata(Inn stdin, String mnd) { System.out.println("Måned : " + mnd); System.out.print("Antall barn som besøkte museet :"); antallBarn = stdin.inInt( ); System.out.print("Antall voksne som besøkte museet :"); antallVoksne = stdin.inInt( ); System.out.print("Antall iskrem som ble solgt :"); antallIskremSolgt = stdin.inInt( ); this.mnd = mnd; } void skrivData() { System.out.println("Måned : " + mnd); System.out.println("Antall barn som besøkte museet : " + antallBarn); System.out.println("Antall voksene som besøkte museet : " + antallVoksne); System.out.println("Antall iskrem som ble solgt : " + antallIskremSolgt); } }

En ting det er viktig å få med seg, er at når vi skriver «besoekende = new Besoeksdata[12]», så oppretter vi ikke 12 objekter av klassen Besoeksdata, men 12 referanser som kan peke til objekter av typen Besoeksdata. Vi må selv lage objektene. Det gjøres med setningen:

besoekende[i] = new Besoeksdata( ); // her lages ett objekt. Legg også merke til følgende: Når vi skriver

X [] y = new X[10]; er y navnet på arrayen, og X er klassen som referansene i arrayen kan peke på. Navnet velger vi fritt, men klassenavnet vi oppgir før likhetstegnet, må være likt det som kommer etter. Det betyr at «String register[] = new int[10]» blir galt, da vi bruker String på den ene siden og int på den andre.

Todimensjonal array En array kan ha flere dimensjoner. For eksempel vil en kinosal ha et gitt antall rader, og et gitt antall seter per rad. Vi kan bruke to-dimensjonale arrayer til å representere dette. I slike tilfeller benyttes ofte doble løkker for å skrive ut innholdet. La oss se på et eksempel:

import inf101.*; class Todimensjonalt { public static void main(String[] argv) { Inn stdin = new Inn ( ); int x, y, verdi, tall = 10;

42

int kine[][] = new int[10][10]; while (tall > 0) { System.out.println("Du har " + tall + " innlesinger igjen"); System.out.print("Oppgi x koordinat (0-9):"); x = stdin.inInt( ); System.out.print("Oppgi y koordinat (0-9):"); y = stdin.inInt( ); System.out.print("Oppgi verdi :"); verdi = stdin.inInt( ); kine[x][y] = verdi; tall--; // "tall--" er det samme som tall = tall-1; } // gjennomløp av to-dimensjonal array med while-løkke for (int x=0; x<10; x++ ) { // starter på rad 0 for (int y=0; y<10; y++ ) { // på hver rad, start i kol. 0 System.out.print (kine[x][y] + " "); } System.out.println ( ); // sørger for ny linje for hver rad } } }

Hva er en hashtabell? Hashtabeller brukes for å lagre objekter. De likner på arrayer, men det er en del forskjeller:

• Vi kan legge et vilkårlig antall elementer i en hashtabell. Vi trenger ikke oppgi størrelsen på forhånd.

• Rekkefølgen bevares ikke i en hashtabell. Når vi går igjennom en hashtabell, må vi regne med

at elementene kommer i vilkårlig rekkefølge.

• Vi brukte tall til slå opp i en array, det vil si at hvert element lå på en bestemt indeks i arrayen. I en hashtabell bruker vi en streng som nøkkel når vi skal finne tilbake til et objekt.

• Vi kan kun lagre referanser til objekter i en hashtabell. I arrayer kunne vi også lagre variable.

Hvordan bruke en hashtabell Når vi ønsker å benytte hashtabeller i et program, må vi importere pakken java.util i programmet vårt. Det gjør vi ved å skrive følgende linje helt øverst i programkoden:

import java.util.*; Vi kan tenke oss at vi har en klasse Person, og en referanse p som refererer til et objekt av denne klassen.

class Person { String navn, String adresse, String telefonnr; } p = new Person( ); p.navn = "En Student" p.adresse = "EttStedIOslo" p.telefonnr = "22222222"

Vi skal nå se på hvordan vi kan legge inn et slikt objekt i en hashtabell, hente det tilbake, og fjerne det.

43

En hashtabell er et objekt, og opprettes på samme måte som andre objekter:

HashMap register = new HashMap( ); Når vi skal legge en referanse til person-objektet inn i hashtabellen (med referanse register), skriver vi:

register.put( navn, p ); Det vi egentlig legger inn, er en peker til objektet, ikke objektet selv. Vi kan ha mange pekere til et objekt. Disse pekerne kan ligge i forskjellige hashtabeller. For å legge en peker inn i en hashtabell bruker vi altså metoden put(). Den første parameteren til metoden er nøkkelen som identifiserer objektet. I dette eksemplet er nøkkelen navnet på personen. Den andre parameteren er referansen til objektet som skal lagres. Legg her merke til to ting :

• Nøkkelen (navn) må være unik. Dersom vi senere legger inn et objekt med en nøkkel som allerede ligger i hashtabellen, vil den referansen som lå der bli overskrevet, og den nye vil legges inn isteden. Metoden put() returnerer pekeren som lå der før, slik at vi f.eks. kan plassere den et annet sted. Hvis vi sammenlikner dette med en array, kan vi tenke oss nøkkelen som indeksen. Vi kan ikke legge flere ting inn på samme indeksen i en array. Tilsvarende kan vi ikke ha flere objekter i en hashtabell med samme nøkkel.

• I INF101 holder vi oss til at nøkkelen skal være en streng. I virkeligheten kan nøkkelen være

et hvilket som helst objekt. Det betyr at om vi er så uheldige å skrive «register.put( p, navn)», gir ikke dette kompilerings- eller kjørefeil, men resultatet blir neppe som forventet når vi senere prøver å hente fram objektet. Dette er en feil som er vanlig å gjøre! Husk derfor at nøkkelen er den første parameteren til put().

Vi bruker hashtabellens metode get(nøkkel) for å hente et objekt fra tabellen.

p = (Person) register.get( nøkkel ); Nøkkelen identifiserer objektet som skal hentes ut. Legg merke til at det står «(Person)» før metoden. I denne parentesen står navnet på klassen som objektet i hashtabellen er laget fra. Når vi henter ut et objekt fra en hashtabell, blir ikke objektet fjernet fra hashtabellen, og vi kan bruke get(nøkkel) så mange ganger vi måtte ønske. Dersom vi ønsker at et objekt ikke lenger skal ligge i en hashtabell, bruker vi metoden remove(nøkkel) i hashtabellen.

register.remove( nøkkel ); Her blir objektet i hashtabellen med nøkkel som identifikator fjernet.

Hvordan finne ut om et objekt ligger i en hashtabell Metoden containsKey(nøkkel) i hashtabellen kan brukes til å se om det eksisterer et objekt i tabellen med en gitt nøkkel.

if (register.containsKey( nøkkel ) ) { gjør noe }

44

Hvordan gå gjennom alle elementer i en hashtabell (Iterator) Da vi skulle gå gjennom alle indekser i en array, brukte vi en for-løkke. For å kunne behandle alle elementene i en hashtabell går vi fram på følgende måte:

• Først lager vi en mengde av alle pekere i hashtabellen ved hjelp av metoden values(). • Så lager vi en oppramsing (Iterator) av elementene i denne mengden ved hjelp av metoden

iterator( ). Disse to skrittene gjøres i én operasjon:

Iterator it = register.values( ).iterator( ); it inneholder nå en oppramsing av referanser til alle objekter i hashtabellen, samt metoder for å hente disse. Metodene er:

• hasNext() Dette er en boolesk metode som returnerer sant så lenge det finnes objekter som ikke har vært hentet.

• next()

Returnerer en peker til neste «uleste» objekt. Husk at hash-tabeller ikke har en bestemt rekkefølge på objektene.

Følgende eksempel illustrerer et gjennomløp av alle lementene i en HashMap:

Iterator it = register.values( ).iterator(); Person p; while (it.hasNext( )) { p = (Person) it.next( ); }

Legg merke til at vi, i likhet med get-metoden, må angi hvilken type objekt vi henter ut. Man kan også hente ut en oppramsing (iterator) av alle nøklene i hashtabellen, om man har bruk for dem. Da brukes metoden keySet( ) som er implementert i hashtabellen. Her er et eksempel:

Iterator it = register.keySet().iterator(); Person p; while ( it.hasNext()) { p = (Person) register.get ( (String) it.next( )); }

Disse eksemplene er nokså like. De henter begge ut objekter fra hash-tabellen, men den første metoden henter dem direkte, den andre henter dem ved hjelp nøklene og get-metoden. Skal man ha tak i objektene, så er den første metoden å foretrekke. Men det kunne jo tenkes at man ville hente ut objektene i sortert rekkefølge der nøklene er sorteringskriterium. Da kan man hente ut nøklene først, sortere dem og deretter hente ut objektreferansene i den sorterte rekkefølgen

Et stort eksempel I dette avsnittet gir vi deg et eksempel som inneholder bruk av både iterator-og keySet-metoden.

import java.util.*; import inf101.*;

45

class Hasheksempel { public static void main(String[] argv){ Inn in = new Inn( ); String nøkkel; Person p; HashMap register = new HashMap( ); Iterator it; int ant; System.out.print ("Antall personer som skal registreres : "); ant = in.inInt(); for (int i=0; i <ant; i++) { System.out.println("Antall personer igjen å registrere " + (ant - i)); p = new Person(in); register.put(p.telefonnr, p); } // Den mest vanlige måten, bruker iterator( ); System.out.println("Viser alle personer : "); it = register.values( ).iterator(); while (it.hasNext( )) { p = (Person) it.next( ); p.skrivData( ); } /* En alternativ måte, bruker keySet( ). Vi har tatt * den med for å demonstrere bruken av get( ). */ System.out.println("Viser alle personer v.h.a keys( ): "); it = register.keySet( ).iterator(); while (it.hasNext( )) { nøkkel = (String) it.next( ); p = (Person) register.get(nøkkel); p.skrivData( ); } } } class Person { String navn, adresse, telefonnr; Person(Inn in) { System.out.print ("Oppgi navn : "); navn = in.inStringln( ); System.out.print ("Oppgi adresse : "); adresse = in.inStringln( ); System.out.print ("Oppgi telefonnummer : "); telefonnr = in.InStringLn( ); } void skrivData( ) { System.out.println("Navn : " + navn); System.out.println("Adresse : " + adresse); System.out.println("Telefonnummer : " + telefonnr); } }

46

Valg mellom bruk av array eller hashtabell Egenskapene til array kan kort oppsummeres slik:

• lengde. Den er fast, når den først er etablert. Lengden kan ikke endres underveis. Man kan eventuelt holde en oversikt over antallet elementer som er brukt ved hjelp av en int-variabel.

• lagring. En array kan bare lagre en bestemt type, f.eks. bare int-verdier eller bare objektreferanser til objekter av en bestemt klasse

• ordning. Elementene ligger i en gitt rekkefølge nummerert fra 0 og til maks-1. En array kan være fler-dimensjonal.

• gjennomløp av en array foregår ved en enkel for-løkke. • sette inn objekt eller verdi, foregår ved enkel tilordning. Man må eventuelt oppdatere

antallet. • ta ut objekt eller verdi, skjer ved tilordning og eventuell flytting, samt oppdatering av antall. • søking. Ingen andre muligheter enn ved gjennomløp.

Tilsvarende egenskaper for HashMap kan kort oppsummeres slik:

• lengde. HashMap har ubegrenset lengde. Antall elementer er gitt ved metoden size(). • lagring. En HashMap kan bare lagre objektreferanser. Disse kan til gjengjeld være til objekter

av en hvilken som klasse. • ordning. Elementene i en HashMap har ingen ordning. • gjennomløp av HashMap foregår ved bruk av interface Iterator. • sette inn objekt. HashMap bruker metoden put som har parametrene nøkkel og

objektreferanse. • ta ut objekt. HashMap har metoden remove (med nøkkel som parameter) • søking. HashMap har metoden get med nøkkel som parameter.

Når vi skal velge om vi skal bruke array eller HashMap, kan det være lurt å ta utgangspunkt i disse egenskapene. Skal vi lagre et bestemt antall (eller et maks antall) som skal være kronologisk ordnet, peker array seg ut. Om vi ønsker kronologi med et ubestemt antall er det ikke alltid gitt hva vi skal velge, men det ubestemte antallet peker i retning av HashMap, men vi kan løse det ved å operere med to arrayer som dataene blir flyttet mellom. Når utvidelsesbehovet kommer defineres en array med tilstrekkelig og dataene flyttes over. Denne operasjonen gjentas når nytt behov melder seg. Ved behov for søking eller gjenfinning etter et bestemt kriterium er det naturlig å bruke HashMap enten antallet er fast eller ubestemt.

47

Kapittel 9 – Klasse/objekt-diagrammer Et klasse/objekt-diagram er et visuelt hjelpemiddel for å holde oversikt over objektene som dannes når et program utføres. Et slikt diagram gir både oversikt over hva slags type objekter man har (dvs hvilke klasser de tilhører), og hvordan objektene er knyttet til hverandre (dvs hvilke objekter som har referanser til hvilke objekter). I tillegg forteller diagrammet hvilke variable, referanser og metoder som finnes i de forskjellige objektene. Vi kan tenke på et klasse/objekt-diagram som et øyeblikksbilde (snapshot) av objektene under programeksekveringen. Det som ikke fremgår av et slikt diagram er hva som skjer inni hver enkelt metode og følgelig heller ikke programmets oppførsel over tid. De viktigste elementene som benyttes i et klasse/objekt-diagram er vist i figuren under. De viktigste reglene for konstruksjon av klasse/objekt-diagrammer er:

• Variable, referanser og metoder som ikke er static tegnes inni objektet de tilhører. • Variable, referanser og metoder som er static tegnes inni klassen de tilhører. • Referanser angis ved hjelp av referansesymbolet i figur 1, samt en pil ut fra referansesymbolet

til et objekt av den typen det refereres til. • Det er ikke nødvendig å tegne klassesymbolet for alle klassene i programmet, kun for de

klassene som inneholder static variable, referanser eller metoder (f.eks. metoden main), samt for de klassene som opptrer som subklasser eller superklasser til andre klasser i programmet.

• Når både en klasse og tilhørende objekter tegnes, angis forbindelsen mellom dem med en rett

linje mellom klassesymbolet og hver av objektsymbolene. • Når en klasse er en direkte subklasse av en annen klasse, angis forbindelsen mellom dem med

en rett linje som forgrener seg i tre i enden som vender mot subklassen.

Klassenavn Klassenavn

variabelnavn referansenavnmetodenavn metodenavn

Klasse Objekt

Variabel Referanse Metode(private)

Metode(public)

Array HashMap

48

Eksempel 1 Betrakt følgende program:

class BokEksempel { public static void main (String [] args) { Bok b = new Bok(); } } class Bok { String tittel, forfatter; Bok() {...} void SkrivUt() {...} }

Det tilhørende klasse/objekt-diagrammet ser slik ut:

Eksempel 2 Følgende eksempel illustrerer en en-til-en relasjon mellom objekter:

Person

partner

Person

partner

BokEksempel

main

Bok

Bok

tittel forfatter

skrivUt

”Reiseskildringar frå Bandar Seri Begawan” ”Muara Tutong”

b

49

Eksempel 3 Følgende eksempel illustrerer en en-til-mange relasjon mellom objekter (ett kurs har mange studenter).

Eksempel 4 Følgende eksempel illustrerer en mange-til-mange relasjon mellom objekter (hvert kurs har mange studenter, og hver student kan ta flere kurser).

Eksempel 5 Følgende eksempel illustrerer subklasse-relasjoner. Vi har Java-programmet

class Person { .... } class Student extends Person { .... }

I dette tilfellet får vi klasse/objekt-diagrammet til høyre.

Kurs

påmeldte

Student

”Karin F. Ormatik”

påmeldte

Kurs

kurser

Student

"Anne Knutsdotter" "INF101"

Person

Student

50

51

Kapittel 10 - Filbehandling – Inn- og Ut-klassene Fram til nå har vi laget programmer hvor alle verdier går tapt i det programmet er ferdig. I dette kapitlet skal vi lære å ta vare på verdier mellom programkjøringer. Til dette bruker vi filer. Verdiene, eller dataene, lagres som tekst. Når vi senere skal lese fra filen må disse dataene tolkes, dvs. at vi må vite hva de representerer. En datafil fra et tenkt bilregister kan se slik ut:

Peder Ås Toyota DF212233 Pia Prill VW DC113322 ... ... Aud-Georg Volvo AH203902

Her er det lagret opplysninger om personer, og bilene de eier. For hver person i registeret følger det én linje med bilmerket, og én linje med registreringsnummeret på bilen. Det er ingen bestemt rekkefølge på personene i filen (det kan godt være det). Opplysninger om en eier og bil, utgjør tilsammen 3 linjer. Disse 3 linjene kalles en post (record). De to linjene med prikker symboliserer et vilkårlig antall poster.

Skrive til fil Å skrive til fil likner svært på å skrive til skjerm, men vi trenger et rammeverk rundt for å få det til å fungere. Vi lager da et objekt av Ut-klassen som en kopling mellom programmet og filen. Ut-klassen ligger i verktøykassen til inf101 og blir importert sammen med den.

import inf101.*; class LagRegister { public static void main(String[] args) { Ut fout = new Ut("register.text"); fout.outStringln("Peder Ås"); fout.outStringln("Toyota"); fout.outStringln("DF212233"); fout.close( ); } }

Dette programmet fører til at det lages en fil som heter «register.text», og at første post (om Peder Ås) skrives til filen. Det er en helt vanlig tekstfil som lages, og vi kan lese innholdet i den ved hjelp av en teksteditor (f.eks. emacs). For å skrive til fil, må følgende være med:

1. import inf101.*; Som for innlesning fra tastatur importeres her hjelpeverktøyet vi skal bruke.

2. Ut fout = new Ut( "register.text" );

52

Her lages filen vi skal skrive til. Filen får navnet filnavn ( i dette eksemplet "register.text"). Hvis det fins en fil med samme navnet fra før, vil den bli overskrevet. Metodene for skriving til fil befinner seg i et objekt av typen Ut. Referansen til objektet har vi kalt fout.

3. fout.close( ); Etter at vi er ferdige med å skrive til filen, må vi lukke den. Hvis vi glemmer dette, hender det at filen ikke inneholder noe som helst når programmet er ferdig. Selve utskriften skjer på linjene

fout.outStringln("Peder Ås"); fout.outStringln("Toyota"); fout.outStringln("DF212233");

Metoden outStringln fungerer tilsvarende som println ved utskrift til skjerm. Hvis du ikke ønsker å skrive ut linjeskift, kan du bruke metoden outString istedenfor outStringln.

Formatering av tall for utskrift Ved utskrift av tall til skjerm ønsker vi ofte at tallene skal komme pent under hverandre, med komma på samme plass. Ut-klassen kan hjelpe oss med dette. Klassen har metoder for utskriving av heltall (outInt) og for flytende tall (outDouble). For heltall skal metoden ha to parametre, tallet som skal skrives ut, og antall plasser som skal brukes. For reelle tall skal den i tillegg ha antall plasser etter komma. La oss se på bruken:

import inf101.*; class TallFormat { public static void main(String[] args) { Ut u = new Ut( ); int i = 12345; int j = 1234; double pi = 3.1415927; double e = 2.718; u.outInt (i, 5); u.outln(); u.outInt (j, 5); u.outln(); u.outDouble (pi, 10, 4); u.outln(); u.outDouble (e, 10, 4); u.outln(); } }

Dette programmet gir følgende utskrift: 12345 1234 3,1416 2,7180 Legg merke til at ved formateringen av reelle tall er kommaplassen inkludert i antall plasser. Derfor må vi sette av 10 plasser for de reelle tallene (4 etter komma, 1 for komma og 5 før komma). Legg også merke til at formatering av reelle tall fører til avrunding. Flere utskriftsmetoder er beskrevet tillegget bakerst i dette heftet.

53

Lese fra fil Det følgende eksemplet forutsetter at det finnes en fil med navn «register.text» på samme området som programmet ligger.

import inf101.*; class LesRegister { public static void main(String[] args) { String tekst; Inn fin = new Inn( "register.text" ); tekst = fin.inString( ); System.out.println("Det som ble lest inn fra filen var: " + tekst); } }

Resultatet av dette programmet er at teksten «Peder» blir lest inn fra filen og skrevet ut til skjermen. Som for innlesing fra tastatur benytter vi også her objekter av typen Inn, men der det tidligere var parameterløst, skriver vi nå inn navn på filen i doble anførsler, som en String. Objektet lages med linjen:

Inn fin = new Inn ( "register.text" ); Her er "register.text” filen vi ønsker å lese fra. Metodene for innlesing fra fil fungerer tilsvarende som for innlesning fra tastatur. Når du begynner å lese fra en fil, starter du alltid på toppen av filen. Vi kan tenke oss en «lesemarkør» som er knyttet til referansen vår. Denne holder rede på hvor vi befinner oss på filen. Hver gang vi leser fra filen, flyttes markøren til neste uleste tegn på linjen evt. til neste uleste linje. Vi nevnte noen lesemetoder i kapitlet om innlesing fra tastatur. Disse kan også brukes ved lesing fra fil. En fullstendig beskrivelse av lesemetoder fins i tillegget bakerst i dette heftet.

Teste om slutten av filen er nådd Det er ikke mulig (lov) å lese forbi slutten av en fil, og når vi programmerer må vi ta hensyn til dette. Det er to teknikker som kan brukes; hvilken som passer avhenger av om man ønsker å lese linjevis eller itemvis fra fil: 1) Hvis man leser linjevis fra fil brukes endofFile for å teste om man er kommet til slutten av filen,

slik som i følgende eksempel:

String linje; Inn fin = new Inn("tekstfil.txt"); while (!fin.endOfFile()) { linje = fin.inStringln(); ...Gjør noe med den leste linjen...

}

2) Hvis man leser itemvis fra fil brukes lastItem for å teste om man er kommet til slutten av filen, slik som i følgende eksempel:

int tall; Inn fin = new Inn("fil.txt"); while (!fin.lastItem()) { tall = fin.inInt(); ...Gjør noe med det innleste tallet...

54

}

Om filstruktur Når du skriver til fil, er det som oftest fordi du senere (neste gang programmet starter) skal lese fra den samme filen. Derfor er det lurt å legge litt arbeid i utarbeidingen av filstrukturen. Med filstruktur menes hvordan du velger å organisere teksten på filen. Ting du bør tenke over er:

• Skal du ha flere typer av opplysninger pr. linje? • I hvilken rekkefølge bør opplysningene ligge? • Er det slik at hvert felt inneholder like mange linjer, eller kan antallet variere? • Hvis antallet linjer på et felt varierer — hvordan skal jeg vite når et felt slutter og neste

begynner. Det er ingen klare regler og holde seg til her. En datastruktur kan skrives ut til fil på mange forskjellige måter, men hvis du tenker nøye gjennom filstrukturen, vil innlesingen fra filen som regel bli lettere. Det er f.eks. mye lettere å lese inn en filen først i dette kapitlet enn en fil som ser slik ut:

Peder Ås Toyota DF212233 Pia Prill VW DC113322 Kåre B. Rangel Polo EF332211 ... ...

De to første linjene går greit, men hva skjer på tredje linje? Her er det fort gjort at «Rangel» blir registrert som bilmerket og «Polo» som registreringsnummer. På fil skriver vi ikke hva dataene representerer. Det ligger implisitt i filstrukturen. Vi skriver altså ikke:

Navn: Peder Ås Bilmerke: Toyota Reg.: DF212233 50

Array og filer Når vi ønsker å skrive innholdet i en array til fil, er det ofte enklest å ha en for-løkke som går igjennom alle elementene i arrayen, og skriver dem til fil, en etter en. På denne måten blir innholdet i arrayen lagret i riktig rekkefølge på filen, noe som gjør innlesningen enkel. Vi trenger altså ikke lagre elementets posisjon i arrayen når vi gjør det på denne måten. Når vi ønsker å lese inn dataene fra filen, bør vi også ha en teller som økes for hvert element som blir lest inn. Dersom vi ser på eksemplet i avsnitt 8.5 på side 48, vil vi etter kallet «person.fraFil(fin)» kunne lagre referansen til person i en array, og øke indeksen i arrayen med 1, slik at neste gang vi kom hit, ble neste referanse lagret på neste posisjon i arrayen.

Hashtabell og filer Vi bruker Iterator sammen med en while-løkke for å skrive ut alle elementene i en hashtabell. Det samme gjør vi når vi ønsker å lagre alle elementene til fil. Det kan ofte være lurt å lagre nøklen fra hashtabellen før resten av dataene i objektet. Før du skriver ut elementene i hashtabellen kan det også være lurt å skrive ut antall elementer i hashtabellen, slik at du ved innlesing vet hvor mange objekter som skal leses. Metoden size( ) i hash-objektet gir deg dette tallet.

55

Kapittel 11 - Unntak (exceptions) Når man programmerer, oppstår det ofte feil. Noen feil skyldes at framgangsmåten i programmet er feil. Slike feil må du selv finne og rette, f.eks. ved å teste programmene grundig. Av og til kan du midlertid få feil som likner på dette:

…\Unntak3.java.9: Exception java.io.IOException must be caught, or it must be declared in the throw clause of this method. message = stdin.readLine();

eller på dette:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0 at Testunntak.<init><Testunntak.java:6> at Testunntak.main<Testunntak.java:3>

Feilmeldingene kan se uforståelige ut, men det er mye informasjon å hente fra dem. Java-språket har en feil-mekanisme som kalles Exceptions (unntak). Den er bygget opp slik at metoder kan si fra til kallstedet at det har skjedd noe unormalt i metoden. Det kan også skje en anormal situasjon under kjøring av programmet som resulteter i en Exception-beskjed. På det programstedet der unntaket blir meldt, kan man så håndtere denne beskjeden. Slike unntak faller i to grupper:

• den første gruppa blir oppdaget av kompilatoren. Den første feilmeldingen over er et eksempel på et slikt unntak. I feilmeldingen angis hvilken Exception det gjelder og hvilken programsetning i programmet det gjelder. I dette tilfellet gjelder det IOException, altså noe som har med lesing og skriving å gjøre (til fil eller skjerm, IO = Input/Output). Programsetningen er : message = stdin.readLine( );.

• den andre gruppa kommer under kjøring av programmet (RuntimeExceptions). Den andre feilmeldingen er et eksempel på dette. Her angis at det er noe galt med en array-indeks (ArrayIndexOutOfBoundsException), hvilken verdi som ikke er akseptabel (0) og hvilke linjer i programmet som leder fram til feilen (konstruktøren til testunntak, konstruktøren blir kalt i main-metoden, linjenummer i java-filen blir også angitt)

Programstedet (enten det er et kall eller noe annet) ligger alltid inne i en metode og håndteringen av unntaket kan skje enten ved å programmere slik at programmet håndterer unntakssituasjonen på stedet, eller ved å gi beskjed videre til neste kallsted, kanskje helt ut av programmet, til JVM. Unntaksbeskjeden kommer i form av et objekt av klassen Exception eller en subklasse av denne. Metoder som gir unntaksbeskjeder har definert unntaket som en del av metodesignaturen:

void lesfrafil ( ) throws IOException { ... } Denne metoden, som skal lese fra fil, kan altså kaste (throws) et unntak som man på kallstedet må gjøre noe med eller sende videre. IOException er en subklasse av Exception.

Sende unntaket videre Om vi tenker oss at lesfrafil-metoden blir kalt fra en metode innlesing, så kan unntaket kastes videre ved å definere innlesing slik:

56

void innlesing ( ) throws IOException { ... lesfrafil( ); ... }

På denne måten kan altså innlesing fraskrive seg ansvaret for unntaket og overlate det til en kallende metode. Om innlesing ble kalt fra konstruktøren til en klasse, kunne vi også la konstruktøren kaste unntaket videre, kanskje helt til main-metoden og derfra til JVM.

Fange unntaket Vi kan også velge å behandle unntaket istedenfor å sende det videre. Vi kan betrakte en metode som "farlig" fordi den kaster unntak og velge å plassere den inne i en programkonstruksjon som prøver den, en try-catch- konstruksjon. I eksemplet innlesing ville det se slik ut:

void innlesing ( ) { ... try { lesfrafil( ); } catch ( IOException e ) { System.out.println ( "Feil ved lesing fra fil."); } ... her fortsetter programmet enten det skjer feil eller ei }

Siden innlesing nå behandler unntaket, trenger den ikke kaste det videre og de metodene som kaller innlesing behøver heller ikke ta hensyn til unntaket.

Mer enn ett unntak En metode kan kaste flere unntak og i metodedeklarasjonen kan man ramse opp disse etter throws. Unntakene skilles av komma:

void lesfrafil ( ) throws IOException, StringIndexOutOfBoundsException { ... }

Når en metode kaster flere unntak, kan man velge å kaste alle videre, behandle alle på stedet, eller kaste noen videre og behandle noen. Om man velger å behandle flere unntak på kallstedet må try-setningen utvides med flere catch-greiner:

void innlesing ( ) { ... try { lesfrafil ( ); } catch ( IOException e ) { System.out.println ( "Feil ved lesing fra fil."); } catch ( StringIndexOutOfBoundsException e ) { System.out.println ("Indeksfeil: "); System.out.println ( e.getMessage( ) ); } ... her fortsetter behandlingen etter et catch }

Det er bare setningene som ligger inne i den spesifikke catch-greina som blir utført. Deretter fortsetter programmet nedenfor alle catch-greinene.

57

Legg merke til den siste catch-greina der vi skriver ut en melding som pleier å følge et unntak. Vi får tak i meldingen ved å kalle på unntaksobjektets metode getMessage( ). En rekke av catch-greiner kan avsluttes med en finally-grein som blir utført uansett hva slags unntak vi fanger og bare om det kommer et unntak. Ønsker vi for eksempel alltid å skrive ut unntaksmeldingen, kan vi gjøre slik (med utgangspunkt i eksemplet over):

void innlesing ( ) { ... try { String melding; lesfrafil ( ); } catch ( IOException e ) { System.out.println ( "Feil ved lesing fra fil."); melding = e.getMessage(); } catch ( StringIndexOutOfBoundsException e ) { System.out.println ("Indeksfeil: "); melding = e.getMessage(); } finally { System.out.println ( melding ); // gjelder alle catch-blokker } ... her fortsetter vi }

Det er også mulig å fange et unntak, utføre noen programsetninger og deretter kaste det videre. Man må da huske på å ta med throws-delen i metodesignaturen:

void innlesing ( ) throws StringIndexOutOfBoundsException { ... try { lesfrafil ( ); } catch ( IOException e ) { System.out.println ( "Feil ved lesing fra fil."); } catch ( StringIndexOutOfBoundsException e ) { System.out.println ("Indeksfeil: "); System.out.println ( e.getMessage( ) ); throw e; } ... her fortsetter behandlingen etter det catch-et som ikke blir kastet videre. }

Exceptions kompilatoren oppdager Nedenfor gjengis de viktigste unntakene som blir kontrollert av kompilatoren. Disse må du enten må kaste videre eller behandle med en try-catch-konstruksjon. Navnet på unntaket sier noe om hva det gjelder:

ClassNotFoundException IOException NoSuchFieldException NoSuchMethodException

Det fins noen flere unntak av denne typen, men du vil neppe støte på dem i INF101. I dokumentasjon av API-metodene fins det opplysning om hvilke exceptions som blir kastet.

58

Exceptions under kjøring Nedenfor gjengis de vitigste unntakene som kan forekomme under kjøring av programmet, de blir ikke kontrollert av kompilatoren:

ArithmeticException ArraryIndexOutOfBoundsException ClassCastException IndexOutBoundsException NegativeArrarySizeException NullPointerException NumberFormatException StringIndexOutOfBoundsException

Det fins også noen flere av denne typen unntak, men de er lite aktuelle i INF101.

Inn- og Ut-klassen Disse klassene håndterer alle unntak som kan oppstå ved lesing og skriving til fil eller skjerm og gir i stedet forståelige feilmeldinger på skjermen. Bruker du Inn- og Ut-klassen, vil du aldri oppleve unntak direkte.

59

Kapittel 12 - Mer om metoder

Hva er parametre? Parametre er variabler i en metode som får sin verdi satt når metoden kalles. Verdiene blir sendt over til metoden mellom parentesene etter metodenavnet.

Hvordan brukes parametre? Parametrene deklareres inne i parentesen som følger etter metodenavnet på det stedet metoden deklareres. Dersom det er flere parametre, skilles deklarasjonene med komma. Merk at for hver parameter som deklareres, må vi oppgi type, til forskjell fra deklarasjon av variabler, der vi kunne skrive «int x, y, z». Skal vi deklarere disse tre variablene som parametre, må vi altså skrive «(int x,int y, int z)». Dette kalles for «formelle parametre». Når vi bruker metoden annet sted i programmet, må vi oppgi verdier for parametrene. De må komme i samme rekkefølge og ha samme type som på det stedet metoden blir deklarert. Verdien til parametrene oppgir vi i parentesen til metodekallet. Disse kalles «aktuelle parametre».

Eksempel med parametre

public static void main(String[] argv){ Inn in = new Inn( ); int x, y; System.out.print ( "Oppgi x : "); x = in.inInt(in); System.out.print ( "Oppgi y : "); y = in.inInt(in); kalkulator2(x,y); } static void kalkulator2(int talla, int tallb) { int sum; sum = talla+tallb; System.out.println("Summen av " + talla + "og "+ tallb + "er:"+ sum); }

Vi har her forandret litt på deklarasjonen av, og kallet på metoden kalkulator. Det vi har gjort, er å gi metoden kalkulator to parametre, nemlig talla og tallb. Legg merke til at det ikke trenger å være samsvar mellom navnet på parameteren i kallet og deklarasjonen av metoden. Det må derimot være samsvar mellom typen på parameteren.

Hva skjer når vi bruker parametre Når metodekallet kalkulator2(x,y) blir utført, vil innholdet i variablen x bli lagt inn i talla, og innholdet i variablen y bli lagt i tallb. Mer generelt vil innholdet i den første parameteren i kallsetningen, bli lagt inn i den første parameteren som står i metodedeklarasjonen; den andre parameteren i kallsetningen blir kopiert til den andre parameteren i deklarasjonssetningen, osv. Derfor må parameteren på kallstedet være av samme type som den tilhørende parameteren i metodedeklarasjonen. Sagt på en annen måte: Den formelle og aktuelle parameteren må være av samme type. Hvis vi f.eks. prøver å legge en streng i en parameter som er av typen int, vil ikke dette fungere.

60

Metodene har sin egen kopi av variabelverdiene, og ting som skjer med verdiene inne i metoden får ingen konsekvenser for variabelverdiene til de aktuelle parametrene.

Returverdier

Hva er returverdier? En returverdi er en verdi som metoden gir tilbake som et resultat av sin behandling. Denne verdien kan brukes direkte på kallstedet, som om det var en variabel av en bestemt type. I dette ligger det også at metoden må typedeklareres dersom den skal returnere en verdi av en viss type. En metode kan ikke returnere mer enn én verdi, men denne verdien kan være en objektreferanse, en array, en hashtabell eller en av de primitive typene, int, double, boolean osv.

Hvordan brukes returverdier? Verdien som skal returneres, oppgis ved å bruke setningen:

return uttrykk ; Metoden får da den verdien som er resultatet av uttrykket i return-setningen. Når programutføringen kommer til en return-setning, avsluttes metoden, og programmet «hopper» tilbake til kallstedet. Programkode som står etter en returnsetning, blir derfor ikke bli utført. Isteden for å skrive void før metodenavnet (i deklarasjonen av metoden), skriver vi typen på returverdien som skal returneres. Legg merke til at metoder som har returverdi, kan være parametre til en annen metode. Dersom dette er tilfellet, vil metoden som står som parameter bli utført først. Returverdien til denne metoden blir så brukt som parameter til neste metode.

Eksempel på returverdier

public static void main(String[] argv) { Inn in = new Inn( ); int x,y,res; System.out.print ("Oppgi x : "); x = in.inInt(in); System.out.print ("Oppgi y : "); y = in.inInt(in); res = kalkulator3(x,y); System.out.println("Summen av " +x + "og " + y + "er :"+ res); } static int kalkulator3(int talla,int tallb) { int sum; sum = talla+tallb; return sum; }

Legg merke til at vi ikke skriver «return (sum)». Selv om det er lov å sette parentes rundt uttrykket som returneres, anbefales det ikke. Det fører ikke til kompileringsfeil, men det kan fort føre til feiltolkinger av typen «return er et metodekall med parameteren sum», noe som ikke stemmer. Vi må passe på at metoden returnerer det den er deklarert til å returnere. Dersom vi har deklarert metoden til å returnere int, må uttrykket i return-setningen resultere i en int. Da er det ikke lov å

61

utelate returnsetningen. Det er heller ikke lov å returnere noe annet enn en int. De metodene som ikke behøver å ha noen returverdi er metoder av typen void. Void betyr som sagt at metoden ikke har noen returverdi.

Hva skjer når vi bruker returverdier? Vi ser først på linja

res = kalkulator3(x,y); Dette er en tilordningssetning, og i tilordningssetninger vil det som står på høyre side av tilordningstegnet (’=’) bli utført først, dvs. at vi starter metoden kalkulator med parameterene x og y. Når programutføringen kommer til linja

return sum; vil metoden avslutte, og kalkulator(x,y) får verdien som ligger i variabelen sum. Høyre side av tilordningstegnet er da ferdig beregnet, og resulatet legges i variabelen res.

Eksempel på bruk av metoder Metoder brukes blant annet til å få bedre oversikt i programmet. Dersom vi har et program som skal kunne utføre forskjellige oppgaver, er det nyttig å lage en metode for hver av oppgavene. Følgende program er en skisse til hvordan dette kan gjøres, og kan brukes som ramme til en mengde programmer i INF101. Du trenger ikke forstå alt som skjer i dette eksemplet, det du bør se på er deklarasjonen av metodene og kall på metodene, resten vil bli forklart i kapitlet om klasser og objekter. Det du bør vite er at setningen

new TallTull( ); gjør at metoden TallTull blir kalt. Dette er en spesiell type metode som ikke skal ha returverdi, og heller ikke void.

import inf101.*; class TallProgram { public static void main(String[] argv) { new TallTull( ); } } class TallTull { Inn in; TallTull( ) { int valg,x; in = new Inn( ); do { meny( ); valg = lesTall("Valg :"); switch (valg) { case 1: siHei( ); break; case 2: skrivTall(lesTall("Tallet du vil ha skrevet ut : ")); break; case 3: x = giDobbeltTilbake(lesTall("Skriv et tall : "));

62

System.out.println("Det dobbelte av tallet er : " + x); break; case 4: System.out.println("Hade!"); break; default: System.out.println("Ugyldig valg, prøv på nytt"); break; } } while(valg!=4); // end do while } // end TallTull void meny( ) { System.out.println("1 Si hei"); System.out.println("2 Skriv tall"); System.out.println("3 Utfør en beregning"); System.out.println("4 Avslutt "); } // end meny int lesTall(String melding) { System.out.print (melding); return in.inInt(in); } void siHei( ) { System.out.println("Hei!"); } void skrivTall(int tall) { System.out.println("Tallet var : "+tall); } int giDobbeltTilbake(int tall) { return tall * 2; } }

Konstruktører En konstruktør er en metode uten returverdi som automatisk blir kalt når et objekt lages —dvs. hver gang du bruker nøkkelordet new. Konstruktøren skal ikke ha type (ikke engang void) og skal ikke returnere en verdi. Navnet på konstruktøren er det samme som for klassen den står i. Konstruktører brukes for å initialisere objektet. La oss nå lage en ny klasse, Bil3. Innholdet i klassen er det samme som for Bil-klassen, men vi ønsker at ethvert bil-objekt som opprettes skal ha et registreringsnummer. For å oppnå dette lager vi en konstruktør som får teksten med registreringsnummer som parameter og tilordner den til variabelen regnummer.

class Bil3 { // variabler som for Bil // Konstruktør Bil3( String reg) { regnummer = reg; } // metoder som for Bil } class Trafikk3 { public static void main(String[] args) { Bil3 b3 = new Bil3("DF212233"); } }

63

På linjen

b3 = new Bil3("DF212233"); opprettes objektet, og parameteren til konstruktøren sendes med. Hver gang du bruker nøkkelordet new lager du et nytt objekt. Det som faktisk skjer, er at du kaller på konstruktøren til klassen. Returverdien (som du ikke skriver) til konstruktøren er en peker til objektet som ble laget. Da vi tidligere kunne skrive

b1 = new Bil( ); er det fordi alle objekter i utgangspunktet er utstyrt med en tom konstruktør9. I klassen Bil finnes det altså en konstruktør med en tom parameterliste som vi slipper å skrive selv. Denne konstruktøren omtales som standardkonstruktøren (på eng. default constructor). I eksemplet fra kap. 6.9 er det ikke lenger mulig å kalle på den tomme konstruktøren. Når vi selv lager en konstruktør forsvinner standardkonstruktøren. Hvis vi ønsker, kan vi skrive den selv. Innholdet i konstruktøren kan da være den initialiseringen vi ønsker utført når objektet blir laget.:

Bil3( ) { regnummer = "Ukjent!"; }

Som for metoder, er det altså mulig å ha flere konstruktører. De skilles fra hverandre ved at de formelle parametrene er ulike ( i antall og/eller type).

Om public og private En av hensiktene med objektorientert programmering er å skjule implementasjonen av de forskjellige objekter og klasser. Det betyr at vi ikke ønsker å gi andre tilgang til objektets variabler. Hvis vi, under utviklingen av programmet, skulle ønske å forandre navnet på en variabel, er det en fordel å kunne gjøre det uten at vi må gjøre forandringen i andre klasser som bruker objektet. Dette gjøres ved at vi skjermer variablene for omverdenen med nøkkelordet private. Når det står private før en variabel (eller metode) er det bare objektet selv som har tilgang til den. Hvis vi i Bil-klassen har en variabel som viser hvilket gir bilen er i, ønsker vi ikke at andre klasser skal kunne «tukle» med denne variabelen. I stedet gir vi tilgang til variabelen via en metode. I denne metoden kan vi passe på at bilen kun settes i «lovlige» gir. Hvis vi i tillegg returnerer en boolesk verdi, kan vi i Trafikkprogrammet få vite om giringen gikk som den skulle.

class Bil4 { // Variabel som hører til klassen static int antGir = 6; /* Variabel som lagrer i hvilket gir bilen er. * Når objektet opprettes er bilen i gir 0 (fri). Variabelen * er «gjemt» for omverdenen. */ private int gir =0; // Resten av variabler som for Bil /* Metode for å gire. «Lovlige» gir er: 1 for revers, * 0 for fri og 1 5 (antGir 1) for framover. Hvis

9 Den arves fra superklassen Object. Du kan lese om sub- og superklasser i kap. 11

64

* et lovlig gir velges returneres true ellers false. */ boolean settIGir(int girNummer) { if (girNummer >= 1 && girNummer <antGir) { gir = girNummer; return true; // Giring ok. } else { return false; // Giring ikke ok. } } // Resten av metoder som for Bil } class Trafikk4 { public static void main(String[] args) { Bil4 b4 = new Bil4( ); if (b4.settIGir(3)) { System.out.println("Bilen er satt i gir nr. 3"); } else { System.out.println("Bilen kunne ikke settes i gir nr. 3"); } if (b4.settIGir(6)) { System.out.println("Bilen er satt i gir nr. 6"); } else { System.out.println("Bilen kunne ikke settes i gir nr. 6"); } }

} Det motsatte av private er public. Hvis vi ønsker at alle andre javaprogrammer skal kunne se metoden (eller variabelen) bruker vi public foran metode- eller variabeldeklarasjonen. I dette kurset vil du normalt kunne klare deg nesten helt uten å bruke public. Det eneste stedet du må bruke den, er foran deklarasjonen av main. Det er fordi main( ) er en metode som kalles av systemet10. Hvis ikke metoden har full synlighet, kan ikke systemet «se» den og får heller ikke utført kallet på den. Av samme grunn må main også deklareres som static — altså som en klassemetode. På det tidspunkt hvor programmet starter er det ikke lagd objekter enda. Hvis main skal kunne kalles, må den derfor eksistere i klassen.

10 Egentlig av den virtuelle javamaskinen.

65

Kapittel 13 - Subklasser Tidligere har vi sett på klasser og objekter. Vi skal nå gå videre med dette, og se hvordan vi kan utvide klasser, og hvordan dette kan gjøre bruken av objekter enda mer fleksibel.

Hva er subklasser? En subklasse er en utvidelse av en eksisterende klasse (kalt superklassen), og får de samme attributter og metoder som superklassen (vi sier at «subklassen arver fra superklassen»). I tillegg kan subklassen utvides med egne deklarasjoner av attributter og metoder. Ettersom vi gir subklassen flere egenskaper, kan den sies å være en spesialisering av superklassen. En referanse som er deklarert til å referere til objekter av en gitt klasse, kan også referere til objekter av alle subklasser av denne. Denne egenskapen kan være til stor hjelp når vi programmerer. Følgende punktliste kan hjelpe deg til å huske hva subklasser er:

• En superklasse er den klassen som subklassen arver fra • Variabler som er deklarert i superklassene, vil arves til subklassene. Det betyr at når vi lager et

objekt basert på denne subklassen, vil objektet også inneholde de variablene som er deklarert i superklassen. Det er altså ingen grunn til å deklarere disse i subklassene.

• Metoder som deklareres i superklassen, vil arves til subklassene. Dersom vi deklarerer

metoden i subklassen, vil den overskygge deklarasjonen i superklassen. Om vi i superklassen skriver final foran metoden, kan vi ikke deklarere den i subklassene.

Hvordan lage subklasser Dersom vi ønsker å deklarere en klasse A, og en en klasse B som skal være subklasse av A, gjør vi dette ved å skrive:

class A { } class B extends A { }

Her er A superklassen til B, og klassen B er en subklasse av A.

Referanser og typekonvertering I kapitlet om objekter og klasser så vi på referanser til objekter. Disse referansene brukte vi til å få tilgang til metoder og variabler i objektet. La oss se på et eksempel på bruk av referanser når vi bruker subklasser. Vi utvider klassene A og B med noen variabler og metoder.

class A { int x; void skrivMelding( ) { System.out.println("Klasse A sier hei!");

66

} final void superMelding( ) { System.out.println("Nå kan klasse A si hei!"); } } class B extends A { int y; void skrivMelding( ) { System.out.println("Klasse B sier hei!"); } void test( ) { System.out.println("Metoden test sier hei!"); } //void superMelding( ) { // System.out.println("Her kan ikke klasse B si noe."); //} } class SubklasseTest { public static void main(String[] argv) { A aref; B bref; // Del 1 aref = new B( ); aref.x = 10; //aref.y = 20; går ikke, siden A-klassen ikke har y aref.skrivMelding( ); aref.superMelding( ); //aref.test( ); går ikke, siden A-klassen ikke har test() // Del 2 bref = (B) aref; bref.y = 20; bref.test( ); bref.superMelding( ); bref.x = 30; ((B) aref).test( ); } }

Vi tar for oss de forskjellige delene i programmet:

Del 1: Tilgang til variable og metoder • aref er deklarert til å referere til objekter av klassen A. Vi lager et objekt av klassen B, og

setter aref til å peke på dette. Det er mulig, siden B er en subklasse av A. • Variablen x er deklarert i klassen A, og arves til subklassen B. Dermed kan vi bruke variablen.

I dette eksemplet setter vi x lik 10. • Objektet som blir referert til av aref inneholder også variablen y. Ettersom y er deklarert i

klassen B, og aref er deklarert til å referere til objekter av klassen A, kan vi ikke bruke den ved å skrive «aref.y = 20;». Kun variable som er deklarert i klassen A, og superklasser til klassen A, vil være tilgjengelige på denne måten.

67

• Metoden skrivMelding( ) i klassen B overskygger metoden skrivMelding( ) i klassen A. Selv

om aref er deklarert til å peke på objekter av klassen A, er objektet det refererer til av klassen B. Metodekallet aref.skrivMelding( ) vil derfor utføre metoden som er deklarert i klassen B, og teksten «Klasse B sier hei!» vil bli skrevet ut.

• Metoden test( ) er ikke deklarert i klassen A, og kan derfor ikke kalles ved å skrive «aref.test(

)» • Vi har ikke lov til å deklarere metoden superMelding( ) i klassen B,da den er deklarert som en

«final» metode i klassen A.

Del 2: Typekonvertering (eng: casting) • Ved å skrive «(B) aref» forteller vi systemet at objektet som aref peker på, er av klassen B. Vi

får da muligheten til å sette bref til å referere til det samme objektet ved å skrive «bref = (B) aref».

• Ettersom bref er deklarert til å referere til objekter av klassen B, vil vi nå ha tilgang til metoder

og variabler deklarert i klassen B. Vi får derfor mulighet til å skrive «bref.y = 20» og å kalle metoden test( ) ved å skrive «bref.test( )»

• Metoden superMelding( ), og variablen x, er ikke deklarert i klassen B. Likevel kan vi skrive

«bref.x = 30» og «bref.superMelding( )». Dette er fordi de er deklarert i superklassen til B. Når vi ikke kunne skrive «aref.y = 10», var det fordi y var deklarert i subklassen.

• Den siste linja i programmet, «((B) aref).test( );» viser at vi kan gjøre både typekonverteringen

og aksesseringen på en gang. Vi behøver altså ikke gå veien om en referanse.

Alle klasser er subklasser I Java er alle klasser, også de vi selv lager, automatisk subklasser av klassen Object. Det er denne egenskapen som gjør at vi kan legge objekter av alle klasser inn i en hashtabell. Det er mulig fordi metodene i HashMap opererer på Objectklassen. Derfor må vi skrive «(MinKlasse)» før hashtabell.get(nøkkel).

MinKlasse h; h = (MinKlasse) register.get(nøkkel);

Metoden get(nøkkel) returnerer et objekt av typen Object, og ved denne konverteringen forteller vi systemet at det objektet som referansen h skal referere til er av typen MinKlasse.

Hvorfor bruke subklasser En referanse til en klasse, kan referere til en hvilken som helst subklasse av denne. Denne egenskapen bruker vi ofte i programmer med registere, der alle elementene deler noen egenskaper, mens andre egenskaper er spesielle for grupper av elementene. De egenskapene som er felles, deklarerer vi i superklassen, de andre blir deklarert i subklasser som arver fra denne superklassen. Eksempler på slike registre er et bilregister som kan inneholde person-biler og lastebiler. Her vil Bil være superklassen, og Personbil og Lastebil, være subklasser av denne. Et universitetsregister som kan inneholde studenter og ansatte, kan ha Person som superklasse, og Student og Ansatt, som subklasser. I disse tilfellene gjør subklasser programmet mer strukturert og oversiktlig.

68

Eksempel på bruk av subklasser import inf101.*; class BilRegister { public static void main(String[] argv) { HashMap register = new HashMap( ); Inn in = new Inn( ); char typebil; Bil bilref; do { System.out.print ("Registrere p)ersonbil eller l)astebil,"+ " eller a)vslutt"); typebil = in.inChar(); bilref = null; if(typebil==’p’) bilref = new Personbil(in); else if(typebil==’l’) bilref = new Lastebil(in); else if(typebil!=’a’) System.exit(0); else System.out.println("Ugyldig valg!"); // Dersom et bilobjekt ble opprettet, legg inn det // i hashtabellen. if(bilref!=null) register.put(bilref.regnr,bilref); } while(typebil!=’a’); Iterator it = register.values().iterator(); while( it.hasNext( ) ) { bilref = (Bil) it.next( ); bilref.skrivData( ); } } } abstract class Bil{ String regnr; String eier; public Bil(Inn in) { System.out.print ("Oppgi registreringsnummeret : "); regnr = in.inString(); System.out.print ("Oppgi navnet på eieren : "); eier = in.inString(); } abstract void skrivData( ); } class Personbil extends Bil { int maxpassasjerer; public Personbil(Inn in) { super(in); System.out.print ("Oppgi maksimalt antall passasjerer : "); maxpassasjerer = in.inInt(); } void skrivData( ) { System.out.println("Regnr : " + regnr); System.out.println("Eier : " + eier); System.out.println("Max passasjerer : " + maxpassasjerer); } } class Lastebil extends Bil {

69

int maxvekt; public Lastebil(Inn in) { super(in); System.out.print ("Oppgi maksimal vekt på last : "); maxvekt = in.inInt(); } void skrivData( ) { System.out.println("Regnr : " + regnr); System.out.println("Eier : " + eier); System.out.println("Maxvekt : " + maxvekt); } }

La oss se på noen detaljer ved programmet:

• Metodekallet super( ) er et kall på superklassens konstruktør. Dette kallet må stå først i subklassens konstruktør (hvis man ønsker å bruke «superkonstruktøren»).

• Når vi skriver abstract foran en klasse, kan vi ikke lage objekter av denne klassen. abstract

bruker vi kun når vi lager subklasser. I dette eksemplet kan vi kun lage objekter av klassen Latebil eller Personbil, ikke av klassen Bil.

• Ved å skrive abstract foran en metode, forteller vi systemet at denne metoden vil finnes i alle

subklassene til metoden. Dette gjør at vi kan kalle metoden ved hjelp av en referanse til denne klassen, og vi behøver ikke å typekonvertere pekeren til den subklassen metoden er deklarert i. Abstrakte metoder må deklareres i alle subklasser av klassen, bortsett fra de subklasser som er deklarert abstrakte. Når vi har en abstrakt metode i en klasse, må klassen deklareres som abstrakt.

Hvordan tegne subklasser Bil Personbil Lastebil regnr Eier antallPassasjerer

Figur 11.1: Subklasser tegnes som vanlige klasser. En strek går fra super-klassen til subklassen. Et objekt som er generert fra en subklasse vil inneholde variabler og metoder som står i både superklassen og subklassen. For å skille mellom hvor variablene er deklarert, deler vi objektet med en horisontal strek. Over streken setter vi variabler og metoder som står deklarert i superklassen, under streken setter vi dem som er deklarert i subklassen.

Feil å unngå Det kan være vanskelig å finne ut når det er riktig å bruke subklasser, og hvilke subklasser man skal bruke. Egen erfaring er ofte den beste måten å lære på, men det kan være greit å kjenne til enkelte feller, slik at man kan unngå disse. En vanlig feil er å forveksle objekter som skal være inneholdt i et annet objekt, med subklasser. Dersom vi har en klasse CD som skal lagre informasjon om data på en CD plate, kan vi ha en klasse Spor som lagrer informasjon om musikksporene på CD’en. Det kan da være fristende å tenke at klassen Spor skal være en subklasse av CD, noe som blir galt. Spor er «inneholdt» i CD. Spor er ikke en CD. På samme måte vil Studenter ikke være subklasse av Universitet, men ligge i en array eller hashtabell i klassen Universitet. Derimot er Personbil og

70

Lastebil, som vi har sett på tidligere, Bil. Om vi kan si at A er en B, så snakker vi om muligheten for subklasser (A extends B), f.eks. kan vi si at Personbil er en Bil. Personbil er en subklasse av Bil. Om vi derimot kan si A er en del av B, så er det andre datastrukturer det er snakk om. Et spor er en del av en CD. Subklasser er ikke aktuelt i dette tilfellet. En annen feil som ofte gjøres, er å lage for mange subklasser. Hvis vi ønsker å lage et personregister, kan vi ha en klasse Person med subklasser Mann og Kvinne. Hver person har en referanse til Mann, og en til Kvinne, som peker på personens foreldre. Vi ønsker også å vite hvilke onkler og tanter denne personen har. Da kan det være fristende å lage en klasse Onkel, og en klasse Tante, som er subklasser av klassen Person. Både onkel og tante er personer, men de har ingen flere egenskaper enn en person. Slektskapet kan avledes fra den eksisterende datastrukturen. Det er derfor ingen grunn til å lage egne klasser for dem. En vanlig feil kan illustreres med følgende eksempel:

abstract class Person { char kjønn; } class Mann { } class Kvinne { }

Vi kan alltid finne ut hva slags klasse et objekt er generert av. Har vi et objekt av typen Mann, er det en mann, hvis ikke er det en kvinne. Det å lagre «kjønn» i superklassen Person, blir dermed å lagre overflødig informasjon. Nednefor skal vi se på hvordan vi kan finne ut hva slags objekt vi har. Derimot er det fornuftig å lage klassen Person abstrakt, siden vi ikke kan ha en person som verken er mann eller kvinne. Ved å la Person være abstrakt, garanterer vi at ingen objekter kan lages av klassen — de må lages av enten Mann- eller Kvinneklassen.

Subklasser og filer Når vi skal lagre data i et objekt, er det vanlig å la objektet gjøre innlesingen av «sine» data. Slik er det også med subklasser, men før vi oppretter subklassen må vi ha lest inn nok informasjon til å vite hvilken av subklassene objektet skal tilhøre. Når vi lagrer data fra subklasser på fil, må vi passe på å skrive ut informasjon om hva slags subklasse dataene lå i, slik at de senere kan leses inn i riktig type objekt

Hva slags objekt har vi (instanceof) Det som står beskrevet her, ofte til stor hjelp når vi lager programmer med subklasser. Ved hjelp av den booleske operatoren «instanceof» har vi mulighet til å få vite hva slags klasse et gitt objekt er basert på. Vi har et register som inneholder informasjon om bøker. Registeret inneholder forskjellige typer bøker, som fagbok, skolebok og roman, og vi ønsker å lagre litt forskjellige typer informasjon avhengig av hva slags type bok det er. Enkelte ting, som forfatter, ISBN-nummer og tittel er felles for alle bøker. Vi lager derfor en klassestruktur der vi har en klasse Bok, og klasser Fagbok, Skolebok og Roman som subklasser av klassen Bok. I tillegg har vi klassen Register, som inneholder en hashtabell. Den skal vi bruke til å lagre alle bok-objektene i modellen (inkl. subklasser). Denne metoden ligger i Register klassen, og skal brukes til å legge en ny bok inn i registeret:

71

void nyBok( ){ char boktype; Bok nybok; Inn stdin = new Inn( ); System.out.println("Hva slags type bok skal du legge inn i registeret?"); System.out.print ("f) fagbok, s) skolebok r) roman"); boktype = Character.toLowerCase( in.inChar( )); switch (boktype) { case ’f’: nybok = new Fagbok( ); break; case ’s’: nybok = new Skolebok( ); break; case ’r’: nybok = new Roman( ); break; default: nybok = null; break; } // end switch if(nybok != null) { nybok.lesData( ); // Skal lese inn informasjon om boken. bokregister.put(nybok.isbn, nybok); } }

Vi ser at hashtabellen bokregister kan inneholde objekter av tre forskjellige typer klasser. Men vi klarer ikke å se hva slags type bok vi har ved å se på ISBN-nummeret. Så, dersom vi henter ut ett objekt fra hashtabellen, hvordan skal vi finne ut hvilken type bok dette er? Det er her "instanceof" hjelper oss. La oss legge en ny metode inn i registerklassen:

void typeBok( ) { String isbn; Bok b; System.out.print ("Tast inn ISBN nummeret på boken : "); if (bokregister.containsKey(isbn)) { b = bokregister.get(isbn); if (b instanceof Fagbok) System.out.println("Boken er en fagbok."); else if(b instanceof Skolebok) System.out.println("Boken er en skolebok."); // Siden boken hverken var en fagbok eller en skolebok // må den være en roman. else System.out.println("Boken er en roman."); } else System.out.println("Boken finnes ikke i registeret."); }

Vi kan med andre ord spørre om hva slags bok referansen peker på. «instanceof»-testen vil i tillegg være sann hvis objektet er en subklasse av den klassen vi tester mot. Det betyr følgende:

Bok b = new Roman( ); // Vi setter b til å peke på ett nytt roman // objekt.

72

if(b instanceof Roman) { // Ettersom objektet er av type roman, vil // utført (b instanceof Roman) være sann. } if(b instanceof Fagbok) { // Ettersom objektet er av type roman, vil // ikke utført (b instanceof Fagbok) ikke være sann. } if(b instanceof Bok) { // Ettersom objektet er av type roman, vil // utført (b instanceof Bok) ikke være sann, fordi } // Roman er subklasse av klassen Bok.

73

Kapittel 14 - Tekststrenger

Hva er strenger? I tidligere kapitler har vi brukt tekststrenger som om de skulle være variabler, men som det ble fortalt tidligere, er dette en forenklet måte å se det på. Strenger er ikke variabler, de er objekter av klassen String, som inneholder den tekststrengen vi oppgir eller leser inn. Disse objektene har også en rekke metoder vi kan benytte for å behandle strengen, og i dette kapitlet skal vi se på noen av de vanligste.

Hvordan bruke strenger Det første vi må gjøre for å bruke et strengobjekt, er å deklarere en strengreferanse:

String s; Mens vi tidligere har tenkt på dette som om «vi deklarerer en strengvariabel s», er sannheten at vi deklarerer en referanse som kan peke på et objekt av klassen String.

s ="En liten melding"; Vi tilordner altså ikke variablen s verdien «En liten melding». Det som skjer er at vi oppretter et strengobjekt som inneholder tekststrengen «En liten melding», og denne blir pekt på av referansen s. Det samme blir det med:

s = stdin.inStringln( ); Her blir det laget et objekt som inneholder teksten lest fra tastatur, og referansen s blir satt til å peke på denne. Vi kan gjøre begge stegene samtidig:

String s = stdin.inStringln( ); Her opprettes referansen, og settes til å peke på et strengobjekt som inneholder hele linja som ble lest fra tastatur.

Hvordan tegne strenger Ettersom strenger ikke er variabler, men objekter av klassen String, vil den riktige måten å tegne disse inn i et objekt/klassediagram, være å ha en referanse som peker på et objekt inneholdende teksten. Dette fører fort til at tegningen blir unødig detaljert, uten at det tilføyer tegningen vesentlige opplysninger. Derfor velger vi i dette kompendiet å tegne strenger som om de var vanlige variabler. Det er likevel viktig å huske på at dette kun er en forenkling, slik at vi, når vi programmerer, behandler strenger som objekter.

Operasjoner på strenger

Sammensetting av strenger Operatoren ’+’ har en helt spesiell betydning når vi benytter den på strenger. Den brukes til å sette sammen to strenger, eller å legge innholdet av variabler til en streng. Dette gjør at vi enkelt kan skrive ut strenger og variabler på samme linje:

74

System.out.println("Tallet som ble lest inn var : " + x +".");

Sammenlikning av strenger Ettersom strenger er objekter, kan vi ikke sammenlikne dem slik vi sammenliknet variabler. Dersom vi har to referanser til strengobjekter, f.eks. String s,r, vil «s==r» være sant dersom begge referansene refererer til samme objekt. Det er som oftest ikke det vi ønsker å teste, isteden ønsker vi å se om teksten i strengene er like. Det gjør vi ved å skrive:

s.equals(r); Metoden equals( ) er sann dersom tekstene, som strengene s og r refererer til, er like, hvis ikke er den usann.

Lengden av en streng Lengden av en streng finner vi enkelt ved å kalle metoden length( ).

System.out.println("Strengens lengde : " + s.length( ));

Konvertering til/fra tall Dersom vi ønsker å representere et tall som en streng, kan vi enkelt bruke ’+’ operatoren sammen med en tom streng.

int x = 20; String s = "" +x;

Dette holder lenge for kurset INF101, men er en lite elegant måte å løse problemet på. En riktigere måte å gjøre det på, vil være følgende kode:

int x = 20; String s = String.valueOf(x);

Hvis vi har en streng, og ønsker å gjøre den om til et heltall, kan vi bruke metoden parseInt i klassen Integer.

String s = "20"; int x = Integer.parseInt(s);

Her vil x få verdien 20. Tilsvarende finnes det en metode parseDouble for konvertering til reelle tall:1

String s = "3.14"; double d = Double.parseDouble(s);

Her vil d få verdien 3.14.

Dele opp strengen Vi kan lage en tekststreng som inneholder en del av en annen tekststreng ved å bruke metoden substring.

String s,r;

75

s ="En lang melding som kan deles opp"; r = s.substring(3,6); System.out.println(r);

Her vil teksten «lang» bli skrevet ut på skjermen. Merk at dersom parameterene til substring går over lengden på strengen, vil feilen StringIndexOutOfBoundsException bli kastet.

Søk i en streng Dersom vi vil se om en tekststreng inneholder noe spesielt, f.eks. om en setning representert som en streng inneholder et spesielt ord, bruker vi metoden indexOf. Denne vil returnere posisjonen i tekststrengen til det vi lette etter. Dersom det ikke ble funnet, vil -1 bli returnert.

String s = "Min streng"; int x = s.indexOf("streng"); System.out.println("Ordet streng funnet på posisjon : " + x);

Ettersom første bokstav i en streng ligger på posisjon 0, vil dette programmet skrive ut «Ordet streng funnet på posisjon : 4». Vi kan bruke metodene startsWith( ) og endsWith( ) til å se om en streng starter eller slutter med en gitt streng.

Et eksempel import inf101.*; class Strenger { public static void main(String[] argv) { Inn stdin = new Inn( ); String strengA, strengB; System.out.print("Tast inn en streng, minst 10 bokstaver lang :"); strengA = stdin.inStrinLn( ); System.out.print("Tast inn en streng, maks 10 bokstaver lang :"); strengB = stdin.inStringln( ); System.out.println("Lengden på den første strengen var : " + strengA.length( )); System.out.println("Første streng fra posisjon 3 til 6 : " + strengA.substring(3,6)); if (strengA.equals(strengB)) System.out.println("De to strengene er like"); else System.out.println("De to strengene er ikke like"); if (strengA.startsWith(strengB)) System.out.println("Den første strengen begynner med den andre"); else System.out.println("Den første strengen begynner ikke " + "med den andre"); if (strengA.indexOf(strengB) >=0) System.out.println("Den andre strengen finnes i den første " + "på posisjon :"+strengA.indexOf(strengB)); else System.out.println("Den andre strengen forekommer ikke " + "i den første"); } }

76

77

Kapittel 15 - Bruk av Java-pakker og dokumentasjon Når man skal skrive programmer, er det nesten alltid nødvendig å bruke en, eller noen få, av de nesten to tusen klassene som er ferdigskrevet i Java og som følger med Java systemet (i Java-biblioteket). Å bruke en eller flere av disse i vårt program vil si at vi kan deklarere pekere til disse ferdigskrevne klassen og eventuelt også opprette objekter av disse. Vi kan også, siden mange av dem har statiske metoder og statiske variable (dvs. klasse-metoder og klasse-variable), kalle disse metodene direkte uten å først opprette et objekt av den klassen vi skal bruke. Det bare et meget lite antall av disse klassene vi trenger i INF101. Vi skal nå først se på hvordan vi bruker disse klassene i våre programmer. Så skal vi se hvordan vi kan bruke den medfølgende dokumentasjonen, som når du bruker en PC hvor dokumentasjonen er installert nesten alltid finnes på:

C:\jdk1.3\docs\api\index.html På unix-anlegget på Blindern finner du den det hvis du fra hjemmesiden til INF101 (dvs http://www.ifi.uio.no/inf101) først klikker på ’læremidler’, og så ’beskrivelse av Javas bibliotek av pakker med klasser og metoder’.

Hva er en pakke og ’import’ De nesten 2000 klassene er samle t i litt over 75 pakker (package) - eller omlag 25 klasser per pakke. Pakker brukes til å gruppere klasser som hører sammen. Når vi skal bruke en klasse som er inne i en

78

av pakkene, bruker vi det reserverte ordet ’import’ i vår programtekst (før egne deklarasjoner) og så navnet på den pakka vi vil importere en eller flere klasser fra (f.eks pakken: java.util) så et punktum og så enten navnet på den klassen vi vil bruke eller ’*’. Sier vi ’*’ , betyr det at vi importerer alle de klassene fra den pakka vi bruker i programmet vårt (men ikke mer). Det er vanligst å bruke ’*’. Typiske importsetninger er: import inf101.*;

import java.io.*; import java.util.*; import javax.swing.*; import java.awt.* ; import java.awt.event.*;

Den første (inf101) brukes til inn-og utlesning på filer og skjerm/tastatur. Den neste (java.io) bruker vi til mer avansert inn/utlesning på fil og den andre (java.util) bl.a.til å få hentet inn HashMap klassen. De tre siste nyttes når vi skal tegne opp viduer på skjermen fra Javaprogrammet vårt, ta imot klikk og bevegelser med musa, inntasting fra tastaturet til felter i vinduer osv. - dvs. vindus-programmering. Den hyppigst brukte pakken, java.lang, er alltid og automatisk inkludert i programmet vårt. Vi trenger ikke si import på den. Den inneholder bla klassen Math som inneholder mange nyttige matematiske funksjoner som kvadratrot (Math.sqrt(..)), logaritme (Math.log(..)), og en rekke andre nyttige funksjoner. ’java.lang’ inneholder også en rekke klasser (Integer, Double,..) som gjør det lett å konvertere mellom verdier av ulik type, f.eks en int-variabel og en tegnrepresentasjon av slike verdier (da vil: ’int j = Integer.parseInt(”123”):’ gi tallverdien ’123’ til int-variabelen ’j’).

Bruk av dokumentasjonen Når vi skal finne fram i alle de klassene som er ferdigskrevet i Javabiblioteket, må vi altså først finne dokumentasjonen på nettet med nettleseren (Opera, Netscape eller Internet Explorer). Her har vi i det nedre, venstre rullefeltet klikket på klassen HashMap og fått opp en beskrivelse av denne går vi lenger

79

nedover i det høyre feltet (selve beskivelsen av klassen), kan vi klikke på en kortbeskrivelse av f.eks. metoden ’get( )’ og få en definisjon av denne.

80

Hvordan få tak i klassene ’Inn’ og ’Ut’, og classpath Når du lager programmer er det et ’vanskelig’ problem at javasystemet ikke alltid finner andre klasser du har laget selv (enten når du først skal kompilere med ’javac’ eller også deretter kjøre ferdigkompilerte systemer med ’java’). Her skal du bare lære den aller enkleste, men kanskje ikke mest elegante løsningen. Siden du i de fleste Java-programmene du selv skriver vil bruke pakken inf101 med de to klassene Inn og Ut som ligger der, skal du:

• Først lage en underkatalog som heter ’inf101’ i den katalogen du har dine egne programmer

• Så kopierer du filene ’Inn.class’ og ’Ut.class’ ned i denne katalogen, enten finner du disse via pekere på hjemmesida til kurset (http://www.ifi.uio.no/inf101), eller du finner de samme filene på Ifi-CDen.

• Til sist setter du inn importsetningen: ’import inf101.*;’ først i programmet ditt.

Da kompilerer og kjører programmene dine uten problemer og kan bruke klassene Inn og Ut. Tilsvarende kan du enten kopiere alle andre ferdigkompilerte klasser (.class filer) du trenger direkte inn til samme filkatalog som du har dine nye filer som bruker disse - eller du lager en egen pakke som ’inf101’- eksempelet ovenfor og legger de i en underkatalog på det område hvor du har det nye programmet ditt. Merk at underkatalogen alltid må hete det samme som pakken du lager. Alternativt lager du bare en slik ’inf101’ filkatalog ett sted (f.eks. på C:\jdk1.3\inf101) og kopierer over de to filene Inn.class og Ut.class dit. Hvis du i tillegg da sier ”C:>set classpath=.;c:\jdk1.3” i DOS-vinduert på PCen før du kompilerer og kjører, skulle du også kunne kompilere og kjøre uten problemer (merk at det står et punktum før semikolon). Vanskene med å sette en såkalt miløvariabel som ’classpath’ er at det er veldig lett å få slike galt satt, eller at man mister slike definisjoner når man lager et nytt DOS-vindu osv. Metoden i forrige avsnitt er i praksis enklere når man lager mindre programmer som i inf101.

81

Appendix A: Klassen Inn java.lang.Object | +--Inn

public class Inn extends java.lang.Object

Denne klassen er laget for bruk i INF101 og inneholder metoder for å lese fra terminal og fil. Klassen støtter både innlesing linje for linje, tegn for tegn, og item for item (hvor et item kan være et heltall, et flyttall eller en tekststreng). De tre typene innlesing kan kombineres. Eksempler på bruk: (1) Lese linje for linje fra fil: String linje; Inn innfil = new Inn("tekstfil.txt"); while (!innfil.endOfFile()) { linje = innfil.inStringln(); ...Gjør noe med den leste linjen... } (2) Lese fil med heltall (atskilt med blanke og/eller linjeskift): int tall; Inn innfil = new Inn("fil.txt"); while (!innfil.lastItem()) { tall = innfil.inInt(); ...Gjør noe med det innleste tallet... }

Constructor Summary

Inn() Lager et Inn-objekt for lesing fra tastatur.

Inn(java.lang.String name) Lager et Inn-objekt for lesing fra spesifisert fil eller URL.

Method Summary

boolean endOfFile() Sjekk om alle tegn (og linjeskift) er lest.

char inChar() Les et tegn.

char inChar(java.lang.String sep) Les et tegn med spesifiserte tegn som separatortegn.

double inDouble() Les et flyttall med blanke som separatortegn.

double inDouble(java.lang.String sep) Les et flyttall med spesifiserte tegn som separatortegn.

82

int inInt() Les et heltall med blank som separatortegn.

int inInt(java.lang.String sep) Les et heltall med spesifiserte tegn som separatortegn.

java.lang.String inString() Les en tekststreng med blank som separatortegn.

java.lang.String inString(java.lang.String sep) Les en tekststreng med spesifiserte tegn som separatortegn.

java.lang.String inStringln() Les resten av linjen som en tekststreng (inkludert blanke tegn).

boolean lastItem() Sjekk om siste ikke-blanke tegn er lest.

boolean lastItem(java.lang.String sep) Sjekk om siste ikke-separator tegn er lest, hvor separatortegn er de tegn som er spesifisert med parameteren sep.

void skipSep(java.lang.String sep) Hopp fram til første tegn som er forskjellig fra de spesifiserte separatortegnene.

void skipWhite() Hopp fram til første ikke-blanke tegn.

Methods inherited from class java.lang.Object clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Constructor Detail

Inn public Inn()

Lager et Inn-objekt for lesing fra tastatur.

Inn public Inn(java.lang.String name)

Lager et Inn-objekt for lesing fra spesifisert fil eller URL. Dersom name starter med "http://" tolkes name som en URL (dvs som en web-adresse). I alle andre tilfeller tolkes name som et filnavn (med eller uten path). Dersom det ikke angis noen path antas det at filen ligger på samme katalog som Java-programmet ligger på. En path kan enten være en relativ path eller en absolutt path. En relativ path angir en katalog relativt til katalogen som Java-programmet ligger på, f.eks. ../viktigbrev.txt obliger/Register.java En absolutt path angir en katalog i forhold til rotkatalogen, f.eks.

83

~in105/Oppgaver/oppgave1.txt

Method Detail

skipWhite public void skipWhite()

Hopp fram til første ikke-blanke tegn. Hopper over blanke tegn (inkludert tabulatortegn) og linjeskift.

skipSep public void skipSep(java.lang.String sep)

Hopp fram til første tegn som er forskjellig fra de spesifiserte separatortegnene. Dersom f.eks. sep er tekststrengen "&* " så vil en hoppe fram til første tegn som ikke er '&', '*' eller ' '. Kontrolltegn som starter med '\' kan også angis, f.eks. "\t" for å hoppe over tabulatortegn. For å hoppe over tegnet '\' må en angi "\\". Eksempel: hvis sep er tekststrengen " \t\\" så vil en hoppe fram til første tegn som ikke er ' ', tabulator-tegn eller '\'.

endOfFile public boolean endOfFile()

Sjekk om alle tegn (og linjeskift) er lest. Returnerer true dersom alle tegn (inkludert blanke) og linjeskift er lest, og returnerer false ellers. Kun ved lesing fra fil eller URL.

lastItem public boolean lastItem()

Sjekk om siste ikke-blanke tegn er lest. Hopper fram til første ikke-blanke tegn, eller til slutten av filen dersom det bare er blanke tegn igjen. I første tilfelle returneres verdien true og i siste tilfelle returneres verdien false. Kun ved lesing fra fil eller URL.

lastItem public boolean lastItem(java.lang.String sep)

Sjekk om siste ikke-separator tegn er lest, hvor separatortegn er de tegn som er spesifisert med parameteren sep. Dersom f.eks. sep er tekststrengen "&* " så er separatortegnene '&', '*' og ' '. Kontrolltegn som starter med '\' kan også angis, f.eks. "\t" for tabulatortegn. For å angi separatortegnet '\' må en bruke "\\". Eksempel: hvis sep er tekststrengen " \t\\" så vil separatortegnene være ' ', tabulator-tegn og '\'. Hopper fram til første ikke-separator tegn, eller til slutten av filen dersom det bare er

84

separator-tegn igjen. I første tilfelle returneres verdien true og i siste tilfelle returneres verdien false. Kun ved lesing fra fil eller URL.

inChar public char inChar()

Les et tegn. Det hoppes over eventuelle innledende linjeskift.

inChar public char inChar(java.lang.String sep)

Les et tegn med spesifiserte tegn som separatortegn. Det hoppes over eventuelle innledende linjeskift og separatortegn spesifisert i sep.

inInt public int inInt()

Les et heltall med blank som separatortegn. Det hoppes over eventuelle innledende blanke tegn (inkludert tabulatortegn) og linjeskift. Det gis feilmelding dersom første ikke-blanke tegn er noe annet enn et siffer.

inInt public int inInt(java.lang.String sep)

Les et heltall med spesifiserte tegn som separatortegn. Det hoppes over eventuelle innledende linjeskift og separatortegn spesifisert i sep. Det gis feilmelding dersom første ikke-separator tegn er noe annet enn et siffer.

inDouble public double inDouble()

Les et flyttall med blanke som separatortegn. Flyttallet må ha en av følgende formater: (1) xx.yy (eksempel: 34.22) (2) .yy (eksempel: .22) (3) xx (eksempel: 34) Det hoppes over eventuelle innledende blanke tegn (inkludert tabulatortegn) og linjeskift. Det gis feilmelding dersom første ikke-blanke tegn er noe annet enn et siffer.

inDouble public double inDouble(java.lang.String sep)

Les et flyttall med spesifiserte tegn som separatortegn. Flyttallet må ha en av følgende formater:

85

(1) xx.yy (eksempel: 34.22) (2) .yy (eksempel: .22) (3) xx (eksempel: 34) Det hoppes over eventuelle innledende linjeskift og separatortegn spesifisert i sep. Det gis feilmelding dersom første ikke-blanke tegn er noe annet enn et siffer.

inString public java.lang.String inString()

Les en tekststreng med blank som separatortegn. Hopper over innledende blanke tegn (inkludert tabulatortegn) og linjeskift, og leser deretter fram til første blanke tegn (inkludert tabulatortegn) eller linjeskift (det som kommer først).

inString public java.lang.String inString(java.lang.String sep)

Les en tekststreng med spesifiserte tegn som separatortegn. Hopper over innledende separatortegn og linjeskift, og leser deretter fram til første separatortegn eller linjeskift (det som kommer først). Separatortegn angis som en tekststreng, f.eks. "%&" for å bruke '%' og '&' som separatortegn.

inStringln public java.lang.String inStringln()

Les resten av linjen som en tekststreng (inkludert blanke tegn).

Class Tree Deprecated Index Help PREV CLASS NEXT CLASS FRAMES NO FRAMES SUMMARY: INNER | FIELD | CONSTR | METHOD DETAIL: FIELD | CONSTR | METHOD

86

87

Appendix B: Klassen Ut

Package Class Tree Deprecated Index Help PREV CLASS NEXT CLASS FRAMES NO FRAMES SUMMARY: INNER | FIELD | CONSTR | METHOD DETAIL: FIELD | CONSTR | METHOD

inf101 Class Ut java.lang.Object | +--inf101.Ut

public class Ut extends java.lang.Object Denne klassen er laget ved Ifi, UiO og inneholder metoder for å skrive til terminal og fil, samt formattering av tall som String. Klassen støtter både skriving linje for linje, tegn for tegn, og item for item (hvor et item kan være et heltall, et flyttall eller en tekststreng). De tre typene skriving kan kombineres. Eksempel på bruk: import inf101.*; class TestUt { public static void main (String [] args) { double [] vekt = {10.6, 23.1, 16.2, 36.2, 8.2, 22.2, 33.1}; double [] høyde= {180.3, 170.2, 175.6, 165.3, 182.2, 160.2, 178.3}; int n = 7; Ut utfil = new Ut("tekstfil.txt"); utfil.outStringln(" Individ Vekt Høyde"); for (int i=0; i < n; i++) { utfil.outInt(i+1, 10); utfil.outDouble(vekt[i], 10, 1); utfil.outDouble(høyde[i], 10, 1); utfil.outln(); } utfil.close(); } } Merk: foreløpig kan en ikke benytte linker (slik som ~ eller /hom/) i pathen når en oppretter et Ut-objekt. Version 15/08/2001/AM og OCL

Constructor Summary Ut() Lager et Ut-objekt for skriving til skjerm.

Ut(java.lang.String filnavn) Lager et Ut-objekt for skriving til spesifisert fil.

Method Summary

88

void close() Lukk fil

void outChar(char c) Skriv tegnet c.

void outChar(char c, int width) Skriv tegnet c venstrejustert på width plasser.

void outDouble(double x, int decimals) Skriv flyttallet x med decimals desimaler.

void outDouble(double x, int width, int decimals) Skriv flyttallet x med decimals desimaler, høyrejustert og på width plasser.

void outInt(int n) Skriv heltallet n.

void outInt(int n, int width) Skriv heltallet n høyrejustert på width plasser.

void outLn() Skriv ut et linjeskift.

void outString(java.lang.String s) Skriv tekststrengen s.

void outString(java.lang.String s, int width) Skriv tekststrengen s venstrejustert på width plasser.

void outStringLn(java.lang.String s) Skriv ut en tekststreng og avslutt med linjeskift.

static java.lang.String writeDouble(double x, int width, int decimals) Lag String av flyttallet x høyrejustert på width plasser med decimals plasser etter komma.

static java.lang.String writeInt(int n, int width) Lag String av haltallet n høyrejustert på width plasser.

static java.lang.String writeLong(long n, int width) Lag String av long n høyrejustert på width plasser.

Methods inherited from class java.lang.Object clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Constructor Detail

Ut public Ut()

Lager et Ut-objekt for skriving til skjerm.

Ut public Ut(java.lang.String filnavn)

Lager et Ut-objekt for skriving til spesifisert fil.

89

Method Detail

outChar public void outChar(char c)

Skriv tegnet c.

outChar public void outChar(char c, int width)

Skriv tegnet c venstrejustert på width plasser.

outInt public void outInt(int n)

Skriv heltallet n.

outInt public void outInt(int n, int width)

Skriv heltallet n høyrejustert på width plasser. Dersom det ikke er plass til heltallet på det spesifiserte antall plasser, avsluttes tallet med ...

writeInt public static java.lang.String writeInt(int n, int width)

Lag String av haltallet n høyrejustert på width plasser. Dersom det ikke er plass til heltallet på det spesifiserte antall plasser, avsluttes tallet med ...

writeLong public static java.lang.String writeLong(long n, int width)

Lag String av long n høyrejustert på width plasser. Dersom det ikke er plass til heltallet på det spesifiserte antall plasser, avsluttes tallet med ...

outDouble public void outDouble(double x, int decimals)

Skriv flyttallet x med decimals desimaler.

writeDouble public static java.lang.String writeDouble(double x, int width, int decimals)

90

Lag String av flyttallet x høyrejustert på width plasser med decimals plasser etter komma. Dersom det ikke er plass til heltallet på det spesifiserte antall plasser, avsluttes tallet med ...

outDouble public void outDouble(double x, int width, int decimals)

Skriv flyttallet x med decimals desimaler, høyrejustert og på width plasser. Dersom det ikke er plass til flyttallet på det spesifiserte antall plasser, avsluttes tallet med ...

outString public void outString(java.lang.String s)

Skriv tekststrengen s.

outString public void outString(java.lang.String s, int width)

Skriv tekststrengen s venstrejustert på width plasser. Dersom det ikke er plass til tekststrengen på det spesifiserte antall plasser, avsluttes tekststrengen med ...

outStringLn public void outStringLn(java.lang.String s)

Skriv ut en tekststreng og avslutt med linjeskift.

outLn public void outLn()

Skriv ut et linjeskift.

close public void close()

Lukk fil

Package Class Tree Deprecated Index Help PREV CLASS NEXT CLASS FRAMES NO FRAMES SUMMARY: INNER | FIELD | CONSTR | METHOD DETAIL: FIELD | CONSTR | METHOD