43
03/13/22 1 Cuvinte importante: - mostenire: derivare; superclase si subclase; ierarhie de clase; clasa Object; mostenire simpla si multipla; sintaxa pentru derivarea unei clase dintr-o superclasa; controlul accesului si mostenirea; metode- constructor pentru clase derivate si cuvantul- cheie super; supraincarcarea (overloading) metodelor; redefinirea (override) metodelor; - polimorfism: caracteristicile polimorfismului; legarea statica si legarea dinamica; - metode si clase finale; metode si clase abstracte; - exemplu de folosire a mostenirii, a polimorfismului, a claselor si metodelor finale si abstracte.

cursuri java

Embed Size (px)

DESCRIPTION

cursuri java

Citation preview

04/17/23 1

Cuvinte importante:

- mostenire: derivare; superclase si subclase; ierarhie de clase; clasa Object; mostenire simpla si multipla; sintaxa pentru derivarea unei clase dintr-o superclasa; controlul accesului si mostenirea; metode-constructor pentru clase derivate si cuvantul-cheie super; supraincarcarea (overloading) metodelor; redefinirea (override) metodelor;

- polimorfism: caracteristicile polimorfismului; legarea statica si legarea dinamica;

- metode si clase finale; metode si clase abstracte;

- exemplu de folosire a mostenirii, a polimorfismului, a claselor si metodelor finale si abstracte.

04/17/23 2

Mostenirea - concept fundamental al programarii orientata obiect

Conceptul de mostenire este folosit in Java la organizarea claselor si a comportamentului acestora. Mostenirea este mecanismul fundamental pentru refolosirea codului.

Mostenirea este un mecanism care permite unei clase sa mosteneasca atributele si comportamentul unei alte clase cu care este inrudita. Mostenirea modeleaza relatii de tipul ESTE-UN (sau ESTE-O). Intr-o relatie de tip ESTE-UN, spunem despre o clasa nou creata ca ESTE-O variatiune a unei clase existente (originala, din care provine). De exemplu, Masina ESTE-UN Vehicul.

Practic, prin mostenire o clasa noua dobandeste toate atributele si comportamentul unei clase existente (clasa originala). Din acest motiv, noua clasa poate fi creata prin simpla specificare a diferentelor fata de clasa originala din care provine.

04/17/23 3

Datorita relatiilor de mostenire clasele de obiecte sunt organizate intr-o ierarhie bine precizata.

In cadrul ierarhiei claselor de obiecte, operatia de definire a unei noi clase de obiecte pe baza uneia deja existente se numeste derivare. Clasa originala (mai generala) se va numi superclasa a noii clase, iar noua clasa de obiecte se va numi subclasa a clasei din care deriva.

Uneori, in loc de derivare se foloseste termenul de extindere. Termenul vine de la faptul ca o subclasa isi extinde superclasa cu noi variabile si metode.

De exemplu, putem extinde clasa Masina la MasinaStraina (pentru care se plateste vama) si MasinaAutohtona (pentru care nu se plateste vama) etc.

Observatie importanta: Un alt tip de relatie intre obiecte este relatia ARE-UN sau ESTE-COMPUS-DIN. De exemplu, Masina ARE-UN volan. Aceasta relatie nu este o relatie de mostenire, ci este de agregare. Componentele care pot fi agregate devin simple campuri (atribute) de tip private ale clasei nou create.

04/17/23 4

Intr-o ierarhie de clase, o clasa poate avea o singura superclasa, insa poate avea un numar nelimitat de subclase. Subclasele mostenesc toate atributele si metodele superclasei lor, care la randul ei mosteneste toate atributele si metodele de la superclasa ei si asa mai departe, urcand in ierarhie. Rezulta ca o clasa nou creata contine toate atributele si metodele claselor aflate deasupra sa in ierarhie, si in plus contine propriile atribute si metode.

Figura de mai jos prezinta o ierarhie de clase.

Clasa A

Clasa B

Clasa DClasa C Clasa E

Clasa A este superclasa a clasei B. Clasa B este subclasa a clasei A.

Clasa B este superclasa pentru clasele C, D si E. Clasele C, D si E sunt subclase ale clasei B.

04/17/23 5

In varful ierarhiei de clase Java se afla clasa Object, iar toate clasele de obiecte, care se creaza, sunt derivate din aceasta unica superclasa.

Object reprezinta clasa initiala, sa-i spunem clasa de obiecte generice, care defineste atributele si comportamentul (metodele) mostenite de toate clasele din biblioteca de clase Java. In varful ierarhiei se definesc concepte (clase) abstracte, foarte generale. Aceste concepte generale devin din ce in ce mai concrete, mai particularizate, o data cu “coborarea” spre subclasele de pe nivelele de mai jos in ierarhie.

Cand clasa nou creata defineste un comportament complet nou si nu este o subclasa a unei alte clase, atunci ea mosteneste direct clasa Object. Astfel, noua clasa se integreaza corect in ierarhia claselor Java.

De asemenea, daca se defineste o clasa care nu specifica o superclasa, Java presupune ca noua clasa mosteneste direct clasa Object. Clasele definite in exemplele de pana acum au mostenit direct clasa Object.

04/17/23 6

De exemplu, se poate construi o ierarhie Om care deriva direct din clasa generica Object si are doua clase derivate: clasa barbatilor (Barbat) si clasa femeilor (Femeie).

Obiect (Object)

Om

Barbat Femeie

Daca la nivelul clasei de obiecte Om am definit forma bipeda a acestuia si capacitatea de a vorbi si de a intelege, toate aceste caracteristici vor fi mostenite si de clasele derivate din clasa Om, si anume clasa barbatilor si cea a femeilor. Fiecare din aceste clase de obiecte derivate isi vor defini propriile lor proprietati si operatii pentru a descrie diferenta dintre ele si clasa originala.

04/17/23 7

Caracteristicile unei ierarhi de clase

Organizarea unei aplicatii informatice intr-o ierarhie de clase presupune o planificare atenta. Proiectarea arborelui de clase de obiecte necesare rezolvarii unei anumite probleme este un talent pe care fiecare programator trebuie sa si-l descopere si sa si-l cultive cu atentie. De alegerea claselor si de proiectarea arborelui acestor clase depinde eficienta si flexibilitatea aplicatiei.

Principalele caracteristici ale unei ierarhie de clase sunt:

- atributele si metodele comune mai multor clase pot fi definite in superclase, care permit folosirea repetata a acestora pentru toate clasele aflate pe nivelele mai joase din ierarhie;

- modificarile efectuate in superclasa se reflecta automat in toate subclasele ei, subclasele acestora si asa mai departe; nu trebuie modificat si recompilat nimic in clasele aflate pe nivelurile inferioare, deoarece acestea primesc noile informatii prin mostenire;

04/17/23 8

- clasa derivata poate sa adauge noi atribute si metode si poate modifica semnificatia metodelor mostenite (prin polimorfism, despre care vom vorbi mai incolo in acesta lectie);

- superclasa nu este afectata in nici un fel de modificarile aduse in clasele derivate;

- o clasa derivata este compatibila ca tip cu superclasa, ceea ce inseamna ca o variabila referinta de tipul superclasei poate referi un obiect al clasei derivate, dar nu si invers; clasele derivate dintr-o superclasa nu sunt compatibile ca tip.

Mostenirea simpla si multipla

Forma de mostenire folosita in Java este denumita mostenire simpla (single inheritance), deoarece fiecare clasa de obiecte Java nou creata poate fi derivata dintr-o singura superclasa (poate avea o singura superclasa).

Mostenirea multipla inseamna ca o clasa nou creata pot fi derivata din doua sau mai multe superclase, mostenind variabilele si metodele combinate din toate aceste superclase. Mostenire multipla (multiple inferitance) ofera mijloace de creare a unor clase care cuprind aproape orice comportament imaginabil. Acest lucru complica semnificativ definitia clasei si a codului necesar acesteia.

04/17/23 9

Mostenirea simpla poate fi restrictiva, mai ales atunci cand exista un comportament similar, care trebuie duplicat pe diferite “ramuri” ale ierarhiei de clase (nu pe aceeasi ramura a ierarhiei).

De exemplu, omul poate fi privit ca un mamifer care naste pui vii sau poate fi privit ca un obiect spatio-temporal care are propria lui forma si pozitie in functie de timp. Aceasta inseamna ca trebuie sa dam definitii de metode despre ce inseamna faptul ca un obiect poate fi privit ca un mamifer sau ca un obiect spatio-temporal. Dar, aceste definitii de metode sunt comune nu numai clasei de obiecte Om dar si altor clase de obiecte derivate sau nu din clasa Om, superclase sau nu ale clasei Om. Putem sa gasim o multime de clase de obiecte ale caror instane pot fi privite ca obiecte spatio-temporale dar care sa nu aiba mare lucu in comun cu omul (de exemplu clasa Minge).

Pentru rezolvarea problemei mostenirii multiple, Java foloseste interfetele.

Declaratiile de metode si atribute comune mai multor clase de obiecte care nu sunt mostenite de la superclasele lor poarta denumirea de interfeta. Interfetele vor fi prezentate in totalitate intr-o lectie viitoare.

04/17/23 10

Sintaxa folosita pentru a deriva o clasa noua dintr-o superclasa

O clasa derivata (numita si subclasa) mosteneste toate atributele (variabilele de instanta si de clasa) superclasei din care provine. Clasa derivata poate apoi sa adauge noi atribute, sa redefineasca metode ale superclasei sau sa adauge noi metode. Fiecare clasa derivata este o clasa complet noua. Pentru a declara o clasa derivata se foloseste clauza extends, astfel:

[<modificatori_acces>] [<modificatori_clasa>] class <nume_subclasa> extends <nume_superclasa>

{<corpul_clasei>

}

unde:

- <modificatori_acces> - specifica domeniul de vizibilitate (folosire sau acces) al subclasei; modificatorul de acces poate fi: public;

- <modificatori_clasa> - specifica tipul subclasei definite; modificatorul clasei poate fi: abstract, final;

- <nume_subclasa> - specifica numele clasei derivate dintr-o superclasa;

04/17/23 11

- <nume_superclasa> - specifica numele unei superclase din care deriva subclasa;

- <corpul_clasei> - variabilele clasei si metodele care lucreaza cu acestea, adaugate sau redefinite in subclasa .

Observatii:

1. Orice metoda neprivata (adica publica, protejata sau prietenoasa) din superclasa, care nu este redefinita (suprascrisa) in clasa derivata, este mostenita nemodificat, cu exceptia constructorilor. Metoda poate fi apoi apelata ca si cum ar face parte din clasa derivata.

2. Clasa derivata contine atribute si metode suplimentare (fata de cele mostenite din superclasa) care pot fi declarate: private, protected, public sau fara modificator de acces.

04/17/23 12

Controlul accesului si mostenirea

Ca regula generala, toti membrii de tip public ai superclasei devin membrii de tip public ai clasei derivate.

De asemenea, membrii de tip private ai superclasei sunt mosteniti, dar acestia nu sunt accesibili in mod direct (adica, folosind operatorul “punct” sau direct numele membrului) in clasa derivata, ci prin intermediul altor metode publice mostenite de la superclasa care fac posibil accesul.

Metodele speciale care examineaza si modifica valoarea fiecarui atribut de tip private sunt denumite “accesori” si, respectiv, “modificatori”.

Se foloseste conventia ca numele metodelor “accesor” sa inceapa cu get, cum ar fi getRaza() din programul TestCerc.java prezentat in lectia 5. De asemenea, se foloseste conventia ca numele metodelor “modificator” sa inceapa cu set, cum ar fi setRaza() din programul TestCerc.java prezentat in lectia 5.

Folosirea metodelor “accesori” si “modificatori” este foarte raspandita in programarea orientata obiect. Acest mod de abordare mareste gradul de reutilizare a codului, evitand folosirea lui necorespunzatoare.

04/17/23 13

Metode-constructor pentru clase derivate si cuvantul-cheie super

Metodele-constructor nu se mostenesc. Fiecare clasa derivata trebuie sa isi defineasca propriile metode-constructor.

Daca nu se defineste nici un constructor, Java va genera un constructor implicit (fara parametri). Acest constructor implicit al clasei derivate:

- va apela automat constructorul implicit (fara parametrii) al superclasei (aflata pe nivelul imediat superior) pentru membrii care au fost mosteniti, apoi

- va aplica initializarea implicita pentru atributele adaugate in clasa derivata (adica 0/false pentru tipurile primitive numerice/booleene si null pentru tipurile referinta).

Asadar, construirea unui obiect al unei clase derivate are loc prin construirea prealabila a portiunii mostenite (constructorul clasei derivate apeleaza automat constructorul superclasei aflata pe nivelul imediat superior). Acest lucu este normal, deoarece mecanismul incapsularii afirma ca partea mostenita este un “intreg”, iar constructorul superclasei ne spune cum sa initializam acest “intreg”.

Metodele-constructor ale superclasei pot fi apelate explicit in clasa derivata prin metoda super(). Metoda super poate sa apara doar in prima linie dintr-o metoda-constructor.

04/17/23 14

Apelul unei metode-constructor a superclasei dintr-o clasa derivata, folosind super se face astfel:

super(<arg1>, <arg2>, <arg3>, …)

unde:

- <arg1>, <arg2>, <arg3>, … - specifica parametrii metodei-constructor a superclasei.

De exemplu, sa presupunem ca o superclasa (ClasaSuper) are un constructor cu doi parametri de tip int. Constructorul clasei derivate va avea, in general, forma:

public class ClasaDerivata extends ClasaSuper{

public ClasaDerivata(int x, int y);{

super(x, y);// alte instructiuni

}…}

Observatie: Daca in superclasa este definit explicit cel putin un constructor, atunci trebuie apelat explicit (prin super) constructorul superclasei respective din interiorul constructorului clasei derivate. Altfel se obtine eroare de compilare.

04/17/23 15

Supraincarcarea (overloading) metodelor. Redefinirea (override) metodelor

Supraincarcarea metodelor permite existenta in interiorul aceleiasi clase a mai multor metode cu acelasi nume, dar cu lista diferita de parametrii (ca numar si tip), deci cu semnatura diferita. Supraincarcarea metodelor este permisa si daca unele dintre metode sunt definite intr-o superclasa si altele in clasele derivate din superclasa respectiva.

De exemplu, putem avea o metoda int max(int a, int b) si o metoda int max(int a, int b, int c), ambele in cadrul aceleasi clase sau putem defini prima metoda in cadrul unei superclase si cea de a doua metoda in cadrul unei clase derivate din superclasa.

Atunci cand se face un apel al unei metode supraincarcate, compilatorul alege definitia de metoda examinand lista parametrilor de apel (adica, semnatura).

Redefinirea (suprascriere) metodelor permite existenta in interiorul claselor derivate dintr-o superclasa a mai multor metode cu acelasi nume, tip de rezultat si aceeasi lista de parametrii, deci cu aceeasi semnatura.

Atunci cand se face un apel al unei metode redefinite, compilatorul foloseste definitia metodei care este gasita prima (incepand din partea de jos a ierarhiei de clase si mergand in sus).

04/17/23 16

Programul urmator (AfisareSubClasa.java) prezinta o clasa ce contine o metoda afisareDate(), care afiseaza numele clasei si valorile variabilelor de instanta. De asemenea, in acelasi fisier-sursa este inclusa si clasa denumita AfisareSubClasa derivata din clasa AfisareClasa. A fost creat un obiect de tip AfisareSubClasa si a fost apelata metoda afisareDate(). Deoarece clasa AfisareSubClasa nu defineste aceasta metoda, Java o cauta in superclasele clasei AfisareSubClasa, incepand cu superclasa AfisareClasa, unde gaseste metoda afisareDate() si o executa.

class AfisareClasa {int x = 0;int y = 1;

void afisareDate() {System.out.println("x este " + x + ", y este " + y);System.out.println("Sunt un obiect al clasei " +

this.getClass().getName()); }}class AfisareSubClasa extends AfisareClasa { int z = 3; public static void main(String [] args) { AfisareSubClasa ob = new AfisareSubClasa();

ob.afisareDate(); }}

04/17/23 17

Rezultatul programului este:

x este 0, y este 1Sunt un obiect al clasei AfisareSubClasa

Deoarece metoda afisareDate() a superclasei AfisareClasa nu afiseaza si variabila de instanta z specifica subclasei AfisareSubClasa, metoda afisareDate() va fi redefinita (suprascrisa) in interiorul subclasei. Iata noul program (AfisareSubClasa.java):

class AfisareClasa {int x = 0;int y = 1;

void afisareDate() {System.out.println("x este " + x + ", y este " + y);System.out.println("Sunt un obiect al clasei " +

this.getClass().getName()); } }class AfisareSubClasa extends AfisareClasa { int z = 3; void afisareDate() {

System.out.println("x este " + x + ", y este " + y + ", z este " + z);System.out.println("Sunt un obiect al clasei " +

this.getClass().getName()); } public static void main(String [] args) { AfisareSubClasa ob = new AfisareSubClasa();

ob.afisareDate();} }

04/17/23 18

Rezultatul programului este:

x este 0, y este 1, z este 3Sunt un obiect al clasei AfisareSubClasa

Nota: Apelul de metoda:

this.getClass().getName());

este folosit pentru aflarea numelui clasei din care face parte un obiect, in cazul de fata obiectul curent. Vom reveni cu amanunte in ce priveste obtinerea de informatii despre o clasa.

Redefinirea partiala a unei metode

Redefinirea partiala inseamna ca metoda din clasa derivata nu redefineste complet metoda cu aceeasi semnatura din superclasa, ci extinde operatiile pe care aceasta le realizeaza. Cu alte cuvinte, metoda din clasa derivata face ceva in plus fata de cea originala din superclasa.

Pentru a apela metoda din superclasa in interiorul metodei din clasa derivata se foloseste referinta super.

04/17/23 19

Urmatorul program (AfisareSubClasa1.java) ilustreaza modul de redefinire partiala a metodei afisareDate() din subclasa AfisareSubClasa1 si apelul in cadrul acesteia a metodei afisareDate() din superclasa AfisareClasa.

class AfisareClasa {int x = 0;int y = 1;

void afisareDate() {System.out.println("Sunt un obiect al clasei " +

this.getClass().getName());System.out.println("x este " + x);System.out.println("y este " + y);

}}class AfisareSubClasa1 extends AfisareClasa { int z = 3; void afisareDate() {

super.afisareDate();System.out.println("z este " + z);

} public static void main(String [] args) { AfisareSubClasa1 ob = new AfisareSubClasa1();

ob.afisareDate(); }}

04/17/23 20

Accesul la metodele din superclasa si redefinirea metodelor in clasele derivate

Atunci cand se creaza o clasa derivata si se redefineste (suprascrie) o metoda declarata intr-o superclasa, trebuie sa se ia in considerare tipul de acces dat pentru metoda originala.

Astfel, in cazul metodelor mostenite, pentru care se doreste redefinirea (suprascrierea) in clasa derivata se impun urmatoarele reguli:

- metodele de tip public dintr-o superclasa trebuie sa fie, de asemenea, de tip public in toate clasele derivate; ele nu pot fi redefinite de tip private in clasele derivate;

- metodele de tip protected dintr-o superclasa pot fi de tip protected sau de tip public in clasele derivate; ele nu pot fi redefinite de tip private in clasele derivate;

- metodele de tip private dintr-o superclasa nu pot fi redefinite (suprascrise) in clasele derivate.

04/17/23 21

Polimorfism

Polimorfismul reprezinta capacitatea unui obiect de a aparea sub diferite forme. De exemplu, in lumea reala, apa apare sub forma solida, sub forma lichida sau sub forma gazoasa.

In Java, polimorfismul inseamna ca o singura variabila referinta x de tipul unei superclase poate fi folosita pentru a construi diferite obiecte (instante) ale claselor derivate, direct sau indirect din acea superclasa, in momente diferite ale executiei unui program. Cand variabila referinta x este folosita pentru a apela o metoda a unui obiect apartinand unei clase derivate, metoda adecvata care va fi selectata depinde de tipul obiectului pe care variabila referinta x il indica in acel moment. Se spune ca variabila referinta este polimorfica.

De exemplu, sa presupunem ca s-au definit clasele: AnimalDeCasa, Pisica, Caine. Se doreste sa se afiseze la ecran (programul Polimorfism.java) caracteristicile principale ale claselor Pisica si Caine, atunci cand instantele lor sunt infometate.

04/17/23 22

class AnimalDeCasa{

private boolean stareSuparare;public boolean flamand;

protected void hranesc() {

System.out.println("Nu se cunoaste"); } public void caracteristici() {

System.out.println("Caracteristici necunoscute"); } public boolean getStare() { return stareSuparare; } public void setStare(boolean stare) {

stareSuparare = stare; }}

04/17/23 23

class Pisica extends AnimalDeCasa{ public void caracteristici() {

String starePisica; if (getStare() == true) starePisica = "miauna"; else starePisica = "nu miauna"; if (flamand == true) System.out.println("Pisica " + starePisica + ". Este flamanda."); else System.out.println("Pisica " + starePisica + ". Este satula.");

} public void hranesc() {

if (flamand==true) {System.out.println("Pisica mananca lapte."); flamand = false; setStare(false);} else System.out.println("Pisica a mancat deja.");}

}

04/17/23 24

class Caine extends AnimalDeCasa{ public void caracteristici() {

String stareCaine; if (getStare() == true) stareCaine = "latra"; else stareCaine = "nu latra"; if (flamand == true) System.out.println("Cainele " + stareCaine + ". Este flamand."); else System.out.println("Cainele " + stareCaine + ". Este satul.");

} public void hranesc()

{ if (flamand==true) {System.out.println("Cainele mananca oase."); flamand = false; setStare(false);} else System.out.println("Cainele a mancat deja.");}

}

04/17/23 25

public class Polimorfism{ public static void main(String args[]) { AnimalDeCasa a = new Pisica(); a.flamand = true; a.setStare(true); System.out.println("Caracteristicile primului animal de casa: "); a.caracteristici(); a.hranesc(); a.caracteristici(); a.hranesc(); a.caracteristici(); a = new Caine(); a.flamand = true; a.setStare(true); System.out.println("Caracteristicile celui de al doilea animal de casa: "); a.caracteristici(); a.hranesc(); a.caracteristici(); }}

04/17/23 26

Ceeace este specific acestui program este ca el contine trei metode cu numele caracteristici() care au aceeasi semnatura (nume, tip valoare returnata si numar si tip parametrii) si trei metode cu numele hranesc() care au, de asemenea, aceeasi semnatura. Dar, aceste metode se afla in clase diferite si anume, intr-o superclasa numita AnimalDeCasa si in doua clase derivate numite Pisica si Caine care extind clasa AnimalDeCasa.

Spunem ca metodele caracteristici() si hranesc() din clasele derivate redefinesc (override) metodea caracteristici() si, respectiv, hranesc() din superclasa.

Sa analizam acum instructiunea urmatoare:

AnimalDeCasa a = new Pisica();

Variabila referinta a care este de tipul AnimalDeCasa desemneaza un obiect de tipul Pisica, care ESTE-UN AnimalDeCasa prin mostenire.

Sa analizam si instructiunea:

a = new Caine();

Variabila a refera (la momente diferite de timp) obiecte de tipuri diferite, dar similare (adica derivate din aceeasi superclasa: AnimalDeCasa).

04/17/23 27

Pe baza celor prezentate mai sus, programul va afisa urmatoarele rezultate:

Caracteristicile primului animal de casa:Pisica miauna. Este flamanda.Pisica mananca lapte.Pisica nu miauna. Este satula.Pisica a mancat deja.Pisica nu miauna. Este satula.Caracteristicile celui de al doilea animal de casa:Cainele latra. Este flamand.Cainele mananca oase.Cainele nu latra. Este satul.

Dupa cum se poate observa, apelurile metodelor caracteristici() si hranesc(), prin intermediul referintei a, au determinat apelarea metodelor corespunzatoare din clasa Pisica si Caine (si prin urmare doua afisari diferite), deoarece la momentul fiecarui apel, variabila a refera un obiect de tip diferit (dar, apartinand unei clase derivate din superclasa).

Trebuie de remarcat ca, inversarea rolurilor celor doua clase nu este posibila, adica:

Pisica p = new AnimalDeCasa();

este incorecta (deoarece un animal nu este in mod obligatoriu o pisica).

04/17/23 28

In concluzie:

- pe de o parte, mostenirea permite tratarea unui obiect ca fiind de tipul propriu sau de tipul de baza (din care este derivat tipul propriu). Aceasta caracteristica permite mai multor tipuri (derivate din acelasi tip de baza) sa fie tratate ca si cum ar fi un singur tip, ceea ce face ca aceeasi secventa de cod sa fie folosita de catre toate aceste tipuri. In cazul din exemplul prezentat, clasa Pisica si clasa Caine au doua atribute (stareSuparare si flamand) si doua metode setStare() si getStare() mostenite de la superclasa AnimalDeCasa din care deriva.

- pe de alta parte, polimorfismul permite unui tip de obiect sa exprime distinctia fata de un alt tip de obiect similar, atata timp cat amandoua sunt derivate din aceeasi superclasa. Distinctia este exprimata prin redefinirea (suprascrierea) metodelor care pot fi apelate prin intermediul unei variabile-referinta de tipul superclasei (in exemplul nostru este vorba despre metodele caracteristici() si hranesc()).

04/17/23 29

Legarea statica si legarea dinamica

Conectarea unui apel de metoda de un anumit corp de metoda poarta numele de legare (binding).

Cand legarea are loc inainte de rularea programului respectiv (adica, in faza de compilare) spunem ca este vorba despre o legare statica(early binding). Termenul este specific programarii orientate pe obiecte. In programarea procedurala (vezi limbajul C sau Pascal) notiunea de legare statica nu exista, pentru ca toate legaturile se fac in mod static.

Cand legarea are loc in faza de executie a programului respectiv, spunem ca este vorba despre o legare tarzie (late binding) sau legare dinamica. Legarea tarzie permite determinarea in faza de executie a tipului obiectului referit de o variabila referinta si apelarea metodei specifice acestui tip (in exemplul prezentat, metodele caracteristici() si hranesc() din clasa Pisica sau din clasa Caine).

Polimorfisul apare doar atunci cand are loc legarea tarzie a metodelor.

04/17/23 30

Metode si clase finale

Metodele finale sunt acele metode care nu pot fi redefinite niciodata intr-o subclasa. Acestea sunt declarate folosind modificatorul final.

Metode finale sunt folosite pentru a mari viteza de executie a aplicatiei care le foloseste. In mod normal, atunci cand interpretorul Java apeleaza o metoda, el cauta metoda mai intai in clasa curenta, dupa aceea in superclasa si “urca” mai departe in ierarhie pana ce gaseste definitia acesteia. Prin acest proces se pierde din viteza in favoarea flexibilitatii si a usurintei in dezvoltare.

In cazul metodelor finale legarea este statica, la compilare, si nu in timpul executiei aplicatiei. Astfel, compilatorul Java poate introduce codul executabil (bytecode-ul) al metodei in locul instructiunii de apel a acesteia in cadrul programelor care o apeleaza.

Nota: Metodele cu acces de tip private sunt implicit si de tip final, deoarece ele nu pot fi suprascrise in nici o situatie.

Clasele finale sunt acele clase din care nu se pot deriva subclase. Acestea sunt declarate folosind modificatorul final.

Clasele finale sunt folosite pentru a mari viteza de executie a aplicatiei care le foloseste.

04/17/23 31

Majoritatea claselor mai des folosite din bibliotecile de clase Java sunt clase finale, cum ar fi: java.lang.String, java.lang.Math, java.lang.Integer etc.

Nota: Toate metodele dintr-o clasa de tip final sunt automat finale.

Metode si clase abstracte

O metoda abstracta este o metoda din superclasa care are sens doar pentru clasele derivate direct din superclasa, nu are implementare (nu are corp) ci numai antet, in superclasa si care in mod obligatoriu trebuie definita (completata cu corpul ei) in clasele derivate (altfel rezulta eroare de compilare).

O metoda abstracta este declarata cu modificatorul abstract.

Intr-o ierarhie de clase, cu cat clasa se afla pe un nivel mai inalt, cu atat definirea sa este mai abstracta. O clasa aflata ierarhic deasupra altor clase poate defini doar atributele si comportamentul comune celor aflate sub ea pe ramura respectiva a ierarhiei.

In procesul de organizare a unei ierarhi de clase, se poate descoperi, uneori, cate o clasa care nu se instantiaza direct (adica din ea nu se pot crea direct obiecte). De fapt, aceasta serveste, doar ca loc de pastrare a unor metode si atribute pe care le folosesc in comun subclasele sale. Acesta clasa se numeste clasa abstracta si este creata folosind modificatorul abstract.

04/17/23 32

Clasele abstracte pot contine aceleasi tipuri de membri ca o clasa normala, inclusiv metodele-constructor, deoarece subclasele lor pot avea nevoie sa mosteneasca aceste metode-constructor.

Clasele abstracte pot contine, de asemenea, metode abstracte. O clasa care are cel putin o metoda abstracta este o clasa abstracta.

Nu se poate declara o metoda abstracta intr-o clasa non-abstracta.

Exemplu de folosire a mostenirii, a polimorfismului, a claselor si metodelor finale si abstracte

Un exemplu simplu de clasa abstracta este clasa formelor geometrice. Din clasa formelor geometrice pot deriva forme specifice cum ar fi: cerc, dreptunghi. Se poate, apoi, deriva clasa patratului ca un caz particular de dreptunghi. Figura de mai jos prezinta ierarhia de clase care rezulta:

Cerc Dreptunghi

Patrat

FormaGeo

04/17/23 33

Clasa FormaGeo poate sa aiba membri care sa fie comuni pentru toate subclasele, cum ar fi, de exemplu tipul formei geometrice, afisarea caracteristicilor formelor geometrice concrete (cerc, dreptunghi etc).

De asemenea, clasa poate defini metode care se aplica fiecarui obiect in parte, cum ar fi, calculul ariei unui obiect oarecare (dreptunghi, cerc etc). In consecinta, metoda arie() va fi declarata ca abstracta.

Clasa FormaGeo fiind abstracta nu se poate instantia. Deci, nu se va putea crea un obiect de tip FormaGeo, ci numai obiecte din clasele derivate. Totusi, o referinta de tip FormaGeo poate sa refere orice forma concreta derivata, cum ar fi: Dreptunghi, Cerc, Patrat.

Fisierul-sursa urmator (FormaGeo.java) prezinta clasa abstracta FormaGeo. Constructorul acestei clase nu va fi apelat niciodata direct, deoarece FormaGeo este o clasa abstracta. Avem totusi nevoie de constructor, care sa fie apelat din clasele derivate pentru a initializa atributul nume de tip private care specifica tipul figurii geometrice.

Metoda cu numele arie() este o metoda abstracta, deoarece nu putem furniza nici un calcul implicit al ariei pentru o clasa derivata care nu isi defineste propria metoda de calcul a ariei.

04/17/23 34

Metoda maiMic() de comparatie a ariei unui obiect curent de tip FormaGeo cu un alt obiect de tip FormaGeo (preluat prin parametrul rhs) nu este abstracta, deoarece ea poate fi aplicata la fel pentru toate clasele derivate. De fapt, definirea ei este invarianta de-a lungul ierarhiei, de aceea am declarat-o cu tipul final.

Variabila rhs poate sa refere orice instanta a unei clase derivate din FormaGeo (de exemplu, o instanta a clasei Dreptunghi). Astfel, este posibil sa folosim aceasta metoda pentru a compara aria obiectului curent (care poate fi, de exemplu, o instanta a clasei Cerc) cu aria unui obiect de alt tip, derivat din FormaGeo. Acesta este un exemplu de folosire a polimorfismului.

Metoda toString afiseaza numele formei geometrice si aria ei. Ea este invarianta de-a lungul ierarhiei si de aceea a fost declarata cu tipul final.

Observatie: Vom face cateva precizari asupra folosirii metodei toString() in orice clasa in care se doreste afisarea starii instantelor unei clase. In general, afisarea starii unui obiect se face utilizand metoda print() din clasa System.out. Pentru a putea face acest lucru, trebuie ca in clasa obiectului care se doreste a fi afisat sa existe o metoda cu numele de toString(). Aceasta metoda trebuie sa intoarca o valoare de tip String (reprezentand starea obiectului) care poate fi afisata. Astfel, in cazul nostru, am definit o metoda toString care permite sa afisam un obiect oarecare de un tip derivat din clasa FormaGeo folosind instructiunea System.out.println(). Practic, compilatorul Java apeleaza automat toString() pentru fiecare obiect care se afiseaza cu metoda print().

04/17/23 35

/* Superclasa abstracta pentru forme FormeGeo * * CONSTRUIREA: nu este permisa, FormaGeo fiind abstracta. * Constructorul cu un parametru este necesar ptr. clasele * derivate. * ------------------- metode publice --------------------- * double arie() --> Intoarce aria (abstracta) * boolean maiMic --> Compara doua forme dupa arie * String toString --> Metoda uzuala pentru afisare */ abstract class FormaGeo {

private String nume; abstract public double arie(); public FormaGeo(String numeForma) {

nume = numeForma; } final public boolean maiMic(FormaGeo rhs) {

return arie() < rhs.arie(); } final public String toString() {

return nume + ", avand aria " + arie(); }

}

04/17/23 36

Pe baza clasei abstracte FormaGeo definite ne propunem sa rezolvam urmatoarea problema:

Se citesc N forme geometrice (patrate, dreptunghiuri, cercuri) de la tastatura. Sa se afiseze formele geometrice ordonate dupa arie.

Mai intai, trebuie sa definim subclasele Cerc, Dreptunghi si Patrat. Definirea lor se face distinct in fisiere-sursa separate (Cerc.java, Dreptunghi.java si Patrat.java).

/* clasa Cerc

* derivata din FormaGeo * CONSTRUCTORI: cu raza ptr. cerc * ------------------- metode publice --------------------- * double arie()-->Implementeaza metoda abstracta din FormaGeo */public class Cerc extends FormaGeo {

private double raza; public Cerc(double rad) {

super("Cerc"); raza = rad;

} public double arie() {

return Math.PI * raza * raza;} }

04/17/23 37

/* clasa Dreptunghi; * derivata din FormaGeo * CONSTRUCTORI: cu lungime si latime ptr. dreptunghi * ------------------- metode publice --------------------- * double arie()-->Implementeaza metoda abstracta din FormaGeo*/public class Dreptunghi extends FormaGeo {

private double lungime; private double latime; public Dreptunghi(double lg, double lat) {

this(lg, lat, "Dreptunghi"); } Dreptunghi(double lg, double lat, String nume) {

super(nume);lungime = lg;latime = lat;

} public double arie() {

return lungime * latime; }

}

04/17/23 38

/* clasa Patrat * derivata din Dreptunghi * CONSTRUCTORI: cu latura ptr. patrat * ------------------- metode publice --------------------- * double arie()-->Implementeaza metoda abstracta din FormaGeo */public class Patrat extends Dreptunghi{

public Patrat(double latura) {

super(latura, latura, "Patrat"); }

}

Observatie: Clasa Patrat mosteneste de la clasa Dreptunghi metoda arie() si de aceea nu o mai defineste in interiorul ei.

04/17/23 39

Pentru rezolvarea problemei ordonarii formelor geometrice dupa aria lor, se foloseste un tablou de tip FormaGeo cu numele forme[] cu o dimensiune citita de la tastatura. Sa retinem ca tablou forme[] este un tablou de referinte de tip FormaGeo pentru care se aloca zona de memorie. Acest tablou nu stocheaza obiecte din clasele derivate ale clasei FormaGeo (de tip Cerc, Dreptunghi, Patrat) ci numai referinte catre aceste obiecte.

Fisierul-sursa (TestForma.java) care realizeaza ordonarea si punerea in executie a aplicatiei se prezinta in continuare.

Metoda citesteForma() citeste de la tastatura atributele obiectelor de tipul Cerc, Dreptunghi, Patrat, pe baza unor optiuni care precizeaza tipul figurii, creaza un nou obiect de un tip derivat (Cerc, Dreptunghi, Patrat) din tipul FormaGeo si returneaza o referinta catre obiectul creat.

In metoda main(), referinta la obiecte este apoi stocata in tabloul forme[].

Metoda sortare() este folosita pentru a sorta formele geometrice referite prin tabloul forme[] in functie de aria calculata a fiecarui tip de figura geometrica. Metoda arie() este apelata prin intermediul metodei maiMic() care la randul ei este apelata in metoda sortare().

04/17/23 40

import java.io.* ;class TestForma {

private static BufferedReader in;public static void main(String[] args) throws IOException {

//Citeste numarul de figuriin = new BufferedReader(newInputStreamReader(System.in));System.out.print("Numarul de figuri: ");int numForme = Integer.parseInt(in.readLine());//citeste formeleFormaGeo[] forme = new FormaGeo[numForme];for (int i = 0; i < numForme; ++i)

{forme[i] = citesteForma();}//sortare si afisaresortare(forme);System.out.println("Sortarea dupa arie: ");for (int i = 0; i < numForme; ++i)

{System.out.println(forme[i]);}}

04/17/23 41

//creaza un obiect adecvat de tip FormaGeo. Functie de datele de intrare. //utilizatorul introduce 'c', 'p' sau 'd' pentru a indica forma, apoi introduce dimensiunile //in caz de eroare se intoarce un cerc de raza 0

private static FormaGeo citesteForma() throws IOException { double rad; double lg; double lat; String s; System.out.println("Introduceti tipul formei: ");do

{ s = in.readLine(); } while (s.length() == 0); switch (s.charAt(0)) {

case 'c': System.out.println("Raza cercului: "); rad = Integer.parseInt(in.readLine()); return new Cerc(rad);

case 'p': System.out.println("Latura patratului: "); lg = Integer.parseInt(in.readLine()); return new Patrat(lg);

04/17/23 42

case 'd': System.out.println("Lungimea si latimea " + " dreptunghiului pe linii separate: "); lg = Integer.parseInt(in.readLine()); lat= Integer.parseInt(in.readLine()); return new Dreptunghi(lg, lat);

default: System.err.println("Tastati c, p sau d: "); return new Cerc(0);

}

}//sortare

private static void sortare(FormaGeo [] a) {FormaGeo temp;for (int i = 0; i <= a.length - 2; i++) {for (int j = i+1; j <= a.length - 1; j++)

{if (a[j].maiMic(a[i])){temp = a[i]; a[i] = a[j]; a[j] = temp;}

}}}

}

04/17/23 43

Dupa executia programului TestForma.class pe ecran se afiseaza:

Sortarea dupa arie:Cerc, avand aria 3.141592653589793Dreptunghi, avand aria 6.0Dreptunghi, avand aria 8.0Dreptunghi, avand aria 24.0Patrat, avand aria 36.0Cerc, avand aria 78.53981633974483Patrat, avand aria 100.0Cerc, avand aria 314.1592653589793Cerc, avand aria 452.3893421169302Cerc, avand aria 452.3893421169302