Wykład 6: Dziedziczenie
Dziedziczenie Jeden z filarów obiektowości. Budowa jednej klasy na bazie drugiej, przez dodawanie/przesłanianie jej składowych: nad-klasa klasa bazowa pod-klasa klasa pochodna od bazowej Pod-klasa jest szczególnym rodzajem nad-klasy.
Składnia Dziedziczenia Składnia: class pod-klasa extends nad-klasa { // treść klasy Każda pod-klasa posiada tylko jedną nad-klasę: Java nie umożliwia wielo-dziedziczenia. Żadna klasa nie jest nad-klasą samej siebie.
Przykład: Klasa Bazowa class A { int i; void pokazi() { System.out.println("i: " + i);
Przykład: Klasa Pochodna class B extends A { int j; void pokazj() { System.out.println("j: " + j); void suma() { System.out.println("i + j: " + (i + j));
Przykład: Klasa Testująca class ProsteDziedziczenie { public static void main(string args[]) { A a = new A(); B b = new B(); Nad-klasa może być używana samodzielnie: a.i = 10; a.pokazi();
Przykład: Klasa Testująca Pod-klasa ma dostęp do wszystkich publicznych składowych swojej nad-klasy: b.i = 7; b.j = 8; b.pokazi(); b.pokazj(); b.suma();
Dziedziczenie i Składniki Prywatne Pod-klasa nie ma dostępu do składowych prywatnych swojej nad-klasy. Składowa zadeklarowana jako private nie jest dostępna poza klasą w której jest zadeklarowana, wliczając jej pod-klasy.
Dziedziczenie i Dostęp, Przykład class A { int i; private int j; void ustalij(int x, int y) { i = x; j = y; class B extends A { int calosc; void suma() { calosc = i + j; // błąd, j niedostępne
Dziedziczenie i Dostęp, Przykład class DziedziczenieDostep { public static void main(string args[]) { B b = new B(); b.ustalij(10, 12); b.suma(); System.out.println("Suma to " + b.calosc);
Kolejny Przykład class Pudelko { double szerokosc; double wysokosc; double glebokosc; Pudelko() { szerokosc = -1; wysokosc = -1; glebokosc = -1; double objetosc() { return szerokosc * wysokosc * glebokosc;
Kolejny Przykład class PudelkoPlus extends Pudelko { double ciezar; PudelkoPlus(double s, double c) { szerokosc = s; wysokosc = s; glebokosc = s; ciezar = c;
Kolejny Przykład class CiezarPudelka { public static void main(string args[]) { PudelkoPlus p1 = new PudelkoPlus(10, 5.5); PudelkoPlus p2 = new PudelkoPlus(2, 0.5); double objetosc; objetosc = p1.objetosc(); System.out.println("Pierwsze: " + objetosc); objetosc = p2.objetosc(); System.out.println("Drugie: " + objetosc);
Odwołanie do Obiektu Podklasy Do zmiennej nad-klasy można przypisać odwołanie do obiektu dowolnej pod-klasy. class NadKlasa {... class PodKlasa extends NadKlasa {... NadKlasa o1; PodKlasa o2 = new PodKlasa(); o1 = o2
Odwołanie Podklasa, Przykład class DziedziczenieOdwolanie { public static void main(string args[]) { PudelkoPlus pp = new PudelkoPlus(10, 0.5); Pudelko p = new Pudelko(); double objetosc; objetosc = pp.objetosc(); System.out.println("Plus: " + objetosc); p = pp; objetosc = p.objetosc(); System.out.println("Pudelko: " + objetosc);
Odwołanie do Obiektu Podklasy Typ zmiennej, nie obiekt na który wskazuje ta zmienna, determinuje osiągalne składowe klasy. To odwołanie byłoby błędem: //System.out.println(p.ciezar);
Użycie Super jako Konstruktora Wywołanie konstruktora nad-klasy: super(lista-parametrow) Musi być pierwszą instrukcją konstruktora podklasy: class NadKlasa {... class PodKlasa extends NadKlasa { PodKlasa(...) { super(...);......
Super jako Konstruktor, Przykład class Pudelko { double szerokosc; double wysokosc; double glebokosc; Pudelko() { szerokosc = -1; wysokosc= - 1; glebokosc =-1; Pudelko(Pudelko p) { szerokosc = p.szerokosc; wysokosc = p.wysokosc; glebokosc = p.glebokosc;...
Super jako Konstruktor, Przykład class PudelkoPlus extends Pudelko { double ciezar; PudelkoPlus() { super(); ciezar = 0; PudelkoPlus(PudelkoPlus p) { super(p); ciezar = 0;...
Super jako Konstruktor, Przykład class SuperKonstruktor { public static void main(string args[]) { PudelkoPlus pp1 = new PudelkoPlus(); PudelkoPlus pp2 = new PudelkoPlus(10, 5.5); PudelkoPlus pp3 = new PudelkoPlus(pp2); double objetosc; objetosc = pp1.objetosc(); System.out.println("Pierwsze " + objetosc); objetosc = pp2.objetosc(); System.out.println("Drugie " + objetosc); objetosc = pp3.objetosc(); System.out.println("Trzecie " + objetosc);
Super jako Konstruktor, Przykład Przesyłamy obiekt pod-klasy: PudelkoPlus(PudelkoPlus p) { super(p); ciezar = 0; do konstruktora który oczekuje obiekt nad-klasy: Pudelko(Pudelko p) { szerokosc = p.szerokosc; wysokosc = p.wysokosc; glebokosc = p.glebokosc;
Odwołanie do Nad-Klasy przez Super Odwołanie do elementu nad-klasy: super.pole super.metoda() Stosowany szczególnie gdy składowe pod-klasy przesłaniają składowe nad-klasy o tych samych nazwach.
Super, Przykład class A { int i; Przesłonięcie pola w nad-klasie: class B extends A { int i; B(int a, int b) { super.i = a; i = b;
Super, Przykład void pokaz() { System.out.println("nad-klasa: " + super.i); System.out.println("pod-klasa: " + i); class SuperPrzesloniecie { public static void main(string args[]) { B b = new B(1, 2); b.pokaz();
Hierarchia Wielo-Poziomowa class PudelkoPlusPlus extends PudelkoPlus { double koszt; PudelkoPlusPlus() { super(); koszt = -1; PudelkoPlusPlus(double s, double c, double k) { super(s, c); koszt = k; PudelkoPlusPlus(PudelkoPlusPlus p) { super(p); koszt = p.koszt;
Hierarchia Wielo-Poziomowa class Przesylka { public static void main(string args[]) { PudelkoPlusPlus pp1 = new PudelkoPlusPlus(10,5,15); PudelkoPlusPlus pp2 = new PudelkoPlusPlus(2, 3, 5); double objetosc; objetosc = pp1.objetosc(); System.out.println("Pierwsze " + objetosc); objetosc = pp2.objetosc(); System.out.println("Drugie " + objetosc);
Porządek Wywołań Konstruktorów W hierarchii klas, najpierw wywołujemy konstruktory nad-klasy, potem pod-klasy. Jeżeli super() nie jest użyte, wywołuje się domyślny bez-parametrowy konstruktor każdej nad-klasy.
Porządek Wywołań Konstruktorów class A { A() { System.out.println("A"); class B extends A { B() { System.out.println("B");
Porządek Wywołań Konstruktorów class C extends B { C() { System.out.println("C"); class PorzadekKonstruktorow { public static void main(string args[]) { C c = new C();
Przesłanianie Metod Kiedy metoda pod-klasy ma tą samą nazwę i typ jak metoda nad-klasy, wtedy mówimy że przesłania ją. Wersja metody dla nad-klasy zostaje ukryta.
Przesłanianie Metod, Przykład class A { int i, j; A(int a, int b) { i = a; j = b; void pokaz() { System.out.println("i i j: " + i + j);
Przesłanianie Metod, Przykład class B extends A { int k; B(int a, int b, int c) { super(a, b); k = c; void pokaz() { System.out.println("k: " + k);
Przesłanianie Metod, Przykład class Przeslon { public static void main(string args[]) { B b = new B(1, 2, 3); b.pokaz();
Super i Przesłanianie Metod Wywołanie przesłoniętej metody nad-klasy przez super: class B extends A { int k; B(int a, int b, int c) { super(a, b); k = c; void pokaz() { super.pokaz(); System.out.println("k: " + k);
Przesłanianie czy Przeciążenie? Przesłanianie metod następuje tylko gdy nazwy i sygnatury dwóch metod są identyczne. class B extends A { int k; B(int a, int b, int c) { super(a, b); k = c; void pokaz(string wiadomosc) { System.out.println(wiadomosc + k);
Przesłanianie czy Przeciążenie? class Przeladowanie { public static void main(string args[]) { B b = new B(1, 2, 3); b.pokaz("oto k: "); b.pokaz();
Dynamiczne Wywołanie Metod Przesłanianie umożliwia dynamiczne wywołanie metod. Odwołanie do przesłoniętej metody przez zmienną super-klasy: Java ustala wersję metody na podstawie faktycznego typu obiektu wskazywanego przez zmienną. Wykonywany kod decyduje się w czasie rzeczywistym, nie w czasie kompilacji.
Dynamiczne Wywołanie, Przykład class A { void wywolajmnie() { System.out.println("A"); class B extends A { void wywolajmnie() { System.out.println("B"); class C extends A { void wywolajmnie() { System.out.println("C");
Dynamiczne Wywołanie, Przykład class DynamiczneWywolanie { public static void main(string args[]) { A a = new A(); B b = new B(); C c = new C(); A z; z = a; z.wywolajmnie(); z = b; z.wywolajmnie(); z = c; z.wywolajmnie();
Polimorfizm Jeden interfejs, wiele zachowań: nad-klasa definiuje wspólne metody dla pod-klas pod-klasa dostarcza specyficzne implementacje dla niektórych z tych metod Swoboda definicji własnych metod przez pod-klase, pod rygorem zachowania interfejsu dla tych metod. Kombinacja dziedziczenia i przesłaniania: nad-klasa opisuje format metod realizowanych przez pod-klasę.
Polimorfizm, Przykład class Figura { double d1; double d2; Figura(double a, double b) { d1 = a; d2 = b; double powierzchnia() { System.out.println("Niezdefiniowana"); return 0;
Polimorfizm, Przykład class Prostokat extends Figura { Prostokat(double a, double b) { super(a, b); double powierzchnia() { System.out.println("Prostokat"); return d1 * d2;
Polimorfizm, Przykład class Trojkat extends Figura { Trojkat(double a, double b) { super(a, b); double powierzchnia() { System.out.println("Trojkat"); return d1 * d2 / 2;
Polimorfizm, Przykład class Polimorfizm { public static void main(string args[]) { Figura f = new Figura(10, 10); Prostokat p = new Prostokat(9, 5); Trojkat t = new Trojkat(10, 8); Figura r; r = p;system.out.println(r.powierzchnia()); r = t;system.out.println(r.powierzchnia()); r = f;system.out.println(r.powierzchnia());
Metody Abstrakcyjne Metoda dla której nie istnieje implementacja. abstract typ nazwa(lista-parametrow); Metody: konkretne - mogą być przesłonięte przez pod-klasy abstrakcyjne - muszą zostać przesłonięte Nie wolno definiować abstrakcyjnych konstruktorów, ani metod statycznych.
Klasy Abstrakcyjne Klasa która posiada metody abstrakcyjne musi sama być deklarowana jako abstrakcyjna. abstract class {... Klasa abstrakcyjna nie posiada obiektów; nie wolno używać new na takiej klasie. Pod-klasa klasy abstrakcyjnej: implementuje wszystkie metody abstrakcyjne albo jest sama deklarowana jako abstrakcyjna.
Klasy Abstrakcyjne abstract class A { abstract void wywolajmnie(); void wywolajmnietez() { System.out.println("metoda konkretna"); class B extends A { void wywolajmnie() { System.out.print("implementacja metody "); System.out.println("abstrakcyjnej");
Klasy Abstrakcyjne class KlasaAbstrakcyjna { public static void main(string args[]) { B b = new B(); b.wywolajmnie(); b.wywolajmnietez();
Klasy Abstrakcyjne, Przykład Abstrakcyjna klasa Figura posiada abstrakcyjną metodę powierzchnia: abstract class Figura { double d1; double d2; Figura(double a, double b) { d1 = a; d2 = b; abstract double powierzchnia();
Klasy Abstrakcyjne, Przykład Pod-klasa Prostokat dostarcza konkretną implementację metody powierzchnia: class Prostokat extends Figura { Prostokat(double a, double b) { super(a, b); double powierzchnia() { System.out.println("Prostokat"); return d1 * d2;
Klasy Abstrakcyjne, Przykład Pod-klasa Trojkat dostarcza konkretną implementację metody powierzchnia: class Trojkat extends Figura { Trojkat(double a, double b) { super(a, b); double powierzchnia() { System.out.println("Trojkat"); return d1 * d2 / 2;
Klasy Abstrakcyjne, Przykład class AbstrakcyjnaFigura { public static void main(string args[]) { Nie wolno tworzyć obiektów klasy abstrakcyjnej: Figura f = new Figura(10, 10); Prostokat p = new Prostokat(9, 5); Trojkat t = new Trojkat(10, 8); Wolno tworzyć odwołania do klasy abstrakcyjnej: Figura r; r=p;system.out.println(r.powierzchnia()); r=t;system.out.println(r.powierzchnia());
Final Zapobiega Przesłanianiu Metodę deklarowaną jako final w nad-klasie nie wolno przesłaniać w pod-klasie: class A { final void meth() { System.out.println("Metoda final"); class B extends A { void meth() { System.out.println("Nielegalne!");
Final Zapobiega Przesłanianiu Dwa rodzaje wywołań metod: wczesne wywołanie ustalone w trakcie kompilacji późne wywołanie ustalane w trakcie wykonania Jako że metoda final nie może zostać przesłonięta, podlega wczesnemu wywołaniu. Czasem używana do poprawiania wydajności systemu.
Final Zapobiega Dziedziczeniu Klasa deklarowana jako final nie posiada potomków, nie wolno po niej dziedziczyć. final class A {... Ta klasa jest nielegalna: class B extends A {...
Klasa Object Klasa Object jest nad-klasą wszystkich klas w Javie. Zmienna typu Object może odwoływać się do obiektu dowolnej klasy, jak też do dowolnej tablicy. Metody deklarowane przez Object: Object clone() tworzy obiekt który jest idealną kopią danego obiektu boolean equals(object object) ustala czy dany obiekt i argument są te same
Klasa Object void finalize() wywołana zanim nieużywany obiekt jest niszczony przez śmieciarkę final Class getclass() uzyskuje dostęp do klasy obiektu w trakcie wykonania int hashcode() zwraca kod haszujący dla danego obiektu final void notify() podejmuje ponowne wykonanie wątku który czeka na danym obiekcie final void notifyall() podejmuje wykonanie wszystkich wątków zawieszonych na obiekcie
Klasa Object String tostring() zwraca ciąg znaków który opisuje dany obiekt, jest wywoływany przez print final void wait() czeka na inny wątek final void wait(long mili) final void wait(long mili, int nano)