Luentomateriaali. Informaatioverkostot: Studio 1. Janne Käki MUUTTUJAT SWING POLYMORFISMI UML-KAAVIOT SOVELMAT SILMUKAT POIKKEUKSET JAVADOC



Samankaltaiset tiedostot
Java-API, rajapinnat, poikkeukset, UML,...

Muusta kuin vesisioista

Taulukot, silmukat ja muut joka koodin pikku veijarit

Sovelmat. Janne Käki

Vesisika. metsiemme työmyyrä.

Javan perusteita. Janne Käki

JAVA-PERUSTEET. JAVA-OHJELMOINTI 3op A JAVAN PERUSTEET LYHYT KERTAUS JAVAN OMINAISUUKSISTA JAVAN OMINAISUUKSIA. Java vs. C++?

Taulukot. Jukka Harju, Jukka Juslin

Java kahdessa tunnissa. Jyry Suvilehto

812341A Olio-ohjelmointi Peruskäsitteet jatkoa

Kääreluokat (oppikirjan luku 9.4) (Wrapper-classes)

Ohjelmointitaito (ict1td002, 12 op) Kevät Java-ohjelmoinnin alkeita. Tietokoneohjelma. Raine Kauppinen

Ohjelmoinnin jatkokurssi, kurssikoe

Java layoutit. Juha Järvensivu 2007

Olio-ohjelmointi Javalla

Java ja grafiikka. Ville Sundberg

Metodit. Metodien määrittely. Metodin parametrit ja paluuarvo. Metodien suorittaminen eli kutsuminen. Metodien kuormittaminen

2. Lisää Java-ohjelmoinnin alkeita. Muuttuja ja viittausmuuttuja (1/4) Muuttuja ja viittausmuuttuja (2/4)

JAVA-OHJELMOINTI 3 op A274615

Rajapinta (interface)

JAVA-OHJELMOINTI 3 op A274615

Java-kielen perusteet

16. Javan omat luokat 16.1

Ohjelmassa henkilön etunimi ja sukunimi luetaan kahteen muuttujaan seuraavasti:

Sisältö. 2. Taulukot. Yleistä. Yleistä

Sisällys. 14. Poikkeukset. Johdanto. Johdanto

Yleistä. Nyt käsitellään vain taulukko (array), joka on saman tyyppisten muuttujien eli alkioiden (element) kokoelma.

14. Poikkeukset 14.1

Sisällys. 14. Poikkeukset. Johdanto. Johdanto

Opintojakso TT00AA11 Ohjelmoinnin jatko (Java): 3 op Taulukot & Periytyminen

Tietojen syöttäminen ohjelmalle. Tietojen syöttäminen ohjelmalle Scanner-luokan avulla

Ohjelmointi 2 / 2010 Välikoe / 26.3

14. Poikkeukset 14.1

Java-kielen perusteet

Sisältö. 22. Taulukot. Yleistä. Yleistä

Listarakenne (ArrayList-luokka)

Harjoitus Olkoon olemassa luokat Lintu ja Pelikaani seuraavasti:

Ohjelmointitaito (ict1td002, 12 op) Kevät Java-ohjelmoinnin alkeita. Tietokoneohjelma. Raine Kauppinen

Informaatioteknologian laitos Olio-ohjelmoinnin perusteet / Salo

9. Periytyminen Javassa 9.1

Vertailulauseet. Ehtolausekkeet. Vertailulauseet. Vertailulauseet. if-lauseke. if-lauseke. Javan perusteet 2004

ITKP102 Ohjelmointi 1 (6 op)

Olion elinikä. Olion luominen. Olion tuhoutuminen. Olion tuhoutuminen. Kissa rontti = null; rontti = new Kissa();

Ohjelmointi 2 / 2008 Välikoe / Pöytätestaa seuraava ohjelma.

20. Javan omat luokat 20.1

Sisällys. 20. Javan omat luokat. Java API. Pakkaukset. java\lang

Javan perusteet. Ohjelman tehtävät: tietojen syöttö, lukeminen prosessointi, halutun informaation tulostaminen tulostus tiedon varastointi

Opintojakso TT00AA11 Ohjelmoinnin jatko (Java): 3 op. Tietorakenneluokkia 2: HashMap, TreeMap

JAVA on ohjelmointikieli, mikä on kieliopiltaan hyvin samankaltainen, jopa identtinen mm. C++

Sisällys. 12. Näppäimistöltä lukeminen. Yleistä. Yleistä

Java-kielen perusteet

12. Javan toistorakenteet 12.1

Java-kielen perusteita

Opintojakso TT00AA11 Ohjelmoinnin jatko (Java): 3 op. Poikkeukset ja tietovirrat: Virhetilanteiden ja syötevirtojen käsittely

Tietorakenteet. JAVA-OHJELMOINTI Osa 5: Tietorakenteita. Sisällys. Merkkijonot (String) Luokka String. Metodeja (public)

17. Javan omat luokat 17.1

Metodien tekeminen Javalla

Java-kielen perusteita

Luokka Murtoluku uudelleen. Kirjoitetaan luokka Murtoluku uudelleen niin, että murtolukujen sieventäminen on mahdollista.

Sisällys. JAVA-OHJELMOINTI Osa 7: Abstrakti luokka ja rajapinta. Abstraktin luokan idea. Abstrakti luokka ja metodi. Esimerkki

12. Javan toistorakenteet 12.1

11. Javan toistorakenteet 11.1

Ohjelmoinnin perusteet Y Python

815338A Ohjelmointikielten periaatteet Harjoitus 5 Vastaukset

Muuttujat ja kontrolli. Ville Sundberg

8. Näppäimistöltä lukeminen 8.1

Sisältö. Johdanto. Tiedostojen lukeminen. Tiedostojen kirjoittaminen. 6.2

Poikkeustenkäsittely

Osoitin ja viittaus C++:ssa

Sisällys. 6. Metodit. Oliot viestivät metodeja kutsuen. Oliot viestivät metodeja kutsuen

Pakkauksen kokoaminen

15. Ohjelmoinnin tekniikkaa 15.1

Alkuarvot ja tyyppimuunnokset (1/5) Alkuarvot ja tyyppimuunnokset (2/5) Alkuarvot ja tyyppimuunnokset (3/5)

1. Omat operaatiot 1.1

Sisällys. 1. Omat operaatiot. Yleistä operaatioista. Yleistä operaatioista

7/20: Paketti kasassa ensimmäistä kertaa

9. Periytyminen Javassa 9.1

4. Luokan testaus ja käyttö olion kautta 4.1

Sisällys. 19. Olio-ohjelmointia Javalla. Yleistä. Olioiden esittely ja alustus

Opintojakso TT00AA11 Ohjelmoinnin jatko (Java): 3 op

A) on käytännöllinen ohjelmointitekniikka. = laajennetaan aikaisemmin tehtyjä luokkia (uudelleenkäytettävyys)

Opintojakso TT00AA11 Ohjelmoinnin jatko (Java): 3 op. Standardi- ja tietorakenneluokkia

Sisällys. Metodien kuormittaminen. Luokkametodit ja -attribuutit. Rakentajat. Metodien ja muun luokan sisällön järjestäminen. 6.2

Rajapinnasta ei voida muodostaa olioita. Voidaan käyttää tunnuksen tyyppinä. Rajapinta on kuitenkin abstraktia luokkaa selvästi abstraktimpi tyyppi.

12. Näppäimistöltä lukeminen 12.1

Sisällys. 9. Periytyminen Javassa. Periytymismekanismi Java-kielessä. Periytymismekanismi Java-kielessä

Sisällys. 11. Javan toistorakenteet. Laskurimuuttujat. Yleistä

Olio-ohjelmointi Käyttöliittymä

Taulukot. Taulukon määrittely ja käyttö. Taulukko metodin parametrina. Taulukon sisällön kopiointi toiseen taulukkoon. Taulukon lajittelu

17. Javan omat luokat 17.1

1 Tehtävän kuvaus ja analysointi

Ohjelmistojen mallintaminen viikon 4 laskareiden mallivastauksia

Luokat ja oliot. Ville Sundberg

Sisältö Johdanto. Tiedostojen lukeminen. Tiedostojen kirjoittaminen. 26.2

ITKP102 Ohjelmointi 1 (6 op)

Sisällys. Yleistä attribuuteista. Näkyvyys luokan sisällä. Tiedonkätkentä. Aksessorit. 4.2

8. Näppäimistöltä lukeminen 8.1

Rinnakkaisohjelmointi kurssi. Opintopiiri työskentelyn raportti

OutputStream ja InputStream. Tietovirrat ja niiden suunnat. Tietovirtojen käyttö. FileInputStream esimerkki. DataOutputStream ja DataInputStream

Luento 6. T Ohjelmoinnin jatkokurssi T1 & T Ohjelmoinnin jatkokurssi L1. Luennoitsija: Otto Seppälä

Transkriptio:

Informaatioverkostot: Studio 1 1 Luentomateriaali Janne Käki 2006 MUUTTUJAT SILMUKAT TAULUKOT MERKKIJONOT 5 11 17 23 POLYMORFISMI POIKKEUKSET JAVA-API TIETOVIRRAT 28 33 35 37 SWING SOVELMAT 2D-GRAFIIKKA SÄIKEET JA SWING 40 45 50 60 UML-KAAVIOT JAVADOC PAKKAUKSET SUUNNITTELUSTA 63 64 66 70

2 Muutama perusasia Tietokone tekee juuri (ja vain) sen, mitä käsketään. Tietokone ymmärtää vain syntaksia (sanojen kirjoitusasua), ei semantiikkaa (sanojen merkitystä). Muuttujat ja metodit voi tietokoneen puolesta nimetä (melkein) ihan miten vaan, olennaista on vain, että samasta muuttujasta tai metodista käytetään johdonmukaisesti samaa nimeä. Java-kielessä on kuitenkin joitakin kymmeniä avainsanoja (public, private, int, void, true, null, return,...), jotka on varattu tiettyyn käyttöön. Näitä ei siis voi valita muuttujien nimiksi. Se, että muuttujat ja metodit nimetään fiksusti ja käyttötarkoitusta kuvaavasti, on tärkeää nimenomaan (ja vain) koodia lukevan ihmisen kannalta. Ohjelman suoritus on normaalisti (virheettömänä) täysin näkymätöntä. Siksi tarvitaan tulostuksia, jotta saisimme käsityksen siitä, mitä ohjelmassa tapahtuu mitä paremmat tulostukset, sitä parempi käsitys.

sijoitusoperaattori (ei yhtäsuuruusmerkki!) Sijoituslause 3 int luku = (5 + 4) * 8-7; 1. Selvitetään oikeanpuoleisen lausekkeen arvo. 2. Määritellään uusi kokonaislukutyyppinen muuttuja nimeltä luku. 3. Sijoitetaan kohdassa 1 laskettu arvo kohdassa 2 määriteltyyn muuttujaan. laskuri = laskuri + 1; 2. Sijoitetaan tämä arvo laskurin uudeksi arvoksi. 1. Lasketaan yhteen laskurin nykyinen arvo ja yksi. (Koska laskurimuuttuja on jo entuudestaan olemassa, sitä ei siis ole syytä määritellä uudelleen, joten emme käytä sanaa int.)

4 Palauttaminen vs. tulostaminen Metodi, joka palauttaa tekstin böö : Metodi, joka tulostaa tekstin böö : paluuarvon tyyppi ei palauta mitään public String palautaböö() { } return böö ; public void tulostaböö() { } System.out.println( böö ); antaa palautettavan arvon käyttöön sille, joka metodia kutsui tuottaa tekstin näytölle String bööteksti = palautaböö(); böö System.out.println(bööTeksti);

5 Attribuutit Oliokohtaiset Luokan yksittäisen ilmentymän eli olion ominaisuudet. Määrittelevät olion tilan. Yleensä yksityisiä, eli vain oliolla itsellään on suora pääsy käsiksi attribuuttien arvoihin. Luokkakohtaiset (static) Ominaisuuksia, jotka ovat kaikkien luokasta luotujen olioiden yhteisessä käytössä. Usein julkisia, eli kuka tahansa näkee nämä. Yleensä lisäksi vakioita, eli niille asetetaan tietty arvo, jota ei jälkeenpäin pysty muuttamaan. Metodit Luokan yksittäisen ilmentymän eli olion toiminnot, mitä olio osaa. Antavat mahdollisuuden saada tietoja olion tilasta ja muuttaa sitä. (Olion metodien tehtävänä on siis tarjota rajapinta, jonka avulla ulkopuolinenkin voi kysyä ja jopa muokata olion attribuuttien arvoja.) Metodeja, jotka eivät kuulu millekään yksittäiselle oliolle. (Niinpä sana this ei merkitse tällaisessa metodissa mitään.) Pääohjelmametodi on aina tällainen. Jos siellä halutaan testata jotakin yksittäisen olion metodia, tällainen olio pitää ensin luoda ja laittaa talteen johonkin muuttujaan.

MUUTTUJAT Tiedon abstraktiotasoja 6 Javan fokus kokoelmat nimetty joukko olioita oliot nimetty joukko muuttujia (ja operaatioita) muuttujat nimetty tietyntyyppisen tiedon muistipaikka muistipaikat joukko bittejä, joilla on yksi osoite bitit nollia tai ykkösiä

MUUTTUJAT 7 Erilaisia muuttujia public class Mursu { } private String nimi; private int nopeus; public Mursu(String nimi, int nopeus) { this.nimi = nimi; this.nopeus = nopeus; } attribuutit määrittävät olion tilan eli ominaisuuksien arvot parametrit antavat metodille sen suorituksen kannalta tarpeelliset lähtötiedot apumuuttujat mahdollistavat jonkin arvon muistamisen niin kauan kuin sitä tarvitaan public double liiku(double aika) { double matka = aika * this.nopeus; System.out.println(nimi + lyllersi + matka + km. ); return matka; }

MUUTTUJAT 8 Muuttujista Muuttujan määrittely (eli esittely): nimetään tietolokero ja kerrotaan, minkä tyyppistä tietoa se voi sisältää. String brutaalisolvaus; int vihreidenpingviinienlukumaara; Muuttujan alustus: sijoitetaan muuttujaan (sen historian ensimmäinen) arvo. brutaalisolvaus = hähä mogari ; Voidaan tehdä myös suoraan määrittelyn yhteydessä: String brutaalimpisolvaus = luetaan sitä API:a ; Muuttujan arvon lukeminen: käytetään muuttujaa missä tahansa muualla kuin sijoituslauseen vasemmalla puolella. System.out.println(brutaalimpiSolvaus); if (vihreidenpingviinienlukumaara > 1) { Ei saa tehdä alustamattomalle muuttujalle, muuten kääntäjää alkaa pelottaa. ( Variable might not have been initialized. ) Attribuuteilla on aina tietty alkuarvo automaattisesti (numeromuuttujilla nolla, booleaneilla false, oliomuuttujilla null), joten niiden alustaminen ei ole välttämätöntä ennen muuttujan käyttämistä yleensä toki suositeltavaa.

MUUTTUJAT 9 Tietotyypeistä byte kokonaisluku short int alkeistyypit desimaaliluku (liukuluku) long float double totuusarvo boolean merkki char viittaustyypit merkkijono alkeistyyppien kääreet taulukot muut oliotyypit String Integer, Double, Boolean, Character,... int[ ], double[ ], Object[ ], Karttaruutu[ ][ ],... Object, Random, HashSet, Pelotteluesine,... olioita

MUUTTUJAT 10 Viittaustyyppiset muuttujat Olio on kuin ilmapallo. Oliomuuttujat ovat viittauksia kuin naruja, joiden päässä se ilmapallo on. Sama olioilmapallo voi olla useamman narun päässä. Siihen voidaan vaikuttaa (eli sen metodeita kutsua) kaikkia naruja pitkin, ja kaikki kutsut muokkaavat yhtä ja samaa oliota. Kun oliomuuttuja lakkaa olemasta tai saa uuden arvon, yksi naru katkeaa. Kun olio ei ole enää yhdenkään narun päässä kiinni, se karkaa stratosfääriin (eli Javan automaattinen roskienkerääjä tulee ja syö sen).

SILMUKAT 11 Klassinen for-lause for (int i = 0; i < 3; i++) { }... ei alustuslause onko ehto tosi? kyllä suoritettavat lauseet for-lauseen jälkeinen elämä kasvatuslause

SILMUKAT 12 Tällainen for-lause... for (int i = 0; i < 3; i++) { }......vastaa while-lauseella toteutettua rakennetta { int i = 0; } while (i < 3) {... i++; } Mikä merkitys on ulommilla aaltosuluilla?

SILMUKAT 13 Iteroiva for-lause public void tulostanimet(set<olento> olennot) { for (Olento o : olennot) { System.out.println(o.annaNimi()); } } Käy läpi kaikki tiettyyn kokoelmaan sisältyvät oliot. Kukin kokoelman olio sijoitetaan siis vuorollaan for-lauseen määrittelemään muuttujaan ja siihen sovelletaan aaltosulkujen sisällä olevia lauseita. Läpikäyntijärjestys riippuu kokoelmasta. Listoilla se on määrätty, joukoilla (Set) yleensä määrittelemätön, mutta ei kuitenkaan aidosti satunnainen. Kokoelman sisältöä ei saa muuttaa (lisätä tai poistaa olioita) kesken iteroinnin, muuten seuraa virhe nimeltä ConcurrentModificationException.

SILMUKAT 14 public void tulostanimet(set<olento> olennot) { String nimet = ; for (Olento o : olennot) { nimet += o.annanimi() +, ; } System.out.println(nimet); } Tulostaa: Arska, Pena, Mats, Rauski, Miten pääsemme eroon ylimääräisestä pilkusta? public void tulostanimet(set<olento> olennot) { String nimet = ; int otuslaskuri = 0; for (Olento o : olennot) { nimet += o.annanimi(); if (otuslaskuri < olennot.size()-1) { nimet +=, ; } otuslaskuri++; } System.out.println(nimet); }

SILMUKAT 15 Iteraattori Vanha tuttu iteroiva for-looppi... for (Olio o : kokoelma) { } System.out.println(o); Kokoelman on toteutettava rajapinta Iterable<T>, joka määrittelee metodin public Iterator<T> iterator()....toimii pinnan alla itse asiassa iteraattoriolion avulla. Sama looppi hieman toisin kirjoitettuna: Iterator<Olio> iter = kokoelma.iterator(); while (iter.hasnext()) { Olio o = iter.next(); System.out.println(o); } Myös Iterator<T> on itse asiassa rajapinta. Iteraattorin metodi next() palauttaa ja poistaa iteraattorista, ei iteroitavasta kokoelmasta järjestyksessä seuraavan elementin. Metodi hasnext() kertoo, vieläkö elementtejä on jäljellä.

SILMUKAT 16 Iteraattori Iteroimisessa on vaaransa. Metodi next() voi heittää poikkeuksia... NoSuchElementException, jos elementtejä ei enää ole. Vältettävissä huolellisella hasnext()-metodin käytöllä. ConcurrentModificationException, jos iteroitava kokoelma on muuttunut iteraattorin luomisen jälkeen. Uusia elementtejä ei siis voi kesken iteroinnin lisätä, ellei iterointia tämän jälkeen keskeytä. Elementtien poistaminen on luvallista iteroinnin lomassa vain iteraattori-olion metodilla remove(), joka poistaa viimeisimmän next()-metodin palauttaman elementin, myös iteroitavasta kokoelmasta. Iteraattori siis antaa luvan myös elementtien poistamiseen kokoelmasta (periaatteessa oma iteraattoriluokka voidaan kuitenkin toteuttaa myös niin, ettei remove()- metodi tee mitään). Aina ulkopuoliselle käyttäjälle ei haluta jättää tällaista mahdollisuutta, jolloin voi olla syytä harkita toisenlaisen rajapinnan tarjoamista kokoelman läpikäyntiin.

TAULUKOT 17 Taulukko Taulukkomuuttujan määrittely ja alustaminen ns. taulukon alustajalla: int[] taulu = { 9, 14, 2, 7, 2, 0, 22 }; 0 9 1 14 2 2 3 7 4 2 5 0 6 22 Taulukon indeksointi ja sen alkioiden arvojen asettaminen: taulu[0] = 1; taulu[2] = 100; taulu[taulu.length-1] = 8; 0 1 1 14 2 100 3 7 4 2 5 0 6 8 Uuden, tyhjän taulukon luonti new-operaattorilla: 0 1 2 3 4 taulu = new int[5]; 0 0 0 0 0 Taulukotkin ovat olioita. Huomaa, että taulukon koko on taulukko-olion, ei taulukkomuuttujan ominaisuus. (Samaan muuttujaan voi sijoittaa minkä kokoisen taulukon tahansa.) Taulukon tietotyyppi on sen sijaan myös taulukkomuuttujan ominaisuus.

TAULUKOT 18 Laskurilla varustettu for-silmukka on kuin luotu taulukon läpikäymiseen, esimerkiksi seuraavassa fiktiivisessä Olento-luokan metodissa: public void kauhistuhirviolaumaa(olento[] hirviot) { } for (int i = 0; i < hirviot.length; i++) { } hirviot[i].pelottele(this); Muista, että taulukon indeksit alkavat nollasta ja päättyvät yhtä pienempään kuin taulukon koko. hirviot[i] viittaa vuorollaan aina yhteen taulukon alkioon, siis Olento-tyyppiseen olioon (ellei kyseinen alkio ole null). this viittaa aina siihen olioon, jonka metodista on kyse. Sitä voi käyttää myös sellaisenaan, esimerkiksi parametrina jollekin toiselle metodille.

TAULUKOT 19 Jos määrittelemme seuraavasti int[] taulua; int[] taulub = null; int[] tauluc = new int[5]; Pelotteluesine[] taulud = new Pelotteluesine[1000]; ja sen jälkeen yritämme seuraavia asioita, mikään niistä ei onnistu. Miksi? taulua[0] = 49; taulub[0] = 88; tauluc[5] = 31; tauluc[2] = 4.86; taulua = new double[10]; taulub = taulua; taulud[666].annapelottavuus(); Variable taulua might not have been initialized. java.lang.nullpointerexception java.lang.arrayindexoutofboundsexception Possible loss of precision. Found: double. Required: int. Incompatible types. Found: double[ ]. Required: int[ ]. Variable taulua might not have been initialized. java.lang.nullpointerexception Inspired by: http://www.cs.helsinki.fi/u/wikla/ohjelmointi/sisalto/3/taulukot.html#2

TAULUKOT 20 Kaksiulotteinen taulukko eli taulukoita taulukossa Luodaan 2D-taulukko eli matriisi, jossa on neljä riviä ja viisi saraketta: 0 1 2 3 4 Olento[][] otusruudukko = new Olento[4][5]; 0 Itse asiassa loimme yhden nelipaikkaisen taulukon, jonka alkioiden tietotyyppi on Olento[]. Se sisältää siis neljä yksiulotteista, viisipaikkaista olentotaulukkoa. Nämä taulukot ovat aluksi tyhjiä, eli niiden jokainen alkio on null. 1 0 0 1 1 2 2 3 3 4 4 Voimme sijoittaa ruudukkoon uusia arvoja kertomalla, mihin alitaulukkoon ja mihin lokeroon siellä kyseinen arvo sijoitetaan: 2 0 1 2 3 4 otusruudukko[2][1] = new Olento( Rauski, 100); 3

TAULUKOT 21 2D-taulukon rivien ei välttämättä tarvitse olla samanpituisia jokainen alitaulukkohan on yksilöllinen olio, jonka pituus voi olla mitä vain: 0 0 1 2 3 4 Olento[][] otusruudukko = new Olento[4][]; 0 1 2 Huomaa tyhjät jälkimmäiset hakasulut. Tässä luotiin tyhjä nelipaikkainen taulukko, johon voi sijoittaa Olento[]-taulukoita. 1 Näitä alitaulukkoja ei kuitenkaan vielä ole olemassa, ne on luotava nyt erikseen. 2 0 otusruudukko[0] = new Olento[5]; otusruudukko[1] = new Olento[3]; 0 1 2 3 otusruudukko[2] = new Olento[1]; 3 otusruudukko[3] = new Olento[4]; otusruudukko[3][3] = new Olento( Rauski, 100);

TAULUKOT 22 for-lauseita voi käyttää myös sisäkkäin. Kaksiulotteisen taulukon läpikäynnissä tämä on usein tarpeen: String[][] ruudut = new String[5][5]; for (int i = 0; i < ruudut.length; i++) { for (int j = 0; j < ruudut[i].length; j++) { ruudut[i][j] = i +, + j; } } 0, 0 0, 1 0, 2 0, 3 0, 4 1, 0 1, 1 1, 2 1, 3 1, 4 2, 0 2, 1 2, 2 2, 3 2, 4 3, 0 3, 1 3, 2 3, 3 3, 4 4, 0 4, 1 4, 2 4, 3 4, 4

MERKKIJONOT 23 Merkkijonojen vertailu String a = "kaikki on mahdollista"; String b = "kaikki on mahdollista"; System.out.println(a == b); true b = new String("kaikki on mahdollista"); System.out.println(a == b); System.out.println(a.equals(b)); System.out.println(a == b.intern()); false true true Esimerkit: Ville Sundberg

MERKKIJONOT 24 EI NÄIN if (nimi == Rauski ) { VAAN NÄIN if (nimi.equals( Rauski )) { TAI JOS KIRJAIN- KOOLLA EI OLE MERKITYSTÄ if (nimi.equalsignorecase( RAUSKI )) {

MERKKIJONOT 25 Merkkijonon paloittelu String lause = Kivet on tosi jänniä. ; String[] sanat = lause.split( ); sanat[0] sanat[1] sanat[2] sanat[3] Kivet on tosi jänniä.

MERKKIJONOT 26 Merkkijonon tulkinta luvuksi Integer.parseInt(String merkkijono) Integer-luokan staattinen metodi yrittää tulkita merkkijonon kokonaisluvuksi heittää poikkeuksen NumberFormatException, jos merkkijono ei esitä puhdasta kokonaislukua (varauduttava aina tähän mahdollisuuteen) Double.parseDouble(String merkkijono) Double-luokan staattinen metodi, muuten sama kuin yllä mutta tulkitsee merkkijonoja desimaaliluvuiksi (desimaalierottimena oletusarvoisesti piste)

MERKKIJONOT 27 String-luokassa lisäksi mm. metodit: String substring(int alku, int loppu) palauttaa osamerkkijonon väliltä alku loppu-1 int indexof(string osamerkkijono) palauttaa indeksin, josta etsittävä osamerkkijono (ensimmäinen löytynyt) alkaa jos osamerkkijonoa ei löydy, palauttaa arvon 1 String trim() palauttaa merkkijonon kopion, jonka alusta ja lopusta on poistettu mahdolliset välilyönnit String tolowercase() palauttaa merkkijonon kopion, jonka kaikki ISOT KIRJAIMET on muutettu pieniksi kirjaimiksi (touppercase() tekee saman toisinpäin) String tostring() :D Luokka String on arvokeskeinen: String-olion metodit eivät muuta kyseisen olion tilaa mitenkään. Jos metodi tekee muutoksia, se palauttaa kopion alkuperäisestä uuden olion.

POLYMORFISMI 28 Halutaan luoda uusi Pelotteluesine... Kun luodaan uutta Pelotteluesinettä, on sille ensin rakennettava yläluokkien määrittelemä perusta alustettava ne ominaisuudet, jotka sille kuuluvat 1) Objectina ja 2) Esineenä. ominaisuuksien määrä Pelotteluesine private int pelottavuus public Pelotteluesine(String nimi, double paino, int pelottavuus) Esine private String nimi private double paino public Esine(String nimi, double paino) Object public Object() public Pelotteluesine(String nimi, double paino, int pelottavuus) { } super(nimi, paino); this.pelottavuus = pelottavuus; public Esine(String nimi, double paino) { } super(); this.nimi = nimi; this.paino = paino; public Object() { }......mutta ennen pelotteluesineen oman pelottavuus-ominaisuuden alustusta on varmistettava, että perustana on oikeaoppinen Esine. Siksi ihan aluksi kutsutaan Esine-luokan luontimetodia......jonka aluksi puolestaan kutsutaan vielä Object-luokan konstruktoria. (Tässä super();ia ei olisi pakko kirjoittaa, koska nyt yläluokan luontimetodille ei tarvitse antaa parametreja. Esineelle sen sijaan täytyi.)

POLYMORFISMI 29 Metodin kuormittaminen (overloading) Samannimisestä metodista on määritelty samassa luokassa (tai samassa yli- ja aliluokkien jatkumossa) useita versioita, joista valitaan suoritettavaksi yksi sen perusteella, mitä parametreja metodikutsussa on annettu. Metodikutsu sidotaan suoritettavaan metodiin metodin nimen sekä parametrien tyyppien ja järjestyksen perusteella. (Sen sijaan esimerkiksi parametrimuuttujien nimillä ei ole mitään merkitystä. Ei myöskään sillä, minkä tyyppisiä arvoja metodin eri versiot palauttavat.) Metodikutsujen on oltava yksiselitteisiä, eli ei saa olla epäselvää, mikä vaihtoehtoisista tietynnimisen metodin versioista nyt suoritetaan: public void metodi(object o, String s) {... } public void metodi(string s, Object o) {... } metodi( nuuh, nuuh ); metodi( nuuh, (Object) nuuh );

POLYMORFISMI Metodin korvaaminen (overriding) 30 Aliluokka määrittelee yliluokassa määritellyn metodin toteutuksen kokonaan uudelleen. Korvaavan metodin puumerkki on täsmälleen sama kuin alkuperäisen, eli metodeilla on sama nimi, samanlainen parametrilista (tyypit ja järjestys) ja sama paluuarvon tyyppi. Voidaan merkitä aliluokkaan kirjoittamalla metodin yläpuolelle erityinen @Override-tägi. Ei pakollista, mutta parantaa luettavuutta. Metodin uusi versio EI saa muuttaa paluuarvon tyyppiä, rajata näkyvyyttä alkuperäistä suppeammaksi (laajentaa sen sijaan saa), heittää sellaisia poikkeuksia joita alkuperäinen ei määritellyt heittävänsä (sen sijaan uusi versio voi mainiosti olla heittämättä joitakin poikkeuksia joita alkuperäinen metodi heitti). Kun luokan A metodi x() on korvattu aliluokassa B metodilla x(), niin alkuperäistä metodia voi kutsua luokan B oliolle vain olio itse notaatiolla super.x(). Muut kutsut johtavat aina luokassa B määritellyn metodin suorittamiseen.

POLYMORFISMI Metodien staattinen ja 31 dynaaminen sidonta Otus eka = new Otus(); Otus toka = new PäheäOtus(); PäheäOtus kolmas = new PäheäOtus(); toka :D kolmas eka :D :) Olkoon PäheäOtus luokan Otus aliluokka. Otus-luokassa on määritelty tylsä metodi eksistoi(), jonka PäheäOtus on korvannut uudella päheämmällä versiolla. Lisäksi PäheäOtus-luokassa on täysin uusi, ennen näkemätön metodi kelaasunlaatuas(). PäheälleOtukselle, joka on sijoitettu Otus-tyyppiseen muuttujaan, voidaan kutsua ainoastaan Otus-luokan metodeja. Sanotaan, että kyseisen olion staattinen tyyppi on Otus. Vaikka olio siis osaisi myös kelata laatuaan, sitä ei voi tuon muuttujan kautta käskeä niin tekemään. Sopivalla tyyppimuunnoksella staattinen tyyppi voidaan kuitenkin saattaa sellaiseksi, että tuokin metodi on käytössä. Sen sijaan muuttujan staattinen tyyppi Otus antaa toki meille luvan kutsua oliollemme metodia eksistoi(). Tällöin metodikutsu sidotaan kuitenkin aina olion todelliseen, dynaamiseen tyyppiin, joka tässä tapauksessa on PäheäOtus. Hämmästykseksemme tylsässä Otuslaatikossa piileksinyt olio alkaakin siis eksistoida hyvin päheästi, kun käskytämme sitä tuollaisella metodikutsulla. Mitenkään emme pysty käskemään tuota oliota käyttäytymään siten kuin puhdas Otus käyttäytyisi, ellei se sitten itse päätä suorittaa tuota metodia kutsulla super.eksistoi(). Staattinen tyyppi siis sanelee sen, mitkä metodikutsut muuttujaan sijoitetulle oliolle ovat ylipäänsä luvallisia. Dynaaminen tyyppi (joka ei olion elinaikana muutu) taas määrää, mitä koodia oliolle tehtyjen metodikutsujen seurauksena todella suoritetaan.

POLYMORFISMI Rajapinnat 32 Rajapinta eli liittymä (engl. interface) on luokka, joka määrittelee olion käyttöliittymän (tai jonkin osa-alueen siitä). Rajapinta toisin sanoen määrittelee yhden tai useamman metodin, jotka tarjoavat tietyn toiminnallisuuden. Ja tarkemmin sanoen se vain määrittelee nämä metodit, ei toteuta niitä (eikä ota kantaa siihen, millaisten teknisten yksityiskohtien avulla niiden toiminnallisuus toteutetaan). Rajapinta on toisin sanoen kuin abstrakti luokka, joka sisältää vain abstrakteja metodeja (siis metodeja ilman toteutusta, eli tavallaan vaatimuksia aliluokille tietynlaisten metodien toteuttamisesta). Mutta siinä missä Java-luokalla voi olla aina vain yksi suoranainen yläluokka (abstrakti tai ei), voi sama luokka toteuttaa yhden, kaksi, kolme tai miljoona rajapintaa. Toteuttaminen tarkoittaa sitä, että luokkaan on laadittu käytännön toteutus kaikille näissä rajapinnoissa määritellyille metodeille ja lisäksi toteuttamisesta on kerrottu avainsanan implements avulla. 1. Rajapintaluokka määrittelee tietyn toiminnallisuuden. 2. Konkreettiset luokat toteuttavat rajapinnan, kukin omalla tavallaan. 3. Toinen luokka voi käyttää kaikkia näitä luokkia rajapinnan edustajina, yhteisten ominaisuuksien pohjalta.

POIKKEUKSET Poikkeukset 33 public Paaryna varastapaaryna() throws KaameaPoikkeus { } if (vartija.onvahdissa() &&!vartija.nukkuu()) { KaameaPoikkeus poikkeus = new KaameaPoikkeus("Kiinni jäit, hähä!"); throw poikkeus; } else { } return paarynapuu.annapaaryna(); Tähän asti olemme tottuneet siihen, että metodin paluuarvo (true tai false, olio tai null) riittää kertomaan, onnistuiko metodi tehtävässään vai ei. Mutta millainen paluuarvo pystyisi ilmaisemaan, että jäimme kiinni varastaessamme päärynää? Javan poikkeukset (engl. exceptions) ovat ikään kuin vaihtoehtoja metodien normaaleille paluuarvoille. Tyypillisesti ne kertovat, että metodissa tapahtui odottamaton virhe. Poikkeusten yhteydessä ei puhuta palauttamisesta, vaan heittämisestä. public void elelevaarallistaelamaa() { } try { // VOI HEITTÄÄ POIKKEUKSEN: Paaryna saalis = this.varastapaaryna(); this.syo(saalis); } catch (KaameaPoikkeus poikkeus) { System.out.println(poikkeus); this.karsirangaistus(); } finally { } this.jatkaelamaaentiseentapaan(); Monet Javan valmiit poikkeukset (ja tyypillisesti kaikki itse laaditut) täytyy käsitellä. Toisin sanoen jos on olemassa vaara (todellinen tai edes teoreettinen), että tietyn metodin kutsusta aiheutuu poikkeus, tämän poikkeuksen mahdollisuuteen tulee varautua ns. try-catch-rakenteen avulla. Try-osioon sijoitetaan se metodikutsu, josta potentiaalisesti voi aiheutua poikkeus, sekä kaikki se mitä onnistuneesta yrityksestä suoraan seuraa. Catch-osiossa puolestaan yleensä reagoidaan jollain tapaa yrityksen epäonnistumiseen. Finally-osio ei ole pakollinen. Se suoritetaan sekä onnistuneen että epäonnistuneen kokeilun lopuksi.

POIKKEUKSET 34 Erilaisia poikkeusluokkia RuntimeException Exception...näitä ei tarvitse käsitellä. Tarvitsee käsitellä, paitsi... Throwable Kaikkien poikkeusluokkien yläluokka. (Nimestään huolimatta ei siis rajapinta.) Error Ei tarvitse käsitellä.

JAVA-API Keskeisimmät Java-API:n pakkaukset 35 API = Application Programming Interface eli sovellusohjelmointirajapinta (!) pakkaus (engl. package) = tapa koota samaan asiaan liittyviä luokkia yhteen java.lang pari aivan keskeistä luokkaa, kuten Object, String ja Math alkeistyyppien kääreluokat (Integer, Double, Boolean, Character,...) useimmat poikkeus- (Exception) ja virheluokat (Error) aina käytössä, ei tarvitse importoida! java.util kokoelmarajapinnat (Collection, Set, List, Map) ja niiden toteutukset (HashSet, Vector, ArrayList, HashMap,...) kirjastoluokat Arrays ja Collections välineitä päiväysten ja kellonaikojen käsittelyyn: Date, Calendar, TimeZone pari muuta hyödyllistä: Random, Timer, Scanner java.io välineet näppäimistön ja tiedostojen lukemiseen (erilaiset InputStream- ja Reader-luokat) sekä näytölle ja tiedostoon kirjoittamiseen (OutputStream- ja Writerluokat) java.net välineet verkkoyhteyksien muodostamiseen java.awt AWT-luokkakirjasto (Abstract Windowing Toolkit), Javan vanhempi kalusto graafisten käyttöliittymien toteutukseen javax.swing Swing-luokkakirjasto, uudemmat välineet graafisten käyttöliittymien tekemiseen

JAVA-API Luetaan sitä API:a! Mutta miten? 36 Java-ohjelmoinnissa monien ongelmien ratkaisu käy seuraavaan tapaan: 1. Etsi API:sta oikea luokka haluamasi asian tekemiseen. 2. Etsi luokasta metodi, jolla sen saa tekemään tuon asian. 3. Selvitä, miten kyseistä metodia käytetään. API:n lukemisessa on kuitenkin muutama sudenkuoppa, joita kannattaa varoa: Varmista, että olet tekemisissä oikean luokan kanssa (tsekkaa myös, missä pakkauksessa se on). Esimerkiksi java.util.list ja java.awt.list ovat kaksi täysin erilaista luokkaa, jotka menevät helposti sekaisin. Katso, mistä tutkimasi luokka periytyy. Yläluokista voi päätellä paljon siitä, mitä luokka osaa omien metodiensa lisäksi tehdä. Luokan omassa Method Summary -listassa ei mainita yläluokilta perittyjä metodeja, mutta luokalla on luonnollisesti myös ne käytettävissään. (Ne luetellaan lyhyesti tuon listan alapuolella.) Joistakin metodeista on tarjolla useampi kuormitettu (engl. overloaded) versio, eli samanniminen metodi erilaisilla parametrivaihtoehdoilla. Osa näistä on suoraviivaisempia käyttää, toiset tarjoavat mahdollisuuden hyvinkin monimutkaisiin säätöihin. Valitse oikea metodi tarpeesi mukaan, säästyt turhalta säätämiseltä. :)

TIETOVIRRAT Tietovirrat 37 Tavuvirta Merkkivirta Syöttö (input) java.io. InputStream java.io.reader Tulostus (output) java.io. OutputStream java.io.writer

TIETOVIRRAT näppäimistö InputStream (System.in) Näppäimistön lukeminen 38 InputStreamReader BufferedReader tavut 11101011 01001110 merkit ö b m r merkkijonot mene avantoon katso olentoa 4

TIETOVIRRAT 39 BufferedReader lukija = new BufferedReader( new InputStreamReader(System.in)); BufferedReader InputStreamReader InputStream (System.in) IOException (tietovirtahepo) vaanii kaikissa tietovirroissa

SWING Graafisen Java-ohjelman osat 40 näkyvät osat näkymättömät osat Komponentit Säiliöt Asettelijat Tapahtumat ja kuuntelijat Muut apuluokat pakkaus javax.swing javax.swing java.awt java.awt.event javax.swing.event java.awt javax.swing.border tärkeitä esimerkkiluokkia JButton JLabel JTextField JMenuItem JComboBox... ja monta muuta JFrame JApplet JDialog JPanel JScrollPane JSplitPane top level FlowLayout BorderLayout GridBagLayout GridLayout BoxLayout CardLayout ActionEvent ActionListener MouseEvent MouseListener ChangeEvent ChangeListener... ja monia muita Color Dimension Font GridBagConstraints Insets Border (Swing) käyttötarkoitus pähkinänkuoressa Käyttöliittymän näkyvät rakennuspalikat, vuorovaikutuksen välineet, affordanssit. Esittävät tietoa käyttäjän ymmärtämässä muodossa sekä tarjoavat mahdollisuuksia ohjelman tilan muuttamiseen. Komponentteja, jotka sisältävät toisia komponentteja. Ylimmän tason (top level) säiliöt tulevat toimeen omillaan, eli sellainen muodostaa käyttöliittymän rungon. Alemman tason säiliöitä (kuten JPanel) voi lisätä myös toisiin säiliöihin. Määrittävät, miten tietyn säiliön sisältö (eli siihen lisättävät komponentit) asetellaan suhteessa säiliöön ja toisiinsa. Se, miten (ts. minkälaisin parametrein) komponentit lisätään säiliöön, riippuu käytetyn asettelijan tyypistä. Vuorovaikutusmekanismien perusta. Käyttäessään jotakin komponenttia käyttäjä aiheuttaa tapahtuman, jonka komponentti lähettää tuntemilleen kyseisen tapahtumatyypin kuuntelijoille. Nämä reagoivat siihen suorittamalla jonkin sopivan toiminnon. Kuvaavat abstraktilla tasolla komponenttien tiettyjä näkyviä ominaisuuksia, kuten väriä, kokoa, kehystä tai asettelua. Annetaan tyypillisesti parametrina sopivalle komponenttiolion metodille, kun halutaan asettaa komponentille kyseinen ominaisuus.

SWING 41 ohjelman käynnistys Tapahtumapohjainen ohjelmointi käyttöliittymän alustus käyttäjä tekee jotain Tapahtuma tapahtuman odottelu Tapahtuman- käsittelysäie (event dispatching thread) ohjelman sulkeminen tapahtumaan reagointi ( ohjelma tekee jotain ) Tapahtuman kuuntelija(t) Työläissäie (worker thread)

SWING 42 GridBagConstraints gridx ja gridy: komponentin sijaintikoordinaatit gridissä (vasemmalta ylhäältä luettuna) gridwidth ja gridheight: komponentin leveys ja korkeus (riveissä ja sarakkeissa) weightx ja weighty: komponentin suhteellinen painoarvo (0.0 1.0) säiliötä täytettäessä GridBagConstraints c = new GridBagConstraints( 0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(5, 2, 5, 2), 0, 0); ipadx ja ipady: paljonko tyhjää reunusta ( paddingia ) komponentin sisään jätetään sen minimikoossa anchor: komponentin sijainti solun sisällä (CENTER, NORTH, EAST, SOUTHWEST, jne.) fill: kuinka komponentti täyttää solunsa (HORIZONTAL, VERTICAL, BOTH tai NONE) insets: montako pikseliä tyhjää tilaa komponentin ympärille jätetään (ylös, vasemmalle, alas, oikealle)

SWING 43 GridBagLayout JPanel paneeli = new JPanel( new GridBagLayout()); JTextField kenttä = new JTextField(); GridBagConstraints c = new GridBagConstraints( 0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(5, 2, 5, 2), 0, 0); paneeli.add(kenttä, c); 1. Luodaan paneeli. 2. Asetetaan paneelin asettelijaksi uusi GridBagLayout. 3. Luodaan käyttöliittymäkomponentti. 4. Luodaan GridBagConstraintsolio, jolle asetetaan sopivat attribuuttien arvot. 5. Lisätään komponentti paneeliin GridBagConstraints:ia käyttäen. 6. Palataan tarvittaessa kohtaan 3.

SWING 44 GridBagLayout, toinen tapa JPanel paneeli = new JPanel( new GridBagLayout()); GridBagConstraints c = new GridBagConstraints(); JTextField kenttä = new JTextField(); c.gridx = 0; c.gridy = 0; c.anchor = GridBagConstraints.SOUTH; c.insets = new Insets(5, 2, 5, 2); paneeli.add(kenttä, c); JButton namiska = new JButton( pl pl ); c.gridy = 1; paneeli.add(namiska, c); 1. Luodaan paneeli. 2. Asetetaan paneelin asettelijaksi uusi GridBagLayout. 3. Luodaan GridBagConstraintsolio oletusarvoisilla attribuuteilla. 4. Luodaan käyttöliittymäkomponentti. 5. Muutetaan GridBag- Constraints:in attribuuttien arvoja, mikäli tarpeen. 6. Lisätään komponentti paneeliin GridBagConstraints:ia käyttäen. 7. Palataan tarvittaessa kohtaan 4.

SOVELMAT 45 Sovellus extends JFrame public static void main(string[] args), joka tyypillisesti vain luo kehysluokan ilmentymän luontimetodi Sovelma extends JApplet ei main-metodia, ei (välttämättä) luontimetodiakaan public void init() - selain kutsuu automaattisesti - alustaa esimerkiksi käyttöliittymän lisäksi: start(), stop(), destroy()

SOVELMAT Sovelman ajaminen 46 appletviewer-ohjelmassa tai selaimessa, selaimien ongelmana sovelmakoodin jääminen välimuistiin (muutokset eivät näy ilman selaimen uudelleenkäynnistystä) Molemmat tarvitsevat HTML-sivun, jolle sovelma sijoitetaan Tulostukset ja virheilmoitukset tulevat joko terminaaliin (appletviewerillä) tai ns. Java-konsoliin (selaimella) <html> <head> <title>kolee appletti</title> </head> <body> <table width= 100% 100% height= 100% 100% border= 0 > <tr> <td align= center center valign= middle middle > </td> </tr> </table> </body> </html> <applet code= KoleeAppletti.class KoleeAppletti.class width= 400 400 height= 300 300 > </applet>

SOVELMAT 47 Appletviewer Unix-terminaalissa ja Windowsin komentorivillä: appletviewer sivujokasisaltaaappletin.html XEmacsissa:

SOVELMAT Java-konsoli (Windowsissa) 48

SOVELMAT Sovelma vs. sovellus 49 Sovelmalla kiinteä ikkunan koko, sovelluksella joustava Sovelma ei saa kirjoittaa mihinkään tiedostoon, sovellus saa ns. servletit (palvelinsovelmat eli palvelmat ) saavat temmeltää jossain määrin vapaammin Jotkin asiat on tehtävä sovelmissa hieman monimutkaisemmin, esimerkkinä kuvan lataaminen javax.swing.imageicon-olioksi: sovellus ImageIcon kuva = new ImageIcon( mursu.png ); sovelma ImageIcon kuva = null; try { kuva = new ImageIcon(this.getImage( new java.net.url(this.getcodebase(), mursu.png ))); } catch (java.net.malformedurlexception e) { e.printstacktrace(); }

2D-GRAFIIKKA 50 Swing-komponentin piirtäminen Jokainen komponentti vastaa siitä, miten se piirretään ruudulle Piirtojärjestelmä vastaa siitä, milloin tämä tapahtuu komponentti.repaint() kutsu tätä tarvittaessa Piirtojärjestelmä korvaa tämä tarvittaessa omalla toteutuksella paintcomponent(graphics g) komponentti.paint(graphics g) paintborder(graphics g) paintchildren(graphics g)

2D-GRAFIIKKA 51 Grafiikkakonteksti java.awt.graphics Mahdollistaa piirtämisen tiettyyn kontekstiin, esimerkiksi näytöllä olevaan paneeliin tai koneen muistissa olevaan kuvaan. paintcomponent-metodi saa tällaisen piirtojärjestelmältä valmiina. Sisältää metodeja, joiden avulla voidaan piirtää mm. viivoja, ovaaleja, monikulmioita, tekstiä sekä muistiin ladattuja kuvia. java.awt.graphics2d Edellisen aliluokka, jossa uusina ominaisuuksina mm. erityisten kuvio- olioiden piirtäminen sekä affiinit koordinaatistonmuunnokset. Jokainen Graphics-olio on yleensä pohjimmiltaan myös Graphics2D-olio.

2D-GRAFIIKKA 52 Piirtäminen tapahtuu metodien avulla: tapahtuu Graphics-luokan perustuu komponentin omaan koordinaatistoon: public void paintcomponent(graphics g) { (0, 0) x super.paintcomponent(g); g.setcolor(this.koleeväri); g.drawoval(-20, -40, 100, 50); g.fillrect(80, 35, 20, 200); g.setcolor(this.getforeground()); g.setfont(this.päheefontti); g.drawstring( hähä hähä,, 10, 150); hähä } g.drawimage(this.kuva, 100, 100, null); y (width-1, height-1) Myös komponentin rajojen ulkopuolelle voi piirtää,, mutta nämä osat eivät näy ruudulla.

2D-GRAFIIKKA 53 Kaksoispuskurointi java.awt.image javax.swing.jpanel Jos komponentti piirretään osissa, piirtämistä ei kannata tehdä suoraan näytölle, vaan koneen muistissa näkymättömissä olevaan kuvaan ( bufferiin( bufferiin ). Valmis kuva piirretään sitten ruudulla näkyvään komponenttiin yhtenä kokonaisuutena, jolloin vältetään kuvan välkkyminen ja eri osien eriaikainen piirtyminen. Swing-komponentit ovat kuitenkin oletusarvoisesti valmiiksi kaksoispuskuroituja. On siis turvallista piirtää suoraan niihin.

2D-GRAFIIKKA 54 Kuvan piirtäminen g.drawimage(image img, int x, int y, ImageObserver obs); Mistä se kuva saadaan? Mitäs laitan koordinaateiksi? Mikä kumma tää nyt sit on? Helpoin tapa: 1. Luo ImageIcon-olio haluamastasi kuvatiedostosta. 2. Kysy Kysy Image Image-olio siltä. On myös muita, vaikeampia tapoja. Komponentin sen pisteen, johon haluat sijoittaa kuvan vasemman yläkulman. Saavat olla myös negatiivisia. Joku, joka odottelee (tarvittaessa) kuvan latautumista muistiin. Jos käytät ImageIcon:ia kuvan hakemiseen, tämä voi hyvin olla null null.

2D-GRAFIIKKA 55 Graphics2D:llä Kuvan piirtäminen Graphics2D:llä g2.drawimage(image img, AffineTransform xform, ImageObserver obs); Mahdollistaa ns. affiinien muunnosten tekemisen piirrettävälle kuvalle. Kuvaa voi esimerkiksi pyöritellä vapaasti. Muunnokset esitetään 3 x 3 -matriisina, java.awt.geom.affinetransform. Ohjelmoijan ei kuitenkaan välttämättä tarvitse juuri vaivata päätään matriisialgebralla riittää, että tietää mitä haluaa (siirtää, kääntää, skaalata, vääntää) ja kuinka paljon :)

2D-GRAFIIKKA 56 Geometriset muunnokset Siirto (translation) Viistoutus (shearing) Kierto (rotation) Skaalaus (scaling) Peilaus (mirroring)

2D-GRAFIIKKA 57 MVC-arkkitehtuurimalli MODEL ohjelman tila visualisoidaan käyttäjälle käyttäjän toimenpiteet muuttavat ohjelman tilaa VIEW CONTROLLER käyttäjä reagoi näkemäänsä käyttöliittymän välityksellä

2D-GRAFIIKKA 58 Graafinen vuorovaikutteinen peli x dsfa y ohjelman tila visualisoidaan käyttäjälle käyttäjän toimenpiteet muuttavat ohjelman tilaa MODEL CONTROLLER VIEW käyttäjä reagoi näkemäänsä käyttöliittymän välityksellä

2D-GRAFIIKKA 59 dsfa x y MODEL VIEW CONTROLLER Pelimaailman malli: paikat, olennot, esineet Pelimaailman (tai sen tietyn osan) visualisaatio Muutoksen aiheuttaja, pelimoottori Muistaa kuka missäkin on, mitä tekemässä, millaisessa kunnossa, ja niin edelleen Piirtää pelin grafiikan (ja toistaa musiikin, ääni- tehosteet, yms.) Kuuntelee pelaajan antamia komentoja ja reagoi niihin Pitää yllä pelaajasta riippumattomia pelitapahtumia

SÄIKEET JA SWING 60 Säikeet ja Swing Swingissä on yhden säikeen sääntö : realisoituneita käyttöliittymäkomponentteja tulee käsitellä ainoastaan yhdestä säikeestä, Swingin tapahtumankäsittelijäsäikeestä (event dispatching thread). Tapahtumankäsittelijäsäie on siis se, joka suorittaa kuuntelijoiden sopivien metodien kutsumisen vastaavien tapahtumien yhteydessä sekä kaikkien Swing-komponenttien piirtämisen ruudulle. Realisoitunut tarkoittaa sitä, että komponentti on tehty näkyväksi ruudulla. Ylimmän tason säiliöille (kuten JFrame) tämän tekee jokin metodikutsuista setvisible(true), show() tai pack(). Alemman tason komponentit realisoituvat, kun ne lisätään näkyvään säiliöön tai ne sisältävä säiliö tulee näkyväksi. Toisin sanoen vielä näkymättömän käyttöliittymän alustus voi periaatteessa tapahtua missä säikeessä tahansa, näkyvien komponenttien tilan tutkiminen ja muuttaminen sen sijaan vain tapahtumankäsittelysäikeessä. Yleensä on tyylikkäintä rajata kaikki GUI-toiminta tuon säikeen vastuulle. Joskus raskaiden uusien käyttöliittymäosakokonaisuuksien alustus voidaan kuitenkin tehdä omassa säikeessään, jottei tapahtumankäsittely hidastu tarpeettomasti.

SÄIKEET JA SWING 61 Entäs sit ku oikeesti tarviin Swingissä muitaki säikeitä? Vai tarviinks? Case 1: Ajasta riippuvat tapahtumat ja javax.swing.timer Usein haluamme Swing-ohjelmaan myös käyttäjän tekemisistä riippumatonta toimintaa, esimerkiksi tietyin aikavälein toistuvia tapahtumia. Tällaiseen oma säie olisi luonteva ratkaisu, mutta hankala, koska se ei saisi käsitellä GUI-komponentteja suoraan. Toimiva ratkaisu on käyttää Swingin Timer-luokkaa. Se siirtää vastuun ajastetuista tapahtumista suoraan tapahtumankäsittelijäsäikeelle, joka toteuttaa ne uusina ActionEvent-tapahtumina määrätylle kuuntelijalle. Vähän kuin tapahtuman käynnistykseen olisi olemassa oma nappi, jota joku kävisi klikkaamassa vaikkapa sekunnin välein.

SÄIKEET JA SWING 62 Entäs sit ku oikeesti tarviin Swingissä muitaki säikeitä? Vai tarviinks? Case 2: Työläissäie ja SwingUtilities.invokeLater()-metodi Raskaita ja aikaavieviä työtehtäviä, kuten vaativaa laskentaa tai suurten oliokokonaisuuksien alustusta, ei kannata suorittaa tapahtumankäsittelysäikeessä, koska tämä näkyisi suoraan käyttäjälle vuorovaikutuksen hidastumisena. Nämä kannattaa delegoida erityisille työläissäikeille, jotka rouskuttelevat omaa urakkaansa huomaamattomasti taustalla. Usein työläissäikeenkin on tarpeen saada aikaan jotakin näkyvää, esimerkiksi ilmoittaa työnsä tuloksista käyttöliittymän kautta. Tätä se ei kuitenkaan saa tehdä suoraan, vaan työläissäikeen pitäisi jotenkin saada vihjattua tapahtumankäsittelysäikeelle, että tämän olisi aika tehdä jotakin. Ratkaisu tähän kommunikaatio-ongelmaan on SwingUtilities-luokan metodi invokelater(runnable r), joka ottaa parametrinaan jotakin suoritettavaa (siis olion, jolla on metodi run()) ja siirtää sen suoritettavaksi tapahtumankäsittelysäikeessä myöhemmin, käytännössä hyvinkin pian. run()-metodissa on tyypillisesti koodia, joka yhdistää työläissäikeen työn tulokset ja graafisten käyttöliittymäkomponenttien käsittelyn sopivalla tavalla.

UML-KAAVIOT UML pähkinänkuoressa (Unified Modeling Language) 63 Olento Karttaruutu attribuutit metodit - nimi : String - elinvoima : int - sijainti : Karttaruutu + Olento(nimi : String, elinvoima : int) : Olento + annanimi() : String + annaelinvoima() : int + muutaelinvoimaa(muutos : int) : void # kuole() : void + annasijainti() : Karttaruutu + asetasijainti(ruutu : Karttaruutu) : void + teesiirto() : void perintä (extends) Basiliski * 0.. 1 kaksisuuntainen viittaus: olento tuntee sijaintinsa ja karttaruutu siinä sijaitsevat olennot; olennolla on vain (enintään) yksi sijainti, mutta karttaruudussa voi olla useita olentoja kursiivi: abstrakti luokka tai metodi alleviivaus: staattinen attribuutti tai metodi ISOT_KIRJAIMET: vakioarvo (final) - nimi : String - olennot : List<Olento> - ruuduntarkkailijat : List<Ruuduntarkkailija> + Karttaruutu(nimi : String) : Karttaruutu + annanimi() : String + lisaaolento(o : Olento) : boolean + poistaolento(o : Olento) : boolean + sisaltaaolennon(o : Olento) : boolean + lisaaruuduntarkkailija(rt : Ruuduntarkkailija) : void + poistaruuduntarkkailija(rt : Ruuduntarkkailija) : void * yksisuuntainen viittaus: Karttaruutu-luokan ilmentymillä saattaa olla attribuuttinaan viittauksia Ruuduntarkkailijoihin - # + private protected public - BASILISKIN_KATSE : Pelotteluesine + Basiliski(nimi : String) : Basiliski + teesiirto() : void + olentosaapunut(r : Karttaruutu, o : Olento) : void + olentopoistunut(r : Karttaruutu, o : Olento) : void rajapinnan toteuttaminen (implements) * <<interface>> Ruuduntarkkailija + olentosaapunut(r : Karttaruutu, o : Olento) : void + olentopoistunut(r : Karttaruutu, o : Olento) : void rajapinnan metodit

JAVADOC Javadoc-kommentointi 64 /** * Luokka, joka kuvaa maailmaa. Maailma koostuu kaksiulotteiseen taulukkoon * järjestetyistä Karttaruutu-olioista. * * @author Veijo Vesisika */ public class Maailma { /** * Ilmansuunta pohjoinen, lukuarvoltaan 0. */ public static final int POHJOINEN = 0; /** * Metodi, jonka avulla voi selvittää tässä maailmassa tietyissä * koordinaateissa sijaitsevan karttaruudun. * * @param x karttaruudun x-koordinaatti * @param y karttaruudun y-koordinaatti * * @return annetuissa koordinaateissa sijaitseva karttaruutu tai null, * jos paikassa ei ole karttaruutua * * @throws PahaPoikkeus jos koordinaatit osoittavat maailman ulkopuolelle */ public Karttaruutu annakarttaruutu(int x, int y) throws PahaPoikkeus { }...

JAVADOC 65 On hyvä tapa Javadoc-kommentoida: luokat käyttötarkoitus sanallisesti mahdollisesti myös versionumero (@version) ja tekijän nimi (@author) sekä viittaukset (@see) muihin luokkiin, joihin on hyvä tutustua tätä luokkaa käytettäessä attribuutit (ainakin public- ja protected-tyyppiset) käyttötarkoitus sanallisesti metodit (ainakin public- ja protected-tyyppiset) käyttötarkoitus sanallisesti parametrien selitykset (@param) kuvaus siitä, mitä metodi voi palauttaa (@return) kuvaukset metodin mahdollisesti heittämistä poikkeuksista ja niihin johtavista tilanteista (@throws) Huomaa pieni mutta tärkeä notaatioero Javadocin ja muiden useampirivisten kommenttien välillä: /** /* * Tämä on Javadocia. Käytä tätä * Tämä on tavallinen kommentti, jollaisia * vain sille varatuissa paikoissa. * voi laittaa myös metodien koodin sekaan. */ */ Javadoc-kommenteista voidaan muodostaa itse laadituille luokille automaattisesti vastaavanlaiset dokumentaatiosivut kuin mitä Java-API:sta löytyy Javan valmiille luokille. Tämä tapahtuu esimerkiksi komennolla: javadoc -d docs -link http://java.sun.com/j2se/1.5.0/docs/api/ *.java

PAKKAUKSET 66 Pakkaukset Pieni Java-projekti: kaikki luokat kiltisti samassa hakemistossa, ei ongelmaa. Iso Java-projekti: luokkien määrän kasvaessa kovin suureksi yksi kansio ei enää riitä. Ongelma ihmiselle, ei tietokoneelle. Muista ihmisen tiedonkäsittelyn rajat, enintään 4±2 hahmotettavaa yksikköä kerrallaan tietoisessa tarkastelussa. Luokkakokonaisuus pysyy hallittavana jakamalla se osakokonaisuuksiin, pakkauksiin (engl. package). Yhdessä pakkauksessa yhteen asiaan liittyvät luokat. Toimintalogiikan malli omassa pakkauksessaan, käyttöliittymä omassaan, jne. Nämä voidaan puolestaan edelleen jakaa useaan erikoistuneeseen pakkaukseen. Käytännössä saman pakkauksen luokat sijoitetaan aina samaan hakemistoon.

PAKKAUKSET 67 Pakkausten nimeäminen ja nimihierarkiat java.awt.event javax.swing.border org.w3c.dom org.omg.corba.portable virallinen Java (by Sun Microsystems) järjestöt (W3C, OMG,...) fi.tkk.inf.studio1.turnaus.labyrintti Egoboosti- ja brändäysprefiksit. (Huomaa päinvastainen logiikka kuin www-palvelinten osoitteissa: maa organisaatio osasto jne.) + Asettavat ohjelmiston suurempaan kontekstiin, luovat tunnistettavuutta. - Syventävät (muutenkin jo syvää) hakemistohierarkiaa. Robottiturnaussoftan labyrinttien esittämiseen käytetyt luokat voisivat sijaita tällaisessa pakkauksessa. Käytännössäkin luokat sijaitsisivat tuollaisen hakemistopolun päässä, esimerkiksi: C:\Javaproggikset\fi\tkk\inf\studio1\turnaus\labyrintti\ Labyrinttiruutu.java

PAKKAUKSET 68 Pakkausten käyttö 1 Pakkaus, johon luokka sijoittuu, määritellään: 1. Avainsanalla package aivan luokan lähdekoodin alussa: package fi.tkk.inf.studio1.turnaus.labyrintti; import java.util.arraylist; public class Labyrinttiruutu { 2. Tallentamalla luokkatiedosto oikeaan paikkaan hakemistohierarkiassa. Pakkaus rajaa luokkien näkyvyyttä niin, että vain samaan pakkaukseen kuuluvat luokat nähdään suoraan muiden pakkausten luokat on importoitava kuten Javan valmiit luokatkin.

PAKKAUKSET Pakkausten käyttö 2 69 Eclipsessä pakkausten käyttö on helppoa ja visuaalista. Uusia pakkauksia luodaan samasta valikosta kuin uusia luokkiakin. Oletuksena kaikille projekteille luodaan oletuspakkaus (default package), mutta Eclipse ei arvosta, jos käytät sitä. Luokkia voi myöhemmin siirtää pakkauksesta toiseen Refactor-valikon Movetoiminnolla. Tämä päivittää automaattisesti kaikki viittaukset kyseiseen luokkaan ja lisää tarvittavat importit. Komentoriviympäristössä pakkaukset tuovat hieman enemmän haastetta. Kääntäminen ja ajaminen vaativat nyt ensin ns. classpathin määrittelemisen. set CLASSPATH=path1;path2;path3 (Windows) setenv CLASSPATH path1:path2:path3 (Unix) Näissä path1 jne. ovat hakemistopolkuja, joista (ja joiden alta) luokkia etsitään. Usein riittää nykyiseen hakemistoon osoittava polku eli pelkkä piste. Se on suhteellinen polku, eli muuttuu valitun hakemiston mukaan. Lisäksi luokkia ajaessa täytyy kertoa, mistä pakkauksesta (määritellyn classpathhakemiston alta) kyseinen luokka löytyy: esim. java fi.tkk.inf.studio1.turnaus.turnaus &

SUUNNITTELUSTA 70 Oliopohjaisessa suunnittelussa mietittävää... Käytänkö Javan valmista luokkaa sellaisenaan vai kirjoitanko sille aliluokan? Mieti, tarvitseeko luokan ilmentymien osata jotain erityistä, jota valmiista luokasta ei löydy, vai riittääkö, että luot valmiista luokasta olion tietyillä ominaisuuksilla. Usein Swingin säiliöille kannattaa laatia omia aliluokkia, muille Swing-komponenteille tämä taas on harvemmin tarpeen. Korkea koheesio eli (luokkien sisäinen) yhtenäisyys: GOOD! Yhden luokan vastuut muodostavat selkeän kokonaisuuden. Mitään olennaista ei ole piilotettu jonnekin muualle, eikä toisaalta mukana ole mitään kovin epärelevanttiakaan. Korkea luokkien välinen kytkeytyneisyys: BAD! Jokainen luokkien välinen riippuvuussuhde tekee kokonaisuudesta vaikeammin hallittavan ja muutettavan. Tietysti luokkien välinen yhteistyö on välttämätöntä kaikissa vähänkin monimutkaisemmissa ohjelmissa, mutta kytkentöjen kannattaa olla selkeitä ja niitä kannattaa olla mahdollisimman vähän. Harmittomin kytkennän muoto on Swingissä yleensä tapahtumankuuntelu: luokan A olio rekisteröityy tiettyä rajapintaa C edustavana kuuntelijana luokan B oliolle ja odottaa, että B ilmoittaa A:lle uusista tätä kiinnostavista tapahtumista. Kun B joutuu kutsumaan suoraan luokan A metodia, kytkentä on vahvempi ja vähemmän joustava. Käyttöliittymä on hyvä pitää erillään varsinaisesta sovelluslogiikasta, ongelmadomainin mallinnuksesta.

SUUNNITTELUSTA Suunnittelumallit (design patterns) 71 Hyväksi havaittuja konsepteja siitä, millainen olioyhteisö soveltuu tietynlaisen ongelman ratkaisuun. (Kuvailevat yleensä muutamia oliota, joilla selkeä vastuunjako. Eivät sinänsä ota kantaa siihen, miten olioita kuvaavat luokat toteutetaan, eivätkä riipu tietystä ohjelmointikielestä.) MVC (Model-View-Controller): sovelluksen datamalli, sen esittäminen käyttäjälle sekä datamallin muokkaaminen on jaettu eri osien vastuulle. Observer: yksi olio ilmoittautuu tarkkailemaan muutoksia toisen olion tilassa. Tarkkailtava (observable) olio ilmoittaa, kun muutoksia tapahtuu. Singleton: luokka, josta voidaan luoda vain yksi olio. Luontimetodi piilotettu, ilmentymän luonti (ja luonnin jälkeen tuon ainoan ilmentymän hakeminen) tapahtuu jollakin staattisella metodilla, kuten getinstance(). Factory: luokka, jonka metodien avulla voidaan luoda usean muun luokan ilmentymiä. Paluuarvon tyyppi voi olla jokin rajapinta, jolloin käyttäjä voi luoda erilaisia olioita välittämättä niiden todellisesta luokasta. Composite: suurempi kokonaisuus rakennetaan tietynlaisista rakennuspalikkaolioista, jotka jälleen voivat edustaa jotakin palikkarajapintaa (ja näin ollen olla todelliselta luokaltaan hyvin erilaisia keskenään). ja onhan näitä vielä muitakin

SUUNNITTELUSTA perintä Tulostusvirrat 72 aggregaatio (ohuessa päässä oleva luokka toimii salmiakkikuviopään luokan rakenteellisena osana) PrintWriter OutputStream Writer BufferedWriter FileOutputStream tavuvirrat FilterOutputStream OutputStreamWriter FileWriter merkkivirrat Korkeimman tason virroissa ns. decorator-suunnittelumalli. Virrat ovat perusmerkkivirta Writerin aliluokkia (eli lupaavat saman toiminnallisuuden), mutta niiden toiminta perustuu johonkin toiseen, matalamman tason merkkivirtaolioon. Ne lisäävät sen ympärille uutta toiminnallisuutta, koristeita. Nämä virrat luodaan siis aina jonkin olemassa olevan virran pohjalle.

SUUNNITTELUSTA Sovelluskehykset (software frameworks) 73 Valmiiden luokkien (ja lopulta pakkausten) muodostamia kokonaisuuksia, joiden varaan voi rakentaa uusia ohjelmistoja, sekä käyttämällä valmiita komponentteja sellaisenaan että laatimalla niille tarpeen mukaan omia aliluokkia. Tutuin esimerkki sovelluskehyksestä: Swing. Usein sovelluskehysten luokkakokonaisuudet on suunniteltu hyvin, ja niissä nähdään monien suunnittelumallien soveltamista käytäntöön: MVC: jokaisen hiemankin monimutkaisemman Swing-komponentin perustana nämä kolme osaa. Observer: tapahtumankuuntelijat ja kuunneltavat komponentit. Singleton: tietyt Swing-sovelluksen hallintaan ja asetuksiin käytetyt luokat, joilla on aina vain yksi ilmentymä. Factory: esimerkiksi erilaisten reunusten (border) luonti. Composite: komponenttien lisääminen säiliöihin asettelijoiden avulla.

74 liikenne jono para laku psyki buutti pelottelu ellistäminen runsauden kuono kusi assistentti

75 MERKKI liikenne jono METRI para laku MOGARI ATRI psyki buutti ESINE pelottelu ellistäminen runsauden kuono TUNTI SARVI kusi assistentti