Helsingin yliopisto / Tietojenkäsittelytieteen laitos / Ohjelmoinnin jatkokurssi
Copyright © 2009 Arto Wikla. Tämän oppimateriaalin käyttö on sallittu vain yksityishenkilöille opiskelutarkoituksissa. Materiaalin käyttö muihin tarkoituksiin, kuten kaupallisilla tai muilla kursseilla, on kielletty.

5. harjoitukset 30.11.-4.12.2009

Aiheita: periytymistä, abstrakteja luokkia, rajapintaluokkia, polymorfismia, korvaamista, erikoistamista, ...

  1. [Teema: Aliluokka voi laajentaa ja monipuolistaa yliluokkansa toiminnallisuutta.]
    Tehtävässä 8 ohjelmoitiin luokalle OmaString (tehtävä 6 & 7) täydennys muokkaamalla itse luokkaa. Nyt sama asia tehdään toisin: Ohjelmoi luokalle OmaString aliluokka OmaStringPlus, jossa OmaString-ominaisuuksia täydennetään String-luokasta tutuin aksessorein compareTo, equals, charAt, indexOf(char), indexOf(OmaStringPlus). String-luokan API-kuvauksesta saa hyviä vinkkejä. Menettele kuitenkin String-luokasta poiketen virheiden käsittelyssä: Älä anna ohjelman kaatua virhetilanteisiin. Määrittele sen sijaan "järkevä" suhtautuminen virheisiin.

    Huom: Poiketen String luokan metodista riittää, että OmaStringPlus-luokan compareTo-metodi palauttaa arvon -1, 0 tai 1.

    Pohdittavaa: Nämä metodit voi toteuttaa tekemällä OmaStringPlus-olioista String-olioita ja käyttämällä String-luokan metodeita. Onko tämä hyvä tapa vai syntyykö liikaa roskaa? Jos haluat antaa aliluokalle pääsyn yliluokan kenttään mjono (eli char-taulukkoon, jossa merkkijono esitetään), muuta perittävän kentän näkyvyys tasolle protected. Jos päätit välttää roskaamista, tämä voi olla hyvä tapa. Toisaalta perityn kaluston kapseloinnin heikentäminen voi olla vaarallista. Miksi? Joissain tilanteissa se voi olla myös mahdotonta; jos vaikkapa on "ostettu" valmis luokka ilman lähdekoodia.

    Suositus: Ohjelmoi OmaStringPlus molemmilla tavoilla! Opit paljon! Tehtävän saa toki merkitä tehdyksi, vaikka tyytyisi vain jompaan kumpaan tapaan.

    Kirjoita pääohjelma, joka esittelee monipuolisesti OmaStringPlus-olioiden käyttöä.

  2. [Teema: Aliluokka voi myös rajoittaa ja erikoistaa yliluokkansa toiminnallisuutta.]
    Tehtävässä 6 & 7 toteutettiin muutettava merkkijono luokkana OmaString. Numerojono voidaan nähdä yleisen merkkijonon erikoistapauksena. Erikoista luokasta OmaString luokka Numerojono, jonka ilmentymät ovat siis muutettavia numerojonoja.

    Numerojonoja voidaan konstruoida ainoastaan parametrittomalla konstruktorilla:

      public Numerojono()  
    
    Konstruktori luo tyhjän numerojonon, siis tyhjän merkkijonon.

    Jotkin aksessorit ovat perittyinä sellaisinaan käyttökelpoisia, toiset täytyy korvata uudella jonon numeerisuuden säilyttämiseksi. Lisäksi tarvitaan yksi uusi aksessori

      public int value()
    
    joka palauttaa arvonaan this-numerojonon esittämän kokonaisluvun. Tyhjällä numerojonolla ei ole numeerista arvoa. Metodi palauttaa tuossa tilanteessa arvon -1. (Numerojonothan voivat esittää ainoastaan ei-negatiivisia lukuja!)

    Vihjeitä:

  3. Kehittele ja konkretisoi luvuissa 4.1 ja 4.5 esitetty esimerkki luokista ja periytymisestä. Toteuta ja testaa luokka Elain ja sen aliluokat Kissa, Nauta ja Hevonen sekä kahden viimeksimainitun aliluokat Lehmä ja Tamma. Mallinna siis noiden olioiden ominaisuuksia ja toimintatapoja luokkina ja luokkien suhteina. Käytä mielikuvitustasi, mutta pidä mielessä, että harjoittelemme periytymisen mekanismeja, emme karjatilan hoitoa.

    Vaatimuksia ja vihjeitä:

  4. & 20.
    Javassa on valmis rajapintaluokka Comparable erilaisten järjestystä edellyttävien yleisten tietorakenteiden toteuttamiseen. Se vaatii ja lupaa metodin compareTo, joka on kurssilaisille tuttu ainakin String-luokasta. Harjoitellaan vastaavaa tekniikkaa "omin käsin"!

    Rajapintaluokka Vertailtava olkoon

       public interface Vertailtava {
         public boolean pienempi(Vertailtava toinen);  // this-olio < toinen-olio
         public boolean isompi(Vertailtava toinen);    // this-olio > toinen-olio
         public boolean yhtäSuuri(Vertailtava toinen); // this-olio = toinen-olio
       } 
    
    Muokkaa oppimateriaalin luokka Pikkuvarasto (ks. luku2) ja tehtävän 9 & 10 luokka OmaString sellaisiksi, että ne toteuttavat rajapintaluokan Vertailtava. Päätä itse (ja määrittele täsmällisesti!), mitä näissä luokissa tarkoittavat järjestys ja yhtäsuuruus. (Varastojen järjestys voisi olla vaikkapa sellainen, että tuotenimien String-suuruusjärjestys on ensisijainen ja tuotteen määrä toissijainen järjestysperuste.)

    Huom: Pikkuvarastojen vertailumetodien parametrin käsittelyssä on yksi ongelma, parametrin tyyppi. Sen pitää olla Vertailtava, mutta tämä tyyppi ei sisällä Pikkuvaraston niitä ominaisuuksia, joihin vertailu voi perustua. Ratkaisu on eksplisiittinen tyyppimuunnos, "cast":

    public boolean pienempi(Vertailtava toinen) {
      Pikkuvarasto toka = (Pikkuvarasto)toinen;
      // nyt toka on kunnon Pikkuvarasto-olio, jonka kaikkia ominaisuuksia pääsee käyttämään
      ...
    

    Ohjelmoi julkinen luokkametodi järjestä, joka saa parametrinaan Vertailtava[]-tyyppisen taulukon ja järjestää sen nousevaan järjestykseen.

    Metodin oikea käyttötapa on sellainen, jossa taulukkoon on viety vain keskenään saman tyyppisiä olioita. Jos taulukossa on vaikkapa sekaisin Pikkuvarasto- ja OmaString-olioita, käy huonosti! Miksi? Voisiko asialle tehdä jotakin? Onko mielestäsi Java-kielen tämä ominaisuus hyvä vai huono? Voisivatko asiat olla toisin? Miten? (Javan versio 1.5 toi kieleen ns. geneeriset tyypit, käännösaikaiset tyyppiparametrit, joiden avulla tämä ongelma voidaan voittaa tyylikkäästi.)

    Laadi myös pieni ohjelma, joka havainnollistaa järjestä-metodin oikeaa käyttöä ja myös erityyppisten olioiden sekoittamisen kauheita seurauksia.


Takaisin harjoitussivulle.