ict02d Osio2- luento 3 Olio-ohjelmointi: Luokkien kirjoittaminen Jukka Juslin
Luokkien kirjoittaminen Tähänmennessä on käytetty valmiiksi määritettyjä luokkia. Nyt opimme kirjoittamaan omia luokkia olioiden määrittämiseksi Seuraavaksi keskitymme näihin: Luokan määritykset Instanssin tieto (olion tieto) kapselointi ja tiedon muuttajat (setterit ja getterit) Metodin määrittäminen ja parametrien välitys Konstruktorit eli oletusmuodostimet (niiden korvaajat) Jukka Juslin 2
Missä ollaan? Luokan anatomia kapselointi Metodin anatomia Jukka Juslin 3
Luokkien kirjoittaminen Luokat, joita olemme aikaisemmin käyttäneet ovat Javan standardi luokkakirjastosta (API) Nyt alamme suunnitella ohjelmia, jotka perustuvat luokkiin joita itse kirjoitamme (kohdeluokat yms.) Luokka joka sisältää main metodin on vain ajettavan ohjelman käynnistyspiste Todellinen olio-ohjelmointi perustuu luokkien määrittämiseen (ei laiteta kaikkea mainin sisään, vain käynnistys!!!). Luokat esittävät olioita hyvin suunnitellun toiminnallisuuden ja attribuuttien kanssa Jukka Juslin 4
Luokat ja oliot Muista että oliolla on aina tila ja käyttäytyminen Tarkastellaan kuusisivuista noppaa (yhtä noppaa) Sen tila voidaan määrittää siitä mitä sivua se näyttää ylöspäin Sen pääasiallinen käyttäytyminen on, että sitä voidaan heittää Voit ajatella samaa realimaailmassa esimerkiksi koskien coca-cola automaattia. Mikä on automaatin tila esim. Ja mikä on automaatin käyttäytyminen? Voimme esittää noppaa ohjelmistossa suunnittelemalla luokan Noppa tjoka mallintaa nopan tilan ja käyttäytymisen. Tuloksena saadaan noppa, joka on itseasiassa parempi kuin perinteinen noppa. Luokka toimii noppa olion piirustuksena Me voimme instantioida niin monta noppa-objektia kuin tarvitsemme missä tahansa ohjelmassa Jukka Juslin 5
Luokat Luokka voi sisältää tiedon määrityksiä ja metodimäärityksiä int koko, paino; char kategoria; Tiedon määritykset Metodi määritykset Jukka Juslin 6
Luokat Tiedon arvot määräävät olion tilan, joka on luokasta luotu Metodien toiminnallisuus määrittää olion käyttäytymisen Noppa luokkaamme voisimme määrittää inttyyppisen muutujan, joka näyttää tällähetkellä ylöspäin osoittavan nopan sivun arvon Yksi metodeista heittää noppaa asettamalla tämän arvon satunnaislukuun, joka on ykkösen ja kuutosen välillä Jukka Juslin 7
Luokat Haluamme suunnitella Noppa luokkaan kaikki tarvittavat tiedot ja metodit, jotta se olisi monikäyttöinen ja uudelleenkäytettävä resurssi Noppa.java, public class Noppa Mikä tahansa käyttävä ohjelma (Testeri) ei välttämättä käytä kaikkia ko. Luokan ominaisuuksia Jukka Juslin 8
Noppa luokka Noppa luokka sisältää kaksi arvoa vakio MAX, joka esittää maksimaalista nopan arvoa muuttujan nopanarvo joka esittää nopan arvoa tällä hetkellä (ylöspäin oleva sivu heiton jälkeen) heitä metodi käyttää random metodia Math luokasta määrätäkseen nopan saaman arvon On myös olemassa metodeita, joilla eksplisiittisesti asetetaan ja noudetaan nopan arvo milloin tahansa Jukka Juslin 9
tostring metodi Kaikkien luokkien, jotka esittävät olioita, pitäisi määrittää tostring metodi tostring metodi palauttaa merkkijono Stringin, joka esittää olion (tekstimuodossa, oliota ei luonnollisesti voi tulostaa suoraan) Sitä kutsutaan automaattisesti kun olio konkatenoidaan Stringiin (+ operaatio) tai kun olio välitetään println metodille Jukka Juslin 10
Konstruktorit eli oletusmuodostimet Kuten aikaisemmin mainittu, konstruktori on erityinen metodi, jota käytetään olion alustamiseen, kun se alunperin luodaan Konstruktorilla on sama nimi kuin luokalla, ei palautusarvoa Noppa konstruktoria käytetään asettamaan jokaisen uuden noppa olion antamaksi lähtötulokseksi yksi Myöhemmin tutustutaan konstruktoreihin lisää Jukka Juslin 11
Tiedon näkyvyys (skooppi) Tiedon näkyvyys on alue ohjelmasta, josta tiettyyn tietoon päästään viittaamaan (käyttämään sitä) Tietoon, joka määritetään luokkatasolla voidaan viitata luokan kaikista metodeista käsin Tietoon, joka määritellään metodin sisällä, päästään käsiksi vain ko. metodin sisällä Tietoa, joka määritellään metodin sisällä kutsutaan paikalliseksi tiedoksi / paikalliseksi muuttujaksi Noppa luokassa muuttuja tulos määritetään tostring metodin sisällä se on pakallinen ko. Metodille ja tulkseen ei voida viitata muualta. Vertaa esimerkiksi taulu-olioiden length attribuuttia, joka on public-tyyppinen ja luokkatasolla Jukka Juslin 12
Instanssin tieto eli olion tieto nopanarvo muuttuja Noppa luokassa kutsutaan instanssin tiedoksi sillä jokainen instanssi (olio) joka luodaan omistaa oman version siitä Luokka määrittää tiedon tyypin, mutta ei varaa tiedolle mitään muistitilaa Jokainen kerta kun Noppa olio luodaan, uusi nopanarvo muuttuja luodaan myös Luokan oliot jakavat metodin määritykset, mutta jokaisella oliolla on oma muistiavaruus Tämä on ainoa tapa miten kahdella oliolla voi olla erilaiset tilat Jukka Juslin 13
Instanssitieto Voimme kuvata kaksi Noppa oliota NopanHeitto ohjelmasta kuten seuraavassa: noppa1 nopanarvo 5 noppa2 nopanarvo 2 Jokaisella oliolla pitää omaa nopanarvo muuttujaajatätäkauttaoliollaon omatila Jukka Juslin 14
UML kaaviot eli diagrammit Kuten aikaisemmasta on tuttua, UML tarkoittaa Unified Modeling Languagea UML diagrammit näyttävät luokkien ja olioiden väliset suhteet UML luokkadiagrammi koostuu yhdestä tai useammasta luokasta, joissa jokaisessa on erotetut osiot luokan nimelle, attribuuteille (tiedolle) ja operaatioille (metodeille) Viivat luokkien välillä (luokkakaaviossa) esittävät yhteyssuhteita eli assosiaatioita. Näistä tutustumme seuraaviin (kahteen) tyyppiin: Katkoviivalla varustettu nuoli kertoo, että toinen luokka (siis luokasta tehty olio) käyttää toista (eli kutsuu sen metodeja) kontrolli siirtyy. Näitä katkoviivanuolia käytämme etupäässä, tosin tutustumme myös koostumus-suhteisiin eli aggregaatioihin (joita ilmaistaan ns. Timanttimerkillä) Jukka Juslin 15
UML luokkakaaviot UML luokka class diagram HeitäNoppaa ohjelmalle: HeitäNoppaa +main (args : String[]) : void -nopanarvo : int Noppa +heitä() : int +setnopanarvo (int arvo) : void +getnopanarvo() : int +tostring() : String Jukka Juslin 16
Missä ollaan? Luokan anatomia Kapselointi Metodin anatomia Jukka Juslin 17
Enkapsulointi Voimme ottaa yhden kahdesta näkökulmasta tarkastella oliota: sisäinen - luokan muuttujien ja metodien yksityiskohdat, eli luokan määrittäminen ulkoinen - palvelut, jotka olio tarjoaa ja kuinka olio vuorovaikuttaa muiden järjestelmän olioiden kanssa Ulkoisestä näkökulmasta, olio on enkapsuloitu entiteetti (eli kokonaisuus), se tarjoaa joukon määritettyjä palveluita Nämä palvelut määrittävät olion rajapinnan (eli interface), joka näkyy ulospäin Jukka Juslin 18
kapselointi Yksi olio (kutsutaan asiakkaksi (client)) voi käyttää toista oliota, jotta voisi tarjota palvelut jotka sen pitää tarjota Olion asiakas voi pyytää ko. olion palveluita (eli kutsua olion metodeja), mutta sen ei pitäisi tietää kuinka ko. palvelut suoritetaan. Vrt. Esim. Coca-Cola automaatin toiminta. Jos käyttäjää ajatellaan oliona, hän haluaa vain Coca-Colaa eikä välittää automaatin sisäisestä toiminnasta. Mikä tahansaa muutos olion tilassa (sen muuttujissa) pitää tehdä olion metodien kautta (eli tavallisesti set ja get metodit) Huomaa myös poikkeukset tästä esim. Taulukko-luokkien lengthattribuutti (public) Meidän pitää tehdä vaikeaksi, ellei jopa mahdottomaksi, asiakaan päästä käsiksi olion muuttujiin suoraan (kuten taulukko-olion length) Eli, olioiden pitäisi olla itsehallintoon perustuvia (self-governance) Jukka Juslin 19
kapselointi Enkapsuloitua oliota voidaan ajatella mustana laatikkona sen sisäinen toiminta peitetään asiakkailta Asiakas kutsuu rajapintametodeja (tavalliset public-tyyppiset metodit) nämä hallitsevat instanssin tietoa Asiakas Metodit Tieto Jukka Juslin 20
Näkyvyyden muuntelu Javassa, me saavutamme kapselointin käyttämällä sopivia näkyvyysmääritteitä (visibility modifiers) näkyvyysmäärite on Javan varattu sana, joka määrittää tietyn metodin tai muuttujan luonteen final määritettä käytetään vakioiden määrittämiseen (esim. private final EUROTOMARK = 5.94) Javassa on kolme näkyvyyden muuntelumäärettä: public, protected ja private protected määre liittyy periytymiseen, jota käsittelemme opintojaksomme osiossa kolme. Tehtävissä, emme käytä ko. määrettä tässä osiossa. Jukka Juslin 21
Näkyvyyden määritteet Luokan osiin (attribuutit tai metodit), jotka määritetään julkisiksi (public visibility) voidaan viitata mistä tahansa käsin Luokan osiin (attribuutit ja metodit), jotka määritetään yksityisiksi (private visibility) voidaan viitata ainoastaan ko. luokan sisältä Luokan osiin (attribuutit ja metodit), joille ei anneta näkyvyyttä (visibility) ollenkaan, annetaan oletusarvoinen näkyvyys (default visibility) ja näihin voidaan viitata mistä tahansa luokasta samassa paketissa Jukka Juslin 22
Näkyvyyden määrittäminen Julkiset muuttujat rikkovat kapselointiperiaatetta vastaan, sillä ne mahdollistava sen että asiakas pääse käsiin ja voi voi muutella luokan attribuuttien arvoja Siksi luokan muuttujia ei saisi määrittää julkisen näkyvyyden kanssa (eli siis pitää aina käyttää private sanaa ennen muuttujan nimeä) On hyväksyttävää antaa vakiolle (public final MAX) julkinen näkyvyys, jolloin sitä voidaan käyttää (mutta ei muuttaa) luokan ulkopuolelta Julkiset vakiot eivät riko kapselointiperiaatetta vastaan, sillä vaikka asiakkaalla on pääsy näihin vakioihin, asiakas ei voi muuttaa niiden arvoa (kun final määre käytössä!) Jukka Juslin 23
Näkyvyyden määrittäminen Metodit, jotka tarjoavat olion palvelut määritetään julkisen näkyvyyden (public visibility) kanssa, jotta niitä voidaan kutsua asiakkaista käsin Esim. annacocacola(1) // määräys Julkisia metodeja kutsutaan myös palvelumetodeiksi (service methods) Metodia, joka luodaan pelkästään auttamaan palvelumetodia kutsutaan tukimetodiksi (esimerkiksi pudotapullo()) Koska tukimetodia ei kutsuta asiakkaasta käsin, se pitää määrittää tyypillisesti private näkyvyyden kanssa Jukka Juslin 24
Näkyvyysmääritteet public private Muuttujat, attribuutit Metodit Rikkovat enkapsulointia Tarjoavat palveluja asiakkaille Tukevat enkapsulointia Tukevat luokan muita metodeja Jukka Juslin 25
Aksessorit ja mutaattorit eli getterit ja setterit Koska instanssitieto on yksityistä (private), luokka yleensä tarjoaa palveluita muuttujien arvojen lukemista ja päivittämistä varten Aksessorimetodi (accessor method) palauttaa muuttujan nykyisen arvon (lukee muuttujan arvon) - kutsutaan myös gettereiksi Mutaattori metodi (mutator method) muuttaa muuttujan arvoa (päivittää muuttujan arvoa) kutsutaan myös settereiksi Nimet aksessori ja mutaattorimetodeille ovat muotoa getx ja setx, jossa X on arvon nimi (esim. setoppilasnumero(numero) Näitä kutsutaan aksessorin ja mutaattorin sijasta monasti gettereiksi ja settereiksi Jukka Juslin 26
Mutaattorin rajoitukset Mutaattorien käyttö antaa luokan suunnittelijalle mahdollisuuden rajoittaa asiakkaan mahdollisuuksia muutella olion tilaa (muuttujien arvoja suoraan, setteriin voi laittaa esim. tarkistuksen minkälainen luku on kyseessä) Mutaattori suunnitellaan usein niin, että muuttujien arvot voidaan asettaa vain tietyissä rajoissa. Esimerkiksi tilin omistajan nimi voidaan rajata max 50 merkkiin sillä tietokannassa jossa tietoja lopulta säilytetään on todennäköisesti kokorajoitus Esimerkiksi setnopanarvo mutaattori Noppa luokassa pitäisi rajoittaa niin, että arvo voidaan asettaa ainostaan johonkin tasalukuun sallitulla arvoaluella (tässä 1:stä MAX vakion arvoon asti) Myöhemmin tutustumme tarkemmin siihen miten tällaisia rajoituksia toteutetaan Jukka Juslin 27
Luokkien kirjoittaminen - this Muista this-avainsanan käyttö This-sanalla viitataan olion attribuuttiin Ilman this sanaa metodille tulevat parametrit on nimettävä erinimisiksi kuin luokan attribuutit Jukka Juslin 28
Lisää this-sanasta This-viittaa aina kyseisellä hetkellä käytössä olevaan olioon Koko nykyinen olio voidaan palauttaa kirjoittamalla return(this); Jukka Juslin 29
tostring metodi Pääsääntöisesti kaikille luokille pitää kirjoittaa tostring metodi tostring konkatenoi Stringiksi olion attribuuttien arvon tällähetkellä Eli kyseessä on ns. olion tilan tulostaminen Ilman tostring metodia saadaan oliosta tulostumaan ns. OID numero, joka on muistiosoite viitaten missä itse olio sijaitsee Jukka Juslin 30
Missä ollaan? Luokan anatomia kapselointi Metodin anatomia Jukka Juslin 31
Metodin määrittämiset Katsomme seuraavassa metodin määrittämistä hiukan tarkemmin Metodin määrittely määrää koodin, joka tullaan suorittamaan kun metodia kutsutaan Kun metodia kutsutaan, kontrolli (ns. etenemisrivi) ohjelmassa hyppää ko. Metodiin ja suorittaa ko. metodin koodin. Tämän suorittaminen loppuu kun tullaan returnlauseeseen. Kun tämä valmistuu, kontrolli palaa takaisin sinne mistä metodia kutsuttiin (voi tehdä esim. sijoituksen) ja jatkaa seuraavalta riviltä Metodi voi palauttaa tai olla palauttamatta arvon, riippuen kuinka metodi on määritetty Jukka Juslin 32
Metodin kontrollivirta Jos kutsuttu metodi on samassa luokassa tarvitaan vain metodin nimi kutsumiseen laske munmetodi munmetodi(); Jukka Juslin 33
Metodin kontrollivirta Kutsuttu metodi on usein osa toista luokkaa tai oliota (siis nimenomaan oliota yleensä, ellei static) main teese autamua olio.teese(); autamua(); Jukka Juslin 34
Metodin headeri Metodin määritys alkaa metodin headerilla char laske(int num1, int num2, String viesti) metodin nimi parametrilista palautus tyyppi Parametrilista määrittää jokaisen parametrin tyypin ja nimen Parametrin nimeä metodin määrittelyssä kutsutaan formaaliksi parametriksi. Ko. muuttujat luodaan aivan kuten metodin sisällä luodaan muuttujia. Jukka Juslin 35
Metodin runko Metodin headeria eli otsikkoa seuraa metodin runko (method body). Muista: Headerissa on määritetty myös formaalit parametrit. char laske(int num1, int num2, String viesti) { int sum = num1 + num2; char tulos = viesti.charat (sum); } return(tulos); Returnissa palautettavan Olion tulee olla palautustyyppiä eli samaa kuin metodin headerissa sum and tulos ovat paikallista tietoa tähän metodiin Nämä muuttujat luodaan aina kun tätä metodia kutsutaan, ja ne tuhotaan kun metodin suoritus loppuu Jukka Juslin 36
return lause Metodin palautustyyppi määrää minkätyyppisen arvon metodi lähettää takaisin sinne, mistä metodia on kutsuttu Metodilla, joka ei palauta arvoa on void palautustyyppi (metodin formaalissa esittelyssä) return lause määrää mikä arvo metodista palautetaan return(olio); Olion on tässä oltava samaa tyyppiä kuin formaalissa esittelyssä määritetty tyyppi ja kutsumispaikassa olio tulee sijoittaa esim. samantyyppiseen muuttujaan Jukka Juslin 37
Parametrit Kun metodia kutsutaan, varsinaisten parametrien arvot kutsun yhteydestä kopioidaan formaaleiden parametrien arvoiksi ch = olio.laske (25, count, Moro"); char laske (int num1, int num2, String viesti) { int sum = num1 + num2; char tulos = viesti.charat (sum); } return tulos; Jukka Juslin 38
Paikallinen data eli paikallinen tieto Kuten olemme huomanneet, paikalliset muuttujat voidaan määrittää metodin sisällä Metodin formaalit parametrit luovat automaattisia paikallisia muuttujia kun metodia kutsutaan Kun metodi lopettaa toimintansa, kaikki paikalliset muuttujat tuhotaan (mukaanlukien formaaleista parametreistä tehdyt muuttujat) Pidä mielessä, että instanssimuuttujat, luokan tasolla määritetyt, ovat olemassa niinkauan kuin olio on olemassa Jukka Juslin 39
Pankkitiliesimerkki Katsotaan toista esimerkkiä, joka demonstroi toteutusyksityiskohdat luokista ja metodeista Esitämme pankkitilä luokalla, jonka nimi on Tili Pankkitilin tila voi sisältää pankkitilin numeron, saldon tällähetkellä ja tilin omistajan nimen Tilin käyttäytyminen (tai sen palvelut) sisältävät otot ja talletukset sekä koron lisäämisen tilille Jukka Juslin 40
Testeriohjelmat Testeriohjelma eli ajuriohjelma ajaa toisia, kiinnostavampia osia ohjelmasta Testeriohjelmia käytetään usein testaamaan muista osia ohjelmasta Testeriohjelma sisältää luonnollisesti mainmetodin, aloittaa siis ajettavan Transaktion luokka sisältää main metodin, joka ajaa Tili luokan, kokeillen sen palveluita Jukka Juslin 41
Pankkitili esimerkki tili1 72354 tilnumero saldo 102.56 nimi Matti Nykänen tili2 69713 tilinumero saldo 140.00 nimi Pekka Pere Jukka Juslin 42
Pankkitili esimerkki On olemassa joitain parannuksia, joita voidaan tehdä Tili luokkaan Muodolliset getterit ja setterit pitäisi määrittää kaikille muuttujille Joidenkin metodien design voisi olla robustimpi (vankempi), kuten todentaa että määrä parametri nosto metodille on positiivinen saldo - nosto Jukka Juslin 43
Konstruktorit - lisää Huomaa, että konstruktorilla ei ole palautustyyppiä määritetty metodin headeriin (formaaliin määritykseen) ei edes void tyyppiä! Yleinen virhe on laittaa konstruktorille palautustyyppi, mikä tekee siitä tavallisen metodin, jolla sattuu olemaan sama nimi kuin ko. luokalla Ohjelmoijan ei tarvitse määrittää konstruktoria luokalla (eli oletuskonstruktori on jo olemassa, kyse on sen korvaamisesta) Jokaisella luokalla on valmiiksi Javan tekemä oletuskonstruktori eli oletusmuodostin (default constructor) joka ei ota parametrejä (muista kuitenkin myös konstruktorin ylikuormittaminen) public Pvm() // esimerkki oletuskonstruktorista Jukka Juslin 44
Konstruktoreista Synonyymi konstruktori-sanalle on muodostin On tärkeää osata seuraavat käsitteet: Oletuskonstruktori (oletusmuodostin) Korvaa Javan oletusarvoisen konstruktorin ilman parametrejä() olevan konstruktorin Parametrillinen konstruktori (parametrillinen muodostin) Saa vaihtelevan määrän parametrejä Kopiokonstruktori (kopiomuodostin) Saa parametrinä oman luokan olion ja kopio olion nykyiseen olioon (eli tekee kopin) Jukka Juslin 45
Missä ollaan? Luokan anatomia kapselointi Metodin anatomia Selvisimme tästä, seuraavaksi yhteenveto Jukka Juslin 46
Yhteenveto Tutustuimme Luokan määrittämiseen Instanssidataan (attribuutit) kapselointi ja Java määreet (private ja public) Metodin määrittäminen ja parametrien välittäminen Konstruktorit Jukka Juslin 47