1(37) PERIYTYMINEN (inheritance) YLILUOKKA (superclass) ALILUOKKA (subclass) A) on käytännöllinen ohjelmointitekniikka = laajennetaan aikaisemmin tehtyjä luokkia (uudelleenkäytettävyys) B) on käsitteiden mallittamista = mallinnetaan yleinen erityinen suhdetta
2(37) A) Laajennetaan aikaisemmin tehtyä luokkaa Esim. Olen aikaisemmin tehnyt Koira-luokan, jonka attribuutteina ovat koiran nimi ja koiran syntymävuosi. Nyt tarvitsen Koira-luokan, joka sisältää nimen ja syntymävuoden lisäksi koiran rodun. En halua koodata Koira-luokkaan uudestaan vaan periytän Koira-luokasta RotuKoira-luokan, jonka attribuuttina on Koiran attribuuttien lisäksi Koiran rotu Koira -nimi : String -syntymavuosi : int RotuKoira -rotu : String Eli en voi muuttaa aikaisemmin tehtyä luokkaa, koska se on tuotannossa ja aikaisemmin tehtyjen ohjelmien tulisi toimia Periytän vanhan luokan ja lisään uuteen luokkaan uusia tarvitsemiani ominaisuuksia ja metodeja
3(37) B) Mallinnetaan yleinen erityinen suhdetta Esim. Tehtäväni on tehdä Henkilö-, Työntekijä- ja Osakasluokat. Henkilön ominaisuudet ovat: henkilön etunimi, sukunimi, henkilön sosiaaliturvatunnus (sotu). Työntekijän ominaisuudet ovat työntekijän etunimi, sukunimi, työntekijän sosiaaliturvatunnus (sotu), osaston nimi, jossa hän työskentelee, nimike. Osakkaan ominaisuudet ovat osakkaan etunimi, sukunimi, osakkaan sosiaaliturvatunnus (sotu), osakkaaksi tulovuosi. Huomaan että kaikilla em.luokilla on samoja ominaisuuksia, siis teen yliluokan, Henkilo, johon sijoitan ne ominaisuudet jotka ovat samoja. Periytän muut luokat Henkiloluokasta.
4(37) Henkilo -etunimi : String -sukunimi : String -sotu : String Tyontekija -osasto : String -nimike : String Osakas -vuosi : int Eli en halua koodata samaa asiaa useaan kertaan etsin luokka-vaihtoehdoista yhteisiä ominaisuuksia, ja jos ne löydän teen yliluokan, jolla on nämä ominaisuudet muut luokat periytän yliluokasta
5(37) Miten minä toteutan luokan periytymisen? aliluokan olio perii yliluokalta kaikki tiedot (attribuutit ja metodit) aliluokan oliolla on yliluokan ilmentymä, johon aliluokan olion metodeissa viitataan sanalla super aliluokka periytetään extends määreellä seuraavasti: public class aliluokka extends yliluokka Esim. public class Koira private String nimi; private int syntvuosi; public class RotuKoira extends Koira private String rotu; RotuKoira koira = new RotuKoira(); Yliluokan ilmentymä koira: rotu: nimi; syntvuosi:
6(37) Muodostimet ja periytyminen aliluokan olion yliluokkailmentymään viitataan määreellä super Mitä tapahtuu, kun aliluokan olio luodaan? 1) kääntäjä valitsee muodostimista sen, joka vastaa kutsua Esim. RotuKoira koira=new RotuKoira( Wilma,2004, Irlannin vesispanieli ); kääntäjä valitsee aliluokan parametrillisen muodostimen RotuKoira(String str1,int kluku,string str2) 2) aliluokan muodostimessa yliluokan muodostimen kutsu suoritetaan ensin jos aliluokan muodostimessa ei ole yliluokan muodostimen kutsua kutsutaan automaattisesti yliluokan oletusmuodostinta (super( );) jos aliluokan muodostimen ensimmäisenä lauseena on yliluokan muodostimen kutsu (super ( )), kutsutaan sitä 2) suoritetaan muut muodostimen lauseet.
7(37) Esim. public class Koira private String nimi; private int syntvuosi; public Koira()//oletusmuodostin nimi = null; syntvuosi = 0; public Koira (Koira koira) // kopiointimuodostin nimi = koira.nimi; syntvuosi = koira.syntvuosi; public Koira (String nimi, int vuosi) //parametrillinen muodostin this.nimi = nimi; if (vuosi >0) syntvuosi = vuosi; else syntvuosi = 0; public class RotuKoira extends Koira private String rotu; public RotuKoira () rotu = null; public RotuKoira (String nimi, int syntvuosi, String rotu) super (nimi, syntvuosi); this.rotu = rotu; public RotuKoira (RotuKoira koira) super ((Koira) koira); rotu = koira.rotu; Automaattinen yliluokan oletusmuodostimen kutsu ( super(); ) Yliluokan parametrillisen muodostimen (public Koira(String nimi, int vuosi)) kutsu Yliluokan kopiointimuodostimen (public Koira (Koira koira)) kutsu
8(37) Metodin korvaaminen (overriding) metodin korvaaminen tarkoittaa perityn metodin korvaamista uudella samantyyppisellä, samannimisellä ja samaparametrisella metodilla on suositeltava tapa, koska voidaan käyttää monimuotoisuutta (polymorfism, myöhemmin) jokainen Javan yliluokka (luokka, jota käyttäjä ei periytä) periytetään automaattisesti Object-luokasta Mitä kääntäjä tekee, kun se etsii kutsuttua metodia? Kääntäjä hakee metodia MUUTTUJAN luokasta (esim. Koira koira;... koira.metodi(); ) Jos metodi löytyy, sitä kutsutaan Jos metodia ei löydy, kääntäjä hakee metodia MUUTTUJAN LUOKAN YLILUOKASTA Jos metodia ei vieläkään löydy,kääntäjä hakee metodia em. luokan yliluokasta, jne. Jos metodia ei ole löytynyt mistään olion luokkahierakkiasta eikä sitä löydy Objectistakaan, tapahtuu VIRHE
9(37) Esim. Tutkitaan tilanne, jossa Koira-luokkaan ei ole toteutettu tostring-metodia, ja sitä kutsutaan ohjelmassa (Objectluokassa on tostring-metodi) public class Koira private String nimi; private int syntvuosi; public Koira() nimi = null; syntvuosi = 0; public Koira (String nimi, int vuosi) this.nimi = nimi; if (vuosi >0) syntvuosi = vuosi; else syntvuosi = 0; public class KoiraTesti public void aja() Koira koira = new Koira ("Raiku", 1998); System.out.println(koira.toString()); public Koira (Koira koira) nimi = koira.nimi; syntvuosi = koira.syntvuosi; public static void main (String [] args) KoiraTesti testi = new KoiraTesti(); tostring-metodia ei löydy Koira-luokasta, etsitään sitä Koiraluokan yliluokasta eli Object-luokasta, BINGO, kutsutaan sitä testi.aja(); KoiraTesti ohjelma tulostaa: Koira@18d107f
10(37) Edellinen tostring-metodin tulostus ei kelpaa meille, joten korvaamme Object-luokan metodin Koira-luokan tostringmetodilla public class Koira private String nimi; private int syntvuosi; public Koira() nimi = null; syntvuosi = 0; public Koira (String nimi, int vuosi) this.nimi = nimi; if (vuosi >0) syntvuosi = vuosi; else syntvuosi = 0; public Koira (Koira koira) nimi = koira.nimi; syntvuosi = koira.syntvuosi; public String tostring () String paluu; if (nimi!= null) paluu = "nimi: " + nimi; else paluu = "nimi: ei ole"; paluu = paluu +" syntymavuosi: " + syntvuosi; return paluu;
11(37) public class KoiraTesti Etsitään tostringmetodia RotuKoiraluokasta, ei löydy, joten etsitään metodia RotuKoiran yliluokasta eli Koira-luokasta. Bingo, löytyi public void aja() Koira koira = new Koira ("Raiku", 1998); System.out.println(koira.toString()); RotuKoira koira2 = new RotuKoira("Wilma", 2004, "Irlannin vesispanieli"); System.out.println(koira2.toString()); public static void main (String [] args) KoiraTesti testi = new KoiraTesti(); testi.aja(); KoiraTesti sovellus tulostaa: nimi: Raiku syntymavuosi: 1998 nimi: Wilma syntymavuosi: 2004
12(37) Edelleen RotuKoiran rotu ei tulostu, joten korvaamme RotuKoiraluokassa Koira luokan tostring-metodin omalla tostringmetodilla public class RotuKoira extends Koira private String rotu; public RotuKoira () rotu = null; public RotuKoira (String nimi, int syntvuosi, String rotu) super (nimi, syntvuosi); this.rotu = rotu; public RotuKoira (RotuKoira koira) super ((Koira) koira); rotu = koira.rotu; public String tostring() String paluu; paluu = super.tostring(); Koira-ilmentymän tostring-metodin kutsu if (rotu!= null) paluu = paluu + " rotu: " +rotu; else paluu = paluu + " rotu: harvinainen, ei tiedossa toistaiseksi"; return paluu;
13(37) public class KoiraTesti public void aja() Koira koira = new Koira ("Raiku", 1998); System.out.println(koira.toString()); RotuKoira koira2 = new RotuKoira("Wilma", 2004, "Irlannin vesispanieli"); System.out.println(koira2.toString()); public static void main (String [] args) KoiraTesti testi = new KoiraTesti(); testi.aja(); tulostuu: nimi: Raiku syntymavuosi: 1998 nimi: Wilma syntymavuosi: 2004 rotu: Irlannin vesispanieli
14(37) Koira -nimi : String -syntymavuosi : int +tostring() : String RotuKoira -rotu : String +tostring() : String Yliluoluokan ilmentymän metodia kutsutaan aliluokan ilmentymän metodista seuraavasti: super.metodinnimi() super-määrettä ei tarvita, mikäli ristiriitaa ei synny, eli kutsuttavaa yliluokan metodia ei ole korvattu aliluokassa
15(37) Näkyvyyssäännöt kun yliluokan attribuutti / metodi näkyvyys on: 1) private aliluokan olio EI näe ko. attribuuttia /metodia 2) protected aliluokan olio näkee ko. attribuutin / metodin ja voi siihen suoraan viitata 3) public aliluokan olio näkee ko. attribuutin / metodin ja voi siihen suoraan viitata 4) ei mitään kaikki yliluokan kanssa samassa paketissa olevat näkevät ko. attribuutin / metodin yliluokan / luokan attribuuttien näkyvyysmääre kannattaa olla private tietyn attribuutin käsittely on siellä, missä kuuluu ylläpidettävyys
16(37) instanceof-operaattori metodin avulla voidaan tutkia, minkä luokan olioon muuttuja viittaa syntaksi: muuttuja instanceof Luokka metodi palauttaa arvon true, jos muuttuja viittaa olioon, jonka tyyppi on Luokka, muuten metodi palauttaa arvonaan false
17(37) Esim. Object koira = new Koira ("Raiku", 1998); koira: Koira: nimi: Raiku syntvuosi:1998 Object koira2 = new RotuKoira("Wilma", 2004, "Irlannin vesispanieli"); koira2: RotuKoira: Rotu: Irlannin vesipanieli Koira: nimi: Wilma syntvuosi:2004 if (koira instanceof Koira) System.out.println( Kyseessa on koira ); tulostuu: Kyseessä on koira if (koira2 instanceof RotuKoira) System.out.println( Kyseessa on rotukoira ); tulostuu: Kyseessä on rotukoira
18(37) Esim. public class KoiraTesti2 public void aja() Object koira = new Koira ("Raiku", 1998); tulosta(koira); Object koira2 = new RotuKoira("Wilma", 2004, "Irlannin vesispanieli"); tulosta(koira2); private void tulosta( Object koira) RotuKoira apu; Koira apu1; if (koira instanceof RotuKoira) System.out.println ("Koiran tiedot: "); apu =(RotuKoira) koira; tyyppimuunnos System.out.println (apu.getnimi()+ " on syntynyt vuonna " + apu.getsyntvuosi()); System.out.println ("ja koiran rotu on " + apu.getrotu()); else if (koira instanceof Koira) System.out.println ("Koiran tiedot: "); apu1 = (Koira) koira; tyyppimuunnos System.out.println(apu1.getNimi()+ " on syntynyt vuonna " + apu1.getsyntvuosi()); public static void main (String [] args) KoiraTesti2 testi = new KoiraTesti2(); testi.aja();
19(37) ABSTRAKTI-LUOKKA on luokka, johon ei voi luoda olioita, mutta joka voidaan periyttää on luokka johon kerätään luokkien yhteisiä tietoja UML-kaaviossa abstraktin luokan nimi kirjoitetaan kursiivilla Action +excecute() : String DeleteAction EditAction InsertAction ListAction UpdateAction +excecute() +excecute() +excecute() +excecute() +excecute() määritellään abstract-määreellä public abstract class Action sen aliluokille voidaan luoda olioita, mikäli ne eivät ole abtrakteja luokkia
20(37) Kun luokka määritellään abstraktiksi: sille voidaan määritellä abstrakteja metodeja abstrakti metodi: määritellään abstract-määreellä eli näkyvyys abstract metodi ( parametrit ); esim. public abstract String excecute (HttpServletRequest req,httpservletresponse res) throws IOException, ServletException, SQLException; abstrakti metodi on korvattava luokan aliluokissa yliluokka vaatii, että sen aliluokilla on kyseinen metodi (ns. metodien nimeämisstandardi) jos yliluokassa määriteltyä abstraktia metodia ei korvata aliluokassa kääntäjä haluaa, että aliluokasta tehdään abstrakti luokka abstraktia metodia ei toteuteta abstraktissa luokassa Kun luokkaan lisätään yksikin abstrakti-metodi: luokka on määriteltävä abstraktiksi
21(37) MONIMUOTOISUUS (polymorfism) on eri olioiden kykyä vastata samaan viestiin eri tuloksella kun olion viittaaman muuttujan luokka on eri kuin olion luokka eli Action actionolio = new InsertAction(); kun olion metodia kutsutaan, ajonaikana tapahtuu ns. dynaaminen sidonta eli metodia haetaan ensin olion luokasta ja jos metodia ei löydy, olion yliluokasta jne Kääntäjä hakee ohjelmaa käännettäessä metodia muuttujan luokasta eli Action-luokasta, joka löytyy sieltä
22(37) esim. Action actionolio = new InsertAction(); actionolio.excecute(req, res) Ohjelman ajoaikana excecute-metodia haetaan olion luokasta eli InsertAction-luokasta, jos metodi on toteutettu siellä, se valitaan, mutta jos ei, metodia haetaan InsertAction-luokan yliluokasta eli Action-luokasta. Jos metodi löytyy, se suoritetaan, mutta jos ei, metodia haetaan Object-luokasta Viittausmuuttujat ja periytyminen Periytymisen idea mahdollistaa, että olion viittaavan muuttujan tyyppi voi olla eri kuin olion tyyppi Olioon viittaavan muuttujan tyyppi voi olla luokkahierarkkiassa olion yläluokan tyyppi tai olion luokan tyyppi, mutta ei olion alaluokan tyyppi eikä ns. sisar-luokan tyyppi
23(37) Object A_luokka B_luokka C_luokka D-luokka E-luokka E-luokan olioon viittava muuttujan tyyppi voi olla: E-luokka, C-luokka, A-luokka tai Object-luokka
24(37) Dynaaminen sidonta Käännösaikana metodin kutsun yhteydessä kääntäjä tutkii muuttujan tyypin ja tarkastaa, että muuttujan luokalla tai sen yliluokalla on kutsuttu metodi. Dynaaminen sidonta tapahtuu ohjelma suoritusaikana olion metodin kutsussa, kun olion tyyppi on eri kuin olioon viittaavan muuttujan tyyppi Kun dynaaminen sidonta tapahtuu, etsitään kutsuttua metodia ensin olion luokasta, jos ei löydy tämän yliluokasta jne.
25(37) Mitä sitten kun aliluokalla on metodi, jota yliluokalla ei ole? Koira -nimi : String -syntymavuosi : int +Koira() +Koira(in nimi : String, in vuosi : int) +Koira(in koira : Koira) +setnimi(in nimi : String) +setsyntymavuosi(in vuosi : int) +getnimi() : String +getsyntymavuosi() : int +tostring() : String RotuKoira -rotu : String +RotuKoira() +RotuKoira(in nimi : String, in vuosi : int, in rotu : String) +RotuKoira(in koira : RotuKoira) +tostring() : String +setrotu(in rotu) +setrotu(string rotu) +getrotu() : String +getrotu():string public class KoiraSovellus private ArrayList <Koira> lista; private Scanner input; public KoiraSovellus() lista = new ArrayList<Koira>(); input = new Scanner(System.in); public void aja()...
26(37) // lisätään parametrina oleva Koira-olio tai RotuKoira-olio // listaan private void lisaakoira(koira koira) String nimi,rotu; RotuKoira apu=null; int vuosi; do System.out.println("Anna koiran nimi:"); nimi = input.nextline(); koira.setnimi(nimi); while (koira.getnimi()==null); do System.out.println("Anna koiran syntymävuosi:"); vuosi = input.nextint(); input.nextline(); koira.setsyntymavuosi(vuosi); while (koira.getsyntymavuosi()!= vuosi); // koiran rotu pyydetään ainoastaan, jos parametri koira viittaa Rotukoira-olioon if (koira instanceof RotuKoira) do System.out.println("Anna koira rotu"); rotu = input.nextline(); apu apu = = (RotuKoira)koira; apu.setrotu(rotu); //tyyppimuunnos while (apu.getrotu()==null); lista.add(koira); // lisää Koira-/RotuKoira-olio listaan
27(37) tyyppimuunnos private void tulosta() for (int i=0;i<lista.size();i++) // tutki ensin onko käsiteltävä olio aliluokan olio if (lista.get(i) instanceof RotuKoira) RotuKoira apu = (RotuKoira)lista.get(i); System.out.println("Koiran nimi on "+ apu.getnimi() + ", rotu on " + apu.getrotu() + " ja on syntynyt vuonna " + lista.get(i).getsyntymavuosi()); else // tutki sitten vasta onko käsiteltävä olio yliluokan olio if (lista.get(i)instanceof Koira) System.out.println("Koiran nimi on " + lista.get(i).getnimi() + " ja on syntynyt vuonna " + lista.get(i).getsyntymavuosi()); public static void main( String[] args)..
28(37) TYYPPIMUUNNOS LUOKKAHIERARKIASSA aliluokan olio voidaan tyyppimuuttaa yliluokan olioksi ( Yliluokka ) aliluokanolio YHTEENVETO MONIMUOTOISUUDESTA Aliluokan olioon voidaan viitata yliluokan muuttujan avulla Aliluokan metodien kutsuminen onnistuu yliluokan tyyppisen viittausmuuttujan avulla, kunhan kutsuttava metodi on määritelty yliluokassa Aliluokan metodien kutsuminen ei onnistu yliluokan tyyppisen viittausmuuttujan avulla, jos kutsuttava metodi ei ole määritelty yliluokassa ainoastaan aliluokassa. Ratkaisu on apu-muuttuja ja tyyppimuunnos: System.out.println("Anna koira rotu"); rotu = input.nextline(); RotuKoira RotuKoira apu apu = (RotuKoira)koira; (RotuKoira)koira; // tyyppimuunnos apu.setrotu(rotu); Yliluokan olioon ei voi viitata aliluokan tyyppisen viittausmuuttujan avulla Aliluokan olioita voidaan käsitellä kuten yliluokan olioita.
29(37) Rajapinta (interface) rajapintojen avulla määrätään, mitä metodeja luokan tulee sisältää, jos tämä ns. toteuttaa rajapinnan nyt ei enää puhuta periytymisestä vaan rajapinnan toteuttamisesta rajapinta sisältää vain abstrakteja metodeja rajapinta ei sisällä attribuutteja luokat toteuttavat rajapinnan implements määreellä Esim. public class Tietokone implements Taltioitava UML-kaaviossa rajapinnan nimen edessä <<interface>> merkintä «interface» Taltioitava Tietokone Rajapinnan toteuttaminen: nuolityyppi kuten periytymisessä, mutta katkoviiva
30(37) Rajapinta määritellään seuraavasti public interface Taltioitava Esim. jossa rajapintaa on määritelty vakioita public interface VAKIOT public static final int YKSI = 1; public static final int KAKSI = 2; public static final int KOLME = 3;
31(37) KERTAUS Yhteyssuhde: A * 1 B A:n yhteys B:hen luetaan viivan B päästä eli A:lla on täsmälleen yhteen B:hen yhteys Ja vastaavasti B:n yhteys A:han luetaan viivan A päästä eli B:lla on nollaan tai useisiin A-olioihin yhteyksiä Siihen luokkaan, jolla on yhteys NOLLAAN tai YHTEEN toisen luokan olioon, lisätään attribuutiksi viittaus yhteydessä olevan luokan olioon eli public class A private B yhteys; Jos luokkien välillä on yhden suhde yhteen, viittaus lisätään siihen luokkaan, jonka kautta yleensä kumpaakin tietoa käsitellään.
32(37) Esim. Oy Yritys Ab 17.4.2009 Saahankatu 78 00890 Hki Tuote maara á hinta hinta yht A23 Harja 10 2.80 28.0 B67 Luuta 100 2.50 250.0 Yhteensä: 278.0 EUR Luokkakaavio: ASIAKAS 1 * TILAUS 1 PVM 1..* TILAUSRIVI 1 TUOTE *
33(37) Mihin luokkiin laitetaan viittaukset yhteyssuhteessa oleviin luokkiin? public class Tilaus private Asiakas tilaaja;. public class Tilausrivi private Tilaus tilaus; private Tuote tuote;. Miten yhteyssuhde attribuuttina toteutetaan? Olio, johon viitataan toisesta luokasta, o elää omaa elämäänsä, o sen elinikä EI ole sidoksissa siihen luokkaan, jossa se on ns. yhteyssuhdeattribuuttina, o sillä saattaa olla useita muita yhteyksiä eri luokkiin ja niiden elämä pitää jatkua vaikka viittaaja kuolisikin Oletusmouodostin, laita yhteyssuhdetta kuvaavan attribuutin arvoksi null public Tilaus() tilaaja = null;
34(37) Parametrillisessa muodostimessa yleensä tuodaan viitattava olio parametrina public Tilaus (,Asiakas tilaaja) this.tilaaja = tilaaja; Kopiointimuodostimessa kopioitu olio viittaa samaan ilmentymään kuin kopioitava olio public Tilaus (Tilaus olio) this.tilaaja = olio.tilaaja; getattribuutti, jossa Attribuutti on yhteyssuhteessa oleva olio public Asiakas gettilaaja() return tilaaja; setattribuutti, jossa Attribuutti on yhteyssuhteessa oleva olio public void settilaaja(tilaaja tilaaja) this.tilaaja = tilaaja;
35(37) Koostumussuhde TILAUS PVM public class Tilaus private Pvm tilauspvm; Koosteluokka sisältää osaluokkia eli Tilaus-luokka on koosteluokka, joka sisältää osaluokan Pvm Koostumussuhteessa oleva osaluokka elää täysin koosteolion elämän mukaan eli se syntyy koosteluokassa ja kuolee, kun koosteluokkakin kuolee Yleensä oletusmuodostimessa osaluokaan viittaavan attribuutin arvoksi laitetaan null public Tilaus() tilauspvm = null; Parametrillisessa muodostimessa, jossa osaluokan olio on parametrina, yleensä kopioidaan parametrina oleva olio public Tilaus(Pvm pvm) if (pvm!= null) tilauspvm = new Pvm (pvm); else tilauspvm = null;
36(37) Kopiointimuodostimessa kopioitavalle luodaan oma osaluokan olio public Tilaus(Tilaus olio) if (olio!= null && olio.tilauspvm!= null) tilauspvm = new Pvm (olio.tilauspvm); else tilauspvm = null; getattribuutti, jossa attribuutti on koosteolion osaolio public Pvm gettilauspvm() Pvm apu = null; if (tilauspvm!= null) apu = new Pvm (tilauspvm); return apu; setattribuutti, jossa attribuutti on koosteolion osaolio public void settilauspvm(pvm pvm) tilauspvm = null; if (pvm!= null) tilauspvm = new Pvm (pvm);
37(37) Esimerkki: yhdellä ajoneuvolla voi olla nolla tai useita omistuksia Yksi omistus kohdistuu vain yhteen ajoneuvoon ja yhteen henkiloon Ajoneuvo -rekisterinumero : String -merkki : String -lukema : int -keskikulutus : double 1 * Omistus * 1 -hinta : double 1 ostopvm 1 Henkilo -etunimi : String -sukunimi : String HenkiloAuto -henkilolkm : int KuormaAuto -kantavuus : double Pvm Yhdellä henkilolla voi olla omistuksessaan nolla tai useita ajoneuvoja Omistus kuvaa yhden ajoneuvon ja yhden omistajan suhdetta. Luokan attribuutit ovat seuraavat: private Ajoneuvo ajoneuvo; private Henkilo omistaja; private double hinta; private Pvm ostopvm; // yhteyssuhde // yhteyssuhde //koostumussuhde