581326-3 Java-ohjelmointi, koe 24.6.2004/AW (Avoin yliopisto)

Kirjoita jokaisen vastauspaperisi alkuun kurssin nimi ja kokeen päivämäärä sekä nimesi, henkilötunnuksesi ja allekirjoituksesi. Kokeessa saa käyttää A4-kokoista muistilappua, "lunttilappua".

  1. Basilisko on yksinkertainen, mutta silti hyvin yksilöllinen olento. Jokaisella basiliskolla on yksikäsitteinen, syntymässä saatu järjestysnumero, ns. yksilöllisyys, joka ei koskaan voi muuttua, eikä kukaan muu koskaan voi saada samaa yksilöllisyyttä.

    Basiliskon perimä on String-olio. Basiliskot lisääntyvät vain pariutumalla. Lapsi saa jomman kumman vanhempansa perimän sellaisenaan. Todennäköisyys molemmille on yhtä suuri. Perimän arvonnan voi suorittaa lauseella if (Math.random()<0.5) ...

    1. Mallinna basilisko luokkana Basilisko, jossa kaikki kentät ovat luonnollisesti private, ja jossa on julkiset välineet (konstruktori ja aksessorit):
      • public Basilisko(String perimä)
      • public String mikäOnPerimä()
      • public Basilisko pariudu(Basilisko toinen)
      • public String toString(), tulostusasu on muotoa: (yksilöllisyys): perimä, ks. esim.

    2. TuplaBasilisko on basiliskon sukulainen. Se eroaa basiliskosta vain pariudu-metodin osalta: TuplaBasiliskon lapsi saa perimäkseen vanhempiensa perimämerkkijonojen katenaation, so. perimää esittävät merkkijonot liitetään yhteen. Toteuta TuplaBasilisko luokan Basilisko aliluokkana. Ohjelmoi uudelleen vain tarvittavat osat - esimerkiksi uusia kenttiä ei tarvita.

    Esimerkki: (juuri näin pitää tulostaa: olion järjestysnumerokin kuuluu siis tulostusasuun, kolmas tulostus voi tietenkin olla joko "(3): Maija" tai "(3): Matti")

        Basilisko isä   = new Basilisko("Matti");
        Basilisko äiti  = new Basilisko("Maija");
        Basilisko lapsi = isä.pariudu(äiti);
        System.out.println(isä);    // tulostus: (1): Matti
        System.out.println(äiti);   // tulostus: (2): Maija
        System.out.println(lapsi);  // tulostus: (3): Maija
    
        TuplaBasilisko äijä  = new TuplaBasilisko("Kalle"); // numero 4
        TuplaBasilisko ämmä  = new TuplaBasilisko("Kaija"); // numero 5
        TuplaBasilisko pentu = ämmä.pariudu(äijä);
        System.out.println(pentu); // tulostus: (6): KaijaKalle
    
    
                                                         (18 pistettä)
    

  2. "Mä en kerta kaikkiaan enää kestä noita sun puheitasi 'abstrakteista luokista' ja 'rajapintaluokista'!" Näin parahti ystäväsi kuunneltuaan intoiluasi Javan hienouksista. Ystäväsi hallitsee Java-kielen muuten oikein hyvin - jopa luokat ja luokkien hierarkiat ovat hänelle tuttuja - mutta nuo mainitut välineet herättävät hänessä vain asiantuntematonta ärtymystä. Auta ystävääsi ymmärtämään, mistä oikein on kysymys ja mihin noita välineitä voi käyttää. Laadi siis asiasta kirjallinen selitys, joka tietenkin sisältää myös valaisevia ohjelmaesimerkkejä (enimmäispituus 1 konseptiarkki, so. 4 sivua). Vastauksen arvioinnissa otetaan huomioon selostuksen ajateltu lukija. Älä siis kirjoita tarkastajalle, joka jo tuntee asian, kirjoita tuolle ystävälle!
                                                         (17 pistettä)
    

  3. Käytössäsi on char-arvoista eli merkeistä muodostuvan tiedoston lukemiseen luokka Merkkitiedosto. Luokalla on konstruktori Merkkitiedosto(String tiedostonNimi). Parametrina annetaan syöttötiedoston nimi. Merkkejä luetaan ilmentymämetodilla public char lueMerkki(). Tiedoston loppumisen metodi ilmaisee palauttamalla arvonaan ns. "null-merkin" eli merkkivakion '\u0000'. Kun siis metodin palauttama merkki on yhtä suuri kuin vakio '\u0000', tiedosto on loppu. Rivin loppumisen metodi lueMerkki ilmaisee palauttamalla arvonaan merkin '\n'.

    Luokassa Merkkitiedosto ei ole varauduttu poikkeuksiin! Konstruktorin ja aksessorin kutsuja joutuu siis itse käsittelemään poikkeukset!

    1. Toteuta luokka Rivitiedosto luokan Merkkitiedosto avulla. Rivitiedosto-luokalla on konstruktori Rivitiedosto(String tiedostonNimi).

      Rivitiedosto-olion avulla tiedostoa voidaan lukea (tuttuun tapaan) riveittäin. Kukin rivi saadaan siis String-oliona, jossa ei ole mukana merkkitiedostossa esiintyvää rivin loppumerkkiä '\n'.

      Rivitiedoston rivit luetaan aksessorilla public String lueRivi(), joka palauttaa arvonaan tiedoston seuraavan rivin.

      Kun tiedosto on loppu, lueRivi palauttaa arvon null.

      Poikkeukset pitää käsitellä luokassa Rivitiedosto siten, että sen ilmentymien käyttäjän ei tarvitse kantaa niistä huolta: Jos Merkkitiedosto-olion luonti epäonnistui, lueRivi()-metodi palauttaa alusta alkaen arvon null. Jos lueMerkki()-metodin kutsu johtaa poikkeukseen, lueRivi()-metodi palauttaa arvon null. Rivitiedosto-olion käyttäjälle siis alunperin rikkinäinen tai kokonaan puuttuva tiedosto näyttää tiedostolta, jossa ei ole lainkaan rivejä Kesken kaiken rikkoutuva tiedosto näyttää vain loppuvan.

      Huom: Riittää että Rivitiedosto käsittelee Merkkitiedoston aiheuttamat poikkeukset vain kaikkein yleisimmällä tasolla, Exception-poikkeuksina.

    2. Ohjelmoi Rivitiedostoa käyttäen sovellus, joka laskee käyttäjän antaman tiedoston rivien lukumäärän.

    Huom: Luokka Merkkitiedosto siis on käytettävissä, älä ihmeessä sitä enää ohjelmoi!

                                                         (17 pistettä)
    

Onnea kokeeseen ja hauskaa kesää!