Wykład 5

Transkrypt

Wykład 5
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
A a
B b
C c
static void main(String args[]) {
= new A();
= new B();
= 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)
●