tifyty

pure Java, what else ?

Többszörös öröklődés

Java nyelvben nincs többszörös öröklődés. Miért nincs? Az első válasz, ami definitív az az, hogy azért, mert a nyelv specifikációja nem engedi meg: persze ez a válasz nem elégít ki sok embert, és mint a hároméves elkezdi kérdezgetni, hogy “demiértt?”.

Innentől kezdve a válasz már csak találgatás, stílus, ízlés és hitvita kérdése. Persze azért nem engedi meg a szabvány a többszörös öröklődést, mert nem egyértelmű. Mi van akkor, ha két ősosztályban is definiálva van ugyanaz a metódus? Akkor az öröklő osztályban melyik lesz örökölve. Persze más nyelvekben erre is van megoldás, csak éppen nem biztos, hogy ez a megoldás olvasható, jól karbantartható kódot eredményez. Mert ha azt mondom, hogy például legyen az, amelyik az extends kulcsszó után az első helyen szerepel, akkor már szigorúan számítani fog a sorrend (most persze nincs, mert csak egy osztály neve lehet ott, de például az implements után lehet több interfész, és mindegy a sorrend). És ha egy osztály csak egy másik osztálytól örökölt, és valamiért felveszünk még egyet, és az más implementációt ad egy korábbi metódusra, akkor kereshetjük a hibát sokáig.

Lehetne azt is mondani, hogy ebben az esetben nem lehet ettől a két osztálytó örökölni. Ez viszont gondokat okozna a fordítónak, és a runtime környezetnek, mert nem feltétlenül ugyanazok az osztály implementációk vannak fordításkor és futtatáskor. Ezt ugyan valamennyire ellenőrzi a JVM, hogy ne legyen ellentmondás, de végig kellene alaposan gondolni, hogy milyen gondok lehetnek ebből.

Van olyan megközelítés is, ahol mind a két metódust örökli a leszármazott osztály, és annak függvényében kerül egyik, vagy másik metódus meghívásra, hogy a hívási helyen melyik apa osztály típusára cast-olom éppen a kifejezésemet.

Na ezekre mondta azt a Java, hogy NEM. Ezekkel mind nem akarunk megküzdeni, mert csak nehézségeket okoz, akármelyik megközelítést is használnánk a nyelvben mindig lenne vita, hogy miért az és miért nem a másik, sok hiba forrása lenne, hogy nem egyértelmű az öröklődés, és ami a legfontosabb: tök fölösleges az egész. (Vagy nem. Ez is lehet vita tárgya, de a vita a kisebb gond, a nagyobb a hibás kódok tömkelege.)

Elékezzünk rá, hogy amikor a Java elindult, akkor azzal kezdett megküzdenie, hogy elfogadja-e az ipar, vagy sem. A létéért küzdött a fejlesztő csapat, és nem volt mögötte olyan monopolisztikus nyomás, mint a .NET mögött, amelyik azt mondta volna, hogy erre van előre és aki nem erre jön, az mehet amerre lát, de arra út nincs. Ezért minden olyan konstrukció (például többszörös öröklődés), amelyik a hibás használatot, a több hibás kódot növelte volna kikerült a nyelvből. Nem akarták, hogy a Java a “hibásan működő program” szinonímája legyen. Ezért is lett például a StringBuffer szinkronizált, és csak nagyon sokára jelent meg a StringBuilder amelyik hatékonyabb.

No és mi van az interfészkekkel? Mi van akkor, ha két interfészket is implementál az osztályunk, és mondjuk mind a kettő deklarál ugyanolyan nevű és ugyanolyan szignatúrájú metódust? Melyiket kelteti ki, implementálja az osztályunk?

A válasz egyszerű: mind a kettőt egy metódusban, hiszen az interfész nem definiál, nem mondja meg, hogy hogyan kell működnie a metódusnak, csak deklarál. Az persze más kérdés, ha a JavaDoc és az elvárásaink ellentmondásosak, de ezzel nem tud mit kezdeni a fordító. Ebben az esetben a programozónak kell odafigyelnie, és valószínűleg refaktorálnia valamelyik interfészt: ha ugyanaz a metódus neve, de egészen mást kell csinálnia, akkor valószínűleg az a név nem jó.

És mi a helyzet akkor, ha a metódus visszatérési értéke nem kompatibilis, az egyik interfészben mást ad vissza a metódus, mint a másikban, de a neve, szignatúrája azonos. Akkor nem írhatom ki, hogy implementálja az osztályom mind a két interfészt?

És akkor itt állj meg és gondolkodj el ezen, mielőtt tovább olvasod!

A válasz már nem olyan egyszerű, de logikus, és nagyon Java. A fordító megengedi, hogy deklaráljad: implementálod mind a két interfészt. Csak éppen nem fogod tudni. Vagy az egyik, vagy a másik interfész kerül implementálásra a kódodban. Hát ez van.

12 responses to “Többszörös öröklődés

  1. BT október 10, 2012 4:41 du.

    Az én véleményem. Én nagyon szeretném ezt a funkciót mert vannak helyzetek amit ennek segítségével lehetne szépen megvalósítani, e nélkül ilyen Helper, Support, Util osztályokra van szükség amitől a hideg kiráz.

    Ha nem egyértelmű az öröklődés mert duplikált deklaráció van akkor a fordító jelezze és kötelező legyen felül definiálni. Itt adhatnál meg saját implementációt és de ha akarod hívhatnád a szülő osztályok megfelelő metódusát: A.super.mymethod() formában mint ahogy van A.this.mymethod() hívás is.

    Szerintem ez egyszerű és szép megoldás lenne.

  2. Janos Haber október 10, 2012 5:01 du.

    Az en velemenyem hogy ha akartak volna meglehetne oldani. Szemelyszerint nekem Scala mixin rendszere tetszik a legjobban ( http://www.scala-lang.org/node/117 )… de izlesek es pofonok.

  3. inv október 10, 2012 6:00 du.

    “És mi a helyzet akkor, ha a metódus visszatérési értéke nem kompatibilis, az egyik interfészben mást ad vissza a metódus, mint a másikban, de a neve, szignatúrája azonos.”

    Nem vagyok egy nagy szaki, de a szignatúrának nem része a visszatérési érték típusa?

  4. Mefi október 11, 2012 12:23 de.

    Valószínűleg csak nagyon csőlátásom van, mivel sosem dolgoztam komolyabban más technológiával, de a többszörös öröklődésről mindig az jutott eszembe, hogy nem sikerült jól meghatározni az osztály felelősségeit. 🙂

    • v október 11, 2012 8:54 de.

      Ebben az eseteben nem kellene engedni a több interface implementálását sem.

      Nézzük a következő példát. Írok mondjuk egy BASIC interpretert. Ebben vannak osztályok, amelyek a szintaktikus elemzést végzik. Ezek mindegyikének van egy analize() metódusa, ezért mindegyik implementálja az Analyzer interface-t.

      Vannak más osztályok, többek között a a szintaktikus elemzőt végzők között is, amelyeket egy absztakt factory menedzsel. Ezek mindegyike implementálja a FactoryManaged interfacet, amelyikben a setFactory és a getFactory metódusok vannak. Ezt implementálni kell a normál hierarchia struktúrában minden osztály csoportban. A lexikális elemzőkben, a szintaktikus elemzőkben, a readerekben, a végrehajtó osztályok hierarchiájában lehetőleg valamilyen abstract szinten.

      Ez copy/paste. Miért nem lehet örökölni az implementációt is?

      Persze az igazán szép megoldás az aspektus orientált programozás, mondjuk AspectJ, hiszen a factory menedzseltség tipikusan egy aspektus. De az már megint nem Java.

  5. tvik október 11, 2012 9:12 de.

    Nekem is a Scala mixin rendszere jön be, ami Java-ra lefordítva delegate-eket jelent. Nem hiányzik a többszörös öröklődés.

  6. Laci október 11, 2012 3:51 du.

    Nem a műveletekkel van a gond a többes öröklődésnél, hanem az adatokkal. Ha az őst kétszer implementálod, a műveleteket meg lehet oldani, végül is függvény pointerek fordítási időben belőve, ezért is megengedett több interface öröklése, de ha van egy kétszer megörökölt int-ed, akkor futási időben nincs jó megoldás. Trükközéssel sem.

    Másrészt interface-ek implementált műveleteit is lehet örököltetni, nem kell állandóan implementálni, erre jó többek között az extension. Oksa, virtual meg static így nincs (bár a virtual-t bizonyos megkötésekkel meg lehet trükközni).

  7. Gábor Garami (@hron84) október 14, 2012 10:30 du.

    Aztan ez az egesz sztori ujra atbeszelesre kerulhet par honapon belul, amikor is kiaraszol a Java 8, benne az alapertelmezett implementaciokat is tartalmazo interfeszekkel. Hat nagyon erdekel a vege, azt kell mondjam.

  8. Visszajelzés:2012 in review | tifyty

Vélemény, hozzászólás?

Adatok megadása vagy bejelentkezés valamelyik ikonnal:

WordPress.com Logo

Hozzászólhat a WordPress.com felhasználói fiók használatával. Kilépés / Módosítás )

Twitter kép

Hozzászólhat a Twitter felhasználói fiók használatával. Kilépés / Módosítás )

Facebook kép

Hozzászólhat a Facebook felhasználói fiók használatával. Kilépés / Módosítás )

Google+ kép

Hozzászólhat a Google+ felhasználói fiók használatával. Kilépés / Módosítás )

Kapcsolódás: %s

%d blogger ezt kedveli: