Programozás I. 5. gyakorlat
Objektumorientáltság Egységbezárás és információ elrejtése (absztrakt adattípus) Adatok és rajtuk végzett műveletek egységbezárása (osztályok írása, múlt hét) Öröklődés Polimorfizmus (többalakúság)
Öröklődés Lényege: hasonló osztályokat ne kelljen újra létrehozni, hanem elegendő a már meglévő osztályt módosítani Specializálás és általánosítás specializálás: őstől a gyerek felé (egyre speciálisabb osztályokat látunk) általánosítás: a gyerektől az ős felé (egyre általánosabb osztályokat láthatunk)
Öröklődés Adattagok: Metódusok: újakat hozhatunk létre (az örököltek is megmaradnak) Metódusok: újakat hozhatunk létre már meglévőket írhatunk felül (overriding) Java-ban csak egyszeres öröklődés van (azaz egy gyerekosztály csak egy ősből származik)
Overriding vs overloading Már meglévő metódus felülírása egy gyerekosztályban Azonos név és paraméterlista Overloading: Egy osztályon belüli metódusok Azonos metódusnév, de különböző paraméterlista
Öröklődés Java-ban az extends kulcsszóval class GyerekOsztály extends ŐsOsztály { //... } Az ősosztálytól örökölt privát adattagok részei lesznek a származtatott osztálynak de csak a publikus getter/setter metódusokkal tudjuk őket elérni konstruktorból az ősosztály konstruktorának hívásával, a super kulcsszóval
This/super this: hivatkozás az aktuális objektumra egy másik konstruktorára egy adattagjára super: hivatkozás az ősre hivatkozás az ősosztály egy konstruktorára egy metódusára
Példa: Ősosztály public class Allat{ private String fajnev; private int varhatoElettartam; public Allat(String fajnev, int vElettartam){ this.fajnev = fajnev; this.varhatoElettartam = vElettartam; }
Példa: Gyerekosztály public class Hal extends Allat{ private int uszonyhossz; public Hal(String f, int v, int u){ super(f, v); //Ős konstruktorának hívása uszonyhossz = u; } A Hal rendelkezik az Állat összes adattagjával, valamint egy sajáttal (uszonyhossz)
Polimorfizmus (Többalakúság) Objektumok felcserélhetőségét biztosítja Fordításkor még nem tudjuk, hogy melyik konkrét operáció fog meghívódni (örökölt vagy felüldefiniált) Futás közben derül ki a konkrét típus alapján kései kötés: Java-ban minden metódushívás ilyen Objektumot az őstípusa alapján kezeljük Minden gyerektípus egyben őstípusú is Fordítva nem igaz! Őst váró metódus kaphat gyerek típust is
Polimorfizmus Előnyei: A kód nem függ a specifikus típusoktól Utólag is lehet definiálni származtatottakat Példakód: Test.java
Object (implicit öröklés) Java-ban minden osztály (a beépítettek és az általunk írtak is) implicit módon az Object nevű ősosztályból származik (közvetve vagy közvetlen) tehát az osztályhierarchia tetején mindig az Object áll az Object típusú változó bármilyen objektumra hivatkozhat ha egy metódus Object típusú paramétert vár, akkor annak bármilyen típusú objektumot átadhathatunk
A toString() metódus Az Object osztály biztosít számunkra néhány hasznos metódust, melyet a származtatott osztályok felüldefiniálhatnak (de nem kötelező) pl.: clone() , equals() , hashCode() , finalize() , toString , getClass() , notify() , notifyAll() , wait() Egyik fontos ilyen metódus a toString() A toString() az objektumot Stringként reprezentálja Teszteléskor hasznos lehet
A toString() használata Létrehozunk egy objektumot, majd ha kiíratjuk azt: Jarmu j = new Jarmu(); System.out.println(j); //Jarmu@58c9e870 Ilyen esetben valójában a toString() metódus hívódik meg (automatikusan), amelyet ha nem definiálunk felül, akkor az Object-től örökölt toString() kerül meghívásra Példakód: Superman.java, SMMain.java
Csomagok (packages) Az összetartozó (valamilyen szempont alapján) osztályokat csomagokba szokás szervezni A forráskódban azt, hogy egy adott osztály melyik csomagba tartozik az alábbi módon jelöljük: package csomagnev; A kódban az első nem komment sornak kell lennie! Egy osztálynak a teljes neve: packagenev.OsztalyNev (pl.: Stringjava.lang.String)
Csomagok (packages) Csomag elnevezése: megállapodás által fordított domain elnevezés: pl.: hu.u_szeged.inf inf.u-szeged.hu Az ennek megfelelő mappaszerkezetről gondoskodni kell (hu/u_szeged/inf) Eclipse létrehozza, különben kézzel kell! Ha egy osztály nincs egyetlen csomagban sem, akkor alapértelmezetten egy default csomagba kerül
Csomagok (packages) Egy adott csomagban lévő osztály importálása: import csomagnev.OsztalyNev; Egy adott csomagban lévő összes osztály importálása: import csomagnev.*; Példa: import java.util.ArrayList; import java.util.*;
Csomagok (packages) Egyes csomagok osztályai automatikusan importálódnak a programunkba, anélkül hogy ezt kérnénk Ilyen a java.lang összes osztálya, mint pl.: Wrapper osztályok Kivételek Math osztály, String, stb.. http://docs.oracle.com/javase/8/docs/api/java/lang/package-summary.html
Statikus import import static OsztályNév; Ezek után az osztály összes statikus adattagját elérhetjük, az osztálynév nélkül is: Pl.: a Math.PI helyett használhatjuk PI-t
Névütközések ha két csomagunk is van ugyanolyan nevű osztállyal, névütközés lehet ha mindkettőt használni szeretnénk (amíg nem használunk ilyet, addig nincs baj) explicit ki kell írni a csomag nevét az osztály elé, amikor használjuk: myPackage.Ember e1 = new myPackage.Ember(); myNewPackage.Ember e2 = new myNewPackage.Ember();
Absztrakt osztály Nem példányosítható (Ha megpróbáljuk, akkor fordítási hibát kapunk) Általánosítás: közös interfészt biztosít a leszármazottaknak abstract class Hangszer { ... }
Absztrakt metódus Csak a deklarációja van, definíciója nincs (nincs függvénytörzs) leszármazott osztályokban kell megvalósítani pl.: abstract public void szolj(Hang h); Ha van benne absztrakt metódus, akkor maga az osztály is absztrakt kell legyen Absztrakt metódus nem lehet private és final, hiszen úgy nem lenne értelme (nem lehetne megvalósítani/felüldefiniálni)
Feladatok Feladat (A megoldáshoz használjuk fel a PrivatEmber, Superman és SMMain osztályokat) Készíts egy abstract Ember osztályt. Vidd át a toString metódust az Ember osztályba, majd módosítsd úgy a programot , hogy abstract legyen a toString metódus. A PrivateEmber osztály öröklődjön az Ember osztályból. Probáld ki mit csinál az SMMain program, ha a toString metódust kikommentezed! Helyezd csomagba a privatEmber és a Superman osztályokat. Az SMMain maradjon csomagon kívül.) Definiálj egy Szuperkepessegek interfészt, amelynek van egy void kriptonittalSugároz() függvény osztályban, Implementáld ezt az interfészt a PrivatEmber osztályban, ahol nem csinál semmit (esetleg kiír valamit a konzolra), de definiáld felül a Superman osztályban úgy, hogy az csökkentse a szupererőt. (Az SMMain futtatóosztály is érdemes módosítani, hogy hívja ezt a függvényt valamilyen módon.)
Interfész Olyan osztály, amiben csak absztrakt metódus van Csak egy formát ad, implementáció nélkül Nincs benne az osztályhierarchiában interface Hangszer{ ... }
Interfész Metódusai: impliciten public és abstract nem lehet private és final implements kulcsszóval lehet interfészt implementálni több interfészt is implementálhatunk egyszerre
Interface vs. abstract class egyetlen metódust sem implementálhat implementáljuk több interface-t is implementálhatunk Abstract class: implementálhat metódusokat örököltetjük csak egyszeresen örököltethetünk
Interfész public class Zongora implements Hangszer{ ... } public abstract class AlkoholosItal extends Ital implements Alkoholos{
Instance of Ezzel vizsgálhatjuk meg az objektum típusát public void kutyaE(Object o){ if(o instanceof Kutya){ System.out.println("Ez egy kutya."); } else { System.out.println("Ez nem egy kutya."); }