Ilkka Koivistoinen 13.02.2002

Edellinen

Seuraava

Yhteenveto

8.1 Luokan muodostaminen

Kurssin alkuosassa on jokainen ohjelma alkanut class -määrittelyllä. Siinä itse asiassa tehtiin uusi luokka, jolla oli haluttuja  ominaisuuksia. Koska haluttiin luoda yksinään toimiva ohjelma, lisättiin luokkaan main -metodi, josta java -tulkki tiesi aloittaa ohjelman toteutuksen. Nyt luomme luokkia, joita käyttävät muut luokat hyväkseen. Main -metodia ei siis tarvita. Main -metodi on ensimmäisissä esimerkeissä kirjoitettu kunkin luokan viimeiseksi metodiksi, josta ohjelman toteutus alkaa (vrt. "Pääohjelma").

Luokka muodostetaan kirjoittamalla

class omena  // luomme luokan omena
{
}

Olio-ohjelmoinnin lähtökohta on muodostaa malli ihmisen abstraktioista todellisessa elämästä. Jos meillä on siis mielleyhtymä omenasta, joka kasvaa omenapuussa tai joka tuodaan lentokoneella Ranskasta, jota syödään, jotka ovat punaisia, kypsiä, raakoja, makeita, kirpeitä, matoisia, rupisia, homeisia jne..., ei luokalla omena kannata ajatella olevan yhtään vähempää ominaisuuksia. Aluksi kannattaa keskittyä vain niistä oleellisimpiin. Ainahan voi periyttää omenaluokan aliluokaksi, jos jokin ominaisuus jäi puuttumaan. Ajattelun täytyy olla lähtöisin ihmisen omasta tavasta ajatella,  ei koneen bittihirviömäisestä liturgiasta. Ihmisen ajattelumallista lähtöisin oleva luokka käyttäytyy kuten - ihminen (toivottavasti. Silloin sen kanssa on paljon mukavampi tulla toimeen.)

8.1.1 Luokan muuttujat eli jäsenmuuttujat

Otamme käyttöön luokalle omena muuttujat vari (nyt yritän kirjoittaa oikeaa javakoodia, joten luovun skandeista. Mitä tulikaan kirjoitettua edellisessä kappaleessa ihmisen abstraktioista!), maku ja matoinen. Näitä sanomme luokan omena jäsenmuuttujiksi.

Luotaessa olio luokasta omena, jäsenmuuttujista vari, maku ja matoinen tulee oliomuuttujia. Niiden ominaisuuksiin pääsee käsiksi kirjoittamalla olio.muuttuja ja jokaisella luokan omena oliolla on omat oliomuuttujansa. Nyt voimme kirjoittaa ensimmäisen olio-ohjelmamme. Samalla luovutaan Javalle varattujen nimien mustaamisesta.

Esimerkki  31.  (esimerkki 31a. sama ohjelma ehkä aloittelijalle hieman selvemmin kirjoitettuna)

class omena  // luomme luokan omena
{
   String vari, maku;  //luokan jäsenmuuttujat
   boolean matoinen;

     public static void main(String args[])     //tässä main -metodi ohjelman testaamista varten
      {
        omena omppu1=new omena(); // luodaan luokasta omena olio omppu1
        omppu1.vari = "punainen"; //omppu1:llä on ominaisuus vari, maku ja matoinen
        omppu1.maku = "hapan";
        omppu1.matoinen = false;
// Tulostetaan omppu1:n ominaisuuksia
        System.out.println("Omenamme väri on "+omppu1.vari);
        System.out.println("Omenamme maku on "+omppu1.maku);
        if (omppu1.matoinen)
           System.out.println("Omenamme on kiusallisen matoinen");
        else
           System.out.println("Omenassamme ei ole matoja");
      }
}

8.1.1.1 Vakiot

Java ei tunne varsinaisia vakioita, mutta ne voidaan toteuttaa laittamalla jäsenmuuttujan eteen sana final. Tällöin ei jäsenmuuttujan arvoa voida enää muuttaa ja siitä tulee vakio.

Esimerkiksi final float pii = 3.14;

8.1.1.2 Luokkamuuttujat

Kirjoittamalla jäsenmuuttujan nimen eteen sana static, tapahtuu seuraavaa. Luotaessa luokasta uusi olio, ei tämä jäsenmuuttuja kopioidu uudelle oliolle vaan sen arvo on kaikilla luokasta luoduilla olioilla sama ja jos jokin oli muuttaa sitä, niin sen arvo muuttuu samalla kertaa kaikille samasta luokasta luodoille olioille. Tätä käytetään esimerkiksi ilmaisemaan luokasta luotujen olioiden määrää. Sen käytössä tulee olla hyvin varovainen, sillä sehän romuttaa koko olioajatelun perustan siitä, että kukin olio käyttäytyy itsenäisesti riippumatta muista olioista.  (Luokkamuuttujaa sanotaan javassa usein instanssimuuttujaksi)

Esimerkiksi

static int luokastaLuotujenOlioidenMaara;
static final int luokastaLuotujenOlioiden Maksimimaara = 10;

8.1.2 Luokan metodit

Tulostusta varten lisäämme luokkaan omena metodin tulostaAttribuutit(), joka tulostaa oliomuuttujien vari, maku ja matoinen arvot. (Luokan muuttujia sanotaan usein luokan attribuuteiksi. Tämän takia tulostusmetodia kutsutaan tällä kertaa tulostaAttribuutit() -metodiksi.)

void tulostaAttribuutit()
{
   System.out.println(" Väri: " + vari + "/n  Maku" +maku+ /n  Matoisuus " + matoinen);
}

Käyttämällä tätä hyväksemme voimme kirjoittaa esimerkin E32, jossa otetaan käyttöön kaksi luokan omena1 oliota syysOmena ja kaneliOmena. Asetettuamme näille olioille ominaisuuksia ja tulostamme niiden ominaisuudet eli attribuutit.

Esimerkki E32

class omena1 // luomme luokan omena1
{
  String vari, maku;  // tässä luokan jäsenmuuttujat
  boolean matoisuus;

  void tulostaAttribuutit()  //tässä luokan metodi tulostaAttribuutit
   {
    System.out.println(" Väri: " + vari + "\n Maku: " +maku+ "\n Matoisuus: " + matoisuus);
   }

  public static void main(String args[])
   //tässä main -metodi ohjelman testaamista varten
   {
    omena1 kaneliOmena = new omena1();  // tässä uusi olio, joka kuuluu luokkaan omena1
    omena1 syysOmena = new omena1();     // tässä samaan luokkaan kuuluva toinen olio
    kaneliOmena.vari = "punainen";   // asetellaan olioiden muuttujia
    kaneliOmena.maku = "makea";
    kaneliOmena.matoisuus = false;
    syysOmena.vari = "vihreä";
    syysOmena.maku = "hapan";
    syysOmena.matoisuus = true;
//Tulostus
    System.out.println("kaneliomena:");
    kaneliOmena.tulostaAttribuutit();
    System.out.println("syysOmena:");
    syysOmena.tulostaAttribuutit();
   }
}

Seuraavaksi toteamme, että suora viittaus olion oliomuuttujiin voidaan korvata metodilla, jolla asetetaan halutut arvot. Tälläisiä metodeja olisivat

void asetaVari(String vari1)
{
  vari=vari1;
}

void asetaMaku(String maku1)
{
   maku=maku1;
}

void asetaMatoisuus(Boolean matoisuus1)
{
   matoisuus=matoisuus1;
}

Sulkujen sisällä olevaa arvoa (esim vari1) sanotaan parametriksi. Parametrien tulee olla samaa tyyppiä metodikutsussa ja luokan metodissa. Seuraavassa esimerkki parametrien välityksestä metodille

Esimerkki 33

class omena
{
   String vari;
   ...
     void asetaVari(String vari1)
      {
        vari=vari1;
      }
  ...
     public static void main(..)
      { String syysVari="punainen";
         int omenoidenMaara = 20;
         omena omppu = new omena();
         ...
         omppu.asetaVari(syysVari); //Oikea parametrikutsu, koska parametrin tyypit tässä ja metodissa samoja
         omppu.asetaVari(omenoidenMaara); //Väärä parametrikutsu, koska parametrin tyypit tässä int ja metodissa String
         ...
       }
}

8.1.2.1 This muuttuja

Halutessa viitata luokan metodissa luokan omaan muuttujaan tai luokan toiseen metodiin, voidaan käyttää this muuttujaa. Tällöin muodostetaan osoite sen olion metodiin, jota oltiin parhaillaan käsittelemässä.  Esimerkiksi

this.maku = maku1;
this.vari = vari1;

8.1.2.2 Parametrien välitys

Parametrien välityksessä metodikutsusta metodille joudumme ensimmäisen kerran tutustumaan käsitteeseen osoite. Merkitään laatikoilla edellisen esimerkin 32 muuttujia syysVari ja omenoidenMaara seuraavasti

wpe11.jpg (14181 bytes)

Metodille välitetään siis osoite siihen muistipaikkaan, jossa syysVari:n arvo sijaitsee. Osoite on metodissa nimeltään vari1.

Metodikutsussa esiintyviä parametreja sanotaan todellisiksi parametreiksi ja metodissa olevia parametreja muodollisiksi parametreiksi.

omppu.asetaVari(syysVari); metodikutsun todellinen parametri syysVari
void asetaVari(String vari1) metodin muodollinen parametri vari1

Kutsuttaessa jonkin olion metodia, pinotaan metodikutsu ja siinä olevat todelliset parametrit metodian paluuarvon kanssa pinoksi. Pinon alimpana on kutsuttavan metodin osoite ja palautusarvo, seuraavana ensimmäinen todellinen parametri, toinen todellinen parametri jne.. . Metodi saa tämän pinon huipun osoitteen ja ottaa ylimmäin parametrin osoitteen ja antaa sen viimeisen muodollisen parametrin osoitteeksi. Tämä toistetaan muodollinen parametri kerrallaan, kunnes pinon pohjalla on enää metodin paluuarvo. Kun metoidin suoritus päättyy, siirtyy toiminta metodia kutsuneeseen lauseeseen siten, että metodin palautusarvo jää metodikutsupinon pohjalle. Kutsuva ohjelma voi käyttää tätä arvoa halutessaan. Metodikutsupinon muistipaikat vapautuvat lopuksi muuhun käyttöön. Oheinen kuva selventäkööt tilannetta.

// Kutsuvassa ohjelmassa kirjoitetaan
String p1;
int p2;
float p3;
boolean p4;
olio.metodi(p1,p2,p3,p4);
...

// luokassa, jossa metodi sijaitsee, kirjoitetaan
palautusarvo metodi(String m1, int m2, float m3, boolean m4);

wpe14.jpg (14181
bytes)

Havaitaan, että pinon parametrien osoitus ei onnistu, jos todellisten parametrien tyypit eivät täsmää muodollisten parametrien kanssa.

Esimerkissä 33 on kokonaisuudessaan ohjelma, jossa asetetaan metodin avulla omenan vari.

Esimerkki 34

class omena3
{
   String vari;
     void asetaVari(String vari1)
      {
         vari=vari1;
      }
     public static void main(String args[])
      { String syysVari="punainen";
         omena3 omppu = new omena3();
         omppu.asetaVari(syysVari);
         System.out.println("ompun väri on nyt "+omppu.vari);
         omppu.asetaVari("Vihreä"); // Näinkin onnistuu
         System.out.println("ompun väri on nyt "+omppu.vari);
       }
}

Nyt olemmekin valmiit kirjoittamaan uudestaan esimerkin 32 (käyttämällä myös this -muuttujaa)

Esimerkki 35

class omena3 {
  String vari, maku; //luokan muuttujat
  boolean matoisuus;
  void asetaVari(String vari1)
   {
    this.vari=vari1;
   }
  void asetaMaku(String maku1)
   {
    this.maku=maku1;
   }
  void asetaMatoisuus(boolean matoisuus1)
   {
    this.matoisuus=matoisuus1;
   }
  void tulostaAttribuutit()
   {
    System.out.println(" Vari: " + this.vari + "\n Maku " +this.maku+ "\n Matoisuus " + this.matoisuus);
   }
//
  public static void main(String args[]) //tassa main -metodi ohjelman testaamista varten
   {
    omena3 kaneliOmena = new omena3();
    omena3 syysOmena = new omena3();
    kaneliOmena.asetaVari("punainen"); //kaneliOmena:lla on ominaisuudet vari, maku ja matoisuus
    kaneliOmena.asetaMaku ("hapan");
    kaneliOmena.asetaMatoisuus(false);
    syysOmena.asetaVari("Keltainen"); //syysOmena:lla on ominaisuudet vari, maku ja matoisuus
    syysOmena.asetaMaku ("makea");
    syysOmena.asetaMatoisuus(true);
// Tulostetaan omppu1:n ominaisuuksia
    System.out.println("kaneliOmena   ");
    kaneliOmena.tulostaAttribuutit();
    System.out.println("syysOmena");
    syysOmena.tulostaAttribuutit();
   }
  }

8.1.2.3 Metodin palautusarvo

Metodi voi paitsi tehdä jotain luokan jäsenmuuttujille, myös palauttaa jonkin objektin ominaisuuden kutsuvalle ohjelmalle. Meillä on ollut tälläisiä käytössä jo aikaisemmin. Esimerkiksi String luokan length() -metodi palautti merkkien määrän merkkijonossa.

Palautusarvon tyyppi ilmoitetaan metodia kirjoitettaessa esittelylauseessa. Esimerkiksi

public String kerroVari() {}

ilmoittaa, että metodi palauttaa kutsuvalle ohjelmalle String -tyyppisen arvon.

Kokonaisuudessaan esimerkki olisi seuraavanlainen. Palautettavan muuttujan arvo asetetaan return -lauseella seuraavasti.

Esimerkki

   //Esimerkkiin 35 voidaan kirjoittaa metodi kerroVari(), joka palauttaa kutsuvaan ohjelmaan olion muuttujan vari arvon
   String kerroVari() //String kertoo palautusarvon tyypin
     {
       return this.vari;   // voi olla myös return (vari);
      }

// Tätä käytetään kutsuvassa ohjelmassa seuraavasti

String apu = syysOmena.kerroVari(); // tai
System.out.println(syysOmena.kerroVari());

Kirjoittamalla metodiin

return this

palautetaan koko objektin osoite kutsuvalle ohjelmalle.

8.1.2.4 Metodin lokaali muuttuja

Mikäli muuttuja määritellään metodin sisällä, siitä tulee lokaali muuttuja, joka näkyy vain metodille itselleen. Siihen ei siis voi viitata muualla kuin metodin aikana.

Esimerkki

void tulostaAttribuutit()
{
  int i;  \\ tässä i on lokaali muuttuja eikä siihen voi viitata missään muussa kohdassa ohjelmaa
  for (i=1; i<10;i++)
     System.out.println("Miksi taas tulostetaan attribuutteja! OMENATHAN MÄTÄNEVÄT KÄSIIN");
  System.out.println(" Vari: " + this.vari + "\n Maku " +this.maku+ "\n Matoisuus " + this.matoisuus);
}

Yhteenveto

luokka olion mallikappale, joka kopioidaan jäsenmuuttujineen ja metodeineen olioksi luotaessa uusi olio. Ei voi käyttää sellaisenaan tiedon talletukseen
olio luokasta otettu kopio, jota voi käyttää ohjelmassa tiedon talletukseen.
jäsenmuuttuja Tiettyyn luokkaan kuuluva muuttuja, jota ei voida sinällään käyttää tiedon tallettamiseen
vakio jäsenmuuttuja jonka edessä oleva muunnin on final
luokkamuuttuja jäsenmuuttuja, jonka edessä oleva muunnin on static (usein kutsutaan instanssimuuttujaksi)
oliomuuttuja luokasta luodun olion jäsenmuuttujia sanotaan oliomuuttujiksi, joita voi käyttää tiedon
talletukseen (paitsi vakioita)
metodi luokkaan kuuluva menetelmä, jolla voidaan operoida luokan jäsenmuuttujia
palautusarvo metodikutsun palautusarvo. void tarkoittaa "ei palautusarvoa"
lokaali muuttuja metodin sisäinen muuttuja, joka ei näy metodin ulkopuolelle
this -muuttuja Sallii olion viitata metodissaan saman olion toiseen metodiin tai muuttujaan

Tehtäviä

  1. Tee luokka kala, jossa on ominaisuudet float paino, int pituus,   String lajiLuokka ja boolean kelpaakoSoppaKalaksi. Tee main() -metodi, jossa luot luokan kala olion hauki ja annat oliomuuttujille sopivat arvot. Vastaus.
  2. Tee edelliseen tehtävään tulostusmetodi tulostaKalanTiedot() ja käytä sitä main() -metodissa. Vastaus.
  3. Tee edelliseen tehtävään metodi asetaPaino(), asetaPituus() jne. Tee kala -luokan oliot särki, lohi ja kirjolohi. Aseta edellisen tehtävän metodeilla oliomuuttujille arvot ja tulosta ne tarpeen mukaan. Voit kysellä arvoja myös näppäimistöltä Lue -luokan metodeilla. Vastaus.

Ilkka Koivistoinen 13.02.2002

Edellinen

Seuraava