ALOITTELIJAN JAVA-OPAS


6. Olio-ohjelmointi

Java on olio-ohjelmointikieli. Olio-ohjelmointi eroaa perinteisestä lausekielisestä ohjelmoinnista siten, että pelkän peräkkäisten toimintaohjeiden luettelemisen sijaan ohjelmalla pyritään mallintamaan reaalimaailman olioita tai joitakin abstrakteja olioita. Ero lausekieliseen ohjelmointiin on lähinnä ajattelutavassa.

6.1. Johdatus oliomaiseen ajatteluun

Esimerkkinä voisimme tehdä oliomallin vaikkapa reaalimaailman virvoitusjuoma-automaatista. Mallinnettavasta kokonaisuudesta pyritään erottamaan jokseenkin itsenäisiä osia, joita tässä tapauksessa kutsutaan olioiksi. Oliossa pitää säilyä ohjelman kannalta kaikki oleellinen tieto, ja siksi olioille on määritettävä tarvittava määrä ominaisuuksia ja toimintoja. Yksi mahdollinen virvoitusjuoma-automaatti koostuu alla luetelluista olioista:

  • Rahanvastaanottolaitteisto (huolehtii rahan vastaanotosta ja yhteistyöstä rahansäilytyslaitteiston kanssa)
  • Rahanpalautuslaitteisto (palauttaa ylimääräiset vaihtorahat, jos rahaa annettiin liikaa)
  • Merkkivalot (ilmoittaa, millaisia juomia on tarjolla)
  • Valintapainikkeet (aktiivinen painike mahdollistaa juomien valinnan; valintapainike aktivoituu kun rahaa on syötetty juoman ostamiseen vaadittava määrä)
  • Juomien jakaja (antaa juoman asiakkaalle)
  • Rahansäilytyslaitteisto (huolehtii syötettyjen rahojen laskennasta ja tallennuksesta)
  • Juomien säilytystila (säilyttää juomat ja tarjoaa niitä juomien jakajalle)

    Jokainen näistä olioista pitää kirjaa omasta tilastaan. Esimerkiksi rahansäilytyslaitteiston on tiedettävä, kuinka paljon rahaa asiakas on tähän mennessä syöttänyt. Niinpä sille on määritettävä ainakin seuraava ominaisuus:

  • syötetty_rahamäärä

    Olion toiminnallisia osia kutsutaan metodeiksi. Metodit vastaavat perinteisten ohjelmointikielten aliohjelmia, mutta ne on kiinnitetty johonkin tiettyyn olioon. Esimerkiksi syötetyn rahasumman laskevaa laske_rahat-metodia käytetään ainoastaan rahansäilytyslaitteisto-olion kanssa. Kyseiselle oliolle voidaan määritellä seuraavat toiminnot eli metodit:

  • laske_rahat (laskee syötetyn rahasumman)
  • laske_vaihtorahat (laskee vaihtorahojen lukumäärän)
  • palauta_vaihtorahat (palauttaa vaihtorahat)
  • tulosta_rahasumma (tulostaa syötetyn rahasumman)

    Olioiden on jollain tavalla toimittava yhteistyössä toisten olioiden kanssa. Tämä tapahtuu siten, että oliot välittävät keskenään tietoa eli lähettävät viestejä metodien sekä mahdollisesti niille välitettävien parametrien avulla. Esimerkiksi kun rahansäilytyslaitteisto-olio saa rahanvastaanottolaitteisto-oliolta tiedon syötetystä rahasta, se puolestaan päivittää tietojäsenensä arvon ja tultuaan kylläiseksi lähettää merkkivalot- ja valintapainikkeet-olioille aktivoitumiskäskyn, jne.

    6.2. Oliot, luokat, tietojäsenet ja metodit

    Olio-ohjelmoinnin peruskäsite olio (object) sisältää sekä tiedon että tietoon kohdistuvat toiminnot eli metodit (methods). Olio kapseloi (encapsulate) tiedon, jotta siihen pääsee suoraan käsiksi ainoastaan metodien avulla.

    Metodi (toiminto) on yleisnimitys koodille, joka käsittelee olion sisältämää tietoa. Olio voi suorittaa ainoastaan sille määritellyt toiminnot. Metodille pitää aina määritellä nimi ja ohjelmoida toiminta. Metodeille voidaan määritellä myös parametreja, joissa olion metodille välitetään tietoa olion ulkopuolelta.

    Olion sisältämä tieto tallennetaan olion ominaisuuksiin (attribute), jotka ovat nimettyjä ja tavallisesti ulkopuolisilta olioilta suojattuja tietokenttiä. Näitä kutsutaan myös olion tietojäseniksi. Olion ominaisuuksia käsitellään yleensä metodien avulla. Olion tila muodostuu kaikkien olion ominaisuuksien yhdistelmästä.

    Ennen olion määrittelyä pitää luoda luokka (kuten Henkilö), josta voidaan luoda yksittäisiä olioita (esim. antti, juuso tai ville). Yhdestä luokasta voi luoda niin monta oliota kuin haluaa. Kun olio luodaan, sen tiedot tallentuvat tietokoneen muistiin; kun olio tuhotaan, se käytännössä tuhotaan tietokoneen muistista.

    Luokka (class) on siis ryhmä samankaltaisia olioita. Luokat määrittelevät miltä oliot näyttävät määrittelemällä mitä tietoa ja toimintoja kaikki luokan oliot sisältävät. Oliot ovat luokan ilmentymiä (instances), jotka toteuttavat luokan käytännössä.

    Olion ja luokan välistä suhdetta kuvaavat seuraavat määritelmät:

  • Olio on luokan ilmentymä (käytännössä toteutus).
  • Olion ominaisuus on luokan ominaisuuden ilmentymä.
  • Olio käyttää ominaisuuksiaan luokan tarjoamilla metodeilla.

    Luokat määritellään Java-kielessä seuraavasti:

    	class Luokan_nimi
    	{
    	   // Luokan toteutus:
    	   // a) Tietojäsenet eli ominaisuudet.
    	   // b) Metodit eli toiminnot.
    	}
    

    Luokan ominaisuudet (tietojäsenet) on tapana esitellä keskitetysti heti luokan alussa. Esimerkiksi Opiskelija-luokka voi sisältää seuraavaa tietoa opiskelijasta:

    	class Opiskelija
    	{
    	   // Alussa kootusti luokan tietojäsenet.
    	   String nimi;
    	   int id;
    
    	   // Luokan metodit alkavat tästä eteenpäin.
    	}
    

    Perussyntaksi luokan metodien toteutuksessa on seuraava:

    	palautustyyppi metodin_nimi (parametrit)
    	{
    	   // Metodin toteutus.
    	   // Lopuksi: return (palautustyyppinen_muuttuja);
    	}
    

    6.3. Luokkahierarkiat

    Olio-ohjelmoinnissa, aivan kuten reaalimaailmassakin, esiintyy luokkien välisiä hierarkkisia rakenteita. Oletetaan vaikka, että meillä on opiskelija nimeltään Olavi, joka on Opiskelija-luokkaan kuuluva olio. Toisaalta kaikki opiskelijat ovat ihmisiä. Biologisesti ihminen on nisäkäs, ja nisäkkäät vastaavasti kuuluvat eläinten luokkaan. Luonnon hierarkioita seuraamalla oppii ajattelun hierarkkisesta rakenteesta, jossa aliluokka perii kaikki yliluokkansa ominaisuudet.

    Olio-ohjelmoinnin tärkein tuntomerkki on perintä (inheritance). Perimällä jokin luokka saadaan luokan yliluokkaan (superclass) liitetyt ominaisuudet ja toiminnot käyttöön ilman erillistä määrittelyä. Vastaavasti perittyä luokkaa kutsutaan perittävän luokan aliluokaksi (subclass). Perinnän keskeisimmät tavoitteet ovat koodin käyttö muissa ohjelmistoissa sekä käsitteiden mallintaminen.

    Javassa kaikki luokat ovat automaattisesti Object-luokan aliluokkia, eikä ohjelmoijan tarvitse erikseen määritellä luokkaa tehdessään että se periytyy tästä perusluokasta. Muutoin periminen määritellään extends-avainsanalla.

    	class Opiskelija extends Ihminen
    	{
    	   // Luokan toteutus
    	}
    

    Näin määriteltynä Opiskelija-luokka siis perii Ihminen-luokan ominaisuudet ja metodit.

    6.4. Konstruktorit

    Konstruktoria (constructor) tarvitaan luokan alustamiseen sitä luotaessa. Konstruktori eli alustaja ei ole metodi, eikä palauta mitään arvoa sitä kutsuttaessa. Konstruktorilla on oltava sama nimi kuin luokalla, jonka alustamiseen sitä käytetään. Konstruktorille voidaan antaa nolla tai useampia parametreja kutsuttaessa, jolloin luokan tietojäsenet voidaan alustaa järkevään alkutilaan (esimerkiksi taulukot kannattaa alustaa halutun kokoisiksi.)

    	class Opiskelija
    	{
    	   // Alussa kootusti luokan tietojäsenet.
    	   String nimi;
    	   int id;
    
    	   // Konstruktori luokalle Opiskelija
    	   Opiskelija() {
    	     nimi = ""; // tyhjä merkkijono
    	     id   = 0;	// alustetaan nollaksi
    	   }
    
    	   // Luokan metodit alkavat tästä eteenpäin.
    	}
    

    Konstruktoreita voi kuitenkin olla useampia; tällöin luokasta voidaan luoda uusia ilmentymiä eri tavoin alustettuina. Mikäli käytetään useampia konstruktoreita, on niiden erottava toisistaan parametrien määrän ja tyypin suhteen. Useampien konstruktorien käyttöä kutsutaan ylikuormittamiseksi (overloading).

    Ylikuormittamalla konstruktoreista (tai metodeista) saadaan aikaan monipuolisempia; niitä voidaan kutsua erilaisilla parametreilla tilanteen mukaan.

    	class Opiskelija
    	{
    	   // Alussa kootusti luokan tietojäsenet.
    	   String nimi;
    	   int id;
    
    	   // Konstruktori luokalle Opiskelija
    	   Opiskelija() {
    	     nimi = ""; // tyhjä merkkijono
    	     id   = 0;	// alustetaan nollaksi
    	   }
    
    	   // Konstruktori yhden parametrin kanssa
    	   Opiskelija(String n) {
    	     nimi = n;	// nimi saa arvokseen merkkijonon n sisällön
    	     id   = 0;	// alustetaan nollaksi
    	   }
    
    	   // Konstruktori parametrien kanssa
    	   Opiskelija(String n, int i) {
    	     nimi = n;	// nimi saa arvokseen merkkijonon n sisällön
    	     id   = i;	// id saa arvokseen kokonaisluvun i
    	   }
    
    	   // Luokan metodit alkavat tästä eteenpäin.
    	}
    

    Java-kieli tekee automaattisesti oletuskonstruktorin, mikäli luokkaan ei ole kirjoitettu yhtään muuta konstruktoria. Oletuskonstruktori ei alusta luokan tietojäseniä mihinkään erityiseen arvoon, vaan toimii ainoastaan apuvälineenä uusien ilmentymien luomisessa.

    Luotaessa luokasta uusia ilmentymiä konstruktorien avulla, on käytettävä avainsanaa new. New -sanalla luodaan luokasta uusi olio:

           class Ainejärjesto
           {
    	   // Ainejärjestön puheenjohtajan tyyppi on Opiskelija
    	   Opiskelija ainejarjeston_PJ = new Opiskelija();
    	   String     ainejarjeston_nimi;
    	   int	      ainejarjesto_ID;
    
    	   // Luokan konstruktorit, aksessorit ja muut metodit
           }
    

    Mikäli ainejärjestön puheenjohtajan nimi on tiedossa alustettaessa luokan Ainejarjesto tietojäseniä, voidaan konstruktoria kutsua myös nimi -parametrin kanssa:

           class Ainejärjesto
           {
    	   // Ainejärjestön puheenjohtajan tyyppi on Opiskelija
    	   Opiskelija ainejarjeston_PJ = new Opiskelija("Matti Mainio");
    	   String     ainejarjeston_nimi;
    	   int	      ainejarjesto_ID;
    
    	   // Luokan konstruktorit, aksessorit ja muut metodit
           }
    

    6.5. Aksessorit

    Luokan sisältämiin tietojäseniin tulisi päästä käsiksi myös luokan ulkopuolelta, mutta niiden suora muuttaminen vaikuttaisi myös tulevaisuudessa luokasta tehtäviin ilmentymiin; tämän takia tarvitaan aksessorimetodeja (accessor methods) .

    Aksessorimetodien avulla luokan sisältämiä attribuutteja voidaan muuttaa siten, että ainoastaan luokasta tehdyn yksittäisen ilmentymän arvot muuttuvat. Aksessorimetodit, jotka palauttavat tietyn tietojäsenen arvon muuttamatta sitä nimetään yleisesti get_Tietojäsenen_nimi. Aksessorimetodit, jotka muuttavat tietyn tietojäsenen arvoa nimetään yleisesti set_Tietojäsenen_nimi.

    	class Opiskelija
    	{
    	   // Alussa kootusti luokan tietojäsenet.
    	   String nimi;
    	   int id;
    
    	   // Konstruktori luokalle Opiskelija
    	   Opiskelija() {
    	     nimi = ""; // tyhjä merkkijono
    	     id   = 0;	// alustetaan nollaksi
    	   }
    
    	   // Aksessorimetodi, joka palauttaa merkkijonon nimi arvon
    	   String getNimi() {
    	     return nimi;
    	   }
    
    	   // Aksessorimetodi, joka muuttaa merkkijonon nimi arvon
    	   // parametrin n sisällön mukaiseksi, mutta ei palauta mitään arvoa (void)
    	   void setNimi(String n) {
    	     nimi = n;
    	   }
    	}
    

    Jos haluaisimme lisätä Ainejarjesto -luokkaan puheenjohtajan tietojäsentä nimi muuttavan aksessorimetodin, meidän tarvitsisi ainoastaan lisätä luokan toteutukseen seuraavanlainen metodi:

    	   // Aksessorimetodi, joka muuttaa merkkijonon nimi arvon
    	   // parametrin uusi_nimi sisällön mukaiseksi
    	   void vaihdaPJ_nimi(String uusi_nimi) {
    	     ainejarjeston_PJ.setNimi(uusi_nimi);
    	   }
    

    Nyt voimme tarkastella Ainejarjesto -luokan avulla aiemmin esitellyn Opiskelija- luokan aksessorimetodien käyttöä. Metodin vaihdaPJ_nimi sisällä kutsutaan luokan Opiskelija metodia setNimi liittämällä kutsu varsinaiseen tietojäseneen käyttämällä pisteoperaattoria tietojäsenen ja kutsuttavan metodin välissä:

           class Ainejärjesto
           {
    	   Opiskelija ainejarjeston_PJ = new Opiskelija("Matti Mainio");
    	   String     ainejarjeston_nimi;
    	   int	      ainejarjesto_ID;
    
    	   // Luokan konstruktori(t)
    	   // ...
    
    	   // esimerkkimetodi, jolla olion ainejarjeston_PJ tietojäsen nimi
    	   // muutetaan merkkijonon uusi_nimi sisällön mukaiseksi
    	   void vaihdaPJ_nimi(String uusi_nimi) {
    	     ainejarjeston_PJ.setNimi(uusi_nimi);
    	   }
           }
    

    6.6. Näkyvyys

    Java-kielessä kaikki luokan sisällä olevat tietojäsenet ja metodit ovat luokan itsensä käytettävissä; muiden luokkien pääsyä näihin tulee pystyä kontrolloimaan. Näkyvyyttä (visibility) voidaan säädellä asettamalla tietojäsenten ja metodien eteen näkyvyyden ilmaiseva määrite (control access modifier).

    Näkyvyyden ilmaisevia määritteitä ovat (heikoimmasta vahvimpaan):

  • public : ominaisuudet ovat saatavilla mistä tahansa muusta luokasta. Ominaisuudet periytyvät aliluokille.
  • protected : Ominaisuudet ovat saatavilla samaan package -luokkaan kuuluvista luokista ja myös muihin package -luokkiin kuuluvista aliluokista.
  • package : oletusnäkyvyys, mikäli muuta ei ole ilmaistu. Ominaisuudet ovat saatavilla ainoastaan samaan
    package-luokkaan kuuluvista luokista.
  • private : ominaisuudet ovat saatavilla ainoastaan luokalle itselleen.

    On suositeltavaa asettaa luokan tietojäsenet yksityisiksi, jolloin niiden tahaton muokkaaminen muista luokista estyy; tietojäsenten muuttamiseen tulee käyttää aksessorimetodeja.

    	public class Opiskelija
    	{
    	   // luokan tietojäsenet, näkyvyys vain luokan itsensä sisällä
    	   private String nimi;
    	   private int id;
    
    	   // julkinen konstruktori luokalle Opiskelija
    	   public Opiskelija() {
    	     nimi = ""; // tyhjä merkkijono
    	     id   = 0;	// alustetaan nollaksi
    	   }
    
    	   // Julkinen aksessorimetodi, joka muuttaa tietojäsenen id
    	   // arvon parametrin uusi_id sisällön mukaiseksi
    	   public void setId(int uusi_id) {
    	     id = uusi_id;
    	   }
    	}
    

    Näkyvyyden säätelyllä voidaan estää vääräntyyppisen tiedon tallentaminen tietojäsenen arvoksi. Olio-ohjelmoinnin periaatteiden mukaisesti luokan käyttäjälle pitää tarjota vain ja ainoastaan se toiminnallisuus, joka riittää luokan metodien käyttämiseen; muu toiminnallisuus tulee pitää käyttäjän ulottumattomissa.


  • Tietojärjestelmien dokumentointi 2005 | Aloittelijan JAVA-opas


    Valid CSS!