Yksi perinnän tärkeimmistä ominaisuuksista on mahdollisuus monimuotoisuuteen, polymorfismiin. Esimerkiksi
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:
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:
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:
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:
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.