Nyt tarvis kiireellistä apua.... Auttakaahan Java nörtit.
Tarkoituksena toteuttaa tietovarasto käyttämällä Javan taulukkoa. Pitää toteuttaa Iterator ja Collection rajapintojen metodit. Aika pitkällä jo olen, mutta pari metodia ei vielä toimi, enkä keksi mikä vikana.
Metodit jotka eivät toimi: addAll, removeAll
Tässä koodi (poistin koodista epätarpeelliset kohdat):
import java.lang.reflect.Array; import java.util.*; public class Taulukko<TYPE> implements Collection<TYPE>, Iterator<TYPE> { public int alkuperainenKoko; public Object alkiot[]; public int alkioita = 0; public int it; Taulukko(int koko, Class<TYPE> luokka) { alkiot = (TYPE[]) Array.newInstance(luokka, koko); alkuperainenKoko = koko; } private void kasvataTaulukko(int tarve) { Class arrayType = alkiot.getClass().getComponentType(); Object[] copy = (Object[])java.lang.reflect.Array.newInstance(arrayType, alkiot.length + tarve); alkiot = copy; } public boolean remove(Object o) { for(Iterator<TYPE> i = this.iterator(); i.hasNext();) { if((TYPE) i.next() == o) { i.remove(); return true; } } return false; } public boolean addAll(Collection<? extends TYPE> c) { Object[] lisattavat = c.toArray(); int uudet = lisattavat.length; if (uudet > size()) {kasvataTaulukko(uudet);} System.arraycopy(lisattavat, 0, alkiot, size(), uudet); return uudet != 0; } public boolean removeAll(Collection<?> c) { boolean virheita = false; for(Iterator<TYPE> i = (Iterator<TYPE>) c.iterator(); i.hasNext();) if(!remove(i.next())) virheita = true; return !virheita; } public Iterator<TYPE> iterator() { return this; } public boolean hasNext() { if(it < alkioita) return true; return false; } public TYPE next() { return (TYPE) alkiot[++it]; } public void remove() { alkiot[it] = alkiot[--alkioita]; alkiot[alkioita] = null; } public static void main(String[] args) { // luodaan uusi testitaulukko Taulukko<String> testi1 = new Taulukko<String>(100, String.class); // lisätään taulukkoon pari elementtiä testi1.add("Mikko"); testi1.add("Tero"); // luodaan toinen testitaulukko Taulukko<String> testi2 = new Taulukko<String>(100, String.class); // lisätään tännekin pari elementtiä, joista toinen on sama kuin testi1 taulukossa testi2.add("Tero"); testi1.addAll(testi2); // pitäisi lisätä testi2:n kamat testi1:een System.out.println(testi2.alkioita); // antaa tuloksena 1, vaikka pitäisi antaa 3 testi1.removeAll(testi2); // pitäisi poistaa "Tero" System.out.println(testi2.alkioita); // edelleen antaa tuloksena 1 ??? } } /** Alkio-luokka josta luodaan uudet alkiot */ class Alkio { Alkio() { } }
Saako vastata, vaikka ei ole ihan oikea Java-nörtti? Huomasin pari kohtaa.
Ensinnäkin, ainoa paikka missä muutat alkioita-jäsenmuuttujan arvoa, on kohta missä sitä vähennetään. Sitä pitäisi myös kasvattaa, kun taulukkoon laitetaan uutta tietoa. Tarkista joka kohta, jossa sen pitäisi muuttua ja varmistu, että muutat sitä oikein.
Toiseksi, metodissa kasvataTaulukko rakennetaan uusi taulukko, mutta en näe mitään koodia, mikä viittaisi vanhojen alkioiden kopioimiseen vanhasta taulukosta uuteen. Eikö ne nyt heitetä vain hukkaan tässä metodissa?
Kolmanneksi: Testaa asioita paremmin, niin löydät virheet ihan itse. Sinun pitäisi katsoa joka operaation jälkeen, että luokkasi ns. invariantit pitävät paikkansa. Nämä tarkoittavat asioita, jotka ovat aina totta onnistuneiden operaatioiden jälkeen. ESimerkkinä käy juuri tuo alkioita-jäsenmuuttuja, jonka pitäisi kertoa paljonko taulukossa on alkioita. Sen pitäisi kasvaa aina yhdellä, kun yksi uusi alkio lisätään, jne. Invariantti on, että sen arvo on aina sama kuin taulukossa olevien alkioiden lukumäärä.
Jos katsot debuggerilla rivi riviltä ohjelman suoritusta, näet sitä kautta kohdan missä alkioita-muuttujan arvo menee luvattomaksi. Olet juuri paikallistanut sillä tavalla bugin. Debuggeri on kiva vekotin.
Toinen tapa olisi tulostaa luokan kaikki tiedot aina joka operaation jälkeen. Näkisit heti, missä vaiheessa tarkalleen taulukosta katoaa tietoa tai sen tiedot menevät muuten vääriksi. Ehdotankin, että jos on kiire, teet tämän. Kirjoita metodi, joka tulostaa luokan kaiken tiedon, ja kutsu sitä joka välissä, kun koodisi käsittelee luokan oliota millään tavalla. Sitten lue joka kohta, ja katso että tiedot ovat mitä oletat. Jossakin vaiheessa ne eivät ole, koska lopputulos ainakin on väärin.
Pointti: Ensimmäinen vaihe virheen korjauksessa on sen tarkka paikallistaminen.
Myös testien kirjoittaminen ohjelman toiminnoille on tyypillistä Java-ohjelmoinnissa. En tiedä oletko tutustunut siihen, mutta sehän on se virallinen tapa varmistua, että koodissa ei ole sellaisia virheitä, mitkä ne testit löytäisivät. Siinä voivat paremmin Javaa osaavat neuvoa sinua, kun minä en oikein tiedä mitä testikirjastoa nykyään kannattaa käyttää tai muutakaan Javan hienouksia. Minun nyt piti jotain kuitenkin arvailla, kun kukaan muu ei näytä jaksavan vielä vastata kyselyysi. Toivottavasti oli jotain apua.
Aihe on jo aika vanha, joten et voi enää vastata siihen.