Java-ohjelmointi, syksy 1999 Arvosteluperusteet, tehtävä 3. Jaakko Nurro Tehtävässä oli kolme kohtaa, joista jokainen tulkittiin 5 pisteen arvoiseksi. Ensimmäinen kohta: Tehtävän ydin oli perusteltu vastaus kysymykseen miksi metodin tai muuttujan pitäisi koskaan olla yksityinen (private). Viiden pisteen arvoinen argumentaatio sisältää suunnilleen seuraavat asiat: Private-määrittely on järkevän olio-ohjelmoinnin perusteita, sillä se mahdollistaa olion käyttörajapinnan ja toteutuksen erottamisen toisistaan, 'perinteisen ohjelmoinnin kielellä' siis ns. abstraktin tietotyypin toteuttamisen. Käyttörajapinta on mahdollista rajata järkevästi tarjoamalla olion yksityisen tietorakenteen käsittelyyn ainoastaan tietyt julkiset työkalut. Nämä julkiset työkalut voidaan sitten toteuttaa siten, etteivät ne saata oliota epämielekkääseen tilaan. Tällainen ohjelmointi helpottaa myös olion toteutuksen muuttamista. Asian kuvaaminen erilaisin valottavin esimerkin oli täysin tuon yleisen vastauksen arvoinen. Yleisimmin sai kolme pistettä, jos perusteluiksi ei laittanut kaikkea tunnetuksi oletettua faktaa. Lisäksi pisteitä meni perustelujen epäselvyydestä tai epämääräisyydestä. Javassa näkyvyysmäärittelyt eivät vaikuta nimiavaruuteen mitenkään. Tämä usein esiintynyt käsitys perusteluina privaten käytölle ei tuonut pisteitä. Toinen kohta: Toisessa kohdassa katsoin oliko vastattu seuraaviin kysymyksiin: - Miten voit luoda ilmentymän luokasta L1 (parametrin tyyppi abstrakti luokka)? - Vastaus: antamalla parametriksi viitteen abstraktin luokan ei-abstraktin aliluokan ilmentymään. (1 piste) - Miksi kukaan haluaisi ohjelmoida abstraktia luokkaa? - Vastaus: (Wikla) Abstrakteja luokkia voi käyttää ns. public interfacen toteuttamiseen, jonkin luokan julkinen, käyttäjälle tarkoitettu kalusto määritellään erillisenä abstraktina luokkana ilman metodien toteutusta. Luokka joka metodit toteuttaa, jää käyttäjältä piiloon. Tämän muotoista vastausta harva kuitenkaan keksi, joten hyväksyin huomiot yleisestä luokasta, joka toimii polymorfismin kautta ulkoisena rajapintana konkreettisille aliluokilleen. Tämän eksplisiittisesta ja selkeästä selittämisestä sai 2 pistettä, vajaammista ja epäselvemmistä yhden. Pelkkä valottava esimerkki, josta ymmärsi vastaajan ymmärtäneen, riitti parhaimmillaan kahteen pisteeseen. - Entä jos T1 on rajapintaluokka? - Vastaus: Konstruktori tarvitsee parametrikseen ilmentymän luokasta, joka toteuttaa (implements) T1-rajapintaluokan. (1 piste) - Mihin rajapintaluokkaa käytetään? - Vastaus: ks. public interface yltä. Rajapintaluokka tarjoaa lisää tyyppimääreitä luokalle sen yliluokkien lisäksi, sillä rajapinnan toteuttavaa luokka voidaan käyttää rajapintaluokan ilmentymänä. Täten saadaan joidenkin kielten moniperinnän polymorfismiominaisuudet käyttöön, mutta ei tule ongelmaa päällekäin periytyvästä aineksesta. Rajapintaluokkaa voidaan käyttää siis yhdistämään myös luokkia, jotka eivät ole saman luokan aliluokkia Kohdasta saattoi saada yhden pisteen, jos osasi kertoa tuon. Epämääräiset viittaukset sopimukseen metodien toteuttamisesta herättivät kysymyksen miksi tehdä tällainen sopimus, ja vihjailut moniperinnästä taas miten rajapintaluokan käyttö on javan vastine moniperinnälle. Moniperintää ei tarvinnut edes mainita, jotta sai pisteen, jos osasi selittää asian muuten. Esimerkit kävivät tähän myös. Koko toisesta kohdasta saattoi saada yhden pisteen, jos teki lähinnä hyviä hajahuomioita abstraktista luokasta ja rajapintaluokista. Jostain syystä moni sotki tässä L1:n ja T1:n tavoilla, joista en sitten antanut pisteitä, vaikka luokannimiä keskenään vaihtelemalla olisi saanut oikeankin vastauksen. Myöskään L1:n ei erityisesti tarvitse toteuttaa T1-rajapintaa. Kolmas kohta: Luokkaan voidaan aina viitata sen koko nimellä eli pakkaus.luokka. Tämä on ainut tapa saada käyttöön useampia samannimisiä (siis ilman pakkausnimeä) luokkia samassa käännösyksikössä. Importia ei lainkaan tähän tarvita, mutta sen mainitsemisesta en sakottanutkaan ellei sitten väittänyt ristiriitaisia. Ilmaus 'import pakkaus.luokka;' tuo luokan eksplisiittisesti käyttöön, jolloin siihen voi viitata vastedes pelkällä luokannimellä. Yhdessä käännösyksikössä voi kuitenkin yhdellä nimellä viitata vain yhteen luokkaan kerrallaan, kahden samannimisen luokan eksplisiittinen tuominen aiheuttaa käännösaikaisen virheen. Implisiittinen 'import pakkaus.*' ei ole tehtävässä erityisen hyödyllinen, sillä K1:n kanssa samassa pakkauksessa oleva L3:n versio asettuu sen edelle. Tämän importin mainitseminen ei ollut mikään synti, kunhan eilaskettu sen varaan mitään. K1:n kanssa samassa pakkauksessa oleva L3 on käytössä pelkällä luokkanimellä, ellei sen edelle eksplisiittisesti tuoda jotain muuta luokkaa. Jos osasi kertoa miten saa kaikki luokat käyttöönsä K1:een, ja miten valitaan eksplisiittisella importilla niistä se, johon viitataan pelkällä luokan nimellä, sai 5 pistettä. Jos osasi kertoa luokkien pitkien nimien käytöstä (eli sai kaikki luokat käyttöönsä), mutta ei maininnut muita tapoja saada luokkia käyttöönsä, sai 4 pistettä. Jos ei osannut saada kaikkia luokkia käyttöönsä tai selitti ristiriitaisia luokkien käytöstä, sai vähemmän. Tyypillinen virhe oli unohtaa, että L3 löytyy K1:n kanssa samasta pakkauksesta, ja siten väittää että java.lang.L3 on käytettävissä pelkällä luokan nimellä ilman mitään importia. Nimien etsintäjärjestystä ei tarvinnut selittää, mutta sen käyttö pohjana selvensi yleensä. Harhaoppiset esitykset nimien etsintäjärjestykseksi olivat virhe, jos niiden takia ei saanut käyttöönsä sitä luokkaa jota vastaaja lupasi.