Sunteți pe pagina 1din 11

,

Clase abstracte i interfee


Metode i clase abstracte
Se ntmpl frecvent ca atunci cnd lucrm cu clase extinse, pentru o clas s nu putem preciza implementarea unei metode, deoarece n subclasele sale ea va fi specific fiecreia dintre ele. Atunci metodele din aceast categorie vor fi marcate cu cuvntul cheie abstract i se vor reduce la antetul lor; n acelai timp i clasa trebuie nso it de atributul abstract. !iecare metod abstract trebuie implementat, adic "re#definit n orice subclas care nu este la rndul su abstract. $u este posibil s crem obiecte ca instan e ale unei clase abstracte. %e de alt parte, ntr&o subclas putem s redefinim o metod a superclasei transformnd&o ntr&o metod abstract; aceasta are sens de exemplu dac n subarborele avnd ca rdcin subclasa, comportamentul materializat prin acea clas nu mai este valabil n subarbore i este specific fiecrei extensii a subclasei. Exemplul 1. 'rmtoarea clas are ca scop s msoare timpul necesitat de executarea unei metode oarecare fr parametri i care nu ntoarce vreun rezultat(
abstract class C { abstract void met(); public long timp() { long t0 = System.currentTimeMillis(); met(); return System.currentTimeMillis()-t0; } } unde a fost folosit metoda static currentTimeMillis() a clasei System, metod care ntoarce timpul curent n milisecunde. )ntr&o clas ce extinde C, se poate redefini metoda met i apoi, folosind un obiect ce este o instan iere a noii clase, putem apela metoda timp pentru a determina timpul de executare a metodei met, ce are acum o

implementare precis(
class C1 extends C { void met () { int x=0; for (int i=0; i<1000000; i++) x=x+1-1; } } class A str { public static void m!in(Strin"#$ s) { C1 % = new C1(); System.&ut.println( '(ur!t!='+% .timp() ); } }

*egat de exemplul de mai sus, nu trebuie s ne mire c e posibil ca la executri diferite s ob inem timpi diferi i( aceasta este o consecin a faptului c pe perioada executrii programului nostru sistemul gazd +mai face i altceva+, sau c a intervenit colectorul de reziduuri.

Noiunea de interfa
Aa cum s&a men ionat anterior, este posibil s declarm clase abstracte n care toate metodele sunt abstracte. Acest lucru poate fi realizat i prin intermediul interfeelor. )n plus, aa cum vom vedea n continuare, ele reprezint mecanismul propus de -ava pentru tratarea problemelor ridicate de motenirea multipl. Motenirea multipl este facilitatea oferit de unele limba.e de programare ca o clas s moteneasc "prin extindere# membri ai mai multor clase. /vident, aceast caracteristic important a programrii orientate pe obiecte nu este negli.at n -ava. 0odul n care aceast facilitate poate fi implementat n -ava va fi tratat n continuare. 1nterfe ele reprezint o modalitate de a declara un tip constnd numai din constante i din metode abstracte. 2a sintax, o interfa este asemntoare unei clase, cu deosebire c n loc de class trebuie precizat interface, iar metodele nu au corp, acesta fiind nlocuit cu );). %utem spune c interfe ele reprezint numai proiecte, pe cnd clasele sunt o combina ie de proiecte i implementri. 2a i n cazul claselor abstracte, este evident c nu pot fi create obiecte de tipul unei interfe e. 2mpurile unei interfe e au n mod implicit modificatorii static i final, deci sunt constante. 0etodele interfe elor sunt totdeauna publice i au n mod implicit modificatorul abstract. )n plus ele nu pot fi statice, deoarece fiind abstracte, nu pot fi specifice claselor. 3rice interfa este gndit pentru a fi ulterior implementat de o clas, n care metodele interfe ei s fie redefinite, adic s fie specificate ac iunile ce trebuie ntreprinse. !aptul c o clas C implementeaz o interfa * trebuie specificat prin inserarea informa iei implements * n antetul clasei. Exemplul 2. %rezentm un prim exemplu de implementare a unei interfe e.
interface * { char c=+!+; int i=0; void scrie(); } class C implements * { public void scrie() { System.&ut.println(c+' '+i); } }

%recizm urmtoarele( & o interfa poate extinde oricte interfe e. )n acest mod interfe ele permit motenirea unor +contracte+ "numele i signaturile unor metode# fr motenirea implementrii; & dac o clas implementeaz doar unele din metodele unei interfe e, atunci ea trebuie declarat cu abstract; & spre deosebire de interfe e "care sunt limitate la constante i anun uri de metode#, clasele abstracte pot avea implementri par iale, metode statice, membri cu modificatorul protected, cmpuri care nu sunt finale etc.; & o clas poate implementa oricte interfe e, dar poate extinde o singur clas.

6 5ac o clas extinde o alt clas i implementeaz una sau mai multe interfe e, atunci trebuie anun at nti extinderea i apoi implementarea, ca n exemplul urmtor(
class C extends , implements *1-*.-*/;

Aa cum vom vedea n continuare, facilitatea ca interfe ele i clasele s poat extinde oricte interfe e reprezint modalitatea prin care -ava rezolv problema motenirii multiple. 5ac s&ar permite ca o clas s extind mai multe clase, ar aprea neclarit i legate de semnifica ia numelor. Astfel, dac ar fi posibil urmtoarea structur de clase extinse(
0 1 3 2

i n clasele 0, 1 i 2 ar fi definit "respectiv redefinit# un cmp c, atunci pentru un obiect % de tipul 3 semnifica ia lui % .c ar fi neclar. !aptul c n -ava o clas poate extinde cel mult o clas nu rezolv ns automat problema conflictelor de nume, problem care va fi tratat n continuare.

Extinderea interfeelor
2a i clasele, interfe ele pot fi extinse. 3 interfa * poate extinde oricte interfe e, n acest mod adugndu&se la * noi constante i "anun uri de# metode. /ste permis ca o interfa ce extinde alt interfa s con in o constant cu acelai nume. 5e exemplu pentru urmtoarea structur de interfe e(
0

este posibil ca n una sau mai multe dintre interfe e s fie declarat o constant c. 5eosebim dou cazuri( ,# 2onstanta c este redeclarat n interfa a 3 ( o referire la c constituie o referire la constanta c din 3. %utem face ns referire i la constantele din celelalte interfe e prin 1.c, 2.c i 0.c. 4# 2onstanta c nu este redeclarat n interfa a 3 ( o referire la c este corect dac exist un unic drum de interfe e ce +coboar+ n 3, drum n care c poate fi declarat de mai multe ori; n acest caz referirea are ca obiect cea mai +recent+ declarare a cmpului, adic cea din interfa a cea mai apropiat de 3. 5ac c este declarat pe mai multe drumuri de interfe e ce +coboar+ n 3, compilatorul va semnala c este vorba de o referire ambigu. 5ac n 3 constanta c nu poate fi regsit pe nici un drum de interfe e ce a.unge n 3, atunci va fi semnalat din nou eroare.

8 7mnnd la structura de interfe e de mai sus, s presupunem acum c n 1 i n 2 "sau n supertipuri ale lor# apare o metod cu acelai nume. 5eosebim situa iile( ,# dac metodele au signaturi diferite, vor fi motenite ambele metode; 4# dac metodele au aceeai signatur i acelai tip pentru valoarea ntoars, va fi motenit o singur metod; 6# dac metodele au aceeai signatur, dar tipurile valorilor ntoarse difer, atunci motenirea nu va fi posibil "eroare de compilare#. /ste posibil ca de exemplu n 1 i n 3 "sau, mai general, ntr&un drum de interfe e extinse# s anun m cte o metod cu acelai nume i aceeai signatur. Atunci o clas care implementeaz interfa a 3 va implementa ambele metode. Exemplul 3. %rogramul urmtor(
interface interface interface interface 0 1 2 3 { char c=)!); } extends 0 { int c=1; void met(); } { boolean c=true; } extends 1-2 { int c=44; void met(); }

class C implements 1 { public void met() { System.&ut.println('++++++'); } } class 5 implements 3 { public void met() { System.&ut.println('666666'); } } class *nter7ete1 implements 3 { public void met() { } public static void m!in (Strin"#$ s) { C % 1 = new C(); % 1.met(); 5 % . = new 5(); % ..met(); int c=-88; 99 met(); System.&ut.println(c+' '+0.c+' '+1.c+' '+2.c+' '+3.c ); } }

produce la ieire(
+++++ 66666 -88 ! 1 true 44

Se impun urmtoarele observa ii( ,# )n clasele C i 5, redefinirea metodei met s&a fcut cu precizarea modificatorului public. Acest lucru este obligatoriu, pentru c altfel ar fi fost folosit modificatorul implicit, dar o redefinire nu poate fi mai restrictiv n privin a drepturilor de acces; 4# 5in metoda principal nu putem invoca implementarea lui met din *nter7ete1, deoarece o metod static poate accesa numai cmpurile i metodele statice ale clasei; pe de alt parte ns, o metod anun at ntr&o interfa nu poate fi redefinit printr&o metod static, deci nu putem preciza atributul static pentru metoda met din *nter7ete1.

Implementarea interfeelor
)n subcapitolul de fa prezentm modul n care sunt rezolvate conflictele de nume ce pot aprea la implementarea interfe elor. !ie C o clas care implementeaz una sau mai multe interfe e i extinde eventual o clas. %resupunem mai nti c n unul sau mai multe dintre aceste tipuri apare un cmp "constant n cazul interfe elor# cu acelai nume c. Atunci discu ia este analoag cu cea referitoare la extinderea interfe elor, cu urmtoarea adugire( dac c este declarat att n 3, ct i n clasa pe care o extinde, va trebui s specificm super.c pentru cmpul din superclas. 9recem acum la cazul metodelor. 0otenirea metodelor interfe elor are loc n modul descris la extinderea interfe elor. 5rept urmare, toate metodele motenite din interfe e trebuie implementate. 5ac o metod cu acelai nume i aceeai signatur apare n superclas i n interfe ele implementate, atunci( & dac precizm n C o implementare a metodei, ea va constitui o redefinire a metodei din superclas; la aceasta din urm putem face ns apel prin super; & dac n C nu este precizat o implementare a metodei, atunci metoda "motenit# din superclas constituie implementarea metodei din interfe e, cu condi ia ca ea s aib modificatorul public. Exemplul 4. %rogramul urmtor(
interface A { int x=1; void scrie(); } interface , { int x=.; void scrie(); } class C { int x=/; public void scrie() { System.&ut.print(A.x+' '+,.x+' '+x); } } class 5 extends C implements A-, { int x=:; } class *nter7ete. { public static void m!in(Strin"#$ ;) { 5 % = new 5(); % .scrie(); System.&ut.println(' '+% .x); A % 1 = new 5(); % 1.scrie(); System.&ut.println(' '+% 1.x); } }
A , C

produce la ieire(
1 . / : 1 . / 1

<

Sunt necesare explica ii doar referitor la obiectul % 1. /l are tipul declarat A i tipul real 5, ceea ce face ca invocarea metodei scrie prin intermediul acestui obiect s se refere la metoda scrie din clasa C, iar referin a % 1.x s se adreseze constantei x din interfa a A.

Rezolvarea n ava a problemei motenirii multiple


S presupunem c plecnd de la clasele C1- C.- ...- Cn dorim s construim o nou clas care s moteneasc unele dintre metodele lor. -ava permite doar motenire simpl, deci va fi necesar s apelm la interfe e. 0odalitatea de rezolvare a problemei motenirii multiple pe care o prezentm n continuare este independent de numrul de clase motenite. ;om folosi urmtoarea structur de interfe e i clase(
*1 *. . . . . . *n

C C1 C. Cn

)n aceast structur clasele C1- C.- ...- Cn implementeaz respectiv metodele anun ate n interfe ele *1- *.- ...- *n, iar clasa C implementeaz toate interfe ele *1- *.- ...- *n. /ste suficient s prezentm modul n care clasa C motenete implementrile din C1 ale metodelor anun ate n *1, lucrurile decurgnd analog pentru celelalte interfe e i clase pe care le implementeaz. 5e aceea n continuare vom presupune c C trebuie s extind doar clasa C1; evident, presupunerea este fcut doar pentru o prezentare mai concis, deoarece pentru extinderea unei singure clase nu apare necesitatea folosirii interfe elor. )n clasa C vom declara i crea un obiect % 1 de tipul C1 "se presupune c n clasa C se tie ce implementare a interfe ei *1 trebuie folosit#. Atunci pentru fiecare metod met implementat de C1 introducem n clasa C metoda met cu aceeai signatur i avnd una dintre formele( tip met(...) { return % 1.met(...); }
void met(...) { % 1.met(...); }

dup cum metoda ntoarce sau nu o valoare. Exemplul 5. %rogramul urmtor(

interface 1 { void x1(); int x.(); } class C1 implements 1 { public void x1() { System.&ut.print('x1 '); } public int x.() { return 1; } } class C implements 1 { 1 % 1= new C1(); 99 Cl!s! C 'stie' c! tre uie s! 7&l&se!sc! 99 implement!re! C1 ! inter7etei 1 public void x1() { % 1.x1(); } public int x.() { return % 1.x.(); } } class Mult1 { public static void m!in (Strin"#$ s) { C % C = new C(); % C.x1(); System.&ut.println(' '+% C.x.()); } }

produce la ieire (
x1 1

S reamintim ns c putem declara variabile avnd ca tip numele unei interfe e i putem atribui unei astfel de variabile un obiect care implementeaz interfa a. Aceast facilitate permite o mai mare libertate de ac iune. Astfel, n exemplul de mai sus nu mai este necesar ca C s tie care este clasa ce implementeaz pe *1, ci poate afla acest lucru prin intermediul unui constructor; cu alte cuvinte, la crearea unei instan ieri a lui C, putem preciza ce implementare a lui *1 s foloseasc. 0ai mult, pentru redefinirea unor metode diferite ale aceleai interfe e, putem folosi implementri diferite. Aceste aspecte sunt ilustrate n Exemplul 6 de mai .os, n care interfa a 1 este implementat de clasele C11 i C1., dar i de clasa C ale crei metode folosesc acelai mecanism( invoc n fapt metodele cu acelai nume ale claselor C11 i C1. prin instan ieri ale acestora. Exemplul 6. )n urma executrii programului(
interface 1 { void x1(); int x.(); } class C11 implements 1 { public void x1() { System.&ut.print('x1 '); } public int x.() { return 1; } } class C1. implements 1 { public void x1() { System.&ut.print('x. '); } public int x.() { return .; }

} class C implements 1 { 1 % 1-% .; C(1 % 1- 1 % .) { this.% 1=% 1; this.% .=% .;} public void x1() { % 1.x1(); } public int x.() { return % ..x.(); } } class Mult. { public static void m!in (Strin"#$ s) { 1 % 1 = new C11(); 1 % . = new C1.(); C % C = new C(% 1-% .); % C.x1(); System.&ut.print(' '+% C.x.()); } }

se ob ine la ieire(
x1 .

1 % 1 = new C1.(); 1 % . = new C11();

5ac ns am nlocui a doua linie din metoda principal cu(

la ieire s&ar ob ine(


x. 1

S remarcm c n metodele x1 i x. ale clasei C nu apare nici un indiciu asupra tipului real al obiectelor care sunt delegate s execute metodele cu aceleai nume ale claselor pe care le instan iaz. 5e asemenea, posibilitatea de a folosi mai multe implementri pentru o interfa i de a folosi una sau alta dintre ele n func ie de context "de exemplu n func ie de valoarea unei variabile# arat pe de o parte c introducerea interfe elor ofer utilizatorului un instrument puternic i flexibil de lucru, iar pe de alt parte .ustific nc o dat de ce -ava utilizeaz legarea dinamic "trzie#.

Clase interne
%n acum am lucrat sub restric ia c o clas nu poate con ine o alt clas. 5ar -ava permite s definim clase ca membri ai unei clase. 0ai mult, aa cum vom vedea mai .os, pot aprea clase fr nume. 3 clas intern poate con ine la rndul ei o clas intern. Avanta.ul utilizrii claselor interne const n primul rnd n faptul c permite includerea lor exact acolo unde trebuie s apar din punct de vedere logic, dar i n uurin a folosirii lor "din interiorul unei clase interne putem s ne referim direct la cmpurile clasei ce o con ine#. Exemplul 7. %rogramul urmtor creaz obiecte ca perechi "nume,vrst# i le ordoneaz dup vrst.
imp&rt <!=!.util.6; cl!ss *nterne { pu lic st!tic =&i( m!in(Strin"#$ sss) { C % = ne; C();

} }

% .cre!re(); % .s&rt!re(); % .list!re();

cl!ss C { cl!ss elem { Strin" nume; int =!rst!; elem(Strin" n- int =) { nume = n; =!rst! = =; } } elem#$ e; int n; =&i( cre!re() { Sc!nner sc = ne; Sc!nner(System.in); System.&ut.print('n = '); n = sc.next*nt(); e = ne; elem#n$; System.&ut.println('(!ti '+n+' perec>i (nume-=!rst!) ?'); 7&r(int i=0; i<n; i++) e#i$ = ne; elem(sc.next()-sc.next*nt()); } =&i( s&rt!re() { 99 s&rt!re 7.7.7. ru(iment!r! int i-<; elem 7; 7&r(i=0; i<n-1; i++) 7&r(<=i+1; <<n; <++) i7(e#i$.=!rst! @ e#<$.=!rst!) { 7 = e#i$; e#i$ = e#<$; e#<$ = 7; } } =&i( list!re() { System.&ut.println('An5up! s&rt!re ?'); 7&r(int i=0; i<n; i++) System.&ut.println(e#i$.nume + 'At' + e#i$.=!rst!); } }

0en ionm c exist i clase fr nume "anonime#. 3 clas anonim apare ntr&o expresie de forma(
new SuperA(...) {...}

prin care clasa anonim extinde o clas sau implementeaz o interfa SuperA i prin care este creat un obiect al clasei anonime. Observaie. 2rearea de clase anonime permite extinderea implicit a unei clase i implementarea implicit a unei interfee "fr a folosi extends sau implements#. 5rept urmare codul devine mai scurt i mecanismul este folosit +la locul potrivit+. Aceast tehnic este larg folosit de exemplu n lucrul cu interfe e grafice. Exemplul 8. S considerm urmtorul program(
! str!ct cl!ss A { A(int i) { System.&ut.println(i); } =&i( met() { }; }

cl!ss ABC { st!tic A % A; pu lic st!tic =&i( m!in(Strin"#$ s) { ObA = new A(3) { void met() { System out println(!O " !)# $ $# % A.met(); } }

2lasa abstract A are un constructor i o metod care nu prevede nici o ac iune. %are ciudat faptul c dei metoda nu este abstract, clasa a fost declarat ca fiind abstract; acest +artificiu+ este de fapt o invita ie la a extinde clasa i a preciza ac iuni specifice pentru metode. )n clasa ABC apare metoda principal, n care obiectul % A "avnd tipul declarat A# este creat ca avnd ca tip real o clas anonim care extinde clasa abstract A. 2lasa anonim este o clas intern. 5up invocarea constructorului este invocat metoda met; este vorba binen eles de metoda met redefinit n clasa anonim. 5rept urmare la ieire va aprea(
/ %.C.

Exemplul 9. Spre deosebire de exemplul precedent, aici am ales ca o clas anonim s implementeze o interfa (
interface * { void met(); } class *BC { static * % *; public static void m!in(Strin"#$ s) { % * = new *() { public void met() { System.&ut.println('%.C.'); } }; % *.met(); } }

5in nou este creat o clas "intern# anonim i un obiect avnd ca tip real aceast clas; obiectul invoc metoda met redefinit n clasa anonim. /xecutarea programului produce la ieire(
%.C.

3 interfa nu poate avea constructori explici i. /xist ns constructorul implicit cu ac iune nul; acest constructor a fost folosit n exemplul de mai sus. /ste interesant de subliniat nc un aspect. 2lasa *BC are modificatorul de acces implicit, dar n interiorul ei apare o metod cu modificatorul "mai permisiv# public. Acesta se datoreaz faptului c metoda redefinete o metod "public# dintr& o interfa . 2lasele interne se dovedesc un instrument foarte util i uor de mnuit i se va face apel la ele n continuare. 2lasele anonime apar ini ial ca fiind mai pu in +naturale+, dar avanta.ele "men ionate mai sus# ale acestei tehnici fac ca ea s fie foarte util i deci folosit, aa cum vom face n lucrul cu interfe e grafice.

n continuare apar aspecte mai fine legate de clasele interne. -ava permite s definim clase nu numai ca membri ai pachetelor, dar i ca membri ai unei clase, n interiorul unei metode sau a unui bloc. 0ai mult, aa cum am vzut, pot aprea clase fr nume. 2lasele care sunt membrii unui pachet sunt considerate clase de nivel superior. 2lasele declarate ntr&o clas se mpart n dou categorii( & clase de nivel superior( este vorba de membrii statici ai unei clase de nivel superior; aceste clase au deci acelai statut cu clasele membre ale unui pachet; & clase interne( clasele care nu sunt de nivel superior. )ntr&o clas de nivel superior putem plasa i o interfa . Aa cum am men ionat, ntr&un bloc sau corpul unei metode putem defini clase la fel cum putem defini variabile locale; aceste clase sunt clase interne. 3 clas intern poate con ine la rndul ei o clas intern. 1nstan ierea unei clase interne este asociat instan ierii curente a clasei care o con ine; drept urmare clasa intern poate accesa direct cmpurile clasei ce o cuprinde. 2ele de mai sus nu mai rmn valabile pentru clasele de nivel superior( o clas care este membru static al unei clase nu poate folosi direct cmpurile clasei ce o cuprinde "dar putem realiza acest lucru n mod indirect, prin crearea unui obiect ce instan iaz clasa al crui membru este#. 3 clas intern nu poate fi folosit direct dect n clasa n care a fost declarat i n descenden ii "n arborele de clase ai# acesteia. 5omeniul ei de vizibilitate este cel al unui cmp, respectiv al unei variabile locale.

S-ar putea să vă placă și