Sunteți pe pagina 1din 9

Programare Java

Curs – 5

FOLOSIREA METODELOR PENTRU INDEPLINIREA SARCINILOR

Metodele sunt partea cea mai importanta a oricarui limbaj de programare orientat obiect deoarece ele
definesc fiecare actiune indeplinita de un obiect .
Clasele si obiectele ofera un cadru de lucru . Variabilele de instanta si de clasa ofera o modalitate de a
defini ceea ce reprezinta aceste clase si obiecte . Doar metodele pot defini comportamentul unui obiect
– lucrurile pe care este capabil sa le realizeze sau modul cum interactioneaza cu alte clase sau obiecte .
In cursurile anterioare am vazut cum sa definim o metoda si sa lucram cu ea practic . In continuare vom
detalia unele caracteristici care fac metodele sa fie mai eficiente si mai usor de folosit :

- supraincarcarea metodelor ( overloading ) – crearea de metode cu diferite semnaturi si definitii


insa cu acelasi nume

- crearea metodelor constructor – metode care permit initializarea obiectelor , pentru a le defini
starea initiala din momentul crearii lor

- suprascrierea metodelor (overriding ) – crearea unei definitii diferite penttu o metoda care a
mai fost definita in superclasa

- metode de finalizare ( finalizer ) – metode care elibereaza resursele ocupate de un obiect dupa
terminarea lucrului cu un el , inainte ca acesta sa fie inlaturat din sistem

CREAREA DE METODE CU ACELASI NUME SI ARGUMENTE DIFERITE

Un exemplu de astfel de metoda este valueOf() ; metoda apartine clasei java.lang.String . In general in
Java vom intalni des clase care contin mai multe metode cu acelasi nume .

Metodele cu acelasi nume se diferentiaza intre ele prin doua caracteristici :

- numarul argumentelor pe care le preiau


- tipul datelor sau obiectelor fiecarui argument

Aceste doua caracteristici definesc semnatura metodei ; folosirea mai multor metode cu acelasi nume si
semnaturi diferite se numeste supraincarcare .
In exemplul clasei String , metodele valueOf() sunt supraincarcate deoarece preiau ca parametri tipuri
de date diferite .
Supraincarcarea metodelor elimina nevoia de a defini metode complet diferite care sa faca in principiu
acelasi lucru . Supraincarcarea face de asemenea posibila comportarea diferita a metodelor in functie de
argumentele primite .
Metodele valueOf() pot fi folosite pentru a converti diverse tipuri de date sau obiecte in siruri . Atunci
cand apelam o metoda a unui obiect Java verifica numele si argumentele acesteia pentru a vedea ce
metoda va executa .

Pentru a crea o metoda supraincarcata intr-o clasa vom defini metode diferite , cu acelasi nume insa cu
liste de argumente diferite . Diferenta poate consta in numarul de argumente , in tipul de argumente sau
ambele . Java permite supraincarcarea metodelor atat timp cat lista de argumente este unica pentru
acelasi nume de metoda .
Mentionez ca Java nu ia in considerare tipul valorii returnate pentru a face diferentierea metodelor
supraincarcate . Daca incercam sa cream doua metode care difera doar prin tipul valorii de retur vom
obtine o eroare inca de la compilare . In plus numele variabilelor pe care le alegem pentru fiecare
argument nu au importanta – tot ceea ce conteaza este numarul si tipul acestora .

1
In continuare vom detalia un exemplu de metoda supraincarcata . Vom crea intai o clasa care defineste
o forma rectangulara cu patru variabile de instanta , pentru a preciza colturile din stanga-sus si dreapta-
jos ale unui dreptunghi : x1 , y1 , x2 , y2 .

class DreptunghiulMeu {
int x1=0;
int y1=0;
int x2=0;
int y2=0;
}

Atunci cand este creata o noua instanta a clasei noastre toate valorile vor fi initializate cu 0 . In
continuare vom defini o metoda care preia patru argumente intregi si returneaza obiectul rectangular .
Deoarece argumentele au acelasi nume cu variabilele de instanta , in cadrul metodei vom folosi
cuvantul cheie this pentru a referi variabilele de instanta :

DreptunghiulMeu construireDreptunghi ( int x1 , int y1 , int x2, int y2) {


this.x1=x1;
this.y1=y1;
this.x2=x2;
this.y2=y2;
return this;
}

O alta varianta ar fi folosirea obiectelor Point in locul coordonatelor individuale . Pentru a implementa
aceasta varianta putem supraincarca metoda noastra astfel incat lista de argumente sa contina doua
obiecte Point :

DreptunghiulMeu construireDreptunghi ( Point stangaSus , Point dreaptaJos ) {


x1=stangaSus.x;
y1=stangaSus.y;
x2=dreaptaJos.x;
y2=dreaptaJos.y;
return this;
}

Pentru ca metoda anterioara sa functioneze clasa Point trebuie importata la inceputul codului sursa .

O alta modalitate de a defini un dreptunghi este de a folosi coordonatele coltului din stanga-sus
impreuna cu valorile inaltimii si latimii sale :

DreptunghiulMeu construireDreptunghi(Point stangaSus , int l , int h ) {


x1=stangaSus.x;
y1=stangaSus.y;
x2=(x1+l);
y2=(y1+h);
return this;
}

Pentru a finaliza exemplul mai cream o clasa , afisareDreptunghi() , care urmeaza sa afiseze
coordonatele dreptunghiului , si o metoda main() care sa apeleze toate aceste metode :

2
import java.awt.Point;

class DreptunghiulMeu {
int x1=0;
int y1=0;
int x2=0;
int y2=0;

DreptunghiulMeu construireDreptunghi(int x1 , int y1 , int x2 , int y2) {


this.x1=x1;
this.y1=y1;
this.x2=x2;
this.y2=y2;
return this;
}

DreptunghiulMeu construireDreptunghi(Point stangaSus , Point dreaptaJos ) {


x1=stangaSus.x;
y1=stangaSus.y;
x2=dreaptaJos.x;
y2=dreaptaJos.y;
return this;
}

DreptunghiulMeu construireDreptunghi(Point stangaSus , int l , int h) {


x1=stangaSus.x;
y1=stangaSus.y;
x2=(x1+l);
y2=(y1+h);
return this;
}

void afisareDreptunghi() {
System.out.print(“Dreptunghiul meu : <”+x1+”, “+y1);
System.out.println(“, “+x2+”, “+y2+”>”);
}

public static void main(String argumente[]) {


DreptunghiulMeu dreptunghi=new DreptunghiulMeu();

System.out.println(“Apelam construireDreptunghi cu coordonatele 25,25,50,50 : “);


dreptunghi.construireDreptunghi(25,25,50,50);
dreptunghi.afisareDreptunghi();
System.out.println(“***”);

System.out,println(“Apelam construireDreptunghi cu punctele (10,10) , (20,20): “);


dreptunghi.construireDreptunghi(new Point(10,10, new Point(20,20));
dreptunghi.afisareDreptunghi();
System.out.println(“***”);

System.out.print(“Apelam construireDreptunghi cu 1 punct (10,10),”);


System.out.println(“ latime 50 si inaltime 50 : “);
dreptunghi.construireDreptunghi( new Point(10,10) , 50 , 50 );
dreptunghi.afisareDreptunghi();
System.out.println(“***”);
}
}

3
Atunci cand avem mai multe metode care fac lucruri asemanatoare , intr-o metoda putem apela o alta .
De exemplu , in cazul de mai sus , metoda construireDreptunghi care primeste ca argumente doua
obiecte Point poate fi inlocuita cu o versiune mult mai scurta :

DreptunghiulMeu construireDreptunghi(Point stangaSus , Point dreaptaJos) {


return construireDreptunghi(stangaSus.x , stangaSus.y , dreaptaJos.x , dreaptaJos.y );
}

METODE CONSTRUCTOR

In afara de metode obisnuite in clase putem defini si metode constructor .


O metoda constructor este o metoda apelata la crearea unui obiect – cu alte cuvinte , atunci cand
obiectul este construit .

Spre deosebire de alte metode , o metoda constructor nu poate fi apelata direct ; Java apeleaza metodele
constructor in mod automat .
Atunci cand este folosita instructiunea new pentru crearea unui nou obiect , Java executa trei activitati :

- aloca memorie pentru obiect


- initializeaza variabilele de instanta ale obiectului fie la valorile initiale fie la cele prestabilite
( o pentru numere , null pentru obiecte , false pentru valori booleene si “\0” pentru caractere )
- apeleaza metodele constructor ale clasei

Chiar daca o clasa nu are definita nici o metoda constructor este totusi posibila crearea unui obiect .
Exista insa cazuri in care dorim sa setam anumite variabile de instanta sau sa apelam alte metode de
care obiectul are nevoie pentru a se initializa .
Prin definirea unor metode constructor in clase , putem seta valorile initiale ale variabilelor de instanta ,
putem apela metode pe bza acestor variabile , putem apela metode ale altor obiecte sau putem seta
proprietatile initiale ale unui obiect . Metodele constructor pot fi si ele supraincarcate , la fel ca
metodele obisnuite , pentru a crea un obiect care are proprietati specifice in functie de argumentele
transmise prin instructiunea new .

METODE CONSTRUCTOR DE BAZA

Constructorii seamana cu netodele obisnuite , cu doua diferente :

- metodele constructor au totdeauna acelasi nume cu cel al clasei


- metodele constructor nu returneaza nimic

In exemplul de mai jos vom vedea o clasa Persoana care foloseste o metoda constructor pentru a-si
initializa variabilele de instanta pe baza argumentelor primite de new :

class Persoana {
String nume;
int varsta;
Persoana (String n , int a) {
nume=n;
varsta=a;
}
void printPersoana() {
System.out.print(“Eu sunt “+nume);
System.out.println(“ si am “+varsta+” de ani”);
}
public static void main (String argumente[]) {
Persoana p;
p=new Persoana(“Ion”,50);

4
p.printPersoana();
System.out.Println(“----“);
p=new Persoana(“Laura”,30);
p.printPersoana();
System.out.println(“----“);
}
}

APELAREA UNEI ALTE METODE CONSTRUCTOR

Am vazut anterior cum o metoda poate apela o alta metoda in casrul ei .


Acelasi lucru poate fi facut si in cazul constructorilor . Daca avem o metoda constructor ce reprezinta
un comportament oarecum asemanator cu cel al unui constructor existent putem apela primul
constructor din interiorul celui de-al doilea . Java ofera o sintaxa speciala pentru a realize acest lucru .
Folosim urmatoarea instructiune pentru a apela o metoda constructor definite in clasa curenta :

this(arg1 , arg2 , arg3);

Folosirea cuvantului cheie this intr-o metoda constructor este similara modului lui de folosire pentru
accesul la variabilele de instanta ale obiectului . In instructiunea anterioara argumentele primate de
this() sunt argumentele metodei constructor . De exemplu , sa luam o clasa care defineste un cerc
folosind coordonatele (x,y) ale centrului si lungimea razei . Clasa CerculMeu poate avea doi
constructori : unul in care este definita raza si unul in care raza primeste valoarea prestabilita 1 :

class CerculMeu {
int x,y,raza;
CerculMeu (int coordX , int coordY , int lungRaza) {
this.x=coordX;
this.y=coordY;
this.raza=lungRaza;
}
CerculMeu (int coordX , int coordY) {
this(coordX, coordY, 1);
}
}

A doua metoda constructor din clasa CerculMeu preia doar coordonatele x si y ale cercului . Deoarece
nu este definite nici o raza se foloseste valoarea prestabilita 1 ; se apeleaza apoi prima metoda
constructor care primeste ca argumente coordX , coordY si literalul 1 .

SUPRAINCARCAREA METODELOR CONSTRUCTOR

Ca si metodele obisnuite constructorii pot avea un numar diferit de argumente sau tipuri ale acestora .
Aceasta ne permite sa cream un obiect cu proprietatile dorite sau ofera acestuia posibilitatea de a-si
calcula proprietatile pornind de la date de intrare diferite .

De exemplu , metodele construireDreptunghi , definite in exemplele anterioare , pot constitui niste


metode constructor foarte logice deoarece sunt folosite pentru a initializa variabilele de instanta . Astfel
, in loc de metoda originala construireDreptunghi ( care primea patru parametric ) am putea crea un
constructor .

SUPRASCRIEREA METODELOR

Atunci cand apelam metoda unui obiect , Java cauta definitia metodei respective in clasa obiectului .
Daca nu o gaseste cauta mai sus in ierarhia de clase pana cand gaseste o definitie . Procesul de

5
mostenire a metodelor ne permite sa definim si sa folosim repetat metode in subclase fara a fi nevoie sa
replicam codul .
Totusi pot exista cazuri cand dorim ca un obiect sa raspunda acelorasi metode , dar sa aiba un
comportament diferit la apelarea acestora . In acest caz , metoda se poate suprascrie . Pentru a
suprascrie o metoda , definim intr-o subclasa o metoda cu aceeasi semnatura ca a unei metode dintr-o
superclasa . Astfel , atunci cand metoda este apelata , metoda din subclasa este gasita prima si executata
in locul celei din superclasa .

CREAREA DE METODE CARE SUPRASCRIU METODE EXISTENTE

Pentru a suprascrie o metoda , in practica trebuie sa cream o metoda cu aceeasi semnatura ( nume , tip ,
valoare returnata , lista de argumente ) ca a metodei din superclasa .
Mai jos cream un exemplu pentru a ilustra supraincarcarea unei metode :

class AfisareClasa {
int x=0;
int y=0;
void afisareDate() {
System.out.println(“x este “+x+” si y este “+y);
System.out.println(“Sunt o instanta a clasei “+this.getClass().getName());
}
}

Cream in continuare si o subclasa a clasei de mai sus , cu o singura diferenta , subclasa contine si
variabila z :

class AfisareSubClasa extends AfisareClasa {


int z=3;
public static void main(String argumente[]) {
AfisareSubClasa obiect=new AfisareSubClasa();
obiect.afisareDate();
}
}

Deoarece subclasa nu defineste o metoda afisareDate() , Java o cauta in superclasa si o gaseste acolo
pentru a o putea executa . Aceasta metoda insa nu afiseaza si variabila de instanta z .

Sa cream o noua subclasa care sa suprascrie metoda afisareDate() :

class AfisareSubClasa2 extends AfisareClasa {


int z=3;
void afisareDate() {
System.out.println(“x este “+x+” si y este “+y+” iar z este “+z);
System.out.println(“Sunt o instanta a clasei “+this.getClass().getName());
}
public static void main(String argumente[]) {
AfisareSubClasa2 obiect=new AfisareSubClasa2();
obiect.afisareDate();
}
}

Acum , dupa initializarea obiectului AfisareSubClasa2 si apelarea metodei afisareDate() va fi apelata


versiunea existenta in subclasa si nu pe cea din superclasa AfisareDate .

6
APELAREA METODEI ORIGINALE

De obicei exista doua motive pentru care se face suprascrierea unei metode implementate deja de o
superclasa :

- pentru a inlocui complet definitia metodei originale


- pentru a extinde functionalitatea metodei originale

In multe cazuri practice comportamentul metodei originale trebuie doar completat si nu inlocuit
definitiv , mai ales in cazurile cand se realizeaza acelasi tip de actiuni si in metoda originala si in cea
care o suprascrie . Prin apelarea metodei originale in cadrul metodei de suprascriere putem adauga
numai insusirea suplimentara .
Pentru a apela metoda originala in cadrul metodei de suprascriere folosim cuvantul cheie super . In
acest fel apelul metodei este transferat mai sus in cadrul ierarhiei de obiecte :

void metodaMea ( String a , String b ) {


//cod sursa
super.metodaMea(a,b);
//cod sursa
}

Cuvantul cheie super este asemanator cuvantului cheie this , deoarece este o denumire generica pentru
superclasa clasei curente . Il putem folosi oriunde am putea folosi si this , insa super refera superclasa
nu clasa curenta .

Sa ne amintim de cele doua metode afisareDate() diferite , folosite anterior .


In loc sa copiem majoritatea codului metodei superclasei in subclasa , putem modifica metoda
superclasei astfel incat ulterior sa se poata adauga cu usurinta o caracteristica suplimentara :

// din AfisareClasa
void afisareDate() {
System.out.println(“Sunt o instanta a clasei “+this.getClass().getName());
System.out.println(“X este “+x);
System.out.println(“Y este “+y);
}

Apoi , cand suprascriem metoda afisareDate() in subclasa putem apela metoda originala si adauga doar
codul suplimentar :

// din AfisareSubClasa2
void afisareDate() {
super.afisareDate();
System.out.println(“Z este “+z);
}

SUPRASCRIEREA CONSTRUCTORILOR

Din punct de vedere tehnic constructorii nu pot fi suprascrisi . Pentru ca au totdeauna acelasi nume ca
al clasei curente , metodele constructor nu se mostenesc ci se creaza altele noi . Acest sistem este
multumitor in marea majoritate a cazurilor ; atunci cand este apelata metoda constructor a clasei se
apeleaza si metoda constructor cu aceeasi semnatura pentru toate superclasele . Din aceasta cauza
initializarea se face pentru toate partile clasei pe care o mostenim .

7
Totusi , atunci cand definim metode constructor pentru clasa noastra putem modifica felul in care este
initializat obiectul nu doar prin initializarea noilor variabile adaugate clasei , ci si prin modificarea
continutului variabilelor deja prezente . Pentru aceasta vom apela explicit metodele constructor ale
superclasei si apoi vom modifica variabilele dorite .

Pentru a apela o metoda obisnuita apartinand superclasei vom folosi sintaxa


super.nume_metoda(lista_argumente) . Deoarece metodele constructor nu au nume sub care pot fi
apelate vom folosi urmatoarea forma :

super(arg1 , arg2 , ... );

Retinem ca Java are o regula stricta pentru folosirea metodei super() : aceasta trebuie sa sie prima
instructiune folosita in cadrul constructorului . Daca nu apelam super() explicit in cadrul
constructorului Java face acest lucru implicit , folosind super() fara argumente . Deoarece apelarea
super() trebuie sa fie prima instructiune nu putem folosi un cod de genul :

if (conditie==true)
super(1 , 2 , 3); // apelarea unui constructor al superclasei
else
super( 1 , 2 ); // apelarea unui alt constructor

La fel ca in folosirea this(...) intr-o metoda constructor , super(...) apeleaza metoda constructor pentru
superclasa imediat urmatoare ( care la randul sau va apela constructorul superclasei sale si asa mai
departe ) . Retinem ca in superclasa trebuie sa existe un constructor cu semnatura respectiva pentru ca
apelul super() sa functioneze . Compilatorul Java verifica aceste lucruri atunci cand incercam sa
compilam fisierul sursa .

Nu trebuie sa apelam constructorul din superclasa care are aceeasi semnatura cu cea a constructorului
clasei noastre ; trebuie doar sa apelam constructorul pentru valorile pe care dorim sa le initializam . De
fapt , putem crea o clasa care are constructori cu semnaturi total diferite de oricare dintre constructorii
superclasei .

In exemplul urmator vom prezenta o clasa PunctCuNume care extinde clasa Point a pachetului java.awt
. Clasa Point are un singur constructor care preia argumentele x si y si returneaza un obiect Point .
PunctCuNume contine o variabila de instanta suplimentara si defineste un constructor care initializeaza
x , y si numele .

import java.awt.Poin;
class PunctCuNume ( int x , int y , String nume ) {
super(x,y);
this.nume=nume;
}
public static void main(String argumente[]) {
PunctCuNume pn=new PunctCuNume(5,5,”PunctulA”);
System.out.println(“x este “+pn.x);
System.out.println(“y este “+pn.y);
System.out.println(“Numele este “+pn.nume);
}
}

Metoda constructor definita aici pentru PunctCuNume apeleaza metoda constructor a clasei Point
pentru a initializa variabilele de instanta x si y . Chiar daca am putea initializa si singuri , explicit ,
variabilele x si y exista posibilitatea sa existe si alte lucruri care s-ar intampla la initilizarea obiectelor
Point ; din aceasta cauza este mai bine sa apelam metodele constructor aflate deasupra in ierarhie ,
pentru a fi siguri ca totul se configureaza corect .

8
METODE DE FINALIZARE

Metodele de finalizare sunt opusul metodelor constructor . O metoda constructor este folosita pentru a
initializa un obiect iar metodele de finalizare sunt apelate chiar inainte de distrugerea obiectului si
recuperarea memoriei ocupate .

Metoda de finalizare este finalize() . Clasa Object defineste o metoda de finalizare prestabilita , care nu
face nimic ( este vida ) . Pentru a crea o metoda de finalizare pentru propriile clase putem suprascrie
metoda finalize() folosind semnatura :

protected void finalize() throws Throwable {


super.finalize();
}

In cadrul metodei finalize() putem specifica toate actiunile de “curatare” pe care dorim sa le realizam in
legatura cu obiectul . De asemenea putem apela super.finalize() pentru a permite superclasei clasei
noastre sa finalizeze obiectul daca este nevoie .
Putem apela metoda finalize() oricand – este o metoda ca oricare alta . Totusi apelarea ei nu semnaleaza
sistemului distrugerea obiectului si recuperarea memoriei ocupate . Numai stergerea tuturor referintelor
la obiectul respectiv duce la marcarea lui pentru distrugere .
Metodele de finalizare sunt folosite de obicei pentru optimizarea distrugerii unui obiect – de exemplu ,
pentru distrugerea referintelor catre alte obiecte . In marea majoritate a cazurilor practice nu este nevoie
se folosim deloc metoda explicita finalize() .