Enkle generiske klasser i Java

Like dokumenter
INF1010, 15. januar time. Parametriserte klasser (generiske klasser) Stein Gjessing Inst. for Informatikk Universitetet i Oslo

INF1010, 21. januar Klasser med parametre = Parametriserte klasser = Generiske klasser

2 Om statiske variable/konstanter og statiske metoder.

UNIVERSITETET I OSLO

2 Om statiske variable/konstanter og statiske metoder.

INF1010. Grensesnittet Comparable<T>

INF1010 våren Grensesnitt

INF våren 2017

Av Stein Gjessing, Institutt for informatikk, Universitetet i Oslo

IN våren 2019 Onsdag 16. januar

IN våren 2018 Tirsdag 16. januar

IN1010 våren januar. Objektorientering i Java

INF1010 våren Grensesnitt

UNIVERSITETET I OSLO

INF Objektorientert programmering. Datastrukturer i Java Klasser med parametre

Velkommen til. INF våren 2016

INF1010 Arv. Marit Nybakken 2. februar 2004

INF1010, 21. februar Om å gå gjennom egne beholdere (iteratorer) Stein Gjessing Inst. for Informatikk Universitetet i Oslo

Klasser, objekter, pekere og UML. INF gruppe 13

INF1010 våren januar. Objektorientering i Java

1. Krav til klasseparametre 2. Om å gå gjennom egne beholdere (iteratorer) Stein Gjessing Inst. for Informatikk Universitetet i Oslo

INF1010 våren 2008 Uke 4, 22. januar Arv og subklasser

Konstruktører. Bruk av konstruktører når vi opererer med "enkle" klasser er ganske ukomplisert. Når vi skriver. skjer følgende:

Oblig 4 (av 4) INF1000, høsten 2012 Værdata, leveres innen 9. nov. kl

INF1010, 22. mai Prøveeksamen (Eksamen 12. juni 2012) Stein Gjessing Inst. for Informatikk Universitetet i Oslo

UNIVERSITETET I OSLO

Eksamen INF1010 V2009 Del B prøveeksamen V2010 Vekt 60 %

UNIVERSITETET I OSLO

Oppsummering. Kort gjennomgang av klasser etc ved å løse halvparten av eksamen Klasser. Datastrukturer. Interface Subklasser Klasseparametre

INF Objektorientert programmering. Datastrukturer i Java Klasser med parametre

Seminaroppgaver IN1010, uke 2

Innhold uke 4. INF 1000 høsten 2011 Uke 4: 13. september. Deklarasjon av peker og opprettelse av arrayobjektet. Representasjon av array i Java

UNIVERSITETET I OSLO

INF1010 våren Grensesnitt (interface)

INF1000: Forelesning 7. Konstruktører Static

INF1000 HashMap. Marit Nybakken 2. november 2003

UNIVERSITETET I OSLO

INF1000: Forelesning 7

INF1000: noen avsluttende ord

Løsningsforslag til eksamen i INF1000 våren 2006

INF1010, 23. februar Parametriserte klasser Om å gå gjennom egne beholdere (subklasser og grensesnitt 3)

UNIVERSITETET I OSLO

INF1000 Prøveeksamen Oppgave 7 og 9

INF1000: noen avsluttende ord

INF Uke 10. Ukesoppgaver oktober 2012

INF1010 siste begreper før oblig 2

Gjennomgang av eksamen H99

Løsningsforslag ukeoppg. 6: 28. sep - 4. okt (INF Høst 2011)

IN1010 våren 2018 Tirsdag 15. mai. Repetisjon av subklasser og tråder. Stein Gjessing Institutt for informatikk Universitetet i Oslo

Lenkelister. Lister og køer. Kopi av utvalgte sider fra forelesningen.

klassen Vin må få en ny variabel Vin neste alle personvariable (personpekere) i listeklassen må byttes til Vin

INF1010 våren Interface (Grensesnitt)

INF1000 Metoder. Marit Nybakken 16. februar 2004

INF Innleveringsoppgave 6

Repitisjonskurs. Arv, Subklasser og Grensesnitt

UNIVERSITETET I OSLO

Sudokubrettet Et sudokubrett består av n n ruter. Vi bruker følgende begreper i oppgaven:

Forkurs INF1010. Dag 2. Andreas Færøvig Olsen Gard Inge Rosvold Institutt for Informatikk, 14.

UNIVERSITETET I OSLO

Oblig4 - obligatorisk oppgave nr. 4 (av 4) i INF1000

INF januar 2015 Stein Michael Storleer (michael) Lenkelister

Introduksjon til objektorientert programmering

INF1000 EKSTRATILBUD. Stoff fra uke 1-5 (6) 3. oktober 2012 Siri Moe Jensen

Forkurs INF1010. Dag 2. Andreas Færøvig Olsen Tuva Kristine Thoresen

Eksamen i emnet INF100 Grunnkurs i programmering (Programmering I) og i emnet INF100-F Objektorientert programmering i Java I

Uke 8 Eksamenseksempler + Ilan Villanger om studiestrategier. 11. okt Siri Moe Jensen Inst. for informatikk, UiO

Oblig4 - forklaringer. Arne og Ole Christian

Argumenter fra kommandolinjen

Stein Gjessing, Institutt for informatikk, Universitetet i Oslo

UNIVERSITETET I OSLO

JavaScriptbibliotek. Introduksjon MVVC. Informasjonsteknologi 2. Gløer Olav Langslet Sandvika VGS

INF1010 våren Arv og subklasser del 1

UNIVERSITETET I OSLO

Obligatorisk oppgave 4 i INF1010, våren 2014: "Leger og resepter" Versjon 1.1

Generiske mekanismer i statisk typede programmeringsspråk

INF1010 Rekursive metoder, binære søketrær. Algoritmer: Mer om rekursive kall mellom objekter Ny datastruktur: binært tre

Faglærerne prøver å besøker eksamenslokalet mellom klokka 15 og 16 for å oppklare eventuelle uklarheter og feil i oppgaveteksten.

Dagens forelesning. Java 13. Rollefordeling (variant 1) Rollefordeling (variant 2) Design av større programmer : fordeling av roller.

Obligatorisk oppgave 4: Lege/Resept

Eksekveringsrekkefølgen (del 1) Oppgave 1. Eksekveringsrekkefølgen (del 2) Kommentar til oppgave 1. } // class Bolighus

Eks 1: Binærtre Binærtretraversering Eks 2: Binærtre og stakk

praktiske eksempler DOM Document Object Model DOM og Høst 2013 Informasjonsteknologi 2 Læreplansmål Gløer Olav Langslet Sandvika VGS

Dagens tema Kapittel 8: Objekter og klasser

INF1000 : Forelesning 4

i=0 i=1 Repetisjon: nesting av løkker INF1000 : Forelesning 4 Repetisjon: nesting av løkker Repetisjon: nesting av løkker j=0 j=1 j=2 j=3 j=4

INF Seminaroppgaver til uke 3

UNIVERSITETET I OSLO

Diverse eksamensgaver

Post-it spørsmål fra timen (Arv og subklasser)

IN1010 våren Repetisjon av tråder. 15. mai 2018

Sortering med tråder - Quicksort

i=0 Repetisjon: arrayer Forelesning inf Java 4 Repetisjon: nesting av løkker Repetisjon: nesting av løkker 0*0 0*2 0*3 0*1 0*4

Forelesning inf Java 4

Oblig 4Hybelhus litt mer tips enn i oppgaven

INF1010 våren 2017 Onsdag 25. januar. Litt om unntak i Java

< T extends Comparable<T> > Indre klasser mm. «Det du bør ha hørt om før oblig 4»

UNIVERSITETET I OSLO

UNIVERSITETET I OSLO

Eksamen IN1010/INF1010 våren 2018

UNIVERSITETET I OSLO

Transkript:

Enkle generiske klasser i Java Oslo, 7/1-13 Av Stein Gjessing, Institutt for informatikk, Universitetet i Oslo Del 1: Enkle pekere Før vi tar fatt på det som er nytt i dette notatet, skal vi repetere litt fra INF1000. Anta at vi har skrevet en klasse Hund, som beskriver hunder: class Hund { String navn; Hund(String n) { navn = n; Hvis vi oppretter en HashMap der vi ønsker å legge inn hunder (av klassen Hund), og vi ønsker å finne disse igjen basert på navn (av klassen String), kan vi gjøre dette slik: HashMap<String, Hund> minehunder = new HashMap<String, Hund>( ); Vi sier at String og Hund er parametre til klassen. Klassen HashMap er laget så fleksibel at den kan ta vare på objekter av alle slags klasser, og disse kan finnes igjen basert på objekter av en annen klasse (i dette tilfellet klassen String). Ser vi i Javas bibliotek, finner vi at overskriften til klassen HashMap ser slik ut class HashMap<K,T>... {... Her er K og T parametre til klassen. Nå har vi snakket om både String og Hund som parametre, og vi har også snakket om K og T som parametre. For å skille disse fra hverandre kaller vi K og T formelle parametre, og String og Hund aktuelle parametre. Hvis vi trenger å skille disse parametrene fra parametre til metoder, kaller vi de parametrene vi her snakker om for klasse- parametre. Vi sier også at klassen HashMap er en generisk klasse (fordi den er generell, den kan brukes med mange klasser som parameter). Som kjent skriver vi parametre til metoder inne i vanlige parenteser slik: "(" og ")". Også når det gjelder parametre til metoder skiller vi mellom formelle parametre (i definisjonen av metoden) og aktuelle parametre (uttrykkene på kallstedet). De nye klasse- parametrene skrives inne i andre slags parenteser, nemlig "<" og ">". La oss se på et annet eksempel. Anta at vi skal lage et program som behandler biler. Vi må da lage et mønster: 1

class Bil { String regnr; Bil(String r) { regnr = r; Vi skal lage en garasje som kan inneholde en bil. Et mønster til en slik garasje kan være: class Garasje { private Bil denne; public void settinn (Bil den) {denne = den; public Bil taut ( ) { return denne; Når programmet kjører kan en garasje med en bil i se slik ut: void settinn (Bil den) denne = den; Bil taut( ) return denne; Type: Bil Navn: denne Objekt av klassen Bil Objekt av klassen Garasje Hvis det ikke er noen bil i garasjen når vi tar en bil ut, vil metoden taut returnere null. Det er OK. Andre ting med denne enkle klassen er derimot ikke så bra, bl.a. er det ikke bra at det er fullt mulig å sette en ny bil inn når det allerede er en bil i garasjen, og det er ikke bra at om vi tar ut en bil, er den fremdeles også inne i garasjen. Oppgave 1: Rett opp klassen Garasje slik at objekter av denne klassen oppfører seg bedre når vi prøver å sette en bil inn i en full garasje, og når vi tar ut en bil. I det følgende må du vite dette: Overskriften til en metode kalles signaturen til metoden. Dette omfatter navnet på metoden, typen til den verdien som returneres (eller void), og typen til parametrene. La oss gå tilbake til hundene, og lage et hundehus. Vi har allerede laget klassen Hund, så mønsteret til hundehuset kan være: 2

class Hundehus { private Hund denne; public void settinn (Hund den) {denne = den; public Hund taut ( ) { return denne; Legg merke til hvor like klassene Garasje og Hundehus er. (At dette hundehuset har de samme feilene og manglene som Garasje- klassen over skal vi ikke bry oss om her). Alt vi har behandlet hittil er kjent stoff. Nå kommer det nye. Klassene Garasje og Hundehus er ganske like. De brukes begge til å oppbevare en ting, en bil eller en hund. Objekter av disse to klassene er alle beholdere til en ting. Å programmere består ofte i å kjenne igjen felles egenskaper, og deretter lage ett begrep for ting som er nesten like. Her kommer en klasse som både kan bli en garasje og et hundehus: class BeholderTilEn <T> { private T denne; public void settinn (T den) {denne = den; public T taut ( ) { return denne; Sammenlign denne klassen med klassene Garasje og Hundehus! Vi kan ikke si "new BeholderTilEn<T>( );" så det finnes ikke objekter av denne klassen, men hadde det eksistert slike, ville de kanskje sett slik ut: void settinn ( T den) denne = den; T taut( ) return denne; Type: T Navn: denne Objekt av klassen T Objekt av klassen BeholderTilEn<T> (men slike finnes IKKE) BeholderTilEn<T> kalles en parametrisert klasse, en klasse med parameter, en generisk klasse eller en generisk type ("kjært barn har mange navn"). BeholderTilEn<T> er et mønster for en beholder som kan ta vare på én ting (ett objekt av klassen T). T kalles den formelle parameteren til klassen. Når vi 3

oppretter et objekt av denne beholderen må vi fortelle hva den skal kunne inneholde: new BeholderTilEn<Bil> ( ) og new BeholderTilEn<Hund> ( ) Bil og Hund er da aktuelle parametre til klassen. For å få tak i et objekt må vi ha en peker til det. I et program vil vi derfor vanligvis deklarere en peker først: BeholderTilEn<Bil> mingarasje; Deretter kan vi opprette et objekt som mingarasje peker på: mingarasje = new BeholderTilEn<Bil> ( ); Nå kan vi lage en bil og legge den inn i garasjen: Bil minbil = new Bil("AB12345"); mingarasje.settinn(minbil); Etter dette er Javaprogrammets datastruktur slik: Type: BeholderTilEn<Bil> Navn: mingarasje Type: Bil void settinn (Bil den) Bil taut( ) denne = den; return denne; Type: Bil Navn: denne Navn: minbil Objekt av klassen Bil Objekt av klassen BeholderTilEn<Bil> 4

La oss gjøre det samme med et hundehus og en hund: BeholderTilEn<Hund> mitthundehus = new BeholderTilEn<Hund> ( ); Hund trofast = new Hund("Trofast"); mitthundehus.settinn(trofast); Hund gneldrebikje; gneldrebikje = mitthundehus.taut( ); Etter dette er datastruktruren denne: (husk det vi sa over om at hunden ble igjen inne i hundehuset selv om vi har tatt den ut) Type: BeholderTilEn<Hund> void settinn (Hund den) Type: Hund denne = den; Hund taut( ) Navn: mitthundehus return denne; Objekt av klassen BeholderTilEn<Hund> Navn: denne Type: Hund Navn: trofast Type: Hund Objekt av klassen Hund Navn: gneldrebikje Nå har du sett ett eksempel på en enkel generisk klasse. Slike generiske klasser med parametre bruker vi når vi ønsker å lage en "generell" klasse, en klasse som kan virke i samspill med en (eller flere (som i HashMap)) annen klasse, og der vi ønsker å utsette valget av denne andre (de andre) klassene. Vi bruker gjerne klasser med parametre når vi lager verktøy, slik at først i det vi tar i bruk verktøyet (dvs. i det vi lager et objekt) bestemmer vi hvilken klasse som skal være aktuell parameter. Gjennom dette eksemplet håper jeg du skjønner det mest grunnleggende om hvordan parametre til klasser virker. I INF1010 vil du etter hvert se mange eksempler, og du skal lage klasser med parametre selv. 5

Del 2 Tabeller av pekere Når vi bruker klasser med parametre sammen med tabeller (engelsk: array) er det en sær ting i Java vi må passe på. Derfor kommer det her en egen del om dette temaet. Vi har fra før lært hvordan vi putter mange objekter inn i en tabell. La oss lage en klasse som vi kan bruke til å opprette hundegårder med plass til 100 hunder. Dette er kjent stoff: class Hundegard { private Hund [ ] hundene = new Hund [100]; private int antall = 0; public void settinn(hund h) { hundene[antall] = h; antall ++; public Hund taut( ) { antall - - ; return hundene[antall]; Hvis vi lager et objekt av denne klassen og setter inn mange hunder ser Javas datastruktur slik ut: public void settinn (Hund h) Hund [ ] hundene Hunde-objekter hundene[antall]=h; antall ++; public Hund taut( ) Navn: antall Type: int antall --; return hundene [antall]; Objekt av klassen Hundegard Oppgave 2: Lag en konstruktør slik at vi kan bestemme størrelsen på hundegården i det vi oppretter en, f.eks. slik: new Hundegard(50); 6

Legg merke til at når vi tar ut en hund fra en slik hundegård, så er dette alltid den hunden som ble satt inn sist. En slik beskrivelse av virkemåten til metodene settinn og taut kaller vi semantikken til disse metodene (i motsetning til bare signaturen). Siden disse metodene er de eneste i klassen, kan vi også kalle dette semantikken til hele klassen. Vi skal senere i INF1010 drøfte hvordan vi egentlig ønsker at taut- metoden skal virke. Dvs. vi skal lage en semantikk som brukerne av klassen er mer fornøyd med, og vi skal programmere klassen slik at den oppfører seg i henhold til denne semantikken. Skulle vi laget en garasje til mange biler, kunne vi bare byttet ut Hund med Bil i klassen over, og så hadde vi hatt et fult virkende mønster for en stor garasje med plass til 100 biler. Oppgave 3: Klassen Hundegard over er ikke noe robust program, dvs. det kan feile når det brukes på bestemte måter. Finn to slike feilsituasjoner og modifiser programmet slik at disse feilene ikke oppstår. Må vi forandre signaturen og semantikken til klassen for å få til dette? (Hint: Feilene oppstår når vi skal legge inn en ny hund, og det allerede er 100 hunder der, og når vi tar ut en hund, men det er null hunder der.) Siden vi alt har lært om parametre til klasser, så kan vi prøve å gjøre om hundegården til en parametrisert klasse. Vi prøver oss med et program, men NB! Dette er IKKE helt riktig: class StorBeholder <T> { private T [ ] alle = new T [100]; private int antall = 0; public void settinn(t det) { alle[antall] = det; antall ++; public T taut( ) { antall - - ; return alle[antall]; Dette ser jo veldig bra ut, og det er ergelig at Java ikke tillater oss å skrive dette. Grunnen behøver bare de spesielt interesserte å kjenne til: Under utføring av programmet har ikke kjøretidsystemet noen kjennskap til hvilken klasse T er, og derfor klarer den ikke å lage en ny tabell (array) av klassen T. Vi må derfor erstatte linjen som oppretter en tabell, med en mer komplisert linje. Hva denne gjør skal vi ikke bry oss om nå, men bare ta det som en besvergelse, og regne med at virkningen er den samme i programmet under, som den ville ha vært i programmet over, hvis dette var lovlig. 7

Dette er et riktig program: class StorBeholder <T> { private T [ ] alle = ( T [ ] ) new Object [100]; private int antall = 0; public void settinn(t det) { alle[antall] = det; antall ++; public T taut( ) { antall - - ; return alle[antall]; Dette programmet gjør akkurat som det vi ville at programmet over skulle gjøre. Når du oversetter dette programmet vil du få en advarsel som sier at programmet ditt "uses unchecked or unsafe operations". Ikke bry deg om det. Hvis du vil, kan du jo gjøre slik det foreslås og oversette med "- Xlint:unchecked" som parameter til kompilatoren. De som vil vite mer om dette, kan slå opp i en beskrivelse av Java. Nedenfor ser du et tenkt objekt av klassen StorBeholder<T> etter at det er tenkt lagt inn mange tenkte objekter av type T. NB! T må først bindes til et klassenavn (vi må ha en aktuell parameter) før et objekt kan bli laget. public void settinn (T det) public T taut( ) alle [antall] = det; antall ++; T [ ] alle Navn: antall Type: int antall --; return alle [antall]; NB! slike objekter finnes ikke!! Nå kan vi lage både store hundegårder og fellesgarasjer: 8

StorBeholder<Hund> minhundegard = new StorBeholder<Hund> ( ); og StorBeholder<Bil> fellesgarasjen = new StorBeholder<Bil> ( ); Så kan vi si, på samme måte som for et hundehus: minhundegard.settinn(trofast); Nedenfor ser du et objekt av klassen new StorBeholder<Hund> ( ) etter at Trofast er lagt inn. Slike objekter finnes virkelig: public void settinn (Hund det) Hund [ ] alle alle [antall] = det; antall ++; public Hund taut( ) antall --; return alle [antall]; Navn: antall 1 Type: int Objekt av klassen Hund Type: Hund Navn: trofast Objekt av klassen StorBeholder<Hund> Nå kan vi ta ut den hunden vi har lagt inn, og la pekeren "gneldrebikkje" peke på den hunden vi tar ut: gneldrebikkje = minhundegard.taut(); Nå vil begge de to pekerene trofast og gneldrebikkje peke på samme hund. Legg merke til at nå har vi virkelig tatt hunden ut av hundegården, for nå vil variablen "antall" inne i objekte ha verdien 0, som betyr at det ikke er noen hunder i gården. Og har du løst oppgave 3 har du en bedre hundegård, dvs. en som bl.a. ikke feiler om du prøver å ta en hund ut av en tom hundegård. Vi kan selvfølgelig gjøre det samme med bilene i fellesgarasjen, f.eks.: fellesgarasjen.settinn(minbil); fellesgarasjen.settinn(dinbil); dennebilen = fellesgarasjen.taut(); Oppgave 4: Skriv en konstruktør til klassen slik at størrelsen på beholderen blir bestemt i det beholderen blir opprettet, f.eks. slik: StorBeholder<Bil> fellesgarasjen = new StorBeholder<Bil> (500); 9