4 a: Tehtävänanto: /*1*/ private final Collection alkiot = new ArrayList(); /*2*/ private final ArrayList alkiot = new ArrayList(); /*3*/ private final Collection alkiot = new Collection(); Tapaukset 1 ja 2 ovat sallittuja. Molemmissa luodaan ArrayList, joka käsittelee Jasen-tyyppisiä olioita. Tapauksessa 1 luotu ArrayList sijoitetaan Collection-tyyppiseen viitemuuttujaan nimeltään "alkiot". Tämä on sallittua koska ArrayList toteuttaa Collection-rajapinnan. Tapaus 2 on luonnollisesti sallittu, koska ArrayList-tyyppinen olio sijoitetaan ArrayList-tyyppiseen viitemuuttujaan. Tapaus 3 on virheellinen, koska Javan peruskirjastossa oleva Collection on rajapinta. Rajapinnat eivät sisällä toiminnallisuutta, vaan se ainoastaan esittelee rajapintaan kuuluvat julkiset metodit ja attribuutit. Siispä siinä ei myöskään ole muodostajaa, joten sitä ei voi muodostaa. Yleisin virhe oli, että lauseen rakennetta ei ollut ymmärretty. Esimerkiksi muutamat opiskelijat väittivät tapauksessa 1 sijoituksen tapahtuvan vasemmalta oikealle. vaikka nämä lauseet eivät millään tavoin poikkea muista Java-kielisistä lauseista, joissa sijoitus tapahtuu oikealta vasemmalle. Älkää antako new-avainsanan häiritä! Ongelmia oli myös rajapinnan ymmärtämisen kanssa. Eli se, että on mahdollista sijoittaa rajapinnan tyyppiseen viitemuuttujaan rajapinnan toteuttavan luokan olio, esimerkiksi Collection <- ArrayList. Osalla oli myös mennyt abstaraktit luokat ja hierarkiat sekaisin rajapintojen kanssa. Hierarkiat kuuluvat perinnän maailmaan. En vähentänyt pisteitä, mikäli kyse oli vain väärän termin käytöstä. Pisteytys kohdassa 4 a perustui siihen, että täydellisessä vastauksessa tiedettiin Collectionin olevan rajapinta, jonka ArrayList toteuttaa ja että rajapinnoista ei voi luoda olioita. Täydelliseen vastaukseen kuuluu myös, että on maininnut tapauksissa luotavien ArrayListien olevan rajoitettuja sisältämään vain Jasen-tyyppisiä olioita. 4 b: Tehtävänanto: Jos esitellään private final ArrayList alkiot = new ArrayList(); ja lisätään: alkiot.add(345); ja luetaan int luku = alkiot.get(0); niin mitä tapahtuu ja miksi? Tehtävässä luodaan kohdan 4a tapaan ArrayList, tässä tapauksessa sellainen, joka on rajoitettu sisältämään Integer-tyyppisiä olioita. Kun alkiot.add -metodille välitetään Integer-tyyppisen olion sijaan int-tyyppinen vakio (345), suoritetaan koodissa näkymätön autoboxing-toiminto ja listaan lisättävä alkio on todellisuudessa new Integer(345). Kun alkiot.get suoritetaan, toimii autoboxing käänteisesti, eli konepellin alla suoritetaan alkiot.get(0).intValue(). Täydelliseen vastaukseen edellytin, että on selittänyt jokaisen rivin osalta, mitä rivit tekevät (ulkopuolelta katsoen) ja selittänyt (sisältäpäin katsoen), mitä tapahtuu. Eli toisin sanoen, että miksi Integer-tyyppisiä olioita vastaanottava alkiot-muuttuja voi ottaa vastaan int-tyyppisen muuttujan ja sama toisinpäin get-metodin kutsumisen osalta. Autoboxing-sanan muistamisella saattoi saattoi saada kompensoitua muuten virheitä sisältävää vastausta, mutta täydet pisteet sai myös ilman termin muistamista, kunhan oli selittänyt toimintaperiaatteen riittävän kattavasti. Yleisimpiä virheitä oli, että oli unohdettu, että tehtävänannossa oli sekä "mitä tapahtuu" ja "miksi". Jos oli selittänyt rivien tarkoituksen, mutta ei ollut ymmärtänyt, että tapahtuu "näkymättömiä" tyyppimuunnoksia, saattoi saada puoli pistettä tai yhden pisteen, riippuen vastauksen perusteellisuudesta. Myöskään pelkkä vastaus "autoboxing" ei tuonut täysiä pisteitä, koska tässäkin tapauksessa oli vastattu vain toiseen kysymyksistä. Tehtävänannossa oli huonoa epämääräisyys, mutta otin sen huomioon pisteytyksessä, että kysymykseen saattoi olla hiukan vaikeaa saada otetta. Toisaalta tentissä ei kukaan esittänyt kysymyksiä, joten voidaan olettaa jokaisen vastaajan ymmärtäneen tämän tehtävänannon. 4 c: if ( Tiedosto.lueTiedosto("koe.txt").length() != 0 ) { String [] rivit = Tiedosto.lueTiedosto("koe.txt"); ... } Tiedosto.lueTiedosto(nimi) lukee parametrina annetun tiedostonnimen 'nimi' sisällön ja palauttaa sen merkkijonolistana, jossa jokainen tiedoston rivi on omalla rivillään. ... Tehtävänantoon oli jäänyt kaksi epätäsmällisyyttä, eli olin tarkoittanut tehtävää laatiessani seuraavaa: "Tiedosto.lueTiedosto(nimi) lukee parametrina annetun tiedostonnimen 'nimi' sisällön ja palauttaa sen merkkijonotaulukkona, jossa jokainen tiedoston rivi on omana alkionaan." He, jotka olivat huomanneet virheeni, että listaa ei voi sisältää taulukkoon, saavat nöyrimmät suosionosoitukseni, joka näkyy tehtävän pisteytyksessäkin. Täydellisessä vastauksessa oli havaittu, että tiedosto luetaan kahdesti. Ensimmäinen luku tapahtuu ehtolausessa ja toinen sen jälkeisellä rivillä. Tiedosto myöskin luetaan aina kokonaan muistiin riippumatta siitä, tarvitaanko sen kaikkea sisältöä muistissa. Tämä kuluttaa huomattavasti enemmän muistia kuin jos rivit luettaisiin yksi kerrallaan tietokoneen keskusmuistiin. Tiedosto voi myös muuttua ensimmäisen ja toisen lukukerran välissä. Tämä on harvinaista, mutta mahdollista. (Tätä kukaan vastanneista ei ollut hoksannut). Muita havaittuja ongelmia toteutuksessa oli, että tiedostonnimi annetaan merkkijonona "koe.txt" kahdesti ja tätä varten olisi voinut käyttää vakiomerkkijonoa. Myöskään poikkeustapauksista ei tullut mitään muuta tietoa kuin että length=0 tai ainakaan sitä ei ollut otettu huomioon esimerkkikoodissa. Lisäksi toteutuksen positiivisia puolia käsiteltiin ja niitä on ainakin selkeys ja abstrahointi. Edellisessä kappaleessa mainittuja seikkoja ei tullut mieleen tehtävänantoa suunniteltaessa, mutta luonnollisesti näiden havaitsemisesta sai pisteitä. Siispä monet saivat tehtävästä täydet 2 pistettä, vaikka kaikkia edellyttämiäni asioita ei ollutkaan mainittu. Merkittävin vastaajia erotellut seikka oli, että osa ei ollut havainnut, että tiedosto luetaan kahdesti. Tehtävästä sai melko helposti pisteitä kunhan vain oli pohtinut ajatuksen kanssa. Tämä tehtävä erosikin tyypillisistä "insinöörikysymyksistä" ja lähestyi hiukan koodin esteettisyyden diskurssia. Tässä hyvin pärjänneillä on mielestäni tilausta ohjelmistotekniikan alalla.