Avatar
Fat Boy
Člen
Avatar
Fat Boy:

Snažím se pochopit, jak funguje dědění v Javě a ve studijních materiálech mám uvedeno:

"Rodičovský podobjekt nemůže poslat překrytelnou zprávu sám sobě. Jakoukoliv překrytelnou zprávu totiž musí poslat znovu „nejvnějšnější“ instanci, v jejíchž útrobách se nachází (dceři, vnučce, pravnučce–prostě té, která už není ničím rodičovským podobjektem)."

Mohl byste mi to prosím někdo osvětlit na nějakém jednoduchém příkladu?

pozn. je to z knihy: Java 7: učebnice objektové architektury pro začátečníky - Rudolf Pecinovsky

https://books.google.cz/books?…

 
Odpovědět 6. května 20:08
Avatar
Atrament
Člen
Avatar
Atrament:

Čtu tu strašlivou větu už asi podesáté, ale nejsem si stoprocentně jistý jestli jsem ji správně pochopil :) Každopádně si myslím, že se autor snaží popsat tohle:

Když máš třídu třeba Vehicle s metodami drive() a driveAndStop(), přičemž metodu drive() voláš v metodě driveAndStop()

public class Vehicle {

    public Vehicle() {

    }

    public void drive() {
        System.out.println("Driving a vehicle");
    }

    public void driveAndStop() {
        drive();
        System.out.println("Stopping a vehicle");
    }

}

Pokud vytvoříš instanci takovéto třídy a zavoláš metodu driveAndStop() tak se vypíše

Driving a vehicle
Stopping a vehicle

tak jak by to člověk čekal.

Pokud ale vytvoříš další třídu, která dědí od Vehicle, s vlastní implementací drive()

 public class Car extends Vehicle{

    @Override
    public void drive() {
        System.out.println("Driving a car");
    }


}

a následně vytvoříš instanci Vehicle a dosadíš implementaci Car a zavoláš driveAndStop()

Vehicle vehicle = new Car();
vehicle.driveAndStop();

uvidíš na výstupu

Driving a car
Stopping a vehicle

prostě se nezavolá metoda drive() z Vehicle, ačkoliv logika by nasvědčovala tomu, že by měla, ale zavolá se metoda drive() z Car. Je to chování, které může vést k docela nepěkným a těžce odhalitelným chybám, proto je na to třeba dávat bacha. Dobrým způsobem jak tomu předcházet, je používat dědičnost z rozmyslem - dělat metody, u nichž je dedění nežádoucí finální, k překrytí nabízet jenom abstraktní metody a tak dále...

 
Nahoru Odpovědět 6. května 21:55
Avatar
B42P6
Člen
Avatar
Odpovídá na Fat Boy
B42P6:

Majme tieto 2 triedy:

class Vehicle
{

        void notOverriden()
        {
                /* Ak je metóda notOverriden volaná na objekte v ktorom je uložený Car,
                   nasledujúci riadok zavolá start() v triede Car a nie v triede Vehicle
                   (takže Vehicle nemôže zavolať start() na sebe, ak sme do neho uložili Car)*/

                  this.start(); //toto je bod a
        }

        void start()
        {
                System.out.println("Starting vehicle");
        }
}

class Car extends Vehicle
{
        void start()
        {
                System.out.println("Starting Car");
        }
}

Ak budeme metodu notOverriden volat na premennej v ktorej je ulozeny objekt typu Car:

Car a = new Car(); // do premennej a ukladame objekt typu Car
Vehicle b = new Car(); // do premennej b ukladame objekt typu Car
Vehicle c = new Vehicle(); // do premennej c ukladame objekt typu Vehicle

a.notOverriden();
b.notOverriden();
c.notOverriden();

a.notOverriden(), zavolá v bode a metódu v triede Car, pretože je v premennej a uložený objekt typu Car

b.notOverriden(), zavolá v bode a metódu v triede Car, pretože je v premennej b uložený objekt typu Car (aj keď je premenná b sama o sebe typu Vehicle)

c.notOverriden() zavolá v bode a metódu v triede Vehicle, pretože je v premennej c uložený objekt typu Vehicle

Skús si to spustiť aby si si to overil.

Ta veta je dosť zvláštne napísaná, až neskor ma napadlo že "poslať správu", znamená zavolať metódu.

Editováno 6. května 23:01
Nahoru Odpovědět 6. května 22:59
'long long long' is too long for GCC
Avatar
Lubor Pešek
Člen
Avatar
Odpovídá na Atrament
Lubor Pešek:

Jako v podstatě ta definice dává smysl, ale aby to vypadalo, že jsou programátoři chytřejší, tak je to napsané složitě:) Do češtiny by se to dalo přeložit asi takto:

Rodičovský podobjekt nemůže poslat překrytelnou zprávu sám sobě.
Třída, která je předek a ze které se dědí, nemůže překrývat své metody (taky je to blbost, proč by si předek měl něco překrývat, když je první, kdo ty metody definuje:) ).

Jakoukoliv překrytelnou zprávu totiž musí poslat znovu „nejvnějšnější“ instanci, v jejíchž útrobách se nachází (dceři, vnučce, pravnučce–prostě té, která už není ničím rodičovským podobjektem).
Metodu předka můžou překrývat pouze jeho potomci. Překrytí metody znamená, že je v potomkovi nějaké třídy definovaná metoda, která má stejný název a počet parametrů v metodě, jako nějaká metoda předka. Překrytí znamená, že si tuto metodu potomek definuje sám podle sebe. Pokud ji nedefinuje (nepřekryje) tak se zavolá metoda jeho předka.

Zkusím ti to popsat na matematice:D

public class Matematika{                //předek

        public int soucet(int scitanecA, int scitanecB){
                return scitanecA + scitanecB;
        }

        public static void main(String[] args){
                Matematika matika = new Matematika();
                System.out.println(matika.soucet(5,5));
        }
}

popravdě si nejsem jistý a nechci to testovat:D psal jsem to tady jako kód a nemám ověřené, že tam nejsou chybky:D kdyžtak si je oprav:)
Tak třída Matematika by normálně pomocí návratové metody soucet sečetla 2 parametry, které bys zadal. A teď si představ, že se Matematice narodila nová třída - Zmetek:)

public class Zmetek extends Matematika{ //potomek třídy Matematika, který je naprosto blbý

}

a třída Zmetek už teď díky děnění zná metodu soucet, takže tohle musí fungovat

public class Zmetek extends Matematika{ //potomek třídy Matematika, který je naprosto blbý
        public static void main(String[] args){
                Zmetek blb = new Zmetek();
                System.out.println(blb.soucet(5,5));
        }
}

No a jak už to tak bývá, tak jako každé nevydařené děťátko, tak to co se Zmetek naučil od Matematiky, tak se snaží vydávat za své, ale po svém:

public class Zmetek extends Matematika{ //potomek třídy Matematika, který je naprosto blbý
        public static void main(String[] args){
                Zmetek blb = new Zmetek();
                System.out.println(blb.soucet(5,5));
        }

        public int soucet(int scitanecA, int scitanecB){
                return scitanecA * scitanecB;
        }
}

Ale jak vidíš, tak teď, díky tomu že je to vůl a dělá si to po svém (překryl si metodu svým kódem) tak když tu samou metodu bude teď volat on, tak už bys měl jeho výsledek.

Trošku zpitomělý příklad, ale myslím, že výstižný:D dokonce i ze života:D
Ale trošku si troufnu nesouhlasit s Atramentem: Je to chování, které může vést k docela nepěkným a těžce odhalitelným chybám.
Přesně kvůli tomuhle ti šikovnější programátoři před překrytou metodu dávají slovíčko "@Override". Bez něj sice IDEčko protestuje, ale i tak to bez něj přeloží do bajtkódu a program jde spustit. Ale raději si zvykni na to, že když překryješ metodu předka, tak tam narveš to @Override. Mysli na to, že někdo po tobě ten kód může číst.

public class Zmetek extends Matematika{ //potomek třídy Matematika, který je naprosto blbý
        public static void main(String[] args){
                Zmetek blb = new Zmetek();
                System.out.println(blb.soucet(5,5));
        }

        @Override
        public int soucet(int scitanecA, int scitanecB){
                return scitanecA * scitanecB;
        }
}

A ještě malá poznámečka. Taková definice tě může opravdu zmáct. Tato knížka mi osobně příjde už pro mírně pokročilejší programátory, kteří už mají OOP myšlení. Zkus si sehnat tuhle knížku:
http://www.grada.cz/…iha/katalog/

Nahoru Odpovědět 12. května 15:49
Existují dva způsoby, jak vyřešit problém. Za prvé vyhoďte počítač z okna. Za druhé vyhoďte okna z počítače.
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 4 zpráv z 4.