Klasy abstrakcyjne, interfejsy i polimorfizm
Programowanie obiektowe
Janusz Jabłonowski
12 kwietnia 2011
Janusz Jabłonowski
Organizacyjne
Klasówka b ˛
edzie 20 IV 2011.
Sale jeszcze s ˛
a pertraktowane.
Materiał do wyj ˛
atków wł ˛
acznie.
Mo˙zna mie´c swoje materiały nieelektroniczne.
Janusz Jabłonowski
Wywołanie z
super
mo˙ze nie by´c intuicyjne
1
2
p u b l i c class A {
3
p u b l i c void m1 ( ) { System . o u t . p r i n t l n ( "A" ) ; }
4
}
5
6
p u b l i c class B extends A {
7
p u b l i c void m2 ( ) {
8
System . o u t . p r i n t ( " super . m1 ( ) −> " ) ;
9
super . m1 ( ) ;
10
System . o u t . p r i n t ( " t h i s . m1 ( ) −> " ) ;
11
t h i s . m1 ( ) ;
12
}
13
14
@Override
15
p u b l i c void m1 ( ) { System . o u t . p r i n t l n ( "B" ) ; }
16
}
Janusz Jabłonowski
Wywołanie z
super
mo˙ze nie by´c intuicyjne
1
2
p u b l i c class C extends B {
3
p u b l i c void m3 ( ) {
4
m2 ( ) ;
/ / Czy wypisze A czy B?
5
}
6
@Override
7
p u b l i c void m1 ( ) { System . o u t . p r i n t l n ( "C" ) ; }
8
}
Janusz Jabłonowski
Wywołanie z
super
mo˙ze nie by´c intuicyjne
1
B b = new B ( ) ;
2
b . m2 ( ) ;
3
C c = new C ( ) ;
4
c . m2 ( ) ;
5
c . m3 ( ) ;
I wynik:
super.m1() -> A
this.m1() -> B
super.m1() -> A
this.m1() -> C
super.m1() -> A
this.m1() -> C
Janusz Jabłonowski
Klasy abstrakcyjne
Nie maj ˛
a obiektów (bezpo´srednio swojej klasy).
Kompilator odrzuci prób ˛
e utworzenia obiektu takiej klasy.
S ˛
a bardzo wa˙zne!
Pozwalaj ˛
a wyabstrahowa´c wspólne cechy wielu poj ˛
e´c (klas).
Zapewniaj ˛
a wspólny interfejs dla swoich podklas.
Zapewniaj ˛
a jednocze´snie wspóln ˛
a implementacj ˛
e.
Typowe zastosowaie - wiele implementacji tego samego poj ˛
ecia.
Klasy abstrakcyjne - klasy konkretne.
Janusz Jabłonowski
Składnia klas abstrakcyjnych
Klasa abstrakcyjna jest deklarowana ze słowem
abstract
.
Klasa abstrakcyjna nie musi mie´c metod abstrakcyjnych, cho´c
zwykle ma.
Metoda abstrakcyjna jest deklarowana ze słowem
abstract
i nie
mo˙ze mie´c tre´sci.
Musi by´c podmieniona na konkretn ˛
a w konkretnych podklasach.
Klasa, która nie podmieni cho´c jednej odziedziczonej metody
abstrakcyjnej lub ma własn ˛
a metode abstrakcyjn ˛
a musi by´c
zadeklarowana jako abstrakcyjna.
Mo˙zna wywoływa´c metody abstrakcyjne (dlaczego nie ma w tym
nic gorsz ˛
acego?).
Mo˙zna te˙z podmieni´c metod ˛
e konkretn ˛
a na abstrakcyjn ˛
a!
Janusz Jabłonowski
Przykład klasy abstrakcyjnej
1
a b s t r a c t class Pojemnik {
2
p u b l i c a b s t r a c t void do daj ( i n t
e l t ) ;
3
/ / Powy˙zsze jest ciekawe - wymusza implementacj ˛
e w podklasach
4
5
p u b l i c void dodajTab ( i n t [ ] t a b ) {
6
f o r ( i n t
i : t a b )
7
do daj ( i ) ;
8
}
9
/ / Powy˙zsze jest ciekawe - konkretna metoda w abstrakcyjnej klasie
10
/ / wywołuje abstrakcyjn ˛
a metod ˛
e
11
12
@Override
13
p u b l i c a b s t r a c t S t r i n g t o S t r i n g ( ) ;
14
/ / Powy˙zsze jest ciekawe - toString było zdefiniowane w Object
15
}
16
17
/ / Całe powy˙zsze jest zatem ciekawe QED.
Janusz Jabłonowski
Przykład podklasy klasy abstrakcyjnej
1
p u b l i c class PojemnikTablicowy extends Pojemnik {
2
/ / Niezm.: dane s ˛
a w tab[0..ile-1]
3
4
PojemnikTablicowy ( ) {
5
t a b = new i n t [ 1 ] ;
/ / 1024 byłoby bardziej naturalne
6
}
7
8
p r i v a t e i n t [ ] t a b ;
9
p r i v a t e i n t
i l e = 0 ;
Janusz Jabłonowski
Przykład podklasy klasy abstrakcyjnej cd
1
@Override
2
p u b l i c void do daj ( i n t
e l t ) {
3
i f ( i l e >= t a b . l e n g t h ) {
4
i n t [ ] pom = new i n t [ t a b . l e n g t h ∗ 2 ] ;
5
f o r ( i n t
i = 0 ; i < i l e ;
i ++)
6
pom [ i ] = t a b [ i ] ;
7
/ / System.arraycopy(tab, 0, pom, 0, ile);
8
t a b = pom ;
/ / nie ma to jak automatyczne od´smiecanie :)
9
}
10
/ / teraz ju˙z na pewno jest miejsce
11
t a b [ i l e ++] = e l t ;
12
}
Janusz Jabłonowski
Przykład podklasy klasy abstrakcyjnej cd
1
@Override
2
p u b l i c S t r i n g t o S t r i n g ( ) {
3
S t r i n g wyn= " [ " ;
/ / Powinien by´c StringBuilder
4
f o r ( i n t
i = 0 ; i < i l e −1; i ++)
5
wyn += t a b [ i ] + " , " ;
6
i f ( i l e >0)
7
wyn+= t a b [ i l e − 1 ] ;
8
wyn+= " ] " ;
9
r e t u r n wyn ;
10
}
/ / toString
11
}
/ / PojemnikTablicowy
Janusz Jabłonowski
Przykład u˙zycia tej hierarchii klas
1
p u b l i c s t a t i c void t e s t ( ) {
2
i n t [ ] dane = { 1 , 3 , 8 , 2 , 5 , 9 , 8 } ;
3
Pojemnik p = new PojemnikTablicowy ( ) ;
4
System . o u t . p r i n t l n ( " p = " + p ) ;
5
f o r ( i n t
e l t : dane )
6
p . d oda j ( e l t ) ;
7
System . o u t . p r i n t l n ( " p = " + p ) ;
8
p . dodajTab ( dane ) ;
9
System . o u t . p r i n t l n ( " p = " + p ) ;
10
}
I wynik:
p = []
p = [1, 3, 8, 2, 5, 9, 8]
p = [1, 3, 8, 2, 5, 9, 8, 1, 3, 8, 2, 5, 9, 8]
Janusz Jabłonowski
Przykład dziwnej hierarchii klas
1
p u b l i c a b s t r a c t class A b s t r a k c y j n a A {
2
p u b l i c a b s t r a c t void m ( ) ;
3
}
4
5
p u b l i c a b s t r a c t class A b s t r a k c y j n a B extends A b s t r a k c y j n a A {
6
@Override
7
p u b l i c a b s t r a c t void m ( ) ;
8
/ / mo˙zna podmieni´c abstrakcyjn ˛
a metod ˛
e na abstrakcyjn ˛
a, tylko po co?
9
}
10
11
p u b l i c class KonkretnaC extends A b s t r a k c y j n a B {
12
@Override
13
p u b l i c void m( ) {
14
System . o u t . p r i n t l n ( " A b s t r a k c y j n a C .m( ) " ) ;
15
}
16
}
Janusz Jabłonowski
Przykład dziwnej hierarchii klas
1
p u b l i c a b s t r a c t class A b s t r a k c y j n a D extends KonkretnaC {
2
/ / klasa abstrakcyjna mo˙ze dziedziczy´c po konkretnej
3
}
4
5
p u b l i c class KonkretnaE extends A b s t r a k c y j n a D {
6
}
7
8
A b s t r a k c y j n a A a = new KonkretnaE ( ) ;
9
a .m ( ) ;
I wynik:
AbstrakcyjnaC.m()
Janusz Jabłonowski
Interfejsy
Klasy abstrakcyjne bez ˙zadnej implementacji.
Jeszcze lepsza posta´c kontraktu.
Nie da si ˛
e utworzy´c obiektu z interfejsu (ale mo˙zna obiekt klasy
impelmentuj ˛
acej interfejs).
Mo˙zna (i bardzo cz ˛
esto tak si ˛
e robi) zadeklarowa´c zmienn ˛
a o
typie b ˛
ed ˛
acym interfejsem.
Interfejs mo˙ze dziedziczy´c po interfejsie (u˙zywa si ˛
e wtedy słowa
extends
).
Interfejs nie mo˙ze dziedziczy´c po klasie.
Tak klasa jak i interfejs mog ˛
a dziedziczy´c po dowolnie wielu
interfejsach.
Interfejsy daj ˛
a wi ˛
ec namiastk ˛
e wielodziedziczenia.
Janusz Jabłonowski
Składnia interfejsów
Domy´slnie wszystkie składowe s ˛
a rozumiane jako publiczne (i
słowa
public
nie pisze si ˛
e.
Stałe interfejsu to atrybuty z
public, static final
. Te modyfikatory
s ˛
a przyjmowane domy´slnie.
Nie maj ˛
a składowych klasowych (tj. ze słowem
static
) poza
stałymi.
Nie maj ˛
a składowych b ˛
ed ˛
acych atrybutami (poza stałymi).
Klasa dziedzicz ˛
aca po interfejsie albo implementuje wszystkie
jego metody (i wtedy mo˙ze by´c konkretna lub mo˙ze by´c
abstrakcyjna), albo nie wszystkie (w szczególno´sci ˙zadnej) i
wtedy musi by´c abstrakcyjna.
Janusz Jabłonowski
Składnia interfejsów
Ka˙zdy interfejs niedziedzicz ˛
acy po innym niejawnie ma
dodawane nagłówki publicznych metod klasy
Object
— wszystko
(prawie) w Javie jest obiektem.
Interfejs mo˙ze zawiera´c tylko:
stałe (pola),
metody,
zagnie˙zd˙zone klasy i interfejsy.
Janusz Jabłonowski
Składnia interfejsów - interfejs Pojemnik
1
p u b l i c i n t e r f a c e Pojemnik {
2
void wstaw ( i n t
i ) ;
3
i n t p o b i e r z ( ) ;
4
boolean p u s t y ( ) ;
5
}
Janusz Jabłonowski