Java: Abstraktní třídy, dědičnost a rozhraní
Z MiS
(Rozdíly mezi verzemi)
(Přidáno srovnání konstruktů.) |
(Přidán příklad z Greenfootu a klíčové slovo '''super'''.) |
||
| Řádka 2: | Řádka 2: | ||
== Dědičnost == | == Dědičnost == | ||
| − | *Klíčové slovo <code>extends</code>. | + | ; Zápis dědičnosti |
| − | *Třída může mít pouze jednu rodičovskou třídu! | + | * Klíčové slovo <code>extends</code>. |
| + | * Třída může mít pouze jednu rodičovskou třídu! | ||
* Potomek „dědí“ všechny vlastnosti předka. | * Potomek „dědí“ všechny vlastnosti předka. | ||
* Potomek může kdykoli nahradit předka. Takže pokud máme proměnnou datového typu <code>Predek</code>, můžeme do ní uložit instanci třídy <code>Potomek</code>. Opačně to však nejde! | * Potomek může kdykoli nahradit předka. Takže pokud máme proměnnou datového typu <code>Predek</code>, můžeme do ní uložit instanci třídy <code>Potomek</code>. Opačně to však nejde! | ||
| − | ; | + | ; Překrývání metod |
| + | * Potomek automaticky dědí všechny metody předka. Ty může používat jako vlastní metody. | ||
| + | * Potomek ale může metodu nadefinovat znovu, čímž ''překryje'' (''override'') původní chování metody předka. | ||
| + | ; Příklady | ||
| + | <div class="Priklad"> | ||
| + | public class Zivocich extends Actor { | ||
| + | ... | ||
| + | public void act() { this.move(5); } ''// Živočichové se pohybují vpravo.'' | ||
| + | ... | ||
| + | } | ||
| + | public class Moucha '''extends''' Zivocich { | ||
| + | ... | ||
| + | '''@Override''' | ||
| + | public void act() { | ||
| + | this.turn(30); | ||
| + | ''// Moucha se nebude pohybovat, jen se bude točit na místě!'' | ||
| + | } | ||
| + | ... | ||
| + | } | ||
| + | </div> | ||
| + | |||
| + | ; Odkaz na kód předka | ||
| + | * Klíčové slovo <code>super</code>. | ||
| + | * Můžeme odkazovat: | ||
| + | ** Na konstruktor rodičovské třídy. | ||
| + | ** Na překrytou metodu předka. | ||
| + | |||
| + | ; Příklady | ||
| + | <div class="Priklad"> | ||
public class Kamion { | public class Kamion { | ||
int nosnost; | int nosnost; | ||
| Řádka 14: | Řádka 43: | ||
... | ... | ||
} | } | ||
| − | public class KamionSPrivesem extends Kamion { | + | public class KamionSPrivesem '''extends''' Kamion { |
Prives prives; | Prives prives; | ||
... | ... | ||
| + | '''@Override''' | ||
public int getNosnost() { | public int getNosnost() { | ||
| − | + | int nosnostKamionu = '''super'''.getNosnost(); ''// Volání překryté metody předka.'' | |
| + | return nosnostKamionu+this.prives.getNosnost(); | ||
} | } | ||
... | ... | ||
} | } | ||
| − | + | </div> | |
| + | <div class="Priklad"> | ||
| + | public class World { | ||
| + | ... | ||
| + | public World(int rozmerX, int rozmerY, int dilek) { ... } | ||
| + | ... | ||
| + | } | ||
| + | public class MyWorld '''extends''' World { | ||
| + | ... | ||
| + | public MyWorld() { | ||
| + | '''super'''(600, 400, 1); ''// Volání konstruktoru předka.'' | ||
| + | } | ||
| + | ... | ||
| + | } | ||
| + | </div> | ||
== Rozhraní == | == Rozhraní == | ||
Verze z 24. 2. 2020, 14:15
Obsah |
Dědičnost
- Zápis dědičnosti
- Klíčové slovo
extends. - Třída může mít pouze jednu rodičovskou třídu!
- Potomek „dědí“ všechny vlastnosti předka.
- Potomek může kdykoli nahradit předka. Takže pokud máme proměnnou datového typu
Predek, můžeme do ní uložit instanci třídyPotomek. Opačně to však nejde!
- Překrývání metod
- Potomek automaticky dědí všechny metody předka. Ty může používat jako vlastní metody.
- Potomek ale může metodu nadefinovat znovu, čímž překryje (override) původní chování metody předka.
- Příklady
public class Zivocich extends Actor {
...
public void act() { this.move(5); } // Živočichové se pohybují vpravo.
...
}
public class Moucha extends Zivocich {
...
@Override
public void act() {
this.turn(30);
// Moucha se nebude pohybovat, jen se bude točit na místě!
}
...
}
- Odkaz na kód předka
- Klíčové slovo
super. - Můžeme odkazovat:
- Na konstruktor rodičovské třídy.
- Na překrytou metodu předka.
- Příklady
public class Kamion {
int nosnost;
...
public int getNosnost() { return this.nosnost; }
...
}
public class KamionSPrivesem extends Kamion {
Prives prives;
...
@Override
public int getNosnost() {
int nosnostKamionu = super.getNosnost(); // Volání překryté metody předka.
return nosnostKamionu+this.prives.getNosnost();
}
...
}
public class World {
...
public World(int rozmerX, int rozmerY, int dilek) { ... }
...
}
public class MyWorld extends World {
...
public MyWorld() {
super(600, 400, 1); // Volání konstruktoru předka.
}
...
}
Rozhraní
- Klíčové slovo
implements. - Může mít pouze hlavičky metod a veřejné konstantní atributy.
- Implementací rozhraní garantujeme, že naše třída má určité metody.
- Zajišťujeme například to, aby objekty různých tříd šly umístit do kontejneru.
- Deklarace rozhraní
public interface Zasahnutelne {
public void zasah(Strela s);
// Neříkáme, jak se má objekt chovat.
// Jen vyžadujeme, že bude mít tuto metodu.
}
- Třída, která implementuje rozhraní
public class Prisera {
...
... Může mít různé metody a atributy, ale musí mít metodu zasah(...)!!!
...
public void zasah(Strela s) {
// Popíšeme, jak se má reagovat na zprávu/metodu zasah(...).
this.getWorld().removeObject(this);
}
Abstraktní třída
- Klíčové slovo
abstract. - Těla některých metod nejsou uvedena.
Srovnání konceptů
- Dědičnost
- Používáme tehdy, kdy potomek přebírá všechny vlastnosti předka (a případně přidává něco dalšího).
- Třída může mít jen jednoho předka.
- Rozhraní
- Pouze předepisuje, jaké metody má třída mít.
- Nemůžeme z rozhraní převzít hotový kód.
- Nelze vytvořit instanci rozhraní (nelze volat
new Rozhrani()). - Můžeme implementovat kolik rozhraní chceme.
- Je užitečné, když každá třída má na společnou zprávu reagovat jinak.
- Abstraktní třída
- Je jakýmsi mezistupněm, kdy přebíráme kód jen některých metod.
- Nelze vytvářet instance abstraktní třídy.
Odkaz na předka — super
- Jsou situace, kdy potřebujeme změnit chování některé metody předka v potomkovi. Mluvíme o překrývání metod.
- Pokud potřebujeme v potomkovi přesto použít metodu předka, použijeme k tomu klíčové slovo
super. - Klíčovým slovem
superlze také zavolat konstruktor předka.
Přetypování
- Potomek může vždy zastoupit předka. Do proměnné datového typu předka tedy můžeme uložit instanci třídy potomka.
- Jsou ale situace, kdy potřebujeme k takto uloženému potomkovi znovu přistupovat jako k potomkovi včetně všech jeho metod a atributů.
- V tom případě musíme použít přetypování.
- Přetypování zapíšeme tak, že do závorky před výraz, který vrací takto uloženého potomka, zapíšeme název třídy předka.
- Příklady přetypování
- Greenfoot a detekce kolize s konkrétním typem aktéra
Prekazka prekazka = (Prekazka) this.getOneIntersectingObject(Prekazka.class);
if (prekazka != null) {
int prekazka.getPruhlednost();
...
}
- GUI pomocí knihovny Swing — zjištění zdroje události
public void actionPerformed(ActionEvent event) {
Button zdroj = (Button) event.getSource();
zdroj.getTitle();
...
}
Pozor, musíme si být stoprocentně jisti, že objekt, který je uložen v proměnné datového typu
Predek je ve skutečnosti opravdu datového typu Potomek. Pokud by nebyl, běh programu by skončil výjimečný stavem a aplikace by havarovala.