Java-ohjelmointi, koe 27.6.2007/AW (Avoin yliopisto) Arvosteluperusteet Jaakko Saaristo --------------------------- Tehtävä 1. Tehtävässä ohjeistettiin ohjelmoimaan vain ja ainoastaan tarpeelliset osat, ja private-tyyppisistä muuttujista johtuen tehtävän oikeita ratkaisutapoja ei ole monta. Oli ymmärrettävä, että kaikkia VarillinenPiste-luokan tarjoamaksi tarkoitettuja aksessoreita/konstruktoreita ei tarvinnut ohjelmoida, vaan osa periytyi automaattisesti yliluokalta. Muunlaisista virheistä tiputettiin pisteitä vakavuuden mukaan. Pisteet jaettiin per ohjelmoitava aksessori/konstruktori seuraavasti: private double väri - Luokkaan tuli ohjelmoida vain ja ainoastaan tämä kenttä. 3 p public VarillinenPiste() - Koska yliluokassa ei ole parametritonta konstruktoria, on sellainen ohjelmoitava tähän luokkaan erikseen ja kutsuttava yliluokan parametrillista konstruktoria (tai tämän luokan kolmiparametrista konstruktoria, joka puolestaan kutsuu yliluokan konstruktoria). 2 p public VarillinenPiste(int x, int y, double väri) - Tässä myös on kutsuttava yliluokan parametrillista konstruktoria. Hyväksyttiin myös, jos arvot x ja y asetettiin aseta-metodin avulla. 2p public void aseta(int x, int y, double väri) - Tässä on kutsuttava yliluokan aseta-metodia. 2 p public void aseta(int x, int y) - Tämä metodi peritään yliluokalta, ja pisteet sai vain, jos jätti sen kirjoittamatta. 2 p public void aseta(double väri) 2 p public int kuka() - Tämä metodi peritään yliluokalta, ja pisteet sai vain, jos jätti sen kirjoittamatta. 2 p public String toString() - Tässä on kutsuttava yliluokan toString:iä. Melkein joka toisessa paperissa oli unohdettu parametrisulkeet super.toString():in kohdalla, mistä ei kuitenkaan vähäisenä syntaksivirheenä rokotettu pisteitä. 2 p Tehtävä oli sinänsä onnistunut, että se erotteli hyvin jyvät akanoista. --------------------------- Tehtävä 2. Jotta todellinen tietämys voitiin erottaa kirjavista sanallisista selityksistä, asiat oletettiin "yleisen selityksen tasolla" tunnetuksi, ja pisteitä annettiin lähinnä asioiden onnistuneesta vertaamisesta (sillä filosofisella oletuksella, että jonkin käsitteen merkityksen ymmärtäminen on sen ymmärtämistä, miten käsitten käyttö eroaa muiden käsitteiden käytöstä). Esiintyi myös paljon vastauksia, missä toistettiin kurssimateriaalin lauseita, mutta vertailu puuttui, mikä tulkittiin puutteelliseksi käsitteen ymmärtämiseksi. Olennaista oli, että vertailtavien asioiden looginen sisältö oli ymmärretty ja osattu selittää oikein, ja tässä suhteessa arvostelu oli salliva. Kohdista a ja b sai a' max 5 pistettä, kohdista c ja d a' max 4 pistettä. Epätarkat ilmaukset sallittiin, mutta loogisesti virheellisen tiedon esittämisestä rokotettiin pisteitä (yleensä kuitenkin vain yksi). a. Kurssimateriaalista: "Kun suoritetettava ohjelma viittaa ensimmäisen kerran johonkin luokkaan, tuo luokka ladataan (load) muistiin. Tällöin luokan staattinen kalusto asetetaan alkutilaan: luokkamuuttujat saavat alkuarvonsa, mahdolliset staattiset alustuslohkot - - suoritetaan. Aina kun suoritettava ohjelma luo olion eli luokan ilmentymän new-operaatiolla, tuon olion oma kalusto asetetaan alkutilaan: ilmentymän muuttujat saavat alkuarvonsa ja jokin konstruktori suoritetaan (nimenomaan tässä järjestyksessä!)." Seuraavista asioista sai pisteitä: - Olion kalusto alustetaan olion luonnin yhteydessä (new-operaatio) (2p) - Luokan lataamisen yhteydessä luokan kalusto alustetaan (ja staattiset alustuslohkot suoritetaan, ei ollut pakko mainita) (2p) - Luokan lataaminen tapahtuu ensimmäisen luokkaan kohdistuvan viittauksen yhteydessä (1p) Mainitsemisen arvoista on, että tehtävään oli niin monta vastausta, joissa toistui samat sanamuodot kuin kurssimateriaalissa, että joko kurssimateriaali oli opiskeltu tältä osin hyvin tai teksti oli osattu ottaa lunttilappuun... b. Kurssimateriaalista: "Luokkametodeita voi kutsua vaikkei luokasta olisi luotu ensimmäistäkään ilmentymää. Luokkametodi määritellään käyttäen static-määrettä. Kutsu on muotoa: Luokka.metodi(parametrit). Luokkametodi voi käyttää vain luokkamuuttujia ja kutsua vain toisia luokkametodeita! Ilmentymämetodeita voi kutsua vain olioihin soveltaen: olio.metodi(parametrit). Se määritellään ilman static-määrettä. Ilmentymämetodi voi käyttää sekä ilmentymämuuttujia että luokkamuuttujia ja kutsua sekä ilmentymämetodeita että luokkametodeita." Seuraavista asioista sai pisteitä: - Luokkametodia voi kutsua ilman olioviitettä (3p) - Luokkametodi voi käyttää vain luokkakalustoa, ilmentymämetodi sekä luokka- että ilmentymäkalustoa (2p) c. Kurssimateriaalista: "Periytyminen (inheritance) on luokan piirteiden - kenttien ja metodien - siirtymistä toiselle luokalle. Saava luokka on aliluokka (subclass), antava luokka on yliluokka (superclass). - - Aliluokka täydentää, erikoistaa, yliluokan määrittelyitä. - - Aliluokalla voi itselläänkin olla aliluokkia. Näin periytymisellä voidaan rakentaa puumainen luokkien hierarkia." Esim. seuraavista asioista sai pisteitä (max 4p): - Yliluokan metodit (ei konstruktorit) ja muuttujat periytyvät aliluokalle (2p) - Yliluokan metodeita voi erikoistaa: peittää ja kuormittaa (1p) - Luokka voi periä vain yhden toisen luokan -> puumaisuus (1p) - Polymorfismi (kutsutun metodin luokka määräytyy olion luokan, ei muuttujan tyypin mukaan) (1p) Mainitsemisen arvoista on, että huolestuttavan useassa vastauksessa oli jostain syystä väitetty virheellisesti, että luokan private-kalusto ei periydy aliluokalle! private-määre rajoittaa muuttujaan/metodiin/luokkaan viittaamisen mahdolliseksi vain kyseisen luokan sisältä, mutta kalusto kyllä on olemassa myös aliluokalla. d. Kurssimateriaalista: "Luokkaa kutsutaan abstraktiksi, jos se ei toteuta (eli implementoi) kaikkia metodeitaan. Tällainen menettely on perusteltua, kun halutaan laatia yleiskäyttöinen luokka, jonka jotkin metodit vaaditaan ohjelmoitavaksi sovelluskohtaisesti aliluokassa. Määreellä abstract ilmaistaan luokan olevan abstrakti. Myös metodi voidaan määritellä abstraktiksi. Abstraktin metodin lohko on pelkkä puolipiste: public abstract void metodi(); Vain abstraktilla luokalla voi olla abstrakteja metodeita. Luokka voidaan määritellä abstraktiksi vaikka se implementoisi kaikki metodinsa. Tällaisesta luokasta ei voida luoda ilmentymiä." ja "Javan rajapintaluokka (interface) on keino kerätä yhteen luokkia, joilla on joitakin samankaltaiseen tarkoitukseen laadittuja samaotsikkoisia metodeita. Rajapintaluokka pelkästään luettelee noiden yhteisten metodien otsikot - toteutustavasta ei sanota mitään. - - Luokan sanotaan toteuttavan (implement) rajapintaluokan kun se toteuttaa kaikki rajapintaluokan luettelemat metodit. - - Luokan alussa oleva implements-ilmaus on lupaus: luokassa on määritelty eli toteutettu kaikki kyseisen rajapintaluokan luettelemat metodit!" ja "- - on tutustuttu yhteen 'abstraktin tietotyypin' merkitykseen: kapseloidaan olion toteutuksen yksityiskohdat ja oliota käyttävällä ohjelmoijalla on vain "abstrakti käyttöliittymä" olioon. - - Tällä tavoin ajatellen rajapintaluokka voidaan nähdä jo aiemminkin mainittuna sopimuksena abstraktin tietotyypin käyttäjän ja toteuttajan välillä. Mutta tässä tapauksessa sopimus on kuitenkin pelkästään syntaktinen, se määrää vain metodien kutsun rakenteen, ei semantiikkaa." Rajapintaluokan ja abstraktin luokan käyttötarkoituksessa on paljon samaa: niiden avulla ohjelmoija tarkasti määrittelee abstraktin tietotyypin (datan ja operaatiot) sitomatta määritelmää toteutukseen. Abstrakti luokka on lähtökohtaisesti tarkoitettu perittäväksi (vaikkakin rajapintaluokka voi periä toisen rajapintaluokan!). Olennaiset tekniset erot ovat: 1. luokka voi periä vain yhden (mahdollisesti abstraktin) luokan, mutta toteuttaa useita rajapintoja, 2. abstrakti luokka voi sisältää tietosisältöä eli kenttiä (rajapintaluokka voi sisältää vain public final-tyyppisiä kenttiä), ja 3. osa abstraktin luokan metodeista voi olla toteutettu. Esim. seuraavista asioista sai pisteitä: - Abstrakti luokka voi sisältää toteutettuja metodeita (hyväksyttiin myös epätarkka väite, että abstrakti luokka ei toteuta kaikkia metodeitaan) (2p) - Abstrakti luokka voi sisältää (myös ei-public-final-tyyppisiä) kenttiä (1p) - Luokka voi periä vain yhden luokan, mutta toteuttaa useita rajapintoja (1p) --------------------------- Tehtävä 3. Tehtävän voi ratkaista monella toimivalla tavalla, jotka kaikki hyväksyttiin. Esimerkkiratkaisussa (EriSanoja.java) on ongelma on ratkaistu helpoimmalla tavalla: lisäämällä sanat Vector-olion loppuun, mikäli niitä ei jo löydy Vector-oliosta, ja lopuksi järjestämällä ja tulostamalla. Kaikki paitsi järjestäminen onnistuu Vector-luokan valmiilla metodeilla. Oli sallittua myös järjestää Vector-olio lisäysten yhteydessä käyttämällä luokan insertElementAt-metodia, mutta koska tätä ei annettu kokeen API-kuvauksessa, esimerkkiratkaisu ei käytä sitä. Tehtävässä tuli kuitenkin huomioida poikkeukset, joista ainoa relevantti on tapaus, jossa annettu tiedostonimi ei vastaa mitään olemassaolevaa tiedostoa. Arvostelun lähtökohtana oli toimiva ja ymmärrettävästi ohjelmoitu ohjelma. Esim. seuraavia tekijöitä pidettiin puutteina: - loogiset virheet - loogiset eksoottisuudet (selkeä asia tehdään erityisen hankalasti) - syntaksivirheet - harhaanjohtava tai epäselvä nimentä - mielikuvituksellinen sisentäminen/rivittäminen, sikäli kun se merkittävästi haittasi luettavuutta - jokin import-lause puuttuu - tulostuslause puuttuu ennen tiedoston nimen lukemista ("ohjelma pyytää") - poikkeuskäsittely puuttuu tiedoston luvusta - tulostaminen ruudulle tehty Vector.toString()-metodilla (tulostaa hakasulkeet ja pilkkuja) - yleinen virhe oli muuttujan esittely try-lohkon sisällä ja siihen viittaaminen sen ulkopuolelta Pisteet annettiin hyvin suuripiirteisesti seuraavien kategorioiden mukaan: - 1-5 p: Ymmärretty tehtävä loogisesti oikein ja yritetty tehdä jotain sinne päin - 6-9 p: Ymmärretty oikein ja ratkaistu suht. oikein, mutta sisältää vakavia virheitä - 10-14 p: Ratkaistu melko oikein, mutta sisältää lieviä virheitä tai puutteita - 15-17 p: Ratkaisu toimiva, korkeintaan pieniä huolimattomuusvirheitä