Pakolliset tehtävät on merkitty harmalla taustavärillä. Punaisella taustavärillä merkatut ovat kontrollitehtäviä, jotka näytetään ohjaajalle harjoitustilaisuudessa!
Mene luokan koodilohkon sisäpuolelle mutta kaikkien metodien ulkopuolelle ja paina yhtä aikaa ctrl ja välilyönti. Jos luokallasi on esim. oliomuuttuja saldo
, tarjoaa NetBeans mahdollisuuden generoida oliomuuttujalle getteri- ja setterimetodit sekä konstruktorin joka asettaa oliomuuttujalle alkuarvon.
Aloitimme viime viikolla olioiden ohjelmoinnin tekemällä LyyraKortti-olioita. Kortilla oli metodit edullisesti ja maukkaasti syömistä sekä rahan lataamista varten.
Viime viikon tyylillä tehdyssä Lyyra-kortissa oli kuitenkin ongelma. Kortti tiesi lounaiden hinnan ja osasi sen ansiosta vähentää saldoa oikean määrän. Entä kun hinnat nousevat? Tai jos myyntivalikoimaan tulee uusia tuotteita? Hintojen muuttaminen tarkoittaisi, että kaikki jo käytössä olevat Lyyra-kortit pitäisi korvata uusilla, uudet hinnat tuntevilla korteilla.
Parempi ratkaisu on tehdä kortit "tyhmiksi", hinnoista ja myytävistä tuotteista tietämättömiksi pelkän saldon säilyttäjiksi. Kaikki äly kannattaakin laittaa erillisiin olioihin, kassapäätteisiin.
Toteutetaan ensin Lyyra-kortista "tyhmä" versio. Kortilla on ainoastaan metodit saldon kysymiseen, rahan lataamiseen ja rahan ottamiseen. Täydennä allaoleva luokka ohjeen mukaan:
public class LyyraKortti { private double saldo; public LyyraKortti(double saldo) { this.saldo = saldo; } public double saldo() { return saldo; } public void lataaRahaa(double lisays) { this.saldo += lisays; } public boolean otaRahaa(double maara){ // toteuta metodi siten että se ottaa kortilta rahaa vain jos saldo on vähintään maara // onnistuessaan metodi palauttaa true ja muuten false } }
Testipääohjelma:
public class Main { public static void main(String[] args) { LyyraKortti pekanKortti = new LyyraKortti(10); System.out.println("rahaa " + pekanKortti.saldo() ); boolean onnistuiko = pekanKortti.otaRahaa(8); System.out.println("onnistuiko otto: " + onnistuiko ); System.out.println("rahaa " + pekanKortti.saldo() ); onnistuiko = pekanKortti.otaRahaa(4); System.out.println("onnistuiko otto: " + onnistuiko ); System.out.println("rahaa " + pekanKortti.saldo() ); } }
Tulostuksen kuuluisi olla seuraavanlainen
rahaa 10.0 onnistuiko otto: true rahaa 2.0 onnistuiko otto: false rahaa 2.0
Unicafessa asioidessa asiakas maksaa joko käteisellä tai Lyyra-kortilla. Myyjä käyttää kassapäätettä kortin velottamiseen ja käteismaksujen hoitamiseen. Tehdään ensin kassapäätteestä käteismaksuihin sopiva versio.
Kassapäätteen runko:
public class Kassapaate { private double rahaa; // kassassa olevan käteisen määrä private int edulliset; private int maukkaat; public Kassapaate() { // kassassa on aluksi 1000 euroa rahaa } public double syoEdullisesti(double maksu) { // edullinen lounas maksaa 2.40 euroa. // päivitetään kassan rahamäärää ja palautetaan vaihtorahat } public double syoMaukkaasti(double maksu) { // edullinen lounas maksaa 4.00 euroa. // päivitetään kassan rahamäärää ja palautetaan vaihtorahat } public String toString() { // palautetaan merkkijonona kassan rahamäärä sekä tieto myydyistä lounaista } }
Kassapäätteessä on aluksi rahaa 1000 euroa. Toteuta ylläolevan rungon metodit ohjeen ja allaolevan pääohjelman esimerkkitulosteen mukaan toimiviksi.
public class Main { public static void main(String[] args) { Kassapaate unicafeExactum = new Kassapaate(); double vaihtorahaa = unicafeExactum.syoEdullisesti(10); System.out.println("vaihtorahaa jäi " + vaihtorahaa ); vaihtorahaa = unicafeExactum.syoEdullisesti(5); System.out.println("vaihtorahaa jäi " + vaihtorahaa ); vaihtorahaa = unicafeExactum.syoMaukkaasti(4); System.out.println("vaihtorahaa jäi " + vaihtorahaa ); System.out.println( unicafeExactum ); } }
vaihtorahaa jäi 7.6 vaihtorahaa jäi 2.6 vaihtorahaa jäi 0.0 kassassa rahaa 1008.8 edullisia lounaita myyty 2 maukkaita lounaita myyty 1
Laajennetaan kassapäätettä siten että myös kortilla voi maksaa. Teemme kassapäätteelle siis metodit joiden parametrina kassapääte saa lyyrakortin jolta se vähentää valitun lounaan hinnan. Seuraavassa uusien metodien rungot ja ohje niiden toteuttamiseksi:
public class Kassapaate { // ... public boolean syoEdullisesti(LyyraKortti kortti) { // edullinen lounas maksaa 2.40 euroa. // jos kortilla on tarpeeksi rahaa, vähennetään hinta kortilta ja palautetaan true // muuten palautetaan false } public boolean syoMaukkaasti(LyyraKortti kortti) { // edullinen lounas maksaa 4.00 euroa. // jos kortilla on tarpeeksi rahaa, vähennetään hinta kortilta ja palautetaan true // muuten palautetaan false } // ... }
Huom: kortilla maksaminen ei lisää kassapäätteessä olevan käteisen määrää.
Seuraavassa testipääohjelma ja haluttu tulostus:
public class Main { public static void main(String[] args) { Kassapaate unicafeExactum = new Kassapaate(); double vaihtorahaa = unicafeExactum.syoEdullisesti(10); System.out.println("vaihtorahaa jäi " + vaihtorahaa ); LyyraKortti antinKortti = new LyyraKortti(7); boolean onnistuiko = unicafeExactum.syoMaukkaasti(antinKortti); System.out.println("riittikö raha: " + onnistuiko); onnistuiko = unicafeExactum.syoMaukkaasti(antinKortti); System.out.println("riittikö raha: " + onnistuiko); onnistuiko = unicafeExactum.syoEdullisesti(antinKortti); System.out.println("riittikö raha: " + onnistuiko); System.out.println( unicafeExactum ); } }
vaihtorahaa jäi 7.6 riittikö raha: true riittikö raha: false riittikö raha: true kassassa rahaa 1002.4 edullisia lounaita myyty 2 maukkaita lounaita myyty 1
Viime viikon tehtävässä 3.2 kehoitettiin poistamaan Lyyra-kortin kahdesta eri metodista samantapainen koodi uuden metodin avulla. On hyvin todennäköistä, että Kassapaate-luokassasi on nyt "copypaste"-koodia. Poista se viime viikon tehtävän 3.2. ohjeita soveltaen.
On todennäköistä, että lounaiden hinnat muuttuvat tulevaisuudessa. Tee koodistasi sellainen, että lounaan hinnat 2.4 euroa ja 4.0 euroa eivät esiinny kassapäätteen koodissa kuin korkeintaan yhdessä kohdassa. Mieti vielä että tapa miten hinnat kassapäätteessä esiintyvät tekee niiden muuttamisen mahdollisimman helpoksi.
Lisätään vielä kassapäätteelle metodi jonka avulla kortille voidaan ladata lisää rahaa. Muista, että rahan lataamisen yhteydessä ladattava summa viedään kassapäätteeseen. Metodin runko:
public void lataaRahaaKortille(LyyraKortti kortti, double summa) { // ... }
Testipääohjelma ja esimerkkisyöte:
public class Main { public static void main(String[] args) { Kassapaate unicafeExactum = new Kassapaate(); System.out.println( unicafeExactum ); LyyraKortti antinKortti = new LyyraKortti(2); System.out.println("kortilla rahaa " + antinKortti.saldo() + " euroa"); boolean onnistuiko = unicafeExactum.syoMaukkaasti(antinKortti); System.out.println("riittikö raha: " + onnistuiko); unicafeExactum.lataaRahaaKortille(antinKortti, 100); onnistuiko = unicafeExactum.syoMaukkaasti(antinKortti); System.out.println("riittikö raha: " + onnistuiko); System.out.println("kortilla rahaa " + antinKortti.saldo() + " euroa"); System.out.println( unicafeExactum ); } }
kassassa rahaa 1000.0 edullisia lounaita myyty 0 maukkaita lounaita myyty 0 kortilla rahaa 2.0 euroa riittikö raha: false riittikö raha: true kortilla rahaa 98.0 euroa kassassa rahaa 1100.0 edullisia lounaita myyty 0 maukkaita lounaita myyty 1
Materiaalissa esiteltiin luokka päiväyksen esittämiseen:
public class Paivays { private int pv; private int kk; private int vv; public Paivays(int pv, int kk, int vv) { this.pv = pv; this.kk = kk; this.vv = vv; } public String toString() { return pv+"."+kk+"."+vv; } public boolean aiemmin(Paivays verrattava){ if ( this.vv < verrattava.vv ) return true; if ( this.vv == verrattava.vv && this.kk < verrattava.kk ) return true; if ( this.vv == verrattava.vv && this.kk == verrattava.kk && this.pv < verrattava.pv ) return true; return false; } }
Lisää päiväykselle metodi public int erotusVuosissa(Paivays verrattava)
, jonka avulla saadaan selville kahden päivämäärän erotus vuosissa.
Ensimmäisessä versiossa metodi toimii vasta aika karkealla tasolla, se ainoastaan laskee verrattavien päiväysten vuosilukujen erotuksen.
Huom: metodin tarvitsee toimia ainoastaan siten, että parametriksi annettava päivämäärä on aiempi kuin se päivämäärä jolle metodia kutsutaan.
Kokeile metodia esim. seuraavalla pääohjelmalla:
public class Main { public static void main(String[] args) { Paivays eka = new Paivays(24, 12, 2009); Paivays toka = new Paivays(1, 1, 2011); Paivays kolmas = new Paivays(25, 12, 2010); System.out.println( toka + " ja " + eka + " ero vuosissa: " + toka.erotusVuosissa(eka) ); System.out.println( kolmas + " ja " + eka + " ero vuosissa: " + kolmas.erotusVuosissa(eka) ); System.out.println( toka + " ja " + kolmas + " ero vuosissa: " + toka.erotusVuosissa(kolmas) ); } }
Tulos näyttää seuraavalta:
1.1.2011 ja 24.12.2009 ero vuosissa: 2 25.12.2010 ja 24.12.2009 ero vuosissa: 1 1.1.2011 ja 25.12.2010 ero vuosissa: 1
Vuosien laskenta ei edellisessä versiossa ollut vielä kovin tarkkaa. Esim. 1.1.2011 ja 25.12.2010 välillä ilmoitettiin olevan vuoden ero. Tarkennetaan metodin toiminta sellaiseksi, että se osaa laskea vuodet kunnolla.
Laske erotukseen mukaan vaan täydet vuodet. Eli vaikka päiväysten ero olisi 1 vuosi ja 364 päivää, ilmoittaa metodi eroksi vuoden.
1.1.2011 ja 24.12.2009 ero vuosissa: 1 25.12.2010 ja 24.12.2009 ero vuosissa: 1 1.1.2011 ja 25.12.2010 ero vuosissa: 0
Laitetaan metodi toimimaan samoin riippumatta onko parametrina annettava päiväys myöhempi vai aiempi kuin päiväys mille metodia kutsutaan. Tulostuksen pitäisi olla seuraava:
24.12.2009 ja 1.1.2011 ero vuosissa: 1 1.1.2011 ja 24.12.2009 ero vuosissa: 1 24.12.2009 ja 25.12.2010 ero vuosissa: 1 25.12.2010 ja 24.12.2009 ero vuosissa: 1 1.1.2011 ja 25.12.2010 ero vuosissa: 0 25.12.2010 ja 1.1.2011 ero vuosissa: 0
public class Main { public static void main(String[] args) { Paivays eka = new Paivays(24, 12, 2009); Paivays toka = new Paivays(1, 1, 2011); Paivays kolmas = new Paivays(25, 12, 2010); System.out.println( eka + " ja " + toka + " ero vuosissa: " + toka.erotusVuosissa(eka) ); System.out.println( toka + " ja " + eka + " ero vuosissa: " + eka.erotusVuosissa(toka) ); System.out.println( eka + " ja " + kolmas + " ero vuosissa: " + kolmas.erotusVuosissa(eka) ); System.out.println( kolmas + " ja " + eka + " ero vuosissa: " + eka.erotusVuosissa(kolmas) ); System.out.println( kolmas + " ja " + toka + " ero vuosissa: " + toka.erotusVuosissa(kolmas) ); System.out.println( toka + " ja " + kolmas + " ero vuosissa: " + kolmas.erotusVuosissa(toka) ); } }
Vihje: jos olet ovela ja hyödynnät metodia aiemmin
, on tämä tehtävä erittäin helppo tehdä.
Tee luokka Opiskelija
,
johon tallennetaan seuraavat tiedot opiskelijasta:
String
)
String
)
Tee luokkaan seuraavat metodit:
haeNimi
, joka palauttaa opiskelijan nimen
haeOpiskelijanumero
, joka palauttaa opiskelijan opiskelijanumeron
toString
, joka palauttaa merkkijonoesityksen opiskelijasta
Seuraava pääohjelma testaa luokan toimintaa:
public class Main { public static void main(String[] args) { Opiskelija pekka = new Opiskelija("Pekka Mikkola", "013141590"); System.out.println("Nimi: " + pekka.haeNimi()); System.out.println("Opiskelijanumero: " + pekka.haeOpiskelijanumero()); System.out.println(pekka); } }
Ohjelman tulostuksen tulisi olla seuraava:
Nimi: Pekka Mikkola Opiskelijanumero: 013141590 Pekka Mikkola (013141590)
Tee uusi pääohjelma, joka kysyy opiskelijoiden tietoja. Ohjelma luo jokaisesta opiskelijasta uuden olion ja tallentaa sen listaan. Kun käyttäjä antaa nimeksi tyhjän merkkijonon, ohjelma tulostaa listalla olevat opiskelijat.
Listan määrittelyn tulisi olla seuraava:
ArrayList<Opiskelija> lista = new ArrayList<Opiskelija>();
Seuraavassa on esimerkki ohjelman suorituksesta:
Nimi: Alfred Apina Opiskelijanumero: 017635727 Nimi: Bruno Banaani Opiskelijanumero: 011288989 Nimi: Cecilia Cembalo Opiskelijanumero: 013672548 Nimi: Alfred Apina (017635727) Bruno Banaani (011288989) Cecilia Cembalo (013672548)
Tee ohjelma, jonka avulla voi hakea opiskelijat, joiden nimessä on annettu hakusana. Ohjelman alussa listaan lisätään joukko opiskelijoita. Tehtävänäsi on toteuttaa hakutoiminto.
Vihje: Käy opiskelijat läpi silmukassa ja
tarkista String
-luokan indexOf
-metodilla,
onko hakusana opiskelijan nimessä.
import java.util.*; public class Main { private static Scanner lukija = new Scanner(System.in); public static void main(String[] args) { ArrayList<Opiskelija> lista = new ArrayList<Opiskelija>(); lista.add(new Opiskelija("Olli Olio", "013632164")); lista.add(new Opiskelija("Melissa Metodi", "013401780")); lista.add(new Opiskelija("Saku Silmukka", "015696234")); lista.add(new Opiskelija("Essi Ehto", "013924429")); lista.add(new Opiskelija("Pasi Parametri", "016956834")); lista.add(new Opiskelija("Lasse Luokka", "012835085")); lista.add(new Opiskelija("Taina Taulukko", "014662803")); lista.add(new Opiskelija("Iiro Indeksi", "012807013")); // kirjoita koodia tähän } }
Esimerkkitulostuksia:
Anna hakusana: ukk Tulokset: Saku Silmukka (015696234) Taina Taulukko (014662803)
Anna hakusana: si Tulokset: Essi Ehto (013924429) Pasi Parametri (016956834) Iiro Indeksi (012807013)
Viikon 5 tehtäväsarjassa 2 tehtiin ensin ylhäältä rajoitettu laskuri ja rakennettiin laskurien avulla pääohjelmaan kello. Tehdään nyt myös itse kellosta olio. Luokan kello runko näyttää seuraavalta:
public class Kello { YlhaaltaRajoitettuLaskuri tunnit; YlhaaltaRajoitettuLaskuri minuutit; YlhaaltaRajoitettuLaskuri sekunnit; public Kello(int tunnitAlussa, int minuutitAlussa, int sekunnitAlussa) { // luodaan kello joka asetetaan parametrina annettuun aikaan } public void etene(){ // kello etenee sekunnilla } public String toString() { // palauttaa kellon merkkijonoesityksen } }
Lisää uuteen projektiin viimeviikkoinen laskuri-luokka ja yllä oleva kellon runko.
Toteuta konstruktori ja puuttuvat metodit. Voit testata kelloasi seuraavalla pääohjelmalla:
public class Main { public static void main(String[] args) throws Exception { Kello kello = new Kello(23, 59, 50); while( true ) { System.out.println( kello ); kello.etene(); // nukutaan sekunti Thread.sleep(1000); } } }
Tulostuksen tulisi edetä seuraavasti:
23:59:50 23:59:51 23:59:52 23:59:53 23:59:54 23:59:55 23:59:56 23:59:57 23:59:58 23:59:59 00:00:00 00:00:01
Kellomme koostuu kolmesta ylhäältärajoitetusta laskurista. Oikeastaan laskurit ovat viisareita. Uudelleennimeämme luokan jolloin kello näyttää seuraavalta:
public class Kello { private Viisari tunnit; private Viisari minuutit; private Viisari sekunnit; // ... }
Uudelleennimentä on NetBeansissa helppoa. Etsi ohje täältä. Vilkaise samalla onko ohjeessa jotain muita hyödyllisiä vihjeitä joitka eivät vielä ole repertuaarissasi. Kokeile samalla uudelleennimetä viisarin metodi seuraava
kuvaavammin.
Materiaalissa lisättiin henkilölle oliomuuttujaksi syntymäpäivän kertova Paivays-olio. Samalla todettiin, että oliomuuttuja ika
kannattaa poistaa sillä iän pystyy laskemaan päiväyksen ja syntymäpäivän avulla.
Toteuta metodi ika
joka palauttaa henkilön iän.
import java.util.Calendar; public class Henkilo { private String nimi; private Paivays syntymaPaiva; public Henkilo(String nimi, int pp, int kk, int vv) { this.nimi = nimi; this.syntymaPaiva = new Paivays(pp, kk, vv); } public int ika() { // laske henkilön ikä syntymäpäivän ja tämän päivän perusteella // tämä päivä saadaan selville seuraavasti // Calendar.getInstance().get(Calendar.DATE); // Calendar.getInstance().get(Calendar.MONTH) + 1; // tammikuun numero on 0 joten lisätään 1 // Calendar.getInstance().get(Calendar.YEAR); } public String getNimi() { return nimi; } public String toString() { return nimi +", syntynyt "+ syntymaPaiva; } }
Huom: voit ottaa pohjaksesi tehtävässä 1 laajennettu Päiväys-luokka ja miettiä miten saat hyödynnettyä päiväyksen metodia erotusVuosissa
iän laskemiseen.
Voit testata Henkilöä seuraavalla pääohjelmalla. Lisää myös itsesi ohjelmaan ja varmista että ikäsi tulostuu oikein.
public class Main { public static void main(String[] args) { Henkilo pekka = new Henkilo("Pekka", 15, 2, 1993); Henkilo antti = new Henkilo("Antti", 1, 3, 1955); System.out.println( antti.getNimi() + " ikä " + antti.ika() + " vuotta"); System.out.println( pekka.getNimi() + " ikä " + pekka.ika() + " vuotta"); } }
Tulostus:
Antti ikä 55 vuotta Pekka ikä 18 vuotta
Tee henkilölle metodi jonka avulla se vertaa ikäänsä parametrina annettuun henkilöön. Jos henkilö on vanhempi eli syntynyt aiemmin, palauttaa metodi true ja muuten false.
public class Henkilo { // ... public boolean vanhempiKuin(Henkilo verrattava) { // vertaa henklöiden ikiä käyttäen henkilöiden syntymäpäivää } }
Ja testaa laajennettua Henkilö-luokkaa esim. seuraavasti:
public class Main { public static void main(String[] args) { Henkilo pekka = new Henkilo("Pekka", 15, 2, 1983); Henkilo martin = new Henkilo("Martin", 1, 3, 1983); System.out.println( martin.getNimi() + " vanhempi kuin " + pekka.getNimi() + ": "+ martin.vanhempiKuin(pekka) ); System.out.println( pekka.getNimi() + " vanhempi kuin " + martin.getNimi() + ": "+ pekka.vanhempiKuin(martin) ); } }
Tulostus:
Martin vanhempi kuin Pekka: false Pekka vanhempi kuin Martin: true
Kurssi
-luokkaTee luokka Kurssi
,
johon tallennetaan kurssin nimi (String
).
Tee luokkaan seuraavat metodit:
haeNimi
, joka palauttaa kurssin nimen
Seuraava pääohjelma testaa luokan toimintaa:
public class Main { public static void main(String[] args) { Kurssi ohpe = new Kurssi("Ohjelmoinnin perusteet"); System.out.println("Kurssi: " + ohpe.haeNimi()); } }
Ohjelman tulostus on seuraava:
Kurssi: Ohjelmoinnin perusteet
Lisää luokkaan seuraavat metodit:
lisaaOpiskelija
, joka lisää opiskelijan kurssille
tulostaOpiskelijat
, joka tulostaa kurssilla olevat opiskelijat
Opiskelijat ovat tehtäväsarjan 3 mukaisia
Opiskelija
-olioita.
Tallenna kurssilla olevat opiskelijat Kurssi
-luokan
sisäiseen ArrayList
-listaan.
Seuraava pääohjelma testaa luokan toimintaa:
public class Main { public static void main(String[] args) { Kurssi ohpe = new Kurssi("Ohjelmoinnin perusteet"); Opiskelija alfred = new Opiskelija("Alfred Apina", "017635727"); Opiskelija bruno = new Opiskelija("Bruno Banaani", "011288989"); ohpe.lisaaOpiskelija(alfred); ohpe.lisaaOpiskelija(bruno); ohpe.lisaaOpiskelija(new Opiskelija("Cecilia Cembalo", "013672548")); //vaikutus on sama kuin edellisillä ohpe.tulostaOpiskelijat(); } }
Ohjelman tulostuksen tulisi olla seuraava:
Alfred Apina (017635727) Bruno Banaani (011288989) Cecilia Cembalo (013672548)
Lisää luokkaan seuraavat metodit:
haeOpiskelijamaara
, joka palauttaa kurssilla olevien opiskelijoiden määrän
asetaSuurinOpiskelijamaara
, joka asettaa kurssin suurimman sallitun opiskelijamäärän
Kurssin suurin sallittu opiskelijamäärä on
oletusarvoisesti 25.
Metodin asetaSuurinOpiskelijamaara
avulla tätä rajaa voi muuttaa.
Muuta metodia lisaaOpiskelija
niin,
että se ei lisää opiskelijaa kurssille,
jos sallittu opiskelijamäärä ylittyisi.
Seuraava pääohjelma testaa luokan toimintaa:
public class Main { public static void main(String[] args) { Kurssi ohpe = new Kurssi("Ohjelmoinnin perusteet"); ohpe.asetaSuurinOpiskelijamaara(3); Opiskelija alfred = new Opiskelija("Alfred Apina", "017635727"); ohpe.lisaaOpiskelija(alfred); System.out.println("Opiskelijoita: " + ohpe.haeOpiskelijamaara()); Opiskelija bruno = new Opiskelija("Bruno Banaani", "011288989"); ohpe.lisaaOpiskelija(bruno); System.out.println("Opiskelijoita: " + ohpe.haeOpiskelijamaara()); Opiskelija cecilia = new Opiskelija("Cecilia Cembalo", "013672548"); ohpe.lisaaOpiskelija(cecilia); System.out.println("Opiskelijoita: " + ohpe.haeOpiskelijamaara()); Opiskelija ylermi = new Opiskelija("Ylermi Ylimääräinen", "014711055"); ohpe.lisaaOpiskelija(ylermi); System.out.println("Opiskelijoita: " + ohpe.haeOpiskelijamaara()); } }
Ohjelman tulostuksen tulisi olla seuraava:
Opiskelijoita: 1 Opiskelijoita: 2 Opiskelijoita: 3 Opiskelijoita: 3
Vihje: Tässä kannattanee kerrata materiaalin luku 20.
Lisää luokkaan seuraava metodi:
etsiOpiskelija
, joka etsii opiskelijan opiskelijanumeron perusteella
Metodin tulee palauttaa Opiskelija
-olio,
joka vastaa annettua opiskelijanumeroa.
Jos tällaista opiskelijaa ei ole,
metodin tulee palauttaa null
-viittaus.
Seuraava pääohjelma testaa luokan toimintaa:
import java.util.Scanner; public class Main { private static Scanner lukija = new Scanner(System.in); public static void main(String[] args) { Kurssi ohpe = new Kurssi("Ohjelmoinnin perusteet"); ohpe.lisaaOpiskelija(new Opiskelija("Alfred Apina", "017635727")); ohpe.lisaaOpiskelija(new Opiskelija("Bruno Banaani", "011288989")); ohpe.lisaaOpiskelija(new Opiskelija("Cecilia Cembalo", "013672548")); System.out.print("Anna opiskelijanumero: "); String opiskelijanumero = lukija.nextLine(); Opiskelija etsittava = ohpe.etsiOpiskelija(opiskelijanumero); if (etsittava == null) { System.out.println("Opiskelijaa ei löytynyt!"); } else { System.out.println(etsittava); } } }
Esimerkkitulostuksia:
Anna opiskelijanumero: 011288989 Bruno Banaani (011288989)
Anna opiskelijanumero: 011288988 Opiskelijaa ei löytynyt!
Lisätään Paivays
-olioon mahdollisuus edistää aikaa.
Tee oliolle metodi Paivays paivienPaasta(int paivia)
, joka luo
uuden Paivays
-olion, jonka päiväys on annetun
päivien lukumäärän verran suurempi kuin oliolla, jolle sitä kutsuttiin.
Tässä vaiheessa voit olettaa, että jokaisessa kuukaudessa on 30 päivää.
Huomaa, että vanhan päiväysolion on pysyttävä muuttumattomana!
Ohessa on esimerkki metodin toiminnasta.
public static void main(String[] args) { Paivays pvm = new Paivays(25, 2, 2011); Paivays uusi_pvm = pvm.paivienPaasta(7); for (int i = 1; i <= 7; ++i) { System.out.println("Perjantai " + i + " viikon kuluttua on " + uusi_pvm); uusi_pvm = uusi_pvm.paivienPaasta(7); } System.out.println("Tämän viikon perjantai on " + pvm); System.out.println("Päivämäärä 790:n päivän päästä tämän viikon perjantaista on " + pvm.paivienPaasta(790)); }
Ohjelma tulostaa:
Perjantai 1 viikon kuluttua on 2.3.2011 Perjantai 2 viikon kuluttua on 9.3.2011 Perjantai 3 viikon kuluttua on 16.3.2011 Perjantai 4 viikon kuluttua on 23.3.2011 Perjantai 5 viikon kuluttua on 30.3.2011 Perjantai 6 viikon kuluttua on 7.4.2011 Perjantai 7 viikon kuluttua on 14.4.2011 Tämän viikon perjantai on 25.2.2011 Päivämäärä 790:n päivän päästä tämän viikon perjantaista on 5.5.2013
Huom! Sen sijaan, että muuttaisimme vanhan olion tilaa
palautamme uuden olion. Kuvitellaan, että Paivays
-luokalle on
olemassa metodi edista
, joka toimii vastaavasti kuin ohjelmoimamme
metodi, mutta se muuttaa vanhan olion tilaa.
Tällöin seuraava koodin pätkä tuottaisi ongelmia.
Paivays nyt = new Paivays(20,2,2011); Paivays viikonPaasta = nyt; viikonPaasta.edista(7); System.out.println("Nyt: " + nyt); System.out.println("Viikon päästä: " + viikonPaasta);
Ohjelman tulostus olisi seuraavanlainen:
Nyt 27.2.2011 Viikon päästä 27.2.2011
Tämä johtuu siitä, että tavallinen sijoitus kopioi ainoastaan viitteen olioon. Siis
itse asiassa ohjelman oliot nyt
ja viikonPaasta
viittavaat
yhteen ja samaan Paivays
-olioon.
Muunna edellisen tehtävän metodia siten, että se ottaa huomioon kunkin kuukauden päivät. Tässä vaiheessa voit jättää karkausvuoden huomiotta.
Jos talletat kuukausien päivät aputaulukkoon on kunkin kuukauden päivien lukumäärä helposti luettavissa. Muunna Paivays-luokan määrittelyä seuraavasti.
public class Paivays { // paikassa 0 = tammikuussa päiviä, 1 = helmikuussa päiviä jne... static int[] kuukaudessaPaivia = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; private int pv; private int kk; private int vv; /* Metodien määrittelyt */ }
Nyt edellisen tehtävän pääohjelman pitäisikin tulostaa seuraavasti:
Perjantai 1 viikon kuluttua on 4.3.2011 Perjantai 2 viikon kuluttua on 11.3.2011 Perjantai 3 viikon kuluttua on 18.3.2011 Perjantai 4 viikon kuluttua on 25.3.2011 Perjantai 5 viikon kuluttua on 1.4.2011 Perjantai 6 viikon kuluttua on 8.4.2011 Perjantai 7 viikon kuluttua on 15.4.2011 Tämän viikon perjantai on 25.2.2011 Päivämäärä 790:n päivän päästä tämän viikon perjantaista on 26.4.2013
Huomio metodissa paivienPaasta
karkausvuodet.
Jos vuosi on karkausvuosi helmikuussa onkin 29 päivää. Jos vuosi jaollinen 400:lla
tai se on jaollinen 4:llä, mutta ei 100:lla se on karkausvuosi. Esimerkiksi 2012 on karkausvuosi,
mutta 2100 ei ole karkausvuosi. Kannattaa tehdä apumetodi boolean karkausvuosi(int vuosi)
.
Kannattaako metodin olla staattinen vai ei-staattinen?
Edellisen tehtävän pääohjelman tulostus onkin nyt:
Perjantai 1 viikon kuluttua on 4.3.2011 ...paljon tulostusta... Päivämäärä 790:n päivän päästä tämän viikon perjantaista on 25.4.2013
Tässä käytetään hyväksi edellä muokattua Paivays
-luokkaa.
Tee luokka LottoRivi
, johon talletetaan yksittäiseen lottoriviin
kuuluvat 7 numeroa. Lisäksi lottoriviin talletetaan arvonnan päivämäärä
Paivays
-olion muodossa.
Lottonumeroden tallettamiseen kannattanee käyttää ArrayListia.
Tee luokalle seuraavat metodit, oliomuuttujat ja konstruktori.
Paivays
-olion
ja kokonaislukuja sisältävän ArrayListin ja päiväyksen ja listan sisältämät luvut.toString
Lottoriviä voi käyttää esimerkiksi seuraavalla tavalla.
public static void main(String [] args) { Paivays pvm = new Paivays(19,2,2011); ArrayList<Integer> luvut = new ArrayList<Integer>(); luvut.add(1); luvut.add(17); luvut.add(20); luvut.add(21); luvut.add(26); luvut.add(33); luvut.add(39); LottoRivi rivi = new LottoRivi(luvut, pvm); System.out.println(rivi); }
Tällöin ohjelma tulostaa:
Päivänä 19.2.2011 arvottiin luvut 1,17,20,21,26,33,39.
Lottorivit ovat samat jos ne sisältävät samat numerot. Tee LottoRivi
-oliolle
metodi samatNumerotKuin
joka palauttaa true
, jos lottorivit ovat samat.
Metodia voidaan käyttää seuraavalla tavalla:
public static void main(String [] args) { Paivays pvm = new Paivays(19,2,2011); ArrayList<Integer> luvut = new ArrayList<Integer>(); luvut.add(1); luvut.add(17); luvut.add(20); luvut.add(21); luvut.add(26); luvut.add(33); luvut.add(39); LottoRivi rivi1 = new LottoRivi(luvut, pvm); luvut.remove(0); luvut.add(7); LottoRivi rivi2 = new LottoRivi(luvut, pvm.paivienPaasta(7)); luvut.remove(6); luvut.add(1); LottoRivi rivi3 = new LottoRivi(luvut, pvm.paivienPaasta(7)); if(rivi1.samatNumerotKuin(rivi2)) { System.out.println("Rivit 1 ja 2 olivat samat."); } if(rivi1.samatNumerotKuin(rivi3)) { System.out.println("Rivit 1 ja 3 olivat samat."); } }
Ohjelma tulostaa
Rivit 1 ja 3 olivat samat.
Huom! jos ohjelmasi kuvittelee, että myös rivit 1 ja 2 ovat samat,
on vika todennäköisesti konstruktorissasi. Aidon ArrayListin kopioimisen sijaan kopioidaan
LottoRivi
-olioon kopioidaan luultavasti ainoastaan viite, jolloin kaikki
luomasi rivit viittaavat samaan ArrayListiin. Tällöin muokatessasi ArrayListia muokkaat
myös kaikkia lottorivejäsi. Uuden ArrayListin luonti vanhan pohjalta on helppoa
ns. kopio-konstruktorin avulla:
ArrayList<Integer> kopio = new ArrayList<Integer>(vanha);
Luodaan Veikkaus
-olio, joka järjestää viikottain lottoarvonnan.
Tee Veikkaus
-olio, jolla on seuraavanlainen konstruktori ja metodi.
Paivays
-olion ja tallettaa
päiväyksen.lottoArvonta
, joka edistää veikkauksen päiväystä viikolla (7 päivää)
ja palauttaa LottoRivi
-olion.
Lottoarvontaa varten kannattanee tehdä Veikkaus
-oliolle ArrayList-oliomuuttuja,
jossa on kaikki mahdolliset lottoarvonnan numerot (1-39). Luotaessa uusi lottorivi,
taulukko tämä lista sekoitetaan (Collections.shuffle
) ja kopioidaan
siitä sopiva osa liitettäväksi palautettavaan LottoRivi
-olioon.
Luokkaa voit käyttää seuraavalla tavalla:
public static void main(String[] args) { Veikkaus veikkaus = new Veikkaus(new Paivays(2,1,1971)); for (int i = 0; i < 3; ++i) { System.out.println(veikkaus.lottoArvonta()); } }
Ohjelman tulostus saattaisi olla seuraavanlainen:
Päivänä 2.1.1971 arvottiin luvut 3,11,13,15,16,19,23. Päivänä 9.1.1971 arvottiin luvut 4,10,19,21,23,36,38. Päivänä 16.1.1971 arvottiin luvut 3,8,10,20,24,26,32.
Arvottuja lukuja ei ole pakko pitää järjestyksessä.
Tehdään vuorovaikutteinen ohjelma, jossa kysytään aluksi käyttäjältä 7 numeroa lottoriviä
varten. Tämän jälkeen luodaan Veikkaus
-olio, joka arpoo lottorivejä niin kauan
kunnes käyttäjä saa 7 oikein (eli kunnes arvottu rivi on sama kuin käyttäjän antama).
Tämän jälkeen tulostetaan oikea rivi.
Ohjelman kulku saattaisi olla seuraavanlainen:
Anna 7 lukua 1 2 1 Luku 1 ei kelpaa, koska se on jo annettu tai se on liian pieni tai suuri. 15 40 Luku 40 ei kelpaa, koska se on jo annettu tai se on liian pieni tai suuri. 39 37 7 26 Aloitimme lottoamisen 19.2.2011 ... ja vihdoinkin onnisti. Päivänä 8.1.76383 arvottiin luvut 1,2,7,15,26,37,39.
Loppuivatko tehtävät kesken? Ei hätää: saatavilla on lisätehtäväsarja Ohpesokkelo. Siinä tehdään graafinen labyrinttipeli!
Vastaa kurssikyselyyn osoitteessa http://ilmo.cs.helsinki.fi/kurssit/servlet/Valinta. Valitse Ohjelmoinnin perusteet.
Muista myös lähettää lomake! Lähetysnäppäin on lomakkeen lopussa. Vastaukset ovat anonyymejä, joten ei tarvitse ujostella...
Kyselylomakkeessa on joukko kohtia joihin ei voi syystä tai toisesta vastata. Jätä sellaiset kohdat väliin. Erityisesti koetta koskevat kysymykset ovat tällaisia. Samoin kysymys 15 "harjoitusryhmän pitäjästä" ei ole tässä kurssityylissä helppo.
Vastauksilla ihan oikeasti on merkitystä laitoksen opetusta kehitettäessä!