Olio-ohjelmointi 2016 Periytyminen
Periytyminen n Perinnässä aliluokka perii kantaluokan ominaisuudet Aliluokka laajentaa kantaluokkaa class LapsiLuokka extends EmoLuokka { LapsiLuokan koodi } n Vain yksi luokka voidaan periä n Kaikki luokat periytyvät Object-luokasta -> kaikissa luokissa mm. Object-luokan metodit equals() clone() tostring() Javalla 2
Periytyminen n LuokkaA: a ja b n LuokkaB: a, b ja c n LuokkaC: a, b, d ja e n LuokkaD: a, b, d, e ja f Javalla 3
Periytyminen n Piirteiden näkyvyys vaikuttaa Piirre a ei saa olla private, jotta sitä voidaan käyttää luokassa D public on liian yleinen Jos piirre a on protected ja b on oletus ja luokka D sijaitsee eri pakkauksessa kuin luokka A n D voi käyttää piirrettä a mutta ei piirrettä b n b:n näkyvyys rajattu vain saman pakkauksen luokille Javalla 4
Periytyminen n Periytymisellä voidaan luoda "is-a"-suhteita n Aliluokka on esi-isiensä kaltainen ympyrä ja suorkulmio ovat kuvioita auto ja polkupyörä ovat kulkuvälineitä mandarini ja kumkvatti ovat hedelmiä Javalla 5
Periytyminen public class Polkupyora { // Pokupyörällä on kaksi attribuuttia private int kadenssi; //polkimen kierrosten maara/min private int nopeus; public Polkupyora(int aloituskadenssi, int aloitusnopeus) { kadenssi = aloituskadenssi; nopeus = aloitusnopeus;; public void setpoljinnopeus(int uusiarvo) { kadenssi = uusiarvo; public void jarruta(int maara) { if(nopeus-maara > 0) nopeus -= maara; else nopeus = 0; public void kiihdyta(int maara) { nopeus += maara; } Javalla 6
Periytyminen public class MaastoPyora extends Polkupyora{ private int istuimenkorkeus; private int vaihde private int vaihteidenlukmaara; public MaastoPyora(int istuimenalkukorkeus,int vaihteidenlkm; int aloituskadenssi,int aloitusnopeus, int aloitusvaihde) { super(aloituskadenssi, aloitusnopeus); istuimenkorkeus = istuimenalkukorkeus; vaihde = aloitusvaihde; vaihteidenlukmaara = vaihteidenlkm; public void asetaistuimenkorkeus(int uusiarvo) { istuimenkorkeus = uusiarvo; public void asetavaihde(int uusiarvo) { if( uusiarvo >=0 && uusiarvo <= vaihteidenlkm) vaihde = uusiarvo; Javalla 7
Periytyminen public class TandemPyora extends Polkupyora{ private int polkijoidenlukumaara; public TandemPyora (int polkijoidenlkm,int aloituskadenssi, int aloitusnopeus) { super(aloituskadenssi, aloitusnopeus); polkijoidenlukumaara = polkijoidenlkm; Javalla 8
Periytyminen public class MaastoPyora extends Polkupyora{ private int istuimenkorkeus; private int vaihde private int vaihteidenlukmaara; public MaastoPyora(int istuimenalkukorkeus,int vaihteidenlkm; int aloituskadenssi,int aloitusnopeus, int aloitusvaihde) { super(aloituskadenssi, aloitusnopeus); istuimenkorkeus = istuimenalkukorkeus; vaihde = aloitusvaihde; vaihteidenlukmaara = vaihteidenlkm; public void asetaistuimenkorkeus(int uusiarvo) { istuimenkorkeus = uusiarvo; public void asetavaihde(int uusiarvo) { if( uusiarvo >=0 && uusiarvo <= vaihteidenlkm) vaihde = uusiarvo; Javalla 9
Periytyminen n this viittaa olion metodissa olioon itseensä n super viittaa olion metodissa sen kantaluokkaan Välitetään näkymättöminä parametreina jokaiselle metodille public class TandemPyora extends Polkupyora{ private int polkijoidenlukumaara; public TandemPyora (int polkijoidenlkm,int aloituskadenssi, int aloitusnopeus) { Kutsuu Polkupyora-luokan super(aloituskadenssi, aloitusnopeus); konstruktoria this.polkijoidenlukumaara = polkijoidenlkm; Asettaa olion muuttujan arvon Javalla 10
Abstraktit luokat n Abstraktista luokasta ei voi suoraan luoda instannsia n Toimii luokkien yliluokkana n Avainsana abstract public abstract class Kuvio { //... public abstract double pintaala(); public class Suorakulmio extends Kuvio { //... public double pintaala() { return leveys * korkeus; Javalla 11
Abstraktit luokat public class Ympyra extends Kuvio { //... public double pintaala() { return Math.PI * Math.pow( sade, 2 ); public class Kolmio extends Kuvio { //... public double pintaala() { return (kanta * korkeus)/2.0; Javalla 12
Abstraktit luokat n Toteuttavan luokan täytyy toteuttaa kaikki perimänsä abstraktin luokan abstraktit metodit n Sama pätee rajapintaluokkien yhteydessä n Syrjäyttäminen (ylikirjoittaminen) Jälkeläisluokassa voidaan määritellä samanniminen metodi kuin kuin yliluokassa. Metodilla vastaavat parametrit ja palautusarvo Javalla 13
Abstraktit luokat abstract class Soitin { protected String nimi; public abstract void soita(); abstract class KieliSoitin extends Soitin { protected int kieltenlukumaara; Javalla 14
Abstraktit luokat public class SahkoKitara extends Kielisoitin { public SahkoKitara () { super(); this.nimi = "Kitara"; this.kieltenlukumaara = 6; public SahkoKitara (int kieltenlukumaara) { super(); this.nimi = "Kitara"; this.kieltenlukumaara = kieltenlukumaara; public void soita() { System.out.println("Sähkökitara" + kieltenlukumaara + "-kieltä " + nimi+ " rokkaa"); Javalla 15
Abstraktit luokat public class SahkoBassoKitara extends KieliSoitin { public SahkoBassoKitara () { super(); this.nimi = "Bassokitara"; this.kieltenlukumaara = 4; public SahkoBassoKitara (int kieltenlukumaara) { super(); this.nimi = "Bassokitara"; this. kieltenlukumaara = kieltenlukumaara; public void soita() { System.out.println("Sähköinen " + kieltenlukumaara + "- kielinen " + nimi + " rokkaa"); Javalla 16
Abstraktit luokat public class KitaraMain { public static void main(string[] args) { SahkoKitara kitara = new SahkoKitara (); SahkoBassoKitara basso = new SahkoBassoKitara(); kitara.soita(); basso.soita(); kitara = new SahkoKitara (12); basso = new SahkoBassoKitara(5); kitara.soita(); basso.soita(); Javalla 17
Abstraktit luokat n Virtuaalinen operaatio public abstract class Kuvio{ //.. public String tostring(){ return "Kuvio: "+ teksti + "" + keskipistemj(); public class Suorakulmio extends Kuvio{ public String tostring(){ String kuviomj = super.tostring(); //ylil. metodi return "Suorakulmion korkeus: "+ korkeus + "leveys: " + leveys + " " +kuviomj; Javalla 18
Abstraktit luokat n tostring() on virtuaalinen operaatio, toisin sanoen sen toimintaa voidaan muuttaa jälkeläisluokissa n Javassa kaikki metodit ovat automaattisesti virtuaalisia n Ei-virtuaalisen metodin voi määritellä finalavainsanalla, estetään metodin syrjäyttäminen jälkeläisluokassa n Luokan määrittely final-määrellä, tekee luokasta lopullisen, luokkaa ei voi periyttää. n Lopullinen luokka ei voi olla abstrakti Javalla 19
Abstraktit luokat n Yliluokan suunnittelussa huomioitava millaisen rajapinnan luokka tarjoaa muille luokille n Abstrakteilla metodelilla voi määritellä rajapinnan toimintoja, jotka toteutetaan myöhemmissä luokissa n Luokan metodien näkyvyys vaikuttaa luokan tarjoamaan rajapintaan public, piirre on kaikkien luokkien käytettävissä protected, jälkeläisluokissa käytettäväksi private, piirre on vain tietyn luokan toteutusta, eivät ole käytössä muissa luokissa
Abstraktit luokat n Jos luokassa on vain abstrakteja metodeja, kannattaa luokasta tehdä rajapinta n Luokka voi toteuttaa useita rajapintoja, mutta periä voi vain yhden luokan
Metodin dynaaminen sidonta n Aliluokassa voidaan uudelleenmääritellä yliluokan metodi Metodin tyyppi täsmälleen sama kuin yliluokassa n Yliluokan tyyppinen muuttuja voi viitata aliluokan olioon Mitä tapahtuu, kun kutsutaan metodia? n Myöhäinen sidonta (dynaaminen) vs. aikainen sidonta (staattinen) Javassa metodikutsu sidotaan dynaamisesti Suoritettava metodi päätetään ajonaikana Etsintä alkaa perusluokasta, sitten perusluokan yliluokasta jne. kunnes metodin toteutus löytyy Javalla 22
Metodin dynaaminen sidonta n Dynaaminen sidonta hitaampaa n Monimuotoisuus Sama kohde voi tarkoitaa useita eri asioita n Viitemuuttujat ovat rajoitetusti monimuotoisia Voi viitata määritelyn luokan olioon Voi viitata luokan jälkeläisluokan olioon n Koskee myös taulukon alkioita Javalla 23
Metodin dynaaminen sidonta class Kanta { public void tulosta() { } } class Ali extends Kanta { public void tulosta(){ } } Uudelleenmäärittely // Ohjelmassa Kanta k = new Ali(); k.tulosta(); Kutsuu Ali-luokan metodia Javalla 24
Metodin dynaaminen sidonta Kuvio kt [] = new Kuvio[2]; kt[0] = new Ympyra(10, 20, 5, "ymp"); kt[1] = new Suorakulmio(10, 20, 5, 10, "SK"); for(int i =0; i kt.length; i++){ System.out.printf("%s %.2f%n", kt[i].getteksti(), kt[i].ala(); Javalla 25
Dynaaminen sidonta n Periytyminen vaikuttaa rakentajien kutsumiseen n Luokan alustus eteenee new varaa oliolle muisti new alustaa olion attribuutit oletusarvoilla Rakentajan kutsu n Jos rakentajan alussa on halutaan kutsua jotain toista ko. luokan rakentajaa (this), tehdään se ensin n Jos luokalla on yliluokka, kutsutaan sen rakentajaa (super) n Yliluokan rakentajasta palattaessa alustetaan attribuutit, joille annetaan arvo määrittelyssä n Rakentajan lopetus Javalla 26
Dynaaminen sidonta public class Counter { private int count; public Counter(){ public Counter(int initialvalue){ //.. count = initialvalue; Counter c1 = new Counter(); Counter c2 = new Counter(100); Javalla 27
Dynaaminen sidonta n Rakentajasta voidaan kutsua Toista saman luokan rakentajaa Yliluokan rakentajaa Luokan muita metodeja n Luokan rakentajaa kutsutaan this([mahdolliset parametrit]) n Yliluokan rakentajaa kutsutaan super([mahdolliset parametrit]) public Counter(){ this(100); Javalla 28
Dynaaminen sidonta public Counter(){ this(100); public Counter(int initialvalue){ super(); //Object luokan rakentajan kutsu count = initialvalue; n Yliluokan rakentajan explisiittinen kutsu tarpeen, jos yliluokalla ei ole oletusrakentajaa Javalla 29
Dynaaminen sidonta class C { protected int x, z; public C(int n){ x=n; laskez(); public void laskez(){ z = 2 * x; class D extends C { protected int y = 1; public D(int nx, int ny){ super(nx); y = ny; public void laskez(){ z = y * x; D joku = new D(3, 4); Javalla 30
Dynaaminen sidonta n Olion tyypin voi tarkistaa instanceof-operaattorilla ennen tyypinmuunnosta Soitin sk = new SahkoKitara(); Nokkahuilu nh = (Nokkahuilu)sk; //yritetään tehdä tyypinmuunnos n Yllä oleva kaatuu poikkeustilanteenseen: Exception in thread "main" java.lang.classcastexception: SahkoKitara cannot be cast to Nokkahuilu at NokkaHuiluTesti.main(NokkaHuiluTesti.java:9) Javalla 31
Dynaaminen sidonta n Jos tutkittava viite sisältää null-arvon, instanceof palauttaa aina arvon false n null-viitteen tyypin voi muuttaa miksi tahansa tyypiksi n Ajonaikaiset tyypintarkastukset kielivät yleensä suunnitteluvirheestä Soitin sk = new NokkaHuilu(); if( sk instanceof SahkoKitara ){ (SahkoKitara)sk.soita(); }else{ //tyypit ovat epäyhteensopivia } Object obj = null; SahkoKitara sk = (SahkoKitara)obj; Javalla 32
Dynaaminen sidonta, generinen tyyppi n Tietotyyppien abstrahointia n Kaikkein yleiskäyttöisin tietorakenne on Object n Voidaan joutua tekemään tyypinmuunnoksia (vanha tyyli alla) ArrayList lista = new ArrayList(); lista.add(0, "Murmeli"); String elukka = lista.get(0); //virhe Muunnos String elukka =(String)lista.get(0); Javalla 33
Genenrinen tyyppi n Nykyisin käytetään generisiä tyyppejä n Säilytettävän olion tyyppi parametrisoidaan n Tyyppiparametri (kulmasulkeissa) ArrayList<String> lista = new ArrayList<String>(); lista.add(0, "Murmeli"); String elukka = lista.get(0); n Tyyppiparametri määrää olion tyypin, listaan ei voi tallettaa väärää tyypiä olevia olioita n Samoin listasta palautuu automaattisesti määriteltyä tyyppiä oleva olio Javalla 34
Generinen tyyppi ArrayList<String> lista = new ArrayList<>(); n Java 7 alkaen kääntäjä voi osata päätellä automaattisesti tyyppiparametrin n Rakentajan kutsussa riittää pelkät kulmasulut (timanttti) n Kääntäjä varoitta kulmasulkujen puuttumisesta Javalla 35
Generinen tyyppi n Luokan tyyppi on parametrisoitu n Myös generinen rajapinta voidaan parametrisoida n Tyyppiä käytettäessä muodolliset tyyppiparametrit korvataan todellisilla public interface Pino<E> { public boolean ontyhja(); public boolean ontaysi(); public void lisaa(e o); public E palauta(); Javalla 36
Generinen tyyppi public class OmaPino<E> implements Pino<E> { private int koko = 0; private E[] otukset; public OmaPino(final int koko){ otukset = (E[]) new Object[koko]; public boolean ontyhja(){ return koko == 0; public boolean ontaysi(){ return koko == otukset.length; public void lisaa(e o){ otukset[koko++] = o; public E palauta(){ E otus = otukset[--koko]; otukset[koko]=null; return otus; Javalla 37
Generinen tyyppi public static void main(string [] args) { OmaPino<String> mjonopino = new OmaPino<String>(10); String mjono = new String("Katti"); mjonopino.lisaa(mjono); mjonopino.lisaa("matti Kattinen"); System.out.println("Pino:"); while( mjonopino.ontyhja() ){ mjono = mjonopino.palauta(); System.out.println("Mjono: " + mjono); Javalla 38
Generinen tyyppi n Ohjelman kääntäminen javac Xlint:unchecked OmaPino.java n Tyyppiparametrien niminä käytetään yksikirjaimisia tunnuksia E, elementti K, avain N, numero T, tyyppi V, arvo Javalla 39
Sisäluokat n Sisäluokka (nested class) on toisen luokan sisällä määritelty luokka n Sisäluokka voi olla myös sisältävän luokan metodin sisällä class SisaltavaLuokka { // attribuutteja // metodeja class Sisaluokka { //attribuutteja // metodeja Javalla 40
Sisäluokat n Sisäluokat pääsevät käsiksi sisältävän luokan piirteisiin n Sisäluokkia käytetään Luokkaa käytetään vain yhdessä paikassa Lisää kapselointia: n Luokat A ja B n A:n jäsenent private-tyyppiä ja B:n pitäisi päästä käsiksi A:n piirteisiin n B kätketään A:n sisälle n Samalla B voidaan piilottaa ulkomailmalta Voi tuottaa helpommin luettavaa ja ylläpidettävää koodia, luokka voi olla lähempänä käyttöpaikkaa Javalla 41
Sisäluokat n Ulommasta luokasta on oltava olio ennen kuin sisemmästä luokasta voidaan luoda olio UlompiLuokka ulompiolio = new UlompiLuokka();... UlompiLuokka.SisempiLuokka sisempiolio = ulompiolio.new SisempiOlio() n Sisäluokka voidaan myös määritellä nimettömäksi sisäluokaksi n Luokka määritellään ja olio luodaan heti n Käytetään kun halutaan ylikirjoitaa luokan tai rajapinnan metodi Javalla 42
Sisäluokat abstract class AnonyymiSisaluokka { public abstract void omametodi(); public class Anonyymi { public static void main(string [] args){ AnonyymiSisaluokka sisempi = new AnonyymiSisaluokka(){ public void omametodi(){ System.out.println("Esimerkki anon. sisäluokasta"); }; huomaa puolipiste sisempi.omametodi(); Javalla 43
Sisäluokat n Sisäluokka voi olla luokkakohtainen sisäluokka n Määritellään käyttäen static-avainsanaa public class Ulompi { static class SisaLuokka{ public void omametodi(){ System.out.println("Tama on minun sisempi luokka"); public static void main(string args[]){ Ulompi.SisaLuokka sisempi = new Ulompi.SisaLuokka(); sisempi.omametodi(); Javalla 44
Lueteltu tietotyyppi n Määritellään käyttämällä avainsanaa enum n Luetellun tyypin avulla voi rajoittaa muuttujan saamia arvoja n Lueteltua tyyppiä olevaan muuttujaan ei voi sijoittaa muita kuin kyseiseen tyyppiin kuuluvia arvoja public enum Viikonpaiva { MA, TI, KE, TO, PE, LA,SU };... Viikonpaiva pv = 5; n Tuloksena virheilmoitus error: incompatible types: int cannot be converted to Viikonpaiva Viikonpaiva pv = 5; Javalla 45
Lueteltu tyyppi n Luetellulla tietotyypillä luokkakohtaiset metodit values(), palautaa arvot määrittelyjärjestyksessä taulukossa valueof(string), palauttaa vakioarvon sen nimen perusteella class EnumDemo { public enum Viikonpaiva { MA, TI, KE, TO, PE, LA,SU }; public static void main(string [] args){ for( Viikonpaiva p: Viikonpaiva.values()) System.out.println(p); Javalla 46