Ylös Edellinen Seuraava Otsikkosivu Hakemisto Sisällys

9.5 Rajapinta ja monimuotoisuus

Yksi perinnän tärkeimmistä ominaisuuksista on mahdollisuus monimuotoisuuteen, polymorfismiin. Esimerkiksi

olioalk\AikaSekB.java - esimerkki polymorfisesta taulukosta

	    AikaB ajat[] = new AikaB[5];
	    ajat[0] = a1; ajat[1] = a2; ajat[2] = a3; ajat[3] = a4;
	    ajat[4] = new AikaSekB(23,59,59);
	
	    for (int i=0; i < ajat.length; i++ ) {
	      ajat[i].tulosta(false); System.out.print(" +" + i + " => ");
	      ajat[i].lisaa(i); ajat[i].tulosta();
	    }

Taulukko ajat koostuu viitteistä AikaB-luokan olioihin. Myös AikaSekB toteuttaa saman rajapinnan, koska se on perittyä samasta luokasta. Siksi taulukkoon voi laittaa mitä tahansa AikaB-luokan jälkeläisluokankin olioita.

Esimerkissä AikaSek7 luokka koostettiin sekunneista ja luokan Aika5 oliosta. Nyt valitettavasti vain polymorfismi ei toimi, eli AikaSek7 ja Aika5 eivät ole perimissuhteessa toisiinsa. Niillä on kyllä Javassa yhteinen kantaluokka Object, koska Javassa kaikki luokat periytyvät Object-luokasta. Mutta yhteistä aikaan liittyvää rajapintaa niillä ei ole. Kömpelö polymorfismi saataisiin aikaan seuraavasti:

olioalk\AikaSek7.java - kömpelö esimerkki polymorfisesta taulukosta

	    Object ajat[] = new Object[5];
	    ajat[0] = a1; ajat[1] = a2; ajat[2] = a3; ajat[3] = a4;
	    ajat[4] = new AikaSekE(23,59,59);
	
	    for (int i=0; i < ajat.length; i++ ) {
	      if ( ajat[i] instanceof Aika5 ) {
	        Aika5 aika = (Aika5)ajat[i];  // pakotettu tyypin muunnos
	        aika.tulosta(false); System.out.print(" +" + i + " => ");
	        aika.lisaa(i); aika.tulosta();
	      }
	      if ( ajat[i] instanceof AikaSek7 ) {
	        AikaSek7 aika = (AikaSek7)ajat[i];  // pakotettu tyypin muunnos
	        aika.tulosta(false); System.out.print(" +" + i + " => ");
	        aika.lisaa(i); aika.tulosta();
	      }
	    }

Tavassa jossa joudutaan testaamaan olion tyyppiä, tulee uusien tyyppien lisääminen järjestelmään erittäin työlääksi.

Javassa avuksi tulee rajapintakäsite. Teemme ensin "mallin" siitä, minkälainen on vähintään kaikkien Aika-luokkien rajapinta:

olioalk\AikaRajapinta.java - malli kaikkien Aika-luokkien rajapinnasta

	public interface AikaRajapinta {
	  void aseta(int h,int m);
	  void tulosta(boolean lf);
	  public void tulosta();
	  void lisaa(int lisa_min);
	  int getH();
	  int getM();
	}

Seuraavaksi kaikki luokat, jotka halutaan kuuluvan "samaan kategoriaan", ilmoitetaan toteuttavan tämän rajapinnan:

olioalk\AikaE.java - luokka joka toteuttaa rajapinnan

	
	public class AikaE implements AikaRajapinta {
	
	  private int h, m;
	  public void aseta(int h,int m) { this.h = h; this.m = m; lisaa(0);  }
	
	  public AikaE()            { this.h = 0; this.m = 0; }
	  public AikaE(int h)       { aseta(h,0);             }
	  public AikaE(int h,int m) { aseta(h,m);             }
	
	  public void tulosta(boolean lf) {
	    System.out.print("" + h + ":" + (m<10?"0":"")+m);
	    if ( lf ) System.out.println();
	  }
	
	  public void tulosta() { tulosta(true); }
	
	  public void lisaa(int lisa_min)  {
	    int yht_min = h * 60 + m + lisa_min;
	    h = yht_min / 60;
	    m = yht_min % 60;
	  }
	
	  public int getH() { return h; }
	  public int getM() { return m; }
	
	}
	

Sitten esim. koosteluokka ilmoitetaan toteuttamaan myös sama rajapinta:

olioalk\AikaE.java - luokka joka toteuttaa rajapinnan => polymorfismi

	public class AikaSekE implements AikaRajapinta {
	
	  private AikaE hm = new AikaE();
	  private int s;
	
	  public void aseta(int h,int m,int s) { hm.aseta(h,m); this.s = s; lisaa(0,0); }
	
	  public void aseta(int h,int m)       { aseta(h,m,0); }
	  public void aseta(int h)             { aseta(h,0);   }
	
	  public AikaSekE()                    { aseta(0,0,0}; }
	  public AikaSekE(int h,int m, int s)  { aseta(h,m,s); }
	  public AikaSekE(int h,int m)         { aseta(h,m,0); }
	  public AikaSekE(int h)               { aseta(h,0,0); }
	
	  public void tulosta(boolean lf) {
	    hm.tulosta(false);
	    System.out.print(":" + (s<10?"0":"")+s);
	    if ( lf ) System.out.println();
	  }
	
	  public void tulosta() { tulosta(true); }
	
	  public void lisaa(int lisa_min,int lisa_sek)  {
	    s += lisa_sek;
	    hm.lisaa(lisa_min+s/60);
	    s %= 60;
	  }
	
	  public void lisaa(int lisa_min)  { lisaa(lisa_min,0); }
	
	  public int getH() { return hm.getH(); }
	  public int getM() { return hm.getM(); }
	
	  public static void main(String[] args) {
	    AikaE a1 = new AikaE();
	    AikaE a2 = new AikaE(13);
	    AikaE a3 = new AikaE(14,175);
	
	    a1.tulosta();  a2.tulosta();  a3.tulosta();
	    a1.aseta(12,15); a2.aseta(16,-15);
	    a1.tulosta(); a2.tulosta();
	
	    AikaSekE a4 = new AikaSekE(14,55,45); a4.tulosta();
	    a4.lisaa(3,30); a4.tulosta();
	
	    // Rajapintaan perustuva esimerkki polymorfisesta taulukosta
	    AikaRajapinta ajat[] = new AikaRajapinta[5];
	    ajat[0] = a1; ajat[1] = a2; ajat[2] = a3; ajat[3] = a4;
	    ajat[4] = new AikaSekE(23,59,59);
	
	    for (int i=0; i < ajat.length; i++ ) {
	      ajat[i].tulosta(false); System.out.print(" +" + i + " => ");
	      ajat[i].lisaa(i); ajat[i].tulosta();
	    }
	
	  }
	
	}

Näin voimme jälleen tehdä taulukon, johon voimme laittaa kaikkia AikaRajapinta-määrittelyn toteuttavien luokkien olioita.


Ylös Edellinen Seuraava Otsikkosivu Hakemisto Sisällys