Perintä tarkoittaa, että luokan toteutuksen lähtökohtana on toisen luokan toteutus.
Luokan määrittelyssä perintä ilmoitetaan sanan extends
avulla. Lähtökohtana olevaa luokkaa sanotaan yliluokaksi, ja uutta
luokkaa sanotaan aliluokaksi.
Luokka Henkilo
on määritelty seuraavasti:
public class Henkilo { private String nimi; public Henkilo(String nimi) { this.nimi = nimi; } public void esittaydy() { System.out.println("Minun nimeni on " + nimi + "."); } public String toString() { return nimi; } }
Seuraava luokka Opiskelija
perii luokan
Henkilo
:
public class Opiskelija extends Henkilo { private int opintopisteet; public Opiskelija(String nimi) { super(nimi); this.opintopisteet = 0; } public void esittaydy() { super.esittaydy(); System.out.println("Olen saanut kokoon " + opintopisteet + " op."); } public void opiskele() { opintopisteet++; } }
Luokkia voidaan käyttää seuraavasti pääohjelmassa:
public class Main { public static void main(String[] args) { Henkilo aapeli = new Henkilo("Aapeli"); System.out.println(aapeli); aapeli.esittaydy(); Opiskelija maija = new Opiskelija("Maija"); maija.opiskele(); maija.opiskele(); System.out.println(maija); maija.esittaydy(); } }
Ohjelman tulostus on seuraava:
Aapeli Minun nimeni on Aapeli. Maija Minun nimeni on Maija. Olen saanut kokoon 2 op.
Tässä siis luokka Henkilo
on yliluokka ja luokka
Opiskelija
on aliluokka. Seuraavaksi katsomme tarkemmin, mitä
perinnässä tapahtuu.
Perintä tuo aliluokan osaksi yliluokan julkiset (public
)
muuttujat ja metodit. Konstruktorit eivät kuitenkaan periydy, vaan ne täytyy
määritellä aina erikseen. Lisäksi perittyjä metodeja on mahdollista
korvata uusilla toteutuksilla.
Yllä olevassa esimerkissä luokassa Opiskelija
on luokasta
Henkilo
peritty metodi toString
. Sen sijaan metodi
esittaydy
on korvattu omalla toteutuksella. Lisäksi luokassa on
uusina asioina muuttuja opintopisteet
ja metodi
opiskele
.
Sanalla super
voi viitata yliluokan muuttujiin ja
metodeihin.
Yllä olevassa esimerkissä luokan Opiskelija
konstruktori
suorittaa ensin yliluokan konstruktorin. Lisäksi metodi esittaydy
suorittaa ensin yliluokan metodin esittaydy
.
Toisinaan yliluokasta olisi hyödyllistä periä asioita, joita ei kuitenkaan
haluaisi päästää julkisiksi. Tämän mahdollistaa sana protected
,
jota käytetään sanan private
tai public
tilalla.
Tällaista muuttujaa tai metodia sanotaan suojatuksi.
Esimerkiksi luokan Henkilo
muuttuja nimi
voisi
olla suojattu:
public class Henkilo { protected String nimi; // luokan muu sisältö }
Nyt luokassa Opiskelija
voisi tehdä näin:
public class Opiskelija { // luokan muu sisältö public void esittaydy() { System.out.print("Minun nimeni on " + nimi + " ja olen "); System.out.println("saanut kokoon " + opintopisteet + " op."); } }
Luokka voi periä toisen luokan, joka taas on perinyt toisen luokan jne. Perintää voi siis tapahtua monella tasolla. Rajoituksena on kuitenkin, että luokka voi periä suoraan vain yhden luokan eli se ei voi yhdistellä monen luokan aineksia.
Javassa jokaisen luokan perimmäisenä yliluokkana on luokka
Object
. Kaikki uudet luokat perivät sen automaattisesti, jos
ne eivät peri mitään muuta luokkaa.
Esimerkissä tilanne on seuraava:
Object
-> Henkilo
-> Opiskelija
Huomaa, että luokkaan voi viitata sen minkä tahansa yliluokan nimellä. Kaikki seuraavat määrittelyt ovat siis mahdollisia:
Opiskelija maija = new Opiskelija("Maija");
Henkilo maija = new Opiskelija("Maija");
Object maija = new Opiskelija("Maija");
Muuttujan tyyppi määrittää, mitä luokan ominaisuuksia on käytettävissä.
Esimerkiksi jos muuttujan tyyppinä on Henkilo
, metodia
opiskele
ei voi käyttää, vaikka muuttuja viittaisi
Opiskelija
-olioon.
Abstrakti luokka on luokka, jonka kaikkia metodeja ei ole toteutettu, vaan niistä on annettu vain runko. Abstraktia luokkaa ei voi käyttää sellaisenaan, vaan toisen luokan täytyy ensin periä se ja toteuttaa puuttuvat metodit.
Seuraavassa on abtrakti luokka Saveltaja
:
public abstract class Saveltaja { private String nimi; public Saveltaja(String nimi) { this.nimi = nimi; } public void esittaydy() { System.out.println("Hei, nimeni on " + nimi); } public abstract void savella(); }
Tässä metodi esittaydy
on toteutettu täydellisesti, mutta
metodista savella
on annettu vain runko.
Seuraavat luokat täydentävät abstraktin luokan:
public class Beethoven extends Saveltaja { public Beethoven() { super("Beethoven"); } public void savella() { // Kohtalonsinfonia System.out.println("aaa f ggg e"); } }
public class Sibelius extends Saveltaja { public Sibelius() { super("Sibelius"); } public void savella() { // Finlandia System.out.println("e d e f e d e c d d e"); } }
Luokkien toimintaa esittelee seuraava pääohjelma:
public class Main { public static void main(String[] args) { Beethoven beethoven = new Beethoven(); beethoven.esittaydy(); beethoven.savella(); Sibelius sibelius = new Sibelius(); sibelius.esittaydy(); sibelius.savella(); } }
Ohjelman tulostus on seuraava:
Hei, nimeni on Beethoven aaa f ggg e Hei, nimeni on Sibelius e d e f e d e c d d e
Rajapinnat ja abstraktit luokat ovat melko samanlaisia. Erot ovat: