Java: Abstraktní třídy, dědičnost a rozhraní

Z MiS
(Rozdíly mezi verzemi)
Přejít na: navigace, hledání
(Dědičnost: Doplnění textu, přidán příklad.)
(Doplnění abstraktních tříd.)
 
(Není zobrazeno 6 mezilehlých verzí od 1 uživatele.)
Řádka 2: Řádka 2:
  
 
== Dědičnost ==
 
== Dědičnost ==
*Klíčové slovo <code>extends</code>.
+
 
*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říklad
+
<div class="Priklad">
 +
public class Zivocich {
 +
    ...
 +
}
 +
public class Moucha '''extends''' Zivocich {
 +
    ...
 +
}
 +
</div>
 +
 
 +
 
 +
=== 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.
 +
 
 +
<div class="Priklad">
 +
public class Zivocich {
 +
    ...
 +
    public void hybejSe() { this.move(5); } ''// Živočichové se pohybují vpravo.''
 +
    ...
 +
}
 +
public class Moucha '''extends''' Zivocich {
 +
    ...
 +
    '''@Override'''
 +
    public void hybejSe() {
 +
        this.turn(30);
 +
        ''// Moucha se nebude pohybovat, jen se bude točit na místě!''
 +
    }
 +
    ...
 +
}
 +
</div>
 +
 
 +
=== Odkaz na kód předka ('''super''') ===
 +
* 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 53:
 
     ...
 
     ...
 
  }
 
  }
  public class KamionSPrivesem extends Kamion {
+
  public class KamionSPrivesem '''extends''' Kamion {
 
     Prives prives;
 
     Prives prives;
 
     ...
 
     ...
 +
    '''@Override'''
 
     public int getNosnost() {  
 
     public int getNosnost() {  
         return this.getHodnota()+this.prives.getHodnota();  
+
         int nosnostKamionu = '''super'''.getNosnost(); ''// Volání překryté metody předka.''
 +
        return nosnostKamionu+this.prives.getNosnost();  
 
     }
 
     }
 
     ...
 
     ...
 
  }
 
  }
 
+
</div>
== Abstraktní třída ==
+
<div class="Priklad">
* Klíčové slovo <code>abstract</code>.
+
public class World {
* Těla některých metod nejsou uvedena.
+
    ...
 +
    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í ==
 
* Klíčové slovo <code>implements</code>.
 
* Klíčové slovo <code>implements</code>.
 
* Může mít pouze hlavičky metod a veřejné konstantní atributy.
 
* 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í
 +
 +
<div class="Priklad">
 +
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.''
 +
}
 +
</div>
 +
 +
; Třída, která implementuje rozhraní
 +
<div class="Priklad">
 +
public class Prisera '''implements''' Zasahnutelne {
 +
 +
    ''...''
 +
    ''... 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);
 +
    }
 +
</div>
 +
 +
== Abstraktní třída ==
 +
* Klíčové slovo <code>abstract</code>.
 +
* Nelze vytvořit instance této třídy.
 +
* Abstraktní třídu lze ale použít jako společného předka dalších metod, které už abstraktní být nemusí.
 +
 +
<div class="Priklad">
 +
public '''abstract''' class Predmet {
 +
 +
    ''...''
 +
}
 +
</div>
 +
 +
=== Abstraktní metody ===
 +
* Abstraktní třída může mít abstraktní metody.
 +
* U&nbsp;takových metod není uveden kód, který se bude provádět, pouze fakt, že metoda ve třídě musí být.
 +
* Pokud potomci nebudou abstraktní, musí ke každé abstraktní metodě uvést konkrétní kód.
 +
 +
<div class="Priklad">
 +
public '''abstract''' class Predmet {
 +
    '''...'''
 +
 +
    public '''abstract''' void pouzij()''';'''
 +
 +
    '''...'''
 +
}
 +
 +
public class Mic extends Predmet {
 +
 +
    '''...'''
 +
 +
    public void pouzij()
 +
    {
 +
        ''... // Co se má stát při volání metody pouzij().''
 +
    }
 +
 +
    '''...'''
 +
}
 +
</div>
 +
 +
 +
== 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 <code>new Rozhrani()</code>).
 +
* 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.
 +
 +
 +
== 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&nbsp;konkrétním typem aktéra
 +
 +
Prekazka prekazka = '''(Prekazka)''' this.getOneIntersectingObject(Prekazka.class);
 +
if (prekazka != null) {
 +
    int prekazka.getPruhlednost();
 +
    ...
 +
}
 +
 +
* GUI pomocí knihovny Swing &mdash; zjištění zdroje události
 +
 +
public void actionPerformed(ActionEvent event) {
 +
    Button zdroj = '''(Button)''' event.getSource();
 +
    zdroj.getTitle();
 +
    ...
 +
}
 +
 +
<div class="Varovani">Pozor, musíme si být stoprocentně jisti, že objekt, který je uložen v&nbsp;proměnné datového typu <code>Predek</code> je ve skutečnosti opravdu datového typu <code>Potomek</code>. Pokud by nebyl, běh programu by skončil výjimečný stavem a aplikace by havarovala.</div>
  
== Viz také ==
+
== Související stránky ==
 
* [[Objektově orientované programování]]
 
* [[Objektově orientované programování]]

Aktuální verze z 24. 2. 2020, 14:31


Obsah

Dědičnost

public class Zivocich {
    ...
}
public class Moucha extends Zivocich {
    ...
}


Překrývání metod

public class Zivocich {
    ...
    public void hybejSe() { this.move(5); } // Živočichové se pohybují vpravo.
    ...
}
public class Moucha extends Zivocich {
    ...
    @Override
    public void hybejSe() { 
        this.turn(30); 
        // Moucha se nebude pohybovat, jen se bude točit na místě!
    }
    ...
}

Odkaz na kód předka (super)

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í

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 implements Zasahnutelne {

    ... 
    ... 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

public abstract class Predmet {

    ... 
}

Abstraktní metody

public abstract class Predmet {
    ...
    public abstract void pouzij();
    ...
}
public class Mic extends Predmet {
    ...

    public void pouzij()
    {
        ... // Co se má stát při volání metody pouzij().
    }
    ...
}


Srovnání konceptů

Dědičnost
Rozhraní
Abstraktní třída


Přetypování

Příklady přetypování
Prekazka prekazka = (Prekazka) this.getOneIntersectingObject(Prekazka.class);
if (prekazka != null) {
    int prekazka.getPruhlednost();
    ...
}
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.

Související stránky

Osobní nástroje
Jmenné prostory
Varianty
Akce
Výuka
Navigace
Nástroje