TURUN YLIOPISTO DEMO III Informaatioteknologian laitos tehtävät Olio-ohjelmoinnin perusteet / Salo 15.2.2006 1. Tässä tehtävässä tarkastellaan erääntyviä laskuja. Lasku muodostaa oman luokkansa. Laskussa esiintyy erääntymispäivämäärä. Päivämääräkin muodostaa oman luokkansa. Laskuja halutaan aika ajoin järjestää päivämäärän mukaiseen järjestykseen. Päivämääriä on tämän vuoksi pystyttävä vertailemaan. Aloitetaan päivämääräluokasta Pvm. Kirjoitetaan luokan otsikkorivi niin, että se on muotoa: Luokalla Pvm on seuraavat piirteet: Esiintymämuuttujat v k p päivämäärän vuosi päivämäärän kuukausi päimäärään sisältyvä kuukauden päivä Pvm(vv, kk, pp) tostring() compareto(pvm pvm) Konstruktori, parametrit vv, kk, pp edustavat vuotta, kuukautta ja kuukauden päivää. Palauttaa merkkijonon, joka on muotoa v.k.p Tässä v, k, p edustavat esiintymämuuttujien arvoja merkkijonomuodossa. Vertailee olion itsensä (this) ja parametrina annetun päivämäärän pvm arvoja. Palauttaa positiivisen kokonaislukuarvon, jos olion itsensä (this) ilmoittama päivämäärä on suurempi kuin parametrin pvm ilmoittama päivämäärä. Negatiivisen kokonaislukuarvon metodi palauttaa päinvastaisessa tapauksessa. Jos päivämäärät ovat yhtä suuria, metodi palauttaa kokonaislukuarvon nolla. Luokan Lasku otsikko rivi on muotoa: Olio-ohjelmoinnin perusteet Demo III 1
Luokalla Lasku on seuraavat piirteet: Esiintymämuuttujat nimike määrä eräpvm merkkijono, joka ilmoittaa laskun aiheen liukuluku, joka ilmoittaa veloitettavan rahamäärän Luokan Pvm olio, joka ilmoittaa laskun erääntymispäivämäärän Lasku(n, m, p) tostring() compareto(lasku la) Konstruktori, parametrit n, m, ja p edustavat nimikettä, määrää ja päivämäärää. Palauttaa merkkijonon, joka sisältää nimikkeen, määrän ja päivämäärän välilyönnillä (tyhjällä merkillä) erotettuna. Vertailee päivämäärän eräpvm arvoa ja parametrina saadun Laskun la päivämäärän la.pvm arvoja käyttäen luokan Pvm metodia compareto. Jos tämän metodin palauttama arvo poikkeaa nollasta, se palautetaan myös nyt ohjelmoitavana olevan metodin arvona. Jos päivämäärät eräpvm ja la.eräpvm ovat yhtä suuria, metodi palauttaa arvon, joka saadaan vertailemalla olion itsensä sisältämää nimikettä parametrin la sisältämään nimikkeeseen String-luokan compareto-metodia käyttämällä (nimike on olion esiintymämuuttuja). Luokalla EraantyvatLaskut on seuraavat piirteet: Esiintymämuuttujat erlaskut Luokan ArrayList<Lasku> olio, johon talletetaan käsiteltävät laskut. EraantyvatLaskut() Konstruktori, joka varaa muistitilan oliolle erlaskut newoperaattoria käyttäen. lisäälasku(la) Lisää erlaskut-rakenteeseen laskun la. poistalasku(la) tulostalaskut() järjestykseen() Poistaa erlaskut-rakenteesta laskun la. Tulostaa erlaskut-rakenteeseen talletetut laskut. Järjestää erlaskut-rakenteeseen talletetut laskut Olio-ohjelmoinnin perusteet Demo III 2
järjestykseen käyttäen Collections-luokan sort-metodia. Lajittelujärjestys määräytyy luokan Lasku comparetometodin mukaan. Huom. Tiedoston EraantyvatLaskut.java alkuun tulee import java.util.*; public class EraantyvienTesti public static void main(string[] args) EraantyvatLaskut erlaskut = new EraantyvatLaskut(); Pvm pvm1 = new Pvm(15, 2, 2006); Pvm pvm2 = new Pvm(10, 2, 2006); Pvm pvm3 = new Pvm(17, 2, 2006); Pvm pvm4 = new Pvm(22, 2, 2006); Lasku la1 = new Lasku("sähkölasku",31.20, pvm1); erlaskut.lisäälasku(la1); Lasku la2 = new Lasku("puhelinlasku",22.25, pvm2); erlaskut.lisäälasku(la2); Lasku la3 = new Lasku("pysäköintisakko",40.0, pvm3); erlaskut.lisäälasku(la3); erlaskut.poistalasku(la2); Lasku la4 = new Lasku("liikennevakuutus", 78.40, pvm4); Lasku la5 = new Lasku("lehtitilaus", 38.65, pvm4); erlaskut.lisäälasku(la4); erlaskut.lisäälasku(la5); erlaskut.järjestykseen(); System.out.println(); Olio-ohjelmoinnin perusteet Demo III 3
2. Sanakirjan toteutuksessa Map-rakenne tuntuu hyvältä vaihtoehdolta. Maprakenteeseen talletettaessa avain-, arvo-parin avain voi toimia hakuavaimena, jolle haetaan käännöstä toiselle kielelle. Käännös saadaan avaimeen liittyvästä arvosta. Hankaluutena on se, että avain voi esiintyä osallisena vain yhdessä avain-, arvoparissa. Kuitenkin sanalle voi löytyä useampia käännöksiä. Tämä hankaluus on voitettavissa, jos käännökset luetellaan yhdessä merkkijonossa pilkulla erotettuna. Seuraavassa sanakirja-luokassa on tarkoitus toimia tällä tavalla. Avaimena toimii englanninkielinen sana ja arvona suomenkielinen käännös. Luokalla SanaKirja on seuraavat piirteet: Esiintymämuuttujat sanat Luokan TreeMap<String, String> olio, johon talletetaan avain-, arvoparit. Avaimena on englanninkielinen sana ja arvona suomenkielinen sana. SanaKirja Konstruktori, joka varaa muistitilan oliolle sanat new-operaattoria käyttäen. lisää(engl, suomi) Lisää Map-rakenteeseen parin: engl, suomi. Kumpikin parametreista on merkkijonoja. Tutki aluksi, onko avaimen arvolla: engl talletettu jotain. Jos ei ole, talleta uusi pari. Jos on talletettu, hae käännös avainta (engl) käyttäen. Lisää sen perään parametri suomi pilkulla erotettuna ja talleta takaisin. hae(engl) Palauttaa merkkijonon, joka sisältää sanan engl käännöksen suomeksi. Tutki ensin, onko avaimen: engl arvolla talletettu jotain. Jos ei ole palauta tyhjä merkkijono. tulosta() Tulostaa Map-rakenteeseen talletetut englanninkieliset sanat ja niiden käännökset suomeksi. Katso luentojen sivulta 56, miten Maprakenne käydään läpi. Esimerkki asiasta löytyy mm. osoitteesta: http://www.oracle.com/technology/pub/articles/maps1.html Joitain TreeMap-luokan metodeja: sanat.containskey(engl) onko avaimen engl arvolla talletettu jotain sanat.get(engl); hae avaimen arvolla engl sanat.put(engl, suomi); talleta pari engl, suomi Huom. Tiedoston alkuun: import java.util.*; Kokeile toimintaa seuraavan pääohjelman avulla: Olio-ohjelmoinnin perusteet Demo III 4
public class SanaKirjaTesti public static void main(string[] args) SanaKirja sanasto = new SanaKirja(); sanasto.lisää("big", "suuri"); sanasto.lisää("big", "iso"); sanasto.lisää("small", "pieni"); sanasto.lisää("bad", "paha"); sanasto.lisää("bad", "huono"); sanasto.lisää("pig", "sika"); sanasto.lisää("pig", "porsas"); sanasto.tulosta(); System.out.println("big = " + sanasto.hae("big")); 3. Ajatellaanpa tehtävää, jossa kokonaislukutaulukosta on haettava kaksi lukua, jotka ovat lukuarvoltaan mahdollisimman kaukana toisistaan. Tehtävä ei ole kovin vaikea: on haettava taulukosta pienin ja suurin luku. Läheinen tehtävä on se, että etsitäänkin taulukosta kahta lukua, jotka ovat ovat arvoltaan lähimpänä toisiaan. Tämän tehtävän ratkaisu vaatiikin jo enemmän työtä. Yksi ratkaisutavoista on se, että vertaillaan taulukon lukuja pareittain ja valitaan pareista se, jonka arvot ovat lähimpänä toisiaan (erotus itseisarvoltaan pienin). Parien läpikäynti vaatii kaksi silmukkaa, ulomman ja sisemmän. Toinen ratkaisutavoista lähtee siitä, että tehdään vertailu helpommaksi: lajitellaan taulukon luvut ensin suuruusjärjestykseen. Tällöin riittää, että käydään taulukon luvut peräjälkeen läpi ja vertaillaan aina kahta peräkkäistä. Tähän jälkimmäiseen ratkaisutapaan TreeSet-tallennusrakenne tarjoaa hyvän vaihtoehtoisen toteutustavan. TreeSet-tallennusrakenne pitää talletetut alkiot suuruusjärjestyksessä eikä erillistä lajittelua tarvita. Rajoituksena Set-rajapinnan toteuttavissa luokissa on, että mitään alkiota ei voi tallettaa kuin kerran. Yrittää voi, mutta ei tallennu. Rajoitus ei välttämättä ole mikään huono rajoitus. Tehtävän ratkaisua varten määritellään luokka LahellaKaukana. Sillä on seuraavat piirteet: Olio-ohjelmoinnin perusteet Demo III 5
Esiintymämuuttujat luvut Luokan TreeSet<Integer> olio, johon talletetaan tarkasteltava kokonaisluvut Integer-luokan olioina. LahellaKaukana Konstruktori, joka varaa muistitilan oliolle luvut newoperaattoria käyttäen. lisää(i) poista(i) lukumäärä() toarray() kauimpana() lähimpänä() Lisää TreeSet -rakenteeseen kokonaisluvun i (boolean add(i) ), joka tallentuu Integer-luokan oliona (autoboxing). Palauttaa totuusarvon, joka kertoo, onnistuiko tallennus. Duplikaatin tallennus ei onnistu, joten silloin paluuarvona on false. Poistaa tallennetun alkion (boolean remove(i) ). Parametri i voi olla kokonaisluku (autoboxing). Palauttaa totuusarvon joka on true, jos poistettavaksi pyydetty alkio oli olemassa, muuten palauttaa arvon false. Palauttaa tallennetujen alkioiden lukumäärän. saadaan selville treeset-luokan metodilla size(). Palauttaa esiintymämuuttujaan luvut tallennetut alkiot taulukkona. Taulukko saadaan metodikutsulla luvut.toarray() ja palautetaan metodin arvona. Taulukon tyyppi on Object[] (kumma kyllä). Tämä on myös nyt ohjelmoitavana olevan metodin tyyppi. Palauttaa int[] tyyppisen taulukon, jossa on kaksi alkiota. Indeksin arvolla 0 on talletettu pienin luvuista ja indeksin arvolla 1 suurin. Pienin luvuista saadaan metodikutsulla luvut.first() ja suurin luvut.last(). Tässä metodissa muodostetaan kahden alkion int[] tyyppinen taulukko, johon nämä luvut viedään (itse asiassa kyseessä on Integer-luokan oliot, mutta autounboxing toimii). Returnlauseeseen kirjoitetaan taulukon nimi (pelkästään). Jos luvut-rakenne on tyhjä(isempty() ), metodi palauttaa arvon null. Tämä testi sijoitetaan metodin alkuun. Palauttaa int[] tyyppisen taulukon, jossa on kaksi alkiota. Taulukkoo tulee luvut, jotka ovat lähinnä toisiaan. TreeSet-rakenteeseen talletetut luvut käydään läpi iteraattorin avulla. Iteraattorin metodin next() peräkkäiset kutsut palauttavat luvut suuruusjärjestyksessä pienimmästä suurimpaan. Metodin tehtävänä on etsiä kaksi peräkkäistä, joiden välinen erotus on pienin. Löydetyt luvut viedään int[] tyyppiseen taulukkoon. Taulukko palautetaan metodin arvona. Jos luvut-rakenteessa on vähemmän kuin kaksi alkiota, metodi Olio-ohjelmoinnin perusteet Demo III 6
. palauttaa arvon null. (Tämä testi metodin alkuun ensimmäiseksi. Alkioiden määrän ilmoittaa metodi size() ) Huom. Tiedoton alkuun: import java.util.*; Kokeile toimintaa seuraavan pääohjelman avulla: import java.util.*; public class LahellaKaukanaTesti public static void main(string[] args) LahellaKaukana laka = new LahellaKaukana(); int k, dupli = 0; System.out.println("Satunnaislukuja:"); while(laka.lukumäärä() < 15) k = (int) (100.0*Math.random()); if(laka.lisää(k)) System.out.print(k + "\t"); else dupli++; System.out.println("\nDuplikaatteja: " + dupli); System.out.println("\nLuvut järjestyksessä"); Object[] lu = laka.toarray(); System.out.println(Arrays.toString(lu)); int[] ka = laka.kauimpana(); System.out.println("\nLukuarvoltaan kauimpana:\n" + Arrays.toString(ka)); int[] la = laka.lähimpänä(); System.out.println("\nLukuarvoltaan lähimpänä:" + Arrays.toString(la)); Demoissa III on kolme tehtävää. Olio-ohjelmoinnin perusteet Demo III 7