Ohjelmistotekniikan seminaari 28.11.1996
Otto Kopra
Viime aikoina on käyty paljon keskustelua tietotekniikan tulevaisuudesta, tietoverkoista, verkkotietokoneista, WWW:stä jne. Tavalla tai toisella keskusteluun on aina liittynyt Java-kieli. Sitä on kaavailty osaksi WWW:n suurta tulevaisuutta, tulevien käyttöjärjestelmien kulmakiveksi tai sulautettujen järjestelmien ohjelmointiympäristöksi. Jopa kilpailevia järjestelmiä kehittävät yritykset ovat ilmoittaneet joka tapauksessa tukevansa Javaa. Tulevaisuus näyttää siis varmalta, mutta pystyykö Java täyttämään kaikki sille asetetut odotukset?
Tässä esitelmässä perehdytään pintapuolisesti Java-kieleen, sen perusrakenteisiin, mukana tuleviin kirjastoihin ja Javan käyttöön WWW-dokumenttien osana. Lukijalla oletetaan olevan perustiedot sekä oliopohjaisesta ohjelmoinnista että C- tai C++-kielestä.
Javan kehitystyö alkoi vuonna 1990 Sun Microsystems:in käynnistäessä Patrick Naughtonin johdolla projektin, joka tunnettiin yksinkertaisesti nimellä "Green". Projektin alkuperäinen tavoite oli kehittää ohjelmointijärjestelmä sulautettuja systeemejä varten.
Kehitystyö alkoi laajentamalla C++-kääntäjää, mutta pian kävi ilmi ettei tämä strategia toimisi kovin pitkälle. C++ oli yksinkertaisesti sopimaton tehtävään. Projektissa työskennellyt James Gosling alkoi kehitellä täysin uutta ohjelmointikieltä, jolle hän antoi työnimeksi Oak työhuoneen ulkopuolella seisoneen puun mukaan. Oakin kehittely jatkui, ja tuotemerkkiä etsittäessä sen nimi lopulta muutettiin Javaksi.
Green-projektin ensimmäinen varsinainen tuote oli Star7, joka oli kädessä pidettävän tietokoneen ja kaukosäätimen risteytys. Star7 ei koskaan päässyt myyntiin, mutta se riitti vakuuttamaan Sunin silloisen pääjohtajan, Scott McNealyn, joka muodosti Green-projektista erillisen yhtiön, First Person Incin.
Samaan aikaan First Person siirsi kiinnostuksensa nk. settop:ien käyttöjärjestelmiin. Settopit, kuten sulautetut järjestelmät, vaativat käyttöjärjestelmän lisäksi ohjelmointikielen, jolla olisi mahdollista kirjoittaa kompaktia, virheetöntä, turvallista ja ennenkaikkea laitteistosta riippumatonta koodia.
Settop-laitteiden markkinat osoittautuivat lähes olemattomiksi, joten vuonna 1994 First Person Inc sulautetttiin takaisin emoyhtiöön Sun:iin. Suuri osa First Person In:cin työntekijöistä siirtyi muihin tehtäviin, mutta osa jäi jatkamaan Javan kehitystyötä ja miettimään sille uusia käyttökohteita. Saman vuonnna World Wide Web oli lyömässä itseään voimalla läpi, ja Naughton näki siinä Javalle sopivan käyttökohteen.
Viikonlopun mittaisen koodaussession aikana syntyi prototyyppi uudenlaisesta selailimesta, WebRunnerista, joka pystyi ajamaan HTML-koodin lomaan istutettuja Java-ohjelmia. WebRunner onnistui vakuuttamaan Sunin johtajat Java-kielen hyödyllisyydestä, ja Javan voittokulku saattoi lopulta alkaa.
Javan suunnittelun lähtökohtia ovat olleet laitteistoriippumattomuus, turvallisuus ja ohjelmoinnin helppous. Java-kieli ei sisällä mitään uusia tai kokeellisia piirteitä, vaan siihen on koottu useissa kielissä hyviksi havaittuja piirteitä.
Java on oliopohjainen, vahvaa tyypitystä tukeva kieli josta löytyvät automaattinen roskien keruu, abstraktit olioluokat, säikeet ja poikkeutukset.
Java on sekä kääntävä että tulkkaava kieli. Java-kieliset ohjelmat käännetään ensin nk. bytecode-muotoon, joka sitten ajetaan Java virtuaalikoneella.
Java muistuttaa paljon C++:aa, eikä ihme, sillä kielen kehitys lähti alunperin liikkeelle C++:n ominaisuuksien laajentamisesta. Myöhemmin Javasta kehittyi oma, erillinen kieli, joka eroaa huomattavasti C++:sta. Muutamia tärkeimpiä Javan ja C++:n välisiä eroja ovat:
Javan syntaksi on hyvin lähellä C:tä tai C++:aa. Ohjelmalohkot merkitään kaarisuluilla, komennot erotetaan puolipisteellä, ja taulukot ja niiden indeksointi ilmaistaan hakasuluilla. Kommentit merkitään joko kaksois-kenoviivalla (//) tai C-kielestä tutulla /* ... */ -rakenteella. Lähes kaikki Javan ja C++:n yhteiset komennot ovat syntaksiltaan täysin identtisiä. Tällaisia komentoja ovat:
if |
else |
switch |
case |
default |
break |
for |
do |
while |
new |
return |
try |
catch |
throw |
continue |
Muut Java-kielen avainsanat on lueteltu seuraavassa:
abstract |
private |
boolean |
do |
implements |
protected |
throws |
double |
import |
public |
transient |
byte |
instanceof |
extends |
int |
short |
void |
final |
interface |
static |
volatile |
char |
finally |
long |
super |
class |
float |
native |
synchronized |
package |
this |
Niistä tärkeimmät käydään läpi myöhemmin tässä luvussa.
Javan tietotyypit jakautuvat kahteen kategoriaan: primitiivi- ja viitetyyppeihin.
Primitiivityyppejä ovat looginen tyyppi boolean
sekä
numeeriset tyypit. Kaikki muut tyypit, kuten taulukot, merkkijonot ja kaikki
olioluokat, kuuluvat viitetyyppeihin.
Primitiivityyppinen muuttuja sisältää itsessään muuttujan arvon, viitetyyppinen muuttuja vain joko null-arvon tai viittauksen johonkin olioon.
Molemmat muuttujatyypit on alustettava ennen käyttöä.
Primitiivityyppinen muuttuja alustetaan yksinkertaisesti asettamalla sille
arvo, viitetyyppinen muuttuja alustetaan new
-operaattorilla.
Alla on taulukoitu kaiki Javan primitiivityypit
Nimi | Pituus (bittejä) |
lukualue |
---|---|---|
byte |
8 | [-127 , 128] |
short |
16 | [-32 768 , 32 767] |
int |
32 | [-2 147 483 648 , 2 147 483 647] |
long |
64 | [-9 223 372 036 854 775 808 , 9 223 372 036 854 775 807] |
Nimi | Pituus (bittejä) |
kommentti |
---|---|---|
float |
32 | IEEE-754 liukuluku |
double |
64 | IEEE-754 liukuluku |
Nimi | Pituus (bittejä) |
lukualue |
---|---|---|
boolean |
1 | true tai false |
char |
16 | Unicode-merkki |
Taulukot määritellään kirjoittamalla halutun tyypin perään hakasulut ja taulukon nimi. Esimerkiksi
int[]kalat;
määrittää kokonaislukutaulukon. Ylläoleva määritelmä
luo vasta viitteen taulukolle. Jotta taulukkoa voitaisiin käyttää,
se on luotava ensin new
-operaattorilla. Samalla määritetään
taulukon haluttu koko.
kalat = new int[100];
int kalapituus = kalat.length;
Taulukot indeksoidaan kuten C:ssä, eli ensimmäisen alkion
indeksi on nolla ja viimeisen (taulukon koko- 1). Kaikilla taulukoilla
on length
-jäsen, kokonaisluku, joka sisältää taulukon
koon ohjelman suorituksen aikana.
Alla on taulukoitu kaikki Javan operaattorit..
Operaattori | Operaattorin käyttö |
Toiminta |
---|---|---|
+ |
op1 + op2 |
Yhteenlasku |
- |
op1 - op2 |
Vähennyslasku |
* |
op1 * op2 |
Kertolasku |
/ |
op1 / op2 |
Jakolasku |
% |
op1 % op2 |
Jakojäännös, kun op1 jaetaan op2:lla |
Operaattori | Operaattorin käyttö |
Toiminta |
---|---|---|
+ |
+ op |
Positiivinen etumerkki |
- |
- op |
Aritmeettinen negaatio |
Operaattori | Operaattorin käyttö |
Toiminta |
---|---|---|
++ |
op++ |
op:n arvoa lisätään yhdellä. Lausekkeen arvo on op. |
++ |
++op |
Kuten edellä, mutta lausekkeen arvo on op+1. |
-- |
op-- |
op:n arvoa vähennetään yhdellä. Lausekkeen arvo on op. |
-- |
--op |
Kuten edellä, mutta lausekkeen arvo on op-1. |
Operaattori | Operaattorin käyttö |
Palauttaa tosi-arvon, jos |
---|---|---|
> |
op1 > op2 |
op1 on suurempi kuin op2 |
< |
op1 < op2 |
op1 on pienempi kuin op2 |
>= |
op1 >= op2 |
op1 on yhtäsuuri tai suurempi kuin op2 |
<= |
op1 <= op2 |
op1 on yhtäsuuri tai pienempi kuin op2 |
== |
op1 == op2 |
op1 on yhtäsuuri kuin op2 |
!= |
op1 != op2 |
op1 on erisuuri tai suurempi kuin op2 |
Operaattori | Operaattorin käyttö |
Kommentti |
---|---|---|
&& |
op1 && op2 |
Looginen AND |
|| |
op1 || op2 |
Looginen OR |
! |
!op |
Looginen negaatio |
Operaattori | Operaattorin käyttö |
Kommentti |
---|---|---|
>> |
op1 >> op2 |
op1:n bittejä siirretään oikealle op2:n verran |
<< |
op1 << op2 |
op1:n bittejä siirretään vasemmalle op2:n verran |
>>> |
op1 >>> op2 |
Bitinsiirto oikealle ilman etumerkkiä. |
& |
op1 & op2 |
AND |
| |
op1 | op2 |
OR |
^ |
op1 ^ op2 |
XOR |
~ |
~op |
komplementti |
Lisäksi Javassa voi käyttää C:stä ja C++:ta tuttuja lyhenteitä +=,-=, *=,/=, jne.
Oliot ja luokat muodostavat Java-kielisen koodin koko rakenteen. Kaiken ohjelmakoodin on kuuluttava osana luokanmääritykseen.
Luokka määritellään class
-avainsanalla:
class Complex { ... }
Kun luokkaa käytetään muuttujanmäärityksessä,
se ei voi olla muu kuin viitemuuttuja, joka täytyy alustaa. Esimerkiksi
seuraava rivi luo Complex
-tyyppisen olion ja asettaa muuttujan a viittaamaan
siihen.
Complex a = new Complex();
Luokka voidaan määritellä abstraktiksi luokaksi, jolloin
luokasta itsestään ei voi luoda instanssia, mutta luokan voi
periä. Abstraktiksi luokaksi määrittely tapahtuu abstract
-avainsanalla:
public abstract class Number { ... }
Normaalisti luokkaa voi käyttää vain saman paketin (ks.
luku 3.7) luokat. Lisäämällä public
-muokkaaja luokanmäärityksen
eteen voidaan käyttöoikeus luokkaan antaa myös paketin ulkopuolisille
luokille. Luokanmäärityksessä ei voi käyttää
muita turvallisuusmuokkaajia.
Luokan perinnän voi estää final
-avainsanalla. Luokkaa
voi käyttää normaalisti, mutta siitä ei voi muodostaa
aliluokkia.
public final class String {
...
}
Luokan attribuutti voi olla joko tieto- tai metodiattribuutti. Attribuutit määritellään kokonaisuudessaan luokanmäärittelyn sisällä. Niille voi antaa erilaisia muokkaajia, jotka sijoitetaan ennen varsinaista attribuutin määrittelyä.
Toisten luokkien käyttöoikeuksia luokan attribuutteihin voidaan rajoittaa sopivalla turvallisuusmuokkaajalla. Alla on lista ja lyhyt kuvaus kaikista attribuuttien käyttöoikeudet määrittelevistä muokkaajista.
public
Kaikilla on käyttöoikeus attribuuttiin.protected
Vain luokalla itsellään, siitä perittyillä aliluokilla ja saman paketin jäsenillä on käyttöoikeus attribuuttiin.private
Vain luokalla itsellään on käyttöoikeus attribuuttiin.
Oletusarvona vain luokalla itsellään ja saman paketin (ks. luku 3.7) muilla luokilla on käyttöoikeudet attribuutteihin.
Tietoattribuutit määritellään kuten muuttujat. Tietoattribuutin voi alustaa joko suoraan määrittelyn yhteydessä, tai myöhemmin jossain metodissa. Tietoattribuuteille voidaan antaa käyttöoikeuden lisäksi myös muita muokkaajia. Alla on lyhyt luettelo kaikista tietoattribuuttien muokkaajista.
final
attribuutti on vakio. final-attribuutti täytyy alustaa määrittelyn yhteydessästatic
luokkaattribuutti. Sille varataan muistia vaikka ohjelma ei missään vaiheessa loisi oliota luokasta.volatile
attribuuttia päivitetään asynkronisesti (tämä muokkaaja ei ole käytössä nykyisessä Javan versiossa)transient
attribuuttia ei tallenneta mahdollisten arkistointioperaatoiden yhteydessä. (ei käytössä nykyisessä Javan versiossa)
Metodit määritellään kuten C++:ssa. Myös metodeille voidaan antaa muita muokkaajia kuin käyttöoikeudet. Alla on lista metodien muokkaajia.
static
Metodi on luokkametodi; sitä voidaan kutsua vaikka ohjelma ei loisikaan yhtään instanssia luokasta.abstract
Metodi on abstrakti, ts. sitä ei toteuteta sen esitelleessä luokassa, vaan aliluokkien on toteutettava se aina erikseen.final
Metodia ei voida uudelleenmääritellä aliluokissa.native
Metodi on toteutettu ohjelman ulkopuolella jollain muulla ohjelmointikielelläsynchronized
Metodi lukitsee olion käyttämän muistialueen, jotta toiset säikeet eivät voisi kutusua olion metodeja.
Seuraavassa esimerkki attribuuttien määrittelystä:
/** The representation of a 3D model */
class Model3D {
float vert[];
int tvert[];
int nvert, maxvert;
int con[];
int ncon, maxcon;
boolean transformed;
Matrix3D mat;
float xmin, xmax, ymin, ymax, zmin, zmax;
Model3D () {
...
}
/** Add a vertex to this model */
int addVert(float x, float y, floatz) {
...
}
/** Transform all the points in this model */
void transform() {
...
}
/* Quick Sort implementation */
private void quickSort(int a[], intleft, int right) {
...
}
static Color gr[];
/** Paint this model to a graphics context */
void paint(Graphics g) {
...
}
}
Java-kielisen ohjelman suoritus alkaa aina main
-metodista, joka on määriteltävä seuraavasti:
public static void main(String[] args) { ... }
Vain yksi luokka voi määrittää main
-metodin. Sen
ainoa parametri, merkkijonotaulukko sisältää ohjelmalle
annetut parametrit.
Luokan rakentaja on metodi jolla sama nimi kuin itse luokalla. Ne eivät
palauta mitään arvoa, eikä niille siis määritetä
palautusarvon tyyppiä. Luokalle ei ole pakko määritellä
rakentajaa, sillä Java määrittää automaattisesti
oletusrakentajan jokaiselle luokalle. Rakentajalle voi antaa minkä
tahansa turvallisuusmuokkaajan, mutta ei muita muokkaajia. Alla esimerkki
rakentajan määrittelystä:
class Model3D {
Model3D () {
...
}
}
Varsinaisia hävittäjiä ei Javassa ole, vaan niiden virkaa
toimittaa Object
-luokan (ks. luku 3.5.4) finalize
-metodi, jonka muut luokat
voivat vapaasti määritellä uudelleen. finalize
-metodia kutsutaan
aina ennen kuin olio poistetaan muistista. Oletustoteutuksena se ei tee
mitään.
Vain yksinkertainen perintä on mahdollista Javassa. Perintää
ilmaistaan extends
-avainsanalla:
class Complex extends Number {
...
}
Kaikki Javan luokkahierarkiaan kuuluvat luokat, käyttäjän
luomat mukaan luettuna, perivät Object
-luokan. Object
-luokka määrittelee joukon yleishyödyllisiä metodeja, jotka alempana hierarkiassa
sijaitsevat luokat voivat määritellä uudelleen tarpeen mukaan.
Tällaisia ovat esimerkiksi ToString
, joka antaa tekstuaalisen esityksen
oliosta ja equals
, joka testaa kahden olion samanarvoisuutta.
Aliluokat voivat käyttää välittömän edeltäjänsä
metodeja tai jäsenmuuttujia super
-komennon avulla. super
-komentoa
käytetään aivan kuin se olisi tavallinen viitemuuttuja.
Luokka voi kutsua edeltäjäluokan konstruktoria super
:in avulla
laittamalla konstruktorin argumentit sulkuihin sen jälkeen. Seuraavassa
esimerkki super
-komennon käytöstä.
class ParseException extends Exception {
ParseException(String s) {
super(s);
}
}
Java luokat voivat kiertää yksinkertaisen perinnän rajoituksia määrittelemällä yhteisen rajapinnan. Niiden avulla voidaan käyttää yhdessä luokkia jotka sijaitsevat erillään luokkahierarkiassa.
Rajapinta määritellään interface
-avainsanan avulla
samaan tapaan kuin luokka. Erona luokanmäärittelyyn rajapinnan
kaikki attribuutit ovat vakioita, ja metodeita ei implementoida. Rajapinta
voi periä yhden tai useampia rajapintoja extends
-avainsanalla. Seuraavassa
on esimerkki rajapinnan määrittelystä.
interface DoubleLinkedList extends Collection, List {
int MAXNUMOFELEMENTS = 500;
void add(Object obj);
void delete(Object obj);
Object find(Object obj);
int currentCount();
}
Jokainen metodin määritys lopetetaan puolipisteellä, koska rajapinta ei itse toteuta metodeja, vaan jättää sen luokkien tehtäväksi.
Luokanmäärityksessä luokan toteuttamat rajapinnat ilmoitetaan
implements
-avainsanalla. Luokka voi toteuttaa useampia rajapintoja kerrallaan.
Esimerkiksi:
class Model3DList implements DoubleLinkedList {
...
}
Rajapintoja käytetään kuten luokkien nimiä. Esimerkiksi
viite:
Collection box;
voi viitata mihin tahansa olioon jonka luokka toteuttaa Collection
-rajapinnan.
Javan luokat on mahdollista koota yhteen paketeiksi. Paketti määritellään
laittamalla tiedoston alkuun avainsana package
ja sen perään
paketin nimi. Kaikki samassa tiedostossa olevat luokat ja käyttöliittymät
kuuluvat samaan pakettiin.
Seuraava esimerkki luo graphics
-nimisen paketin, joka sisältää
yhden luokan ja yhden rajapinnan:
package graphics;
interface GraphicObject {
...
}
class BitMap implements GraphicObject {
...
}
Ulkopuolisen paketin luokat tuodaan mukaan ohjelmaan import
-komennolla:
import graphics.*;
import graphics.BitMap;
import
-komennon avulla voidaan ottaa paketista joko yksittäinen
paketin jäsen, tai käyttämällä jokerimerkkiä
* kaikki paketin jäsenet. Paketin jäseniä voidaan importin
jälkeen käyttää kuten mitä tahansa ohjelmassa
määritettyä luokkaa tai rajapintaa. Jos ohjelmassa määriteltyjen
luokkien tai rajapintojen ja mukaantuotujen pakettien jäsenten nimien
välillä on sekaannuksen vaara, voidaan paketin jäsenet määritellä
tarkasti laittamalla paketin nimi pisteellä erotettuna ennen jäsenen
nimeä:
graphics.Circle FirstCircle;
class Triangle implements
graphics.GraphicObject {
...
}
Paketin binääritiedostojen täytyy sijaita hakemistossa,
jolla on sama nimi kuin paketilla, ja joka löytyy classpath
-järjestelmämuuttujasta.
Pakettien nimet voivat sisältää useampia osia pisteellä
erotettuna, jolloin jokainen nimen osa viittaa omaan hakemistoon. Esimerkiksi
seuraavalla import
-komennolla haettavan paketin pitäisi löytyä
hakemistosta ../java/lang/awt/
import java.lang.awt.*;
Kaikki luokat ja rajapinnat kuuluvat automaattisesti johonkin pakettiin. Jos pakettia ei määritellä erikseen, kuuluvat tiedoston luokat ja rajapinnat oletuspakettiin, jolla ei ole nimeä ja joka otetaan aina mukaan ohjelmaan.
Java-kielen mukana tulee laaja luokkakirjasto, jonka paketeista löytyy kaikki tarvittava applettien ohjelmoimiseen, graafisten käyttöliittymien luomiseen, syöttöön, tulostukseen ja moneen muuhun tarkoitukseen. Seuraavassa lyhyt luettelo Javan mukana tulevista paketeista:
Applet- ja AWT-paketit käydään läpi omissa luvuissaan. Muista paketeista, erityisesti j
java.lang:ista, annetaan jäljempänä lyhyt kuvaus.
Java.lang on ehkä tärkein Javan mukana tulevista paketeista. Alla on lyhyt lista sen sisällöstä. Tärkeimmät luokat käsitellään vielä erikseen.
Object
- koko Javan luokkahierarkian ylin luokka System
-luokka sisältää informaatiota laitteistosta ja
käyttöjärjestelmästä. Kaikki sen metodit ja tetoattribuutit
ovat luokkakohtaisia; siitä ei siis tarvitse luoda instanssia jotta
sen attribuutteihin pääsisi käsiksi. System
-luokan tarjoamat
palvelut on lueteltu alla lyhyesti.
System.in
, System.out
ja System.err
System.getProperty
ja System.getProperties
System.runFinalization
ja System.gc
System.arraycopy
System.currentTimeMillis
System.exit
System.getSecurityManager
ja
System.setSecurityManager
String
ja StringBuffer
ovat Javan merkkijonojen käsittelyyn tarkoitetut
luokat. String
on sopivin muuttumattomien merkkijonojen käsittelyyn.
StringBuffer
on tarkoituksenmukaisin kun on tarpeen muuttaa merkkijonon
sisältöä ajon aikana.
String
-luokka sisältää useita merkkijonon sisällön
lukemiseen tarkoitettuja metodeja. Näitä ovat mm. charAt
, length
,
substring
, indexOf
ja lastIndexOf
.
StringBuffer
sisältää edellisten lisäksi paljon
merkkijonojen muuttamiseen tarkoitettuja metodeja kuten setCharAt
, reverseIt
ja append
. Lisäksi, koska StringBuffer
on itse asiassa merkkijonojen
tallettamiseen varattu muistialue, se sisältää capacity
-metodin,
joka kertoo varatun muistin määrän.
Java-kieli sisältää sisäänrakennetun tuen säikeille. Koska Java on tarkoitettu toimimaan useissa eri laiteympäristöissä ja käyttöjärjestelmissä, se ei voi luottaa järjestelmän moniajoon. Javan säikeet on suunniteltu mahdollisimman ympäristöriippumattomiksi, joskin järjestelmän oma moniajotuki vaikuttaa jonkin verran niiden toimintaan.
Säikeen voi luoda kahdella tavalla: luomalla sille oman luokan,
joka perii java.lang -paketin Thread
-luokan, tai luomalla luokan joka toteuttaa
Runnable
-rajapinnan. Jälkimmäinen tapa on parempi jos luokan
on perittävä jokin muu luokka (esimerkiksi Applet
).
Säikeen on määriteltävä joukko metodeita, jotka
ohjaavat sen toimintaa. start
-metodi käynnistää säikeen
ja varaa sen tarvitsemat resurssit, run
sisältää säikeen
varsinaisen ohjelmakoodin, ja stop
pysäyttää säikeen
ja vapauttaa sen varaamat resurssit.
Poikkeutukset ovat tehokas tapa käsitellä ohjelman sisällä tapahtuvia virheitä. Tyypillisesti virhetilanteessa virheen aiheuttanut metodi lähettää poikkeutuksen metodia kutsuneelle metodille. Jos kutsunut metodi ei käsittele poikkeutusta, se välitetään kutsupinossa (call stack) eteenpäin, kunnes jokin metodi lopultaa käsittelee lähetetyn poikkeutuksen. Jos mikään metodi ei käsittele poikkeutusta, ohjelman suoritus loppuu.
Java-kielen poikkeutukset välitetään Throwable
-luokan,
tai jonkin sen aliluokan avulla. Käyttäjä voi määritellä
omia poikkeutuksiaan perimällä jonkun Throwable
-luokkahierarkian
luokan.
Kuva 1: Java-kielen poikkeutusten luokkahierarkia
Metodin täytyy joko käsitellä tai esitellä kaikki
poikkeutukset, mitä metodin sisällä voi tapahtua. Poikkeutuksen
määrittely esittely throws
-avainsanalla, joka lisätään
metodin argumenttilistan perään ennen varsinaista ohjelmalohkoa.
Sen jälkeen luetellaan kaikki ne poikkeutukset mitä metodi saattaa
aiheuttaa. Poikkeutuksen lähettäminen tapahtuu throw
-komennolla:
class ParseException extends Exception {
...
}
String Parse(String sentence) throws ParseException {
if (!sentence.endsWith(".") {
throw new ParseException("Not a full sentence");
}
...
}
Poikkeutusten käsittely tapahtuu try-catch-finally
-lohkolla. try
-lohkon
sisään sijoitetaan mahdollisen poikkeutuksen lähettävä
ohjelmakoodi, catch
-lohkot yrittävät tunnistaa ja käsitellä
lähetetyn poikkeutuksen ja finally
-lohko suoritetaan aina lopuksi,
lähettipä ohjelma poikkeutuksen tai ei. Alla on esimerkki try-catch-finally
-lohkosta:
String Translate(String s) {
...
String t;
try {
t = Parse(s);
} catch (ParseException p) {
...
} catch (Exception e) {
...
} finally {
...
}
...
}
catch
-lohkoja läpikäydessään ohjelma suorittaa ensimmäisen
sopivan catch
-lauseen, ja hyppää loppujen yli. Yleisluontoiset
virhetilanteet käsittelevät lauseet kannattaa sijoittaa lohkon
loppupäähän.
Java.io-paketti sisältää syöttö- ja tulostusvirtojen luokkamäärittelyt, tiedostojen käsittelyyn tarvittavat luokat, sekä käyttöliittymät Javan primitiivityyppisen tiedon syöttöön ja tulostukseen.
InputStream
ja OutputStream
ovat syöttö- ja tulostusvirtojen
perusluokat. Ne sisältävät vain yksinkertaisen käyttöliittymän,
ja pystyvät rajoitettuun tiedonkäsittelyyn. Kaikki monimutkaisemmat
tominnot on toteutettu näiden luokkien aliluokissa. Alla on lista
InputStream
:in ja OutputStream
:in tärkeimmistä aliluokista ja
niiden käyttötarkoituksista.
FileInputStream
ja FileOutputStream
on tarkoitettu tiedostojen lukemiseen
ja kirjoittamiseen. PipedInputStream
ja PipedOutputStream
toteuttavat tietojen siirron
putkia pitkin. Putkien avulla voidaan siirtää tietoa eri ohjemien
tai ohjelman eri säikeiden välillä. PipedInputStream
-olion
täytyy aina olla liitettynä vastaavaan PipedOutputStream
-olioon,
ja päinvastoin. ByteArrayInputStream
ja ByteArrayOutputStream
mahdollistavat tietojen
lukemisen ja kirjoittamisen muistialueisiin. SequenceInputStream
yhdistää syöttövirtoja useasta
eri lähteestä yhdeksi virraksi. StringBufferInputStream
mahdollistaa tietojen lukemisen StringBuffer
-oliosta
ikäänkuin se olisi syöttövirta Edellämainittujen luokkien lisäksi java.io sisältää kirjaston erilaisia syöttö- ja tulostusvirtaluokkia, jotka käsittelevät tietoa lukemisen ja tulostamisen ohella. Näitä luokkia ei käsitellä tässä esitelmässä.
Syöttö- tai tulostusvirta avataan automaattisesti luotaessa,
ja se suljetaan joko close
-metodilla, tai automaattisesti kun systeemi
poistaa virtaa vastaavan olion muistista. Avatun virran lukeminen ja kirjoittaminen
tapahtuu luokan metodeilla. Alla on lyhyt esimerkki tiedostojen lukemisesta
ja kirjoittamisesta FileInputStream
:in ja FileOutputStream
:in avulla:
class FileStreamsTest {
public static void main(String[] args) {
try{
File inputFile = new File("farrago.txt");
File outputFile = new File("outagain.txt");
FileInputStream fis = new FileInputStream(inputFile);
FileOutputStream fos = new FileOutputStream(outputFile);
int c;
while ((c = fis.read()) !=-1) {
fos.write(c);
}
} catch (FileNotFoundException e) {
System.err.println("FileStreamsTest:" + e);
} catch (IOException e) {
System.err.println("FileStreamsTest:" + e);
} finally {
fis.close();
fos.close();
}
}
}
Javan AWT (Abstract Window Toolkit) sisältää laajan kokoelman graafisen käyttöliittymän ohjelmointiin tarvittavia luokkia. Tavallisten ikkunointijärjestelmän komponenttien kuten painikkeiden, valikkojen, jne. lisäksi AWT sisältää luokkia, joiden avulla voidaan käsitellä ja jossain määrin muokata bittikarttamuodossa olevia kuvia.
Java-ohjelman käyttöliittymä koostuu kahdenlaisista komponenteista: peruskomponenteista ja säiliökomponenteista. Peruskomponentteihin kuuluvat kaikki ikkunointijärjestelmän tärkeimmät osat: nappulat, listat, valintalistat, valikot, vierityspalkit, otsikot, checkboxit, radiopainikkeet, valintalistat ja tekstilaatikot. Säiliökomponentteja, kuten ikkunoita, dialogeja ja paneleita, käytetään peruskomponenttien sommitteluun. Kuvassa 2 näkyvät kaikki AWT:n komponentit sellaisina kuin ne näkyvät Windows NT 3.51-järjestelmässä.
Valikkoa lukuunottamatta kaikki AWT:n komponenttiluokat ovat Component
-luokan
alaluokkia. Kuvissa 3 ja 4 esitetään AWT:n komponenttien luokkahierarkia.
Ennenkuin komponentti voi tulla näkyviin, sen on kuuluttava johonkin
säiliökomponenttiin. Ainoa poikkeus tästä säännöstä
ovat säiliökomponentit itse. Kaikki säiliökomponentit
ovat Container
-luokan aliluokkia. Frame
on tavallinen ikkuna, Dialog
on
joko modaalinen tai ei-modaalinen dialogi, FileDialog
on AWT:n mukana tuleva
tiedostojen käsittelyyn tarkoitettu dialogi ja Panel
yleiskäyttöinen
komponenttien ryhmittelyyn tarkoitettu komponentti.
Komponentti lisätään säiliöön Container
-luokan
add
-metodilla. Tämän jälkeen komponentti tulee näkyviin
automaattisesti, kun säiliö piirretään ensimmäisen
kerran näytölle. add
-metodin parametrit riippuvat käytössä
olevasta layoutmanagerista (ks. luku 5.3), viimeinen argumentti on kuitenkin
aina säiliöön lisättävä komponentti.
Komponenttien piirto näytölle tapahtuu aina alimmasta komponentista ylimpään. Kukin komponentti siis piirtää itsensä ennen sen mahdollisesti sisältämiä komponentteja.
Komponentin piirtäminen tapahtuu vain, kun AWT antaa siihen luvan.
Tämä siksi, että piirtäminen voisi tapahtua keskeytymättä.
AWT pyytää komponenttia piirtämään itsensä
kutsumalla sen update
-metodia. Oletuksena (Component
-luokan toteutuksessa)
update
tyhjentää komponentin alueen piirtämällä
taustanvärisen suorakulmion koko komponentin alueelle, ja kutsuu komponentin
paint
-metodia.
Sekä update
että paint
-metodille välitetään
vain yksi argumentti. Tämä Graphics
-luokan olio, joka edustaa
graafista kontekstia johon komponentti voi piirtää. Graphics
-luokka
sisältää metodit kuvioiden (viiva, kaari, ympyrä, soikio,
suorakulmio, monikulmio), tekstin ja bittikarttojen piirtämiseen sekä
värien ja piirtomoodin asetukseen.
Yksinkertaisin tapa toteuttaa oman komponentin piirto on määrittää
uudestaan paint
-metodi, ja antaa AWT :n päättää milloin
piirtäminen tapahtuu. Koska update
puhdistaa koko komponentin alueen
ennen paint
-metodin kutsua, se saattaa aiheuttaa vilkkumista erityisesti
animaatioissa. Tällaisissa tapauksissa on parasta tehdä oma toteutus
update
-metodista turhan piirtämisen eliminoimiseksi.
AWT on suunniteltu siten, että se on riippumaton alla olevasta käyttöjärjestelmästä, mutta säilyttää silti kunkin järjestelmän oman graafisen tyylin. Jotta tämä olisi mahdollista, on AWT:n rakenne jaettu kahteen osaan. Käyttäjälle näkyvän osan muodostavat AWT:n luokkakirjasto, jonka avulla komponentteja voidaan käsitellä. Jokaista luokkaa vastaa vastinkappale (engl. peer), joka toteuttaa kunkin komponentin järjestelmäkohtaisilla kutsuilla. Vastinkappaleet määräävät viimekädessä kunkin komponentin ulkoasun ja käyttäytymisen, jonka takia Java-käyttöliittymät näyttävät hieman erilaisilta eri järjestelmissä.
Kunkin komponentin vastinkappale luodaan vasta viime hetkellä,
juuri ennen kuin vastinkappaletta vastaava komponentti piirretään
näytölle. Tästä johtuu muunmuassa se, että komponenttien
kokoa ei tiedetä ennen kuin ne piirrettään ensimmäisen
kerran. Jos komponentti lisätään säiliöön
jota ei ole vielä tuotu näkyviin, kaikki sen sisältämien
komponenttien vastinkappaleet luodaan automaattisesti kun säiliö
piirretään. Jos komponentti lisätään jo näkyvillä
olevaan säiliöön, komponentin vastinkappale on luotava erikseen
validate
-kutsulla.
Kuva 5: Esimerkki AWT:n komponenttien rakenteesta
Koska AWT on laiteriippumaton kirjasto, komponenttien tarkka sijoittelu säiliön sisällä on yleensä erittäin hankalaa, mikä johtaa usein järjestelmästä riippuvaan toteutukseen. Ongelmaan voidaan ratkaista layoutmanagereiden avulla.
Layoutmanager huolehtii komponenttien tarkasta sijoittelusta säiliön sisällä. AWT:n mukana tulee 5 valmista layoutmanager:ia, jotka käsitellään kukin erikseen. Myös omien layoutmanagerien teko on mahdollista, mutta siihen ei puututa tässä.
Layoutmanager otetaan käyttöön luomalla instanssi halutun
tyyppisestä managerista, ja käyttämällä säiliökomponentin
setLayout
-metodia. Tämän jälkeen sijoiteltavat komponentit
lisätään säiliöön add
-metodilla. Jotkut layoutmanagerit
vaativat useamman parametrin käyttöä add
-metodissa; tästä
mainitaan erikseen kunkin managerin kohdalla.
BorderLayout
on AWT:n oletusmanageri kaikille ikkunaluokille, ts. Frame
ja Dialog
-luokille ja niiden alaluokille. BorderLayout
jakaa säiliön
viiteen osaan: pohjoiseen, etelään, itään, länteen
ja keskustaan. Näihin kuhunkin voi asettaa yhden komponentin.
BorderLayout
vaatii kahden argumentin käyttöä add
-metodin
kutsussa. Ensimmäisenä annettava argumentti on merkkijono, joka
sisältää säiliön osan nimen, minne komponentti
sijoitetaan ("North", "South", "East", "West"
tai "Center"). Jälkimmäinen argumentti on viite sijoitettavaan
komponenttiin. Jos yhteen osaan sijoitetaan useampi komponentti, vain viimeisin
komponentti tulee näkyviin.
CardLayout
mahdollistaa usean vaihtoehtoisen komponentin näyttämisen
samassa paikassa. Layoutmanager toimii kuin korttipakka, jossa vain päällimmäinen
kortti on kerrallaa näkyvissä.
CardLayout
käyttää kahta argumenttia add
-metodin kutsussa.
Ensimmäinen argumentti on lisättävän komponentin nimi.
Komponentti voidaan valita näkyviin joko kutsumalla sitä suoraan
nimeltä show
-metodilla, käymällä korttipakkaa läpi
eteen- tai taaksepäin next
ja previous
-metodeilla, tai valitsemalla
pakan ensimmäinen tai viimeinen kortti first
ja last
-metodeilla.
FlowLayout
on oletusmanageri kaikille Panel
-komponenteille. Se sijoittaa
komponentit säiliöön riveittäin vasemmalta oikealle
komponenttien lisäysjärjestyksessä.
GridLayout
jakaa säiliön ristikkoon, jonka kuhunkin soluun
voi sijoittaa yhden komponentin. Kaikki solut (ja niiden sisältämät
komponentit) ovat saman kokoisia. Ristikon koko täytyy määrittää
GridLayout
:ia luotaessa. Koon lisäksi voidaan määritellä
ristikon solujen väliin jäävä tila. Komponentit lisätään
säiliöön vasemmalta oikealle ja ylhäältä
alas. Ensimmäinen komponentti sijoitetaan siis vasempaan yläkulmaan.
GridBagLayout
on monimutkaisin ja monipuolisin kaikista AWT:n mukana
tulevista layout managereista. GridBagLayout
jakaa säiliön tilan
halutun kokoiseen ristikkoon kuten GridLayout
., mutta yksittäinen
komponentti voi viedä useamman solun tilan joko vaaka- tai pystysuunnassa.
Kullekin komponentille voidaan lisäksi antaa painoarvo, joka määrää
miten tila jaetaan komponenttien kesken pysty- tai vaakasuunnassa.
GridBagLayout
käyttää kahta argumenttia add-metodin kutsussa.
Ensimmäinen argumentti on GridBagContext
-luokan olio, jonka avulla
asetetaan komponentin paikka ja muut siihen liittyvät arvot.
Myös omien layoutmanagerien ohjelmointi on mahdollista. Tällöin
tulee luoda luokka joka toteuttaa LayoutManager
-rajapinnan ja kaikki siinä
määritellyt metodit. Layoutmanagerien ohjelmointia ei käsitellä
tässä tarkemmin.
Javan graafisen käyttöliittymän toiminta perustuu järjestelmän
lähettämien viestien sieppaamiseen ja käsittelemiseen. Viestien
välitys tapahtuu Event
-luokan olioiden avulla. Käyttäjän
tehdessä jonkin toiminnan, esimerkiksi painaessa hiiren nappia, Java
luo asianmukaisen Event
-olion, ja lähettää sen ylös
komponenttihierarkiaa. Jokainen komponentti saa mahdollisuuden käsitellä
viestin, ennen kuin komponentin vastinkappale (ks. luku 5.1.3) lopulta
käsittelee viestin.
AWT käyttää viestin välitykseen Event
-olioita, jotka
sisältävät seuraavat tiedot viestin synnyttäneestä
tapahtumasta:
AWT ei saa käsiteltäväkseen jokaista käyttäjän toimintaa, vaan ainoastaan ne mitkä järjestelmä välittää sille. Esimerkiksi Motif ei välitä MOUSE_MOVE-viestiä tekstilaatikoille, joten Java-ohjelma ei pysty reagoimaan siihen.
AWT:n välittämät viestit luetellaan seuraavassa aliluvussa viestinkäsittelymetodien kanssa.
Komponentti voi reagoida viestiin neljällä eri tavalla:
Viestiin reagointi tapahtuu määrittelemällä uudelleen
jonkun Component
-luokan viestinkäsittelymetodin. Näitä metodeja
ovat (viestin tyyppi suluissa):
action
(ACTION_EVENT) mouseEnter
(MOUSE_ENTER) mouseExit
(MOUSE_EXIT) mouseMove
(MOUSE_MOVE) mouseDown
(MOUSE_DOWN) mouseDrag
(MOUSE_DRAG) mouseUp
(MOUSE_UP) keyDown
(KEY_PRESS tai KEY_ACTION) keyUp
(KEY_RELEASE tai KEY_ACTION_RELEASE) gotFocus
(GOT_FOCUS) lostFocus
(LOST_FOCUS) handleEvent
(kaikki viestityypit) Kaikki metodit palauttavat boolean
-arvon. true
ilmaisee metodin käsitelleen
viestin kokonaan, eikä sitä enää välitetä
eteenpäin. false
ilmaisee, että viesti tulisi välittää
edelleen.
Erityisen merkillepantavia viestinkäsittelymetodeja ovat action
ja handleEvent
. HandleEvent
on yleinen viestienkäsittelymetodi, jolle
välitetään kaikki viestit ja joka (oletusarvona) välittää
viestit eteenpäin muille metodeille. handleEvent
:in tulisi aina palauttaa
super.handleEvent
, jotta varmistuisi että viesti tulee käsiteltyä
kunnolla.
Vain tietyille komponenteille välitetään action-viesti
eli luokkien Button, Checkbox, Choice, List, MenuItem
ja TextField
olioille.
action
on korkean tason viesti, joka välitetään komponentille
vasta kun järjestelmätason koodi on jo käsitellyt viestin.
Sitä käsitellessä ei tarvitse välittää sen
synnyttäneistä alemman tason viesteistä, kuten hiiren näppäimen
alaspainamisesta, eikä komponentin ulkoasusta. Järjestelmä
on hoitanut kaiken tarvittavan siinä vaiheessa kun komponentin action
-metodia
kutsutaan.
Kuvien käsittelyyn tarvittavat luokat on jaettu pakettien java.applet, java.awt ja java.awt.image välillä. Kukin paketti sisältää tuen kuville, niiden lataamiselle muistiin, piirtämiselle ja yksinkertaiselle muokkaukselle. Applettien kuvankäsittelyä tarkastellaan seuraavassa luvussa, tässä luvussa kerrotaan vain AWT:n sisältämästä kuvien käsittelystä
Kuvien käsittelyä varten AWT tarjoaa Image
-luokan. Se sisältää
viittauksen bittikarttaan, ja se on yleensä aina argumenttina kun
kutsutaan jonkin komponentin kuvanpiirto-metodia.
Java tukee suoraan GIF- ja JPEG-kuvaformaattia. Kuvan lataaminen muistiin
tapahtuu Toolkit
-luokan getImage
-metodeilla. Asianmukaisen Toolkit
-olion
saa joko Toolkit
-luokan getDefaulttoolkit
-metodilla, tai yksittäisen
komponentti-olion getToolkit
-metodilla. Kuva voidaan hakea joko tiedostonimen
tai URL:n avulla.
Toolkit toolkit = Toolkit.getDefaultToolkit();
Image image1 = toolkit.getImage("imageFile.gif");
Image image2 = toolkit.getImage(new URL("http://java.sun.com/graphics/people.gif"));
getImage
ei lataa kuvaa heti muistiin, vaan ohjelman suoritus jatkuu
välittömästi metodin kutsun jälkeen. Kuvan lataus suoritetaan
taustaprosessina. Jos on tarpeen tietää kuvan latauksen vaihe,
sitä varten ovat MediaTracker
- ja ImageObserver
-luokat. Näitä
luokkia ei käsitellä tässä yhteydessä tarkemmin.
Kuvan piirto tapahtuu Graphics
-olion drawImage
-metodilla.
drawImage
tarvitsee argumenteikseen ainakin Image
-olion,
joka sisältää piirrettävän kuvan, x ja y-koordinaatit, johon kuva piirretään, sekä olion joka toteuttaa imageObserver
-rajapinnan
(useimmat komponentit ovat sopivia).
Appletti tarkoittaa pientä ohjelmaa, joka on istutettu HTML-dokumentin sisään. Tavallisesti Java-kieltä tukeva HTML-selain hakee appletin muistiin samaan aikaan kuin itse HTML-dokumentin, ja suorittaa appletin paikallisessa järjestelmässä.
Applettien toiminta poikkeaa jonkin verran tavallisten Java-ohjelmista. Koska applet ladataan ulkopuolisesta järjestelmästä ja ajetaan paikallisesti, turvallisuus on tärkeä näkökohta. Yleensä WWW-selaimet rajoittavat appletien toimintamahdollisuuksia juuri turvallisuuden takia. Toiseksi, koska appletit ovat osa dokumenttia, niiden koko ja paikka on aina tarkasti määritelty ja niiden täytyy varautua toimimaan rajoitetussa tilassa.
Applet lisätään HTML-dokumenttiin applet
-koodin avulla.
Sen täytyy sisältää ainakin seuraavat parametrit:
code
- ohjelmatiedoston nimi width
- appletin koko vaakasuunnassa pikseleinä height
- appletin koko pystysuunnassa pikseleinä Lisäksi applet
-koodin sisään voi laittaa codebase
-parametrin,
joka ilmoittaa missä hakemistossa tai URL:ssä ohjelmakoodi sijaitsee.
Applet
-lohkon sisäpuolelle voi laittaa param
-koodeja, joiden avulla
on mahdollista välittää parametrejä applet:ille. param
-koodi
sisältää name
- ja value
-muuttujat, joista ensimmäinen
on välitettävän parametrin nimi ja jälkimmäinen
sen arvo.
Applet
-lohkon sisäpuolelle voi sijoittaa myös vaihtoehtoista
HTML-koodia. Appletteja ja Java-kieltä tukeva HTML-selain jättää
huomiotta kaiken applet
-lohkon sisällä olevan ylimääräisen
HTML-koodin (param
-koodeja lukuunottamatta), kun taas selain, joka ei tue
Java-kieltä jättää applet
- ja param
-koodit huomiotta,
ja näyttää vain vaihtoehtoisen koodin.
Alla esimerkki applet
-koodin käytöstä.
<applet code=AppletButton.class codebase=example width=350 height=60 >
<param name=windowType value=BorderWindow>
<param name=windowText value="BorderLayout">
<param name=buttonText value="Click here to see a BorderLayout in action">
<blockquote>
<hr>
<em>
Your browser can't run 1.0 Java applets, so here's a picture of the
window the program brings up:
</em>
<p>
<img src=images/BorderEx1.gif width=302 height=138>
<hr>
</blockquote>
</applet>
Kaikki appletit luodaan perimällä Applet
-luokasta uusia aliluokkia.
Applet
-luokka on Panel
-luokan aliluokka, joten se perii kaikki AWT:n komponenttien
ominaisuudet. Kuva 11 näyttää koko Applet
-luokan perintähierarkian.
Koska Applet
-luokka perii Panel
-luokan, ei appletin ohjelmointi eroa
kovin paljon tavallisen Java-käyttöliittymän ohjelmoinnista.
Ainoa ero löytyy appletin toimintaa ohjaavista metodeista. Nämä
metodit ovat:
init
-metodia kutsutaan joka kerta kun applet luetaan muistiin. start
-metodi aloittaa appletin suorituksen stop
-metodi pysäyttää appletin suorituksen. Destroy
-metodi vapauttaa appletin varaamat resurssit ja valmistaa
appletin roskien keruuta varten. Kaikki appletin vaatimat resurssit on syytä varata init
-metodissa,
sillä ei ole varmaa että appletin ympäristö olisi täysin
toiminnassa konstruktoria kutsuttaessa. Esimerkiksi appletin kuvanlataamismetodit
eivät toimi vielä konstruktorin suorituksen aikana.
Muita tärkeitä Applet-luokan metodeja ovat:
getParam
-metodi palauttaa PARAM-koodissa annetun parametrin arvon getImage
-metodi on Applet-luokan versio kuvanlukemismetodista getApplet
-metodi hakee nimen perusteella viiten toiseen samassa dokumentissa
olevaan appletiin. Tarpeellinen kun applettien halutaan kommunikoivan keskenään.
ShowStatus
-metodi näyttää viestin selailuohjelman status-kentässä.
GetAppletContext
-metodi palauttaa tietoa appletin toimintaympäristöstä.
Applettien turvallisuus on eräs tärkeimmistä Java-kielen suunnittelun lähtökohdista. Jos tuntemattomalta WWW-sivulta ladattu appletti pystyisi aiheuttamaan minkäänlaista tuhoa, aplettien hyödyllisyys olisi vähintäänkin kyseenalaista. Ongelman välttämiseksi selaimet asettavat appleteille yleensä seuraavat rajoitukset:
Ylläolevat rajoitukset koskevat vain niitä appletteja, jotka luetaan ulkopuoliselta koneelta. Paikallisesta tiedostojärjestelmästä käynnistetyllä appletilla ei ole mitään rajoituksia.
Yläolevasta listasta voi päätellä että virusappletin tekeminen on varsin vaikeaa. Koska rajoitukset eivät koske paikallisia appletteja, troijan hevosen tai loogisen pommin tekeminen on mahdollista. Toisaalta, applet voi avata verkkoyhteyden systeemiin josta se ladattiin muistiin ja kirjoittaa tietoja kyseisen systeemin tiedostoihin. Client-server tyyppinen ohjelma, joka hämää käyttäjän paljastamaan tietoja itsestään ja tallettaa saadut tiedot emosysteemin tiedostoihin, on siten mahdollinen.
Appletien toimintarajoitukset toteutetaan nk. turvallisuusmanagerien
avulla. Turvallisuusmanageri on systeemikohtainen olio, joka havaitessaan
laittoman operaation pysäyttää sen ja lähettää
SecurityException
-poikkeutuksen. Yleensä Java-kieltä tukevat
HTML-selaimet käyttävät omaa turvallisuusmanageria, joten
appletien toiminnoille asetetut rajoitukset saattavat vaihdella eri selaimissa.
[GOS] James Gosling, Bill Joy ja Guy Steele, "The Java Language Specification", http://java.sun.com/doc/language_specification/, Sun Microsystems [CAM] Mary Campione ja Kathy Walrath, "The Java Tutorial", http://java.sun.com/doc/tutorial.html, Sun Microsystems [HAR] Elliotte Rusty Harold, "Comp.lang.java FAQ", http://sunsite.unc.edu/javafaq/javafaq.html [CON] Michael O'Connell, "Java: the Inside Story", http://www.sun.com/sunworldonline/swol-07-1995/swol-07-Java.htm l, Web Publishing Inc [MEY] Scott Meyers, "More Effective C++", Addison-Wesley Publishing Company [ITK] Jonne Itkonen, "Inferno ja JavaOS", ohjelmistotekniikan seminaari 1996 [NUR] Terhi Nurminen, "Virukset" , ohjelmistotekniikan seminaari 1996
Sun, Sun Microsystems, HotJava, and Java are trademarks or registered trademarks of Sun Microsystems, Inc.
Kiitokset Jukka-Pekka Santaselle, Jonne Itkoselle ja Kai Parviaiselle opastuksesta ja avunannosta.
Seuraava appletti laskee kahden kokonaisluvun suurimman yhteisen tekijän arvon.
SytApplet.Java:
import Java.awt.*; import Java.applet.*; /************************************************** * * SytCalc * * Kahden luvun suurimman yhteisen tekijän (syt) * laskemiseen tarkoitettu luokka. Syt:in laskeminen * tapahtuu Euklideen algoritmilla. */ class SytCalc { static long syt(long number1, long number2) { long r = number1 % number2; if (r==0) return number2; else return syt(number2,r); } } /*************************************************** * * SytApplet * * Käyttöliittymä syt:in laskemiselle. */ public class SytApplet extends Applet { Button laske; // Laske-painonappi Button reset; // Nollaa-painonappi Label tulos; // Tuloskenttä TextField luku1; // luvun syöttökenttä TextField luku2; // " " Panel buttonpanel; // paneli jolla ryhmitetään //painonapit ja syöttökentät final String T = new String("Suurin yhteinen tekijä on:"); public synchronized void init() { // Otetaan BorderLayout käyttöön setLayout(new BorderLayout()); // Luodaan oliot käyttöliittymän // komponenteille laske = new Button("Laske"); reset = new Button("Nollaa"); tulos = new Label(); tulos.setAlignment(Label.CENTER); luku1 = new TextField(9); luku2 = new TextField(9); buttonpanel = new Panel(); // Lisätään komponentit paneliin buttonpanel.add(luku1); buttonpanel.add(luku2); buttonpanel.add(laske); buttonpanel.add(reset); // Sijoitetaan ryhmittelypaneli alalaitaan // ja tuloskenttä keskelle add("South",buttonpanel); add("Center",tulos); } public boolean action(Event e, Object arg) { if(e.target == reset) { tulos.setText(""); luku1.setText(""); luku2.setText(""); } else { String S1 = luku1.getText(); String S2 = luku2.getText(); long Num1,Num2; // Seuraava lohko koettaa muuttaa merkkijonon // long:iksi. Jos merkkijono sisältää ei-numeerisia // merkkejä, napataan lähetetty poikkeutus, // ja annetaan käyttäjälle virheilmoitus try { Num1 = Long.valueOf(S1).longValue(); Num2 = Long.valueOf(S2).longValue(); } catch (NumberFormatException T) { tulos.setText("Ole hyvä ja syötä numeerinen arvo"); return true; } // Lasketaan suurin yhteinen tekijä // ja näytetään tulos tuloskentässä. long L = SytCalc.syt(Num1,Num2); tulos.setText(T+Long.toString(L)); } // palautetaan tosi, eli AWT saa käsitellä // viestin loppuun saakka return true; } }