Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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ä.

Opiskelija.java
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.

Henkilo.java
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.

Henkilo.java
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.

Henkilo.java
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

Tehtävä 3.1: Luokkahierarkia, osa 1. 1 p.

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.

Tee tehtävä TIMissä
Tehtävä 3.2: Luokkahierarkia, osa 2. 1 p.

Jatketaan edellistä tehtävää. Peri Tuote-luokasta myös luokka Elektroniikka.

Lisää erityispiirteitä kuhunkin aliluokkaan:

  • Vaate: attribuutti String koko (esim. "M", "L", jne.), metodi void sovita(String sovittajanKoko), joka tulostaa, onko vaate sopiva sovittajalle.
  • Elektroniikka: attribuutti int takuuKuukausina (esim. 24), metodi int takuutaJaljella(int kuukausiaKulunut) palauttaa montako kuukautta takuuta on jäljellä (tai 0, jos takuu on umpeutunut).
  • Ruoka: attribuutti String parastaEnnen (esim. "31.01.2026"), ja metodi void syo(), joka tulostaa "Nautit ruoan, jonka viimeinen käyttöpäivä on DD.MM.YYYY." (korvaa DD.MM.YYYY parastaEnnen-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.

Tee tehtävä TIMissä
Tehtävä 3.3: Luokkahierarkia, osa 3. 1 p.

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.

  1. Puhelin (perii Elektroniikka)

    • 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 0401122330
      • public 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).
  2. Pakaste (perii Ruoka)

    • 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.

Tee tehtävä TIMissä