Perintä
osaamistavoitteet
- Ymmärrät perinnän käsitteen olio-ohjelmoinnissa ja osaat periä luokkia Javassa
- Osaat luoda yksinkertaisen luokkahierarkian, jossa luokka perii toisen luokan
- Ymmärrät, että kaikki Javan luokat perivät
Object-luokan
Perintä tarkoittaa mekanismia, jossa luokka sisällyttää itseensä toisen luokan ominaisuudet (attribuutit) ja toiminnallisuudet (metodit). Tämä mahdollistaa koodin uudelleenkäytön ja luokkien välisen hierarkian luomisen.
Käytännössä olioilla on usein yhteisiä piirteitä. Yksi tapa näiden yhteisten piirteiden käsittelemiseen siten, että koodia ei tarvitse toistaa, on perintä.
Opintotietojärjestelmä
Otetaan keksitty esimerkki henkilötietojärjestelmästä: Olli Opiskelija, Maija Opettaja ja Satu Sihteeri voisivat kaikki olla olioita kuvitteellisessa Kisu-opintotietojärjestelmässä. Kaikilla näillä on kaikille käyttäjille tyypillisiä ominaisuuksia, kuten nimi ja käyttäjätunnus. Jokaisen pitäisi myös päästä kirjautumaan sisään järjestelmään ja sieltä ulos.
Kullakin käyttäjällä on kuitenkin myös omia erityispiirteitään: Opiskelijalla voisi olla lista kursseista, joille hän on ilmoittautunut, sekä hänen suorittamansa opintopisteet. Opettajalla on kurssit, joita hän opettaa sekä tehtävänimike, mutta hänellä ei ole opintopisteitä. Sihteeri on vastuussa opintosuoritusten kirjaamisesta ja tutkinnon antamisesta, mutta hänellä ei ole opiskelijanumeroa tai opetettavia kursseja.
Lähdetään kuitenkin aluksi liikkeelle pienesti. Alla on Opiskelija- ja
Opettaja-luokat, joihin olemme tehneet pari attribuuttia ja metodia. Tutki
näitä luokkia.
varoitus
Useista alla olevista esimerkeistä puuttuu dokumentaatiokommentit, tai kommentit voivat olla osittain puutteellisia. Tämä on tietoinen valinta, sillä niiden lisääminen pidentäisi esimerkkikoodia, ja siten hankaloittaisi lukemista. Tässä materiaalissa koodia "dokumentoidaan" ja sitä selitetään ympäröivällä tekstillä, joten tämän materiaalin esitystavassa dokumentaatio ei ole välttämättä tarpeen.
varoitus
Alla oleva esimerkki on tarkoitettu havainnollistamaan perinnän
syntaksia, eikä siitä syystä noudata (vielä) parhaita käytäntöjä. Erityisesti
nimen asettaminen sellaisenaan attribuutin arvoksi käyttämällä julkista
setNimi-metodia rikkoo tiedon piilottamisen periaatetta (ks. Luku
2.3). Korjaamme tämän asian kuitenkin esimerkin
edetessä.
import java.util.ArrayList;
class Opiskelija {
String nimi;
List<String> kaynnissaOlevatKurssit;
public Opiskelija() {
this.kaynnissaOlevatKurssit = new ArrayList<>();
}
void setNimi(String nimi) {
this.nimi = nimi;
}
String getNimi() {
return this.nimi;
}
void naytaOpintoOhjelma() {
String kurssit = String.join(", ", kaynnissaOlevatKurssit);
IO.println(nimi + " opiskelee kursseilla: " + kurssit);
}
void ilmoittauduKurssille(String kurssi) {
IO.println(this.nimi + " ilmoittautui kurssille: " + kurssi);
kaynnissaOlevatKurssit.add(kurssi);
}
}
Huomaat, että kummassakin luokassa on samat attribuutti nimi sekä metodit
getNimi ja setNimi. Näiden luokkien välillä on toki myös eroja, mutta nimen
omaan toisto on ongelmallista, koska:
- jokaisessa luokassa on määriteltävä samat ominaisuudet ja toiminnot uudelleen,
- jos haluamme muuttaa jotain yhteistä ominaisuutta tai toimintoa, meidän täytyy tehdä se kolmessa eri paikassa,
- uuden luokan lisääminen, jolla on samat ominaisuudet, vaatii saman koodin kopioimisen uudelleen taas uuteen paikkaan.
Jos nyt haluaisimme muuttaa esimerkiksi nimi-attribuuttia niin, että etunimi
ja sukunimi tallennetaan erikseen kahteen attribuuttiin, meidän pitäisi tehdä
tämä muutos kaikissa näissä luokissa. Tämä lisää virheiden mahdollisuutta ja
tekee koodin ylläpidosta hyvin hankalaa. Yksi ohjelmistokehityksen periaatteista
onkin älä toista itseäsi (Don't Repeat Yourself, lyh. DRY; ks.
Wikipedia).
Luokkahierarkia
Toistamisen välttämiseksi voimme luoda yliluokan (engl. superclass) nimeltä
Henkilo, joka sisältää kaikki yhteiset ominaisuudet ja toiminnot. Sitten
alaluokat (engl. subclass) Opiskelija ja Opettaja voivat periä
Henkilo-luokan, jolloin ne saavat automaattisesti kaikki sen määrittelemät
ominaisuudet ja metodit. Näin voimme lisätä vain erityispiirteet kuhunkin
aliluokkaan ilman koodin toistamista.
Toteutetaan nyt uusi Henkilo-luokka, ja muutetaan Opiskelija- ja
Opettaja-luokkia niin, että ne perivät Henkilo-luokan. Javassa perintä
toteutetaan käyttämällä extends-avainsanaa. Esimerkiksi class Opiskelija extends Henkilo tarkoittaa, että Opiskelija-luokka perii Henkilo-luokan.
Tehdään tämä muutos koodissamme.
public class Henkilo {
String nimi;
String getNimi() {
return this.nimi;
}
void setNimi(String nimi) {
this.nimi = nimi;
}
}
Huomaa, että Opiskelija- ja Opettaja-luokat eivät enää määrittele nimi-attribuuttia tai getNimi- ja setNimi-metodeja, koska ne perivät nämä Henkilo-luokasta, eikä sitä koodia enää tarvitse uudelleen kirjoittaa. Tämä tekee koodista huomattavasti siistimpää ja helpommin ylläpidettävää. Perinnällä siis määritetään yksi yliluokka (tässä Henkilo) ja aliluokka tai aliluokat (tässä Opiskelija ja Opettaja), jotka laajentavat (engl. extend) Henkilo-luokan lisätiedoilla ja -toiminnallisuuksilla opiskelijasta ja opettajasta.
Toisin sanoen, Opiskelija ja Opettaja saavat itselleen samat (ei-yksityiset) attribuutit ja (ei-yksityiset) metodit kuin Henkilo-luokka ilman sitä, että ne pitää erikseen määritellä aliluokissa.
Kirjallisuudessa käytetään joskus yliluokka- ja aliluokka-termeistä myös nimityksiä kantaluokka (engl. base class) ja johdettu luokka (engl. derived class). Myös muita nimityksiä on käytössä. Näillä termeillä tarkoitetaan samaa asiaa kuin yliluokka- ja aliluokka-termeillä. Käytämme tässä materiaalissa kuitenkin pääasiassa yliluokka- ja aliluokka-termejä.
Periytymistä voidaan kuvata alla olevan tapaisella kuviolla. Tässä Henkilo on yliluokka (superclass) ja Opiskelija ja Opettaja ovat aliluokkia (subclasses), jotka perivät Henkilo-luokan ominaisuudet ja metodit.
Iso C-kirjain tarkoittaa, että kyseessä on luokka. Nuoli ylöspäin tarkoittaa perintää, eli aliluokka (nuolen tyvessä) perii yliluokan (nuolen kärjessä). Yllä oleva kuvio on tehty mukaillen niin sanottua UML-kuvauskieltä (engl. Unified Modelling Language).
Muodostajat ja super-avainsana
Yliluokan muodostajia voidaan kutsua aliluokista käyttäen super-avainsanaa.
Katsotaan esimerkin kautta, missä tällainen kutsu on tarpeen.
Yllä olevassa esimerkissämme on pari ongelmaa. Henkilo-luokassa ei ole
muodostajaa, jolloin nimen alustaminen tapahtuu setNimi-metodin kautta. Tästä
seuraa, että Henkilo-olion muodostamisen jälkeen nimi-attribuutti on aina
null, ennen kuin se erikseen asetetaan. Tämä ei ole hyvä käytäntö kahdestakaan
syystä: Ensinnäkin, on parempi, että olio on käyttökelpoinen heti luomisen
jälkeen ilman, että erillisiä asettamisia tarvitsee tehdä. Toiseksi, nimen
asettaminen julkisen setNimi-metodin kautta ei ole hyvä idea, sillä se rikkoo
tiedon kapseloinnin periaatetta.
Vaikka nimen muuttaminen toki pitäisikin tietyissä tilanteissa olla
opintotietojärjestelmässä mahdollista, sen asettaminen julkisen metodin kautta,
eli niin, että mikä tahansa olio voisi kutsua minkä tahansa Henkilo-olion
metodia nimen muuttamiseksi, ei pitäisi olla sallittua, vaan pitäisi tapahtua
huomattavasti hallitumman prosessin kautta.
Korjataan tilanne. Asetetaan aluksi nimi-attribuutti yksityiseksi
Henkilo-luokassa. Lisätään sitten muodostaja, joka ottaa nimi-parametrin, ja
alustaa attribuutin arvon vastaavasti. Tämän jälkeen voimme poistaa
setNimi-metodin kokonaan, jolloin nimen asettaminen onnistuu vain muodostajan
kautta. Niinpä nimen muuttaminen ei enää onnistu, mutta tämä sopii meille tässä
vaiheessa.
Muutetaan olioiden rakentelu pääohjelmassa vastaamaan tätä uutta muodostajaa.
class Henkilo {
// HIGHLIGHT_GREEN_BEGIN
private String nimi;
public Henkilo(String nimi) {
this.nimi = nimi;
}
// HIGHLIGHT_GREEN_END
// HIGHLIGHT_RED_BEGIN
void setNimi(String nimi) {
this.nimi = nimi;
}
// HIGHLIGHT_RED_END
public String getNimi() {
return this.nimi;
}
}
Nyt koska Henkilo-luokassa on määritelty muodostaja, joka ottaa parametreja,
Java ei enää luo oletusmuodostajaa—siis sellaista, jossa ei ole
parametreja—automaattisesti. Tämä aiheuttaa käännösvirheen—valitettavasti
hieman kryptisen sellaisen.
java: constructor Opiskelija in class Opiskelija cannot be applied to given types;
required: no arguments
found: java.lang.String
reason: actual and formal argument lists differ in length
Virheilmoituksen pointti on, että Opiskelija-olion muodostaja ei vastaa sitä,
miten yritämme luoda olion pääohjelmassa.
Tässä tuleekin tärkeä huomio: Luokat eivät peri muodostajia yliluokiltaan.
Esimerkiksi Opiskelija-luokka ei peri Henkilo-luokan muodostajia, vaan ne
täytyy määritellä erikseen jokaisessa aliluokassa. Tehdään Opiskelija ja
Opettaja-luokkiin muodostajat vastaamaan tätä vaatimusta. Esimerkiksi
Opiskelija-luokassa muodostajan alku näyttäisi tältä.
class Opiskelija extends Henkilo {
public Opiskelija(String nimi) {
// Muodostajan runko tulee tähän
}
}
Toisaalta nyt kun määrittelimme nimi-attribuutin yksityiseksi, emme voi
myöskään asettaa niitä perivästä luokasta käsin, esimerkiksi seuraavasti.
class Opiskelija extends Henkilo {
public Opiskelija(String nimi) {
// HIGHLIGHT_YELLOW_BEGIN
this.nimi = nimi;
// HIGHLIGHT_YELLOW_END
}
}
Opiskelija.java:6:5
java: constructor Henkilo in class Henkilo cannot be applied to given types;
required: java.lang.String
found: no arguments
reason: actual and formal argument lists differ in length
Opiskelija.java:8:13
java: nimi has private access in Henkilo
Ensimmäinen virhe liittyy siihen, että Henkilo-luokassa ei ole ei-parametrista
muodostajaa. Korjaamme tämän hieman myöhemmin. Jälkimmäinen virhe on tämän
hetkinen ongelmamme: nimi-attribuutti on yksityinen, joten emme voi asettaa
sitä suoraan perivästä luokasta käsin.
Koska poistimme setNimi-metodin, niin ainoa tapa asettaa nimen arvo on tehdä
se kutsumalla aliluokasta muodostajasta käsin yliluokan muodostajaa ja
välittämällä tuossa kutsussa tarvittavat parametrit. Tämä kutsuminen toteutetaan
super-avainsanaa. Tehdään tämä muutos kumpaankin aliluokkaan. Muutetaan
samalla myös loputkin attribuutit yksityisiksi.
import java.util.ArrayList;
class Opiskelija extends Henkilo {
// HIGHLIGHT_GREEN_BEGIN
private ArrayList<String> kaynnissaOlevatKurssit;
// HIGHLIGHT_GREEN_END
// HIGHLIGHT_GREEN_BEGIN
public Opiskelija(String nimi) {
super(nimi);
kaynnissaOlevatKurssit = new ArrayList<>();
}
// HIGHLIGHT_GREEN_END
// ...
}
Huomaa, että järjestys on oltava nimen omaan tämä: super-kutsu tulee
ensimmäisenä muodostajan rungossa. Vasta sen jälkeen voidaan tehdä muita
alustuksia.
Tee vastaava muutos myös Opettaja-luokkaan.
Tämän jälkeen ohjelma ei kuitenkaan vielä käänny, koska perivissä luokissa emme
edelleenkään pääse käsiksi yliluokan yksityiseen nimi-attribuuttiin.
class Opiskelija extends Henkilo {
void naytaOpintosuunnitelma() {
String kurssit = String.join(", ", kaynnissaOlevatKurssit);
// HIGHLIGHT_YELLOW_BEGIN
IO.println(this.nimi + " opiskelee kursseilla: " + kurssit);
// HIGHLIGHT_YELLOW_END
// Käännösvirhe: nimi on yksityinen muuttuja
}
}
Ainoa tapa päästä käsiksi nimi-attribuuttiin on kutsua yliluokan
getNimi()-metodia, sillä kyseinen metodi on julkinen. Tehdään tämä muutos
kaikkiin kohtiin, joissa nimi-attribuuttiin viitataan suoraan perivissä
luokissa.
class Henkilo {
private String nimi;
public Henkilo(String nimi) {
this.nimi = nimi;
}
public String getNimi() {
return nimi;
}
}
Ei-parametrista muodostajaa emme tarvitse enää, joten jätämme sen toteuttamatta.
UML-kaavioihin on tapana lisätä perintäsuhteiden lisäksi tietoja luokkien
attribuuteista ja metodeista sekä niiden näkyvyydestä. Attribuutit tyyppeineen
merkitään luokan nimen alle, ja metodit, myös muodostajat, vastaavasti ihan
alimmaiseksi. Perittyjä attribuutteja metodeja, kuten tässä attribuutti nimi
ja metodi getNimi(), ei yleensä merkitä kaavioon, paitsi jos ne
ylikirjoitetaan aliluokassa—tästä lisää Luvussa 3.2.
Vihreä pallo tarkoittaa, että kyseessä on julkinen (public) attribuutti/metodi,
ja punainen neliö, että kyseessä on yksityinen attribuutti/metodi. Tietojen
merkitseminen kaavioon mahdollistaa rakenteiden kuvailemisen ilman, että
tarvitsee sanallisesti kuvailla kaikkia yksityiskohtia.
Luokkahierarkia voi olla enemmänkin kuin kaksi tasoa syvä. Meillä voisi olla
myös Sihteeri, joka voi kirjata opintosuorituksia. Sihteeri peritään
Henkilo-luokasta. Voisimme tehdä myös kahdenlaisia erilaisia opiskelijoita:
Tutkinto-opiskelijoita sekä Avoimen yliopiston opiskelijoita.
Tutkinto-opiskelijalla voisi olla oma tutkinto-ohjelma, kun taas Avoimen
opiskelijalla ei ole tutkinto-ohjelmaa. Toisaalta Avoimen opiskelijan täytyisi
suorittaa maksu ennen kuin hän voi saada opintopisteitä.
Luokkahierarkia näyttäisi nyt seuraavalta. Merkitään tähänkin kuvioon attribuutit ja metodit mukaan. Tekstit menevät jo aika pieneksi, joten saat halutessasi kuvan auki uuteen välilehteen klikkaamalla sitä oikealla (tai Ctrl+klikkaamalla macOS:ssa) ja avaamalla kuvan uuteen välilehteen.
Koska nuoli TutkintoOpiskelija-luokasta osoittaa Opiskelija-luokkaan ja
sieltä edelleen Henkilo-luokkaan, niin TutkintoOpiskelija-luokasta
muodostettu olio perii sekä Opiskelija-luokan ominaisuudet ja metodit, että
Henkilo-luokan ominaisuudet ja metodit. Vastaavasti AvoinOpiskelija-luokasta
tehty olio perii myös molemmat luokat.
Jätämme esimerkin tässä toteuttamatta, mutta voit halutessasi tutkia valmista koodia täällä.
Huomautetaan vielä, että yliluokan muodostajan kutsuminen super-avainsanalla
kutsuu nimen omaan luokan välittömän yliluokan muodostajaa. Luokkarakenteessa
"yli hyppiminen", tyyliin super().super() ei ole mahdollista. Niinpä
TutkintoOpiskelija-luokan muodostajassa voi kutsua vain Opiskelija-luokan
muodostajaa, ei Henkilo-luokan muodostajaa.
Metodit ja super-avainsana
super-avainsanaa voidaan käyttää kutsuttaessa yliluokasta perittyä
metodia, kun halutaan eksplisiittisesti viitata yliluokan metodiin.
class Opiskelija extends Henkilo {
// ...
public void naytaKurssit(){
String kaikkiKurssit = String.join(", ", kaynnissaOlevatKurssit);
// HIGHLIGHT_RED_BEGIN
IO.println(this.getNimi() + " opiskelee kursseilla: " + kaikkiKurssit);
// HIGHLIGHT_RED_END
// HIGHLIGHT_GREEN_BEGIN
IO.println(super.getNimi() + " opiskelee kursseilla: " + kaikkiKurssit);
// HIGHLIGHT_GREEN_END
}
}
Tässä esimerkissä tällä ei ole mitään vaikutusta, koska getNimi() on sama sekä
yliluokassa että aliluokassa. Seuraavassa luvussa 3.2
Polymorfismi käsitellään tilannetta, jossa aliluokassa on
määritelty saman niminen metodi kuin yliluokassa. Tällöin super-avainsanalla
voidaan viitata nimenomaisesti yliluokan metodiin.
Huomautus moniperinnän puuttumisesta
Javassa luokka voi periä vain yhden luokan. Joissain muissa ohjelmointikielissä, kuten C++:ssa, on mahdollista käyttää moniperintää (engl. multiple inheritance), jossa luokka voi periä useamman kuin yhden luokan. Emme tässä mene syvemmälle moniperinnän käsitteeseen, mutta mainittakoon, moniperinnän käyttö voi joissain tilanteissa olla ongelmallista (esim. Timanttiongelma).
Usein kirjallisuudessa mainitaan, että Javassa moniperintää muistuttaa hieman rajapinnan käsite (engl. interface). Kysymys on kuitenkin monin tavoin eri asiasta. Rajapintoja käsitellään osassa 4 (TODO: linkki kuntoon)
Tehtävät
Tee luokka Tuote. Tee sille attribuutit nimi (merkkijono) ja hinta
(desimaaliluku). Aseta attribuuttien arvot konstruktorissa. Tee myös metodi
void tulostaTiedot(), joka tulostaa tuotteen nimen ja hinnan muodossa "Nimi: Hinta
€".
Peri Tuote-luokasta luokat Vaate ja Ruoka. Perivien luokkien
konstruktoreissa ei tarvitse tehdä muuta kuin kutsua yläluokan
konstruktoria oikeilla arvoilla.
Tee nyt ohjelmassasi kaksi erilaista vaatetta ja kaksi erilaista ruokatuotetta
ja tulosta niiden tiedot kutsumalla void tulostaTiedot()-metodia.
Jatketaan edellistä tehtävää. Peri Tuote-luokasta myös luokka Elektroniikka.
Lisää erityispiirteitä kuhunkin aliluokkaan:
Vaate: attribuuttiString koko(esim. "M", "L", jne.), metodivoid sovita(String sovittajanKoko), joka tulostaa, onko vaate sopiva sovittajalle.Elektroniikka: attribuuttiint takuuKuukausina(esim. 24), metodiint takuutaJaljella(int kuukausiaKulunut)palauttaa montako kuukautta takuuta on jäljellä (tai 0, jos takuu on umpeutunut).Ruoka: attribuuttiString parastaEnnen(esim. "31.01.2026"), ja metodivoid syo(), joka tulostaa "Nautit ruoan, jonka viimeinen käyttöpäivä on DD.MM.YYYY." (korvaa DD.MM.YYYYparastaEnnen-arvolla).
Huomaa, että perivien luokkien konstruktoreissa tulee nyt kutsua yläluokan konstruktoria oikeilla arvoilla, sekä asettaa omat attribuutit.
Tehtäväsivulla on valmiiksi annettuna pääohjelma. Käytä sitä luokkiesi testaamiseen. Se ei saa tuottaa käännös- tai ajonaikaisia virheitä. Voit kuitenkin halutessasi lisätä pääohjelmaan omaa koodiasi.
EDIT 30.1.2026: UML-kaavio korjattu vastaamaan tehtävänantoa
EDIT 29.1.2026: UML päivitetty vastaamaan tehtävänantoa
Laajenna aiemmin tekemääsi verkkokaupan luokkahierarkiaa alla olevan UML-kaavion mukaisesti. Saat kuvan suuremmaksi oikeaklikkaamalla (Windows) tai Control-klikkaamalla (macOS) sitä ja valitsemalla "Avaa kuva uudessa välilehdessä".
Tehtäväsivulla on valmiiksi annettuna pääohjelma, jota voit käyttää luokkiesi testaamiseen.
Avaa tästä ohjelman antama esimerkkituloste.
Kutsutaan perittyjä metodeja:
Talvitakki Dulce & Käppänä: 120.0 €
Ruisleipä Reissurähjä: 2.5 €
Tietokone HighPower: 899.0 €
----------------------------
Kutsutaan omia metodeja:
Testi 1: Sovitetaan M-kokoista käyttäjää:
Sovitetaan vaatetta Talvitakki Dulce & Käppänä...
Ei välttämättä sopivin koko. Sinä olet kokoa M, mutta tämä vaate on L.
Testi 2: Sovitetaan L-kokoista käyttäjää:
Sovitetaan vaatetta Talvitakki Dulce & Käppänä...
Mahtavaa! Koko L istuu sinulle täydellisesti!
Syödään Ruisleipä Reissurähjä.
Parasta ennen oli 20.12.2024, toivottavasti on hyvää.
Takuuta jäljellä: 19 kk.
pHone: 999.99 €
Takuuta puhelimessa jäljellä: 19 kk
Käyttöjärjestelmä: Orange
Yhteystyyppi: 4G
Soitetaan käyttöjärjestelmästä Orange(4G) numeroon 0401122330
Hernepussi: 0.99 €
Sulatit pakastetta Hernepussi 10 minuuttia. Säilytyssuositus on -18 astetta C.
Syödään Hernepussi.
Parasta ennen oli 31.5.2026, toivottavasti on hyvää.
Tehtävän kuvaus sanallisessa muodossa
Tässä on kuvaus uusista luokista ja niiden vaadituista ominaisuuksista. Löydät vastaavat tiedot UML-kaaviosta.
-
Puhelin(periiElektroniikka)- Lisää attribuutit:
private String kayttojarjestelma(esim. "Droid" tai "AiOS")private boolean onko5G
- Lisää metodit:
public void soita(String numero). Metodi tulostaa esimerkiksi:Soitetaan käyttöjärjestelmästä Orange(4G) numeroon 0401122330public void tulostaPuhelimenTiedot(int kuukausiaKulunut). Metodin tulee kutsua ensin perittyä metodia (tulostaTiedot()), ja sitten tulostaa puhelimeen liittyvät lisätiedot (jäljellä olevan takuuajan, käyttöjärjestelmän ja 5G-tuki).
- Lisää attribuutit:
-
Pakaste(periiRuoka)- Lisää attribuutti:
private int lampotilaSuositus(esim. -18)
- Lisää metodi:
private void sulata(int minuutit)(huomaa private-määre)- Kun metodia kutsutaan, se tulostaa esimerkiksi:
Sulatat pakastetta 10 minuuttia. Säilytyssuositus: -18 C.
- Lisää metodi:
public void sulataJaNauti(int minuutit)- Metodi kutsuu ensin
sulata(minuutit)-metodia ja sitten perittyäsyo()-metodia.
- Lisää attribuutti: