Title: Informaatioverkostot: Studio 1 Luentomateriaali
1Informaatioverkostot Studio 1Luentomateriaali
5 11 17 23
40 45 50 60
28 33 35 37
63 64 66 70
2Muutama 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.
3Sijoituslause
sijoitusoperaattori (ei yhtäsuuruusmerkki!)
- int luku (5 4) 8 - 7
- laskuri laskuri 1
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.
1. Lasketaan yhteen laskurin nykyinen arvo ja
yksi.
2. Sijoitetaan tämä arvo laskurin uudeksi
arvoksi. (Koska laskurimuuttuja on jo
entuudestaan olemassa, sitä ei siis ole syytä
määritellä uudelleen, joten emme käytä sanaa int.)
4Palauttaminen vs. tulostaminen
Metodi, joka palauttaa tekstin böö public
String palautaBöö() return böö
Metodi, joka tulostaa tekstin böö public
void tulostaBöö() System.out.println(böö)
paluuarvon tyyppi
ei palauta mitään
antaa palautettavan arvon käyttöön sille, joka
metodia kutsui
tuottaa tekstin näytölle
String bööTeksti palautaBöö() System.out.print
ln(bööTeksti)
böö
5Oliokohtaiset Luokkakohtaiset (static)
Attribuutit 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. 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.
6Tiedon abstraktiotasoja
kokoelmatnimetty joukko olioita
oliotnimetty joukko muuttujia (ja operaatioita)
Javan fokus
muuttujatnimetty tietyntyyppisen tiedon
muistipaikka
muistipaikatjoukko bittejä, joilla on yksi osoite
bititnollia tai ykkösiä
7Erilaisia muuttujia
attribuutit määrittävät olion tilan eli ominaisuuksien arvot
attribuutit määrittävät olion tilan eli ominaisuuksien arvot
parametritantavat metodille sen suorituksen kannalta tarpeelliset lähtötiedot
parametritantavat metodille sen suorituksen kannalta tarpeelliset lähtötiedot
apumuuttujat mahdollistavat jonkin arvon muistamisen niin kauan kuin sitä tarvitaan
apumuuttujat mahdollistavat jonkin arvon muistamisen niin kauan kuin sitä tarvitaan
- public class Mursu
- private String nimi
- private int nopeus
- public Mursu(String nimi, int nopeus)
- this.nimi nimi
- this.nopeus nopeus
-
- public double liiku(double aika)
- double matka aika this.nopeus
- System.out.println(nimi lyllersi matka
km.) - return matka
-
8Muuttujista
- 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ä APIa - Muuttujan arvon lukeminen käytetään muuttujaa
missä tahansa muualla kuin sijoituslauseen
vasemmalla puolella. - System.out.println(brutaalimpiSolvaus)
- if (vihreidenPingviinienLukumaara gt 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.
9Tietotyypeistä
alkeistyypit kokonaisluku byte
alkeistyypit kokonaisluku short
alkeistyypit kokonaisluku int
alkeistyypit kokonaisluku long
alkeistyypit desimaaliluku (liukuluku) float
alkeistyypit desimaaliluku (liukuluku) double
alkeistyypit totuusarvo boolean
alkeistyypit merkki char
viittaustyypit merkkijono String
viittaustyypit alkeistyyppien kääreet Integer, Double, Boolean, Character, ...
viittaustyypit taulukot int , double , Object , Karttaruutu , ...
viittaustyypit muut oliotyypit Object, Random, HashSet, Pelotteluesine, ...
olioita
10Viittaustyyppiset 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).
11Klassinen for-lause
for (int i 0 i lt 3 i) ...
ei
onkoehtotosi?
for-lauseen jälkeinen elämä
alustus-lause
suoritettavatlauseet
kyllä
kasvatus-lause
12Tällainen for-lause...
for (int i 0 i lt 3 i) ...
...vastaa while-lauseella toteutettua rakennetta
int i 0 while (i lt 3) ...
i
Mikä merkityson ulommillaaaltosuluilla?
13Iteroiva for-lause
public void tulostaNimet(SetltOlentogt 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.
14public void tulostaNimet(SetltOlentogt olennot)
String nimet for (Olento o olennot)
nimet o.annaNimi() ,
System.out.println(nimet)
Miten pääsemme eroon ylimääräisestä pilkusta?
Arska, Pena, Mats, Rauski,
Tulostaa
public void tulostaNimet(SetltOlentogt olennot)
String nimet int otuslaskuri 0
for (Olento o olennot) nimet
o.annaNimi() if (otuslaskuri lt
olennot.size()-1) nimet ,
otuslaskuri
System.out.println(nimet)
15Iteraattori
Vanha tuttu iteroiva for-looppi...
Kokoelman on toteutettava rajapintaIterableltTgt,
joka määrittelee metodin public IteratorltTgt
iterator().
- for (Olio o kokoelma)
- System.out.println(o)
...toimii pinnan alla itse asiassa
iteraattoriolion avulla.Sama looppi hieman
toisin kirjoitettuna
IteratorltOliogt iter kokoelma.iterator() while
(iter.hasNext()) Olio o iter.next()
System.out.println(o)
Myös IteratorltTgt on itse asiassa
rajapinta.Iteraattorin metodi next() palauttaa
ja poistaa iteraattorista, ei
iteroitavastakokoelmasta järjestyksessä
seuraavanelementin. Metodi hasNext()
kertoo,vieläkö elementtejä on jäljellä.
16Iteraattori
- 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.
17Taulukko
Taulukkomuuttujan määrittely ja alustaminen ns.
taulukon alustajalla
0 1 2 3 4 5 6
9 14 2 7 2 0 22
int taulu 9, 14, 2, 7, 2, 0, 22
Taulukon indeksointi ja sen alkioiden arvojen
asettaminen
taulu0 1taulu2 100taulutaulu.length-1
8
0 1 2 3 4 5 6
1 14 100 7 2 0 8
Uuden, tyhjän taulukon luonti new-operaattorilla
0 1 2 3 4
0 0 0 0 0
taulu new int5
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.
18Laskurilla 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 lt
hirviot.length i) hirvioti.pelottel
e(this)
this viittaaaina siihen olioon, jonkametodista
on kyse.Sitä voi käyttää myössellaisenaan,
esimerkiksiparametrina jollekintoiselle
metodille.
Muista, ettätaulukon indeksitalkavat nollasta
japäättyvät yhtäpienempään kuintaulukon koko.
hirvioti viittaavuorollaan aina
yhteentaulukon alkioon,siis Olento-tyyppiseenol
ioon (ellei kyseinenalkio ole null).
19Jos määrittelemme seuraavasti
int tauluA int tauluB null int tauluC
new int5 Pelotteluesine tauluD new
Pelotteluesine1000
ja sen jälkeen yritämme seuraavia asioita, mikään
niistä ei onnistu. Miksi?
tauluA0 49 tauluB0 88 tauluC5
31 tauluC2 4.86 tauluA new
double10 tauluB tauluA tauluD666.annaPelot
tavuus()
Inspired by http//www.cs.helsinki.fi/u/wikla/Ohj
elmointi/Sisalto/3/Taulukot.html2
20Kaksiulotteinen taulukkoeli taulukoita taulukossa
Luodaan 2D-taulukko eli matriisi, jossa on neljä
riviä ja viisi saraketta
0 1 2 3 4
0
1
2
3
Olento otusruudukko new
Olento45 otusruudukko21 new
Olento(Rauski, 100)
0 1 2 3 4
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. Voimme sijoittaa ruudukkoon uusia arvoja
kertomalla, mihin alitaulukkoon ja mihin lokeroon
siellä kyseinen arvo sijoitetaan
0 1 2 3 4
0 1 2 3 4
212D-taulukon rivien ei välttämättä tarvitse olla
samanpituisia jokainen alitaulukkohan on
yksilöllinen olio, jonka pituus voi olla mitä
vain
0 1 2 3 4
0
1
2
3
Olento otusruudukko new Olento4
0 1 2
Huomaa tyhjät jälkimmäiset hakasulut. Tässä
luotiin tyhjä nelipaikkainen taulukko, johon voi
sijoittaa Olento-taulukoita. Näitä
alitaulukkoja ei kuitenkaan vielä ole olemassa,
ne on luotava nyt erikseen.
0
otusruudukko0 new Olento5 otusruudukko1
new Olento3 otusruudukko2 new
Olento1 otusruudukko3 new
Olento4 otusruudukko33 new
Olento(Rauski, 100)
0 1 2 3
22for-lauseita voi käyttää myös sisäkkäin. Kaksiulot
teisen taulukon läpikäynnissä tämä on usein
tarpeen
String ruudut new String55 for (int i
0 i lt ruudut.length i) for (int j
0 j lt ruuduti.length j)
ruudutij 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
23Merkkijonojen vertailu
String a "kaikki on mahdollista" String b
"kaikki on mahdollista"
System.out.println(a b) b new
String("kaikki on mahdollista")
System.out.println(a b) System.out.println(a.
equals(b)) System.out.println(a b.intern())
true false true true
Esimerkit Ville Sundberg
24EI NÄIN
if (nimi Rauski)
VAAN NÄIN
if (nimi.equals(Rauski))
TAI JOS KIRJAIN-KOOLLA EI OLE MERKITYSTÄ
if (nimi.equalsIgnoreCase(RAUSKI))
25Merkkijonon paloittelu
String lause Kivet on tosi jänniä. String
sanat lause.split( )
sanat0 sanat1 sanat2 sanat3
Kivet on tosi jänniä.
26Merkkijonon 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 (desimaali-erottimena
oletusarvoisesti piste)
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 arvo-keskeinen String-olion
metodit eivät muuta kysei-sen olion tilaa
mitenkään. Jos metodi tekee muutoksia, se
palauttaa kopion alku-peräisestä uuden olion.
28Halutaan 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ä.
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...
Pelotteluesine private int pelottavuus public
Pelotteluesine(String nimi,double paino, int
pelottavuus)
Esine private String nimiprivate double
paino public Esine(String nimi, double paino)
...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.)
ominaisuuksien määrä
Object public Object()
29Metodin 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)
30Metodin korvaaminen(overriding)
- 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 _at_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.
31Metodien staattinen ja dynaaminen sidonta
Otus eka new Otus() Otus toka new
PäheäOtus() PäheäOtus kolmas new PäheäOtus()
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ä Otus-laatikossa
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.
)
D
eka
toka
D
kolmas
32Rajapinnat
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). Rajapi
nta 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 toteuttami-sesta 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.
33Poikkeukset
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 Paaryna varastaPaaryna() throws
KaameaPoikkeus if (vartija.onVahdissa()
!vartija.nukkuu()) KaameaPoikkeus
poikkeus new KaameaPoikkeus("Kiinni
jäit, hähä!") throw poikkeus
else return paarynapuu.annaPaaryna()
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.
34Erilaisia poikkeusluokkia
RuntimeException
...näitä ei tarvitse käsitellä.
Tarvitsee käsitellä, paitsi...
Throwable
Kaikkien poikkeus-luokkien yläluokka. (Nimestään
huolimatta ei siis rajapinta.)
Ei tarvitse käsitellä.
35Keskeisimmät Java-APIn pakkaukset
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 Writer-luokat) - 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
36Luetaan sitä APIa!Mutta miten?
Java-ohjelmoinnissa monien ongelmien ratkaisu käy
seuraavaan tapaan
- Etsi APIsta oikea luokka haluamasi asian
tekemiseen. - Etsi luokasta metodi, jolla sen saa tekemään tuon
asian. - Selvitä, miten kyseistä metodia käytetään.
APIn 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
suora-viivaisempia käyttää, toiset tarjoavat
mahdollisuuden hyvinkin monimutkaisiin säätöihin.
Valitse oikea metodi tarpeesi mukaan, säästyt
turhalta säätämiseltä. )
37Tietovirrat
Tavuvirta Merkkivirta
Syöttö (input) java.io.InputStream java.io.Reader
Tulostus (output) java.io.OutputStream java.io.Writer
38Näppäimistön lukeminen
tavut
11101011
merkit
01001110
b
r
merkkijonot
ö
m
mene avantoon
katso olentoa 4
39BufferedReader lukija new BufferedReader(
new InputStreamReader(System.in))
BufferedReader
InputStreamReader
InputStream (System.in)
?
IOException (tietovirtahepo) vaanii kaikissa
tietovirroissa
40Graafisen Java-ohjelman osat
näkyvät osat näkyvät osat näkymättömät osat näkymättömä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.eventjavax.swing.event java.awtjavax.swing.border
tärkeitäesimerkki-luokkia JButton JLabel JTextField JMenuItem JComboBox ... ja monta muuta JFrame JApplet JDialog JPanel JScrollPane JSplitPane FlowLayout BorderLayout GridBagLayout GridLayout BoxLayout CardLayout ActionEventActionListener MouseEventMouseListener ChangeEventChangeListener ... ja monia muita Color Dimension Font GridBagConstraints Insets Border (Swing)
käyttö-tarkoitus pähkinän-kuoressa Käyttöliittymän näkyvät rakennuspalikat, vuoro-vaikutuksen välineet, affordanssit. Esittävät tietoa käyttä-jän ymmärtämässä muodossa sekä tarjoa-vat mahdollisuuksia ohjelman tilan muutta-miseen. Komponentteja, jotka sisältävät toisia kompo-nentteja. 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 kompo-nentit) asetellaan suhteessa säiliöön ja toisiinsa. Se, miten (ts. minkä-laisin parametrein) komponentit lisätään säiliöön, riippuu käyte-tyn asettelijan tyypistä. Vuorovaikutus-mekanismien perusta. Käyttäessään jotakin komponenttia käyttäjä aiheuttaa tapahtuman, jonka komponentti lähettää tuntemilleen kyseisen tapahtuma-tyypin 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.
top level
41Tapahtumapohjainen ohjelmointi
ohjelman käynnistys
käyttöliittymän alustus
Tapahtuman kuuntelija(t)
tapahtuman odottelu
42GridBagConstraints
anchorkomponentin sijainti solunsisällä
(CENTER, NORTH,EAST, SOUTHWEST, jne.)
GridBagConstraints c new GridBagConstraints(
0, 0, 1, 1, 0.0, 0.0,
GridBagConstraints.CENTER,
GridBagConstraints.BOTH, new Insets(5, 2,
5, 2), 0, 0)
gridx ja gridykomponentin sijainti-koordinaatit
gridissä(vasemmalta ylhäältä luettuna)
fillkuinka komponentti täyttääsolunsa
(HORIZONTAL,VERTICAL, BOTH tai NONE)
gridwidth ja gridheightkomponentin leveys ja
korkeus(riveissä ja sarakkeissa)
insetsmontako pikseliätyhjää
tilaakomponentinympärille jätetään(ylös,
vasemmalle,alas, oikealle)
ipadx ja ipadypaljonko tyhjää
reunusta(paddingia) kompo-nentin sisään
jätetäänsen minimikoossa
weightx ja weightykomponentin
suhteellinenpainoarvo (0.01.0)säiliötä
täytettäessä
43GridBagLayout
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(ken
ttä, c)
- Luodaan paneeli.
- Asetetaan paneelin asettelijaksi uusi
GridBagLayout. - Luodaan käyttöliittymä-komponentti.
- Luodaan GridBagConstraints-olio, jolle asetetaan
sopivat attribuuttien arvot. - Lisätään komponentti paneeliin GridBagConstraints
ia käyttäen. - Palataan tarvittaessa kohtaan 3.
44GridBagLayout, toinen tapa
JPanel paneeli new JPanel( new
GridBagLayout()) GridBagConstraints c new
GridBagConstraints() JTextField kenttä new
JTextField() c.gridx 0c.gridy 0c.anchor
GridBagConstraints.SOUTHc.insets new
Insets(5, 2, 5, 2) paneeli.add(kenttä,
c) JButton namiska new JButton(pl) c.gridy
1 paneeli.add(namiska, c)
- Luodaan paneeli.
- Asetetaan paneelin asettelijaksi uusi
GridBagLayout. - Luodaan GridBagConstraints-olio oletusarvoisilla
attribuuteilla. - Luodaan käyttöliittymä-komponentti.
- Muutetaan GridBag-Constraintsin attribuuttien
arvoja, mikäli tarpeen. - Lisätään komponentti paneeliin GridBagConstraints
ia käyttäen. - Palataan tarvittaessa kohtaan 4.
45Sovellusextends JFrame
public static void main(String args), joka tyypillisesti vain luo kehysluokan ilmentymän luontimetodi
Sovelmaextends 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()
46Sovelman ajaminen
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)
lthtmlgt ltheadgt lttitlegtKolee applettilt/titlegtlt/he
adgt ltbodygt lttable width100 height100
border0gt lttrgt lttd aligncenter
valignmiddlegt ltapplet
codeKoleeAppletti.class width400
height300gt lt/appletgt lt/tdgt
lt/trgt lt/tablegtlt/bodygt lt/htmlgt
47Appletviewer
Unix-terminaalissa ja Windowsin komentorivillä appletviewer sivuJokaSisaltaaAppletin.html XEmacsissa
48Java-konsoli(Windowsissa)
49Sovelma vs. sovellus
- 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 - ImageIcon kuva new ImageIcon(mursu.png)
- ImageIcon kuva null try kuva new
ImageIcon(this.getImage( new
java.net.URL(this.getCodeBase(),
mursu.png))) catch
(java.net.MalformedURLException e)
e.printStackTrace()
sovellus sovelma
50Swing-komponentin piirtäminen
- Jokainen komponentti vastaa siitä, miten se
piirretään ruudulle - Piirtojärjestelmä vastaa siitä, milloin tämä
tapahtuu
Piirtojärjestelmä
paintComponent(Graphics g)
komponentti.paint(Graphics g)
paintBorder(Graphics g)
paintChildren(Graphics g)
51Grafiikkakonteksti
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.
52Piirtäminen
perustuu komponentin omaan
koordinaatistoon
tapahtuu Graphics-luokan metodien avulla
x
(0, 0)
public void paintComponent(Graphics g)
super.paintComponent(g) g.setColor(this.kolee
Vä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ä, 10, 150)
g.drawImage(this.kuva, 100, 100, null)
hähä
(width-1, height-1)
y
Myös komponentin rajojen ulkopuolelle voi
piirtää, mutta nämä osat eivät näy ruudulla.
53Kaksoispuskurointi
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). 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.
54Kuvan piirtäminen
g.drawImage(Image img, int x, int y,
ImageObserver obs)
Mitäs laitan koordinaateiksi?
Mikä kumma tää nyt sit on?
Mistä se kuva saadaan?
- Helpoin tapa
- Luo ImageIcon-olio haluamastasi kuvatiedostosta.
- Kysy Image-olio siltä.
Joku, joka odottelee (tarvittaessa) kuvan
latautumista muistiin.
Komponentin sen pisteen, johon haluat sijoittaa
kuvan vasemman yläkulman.
Jos käytät ImageIconia kuvan hakemiseen, tämä
voi hyvin olla null.
Saavat olla myös negatiivisia.
On myös muita, vaikeampia tapoja.
55Kuvan piirtäminen Graphics2Dllä
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 )
56Geometriset muunnokset
Siirto (translation)
Viistoutus (shearing)
Kierto (rotation)
Peilaus (mirroring)
Skaalaus (scaling)
57MVC-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ä
58Graafinen vuorovaikutteinen peli
ohjelman tila visualisoidaan käyttäjälle
MODEL
käyttäjän toimenpiteet muuttavat ohjelman tilaa
VIEW
CONTROLLER
käyttäjä reagoi näkemäänsä käyttöliittymän
välityksellä
59VIEW
MODEL
CONTROLLER
Pelimaailman malli paikat, olennot, esineet
Pelimaailman (tai sen tietyn osan) visualisaatio
Muutoksen aiheuttaja, pelimoottori
Kuuntelee pelaajan antamia komentoja ja reagoi
niihin
Piirtää pelin grafiikan(ja toistaa musiikin,
ääni-tehosteet, yms.)
Muistaa kuka missäkin on,mitä tekemässä,
millaisessakunnossa, ja niin edelleen
Pitää yllä pelaajastariippumattomiapelitapahtumi
a
60Sä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.
61Entä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äikeell
e, joka toteuttaa ne uusina ActionEvent-tapahtumin
a määrätylle kuuntelijalle. Vähän kuin tapahtuman
käynnistykseen olisi olemassa oma nappi, jota
joku kävisi klikkaamassa vaikkapa sekunnin välein.
62Entä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äsittely
sä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.
63UML pähkinänkuoressa (Unified Modeling Language)
Olento
- 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
Karttaruutu
- nimi String- olennot ListltOlentogt- ruuduntarkkailijat ListltRuuduntarkkailijagt
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
0 .. 1
attribuutit
kaksisuuntainen viittaus olento tuntee
sijaintinsa ja karttaruutu siinä sijaitsevat
olennot olennolla on vain (enintään) yksi
sijainti, mutta karttaruudussa voi olla useita
olentoja
metodit
kursiivi abstrakti luokka tai metodi alleviivaus
staattinen attribuutti tai metodi ISOT_KIRJAIMET
vakioarvo (final)
yksisuuntainen viittaus Karttaruutu-luokan
ilmentymillä saattaa olla attribuuttinaan
viittauksia Ruuduntarkkailijoihin
perintä (extends)
Basiliski
- BASILISKIN_KATSE Pelotteluesine
Basiliski(nimi String) Basiliski teeSiirto() void olentoSaapunut(r Karttaruutu, o Olento) void olentoPoistunut(r Karttaruutu, o Olento) void
- private
protected
public
ltltinterfacegtgtRuuduntarkkailija
olentoSaapunut(r Karttaruutu, o Olento) void olentoPoistunut(r Karttaruutu, o Olento) void
rajapinnan toteuttaminen (implements)
rajapinnan metodit
64Javadoc-kommentointi
/ Luokka, joka kuvaa maailmaa. Maailma
koostuu kaksiulotteiseen taulukkoon
järjestetyistä Karttaruutu-olioista.
_at_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.
_at_param x karttaruudun x-koordinaatti
_at_param y karttaruudun y-koordinaatti
_at_return annetuissa koordinaateissa
sijaitseva karttaruutu tai null,
jos paikassa ei ole karttaruutua
_at_throws PahaPoikkeus jos koordinaatit osoittavat
maailman ulkopuolelle / public
Karttaruutu annaKarttaruutu(int x, int y) throws
PahaPoikkeus ...
65- On hyvä tapa Javadoc-kommentoida
- luokat
- käyttötarkoitus sanallisesti
- mahdollisesti myös versionumero (_at_version) ja
tekijän nimi (_at_author) sekä viittaukset (_at_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 (_at_param)
- kuvaus siitä, mitä metodi voi palauttaa (_at_return)
- kuvaukset metodin mahdollisesti heittämistä
poikkeuksista ja niihin johtavista tilanteista
(_at_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-APIsta 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
66Pakkaukset
- 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 42
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.
67Pakkausten nimeäminen ja nimihierarkiat
- java.awt.event
- javax.swing.border
- org.w3c.dom
- org.omg.CORBA.portable
- fi.tkk.inf.studio1.turnaus.labyrintti
-
virallinen Java (by Sun Microsystems)
järjestöt (W3C, OMG, ...)
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
68Pakkausten käyttö 1
- Pakkaus, johon luokka sijoittuu, määritellään
- Avainsanalla package aivan luokan lähdekoodin
alussa package fi.tkk.inf.studio1.turnaus.lab
yrintti import java.util.ArrayList
public class Labyrinttiruutu - 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.
69Pakkausten käyttö 2
- 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 Move-toiminnolla. 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 CLASSPATHpath1path2path3 (Windows)
- setenv CLASSPATH path1path2path3 (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 classpath-hakemiston
alta) kyseinen luokka löytyy - esim. java fi.tkk.inf.studio1.turnaus.Turnaus
70Oliopohjaisessa 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
Alle 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.
71Suunnittelumallit(design patterns)
- 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 rakennus-palikkaolioista, jotka
jälleen voivat edustaa jotakin palikkarajapintaa
(ja näin ollen olla todelliselta luokaltaan
hyvin erilaisia keskenään). - ja onhan näitä vielä muitakin
72Tulostusvirrat
perintä
aggregaatio(ohuessa päässä oleva luokka toimii
salmiakkikuviopään luokan rakenteellisena osana)
PrintWriter
OutputStream
Writer
BufferedWriter
OutputStreamWriter
FilterOutputStream
Korkeimman tason virroissa ns. decorator-suunnitte
lumalli. Virrat ovat perusmerkkivirta Writerin
aliluokkia (eli lupaavat saman toiminnallisuuden),
mutta niiden toiminta perustuu johonkin toiseen,
matalamman tason merkkivirta-olioon. Ne lisäävät
sen ympärille uutta toiminnallisuutta,
koristeita. Nämä virrat luodaan siis aina
jonkin olemassa olevan virran pohjalle.
FileWriter
FileOutputStream
tavuvirrat
merkkivirrat
73Sovelluskehykset(software frameworks)
- 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.
74liikenne ______ jono para _____ laku psyki _____
buutti pelottelu _____ ellistäminen runsauden
_____ kuono kusi ___ assistentti
75liikenne ______ jono para _____ laku psyki _____
buutti pelottelu _____ ellistäminen runsauden
_____ kuono kusi ___ assistentti