Sunteți pe pagina 1din 184

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

IE.
TEHNICI AVANSATE DE
PROGRAMARE

-1-

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

CUPRINS
Cuvnt nainte ........................................................................................................................................... 6
Capitolul IE.01. Noiuni de baz ale programrii orientate obiect 7
IE.01.1. Paradigme de programare .......................................................................................... 7
IE.01.2. Programare orientat pe obiecte ............................................................................ ... 8
IE.01.3. Avantajele programrii cu obiecte ........................................................................... 11
IE.01.4. Clasele ca module de program reutilizabile ............................................................. 13
IE.01.5. ncapsulare .............................................................................................................. 14
IE.01.6. Clasele permit programarea generic ....................................................................... 15
IE.01.7. Clasele creeaz un model pentru universul aplicaiei .............................................. 16
IE.01.8.Tehnici de programare specifice POO ....................................................... 17
IE.01.9. Analiza i proiectarea orientate pe obiecte ............................................... 19
Capitolul IE.02. Clase i obiecte n Java ................................................................................................. 21
IE.02.1. Sintaxa limbajului Java ........................................................................................... 21
IE.02.2. Definirea de clase n Java ......................................................................................... 30
IE.02.3. Obiecte Java .............................................................................................................. 33
IE.02.4. iruri de caractere n Java ......................................................................................... 34
IE.02.5. Operaii de citire-scriere n Java ............................................................................... 36
Capitolul IE.03. Derivare, motenire, polimorfism n Java ..39
IE.03.1. Derivarea (extinderea) claselor ................................................................................ 39
IE.03.2. Clasa Object ca baz a ierarhiei de clase Java ........................................................ 40
IE.03.3. Suprascriere de metode n subclase ........................................................................... 41
IE.03.4. Derivarea ca metod de reutilizare ............................................................................ 42
IE.03.5. Derivare pentru crearea unor ierarhii de tipuri .......................................................... 44
IE.03.6. Polimorfism ....................................................................................... 46
IE.03.7. Delegarea ca alternativ la derivare pentru reutilizare .............................................. 48
IE.03.8. Motenire multipl prin derivare i delegare ............................................................ 50
Capitolul IE.04. Clase abstracte i interfee ... 54
IE.04.1. Clase abstracte n Java ................................................................................ 54
IE.04.2. Interfee n Java ....................................................................................................... 56
IE.04.3. Comparaie ntre interfee i clase abstracte.............................................................. 57
IE.04.4. Interfee Java pentru compararea de obiecte ............................................................. 59
IE.04.5. Interfee Java pentru enumerare ............................................................................... 59
IE.04.6. Interfee Java pentru filtrare ......................................................... 61
Capitolul IE.05. Tehnici de programare orientat obiect n Java . 66
IE.05.1. Excepii n Java ........................................................................................................ 66
IE.05.2. Reflecie n Java ........................................................................................................ 69
IE.05.3. Clase incluse . 70
IE.05.4. Fire de execuie ca obiecte ........................................................................................ 74

-2-

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Capitolul IE.06. Colecii de obiecte n Java .. 82


IE.06.1. Grupul claselor colecie ........................................................................................ 82
IE.06.2. Mulimi de obiecte ................................................................................................. 84
IE.06.3. Liste ( secvene) .................................................................................................... 85
IE.06.4. Dicionare (asocieri) .............................................................................................. 87
IE.06.5. Colecii ordonate ................................................................................................... 88
IE.06.6. Iteratori .................................................................................................................. 90
IE.06.7. Generice ................................................................................................................. 92
Capitolul IE.07. Diagrame de clase n UML .... 96
IE.07.1. Grupul claselor colecie ........................................................................................ 96
IE.07.2. Standardul UML ................................................................................................... 96
IE.07.3. Relaia de generalizare n UML............................................................................. 98
IE.07.4. Relaii de asociere n UML.................................................................................... 98
IE.07.5. Relaia de includere n UML ............................................................................... 100
IE.07.6. Clase abstracte i interfee n UML ..................................................................... 101
IE.07.7. Studiu de caz ....................................................................................................... 103
Capitolul IE.08. abloane de proiectare cu clase.. 106
IE.08.1. Proiectarea orientat pe obiecte ........................................................................ 106
IE.08.2. abloane de proiectare ....................................................................................... 107
IE.08.3. ablonul Singleton .............................................................................................. 107
IE.08.4. ablonul Iterator.................................................................................................. 109
IE.08.5. ablonul Observator............ ............................................................................... 110
IE.08.6. ablonul Adaptor........................... ..................................................................... 111
IE.08.7. ablonul Compozit............................................................................................... 112
IE.08.8. ablonul Decorator.............................................................................................. 113
IE.08.9. ablonul Fabric de obiecte.. ............................................................................. 114
IE.08.10. ablonul Fabric abstract....................................................................... 116
IE.08.11. ablonul Model-View-Controller...................................................................... 117
IE.08.12. ablonul DI (Injectarea dependenelor) ........................................................... 119
Capitolul IE.09. Interfee grafice i programare orientat pe evenimente ... 123
IE.09.1. Aplicaii cu interfa grafic ..... .......................................................................... 123
IE.09.2. Clase Java pentru o interfa grafic .................................................................. 124
IE.09.3. Plasarea componentelor ...................................................................................... 125
IE.09.4. Structura programelor cu interfa grafic .......................................................... 127
IE.09.5. Programarea bazat pe evenimente ..................................................................... 129
IE.09.6. Evenimente Swing ........................ ..................................................................... 130
IE.09.7. Structura programelor dirijate de evenimente ..................................................... 132
IE.09.8. Aplei Java ................................................................................... 135
IE.09.9. Clase Swing cu model .............................................................................136
Capitolul IE.10. Mediul de programare NetBeans .... 140
IE.10.1. Dezvoltarea de aplicaii Java ... ......................................................................... 140
IE.10.2. Mediul integrat NetBeans .................................................................................. 141
IE.10.3. Editorul Java din NetBeans ................................................................................ 145
IE.10.4. Refactorizare n NetBeans .................................................................................. 149
IE.10.5. Testarea programelor Java n NetBeans .............................................................. 150
IE.10.6. Programare vizual n NetBeans ......................................................................... 153
-3-

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Capitolul IE.11. Platforma Java .. 159


IE.11.1. Java ca platform orientat obiect ..................................................................... 159
IE.11.2. Limbajul Groovy ........ ....................................................................................... 159
IE.11.3. Simplificarea codului surs n Groovy................................................................ 160
IE.11.4. Operatori i instruciuni Groovy ......................................................................... 161
IE.11.5. Clase Groovy ...................... ............................................................................... 162
IE.11.6. Diferene Groovy- Java ................ ..................................................................... 163
IE.11.7. Metode noi n clase Java .................................................................................... 164
IE.11.8. Utilizarea de expresii regulate ............................................................................ 165
IE.11.9. Functori Groovy .............................................................................. 166
IE.11.10. Colecii Groovy ......................................................................... 171
IE.11.11. Metaprogramare n Groovy ....................................................................... 175
Capitolul IE.12. Autoevaluare .. 184
IE.12.1. Noiuni de baz ale programrii orientate obiect .............................................. 184
IE.12.2. Clase i obiecte n Java ....................................................................................... 185
IE.12.3. Derivare, motenire, polimorfism n Java .......................................................... 187
IE.12.4. Clase abstracte i interfee ................................................................................... 188
IE.12.5. Tehnici de programare orientat obiect n Java ................................................... 189
IE.12.6. Colecii de obiecte n Java ............. ..................................................................... 190
IE.12.7. Diagrame de clase n UML .................................................................................. 192
IE.12.8. abloane de proiectare cu clase ........................................................................... 193
IE.12.9. Interfee grafice i programare orientat pe evenimente ...................................... 194
IE.12.10. Mediul de programare NetBeans ...................................................................... 195
IE.12.11. Platforma Java ........................................................................ 196

Bibliografie ......................................................................................................................................... 197

-4-

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

-5-

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Cuvnt nainte
Scrierea de programe pentru calculatoare poate fi abordat din puncte de vedere diferite, numite i
paradigme de programare. Principalele paradigme i limbajele de programare reprezentative pentru acestea
sunt: programarea procedural ( Pascal, C), programarea funcional (Lisp, Scheme), programarea logic
(Prolog), programare orientat pe obiecte (C++,C#, Java, Scala), programare declarativ (HTML,XML) i
programare specific unor domenii (SQL, Javascript, PHP). In raport cu programarea procedural,
programarea cu clase i obiecte este considerat ca programare avansat, care include tehnici de
programare procedural dar adaug conceptul de clas.
Pentru aplicaii mari sau cu interfa grafic s-a impus programarea orientat pe obiecte i limbajul Java,
care ntr-un studiu din aprilie 2013 era pe locul 2 ntre cele mai cerute limbaje de firme la angajare. Toate
sistemele de operare au un interpretor de Java iar toate programele necesare dezvoltrii de aplicaii n Java
sunt gratuite. n plus exist cteva medii integrate de programare gratuite care faciliteaz mult dezvoltarea,
testarea i ntreinerea aplicaiilor Java : Eclipse, NetBeans, IDEA. Limbajul Java i programarea cu obiecte
se studiaz la toate universittile i colegiile din lume, iar la Universitatea Politehnica din Bucuresti este
disciplin obligatorie la facultile de Automatic si Calculatoare i de Inginerie n Limbi Strine.
Acest suport de curs, care include i probleme propuse si/sau rezolvate, se bazeaz pe materia cursurilor
Programare Orientat pe Obiecte i Ingineria Programrii, dar conine cele mai importante subiecte
abordate i n cursuri cu acelasi profil din alte universitti din lume. De obicei prezentarea limbajului Java
este precedat de o discuie despre specificul programrii cu obiecte i despre tehnicile de programare proprii
acestei abordri: derivare, polimorfism, delegare, clase abstracte i interfee, interfee grafice i programare
cu evenimente, s.a. Scrierea unei aplicaii reale este precedat de o faz de analiz a cerintelor, de
identificare a noiunilor importante din aplicatie; substantivele pot deveni clase (obiecte), iar verbele pot
deveni operaii (metode ale obiectelor).
Proiectarea ca faz anterioar scrierii de cod nseamn gsirea celor mai bune soluii de mprire n clase
astfel nct modificrile ulterioare s fie uurate i s nu produc efecte secundare nedorite. Aceste bune
practici sau soluii optime de proiectare se mai numesc i abloane de proiectare sau modele de proiectare
(design patterns) i trebuie cunoscute pentru a fi aplicate corect i eficient. O reprezentare grafic a
claselor i obiectelor existente, a relaiilor statice i dinamice dintre ele este de obicei parte a procesului de
proiectare dar i a documentaiei care nsoeste codul surs; limbajul UML (Unified Modelling Language)
este standardizat i ofer aceast reprezentare grafic unitar.
In producia de software se foloseste un mediu integrat pentru dezvoltare (IDE=Integrated Development
Environment) ca parte a metodologiei i tehnicilor specifice ingineriei de software (Software Engineering).
Am ales produsul NetBeans care are toate facilitile existente ntr-un IDE fiind n acelai timp intuitiv i
uor de folosit; n plus permite i dezvoltarea de aplicaii n alte limbaje importante (C, C++, HTML, XML,
PHP, Groovy).
Limbajul Java i bibliotecile de clase s-au dezvoltat continuu, iar n ultima vreme Java s-a impus mai mult
ca platform poliglot pentru dezvoltarea de programe, n sensul c tot mai multe limbaje conduc la codul
intermediar executat pe maina virtual Java (JVM) i folosesc bibliotecile de clase Java: Scala, Clojure,
Groovy, s.a. Am ales pentru prezentare aici limbajul Groovy, care este mai apropiat ca sintax de Java.

-6-

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Capitolul IE.01. Noiuni de baz ale programrii orientate obiect


Cuvinte cheie
POO(Programare orientat pe obiecte),Programare procedural,
Obiecte, Clase, Metode, Instaniere, Mesaje, Metode statice
Incapsulare,Programare generic,Clase abstracte, Interfee
IE.01.1 Paradigme de programare
Programarea calculatoarelor este despre crearea unor programe pe baza crora un calculator (sau mai multe)
s poat rezolva o problem dintr-o clas de probleme. Particularizarea unei probleme se face prin date de
intrare sau parametri. Un program descrie prelucrrile (operaiile) ce trebuie efectuate asupra datelor de
intrare pentru a obine anumite rezultate sau o anumit comportare sau descrie un algoritm de prelucrare a
datelor. Mai exact, programatorul comand paii necesari numai n stilul de programare imperativ deoarece
n programarea declarativ se specific doar ce rezultate (obiective) sunt urmrite dar nu i cum (prin ce
pai) vor fi ele obinute.
Au existat i exist mai multe moduri de abordare a programrii, numite i paradigme sau stiluri de
programare (stil de programare se refer mai des la modul de redactare a textelor surs: indentri, utilizare
de litere mari i mici, etc.). O clasificare posibil distinge patru paradigme: programare imperativ
(procedural), programare funcional, programare logic i programare orientat obiect (Object Oriented =
OO). Paradigmele de programare sunt aplicate prin limbaje de programare; exist limbaje pure care
reflect o singur paradigm i limbaje care permit dou sau chiar trei paradigme. Mai nou se consider c
programarea cu obiecte este o dezvoltare a programrii procedurale i c principala distincie are loc ntre
programarea orientat pe obiecte (POO) i programarea funcional (PF).
Limbaje tipice pentru programarea procedural sunt Pascal i C, limbaje tipice pentru programarea
funcional sunt Lisp i derivate din Lisp, un limbaj tipic pentru programare logic este Prolog, iar pentru
POO limbaje reprezentative sunt Java, Python, Ruby, C# .a. Limbaje care permit cteva paradigme de
programare sunt C++ (procedural i cu obiecte) i Scala (cu obiecte i funcional). Altfel spus, un limbaj
poate impune sau nu o anumit abordare; n C++ i chiar n Java (prin metode statice) se poate programa
procedural i/sau cu obiecte.
In plus, exist o serie de limbaje destinate programrii concurente (paralele), subiect care are i el cteva
paradigme (fire de execuie cu memorie comun, actori care comunic prin mesaje, .a.).
Toate limbajele de programare aprute dup anii 1980 sunt limbaje orientate obiect: C++, Java, Python,
Ruby, JavaScript, iar limbaje mai vechi au fost extinse pentru POO: C (C++),Pascal, Basic, PHP, s.a.
Desi noiunile de obiect i de clas sunt strns legate, nu toate limbajele orientate pe obiecte folosesc i
noiunea de clas; n astfel de limbaje un obiect prototip poate fi modificat dinamic, pentru a obine
tipuri diferite de obiecte (din alte clase). Exemple sunt cele derivate din ECMAScript ( JavaScript, .a.).
La nivel de instruciuni main (de limbaj de asamblare) programarea este imperativ, astfel c n mod firesc
primele limbaje independente de main (Fortran, Basic, Algol, s.a.) au fost i ele imperative dar s-au
ndeprtat de main prin utilizarea de variabile i de instruciuni mai puternice.
Pe msur ce aplicaiile (programele) au devenit mai mari si mai complexe programarea imperativ a
progresat prin programarea structurat (utilizarea unor structuri de control ca decizia i ciclul, n locul
-7-

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

instruciunilor de salt) i prin programarea modular (definirea i utilizarea de funcii). Aceste ctiguri au
fost preluate i de programarea cu obiecte (POO).
Programele i limbajele sunt clasificate n limbaje statice si limbaje dinamice; un limbaj static nu permite
unui program s se modifice n cursul execuiei, spre deosebire de un limbaj dinamic. Desi primul limbaj
dinamic a fost Lisp, aceast caracteristic nu apartine numai paradigmei funcionale; tot mai multe limbaje
OO includ aspecte de metaprogramare (MOP=Meta-Object Protocol) care permit astfel de modificri ale
claselor i obiectelor in cursul execuiei.
Un limbaj cu tipuri statice menine tipurile declarate pentru variabile (parametri, funcii) la compilare i
permite efecturea unor verificri de utilizare corect a lor nc de la compilare; un limbaj cu tipuri dinamice
nu declar tipul variabilelor, tip care rezult la execuie din tipul valorilor atribuite i care se poate modifica
ulterior n funcie de atribuirile efectuate. Tipurile dinamice sunt folosite mai ales n limbaje interpretate (de
scripting); ele simplific codul surs dar operaiile nu pot fi verificate (nu exist compilare) i pot produce
erori sau rezultate neateptate la execuie (prin conversii automate de tip).
Limbajele orientate obiect pot folosi tipuri statice (Java, Scala) sau tipuri dinamice (Python, Ruby), pot fi
interpretate (JavaScript, Python) sau compilate (Java, Scala) sau admit ambele moduri de folosire (Groovy
poate fi folosit ca limbaj de scripting sau ca limbaj compilat).
Incepnd cu Java, multe din limbajele cu orientare pe obiecte sunt parial compilate i parial interpretate;
compilatorul genereaz un cod intermediar care este apoi interpretat de o ma in virtual. Codul intermediar
i masina virtual constituie o platform pe care se pot folosi mai multe limbaje. In prezent se folosesc dou
platforme: platforma Java (bytecode i maina virtual Java JVM) i platforma .NET (cod intermediar
Microsoft MSIL i maina virtual CLR= Common Language Runtime). Avantajul este acela c execuia
codului intermediar are loc sub controlul mainii virtuale, care poate face o serie de verificri la execuie i
poate genera mesaje (excepii program), motiv pentru care se numete managed code (cod gestionat sau
asistat).

IE.01.2 Programare orientat pe obiecte


Programarea cu clase i obiecte reprezint un alt mod de abordare a programrii dect programarea
procedural, cu avantaje n dezvoltarea programelor mari. POO (Programare orientat pe obiecte,
Programare orientat obiect) este o paradigm de programare n care codul surs este structurat pe clase i
obiecte i nu pe funcii ca n programarea procedural (n limbajul C, de exemplu).
Un program OO este o colecie de obiecte care interacioneaz i nu o succesiune de funcii care se apeleaz
unele pe altele. Ideea POO este c problemele reale conin obiecte care interacioneaz iar programele care
rezolv astfel de probleme vor conine obiecte software care modeleaz obiectele reale.
Un obiect, n sensul POO, este un model pentru o entitate sau un concept i poate desemna aproape orice:
obiecte fizice, persoane, documente, servicii, agregate (colecii), algoritmi, etc. Un obiect are o identitate,
atribute i responsabiliti. Un obiect are un ciclu de via (lifetime): creare, utilizare, distrugere.
Obiectele cu aceleai caracteristici formeaz clase de obiecte. De exemplu toate butoanele folosite n
interfee grafice formeaz o clas (JButton n Java), dei ele pot avea forme, dimensiuni, margini i inscripii
diferite. In general, obiecte diferite conin date diferite, dar toate obiectele suport aceleai operaii, realizate
prin metodele clasei din care fac parte.

O clas reprezint o categorie, adic un grup de obiecte care au n comun aceleai proprietti
(numite i atribute), aceeai comportare (operaii , mod de utilizare) i aceleai relaii cu obiecte
-8-

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

din alte clase. O clas este un ablon pentru toate obiectele care au aceeai comportare (aceleai operaii).
Un obiect este un element particular al unei clase, numit i "instan" a clasei. Crearea unui obiect
poart i numele de instaniere a clasei, aciune prin care se stabilesc i o parte din atributele
obiectului creat, numite i variabile ale instantei (instance variables). Alte atribute pot fi stabilite
ulterior ca parametri ai unor metode apelate pentru acel obiect.
Metodele sunt aceleai pentru toate obiectele unei clase i reprezint operaiile posibile cu aceste
obiecte. De exemplu, conturile din banc ale clienilor bncii constituie o clas; contul unui client
este un obiect i are n general proprieti diferite de alte obiecte din aceeai clas: datele personale,
tipul de cont (debit / credit), soldul contului, istoricul operaiilor. Dar toate conturile bancare
suport aceleai operaii: crearea unui nou cont cu datele specifice clientului, depunerea unei sume
n cont, extragerea unei sume din cont, calcul dobnzi i comisioane, etc.
Programare cu obiecte nseamn definirea de clase plus crearea de obiecte plus apeluri de metode ntre
obiecte pentru realizarea obiectivelor aplicaiei. Un program procedural (scris n C de exemplu) este o
colecie de funcii, iar datele prelucrate se transmit ntre funcii prin argumente (sau prin variabile externe).
In programarea procedural obiectivul este definirea de funcii pentru operaii de prelucrare a datelor i
obinere a rezultatelor, dar n programarea orientat obiect scopul este crearea de obiecte axate pe date, cu
operaii ataate acestor
date. Accentul se mut
de pe aciuni (funcii) pe
date (obiecte).

Aciunile dintr-un program cu obiecte sunt realizate prin apeluri de metode pentru anumite obiecte, apeluri
provenite din alte obiecte. Se mai spune c obiectele interacioneaz prin transmiterea de mesaje. De
exemplu, atunci cnd se apeleaz metoda read() de citire a unui caracter dintr-un fiier (flux), se poate spune
c se transmite obiectului din clasa FileReader mesajul d-mi urmtorul caracter din fiierul asociat acestui
obiect (numele fiierului este transmis la crearea obiectului de tip FileReader).

-9-

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

La nivel sintactic, obiectele sunt asocieri de date i operatii aplicabile acestor date si pot fi privite ca o
generalizare a variabilelor structur din limbajele procedurale (de tip struct din limbajul C). Aa cum
definiia unei structuri n C creeaz un nou tip de date, la fel definiia unei clase va crea un nou tip clas.
In C o stiv vector se defineste printr-o structur care grupeaz un vector cu un indice ctre prima adres
liber (vrful stivei); n Java un obiect stiv mai conine n plus i operaii asociate unei stive: push() (pune
un obiect pe stiv), pop()(scoate ultimul obiect pus n stiv), empty() (verific dac stiva este goal), init()
(iniializare stiv goal), .a.
Exemplul urmtor este o funcie C de copiere a unui fiier, octet cu octet:
// copiere fisier in C
void filecopy ( char * src, char * dst) {
char ch;
FILE * in =fopen(src,"r");
// deschide fisier sursa
FILE * out =fopen(dst,"w"); // deschide fisier destinatie
while ( (ch=fgetc (in)) != -1) // citeste un caracter
fputc (ch, out);
// scrie un caracter
fclose(out); fclose(in);
}

Aciunile necesare copierii se realizeaz prin funciile fopen(), fgetc(), fputc(), fclose() care primesc ca date
variabilele in, out i ch. Exemplul urmtor este o funcie Java de copiere octei dintr-un fiier surs
src ntr-un fiier destinaie dst:
public static void filecopy (String src, String dst) throws IOException {
FileReader in = new FileReader (src);
// un obiect
FileWriter out = new FileWriter (dst);
// alt obiect
int ch;
while ( (ch= in.read()) != -1)
// cere obiectului in operatia read
out.write(ch);
// cere obiectului out operatia write
in.close(); out.close();
// cere obiectelor operatia close
}
In acest exemplu se folosesc dou obiecte: un obiect de tip FileReader (prin variabila in) i un obiect de tip
FileWriter (prin variabila out); prin metoda read() se cere obiectului in s citeasc i s furnizeze un
caracter, iar prin metoda write() se cere obiectului out s scrie n fisier caracterul primit ca argument. Pentru
obiectele in si out se pot apela i alte metode, din clasele respective. Obiectele in i out conin informaii
despre fisierele src i dst necesare prelucrrii lor, cam aceleai care se memoreaz ntr-o structur de tip
FILE n limbajul C. La crearea obiectelor, folosind operatorul new, se deschid cele dou fiiere (aciunea
funciei fopen() din C).
O clas corespunde unei noiuni abstracte cum ar fi orice fiier disc, iar un obiect este un caz concret (o
realizare a conceptului sau o instaniere a clasei). Un obiect de tip FileReader corespunde unui anumit fiier,
cu nume dat la construirea obiectului.
Relativ la exemplul Java, trebuie spus c utilizarea unei metode statice de copiere nu este n spiritul POO.
Metodele statice Java corespund funciilor C i pot fi folosite fr ca s existe obiecte (ele fac parte totui din
- 10 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

anumite clase). Mai aproape de stilul propriu POO, ar trebui definit o clas copiator de fisiere, avnd si o
metod (nestatic) de copiere copy(), aplicabil obiectelor FileCopier. Exemplu:
public class FileCopier {
// datele clasei
private FileReader in;
// sursa datelor
private FileWriter out;
// destinatia datelor
// constructor
public FileCopier (String src, String dst) throws IOException {
in = new FileReader (src);
out = new FileWriter (dst);
}
// o metoda de copiere
public void copy () throws IOException {
int c;
while ( (c= in.read()) != -1)
out.write(c);
in.close(); out.close();
}
// verificarea clasei FileCopier
public static void main (String arg[]) throws IOException {
FileCopier fc = new FileCopier (arg*0+, arg*1+);
// creare obiect fc
fc.copy();
// cere obiectului fc operatia copy
}
}
In exemplele anterioare i n cele ce vor urma se poate observa mutarea accentului de pe aciuni (funcii) pe
obiecte (date) n programarea orientat pe obiecte. Numele de clase sunt substantive, uneori derivate din
verbul ce defineste principala aciune asociat obiectelor respective. In Java exist obiecte comparator (de
tip Comparator) folosite n compararea altor obiecte, clasa Enumerator folosit la enumerarea elementelor
unei colecii, clasa StringTokenizer folosit la extragerea cuvintelor dintr-un ir .a.

IE.01.3 Avantajele programrii cu obiecte


- Programare modular la nivel de clas i nu la nivel de funcie simplific programarea aplicaiilor mari
- Existena unui numr mare de clase predefinite reduce mult timpul de dezvoltare a unor noi aplicaii
- Cuplajul ntre clase este mai slab i favorizeaz reutilizarea de clase ca module de program
- Funciile (metodele clasei) au mai puine argumente
- Se simplific definirea unor noi tipuri de date
- Permite programarea generic a unor colecii cu date de orice tip
- Clasele pot ncapsula algoritmi dificili de programat
- Programele modeleaz mai bine universul aplicaiei: obiectele din program corespund unor obiecte reale
- Programarea cu clase se face la un nivel de abstractizare mai ridicat.
Pentru concretizare vom prezenta soluiile C si Java pentru cteva probleme. Primul exemplu se refer la
utilizarea structurii de tip stiv (stack) n aplicaii. O stiv poate fi realizat fie printr-un vector, fie printr-o
list nlnuit, dar operaiile cu stiva sunt aceleai, indiferent de implementare: pune date pe stiv, scoate
- 11 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

datele din vrful stivei i test de stiv goal. In limbajul C se pot defini funciile pentru operaii cu stiva astfel
ca utilizarea lor s nu depind de implementare, prin folosirea unui pointer la o structur:
void initSt ( Stiva * sp); // initializare stiva
int emptySt (Stiva * s);
// test stiva goala
int push (Stiva * sp, T x); // pune in stiva un element de tip T
T pop (Stiva * sp );
// scoate din stiva un element de tip T

Definiia tipului Stiva i definiiile funciilor depind de implementare. Exemplu de utilizare stiv n C:
#include "stiva.h"
void main () {
int x; Stiva s ;
initSt (&s);
// initializare stiva
for (x=1; x<10; x++)
// genereaza date ptr continut stiva
push (&s,x);
// pune x pe stiva
while ( ! emptySt (&s) )
// cat timp stiva contine ceva
printf("%d \n", pop (&s) ) ; // scoate din stiva si afiseaza
}
Modificarea tipului de stiv (list n loc de vector) sau modificarea tipului datelor memorate n stiv necesit
un alt fiier stiva.h i o alt bibliotec de funcii push(), pop()).
In POO se va crea un obiect de tip stiv i se vor apela pentru acest obiect metoda push() avnd ca argument
obiectul pus pe stiv i metoda pop() cu rezultat obiectul scos din stiv. Obiectele memorate n stiv pot avea
orice tip.
In Java exist o clasa predefinita Stack iar programul de exersare a operaiilor cu stiva arat astfel:
public static void main (String arg[ ]) {
Stack s = new Stack();
// creare obiect stiva
for (int x=1; x<10; x++)
// pune 10 numere in stiva
s.push ( new Integer(x));
// s.push(x) in Java 5
while ( ! s.empty())
// cat timp stiva nu e goala
System.out.println ( s.pop()); // afiseaza obiectul scos din stiva
}

Modificarea implementrii stivei, prin definirea unei alte clase Stack nu necesit modificri n funcia
anterioar, ci doar punerea noii clase n cile de cutare ale compilatorului i interpretorului Java. In plus, se
poate defini o clas abstract care s corespund tipului de date abstract Stiv i care s precizeze
operaiile cu stiva , fr s presupun o anumit implementare (o structur de date concret).
Un al doilea exemplu este cel al extragerii de cuvinte succesive dintr-un ir de caractere ce poate conine
mai multe cuvinte, separate prin anumite caractere delimitator. Problema este aceea c dup fiecare cuvnt
extras se modific adresa curent n irul analizat, deci starea sau contextul n care se execut funcia care d
urmtorul cuvnt.
In limbajul C se pot ntlni mai multe soluii ale acestei probleme n diferite funcii de bibliotec. Una din ele
este funcia strtok() care modifica irul analizat i foloseste o variabil static intern a funciei pentru

- 12 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

adresa curent n irul analizat. In plus, primul apel difer de urmtoarele apeluri ale funciei. Exemplu de
utilizare:
cuv=strtok(str, sep);
// primul cuvnt din str, sep= sir de separatori
while (cuv !=NULL) {
// daca s-a gasit un cuvant
puts(cuv);
// afisare cuvant
cuv=strtok(0,sep);
// urmatorul cuvant din str
}
In Java exist clasa de bibliotec StringTokenizer, folosit dup cum urmeaz:
String sep = new String (" ,.;\n\t");
// lista separatori de cuvinte
StringTokenizer st = new StringTokenizer (sir,delim); // sir = sir analizat
while (st.hasMoreTokens()) {
// daca mai sunt cuvinte in sirul analizat
String token = st.nextToken();
// extrage urmatorul cuvint din linie
System.out.println (token);
// afisare cuvint
}

La crearea unui obiect StringTokenizer se specific irul analizat, astfel c se pot analiza n paralel mai
multe iruri, pentru fiecare folosind un alt obiect. Metodele nextToken()i hasMoreTokens() folosesc n
comun o variabil a clasei care conine poziia curent n irul analizat (iniializat cu adresa irului, la
construirea obiectului).
In prelucrarea fiierelor apar situaii cnd execuia cu succes a unei funcii depinde de folosirea anterioar a
altor funcii (cu anumite argumente); de exemplu pentru a putea scrie ntr-un fiier, acesta trebuie mai nti
deschis pentru creare sau pentru adugare (extindere fiier existent). O situaie asemntoare apare la
utilizarea unor funcii care compun o interfa grafic i care trebuie folosite ntr-o anumit ordine. Astfel de
condiionri reciproce nu se pot verifica automat n C, fiind vorba de funcii independente. In Java operaiile
sunt metode dintr-o aceeai clas i se poate verifica printr-o variabil a clasei succesiunea corect de
folosire a metodelor.

IE.01.4 Clasele ca module de program reutilizabile


Definirea i utilizarea de module funcionale permite stpnirea complexitii programelor mari i
reutilizarea de module prin crearea de biblioteci.
n limbajul C un modul de program este o funcie, dar n POO un modul este o clas, care reunete n general
mai multe funcii n jurul unor date. Utilizarea de clase ca module componente ale programelor are o serie de
avanaje fat de utilizarea de funcii independente:
- Metodele unei clase necesit mai puine argumente, iar aceste argumente nu sunt modificate n funcie;
efectul unei metode este fie de a face accesibile date din clas, fie de a modifica variabile din clas pe baza
argumentelor primite. Variabilele unei clase sunt implicit accesibile metodelor clasei i nu mai trebuie
transmise explicit, prin argumente (ca variabile externe metodelor, dar interne clasei).
- Soluii mai simple pentru funcii al cror efect depinde de stare (de context), cum ar fi de apeluri anterioare
ale aceleeasi funcii sau ale altor funcii pregtitoare.
- Sunt posibile verificri de utilizare corect a unor metode sau asupra succesiunii de apelare a unor funcii;
de exemplu nu se poate folosi o metod de scriere pentru un fiier deschis numai pentru citire sau dintr-o
clas ce permite numai citirea de date.
- 13 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

- O clas poate ncapsula algoritmi de complexitate ridicat, realizai prin colaborarea mai multor funcii,
unele interne clasei; astfel de algoritmi fie nu sunt disponibili n C, fie sunt disponibili prin biblioteci de
funcii destul de greu de utilizat. Exemple sunt algoritmi pentru lucrul cu expresii regulate, pentru arhivaredezarhivare, pentru operaii cu anumite structuri de date (arbori binari cu auto-echilibrare), s.a.
- Se poate realiza un cuplaj mai slab ntre module, n sensul c modificarea anumitor module nu va afecta
restul programului. Aceast decuplare sau separare ntre module se poate realiza prin mai multe metode,
printre care folosirea de interfee Java, n spatele crora pot sta clase cu implementri diferite dar cu acelai
mod de utilizare.
Funcionalitatea unei clase poate fi reutilizat n alte clase fie prin derivare, fie prin delegare (compunere). In
acest fel, operaiile necesare ntr-o clas sunt fie motenite de la o alt clas, fie delegate spre execuie
metodelor unei alte clase. De exemplu, extinderea automat a unui vector, necesar uneori dup adugarea la
vector, este refolosit i ntr-o clas stiv vector, fie prin definirea clasei stiv ca o clas derivat din vector,
fie prin folosirea unei variabile Vector n clasa stiv.
In POO adaptarea unei clase la cerine specifice unor aplicaii nu se face prin intervenie n codul clasei ci
prin derivare sau prin delegare, tehnici specifice POO.
O noiune proprie programrii cu obiecte este noiunea de component software. Ideea este de a obine rapid
un prototip al aplicaiei fr a scrie cod sau cu un minim de programare, prin asamblarea de componente
prefabricate (n special pentru interfaa grafic, dar nu numai). O component poate conine una sau mai
multe clase i poate fi reutilizat i adaptat fr intervenie n codul surs al componentei (care nici nu este
disponibil).
O component JavaBeans poate fi utilizat fr a scrie cod, prin generarea automat a operaiilor de
instaniere, de modificare a proprietilor si de conectare cu alte clase (prin apeluri de metode sau prin
evenimente), n urma unor comenzi date de utilizator unui mediu vizual de dezvoltare a aplicaiilor. O
component este de obicei o clas care respect anumite condiii.

IE.01.5 Incapsulare
Datele coninute n obiecte nu sunt accesibile direct pentru metode din alte obiecte (sunt private), dar ele sunt
folosite de metodele apelate pentru obiectele respective. Datele sunt ncapsulate i invizibile n afara clasei
iar utilizatorii clasei vd numai serviciile oferite de clas prin metodele ei.
Putem compara un obiect cu o cutie neagr care are cteva butoane i cteva afiri (un televizor, de
exemplu); utilizatorul nu trebuie s tie ce este n interiorul acestei cutii negre ci doar ce comenzi se
transmit prin butoane i s interpreteze afirile.
Interfaa public expus de un obiect celorlalte obiecte este format din constructori i metode publice,
utilizabile din alte clase. Constructorii sunt ntotdeauna publici pentru a permite instanierea clasei i crearea
de obiecte. Metodele publice sunt metode motenite sau metode proprii.
Mai multe clase pot avea implementri diferite dar pot s prezinte o aceeai interfa public; aa sunt clasele
pentru anumite colecii de date (liste, mulimi, dicionare, etc.).
Variabilele dintr-o clas sunt declarate de obicei cu atributul private, ceea ce le face inaccesibile pentru
metode din alte clase. Se mai spune c datele sunt ascunse sau sunt ncapsulate n fiecare obiect. Metodele
clasei sunt de obicei publice pentru a putea fi apelate din alte clase.

- 14 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Deoarece datele dintr-un obiect (variabile private) nu sunt direct accesibile din afara clasei i pot fi
modificate numai prin intermediul metodelor clasei, utilizarea tipurilor de date definite prin clase este mai
sigur dect a celor definite prin structuri. De exemplu, orice modificare a vectorului de caractere dintr-un
obiect StringBuffer (StringBuilder) este nsoit de modificarea lungimii irului (n metodele care pot
modifica lungimea irului), dar lungimea nu poate fi modificat direct de ctre funcii din alte clase (i nici
coninutul vectorului de caractere).
In reprezentarea UML a unei clase atributul private este notat cu minus (-), iar atributul public este notat cu
plus (+). Exemplu de clas pentru o persoana, cu variabilele name, address i 5 metode publice:

IE.01.6 Clasele permit programarea generic


Programarea generic ne permite s avem o singur clas pentru un vector (sau pentru o list), indiferent de
tipul datelor care vor fi memorate n vector (n list). Tot programarea generic ne permite s folosim o
singur funcie (metod) pentru a parcurge elementele oricrei colecii (indiferent de structura ei fizic ) sau
pentru a ordona orice list abstract (o colecie care suport acces direct prin indice la orice element ).
Genericitatea coleciilor de obiecte poate fi realizat n limbajele cu clase prin dou metode:
- prin colecii ce conin un supertip al tuturor tipurilor clas (tipul Object n Java);
- prin clase ce au ca parametri tipurile de date folosite (numite templates n C++).
Coleciile cu elemente de tip Object au existat de la nceput n Java, iar coleciile cu tipuri de date ca
parametri au aprut din versiunea 5 si sunt numite generice (generics).
Pentru a permite colecii cu date de orice tip limbajul Java consider c toate clasele predefinite sau care
urmeaz a fi definite de utilizatori sunt implicit derivate dintr-o clas Object, care este rdcina ierarhiei de
clase Java. Tipul unei clase derivate este subtip al tipului clasei din care deriv, asa cum tipul int poate
fi considerat ca un subtip al tipului long, iar tipul float ca un subtip al tipului double. La fel cum un argument
formal de tip double poate fi nlocuit cu un argument efectiv de tip int, tot aa un argument formal de un tip
clas B poate fi nlocuit cu un argument efectiv de un tip clas D; clasa D fiind derivat din clasa B. In felul
acesta se pot scrie functii generice, cu argumente de un tip general i utilizabile cu o multitudine de tipuri de
argumente (asa cum functia sqrt() se poate apela cu argument de orice tip numeric din limbajul C).
O colecie de variabile de tip Object poate conine referinte la obiecte de orice tip, pentru c acestor variabile
li se pot atribui variabile de orice alt tip clas (care contin adresele unor obiecte). Este la fel cum n limbajul
C un vector de pointeri de tip void* poate fi folosit pentru a memora adrese ale unor date (alocate dinamic)
de orice tip predefinit sau definit de utilizatori; adugarea la vector a unui pointer oarecare nu necesit o
conversie, dar la extragerea din vector trebuie trecut de la tipul void* la tipul de pointer folosit la adugare
(prin operatorul cast pentru conversie de tip).
Exemplu de calcul a sumei valorilor unor obiecte numerice dintr-un vector:
- 15 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Vector v = new Vector();


// creare obiect vector (extensibil)
for (int k=1; k<11; k++)
// genereaza numerele 1,2.3 10
v.add ( new Integer(k));
// adauga numarul k la vector ca obiect de tip Integer
int sum=0;
for (int k=0;k<v.size();k++) {
Integer obj = (Integer) v.get(k); // extrage din vector si conversie din Object n Integer
sum += obj.intValue();
// aduna numarul de tip int din obiectul obj
}
Conversia n sus de la subtipul Integer la supertipul Object se face automat (argumentul metodei add() este
de tip Object), dar conversia n jos (de la Object la Integer, pentru rezultatul metodei get()) trebuie cerut n
mod explicit prin operatorul de conversie ( ca i n C).
O colecie Java generic specific tipul obiectelor coninute nc de la declarare (care poate fi orice subtip de
Object sau de alt tip), iar la extragere nu mai trebuie fcut nici o conversie de tip. Acelai exemplu dinainte
cu colecii generice:
Vector <Integer> v = new Vector<Integer>();
// creare obiect vector de Integer
for (int k=1; k<11; k++)
// genereaza numerele 1,2.3 10
v.add ( new Integer(k));
// adauga numarul k la vector ca obiect de tip Integer
int sum=0;
for (int k=0;k<v.size();k++)
sum += v.get(k).intValue();
Programarea cu obiecte permite un nivel de abstractizare i de generalizare mai ridicat prin clase abstracte
i interfee. Cel mai bun exemplu este cel oferit de tipurile de date colective (numite colecii sau structuri de
date): orice colecie de obiecte trebuie s aib operaii pentru adugarea i eliminarea de elemente, pentru a
obine
dimensiunea
coleciei,
pentru
enumerarea
elementelor
din
colecie
.a.
Ca implementare, coleciile pot fi realizate ca vectori (Arrays), ca liste nlnuite, ca arbori binari, ca tabele
hash sau altfel. O colecie de tip mulime (Set) este o colecie cu elemente distincte i cu timp de cutare
redus, dar o mulime poate fi un arbore, un tabel hash, etc.
O interfa este o colecie de metode nedefinite (abstracte), iar o clas abstract are metode definite, metode
abstracte i (posibil) date. In Java exist o interfa Collection, o subinterfa Set, o clas abstract
AbstractSet i clasele instaniabile TreeSet i HashSet.

IE.01.7 Clasele creeaz un model pentru universul aplicaiei


Un program destinat unei aplicaii trebuie s transforme noiunile i aciunile specifice aplicaiei n
construcii specifice limbajului de programare folosit (funcii, variabile, argumente de funcii, etc.).
Evoluia limbajelor de programare poate fi privit i ca un progres al abstractizrii, n sensul ndeprtrii
progresive de maina fizic prin introducerea de noiuni tot mai abstracte dar mai apropiate de aplicaie.
Programarea orientat pe obiecte permite definirea de clase i obiecte ce corespund direct obiectelor din
universul aplicaiei i modelarea relaiilor statice i dinamice dintre aceste obiecte. Identificarea obiectelor i
aciunilor specifice unei aplicaii se face n faza de analiz orientat obiect a problemei de rezolvat i implic
o abordare diferit de cea anterioar.
Intr-o aplicaie bancar vor exista clase i obiecte de genul Cont si Client. Un obiect Client va conine
date de identificare ale clientului i metode pentru obinerea sau modificarea acestor date. Un obiect de tip
- 16 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Cont va conine suma din cont (si alte date asupra operaiilor cu acel cont), precum i metode pentru
depunerea de bani n cont, pentru retragerea de bani din cont i pentru vizualizarea sumei de bani din cont.
Obiectele de tipul Cont sau Client se numesc i obiecte din domeniul aplicaiei (domain objects).
Aplicaiile mai pot conine obiecte ajuttoare (helper) sau obiecte din clase predefinite pentru operaii cu
anumite tipuri de date, cu colecii de obiecte, cu baze de date, cu conexiuni ntre calculatoare s.a.

IE.01.8 Tehnici de programare specifice POO


Programarea cu obiecte a adus cu sine noi tehnici de programare, cum ar fi: derivarea (extinderea) claselor,
delegarea, suprancrcarea functiilor, suprascrierea functiilor polimorfice dintr-o clas ntr-o subclas,
crearea unor ierarhii de tipuri, componente reutilizabile, sabloane de proiectare cu clase (Design Patterns),
standardul UML pentru reprezentarea grafic a claselor i relaiilor dintre ele s.a.
Reutilizarea n programare este un vechi obiectiv i are dou aspecte:
- Reutilizarea ca atare a unor module existente i adaptarea lor prin parametri modificabili
- Reutilizarea parial a unor module existente n definirea altor module (funcii).
Reutilizarea unor module existente se realizeaz prin biblioteci de funcii i respectiv prin biblioteci de clase
n POO. Limbajul Java este renumit i prin numrul mare de clase predefinite care simplific mult
dezvoltarea de noi aplicaii, n mod special a celor cu interfa grafic. Mai mult dect att, se pot defini i
utiliza componente standard JavaBeans, care respect anumite convenii ce permit instanierea lor fr
scrierea manual de cod (prin interaciune cu un mediu vizual de programare).
Reutilizarea parial a unor functii n definirea altor funcii nseamn, n programarea procedural, preluarea
unor secvene de cod i completarea lor cu alte operaii noi. In POO reutilizarea parial a unor clase nu se
face prin editarea codului surs (operaie supus erorilor) ci prin derivare sau prin delegare.
Un exemplu este definirea unei clase pentru mulimi de obiecte realizate ca vectori sau ca liste nlnuite pe
baza unor clase existente (n bibliotecile de clase Java) pentru vectori i liste. Diferena dintre un vector i o
mulime vector este interzicerea obiectelor cu valori identice n mulimi, care se poate face n operaiile de
adugare a unor noi elemente la mulimea vector. Alte operaii cu multimi pot fi preluate ca atare de la
vectori , fr a mai fi definite explicit n clasa multime: eliminare element, determinare dimensiune mulime,
operaii cu dou mulimi .a. Reutilizarea operaiilor cu vectori ntr-o nou clas mulime vector se poate
face fie prin derivare, fie prin delegare.
Derivarea nseamn definirea clasei mulime vector ca o subclas a clasei vector (ca un caz particular de
vector) cu redefinirea operatiilor care pot crea elemente cu valori egale. Relaia dintre clase creat prin
derivare este o relatie de tip este un fel de (is a kind of), deci o mulime vector este un fel de vector.
Metodele din calasa vector care rmn la fel si n clasa mulime vector nu mai trebuie definite si nici
mcar declarate n noua clas.
- 17 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Delegarea nseamn c n clasa mulime vector exist o variabil de tip vector i c operatiile cu
mulimea vector sunt delegate prin aceast variabil ctre operaiile clasei vector (prin apeluri de metode
din clasa vector).
Derivarea poate fi folosit i pentru crearea unor ierahii de tipuri: o clas reprezint un tip de date, o clas
derivat reprezint un subtip al tipului clasei din care a fost derivat. Cele dou tipuri sunt compatibile la
atribuirea ntre variabile si la transmiterea de argumente, la fel cum n limbajul C orice tip aritmetic este
compatibil cu alte tipuri aritmetice (short, int, float, double, etc) sau cum sunt compatibile ntre ele tipul
void* cu orice alt tip pointer.
In programarea cu obiecte se folosesc multe ierarhii de tipuri i ele au diferite beneficii. De exemplu, n Java
toate clasele existente sau definite de utilizatori sunt subclase ale clasei Object si deci toate tipurile clas
sunt compatibile cu tipul de baz Object (rdcina ierarhiei de tipuri Java). O colecie de variabile de tip
Object poate fi folosit drept colectie cu date de orice alt tip clas, fiind deci o colecie generic. O metod
cu un argument de tip Object sau cu rezultat Object poate fi apelat cu argument de orice tip clas si este o
funcie generic.
Specific POO este c ierarhiile de tipuri pot conine tipuri abstracte, foarte generale n partea de sus a
ierarhiei. Familia claselor colecie sau a claselor dicionar ncepe cu o interfa care are sub ea clase
abstracte, care au ca subtipuri clase instaniabile. O interfa are toate metodele abstracte i nu are date n
timp ce o clas abstract poate avea i date i metode definite (ne-abstracte). Interfeele i clasele abstracte
Java sunt i ele subtipuri ale tipului Object. Interfaa impune anumite metode pentru toate subtipurile sale,
clasa abstract definete o parte din metodele interfeei (care nu depind de date i n funcie de alte metode),
iar clasa instaniabil definete i metodele rmase abstracte (i care depind de datele clasei).

O funcie polimorfic (virtual) este o funcie cu acelasi nume, tip i argumente dar cu implementri
(definiii) diferite n clase diferite. Metoda polimorfic are acelai rol i primeste aceleai date dar definiia
difer n funcie de specificul clasei; ea este virtual pentru c definete un prototip de funcie i nu o anume
funcie concret. Exemplu: Metoda toString() din Java are rolul de a produce un ir (obiect String) cu datele
dintr-un obiect, n vederea afirii sau scrierii acestora ntr-un fiier, sau pentru combinarea cu alte iruri.
Deoarece clase diferite conin date diferite este normal ca i metoda toString() s fie diferit n clase diferite.
Metoda toString() este impus de clasa Object tuturor celorlalte clase i este de obicei redefinit
(suprascris) n fiecare clas; este posibil ca o aceeai definiie s fie folosit n comun de cteva clase (de
ex. toate clasele mulime pot folosi toString() din clasa AbstractSet). Selectarea uneia dintre metodele cu
acelai nume se face n funcie de tipul obiectului pentru care se apeleaz metoda, deci aceast tehnic este
posibil numai n programarea cu obiecte.
Suprascrierea funcilor (Ovverriding) este necesar pentru a redefini o metod motenit ntr-o subclas; n
felul acesta o metod cu acelai nume, tip i argumente are efecte (definiii) diferite n clasele din ierarhie i
este polimorfic. Pentru ca s fie posibil selectarea unei definiii dintre mai multe definiii ale unei metode
- 18 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

polimorfice n funcie de tipul obiectului pentru care se aplic s-a introdus i o sintax diferit de apelare a
metodelor, alta dect sintaxa de apelare a funciilor C (sau a metodelor statice din Java). Numele metodei
este prefixat de numele variabilei referin care identific obiectul pentru care se apeleaz metoda:
LinkedList list = new LinkedList(); String str = list.toString();
TreeSet set = new TreeSet(); String str = set.toString();
In exemplul anterior se va folosi metoda toString() din clasa LinkedList n primul apel i metoda toString()
din clasa TreeSet n al doilea apel, n funcie de tipul variabilelor list si set.
Extinderea simultan a mai multor clase X,Y este necesar pentru a crea un nou tip compatibil simultan cu
tipurile X,Y. O clas C++ poate extinde simultan (prin derivare) mai multe clase, deci poate moteni
(metode si date) din mai multe surse. Exist ns posibilitatea ca o aceeai variabil (dintr-o superclas A) s
fie motenit de o clas D, pe ci diferite, de la subclase ale clasei A (fie B si C aceste subclase). Variabilele
din obiecte de tip B si C pot avea valori diferite pentru variabila motenit, dar obiectele clasei D ce valoare
motenesc ?
O clas Java poate extinde o singura clas dar poate implementa simultan mai multe interfee, ceea ce
rezolv problemele create de o motenire multipl: se preiau tipuri dar nu i date de la interfee. In Java
interfeele au o utilizare mult mai larg fa de clasele abstracte (exist multe interfee predefinite n
bibliotecile de clase).

IE.01.09 Analiza i proiectarea orientate pe obiecte


Analiza i proiectarea orientate pe obiecte reprezint o parte a procesului de dezvoltare a programelor n
paradigma OO sau a ingineriei software orientate pe obiecte. Analiza se ocup cu descompunerea aplicaiei
n componente software distincte, abordabile separat, iar proiectarea stabilete modul cum sunt asamblate
componentele software n aplicaii funcionale i performante.
Analiza orientat pe obiecte identific n descrierea aplicaiei acele substantive ce vor deveni obiecte n
program i acele verbe care vor deveni metode asociate obiectelor. Rezultatul analizei este un model
conceptual realizat pe baza specificaiilor. Parte din aceast faz este analiza cazurilor de utilizare: cine i
cum foloseste aplicaia.
Modelul conceptual conine noiuni abstracte ce corespund participanilor la realizarea aplicaiei i relaiile
de colaborare dintre acestea. Sunt utile att modele statice ct i modele dinamice, care arat succesiunea
evenimentelor i aciunilor din sistemul proiectat.
In faza de proiectare se trece de la conceptele abstracte din model la clase avnd n vedere diferite
constrngeri de performan i de bune practici n domeniu (best practices), adic de scheme de proiectare cu
clase verificate de practic.
In analiza i proiectarea orientate pe obiecte se pot folosi diverse instrumente auxiliare, cum ar fi diagrame
UML (Unified Modelling Language) i cartele CRC (Class Responsibility Collaboration card). O cartel
CRC precizeaz pentru fiecare clas responsabilitile i colaboratorii (alte clase). In faza de proiectare se
stabileste i care clase trebuie s aib un caracter mai general, n vederea reutilizrii lor n alte aplicaii,
precum i clasele de bibliotec utilizabile.
Dezvoltarea unei aplicaii software este un proces iterativ, de rafinare succesiv, care ncepe cu un prototip
realizat ct mai repede pentru ca beneficiarii s-i poat preciza cerinele, mai ales pentru aplicaii cu
interfa grafic. Din acest motiv exist produse de tip framework sau medii vizuale pentru crearea rapid de
prototipuri (RAD =Rapid Application Development) pentru aplicaii Web si pentru aplicaii locale cu
interfa grafic.
- 19 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Ingineria software (Software Engineering) nseamn aplicarea sistematic i disciplinat a unor metode
(metodologii) pentru proiectarea, dezvoltarea (implementarea), operarea si ntreinerea unor produse
software de calitate. Metodologii propuse pentru dezvoltarea de aplicaii: Agile, Extreme, Lean, Joint,
Scrum, RAD. Aceste metodologii se refer nu numai la limbaje, la instrumente software folosite i la fazele
procesului ci i la modul de colaborare cu beneficiarii i n cadrul echipei care dezvolt o aplicaie.
Obiectele dintr-o aplicaie i au originea n:
- Obiecte din domeniul aplicaiei: client, cont, factur, tranzacie,.a.
- Obiecte colecie: vectori, liste, dicionare, arbori etc.
- Obiecte care conin algoritmi: operaii pe iruri, operaii cu expresii regulate, operaii de arhivare sau
dezarhivare, etc.
- Obiecte din interfaa grafic a aplicaiei: ferestre, butoane, casete cu text, imagini, meniuri, etc
- Obiecte pentru operaii de citire-scriere fiiere, pentru operaii n reteaua Internet, parsere de fiiere
XML , pentru fire de execuie concurente, s.a.
- Obiecte auxiliare necesare n realizarea unor scheme de clase (abloane de proiectare): obiecte iterator sau
enumerator al elementelor dintr-o colecie, obiecte asculttor (observator), etc.

- 20 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Capitolul IE.02. Clase i obiecte n Java


Cuvinte cheie
Sintaxa Java, Tipuri primitive, Supradefinire de funcii,
Tipuri clas,Variabile referin, Spaii de nume, Pachete de clase,
Metode, Metode statice, Metode ale obiectelor,Vectori n Java

IE.02.1 Sintaxa limbajului Java


Limbajul Java folosete aceleai instruciuni cu limbajul C, mai puin instruciunea goto. Tipurile de date
primitive sunt aceleai, plus tipul boolean, care a schimbat i sintaxa instruciunilor care verific condiii.
Diferenele apar la tipurile de date derivate (vectori, structuri, pointeri) i la structura programelor.
In limbajul C exist un singur fel de comentarii, care ncep prin perechea de caractere "/*" i se termin prin
perechea de caractere "*/". In C++ au aprut, n plus, comentarii care ncep prin perechea de caractere "//"
i se termin la sfritul liniei n care apare acel comentariu. Java preia aceste dou feluri de comentarii, la
care se adaug comentarii destinate generrii automate a documentaiilor programelor; aceste comentarii
ncep prin irul de 3 caractere "/**" i se termin la fel cu comentariile C, prin "*/".

IE.02.1.1 Tipurile de date primitive


Java preia de la C i C++ aproape toate tipurile aritmetice (short, int, long, float, double) i tipul void, dar
impune o aceeai lungime i reprezentare a tipurilor numerice pentru toate implementrile limbajului. Un
ntreg de tip int ocup 32 de bii, un short ocup 16 bii, iar un long ocup 64 de bii. Un float ocup 32 de
bii iar un double ocupa 64 de bii. Tipul aritmetic byte ocup 8 bii (valori ntre 128 si 127). Toate tipurile
aritmetice din Java reprezint numere cu semn i nu mai exist cuvntul unsigned pentru declararea de
variabile aritmetice fr semn.
Tipul char ocup 16 bii pentru c standardul de reprezentare a caracterelor este UTF-16 sau Unicode (n
locul codului ASCII) i permite utilizarea oricrui alfabet.
Tipul boolean din Java ocup un singur bit; constantele de tip boolean sunt true i false. Existena acestui
tip modific sintaxa instructiunilor if, while, do i a expresiei condiionale, precum i rezultatul expresiilor de
relaie (care este acum de tip boolean i nu de tip int). Asadar, instruciunile urmtoare sunt greite sintactic
n Java, dei sunt corecte n C i C++.
while ( a%b) {a=b; b=a%b;} // corect este : while ( a%b !=0) {...};
return x ? 1:0 ;
// corect este: return x !=0 ? 1:0 ; cu x de tip int
if ( ! n) { ... }
// corect este: if (n==0) { ... }
do { nf=nf *n--;} while (n) ; // corect este: do { nf=nf*n--;} while ( n>0);
Variabilele declarate n funcii nu primesc valori implicite iar compilatorul semnaleaz utilizarea de variabile
neiniializate explicit de programator.
In Java, se fac automat la atribuire numai conversiile de promovare de la un tip numeric inferior la un tip
aritmetic superior, care nu implic o trunchiere. Exemple:
int n=3; float f; double d;
d=f=n;
// corect f=3.0, d=3.0
n=f;
// gresit sintactic
f=d;
// gresit sintactic
- 21 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Ierarhizarea tipurilor aritmetice, de la inferior la superior este:


byte, short, int, long, float, double
Tipul char nu este un tip aritmetic dar se pot face conversii prin operatorul cast, de forma (tip) ntre tipul
char i orice tip aritmetic ntreg. Exemplu:
byte b=65; char ch; ch =(char)b;
ch='\n'; b =(byte)ch;

// ch este 'A'
// b este 10

Aceleai reguli de conversie ntre tipuri numerice se aplic i ntre argumentele efective i argumentele
formale, deoarece compilatorul face automat o atribuire a valorii argumentului efectiv la argumentul formal
corespunztor. Exemplu: double r = Math.sqrt(2);
// promovare de la int la double
Conversia de la un tip numeric superior la un tip aritmetic inferior trebuie cerut explicit prin folosirea
operatorului cast de forare a tipului i nu se face automat ca n C. Exemple :
f= (float)d;
// cu pierdere de precizie
n=(int)f;
// cu trunchiere
int r = (int) Math.sqrt(4);
// conversie necesara de la double la int
// functie de rotunjire din clasa Math
public static int round (float a) {
return (int)floor(a + 0.5f);
// "floor" are rezultat double
}
Compilatorul Java verific dac este specificat un rezultat la orice ieire posibil dintr-o funcie cu tip diferit
de void (de exemplu, instruciuni if fr else ). Exemplu:
public static int indexOf (int a[], int b) { // pozitia lui b in vectorul a
for (int i=0;i<a.length;i++)
if (a[i]==b)
return i;
// return 1;
// eroare de compilare !
}
Cea mai important diferen dintre Java, pe de o parte, i limbajele C, C++ pe de alt parte, este absena
tipurilor pointer din Java. Deci nu exist posibilitatea de a declara explicit variabile pointer i nici operatorii
unari & (pentru obinerea adresei unei variabile) i * (indirectare printr-un pointer). Operatorul new din
C++ pentru alocare dinamic are n Java un rezultat o referin i nu un pointer.

IE.02.1.2 Supradefinirea funciilor


Supradefinirea sau suprancrcarea funciilor (Function Overloading) a fost introdus n C++ pentru a
permite definirea mai multor funcii cu acelai nume i cu acelasi tip dar cu argumente diferite ntr-o aceeai
clas. Pot exista funcii cu acelai nume (eventual i cu acelasi argumente i tip) n clase diferite, dar acesta
nu este un caz de supradefinire, fiindc ele se afl n spaii de nume diferite.
In Java, ca i n C++, o funcie este deosebit de alte funcii din aceeai clas prin "semntura" sa (prin
"amprenta" funciei), care este format din numele, tipul i argumentele funciei. Un exemplu uzual de
funcii supradefinite este cel al funciilor de afiare la consol n mod text print i println, care au mai
multe definiii, pentru fiecare tip de date primitiv i pentru tipurile clas String i Object :

- 22 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

public class PrintStream ... {


// din pachetul java.io
public void print (int i) {
// scrie un ntreg
write (String.valueOf(i));
}
public void print (float f) ,
// scrie un numr real
write (String.valueOf(f));
}
public void print (boolean b) {
// scrie un boolean
write (b ? true : false);
}
public void print (String s) {
// scrie un sir de caractere
if (s== null) s= null;
write (s);
}
Type a quote from the document or the summary of an interesting point. You
can position the text box anywhere in the document. Use the Text Box Tools
IE.02.1.3 Declaraii de variabile
tab to change the formatting of the pull quote text box.]
O declaraie de variabil poate s apar fie ntr-o funcie, fie n afara funciilor, dar ntr-o clas; nu exist
variabile externe claselor. Locul declaraiei este important; o variabil dintr-o funcie este local acelei
funcii, iar o variabil declarat la nivel de clas este utilizabil de orice funcie din clas (i chiar de funcii
din alte clase,dac este public).
In C toate declaraiile dintr-un bloc trebuie s precead prima instruciune executabil din acel bloc. In C++
i n Java o declaraie poate apare oriunde ntr-un bloc, ntre alte instruciuni sau declaraii. Domeniul de
valabilitate al unei variabile ncepe n momentul declarrii i se termin la sfritul blocului ce conine
declaraia.
Instruciunea for constituie un caz special: variabila contor se declar de obicei n instruciunea for, iar
valabilitatea acestei declaraii este limitat la instruciunile repetate prin instruciunea for . Exemplu:
public static boolean este ( int x[ ], int y) {
// daca y este in vectorul x
int n=x.length;
// lungime vector x
for (int k=0; k<n; k++)
if ( x[k]==y)
break;
return k==n ? false : true;
// eroare: k nedeclarat !
}
In Java nu exist cuvntul cheie const iar constantele sunt declarate ca variabile cu atributele static i final.
Exemplu:
public static final double PI = 3.14159265358979323846;

// in clasa Math

In Java nu exist declaratia typedef deoarece definirea unei clase introduce automat un nume pentru un nou
tip de date.
In Java nu exist operatorul sizeof , pentru c lungimea variabilelor este cunoscut, iar la alocarea de
memorie (cu new) nu trebuie specificat dimensiunea alocat.

- 23 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

IE.02.1.4 Structura programelor Java


O aplicaie Java conine cel puin o clas, care conine cel putin o metod cu numele main de tip void i cu
atributele static i public. Metoda main trebuie s aib ca unic argument un vector de obiecte String. Ca i n
C, execuia unui program ncepe cu funcia main, doar c main trebuie s fie inclus, ca metod static, ntr-o
clas i trebuie s aib un argument vector de iruri. Exemplul urmtor este un program minimal, care
afieaz un text constant:
public class Main {
public static void main ( String arg[ ] ) {
System.out.println (" Main started ");
}
}
In Java nu conteaz ordinea n care sunt scrise funciile (metodele) unei clase, deci o funcie poate fi apelat
nainte de a fi definit i nici nu este necesar declararea funciilor utilizate (nu se folosesc prototipuri de
funcii). Orice funcie aparine unei clase i nu se pot defini funcii n afara claselor.
In exemplele urmtoare se vor folosi numai clase care reunesc cteva metode statice, funcii care pot fi
executate fr a crea obiecte de tipul clasei respective.
Exemplu de fiier surs cu o singur clas, care conine dou metode, ambele publice i statice:
class Main {
public static void main (String arg[ ]) {
writeln ("Hello world !");
}
public static void writeln (String txt) {
System.out.println (txt);
}
}

// cu "main" incepe executia

// afiseaza un text pe ecran

Numele unei metode statice trebuie precedat de numele clasei din care face parte (separate printr-un punct),
dac este apelat dintr-o metod a unei alte clase. Exemplu:
public class Main {
public static void main (String arg[ ]) {
Util.writeln ("Hello world !");
}
}
public class Util {
public static void writeln (String txt) {
System.out.println (txt);
}
}

// cu "main" incepe executia

// afiseaza un text pe ecran

O metod ne-static trebuie apelat pentru un anumit obiect, iar numele ei trebuie precedat de numele
obiectului (i un punct). Metoda println() este apelat pentru obiectul adresat de variabila out, variabil
public din clasa System.

- 24 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Un fiier surs Java poate conine mai multe clase, dar numai una din ele poate avea atributul public. Numele
fiierului surs (de tip java) trebuie s coincid cu numele clasei publice pe care o conine. O clas public
este accesibil i unor clase din alte pachete de clase.
Compilatorul Java creeaz pentru fiecare clas din fiierul surs cte un fiier cu extensia class i cu numele
clasei. Dac este necesar, se compileaz i alte fisiere surs cu clase folosite de fiierul transmis spre
compilare.
Faza de execuie a unui program Java const din ncrcarea i interpretarea tuturor claselor necesare
execuiei metodei main din clasa specificat n comanda java.

IE.02.1.5 Tipuri clas i variabile referin


O clas este o structur care poate conine att date ct i funcii ca membri ai structurii. In Java nu mai
exist cuvntul cheie struct , iar definirea unei clase folosete cuvntul cheie class. Se pot defini clase numai
cu date publice, echivalente structurilor din limbajele C i C++. Exemplu:

public class Point {


// orice punct din plan
public double x, y;
// coordonate punct
}
// creare si utilizare obiect din clasa "Point"
Point a = new Point();
// constructor implicit, generat automat
a.x=2.; a.y =-3;
// un punct in cadranul 4

In practic se prefer ca variabilele clasei Point s fie de tip private (inaccesibile unor metode din alte clase)
i ca iniializarea lor s se fac n constructorul clasei:
public class Point {
// orice punct din plan
private double x,y;
// coordonate punct
public Point (double xi, double yi) { x=xi; y=yi; } // functie constructor
}
Point a = new Point (2,-3);
Clasele (neabstracte) Java sunt de dou categorii:
- Clase instaniabile, care pot genera obiecte, care conin date i metode (ne-statice).
- Clase neinstaniabile, care conin doar metode statice (i eventual constante).
O metod static corespunde unei funcii din limbajul C, cu diferena c numele funciei trebuie precedat de
numele clasei din care face parte. Exemple:
double xabs = Math.abs(x);
// valoarea absoluta a lui x
double y = Math.sqrt(x);
// radical din x
int n = Integer.parseInt (str);
// conversie sir "str" la tipul "int"
Definirea unei clase instaniabile T creeaz automat un nou tip de date T. Un obiect de tip T este o instaniere
a clasei T i este referit printr-o variabil de tip T. Clasa Java cu numele String definete un tip de date
String, ce poate fi folosit n declararea de variabile, vectori sau funcii de tip String. Exemple:
- 25 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

String msg = "Eroare";


String tcuv[] ={"unu","doi","trei"};

// o variabila sir
// un vector de siruri

Un obiect Java corespunde unei variabile structur din C, iar o variabil de un tip clas corespunde unei
variabile pointer la o structur din C. In Java toate obiectele sunt alocate dinamic, folosind operatorul new,
iar variabila de tip clas trebuie iniializat cu rezultatul operatorului new. Exemplu:
String mesaj;
// String este o clas predefinit
mesaj = new String ( Eroare ! ) ; // alocare memorie pentru sir
Pentru constantele de tip String se creeaz obiecte automat, de ctre compilator, ale cror adrese pot fi
folosite n atribuiri sau iniializri la declarare. Exemple:
System.out.println ("Eroare !");
String msg; msg = " Corect";
Clasa String conine mai multe metode publice, utilizabile n alte clase. De exemplu, metoda length(), fr
argumente, are ca rezultat (ntreg) lungimea irului coninut n obiectul de tip String pentru care se apeleaz
metoda. Exemplu:
int len = mesaj.length();
Acest exemplu arat c membrii unei clase se folosesc la fel cu membrii unei structuri, indiferent c ei sunt
variabile (cmpuri) sau funcii (metode). Un alt exemplu este o construcie mult folosit n Java pentru
afiarea la consol (n mod text) a unor iruri de caractere:
System.out.println (mesaj);
System.out.println ( Eroare );
In aceste exemple System este numele unei clase predefinite, out este numele unei variabile publice (din
clasa System) de un tip clas (PrintStream), iar println() este numele unei metode din clasa PrintStream.
Numele unei metode poate fi precedat de numele unei variabile clas sau de numele unei clase, dar
ntotdeauna caracterul separator este un punct. Este uzual n Java s avem denumiri de variabile sau de
metode care conin cteva puncte de separare a numelor folosite n precizarea contextului. Exemple:
if ( Character.isDigit ( str.charAt(0)) ) . . . // daca primul caracter e o cifra
System.out.println (obj + obj.getClass().getName());
int maxdigits= (Integer.MAX_VALUE+"").length();
O referin la un tip clas T este de fapt un pointer la tipul T dar care se folosete ca i cum ar fi o variabil
de tipul T. Indirectarea prin variabila referin este realizat automat de compilator, fr a folosi un operator
special, ca n C .
Tipul referin a fost introdus n C++ n principal pentru a declara parametri modificabili n funcii, cu
simplificarea scrierii i utilizrii acestor funcii. In Java nu trebuie folosit o sintax special pentru
declararea de variabile sau de parametri referin, deoarece toate variabilele de un tip clas sunt automat
considerate ca variabile referin. Nu se pot defini referine la tipuri primitive.
O variabil referin Java nu este un obiect, dar conine adresa unui obiect alocat dinamic. O variabil
referint apare de obicei n stnga unei atribuiri cu operatorul new sau cu constanta null n partea dreapt.
Exemplu:
Vector a = new Vector( );

// a = variabila referinta la un obiect de tip Vector

- 26 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Atunci cnd se apeleaz o metod pentru un obiect, se folosete numele variabilei referin ca i cum acest
nume ar reprezenta chiar obiectul respectiv i nu adresa sa. Exemplu:
System.out.println ( a.size() );

// afisare dimensiune vector a

Operatorul de concatenare '+', folosit ntre obiecte de tip String, poate crea impresia c variabilele de tip
String conin chiar irurile care se concateneaz i nu adresele lor. Exemple:
String s1="java.", s2="util.", s3="Rand";
System.out.println (s1+s2+s3);
// scrie java.util.Rand
Operatorul de concatenare + este singurul operator supradefinit n Java i el poate fi utilizat ntre
operanzi de tip String sau cu un operand de tip String i un alt operand de orice tip primitiv sau de un tip
clas (pentru care exist o funcie de conversie la tipul String ). Exemplu:
int a=3, b=2 ;
System.out.println ( a + + + b + = + (a+b)); // scrie: 3 + 2 = 5
Efectul operatorului '+' depinde de tipul operanzilor: dac unul din operanzi este de tip String atunci este
interpretat ca operator de concatenare iar rezultatul este tot String.

IE.02.1.6 Spaii de nume n Java


Un spaiu de nume (namespace) este un domeniu de valabilitate pentru un nume simbolic ales de
programator. In cadrul unui spaiu nu pot exista dou sau mai multe nume identice (excepie fac metodele
supradefinite dintr-o aceeai clas). Pot exista nume identice n spaii diferite.
Fiecare clas creeaz un spaiu de nume pentru variabilele i metodele clasei; ca urmare numele metodelor
sau datelor publice dintr-o clas trebuie precedate de numele clasei, atunci cnd se folosesc n alte clase.
Exemple:
Main.writeln ("abc");
// clasa Main, metoda writeln
Math.sqrt(x);
// clasa Math, metoda sqrt
System.out
// clasa System, variabila out
Clasele nrudite ca rol sau care se apeleaz ntre ele sunt grupate n "pachete" de clase (package).
Instruciunea package se folosete pentru a specifica numele pachetului din care vor face parte clasele
definite n fisierul respectiv; ea trebuie s fie prima instruciune din fiierul surs Java. In lipsa unei
instruciuni package se consider c este vorba de un pachet anonim implicit, situaia unor mici programe de
test pentru depanarea unor clase. Un nume de pachet corespunde unui nume de director, cu fiierele de tip
class corespunztoare claselor din pachet.
Numele unui pachet poate avea mai multe componente, separate prin puncte. Numele de pachete cu clase
predefinite, parte din JDK, ncep prin java sau javax. Exemple : java.io , java.util.regex , java.awt,
javax.swing.tree
Un pachet este un spaiu pentru numele claselor din acel pachet. In general numele unei clase publice trebuie
precedat de numele pachetului din care face parte, atunci cnd este folosit n alt pachet. De observat c un
fiier surs nu creeaz un spaiu de nume; este posibil i chiar uzual ca n componena unui pachet s intre
clase aflate n fiiere surs diferite, dar care au la nceput aceeai instruciune package.
Pachetul cu numele "java.lang" (language) este folosit de orice program Java i de aceea numele lui nu mai
trebuie menionat naintea numelui unei clase din java.lang. Clasele String,Integer,Object,System .a. fac
parte din pachetul java.lang. Exemplu de utilizare a unei clase dintr-un alt pachet dect java.lang :
- 27 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

public static void main (String arg[]) {


java.util.Random rand =new java.util.Random();
for (int i=1;i<=10;i++)
// scrie 10 numere aleatoare
System.out.println ( rand.nextFloat());
}
Variabila cu numele "rand" este de tipul Random, iar clasa Random este definit n pachetul "java.util".
Notaia rand.nextFloat() exprim apelul metodei nextFloat() din clasa Random pentru obiectul adresat de
variabila rand.
Instruciunea import permite simplificarea referirilor la clase din alte pachete i poate avea mai multe forme.
Cea mai folosit form este:
import pachet.* ;
Instruciunea anterioar permite folosirea numelor tuturor claselor dintr-un pachet cu numele "pachet", fr a
mai fi precedate de numele pachetului. Exemplul urmtor ilustreaz folosirea instruciunii import:
import java.util.*;
// sau: import java.util.Random;
class R {
public static void main (String arg[]) {
Random rand =new Random();
for (int i=1;i<=10;i++)
// scrie 10 numere aleatoare
System.out.println ( rand.nextFloat());
}
}
Uneori se prefer importul de clase individuale, pentru documentare i pentru evitarea ambiguitilor create
de clase cu acelai nume din pachete diferite. Exemplu care arat riscurile importului tuturor claselor dintrun pachet:
import java.util.*;
import java.awt.*;
...
public static void main (String av[ ]) {
List list; . . . // clasa java.awt.List sau interfaa java.util.List ?
}

IE.02.1.7 Definirea i utilizarea de vectori n Java


Cuvntul vector este folosit aici ca echivalent pentru array din limba englez i se refer la un tip de date
implicit limbajelor C, C++ i Java. Acest tip este diferit de tipul definit de clasa Vector pentru vectori ce se
pot extinde automat). In Java, declararea unei variabile (sau unui parametru formal) de un tip vector se
poate face n dou moduri, echivalente:
tip nume [ ];
tip [ ] nume;

// la fel ca in C si C++
// specific Java

Declararea matricelor (vectori de vectori) poate avea i ea dou forme. Exemplu:


int a[ ][ ] ;
int * +* + b;

// o matrice de ntregi
// alt matrice de ntregi

In Java nu este permis specificarea unor dimensiuni la declararea unor vectori sau matrice, deoarece
alocarea de memorie nu se face niciodat la compilare. Exemplu de eroare:
- 28 -

INFORMATIC*I*

int a[100];

IE. TEHNICI AVANSATE DE PROGRAMARE

// corect: int a[] = new int[100];

O variabil vector este automat n Java o variabil referin iar memoria trebuie alocat dinamic pentru orice
vector. Alocarea de memorie pentru un vector se face folosind operatorul new urmat de un nume de tip i
de o expresie (cu rezultat ntreg) ntre paranteze drepte; expresia determin numrul de componente (nu de
octei !) pe care le poate conine vectorul. Exemple:
float x[ ] = new float [10];
// aloca memorie ptr 10 reali
int n=10;
byte[ ][ ] graf = new byte [n][n];
Este posibil i o alocare automat, atunci cnd vectorul este iniializat la declarare cu un ir de valori.
Exemplu:
short prime[ ] = {1,2,3,5,7};
In lipsa unei iniializri explicite, componentele unui vector sunt iniializate automat, cu valori ce depind de
tipul lor: zerouri pentru elemente numerice i null pentru variabile referin de orice tip.
Un vector intrinsec cu componente de un anumit tip este considerat ca un obiect de un tip clas, tip
recunoscut de compilator dar care nu este definit explicit n nici un pachet de clase. Numele acestor clase
este format din caracterul [ urmat de o liter ce depinde de tipul componentelor vectorului: [I pentru int[],
[B pentru byte[], [Z pentru boolean[], [C pentru char[], [F pentru float[] s.a.m.d.
Variabila predefinit cu numele length poate fi folosit ( ca membru al claselor vector ) pentru a obine
dimensiunea alocat pentru un vector (capacitatea vectorului). Exemplu:
// functie de copiere a unui vector
public static void copyVec ( int a [ ] ,int b[ ] ) {
for (int i=0;i < a.length; i++)
// a.length =dimensiunea vectorului a
b[i] = a[i];
}
De reinut c length este dimensiunea alocat i nu dimensiunea efectiv a unui vector, iar numrul de
elemente din vector se transmite ca argument la funcii, atunci cnd difer de capacitatea sa. Variabila length
nu trebuie confundat cu metoda length() din clasa String.
In Java, se verific automat, la execuie, ncadrarea indicilor ntre limitele declarate; ieirea din limite
produce o excepie i terminarea programului. Exemplu:
int [ ] a= new int [10];
for (int i=1;i<=10;i++) a[i]=i;

// exceptie la a[10]=10

Numerotarea componentelor unui vector este de la zero la (length-1), deci n exemplul anterior se produce
excepia de depire a limitelor la valoarea i=10 .
O matrice este privit i n Java ca un vector de vectori, iar variabila length se poate folosi pentru fiecare
linie din matrice, pentru a determina numrul de coloane. Deoarece orice matrice este alocat dinamic, nu
exist probleme la transmiterea unei matrice ca argument la o funcie. Nu este necesar transmiterea
dimensiunilor matricei la o funcie dac matricea este ocupat complet (la capacitatea ei).
O funcie poate avea un rezultat de un tip vector (sau matrice).

- 29 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

In Java, ca i n C, transmiterea parametrilor se face prin valoare, adic se copiaz valorile parametrilor
efectivi n parametrii formali corespunztori, nainte de execuia funciei. Deci o funcie Java nu poate
transmite rezultate prin argumente de un tip primitiv, dar poate modifica componentele unui vector primit ca
argument. Exemplu:
static int divizori (int n, int d[ ]) {
// creare vector cu divizorii unui ntreg
int k=0;
for (int i=1;i<n;i++)
if ( n %i == 0)
d[k++]=i;
// pune divizorul i n vectorul d
return k;
// numar de divizori
}
// utilizare funcie
int div[ ]= new int [m];
// aloca memorie ptr vector divizori
int nd = divizori (m, div);
// completare vector divizori
Clasa Arrays din pachetul java.util reunete funcii pentru operaii uzuale cu vectori avnd elemente de orice
tip (primitiv sau clas): afiare, sortare, cutare s.a.

IE.02.2 Definirea de clase n Java


O clas Java corespunde unui tip structur din limbajul C, dar o clas mai conine ca membri i funcii
(metode) care realizeaz operaii cu variabilele clasei. Clasele Java pot avea diferite niveluri de
accesibilitate fa de alte clase:
public (accesibil pentru orice alt clas)
private (inaccesibil pentru orice alt clas)
protected (accesibil pentru subclase)
package (implicit) ( accesibil pentru clase din acelai pachet de clase)
Clasele de bibliotec Java sunt publice i fiecare este definit ntr-un fiier separat de celelalte clase; numele
clasei este acelai cu numele fiierului.
O clas (neabstract) poate conine: numai metode statice, numai date, date i metode nestatice (Object
methods), date, metode statice i nestatice.
Notiunea de funcie se folosete n Java pentru ambele categorii de funcii dintr-o clas Java:
-

Metode statice sau nestatice (cu nume diferit de numele clasei)

Constructori de obiecte (cu acelasi nume ca i clasa)

IE.02.2.1 Metode statice


Metodele statice se folosesc rar: funcii cu date i rezultate de un tip primitiv , funcii recursive, .a.
Utilizarea excesiv de metode statice este specific programrii procedurale (practicat n limbajul C)
Metodele statice sunt precedate de cuvntul static i au alt mod de utilizare dect metodele aplicabile
obiectelor. Utilizarea lor nu este condiionat de existena unor obiecte. Ele se mai numesc i metode ale
claselor (Class Methods) n contrast cu metodele nestatice (ale obiectelor).

- 30 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Metodele statice corespund funciilor din C; ele pot fi apelate fr a crea obiecte dar folosind i numele clasei
naintea numelui metodei. Metodele statice sunt de obicei i publice, pentru a fi apelate din afara clasei n
care sunt definite
Metoda main cu care ncepe execuia unei aplicaii Java trebuie s fie o metod static pentru c la nceput
nu exist nici un obiect. Clasa de bibliotec Math grupeaz metode (funcii) matematice care au argumente
i rezultate de un tip primitiv (double), deci nu sunt asociate unor obiecte sau clase. Exemplu:
class Sqrt {
public static void main (String args[ ]) {
int x = Integer.parseInt (args[0]);
double r = Math.sqrt (x);
System.out.println (r);
}
}

// functie statica din clasa Integer


// functie statica din clasa Math

IE.02.2.1 Metode ale obiectelor


Specific programrii orientate obiect este definirea i utilizarea de clase cu date i metode nestatice, numite
Object Methods (metode aplicabile obiectelor). Metodele obiectelor sunt in general publice pentru a putea fi
apelate din afara clasei. Metodele publice nestatice ale unei clase pot fi clasificate astfel:
-

Metode de acces la datele ncapsulate n clas (getter, setter)

Metode motenite de la clasa Object i redefinite (suprascrise)

Metode specifice clasei respective (determinate de rolul ei in aplicaie)

O clas Complex pentru numere complexe, va conine partea real i partea imaginar a unui numr
complex (ca date private), metode publice de acces la aceste date, metode mostenite (toString(), equals())
dar i operaii necesare lucrului cu numere complexe: adunare, scdere, .a.
public class Complex {
// datele clasei
private int re, im;
// constructor
public Complex (int re, int im) { this.re=re; this.im=im; }
// metode publice proprii clasei
public void add ( Complex cpx) { // adunarea a doua numere
re = re + cpx.re; im = im + cpx.im;
}
public void sub ( Complex cpx) { // scaderea a doua numere
re -= cpx.re; im -= cpx.im;
}
// metode mostenite si redefinite
public String toString () , return "(" + re + "," + im + ");}
Datele unui obiect au de obicei atributul private; ele nu sunt accesibile direct pentru metode din alte clase ci
numai prin intermediul metodelor clasei. De exemplu, variabilele re i im dintr-un obiect de tip Complex nu
pot fi citite sau modificate, dar metode ale clasei Complex opereaz cu aceste variabile. Dac este nevoie de
citirea sau de modificarea direct a datelor dintr-un obiect atunci se vor defini metode getter i setter :

- 31 -

INFORMATIC*I*

public void setRe (re,2);


public int getRe (re);

IE. TEHNICI AVANSATE DE PROGRAMARE

// re=2

Modificarea datelor din obiecte este consistent cu operaiile permise i se evit erori de programare cauzate
de modificri nedorite ale datelor. De exemplu, datele dintr-un vector folosit ca stiv nu se pot accesa sau
modifica aleator ci numai n cadrul impus de operaiile push i pop (la vrful stivei).
Toate clasele Java extind clasa Object i redefinesc cteva metode motenite de la clasa Object: toString(),
equals(), .a.
public class Complex extends Object {
... // date si constructori
// redefinire metoda mostenita
public String toString () {
StringBuffer sb = new StringBuffer ();
sb.append(re);
if (im>0) sb.append('+');
else { sb.append('-'); im =-im; }
return sb.append(im).toString();
}
... // alte metode
}
O funcie nu poate transmite n afar adresa unui obiect creat n funcie printr-un parametru referin.
Exemplu de funcie fr efect n afara ei:
// metoda statica pentru trecere sir in litere mari - gresit !!!
static void toUpper (String t) {
t = t.toUpperCase();
// se creeaza un nou obiect, cu alta adresa
}
Aici se creeaz un obiect String prin metoda toUpperCase(), iar adresa sa este memorat n variabila local
t (care coninea iniial adresa irului dat). Un obiect creat ntr-o funcie trebuie transmis ca rezultat al
funciei. Exemplu:
static String toUpper (String s) { return s.toUpperCase(); }

O funcie poate modifica un obiect a crui adres o primete ca argument numai dac n clasa respectiv
exist metode pentru modificarea obiectelor.
Clasele String, Integer, Float .a. nu conin metode pentru modificarea datelor din aceste clase, deci o
funcie care primete o referin la un astfel de obiect nu poate modifica acel obiect. In acest fel se protejeaz
obiectul transmis ca argument fa de modificarea sa nedorit de ctre funcia care l folosete. Obiectele din
clase fr metode de modificare a datelor (read-only) se numesc obiecte nemodificabile (immutable objects).
Pentru o scriere mai compact se practic uneori nlntuirea de metode (method chaining), adic aplicarea
unei metode asupra rezultatului unei alte metode, ntr-o aceeasi expresie. Exemple:
String line = f.readLine().trim().toUpperCase(); // citeste linie, elimina spatii si trece in litere mari
if ( fname.substring(fname.indexOf(.)+1).toLowerCase().equals(java) ) ...

- 32 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Utilizarea abuziv de metode statice este o prelungire a programrii procedurale n limbajele orientate obiect.
Utilizarea de metode obiect (nestatice) permite utilizarea unor tehnici specifice programrii cu obiecte:
derivare, motenire, polimorfism, programare cu interfete, s.a. Avantajele metodelor obiect sunt mai evidente
n cazul unor familii de clase deschise pentru extindere i atunci cnd se urmrete reutilizarea metodelor
unor clase n alte clase.

IE.02.3 Obiecte Java


Un obiect Java corespunde unei variabile de un tip structur din C; obiecte diferite pot conine date diferite
dar operaiile sunt comune tuturor obiectelor.
Toate obiectele sunt create dinamic, folosind operatorul new, care apeleaz implicit constructorul clasei
pentru iniializarea variabilelor din obiectul creat.
Obiecte diferite din aceeai clas suport aceleai operaii (comune obiectelor clasei) dar conin de obicei
date diferite (nu neaprat). Obiecte diferite au adrese diferite n memorie, adrese memorate n variabilele
referin. Variabilele de tip clas corespund variabilelor pointer din limbajele C. Ele se numesc variabile
referin deoarece permit referirea la obiecte. Exemplu de creare i utilizare de obiecte Java:
public static void main (String[] a) {
Complex c1 = new Complex (2,3); // un obiect
Complex c2 = new Complex (1,4); // alt obiect
c1.add (c2);
// c1=c1+c2
System.out.println (c1.toString( ) ); // afisare date obiect c1
}
Variabilele de un tip clas contin referine (pointeri) la obiecte, n timp ce variabilele de un tip primitiv (int,
double, char) conin valori. Iniializarea variabilelor referin se face de obicei cu rezultatul operatorului new
dar i ca rezultat al unei atribuiri sau unei funcii. Este posibil ca dou sau cteva variabile referin s se
refere la acelai obiect (prin atribuire ntre ele).
Efectul atribuirii ntre variabile referin este copierea unei adrese i nu copierea unui obiect; duplicarea unui
obiect se face prin clonare. Folosirea operatorului de comparaie == ntre variabile referin va compara
adrese i nu obiecte; comparaia la egalitate ntre obiecte se face cu metoda equals() care exist n orice clas
(motenit de la clasa Object i redefinit). Exemplu:
String linie= file.readLine();
if (linie.equals (.)) break; // NU: if (linie==.) break;

Majoritatea claselor sunt clase instaniabile (care pot genera obiecte prin instanierea clasei), deoarece
aciunile dintr-un program Java rezult prin apeluri de metode ntre obiecte.
Instanierea unei clase se face n Java folosind operatorul new, care aloc memorie pentru un nou obiect i
face iniializrile necesare. Iniializarea datelor (variabilelor) dintr-un obiect este realizat prin apelarea unei
funcii numit constructor, care are numele clasei. Orice clas instaniabil trebuie s aib (cel puin) un
constructor public (apelabil dintr-o alt clas). Este uzual ca o clas s aib civa constructori, care se
deosebesc prin argumente (parametri) i prin numrul de variabile iniializate.
- 33 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

In lipsa unor constructori declarai explicit de programator, orice clas Java primete automat un constructor
public fr argumente i care nu are nici un efect.

IE.02.4 Cuvntul cheie this


Cuvntul cheie this are dou utilizri n Java:
- ca variabil referin implicit care se refer la obiectul curent i este folosit n metode nestatice
- ca nume de constructor.
Cuvntul this este folosit ca variabil referin n diferite siuatii:
- Pentru a deosebi variabilele clasei de argumente cu acelai nume:
public MyVector ( int nmax) , this.nmax=nmax; n=0; - Pentru a explicita c este vorba despre metode sau variabile din aceeai clas sau din acelai obiect:
public int size () { return this.n;}

// din clasa MyVector

- Atunci cnd rezultatul metodei este chiar obiectul pentru care s-a apelat metoda ( modificat) :
// metoda din clasa StringBuffer
public StringBuffer deleteCharAt (int k) {
// sterge caracterul din poz k
System.arraycopy (value, k+1, value, index, count-k-1);
count--;
// numar de caractere in sir
return this;
// rezultatul este obiectul modificat de metod
}
Un constructor se poate referi la alt constructor din aceeai clas numai folosind this i nu prin numele sau.
Exemplu:
public class MyVector {
private Object a[];
// adresa vector
private int n, nmax;
// dimensiune si capacitate vector
public MyVector (int m) {
// un constructor
nmax=m; n=0;
a= new Object[m];
// aloca memorie
}
// alt constructor
public MyVector () { this (10); } // capacitate implicita 10
.
}

IE.02.5 iruri de caractere n Java


Operaiile cu iruri sunt prezente n multe aplicaii i ele difer mult n Java de forma lor din limbajul C. In
Java un ir este un obiect din clasa String sau din clasele StringBuffer, StringBuilder, iar operaiile cu
iruri se realizeaz prin apeluri de metode din aceste clase. Constantele ir, ntre ghilimele, sunt obiecte
nemodificabile de tip String.

- 34 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Clasa String este o clas read-only i final, deci nu se poate extinde cu metode de modificare a vectorului
de caractere coninut n fiecare obiect. Exemplu de utilizare greit a metodei replaceAll() din clasa String
pentru nlocuirea unui subir s1 cu un alt subir s2 n irul s:
s.replaceAll (s1,s2);
Metodele replaceAll() si replace() au ca rezultat un nou ir obinut dup substituire i nu modific obiectul
pentru care se apeleaz; de aceea utilizarea corect este urmtoarea:
s = s.replaceAll (s1,s2);
Clasele StringBuffer si StringBuilder (din 1.5) sunt variante ale clasei String care conin n plus i metode
pentru modificarea obiectului (irului). Exemple de metode care modific irul coninut ntr-un obiect de tip
StringBuffer: append, insert, delete, setCharAt, setLength. Un obiect de tipul StringBuffer transmis unei
funcii ca argument poate fi modificat de ctre funcie. Variant pentru funcia toUpper():
static void toUpper (StringBuffer s) {
String str= new String (s);
s.replace (0,str.length(),str.toUpperCase());
}
Clasa StringBuilder este mai performant dect StringBuffer pentru programele fr fire de execuie.
Concatenarea de iruri este o operaie frecvent n Java. Metoda println() folosit pentru afiarea pe ecran
poate avea un singur argument de tip String. Pentru a scrie mai multe iruri acestea se concateneaz ntr-un
singur ir cu operatorul +.Exemplu:
System.out.println ( x= + x);

// x de orice tip

Intr-o expresie cu operatorul binar +, dac unul din operanzi este de tip String, atunci compilatorul Java
face automat conversia celuilalt operand la tipul String (pentru orice tip primitiv i pentru orice tip clas care
redefineste metoda toString). Aceast observaie poate fi folosit si pentru conversia unui numr n ir de
caractere, ca alternativ a utilizrii metodei valueOf() din clasa String. Exemplu:
float x = (float) Math.sqrt(2);
String str = +x;
// sau str = String.valueOf(x);
O instruciune de forma a=a+b; cu a si b de tip String este tratat de compilator astfel: se transform
obiectele a i b n obiecte de tip StringBuilder, se apeleaz metoda append()i apoi creeaz un obiect String
din obiectul StringBuilder rezultat din concatenare:
String a=unu, b=doi;
StringBuffer am= new StringBuffer (a), am.append(bm);
a= new String (am);
Dac trebuie s facem multe concatenri de iruri este preferabil ca timp s se foloseasc direct metoda
append() din clasa StringBuilder. Exemplu:
public static String arrayToString ( int a[ ]) { // creare sir cu continutul unui vector
StringBuilder aux = new StringBuilder (*);
int n =a.length;
for (int i=0;i<n-1;i++)
aux.append (a*i+ + ,);
return new String (aux.append (a[n-1+ ++) ) ;
}

- 35 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

De observat c trecerea de la tipul String la tipul StringBuffer se poate face numai printr-un constructor, dar
trecerea invers se poate face prin metoda toString(), iar aceste transformri pot fi necesare pentru c n clasa
StringBuffer nu se regsesc toate metodele din clasa String.
Metoda toString() exist n toate clasele i produce un ir cu datele din obiectul pentru care se apeleaz (face
conversia de la tipul datelor din obiect la tipul String). Orice tip de obiect se poate transforma ntr-un ir
String prin metoda toString(), apelat explicit sau implicit, dar nu i prin cast. Exemplu:
Float x = new Float(3.14); String s = (String)x; // eroare la compilare
String s =x.toString(); String s = x+; // apel implicit toString
Pentru extragerea de cuvinte (tokens) dintr-un text se folosesc fie clasele Scanner, StringTokenizer i
StreamTokenizer, fie clasele pentru lucrul cu expresii regulate: Pattern, Matcher .a.
Imprirea unui text n cuvinte se poate face folosind clasele Pattern, Matcher sau cu metoda split() din
clasa String, care creeaz un vector de cuvinte: String[] split (regex)

IE.02.6 Operaii de citire-scriere n Java


Majoritatea aplicaiilor locale (Desktop Applications) folosesc o interfa grafic pentru preluarea datelor de
intrare i pentru prezentarea rezultatelor. Programele folosite n linie de comand i cele care folosesc fiiere
text trebuie s foloseasc clase de intrare-ieire. Exist un numr mare de clase de I/E: cele mai vechi n
pachetul java.io iar cele mai noi n pachetul java.nio. Aceste clase se folosesc direct (prin obiecte ale lor) sau
indirect, prin clase care adaug i unele prelucrri cum sunt Scanner, Formatter, StreamTokenizer, s.a.
Afiarea pe ecran i scrierea n fiiere text a oricrui tip de date se face simplu folosind metodele print()i
println() din clasele PrintStream sau PrintWriter. Aceste metode pot primi un singur argument de orice tip
primitiv sau de tipul generic Object i realizeaz automat conversia numerelor din format intern n format
extern (n ir de caractere). Variabila System.out, de tip PrintStream, desemneaz ecranul i este folosit
pentru afiarea n mod text (nu i ntr-o interfa grafic). Pentru citire de numere de la consol, cu conversie
din format extern n format intern, se poate folosi clasa Scanner. Exemplu:
public static void main (String arg[]){
float sum=0;
Scanner sc = new Scanner (System.in);
while ( sc.hasNextFloat())
sum += sc.nextFloat();
System.out.println(sum);
}
Numerele citite cu un obiect Scanner pot fi repartizate cte unul sau mai multe pe o linie i terminate cu un
caracter nenumeric (care nu pot s apar ntr-un numr).
In general, un fiier text este identificat sau prin numele su (de tip String) sau prin calea complet la fiier
(obiect de tip java.io.File). Clasele de I/E pentru operaii cu fiiere disc au constructori cu argument String
si cu argument File pentru numele fiierului disc cu care lucreaz. Constructorii i metodele acestor clase pot
genera excepii de tip IOException, care trebuie aruncate sau tratate.
Excepiile sunt provocate n general de erori la execuie, dar pot fi cauzate i de alte situaii care nu sunt erori
i nu trebuie s produc terminarea automat a programului (de exemplu sfrit de fiier la citire). Unele
excepii nu necesit nici o aciune din partea programatorului, iar efectul lor este oprirea programului cu un
mesaj privind cauza excepiei i linia surs unde s-a produs. Excepiile la operaii de intrare-ieire (i altele)
- 36 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

trebuie fie aruncate (clauza throws cu numele excepiei n antetul funciei n care poate apare excepia), fie
tratate printr-un bloc de instruciuni (construcia try-catch).
Clasele din pachetul java.io pot fi grupate astfel:
- Clasa RandomAccessFile, pentru operaii de citire i/sau de scriere cu acces secvenial i direct
- Clasele din familiile InputStream si OutputStream, pentru operaii de citire octei i respectiv de scriere
octei (dar nu citire i scriere n acelai fiier)
- Clasele din familiile Reader si Writer, pentru operaii de citire caractere i respectiv de scriere caractere
(dar nu citire i scriere n acelai fiier).
Pentru a scrie numere ntr-un fiier text pe disc se creeaz mai nti un obiect FileInputStream sau
FileWriter i apoi se creeaz obiectul PrintStream sau PrintWriter. Exemplu de scriere ntregi:
try {
PrintStream ps = new PrintStream ( new FileOutputStream ("numere.txt")) ;
for (int x=1; x<100;x++)
ps.print (x+" ");
// cu spatii intre numere
ps.close();
} catch (IOException e) { e.printStackTrace();}

Exist i un corespondent al funciei sprintf() din limbajul C sub forma metodei format() din clasele
String si java.util.Formatter, cu o utilizare asemntoare funciei sprintf().
Pentru scrierea de iruri n fiiere text se poate utiliza direct metoda write () din clasa FileWriter, dar pentru
a scrie linii de text trebuie adugat explicit caracterul \n. Exemplu:
try {
FileWriter fw = new FileWriter("t.txt");
for (int i=1;i<21;i++)
fw.write (i+" ");
// conversie din int in String si spatii intre numere
fw.close();
} catch (IOException e) { e.printStackTrace();}

Citirea de linii de la tastatur sau dintr-un fiier text se poate face cu metoda readLine() din clasa
BufferedReader sau din DataInputStream, pentru citire din fisiere text formate din linii. Exemplu de citire
linii dintr-un fiier text pe disc:
String line, fname;
// linie de text si nume fisier
try {
BufferedReader br = new BufferedReader (new FileReader(fname));
while ( (line = br.readLine()) != null)
// rezultat null la sfrsit de fisier
System.out.println (line);
} catch (Exception e) { e.printStackTrace();}
Exemplu de citire linii de la tastatur (consol):
public static void main (String [] arg) throws IOException {
String line;
DataInputStream cin = new DataInputStream (System.in);
while ( (line = cin.readLine()) != null)
System.out.println (line);
}
- 37 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Pentru citire de numere de la consol trebuie extrase din linia citit irurile de cifre i fcut conversia din
format extern n format intern (binar) folosind metode statice ca Double.parseDouble(String s)
Integer.parseInt(String s), Float.parseFloat(String s), .a. Exemplu:
public static void main (String arg[])throws IOException{
float x,sum=0; String line, words[];
DataInputStream cin = new DataInputStream (System.in);
try {
while ( (line = cin.readLine()) != null){
words=line.split(" ");
for (String w: words)
if ( ! w.isEmpty()) {
x=Float.parseFloat(w);
sum += x;
}
}
} catch (NumberFormatException e){
System.out.println (sum);
}
}
Pentru programul anterior am considerat c se introduce o liter sau alt caracter nenumeric pentru a termina
secvena de numere introdus, iar aceast liter produce excepia de format nenumeric. La citirea dintr-un
fiier text pe disc este mai simplu, deoarece sfritul de fiier este recunoscut dup lungimea fiierului i nu
trebuie folosite caractere speciale ca terminator de fiier.
Clasa RandomAccessFile are o serie de avantaje fa de alte clase de I/E, dar acest tip nu apare ca posibil
argument n constructorii altor clase care folosesc fiiere disc: clase pentru compresie i arhivare de fiiere,
clase parser de fiiere text sau de fiiere XML, s.a. Aceti constructori au fie un argument File, fie un
argument de tip Reader (InputStream) sau Writer (OutputStream). Clasa RandomAccessFile permite
att operaii de scriere ct i operaii de citire, permite crearea i citirea de fiiere binare, cu numere n
format intern (readInt(), writeInt(), s.a.), permite citirea de linii de text (readLine()), permite accesul direct
la date din fiier pe baza adresei de octet n fiier (seek()), aflarea adresei curente n fiier (getFilePointer()),
aflarea lungimii unui fiier (length()) i permite citirea unui ntreg fiier n memorie (readFully()).

- 38 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Capitolul IE.03. Derivare, motenire, polimorfism n Java


Cuvinte cheie
Derivare, Extindere, Motenire, Superclas, Subclas,
Ierarhii de tipuri, Suprascriere metode, Cuvntul super
IE.03.1 Derivarea (extinderea) claselor
Derivarea este o tehnic de programare specific programrii orientate obiect i este folosit pentru:
- Reutilizarea unor metode dintr-o clas existent n clasele derivate, fr a mai fi declarate sau definite.
- Crearea unor ierarhii de tipuri compatibile.
Derivarea nseamn definirea unei clase D ca o subclas a unei clase A, de la care motenete toate
variabilele i metodele dar nu i constructorii. Clasa A se mai numete i clas de baz sau clas printe sau
superclasa lui D, iar D se numete subclasa lui A.
In Java se spune c o subclas extinde funcionalitatea superclasei, n sensul c ea poate conine metode i
date suplimentare. In general o subclas este o specializare, o particularizare a superclasei i nu extinde
domeniul de utilizare al superclasei. De exemplu, o mulime realizat ca vector este un caz particular de
vector n care elementele sunt diferite ntre ele, iar clasa mulime poate fi derivat din clasa vector cu
redefinirea metodelor de adugare la vector.
Motenire (Inheritance) nseamn c toate metodele publice i protected din clasa A pot fi folosite pentru
obiecte din clasa D, fr ca acestea s fie declarate sau definite n D. Variabilele clasei A se regsesc i n
obiectele de tip D. Variabilele private din superclasa A se motenesc dar nu sunt direct accesibile pentru a fi
folosite n noile metode definite n subclasa D.
Subclasa D poate redefini metode motenite de la clasa printe A i poate aduga noi metode si variabile
clasei A. Tipul D este un subtip al tipului A. La definirea unei clase derivate se foloseste cuvntul cheie
extends urmat de numele clasei de baz.
Exemplul urmtor arat cum se poate defini o clas VSet pentru multimi din vectori prin extinderea clasei
java.util.Vector i redefinirea a dou metode motenite : addElement() si setElementAt(). Pentru obiecte de
tip VSet se pot folosi toate metodele publice din clasa Vector (peste 50 ca numr): toString(), size(),.a., aa
cum se vede din exemplul urmtor:
public static void main (String [] args) {
VSetv =new VSet();
for (int i=1;i<21;i++)
v.addElement (new Integer(i%10));
System.out.println (v.toString()); System.out.println (v.size());
}
Definirea clasei derivate, cu metodele mai vechi din clasa Vector, poate arta astfel:
class VSet extends Vector {
public void addElement (Object obj) {
// adaugare la multimea vector
if ( ! contains(obj))
// daca nu exista deja obj
super.addElement(obj); // atunci se adauga la multimea vector
}
}
- 39 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Se observ cum metoda addElement() din subclas apeleaz o metod motenit de la superclasa Vector i
anume contains(). Crearea de elemente cu aceeai valoare se poate face i cu metoda care modific valoarea
unui element dintr-o poziie dat setElementAt ( Object obj, int i), care ar trebui fie suprascris, fie interzis
pentru mulimi vector (n Java nu este permis accesul prin indici la mulimi).
n acest exemplu metoda suprascris din subclas apeleaz metoda cu acelai nume i argumente din
superclas, iar pentru a deosebi cele dou versiuni se foloseste cuvntul cheie super. Dac nu s-ar folosi
super atunci funcia ar fi infinit recursiv.
O subclas poate deveni superclas pentru alte (sub)clase, iar derivarea (extinderea) poate continua pe oricte
niveluri. In Java nu este permis extinederea simultana a mai multor clase pentru motenire multipl de date
i operaii de la cteva clase. Cuvntul extends poate fi urmat de un singur nume de clas.
Nu se poate extinde o clas final (cu atributul final) i nu pot fi redefinite metodele din superclas care au
unul din modificatorii final, static, private.

IE.03.2 Clasa Object ca baz a ierarhiei de clase Java


In Java, clasa Object (java.lang.Object) este superclasa tuturor claselor JDK i a claselor definite de
utilizatori. Orice clas Java care nu are clauza extends n definiie este implicit o subclas derivat direct din
clasa Object. Clasele abstracte i interfeele Java sunt i ele subtipuri implicite ale tipului Object.
Variabile sau argumente de tip Object (referine la tipul Object) pot fi nlocuite cu variabile de orice alt tip
clas, deoarece orice tip clas este n Java derivat din i deci compatibil cu tipul Object.
Clasa Object transmite foarte puine operaii utile subclaselor sale; de aceea n alte ierarhii de clase (din alte
limbaje) rdcina ierarhiei de clase este o clas abstract. Deoarece clasa Object nu conine nici o metod
abstract, nu este obligatorie redefinirea metodelor mostenite, dar n practic se redefinesc cteva metode:
toString(), equals(), hashCode().
Metoda toString() din clasa Object transform n ir adresa obiectului pentru care se apeleaz this (un ir de
8 caractere hexazecimale) i deci trebuie s fie redefinit n fiecare clas cu date, pentru a produce un ir cu
coninutul obiectului. Metoda toString() permite obinerea unui ir echivalent cu orice obiect, deci trecerea
de la orice tip la tipul String. Ea este apelat explicit sau implicit cnd este necesar conversia. Exemple:
Date d = new Date(); String s = d.toString(); // apel explicit
System.out.println (d);
// apel implicit: println( d.toString())
String s = d+\n;
// apel implicit: d.toString()+\n
Metoda equals() din clasa Object consider c dou variabile de tip Object sau de orice tip derivat din
Object sunt egale dac i numai dac se refer la un acelai obiect:
public boolean equals (Object obj) { return (this == obj); }
Pe de alt parte, un utilizator al clasei String ( sau al altor clase cu date) se ateapt ca metoda equals() s
aib rezultat true dac dou obiecte diferite (ca adres) conin aceleai date. De aceea, metoda equals() este
rescris n clasele unde se poate defini o relaie de egalitate ntre obiecte. Exemplu de clas pentru o pereche
cheie-valoare, necesar n clasele dicionar:

- 40 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

public class Entry {


private Object key,value;
public Entry ( Object k, Object v ) {
key=k; value = v;
}
public String toString () {
return "("+key.toString()+"="+value.toString()+")";
}
public boolean equals (Object obj) {
Entry e = (Entry)obj;
return key.equals (e.key); // this.getKey().equals (e.getKey());
}
public Object getKey() { return key;}
public Object getValue() { return value;}
public void setKey( Object k) {key=k;}
}
Metoda equals() motenit are argument de tip Object, dar n cadrul clasei Entry ea va fi apelat pentru a
compara dou obiecte de tip Entry; de aceea prima operaie din metoda redefinit este conversia la tipul
Entry pentru a putea folosi membrii acestei clase (variabile i metode). De observat ca se compara doar
cheile n metoda equals(), nu si valorile.
O metod equals() cu argument de tip Entry nu ar reprezenta rescrierea metodei motenite ci o alt metod;
exist metode n colectii i dictionare (indexOf(), contains(), s.a.) care folosesc metoda equals() cu argument
Object i care nu ar lucra corect n cazul metodei equals() cu argument Entry.
Pentru dicionare tabel de dispersie (HashMap) ar trebui redefinit i metoda hashCode(), dar poate fi
utilizat i varianta mostenit (care folosete adresa obiectului drept identificator unic al obiectului).

IE.03.3 Suprascriere de metode n subclase


De multe ori, subclasele nu fac altceva dect s redefineasc una sau cteva metode ale superclasei din care
sunt derivate. Acest tip de redefinire se numete suprascriere (Overriding) pentru a fi deosebit de
redefinirea unei metode cu argumente diferite n aceeai clas, operaie numit suprancrcare (Overloading).
Suprancrcarea este rezolvat de compilatorul Java, dar selectarea unei metode dintre mai multe metode
suprascrise i cu acelai nume se face la execuie (pe baza unui tabel de metode generat de compilator pentru
fiecare clas).
Redefinirea unei metode trebuie s pstreze "amprenta" funciei, deci numele i tipul metodei, numrul i
tipul argumentelor. Dac nu se respect aceste reguli atunci compilatorul consider c subclasa adaug alt
metod la cele motenite i nu suprascrie o metod motenit. La nceput compilatorul Java nu putea verifica
acest fel de eroare de programare i de aceea s-a adugat limbajului o adnotare numit @Override care poate
fi folosit de programatori pentru a arta c se intenioneaz o suprascriere i care permite compilatorului s
verifice c metoda redefinit are acelasi tip i aceleasi argumente ca una motenit.
Nu este neobinuit ca o metod s fie i suprancrcat (n aceeasi clas) i suprascris (n alte clase). Un
exemplu este forma mai nou a metodei de adugare la un vector de tip ArrayList, metod numit add().
In exemplul urmtor se definete alt clas pentru multimi vector, prin extinderea clasei java.util.ArrayList
si suprascrierea a dou metode: adugare la sfrit de vector i adugare ntr-o poziie dat din vector
(inserie n vector).
- 41 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

public class ArraySet extends ArrayList {


@Override
public boolean add (Object obj) {
// adaugare la multime
if ( contains(obj) return false;
// daca exista deja, se iese
super.add(obj);
// se adauga daca nu exista deja
return true;
}
@Override
public void add (int k, Object obj) {
throw new UnsupportedOperationException();
}
}
Pentru a fi compatibil cu alte clase mulime ar trebui ca i clasa ArraySet s implementeze interfaa Set.
Operatiile clasei derivate ArraySet pot fi i ele reutilizate prin extindere i definirea unei clase
SortedArraySet pentru mulimi ordonate realizate ca vectori.
Metodele equals() i toString() pot fi motenite de subclas sau redefinite dac au efect diferit; n exemplul
anterior ele sunt motenite fr modificri. Exemplul urmtor arat cum se poate defini o mulime ca tabel de
dispersie pe baza clasei Hashtable, punnd valori identice cu cheile asociate.
class HSet extends Hashtable {
public boolean add (Object obj) {
return (put (obj,obj)== null);
}
public String toString() {
String s="";
Enumeration e= keys();
while (e.hasMoreElements())
s= s+ e.nextElement()+" ";
return s;
}

Redefinirea metodei toString() s-a fcut pentru a nu se afia i pentru mulimi perechi de valori
(identice) de forma k=v (k = cheie, v= valoare), aa cum se face n clasa dicionar Hashtable.
IE.03.4 Derivarea ca metod de reutilizare
Principala modalitate de specializare a unei clase este redefinirea unor metode din superclas. Prin redefinire
(override) se modific operaiile dintr-o metod, dar nu i modul de utilizare al metodei.
Clasa SortedArray definit anterior refolosete funcionalitatea clasei ArrayList, adic toate operaiile deja
definite acolo pentru vectori extensibili dinamic: adugare, inserie, nlocuire, eliminare de elemente,
adugarea unei colecii la vector, cutarea unei valori date de la nceput sau de la sfrit .a. In mod
asemntor se pot defini prin derivare clase pentru mulimi vector, pentru stive vector .a.
O clas pentru mulimi realizate ca list nlnuit poate fi obinut la fel de simplu, prin extinderea clasei
java.util.LinkedList, fr s ne intereseze detaliile de lucru cu lista, care sunt ncapsulate n clasa de
bibliotec deja definit.

- 42 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Absena unor clase pentru mulimi vector sau mulimi liste sau dicionare din vectori din bibliotecile Java se
explic tocmai prin uurina de a defini astfel de clase prin derivare de ctre programatori.
Avantajele reutilizrii unor clase existente este i mai evident n cazul claselor Swing sau AWT pentru
obiecte de interfa grafic: puini programatori ar putea s scrie singuri clase ca JFrame, JPanel,
JTextField, JTable, JTree s.a. dar obinerea unor subclase ale acestora este destul de simpl.
Pentru a interzice utilizarea unor metode motenite n clasa derivat se suprascriu acele metode cu o nou
definiie n care se arunc excepii de tip NotSupportedOperationException.
O clas derivat nu motenete constructorii superclasei. Dac nu exist nici un constructor definit explicit
ntr-o subclas atunci se genereaz automat un constructor care apeleaz un constructor fr argumente din
superclas (dac exist, altfel este eroare de compilare). Regula anterioar nu se aplic dac exist un
constructor cu argumente n subclas, caz n care apelul (super)constructorului fr argumente trebuie scris
explicit.
In clasa SortedArray nu apare explicit un constructor dar compilatorul Java genereaz automat un
constructor fr argumente care apeleaz constructorul fr argumente din superclasa ArrayList. Dac vrem
s avem i ali constructori n clasa derivat atunci trebuie s definim explicit toi aceti constructori.
Exemplu:
public class SortedArray extends ArrayList {
// constructori
public SortedArray() { super();}
public SortedArray(int n) { super(n);}
// metode
...
Un constructor dintr-o subclasa D poate apela un constructor din superclasa A folosind cuvntul cheie super
i nu prin numele sau. Apelul super() trebuie s fie prima instruciune din constructor. Aceast situaie
apare atunci cnd subclasa are variabile n plus fa de superclas; iniializarea variabilelor motenite se face
prin constructorul superclasei iar iniializarea variabilelor proprii subclasei se face n constructorul subclasei.
Exemplu:
public class SortedArray extends ArrayList {
private Comparator cmp=null; // obiect comparator folosit la sortare
// constructori
public SortedArray() { super();}
public SortedArray (Comparator comp) {
super(); cmp=comp;
}
// metode
public int indexOf (Object obj) {
if (cmp==null)
return Collections.binarySearch (this,obj);
else
return Collections.binarySearch (this,obj,cmp);
}
...
}

- 43 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

IE.03.5 Derivare pentru crearea unor ierarhii de tipuri


Definirea unei noi clase este echivalent cu definirea unui nou tip de date, care poate fi folosit n declararea
unor variabile, argumente sau funcii de tipul respectiv. Prin derivare se creeaz subtipuri de date compatibile
cu tipul din care provin (compatibile la atribuire). Totui nu orice ierarhie de clase este folosit i ca ierarhie
de tipuri; de exemplu, o mulime vector nu este folosit ca un subtip de vector, chiar dac clasa pentru
mulimi este derivat din clasa pentru vectori.
Tipurile superclas i subclas sunt compatibile, n sensul c o variabil (sau un parametru) de un tip A poate
fi nlocuit fr conversie explicit cu o variabil (cu un parametru) de un subtip D, iar trecerea de la o
subclas D la o superclas A se poate face prin conversie explicit (cast). Conversia de tip ntre clase
incompatibile produce excepia ClassCastException.

Conversia de la un subtip la supertip (upcast) se face automat, fr a folosi operatorul de conversie, deoarece
se pot folosi toate metodele din supertip i n subtip. Exemplu:
Vector v= new Vector;
Object obj = v;
Conversia de la un supertip la un subtip (downcast) se face folosind operatorul de forare a tipului (cast),
deoarece subtipul poate avea metode n plus fat de supertip. Exemplu:
Object obj;
Vector v = (Vector) obj;
Conversia de tip se aplic unor variabile referin (sau unor argumente de funcii) i nu unor obiecte. Tipul
variabilei referin este folosit de compilator pentru a verifica dac metodele folosite cu aceast variabil
exist pentru tipul respectiv sau nu. O variabil de tip Object nu poate fi urmat de o metod din clasa
Vector (de ex. size()) chiar dac obiectul referit de variabil este de tip Vector.
Anumite conversii de tip nu pot fi verificate la compilare iar erorile de conversie apar la execuie, ca excepii
ClassCastException. Exemple:
Object x = new String() ;
Object y = new Vector() ;
Vector v = (Vector) x; // exceptie la executie: un String nu poate fi transformat n vector
int sz= y.size();
// eroare la compilare : clasa Object nu are metoda size()
Prin derivare succesiv se pot crea ierarhii de tipuri compatibile. Exemplu:
// vector ordonat
public class SVec extends Vec { .... }
// multime vector
public class VSet extends Vec { ... }
- 44 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

// multime ordonata
public class SVSet extends VSet {... }

De remarcat c dou subtipuri ale unui tip comun A nu sunt compatibile ( de exemplu tipurile SVec i VSet
nu sunt compatibile, dei ambele sunt derivate din tipul Vec). Trecerea ntre cele dou tipuri nu se poate face
prin operatorul de conversie, dar se poate face prin construirea altui obiect.
Uneori subclasele nu adaug nimic superclasei dar motivul extinderii este crearea unei familii de tipuri
compatibile. Un exemplu este familia claselor excepie, derivate direct din clasa Exception sau din subclasa
RuntimeException. Instruciunea throw trebuie s conin un obiect de un tip compatibil cu tipul
Exception; de obicei un subtip ( IOException, NullPointerException s.a.). O subclas a clasei Exception
nu adaug metode noi i conine doar constructori:
public class IOException extends Exception {
public IOException() { super(); }
public IOException(String s) { super(s); } // s= un mesaj suplimentar
}
public class EOFException extends IOException {
public EOFException() { super(); }
public EOFException(String s) { super(s); } // s= un mesaj suplimentar
}
Ierarhia claselor excepie permite tratarea individual a unor excepii de I/E (sfrit de fiier, fiier inexistent,
eroare de cirire/scriere) sau tratarea lor colectiv, folosind tipul mai general IOException:
public static void main (String[] arg) { // o singura actiune ptr toate exceptiile
RandomAccessFile f=null;
try {
f= new RandomAccessFile("date.bin","r");
while ( true)
System.out.println ( f.readInt());
} catch (IOException e) { e.printStackTrace();} // ptr toate exceptiile de I/E
}

Exemplu de tratare individual a diferitelor excepii de I/E:

- 45 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

public static void main (String[] arg) {


RandomAccessFile f=null;
try {
f= new RandomAccessFile("date.bin","r");
while ( true)
System.out.println ( f.readInt());
}
catch (FileNotFoundException e) { System.out.println ("Fisier negasit"); }
catch (EOFException e) { }
catch (IOException e) { System.out.println("Eroare la citire fisier"); }
}

IE.03.6 Polimorfism
O funcie polimorfic este o funcie care are acelasi prototip, dar implementri (definiii) diferite n clase
diferite dintr-o ierarhie de clase (obinute prin suprascrierea metodei).
Metodele equals() i toString() sunt exemple tipice de funcii polimorfice, al cror efect depinde de tipul
obiectului pentru care sunt apelate (altul dect tipul variabilei referin). Exemple:
Object d = new Date(); Object f = new Float (3.14);
String ds = d.toString();
// apel Date.toString()
String fs = f.toString();
// apel Float.toString()
In definirea clasei Entry polimorfismul explic de ce n metoda equals() nu este un apel recursiv; ceea ce se
apeleaz este metoda equals() din clasa de care aparine cheia (diferit de clasa Entry):
public boolean equals (Object obj) {
Entry e = (Entry)obj;
return key.equals (e.key);
}

// equals din clasa Entry


// equals din clasa variabilei key

Asocierea unui apel de metod cu funcia ce trebuie apelat se numeste "legare" (Binding). Legarea se poate
face la compilare (legare timpurie) sau la execuie ("legare trzie" sau "legare dinamic"). Pentru
metodele finale i statice legarea se face la compilare, adic un apel de metod este tradus ntr-o instruciune
de salt care conine adresa funciei apelate. Legarea dinamic are loc n Java pentru orice metod care nu
are atributul final sau static, metod numit polimorfic. In Java majoritatea metodelor sunt polimorfice.
Metodele polimorfice Java corespund funciilor virtuale din C++.
Figura urmtoare ilustreaz mecanismul de realizare a polimorfismului pe traseul :
variabil referin obiect tabel de metode al clasei definiie metod polimorfic n clasa respectiv.

- 46 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Fiecare obiect Java conine, pe lng datele nestatice din clas, un pointer la tabela de metode virtuale
(polimorfice). Compilatorul traduce un apel de metod polimorfic printr-o instruciune de salt la o adres
calculat n funcie de tipul obiectului adresat de variabila referin i de definiia clasei.
Exemplu de secven pentru explicarea mecanismului:
Vec v = new Vec(); v.add(1);
VSet vs = new VSet(); vs.add (1); String s = vs.toString();
Apelul v.add() pleac de la obiectul referit de variabila "v" la tabela metodelor clasei Vec i de acolo ajunge
la corpul metodei add() din clasa Vec. Apelul vs.toString() conduce la metoda toString() din clasa VSet i de
acolo la metoda toString() din superclasa Vec deoarece este o metod motenit i care nu a fost redefinit.
Apelul vs.equals(v) merge n sus pe ierahia de clase i ajunge la definiia din clasa Object, deoarece nici o
subclas a clasei Object nu redefinete metoda equals(), n acest exemplu.
Alegerea automat a variantei potrivite a unei metode polimorfice se poate face succesiv, pe mai multe
niveluri. De exemplu, apelul metodei toString() pentru un obiect colecie alege funcia ce corespunde tipului
de colecie (vector, lista nlntuit, etc); la rndul ei metoda toString() dintr-o clas vector apeleaz metoda
toString() a obiectelor din colecie, n funcie de tipul acestor obiecte (String, Integer, etc.).
Soluia funciilor polimorfice este specific programrii orientate pe obiecte i se bazeaz pe existena unei
ierarhii de clase, care conin metode (nestatice) cu aceeai semnatur, dar cu efecte diferite n clase diferite.
Numai metodele obiectelor pot fi polimorfice, n sensul c selectarea metodei apelate se face n funcie de
tipul obiectului pentru care se apeleaz metoda. O metod static, chiar dac este redefinit n subclase, nu
poate fi selectat astfel, datorit modului de apelare.
Exemplul urmtor este o simplificare a polimorfismului din familiile de clase AWT sau Swing: toate
componentele de interfa grafic AWT sunt derivate din clasa Component i au o metod paint() pentru
- 47 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

afiarea pe ecran a componentei; clasa Container este o component care poate conine mai multe alte
componente. Simplificarea aici se refer la efectul metodei polimorfice paint(), care scrie un mesaj n loc s
deseneze componenta, dar efectul ei depinde de tipul obiectului pentru care se apeleaz.
abstract class Component { public abstract void paint (); }
class Container extends Component {
private Vector v;
public Container(){v= new Vector();}
public void add (Component d){v.add(d);}
public void paint (){
for (int i=0;i<v.size();i++)
((Component)v.get(i)).paint();
}
}
class SquareButton extends Component {
private int x1,y1,x2,y2;
public SquareButton (int a1,int a2,int b1,int b2) { x1=a1;x2=a2;y1=b1;y2=b2; }
public void paint () { System.out.println ("Square ("+x1+","+x2+","+y1+","+y2+")"); }
}
class RoundButton extends Component {
private int xc,yc,rc;
public RoundButton (int x,int y,int r){ xc=x;yc=y;rc=r; }
public void paint () { System.out.println ("Round ("+xc+","+yc+","+rc+")"); }
}
class A {
public static void main (String [] a) {
Container c1 = new Container ();
c1.add (new SquareButton(1,1,5,5)); c1.add (new RoundButton(3,3,6));
Container c2 = new Container();
c2.add (new SquareButton(7,7,9,9)); c2.add (new SquareButton(6,6,8,8));
c2.add(c1); c2.paint ();
}
}

IE.03.7 Delegarea ca alternativ la derivare pentru reutilizare


Reutilizarea funcionalittii unei clase A se poate face n dou moduri:
-

Prin derivare din clasa A, cu motenirea datelor si metodelor publice;

Prin delegare (compunere), cu apelarea metodelor clasei A.

Delegare sau compunere este atunci cnd o clas D conine o variabil (delegat) de un tip A iar o parte din
metodele clasei D apeleaz metode din clasa A prin intermediul variabilei delegat. Exemplu de clas pentru
mulimi care deleag operaii ctre clasa Vector:

- 48 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

class VSet {
private Vector v;
// variabila delegat
public VSet () { v= new Vector(); }
public boolean add (Object obj) {
if ( v.contains(obj))
return false;
// nu s-a modificat multimea
v.addElement (obj);
return true;
}
public String toString () { return v.toString(); }
public int size() { return v.size();}
}
Sursa clasei anterioare poate fi mai mare dac vrem pentru mulimi i alte operaii existente n clasa Vector.
Delegarea creeaz o relaie de tipul D conine un A ( D has an A) i se recomand atunci cnd D folosete
puine metode din A sau cnd se folosesc subtipuri ale tipului A.
Derivarea conduce la un cod mai compact pentru noua clas (nu se mai declar metodele motenite) i
creeaz tipuri compatibile. Relaia dintre clase derivate este o relaie static stabilit la compilare.
Derivarea creeaz o relaie de tipul D este un fel de A (D is a kind of A) i se recomand atunci cnd noua
clas D folosete o mare parte a metodelor din A (i adaug sau modific numai cteva metode) sau atunci
cnd tipul D trebuie s fie compatibil cu tipul A.
Alegerea ntre cele dou tipuri de relaii (is a sau has a) poate fi discutabil i subiectiv: ce este o stiv?
Este un caz particular de vector (list) sau este un obiect care conine un vector (o list) ? Metodele clasei
stiv au nume consacrate i diferite de numele metodelor din clasele ArrayList (Vector) sau LinkedList.
Clasele Java pentru stive sunt: java.util.Stack care este derivat din clasa Vector i clasa mai nou
java.util.ArrayDeque care conine un vector, deci se folosesc ambele metode de reutilizare.
Pentru comparaie urmeaz trei variante de realizare a unei stive ca list nlnuit: prin derivare, prin
delegare i prin derivare plus delegare.
Exemplu de clasa stiv obinut prin derivare din clasa LinkedList :
class StackList extends LinkedList {
public void push (Object obj) {
addFirst (obj);
// super.addFirst(obj);
}
public Object pop () {
return removeFirst();
// super.removeFirst ();
}
public Object peek () {
return peekFirst(); // super.peekFirst();
}
public boolean empty() {
return size()==0; // super.size()
}
// toString() este mostenita si poate fi folosita ptr afisare stiva
}

- 49 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Exemplu de clas stiv obinut prin delegare din clasa LinkedList (pentru stive liste nlnuite):
class StackList {
private LinkedList stack;
// variabila delegat
public StackList (LinkedList list) { stack=list; }
// delegare de operatii catre LinkedList
public Object push (Object obj) {
stack.add (0,obj); return obj;
}
public Object pop () {
Object obj= stack.get(0); stack.remove(obj);
return obj;
}
public Object peek () { return stack.get(0); }
public boolean empty() { return stack.size()==0; }
public String toString() { return stack.toString(); }
}
Delegarea permite mai mult libertate n alegerea obiectului folosit ca delegat; acest obiect este primit prin
constructor i poate avea diferite tipuri compatibile cu variabila delegat. Relaia dintre clasele D i A se
poate modifica dinamic, la execuie. Exemplul urmtor foloseste derivare i delegare pentru o stiv
neprecizat ca implementare la definirea clasei; Clasa StackList extinde pe AbstractList i conine o
variabil (delegat) de tip AbstractList. Stabilirea tipului de colecie folosit ca stiv (ArrayList sau
LinkedList) se face la construirea unui obiect:
StackList st = new StackList ( new ArrayList()); // sau (new LinkedList())
class StackList extends AbstractList {
private AbstractList stack;
// delegat clasa abstracta
public StackList (AbstractList list) { stack=list; } // concretizare delegat
public Object push (Object obj) {
stack.add (0,obj);
return obj;
}
public Object pop () {
Object obj= get(0);
stack.remove(obj);
return obj;
}
public Object peek() {
return get(0);
}
public boolean empty() { return stack.isEmpty(); }
public int size() { return stack.size(); } // abstracta in AbstractList
public Object get (int i) { return stack.get(i); } // abstracta in AbstractList
}

IE.03.8 Motenire multipl prin derivare i delegare


Derivarea i delegarea se pot combina pentru a realiza un fel de motenire multipl: clasa D este derivat din
A i conine o variabil delegat de tip B. Prin motenire se preiau metode din A iar prin apelare se pot folosi
metode din B pentru obiecte de tip D. Exemplu:
- 50 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

class A {
public void f1 () { System.out.println ("A.f1"); }
}
class B {
public void f2 () { System.out.println ("B.f2"); }
}
class D extends A {
private B b = new B ();
public void f2 () { b.f2();} // delegare obiect b pentru operatia f2
}
class X {
public static void main (String arg[]) {
D m = new D();
d.f1();
// metoda mostenita de la A
d.f2();
// metoda din clasa B
}
}
Aceast soluie de motenire multipl este folosit n cteva clase JFC (Swing) de tip model; de exemplu,
clasa DefaultListModel preia prin motenire metode de la superclasa AbstractListModel i deleag unei
variabile interne de tip Vector operaii cu un vector de obiecte. Un model de list este un vector cu
posibiliti de generare evenimente (de apelare asculttori la evenimente ) la modificri operate n vector. In
general o clas model din JFC este o colecie care poate avea asculttori i poate apela metode din
obiectele asculttor (genereaz evenimente semnificative pentru asculttori).
Urmeaz un exemplu mai simplu: o mulime realizat ca vector, care extinde clasa AbstractSet i conine o
variabil de tip ArrayList. Clasa preia de la ArrayList metodele add(), iterator() i size() i de la
AbstractSet alte metode definite n functie de iterator() i size() : contains(),toString(),remove() .a.
public class ArraySet extends AbstractSet {
private ArrayList set;
public ArraySet() {
set = new ArrayList();
}
public boolean add (Object obj) {
if (! contains(obj) )
return set.add(obj);
// delegare pentru operatia de adaugare
return false;
}
public Iterator iterator() {
return set.iterator();
// delegare pentru creare obiect iterator
}
public int size() { return set.size(); } // delegare metoda size()
}

IE.03.9 Clase Java de I/E cu delegare i derivare


Combinarea derivrii cu delegarea a fost folosit la proiectarea claselor din pachetul java.io. Exist dou
familii de clase paralele : familia claselor flux (Stream) cu citire-scriere de octei i familia claselor
Reader-Writer, cu citire-scriere de caractere. Clasele Reader, Writer i celelalte sunt abstracte. Toate
- 51 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

clasele flux de intrare sunt subtipuri ale tipului InputStream (Reader) i toate clasele flux de ieire sunt
subtipuri ale tipului OutputStream (Writer).
Numrul de clase instaniabile de I/E este relativ mare deoarece sunt posibile diverse combinaii ntre
suportul fizic al fluxului de date i facilitile oferite de fluxul respectiv. Dup suportul fizic al fluxului de
date se poate alege ntre: fisiere disc ( FileInputStream, FileOutputStream, FileReader, FileWriter s.a.),
vector de octei sau de caractere (ByteArrayInputStream, ByteArrayOutputStream, CharArrayReader,
CharArrayWriter), buffer de iruri n memorie (StringBufferInputStream, StringBufferOutputStream),
canal pentru comunicarea sincronizat ntre fire de execuie (PipedReader, PipedWriter,
PipedInputStream, PipedOutputStream).
Dup facilitile oferite avem de ales ntre: citire-scriere la nivel de octet sau bloc de octei (metode read(),
write()), citire-scriere pe octei dar cu zon buffer (BufferedInputStream, BufferedReader,
BufferedOutputStream, BufferedWriter), citire-scriere la nivel de linie i pentru numere de diferite tipuri,
fr conversie (DataInputStream, DataOutputStream), citire cu punere napoi n flux a ultimului octet
citit (PushBackInputStream), citire nsoit de numerotare automat a liniilor citite
(LineNumberInputStream).
Combinarea celor 8 clase surs/destinaie cu opiunile de prelucrare asociate transferului de date se face prin
intermediul claselor anvelop , care sunt numite i clase filtru de intrare-ieire. Dac s-ar fi utilizat
derivarea pentru obinerea claselor direct utilizabile atunci ar fi trebuit generate, prin derivare, combinaii ale
celor 8 clase cu cele 4 opiuni, deci 32 de clase (practic, mai puine, deoarece unele opiuni nu au sens pentru
orice flux). Pentru a folosi mai multe opiuni cu acelasi flux ar fi trebuit mai multe niveluri de derivare i
deci ar fi rezultat un numr i mai mare de clase.
Clasele de tip filtru sunt clase intermediare, din care sunt derivate clase care adaug operaii specifice (de
prelucrare): citire de linii de text de lungime variabil, citire-scriere de numere n format intern, scriere
numere cu conversie de format .a. O clas anvelop de I/E conine o variabil de tipul abstract
OutputStream sau InputStream, care va fi nlocuit cu o variabil de un tip flux concret
(FileOutputStream, ...), la construirea unui obiect de un tip flux direct utilizabil.
Clasele filtru de I/E fac parte din categoria clasele decorator, care aplic diverse decoraiuni
(funcionaliti) unor clase existente. Un decorator nu adaug funcii noi clasei decorate dar modific
aciunea unor metode existente prin delegare ctre metode ce provin din obiectul transmis ca argument la
construirea unui obiect din clasa decorator (i care nlocuiete o variabil de tip interfa din clasa decorator).
Clasa FilterInputStream este derivat din InputStream i conine o variabil de tip InputStream:
public class FilterInputStream extends InputStream {
protected InputStream in;
protected FilterInputStream (InputStream in) {
// constructor
this.in=in;
// adresa obiectului "flux"
}
// citirea unui octet
public int read () throws IOException {
return in.read (); // citirea depinde de tipul fluxului
}
... // alte metode
}
Metoda read() este o metod polimorfic, iar selectarea metodei necesare se face n funcie de tipul concret
al variabilei "in" (transmis ca argument constructorului). Metoda read() din FilterInputStream preia
- 52 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

funcionalitatea metodei read() din clasa delegat, sau deleag operaia de citire ctre clasa folosit la
construirea obiectului filtru.
Nu se pot crea obiecte de tipul FilterInputStream deoarece constructorul clasei este protected, dar se pot
crea obiecte din subclase ale clasei FilterInputStream: DataInputStream, BufferedInputStream,
PushbackInputStream, LineNumberInputStream. Cea mai folosit este clasa DataInputStream care
adaug metodelor de citire de octei motenite i metode de citire a tuturor tipurilor primitive de date:
readInt(), readBoolean(), readFloat(), readLine(), etc.
La crearea unui obiect de tipul DataInputStream constructorul primete un argument de tipul InputStream
(sau un tip derivat direct din InputStream sau din FilterInputStream) prin care se specific suportul fizic
al datelor i modul concret de citire din flux. Pentru citire linii dintr-un fiier disc metoda readLine() deleaga
citirea de octei ctre metoda read() din FileInputStream:
FileInputStream fis= new FileInputStream (t.txt);
DataInputStream dis = new DataInputStream (fis);
Decorarea unei clase flux de I/E se poate face repetat; astfel pentru a citi linii dintr-un fiier folosind o zon
tampon i numerotare de linii vom folosi urmtoarea secven de instruciuni:
public static void main (String arg[]) throws IOException {
FileInputStream fis= new FileInputStream (arg[0]);
BufferedInputStream bis = new BufferedInputStream (fis);
LineNumberInputStream lnis= new LineNumberInputStream (bis);
DataInputStream dis = new DataInputStream (lnis);
String linie;
while ( (linie=dis.readLine()) != null)
System.out.println (lnis.getLineNumber()+" "+linie);
}
De obicei nu se mai folosesc variabile intermediare la construirea unui obiect flux. Exemplu de citire linii cu
buffer, dintr-un fiier disc:
public static void main (String arg[ ]) throws IOException {
DataInputStream dis = new DataInputStream (
new BufferedInputStream (new FileInputStream (arg[0])));
String linie;
while ( (linie=dis.readLine()) != null)
System.out.println ( linie);
}

Ordinea n care sunt create obiectele de tip InputStream este important : ultimul obiect trebuie s fie de
tipul DataInputStream, pentru a putea folosi metode ca readLine() i altele. Familia claselor ReaderWriter folosete de asemenea clase care combin derivarea cu delegarea.

- 53 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Capitolul IE.04. Clase abstracte i interfee


Cuvinte cheie
Clas abstract, Metod abstract, Interfa,Funcie callback
Interfeele Comparable,Comparator, Filter
Interfeele Enumerator, Iterator
IE.04.1 Clase abstracte n Java
Generalizarea i abstractizarea n programarea cu obiecte sunt realizate i prin clase abstracte. O superclas
definete un tip mai general dect tipurile definite prin subclasele sale. Uneori superclasa este att de
general nct nu poate preciza nici variabile i nici implementri de metode, dar poate specifica ce operaii
(metode) ar fi necesare pentru toate subclasele sale. In astfel de cazuri superclasa Java este fie o clas
abstract, fie o interfa. Exemplu din JDK: tipul (clasa) Number este o generalizare a tipurilor clas
numerice (Double, Float, Integer, Short, Byte).
public abstract class Number {
public abstract int intValue();
public abstract long longValue();
public abstract float floatValue();
public abstract double doubleValue();
public byte byteValue() { return (byte)intValue(); }
public short shortValue() { return (short)intValue(); }
}
O clas care conine cel puin o metod abstract trebuie declarat ca abstract, dar nu este obligatoriu ca o
clas abstract s conin i metode abstracte. O clas abstract poate conine date i metode neabstracte
utilizabile n subclase dar nu este instaniabil (nu se pot crea obiecte de acest tip clas). Constructorul clasei
abstracte este de obicei protected i nu public.
O metod abstract este doar declarat (ca nume, tip i argumente) dar nu este definit; ea este precedat de
cuvntul cheie abstract. Ea urmeaz a fi definit ntr-o subclas a clasei (interfeei) care o conine. Metodele
abstracte pot s apar numai n interfee i n clasele declarate abstracte.
Scopul unei clase abstracte nu este acela de a genera obiecte utilizabile, ci de a transmite anumite metode
comune pentru toate subclasele derivate din clasa abstract (metode implementate sau neimplementate).
Derivarea dintr-o clas abstract se face folosind cuvntul extends. O clas abstract poate face o
implementare parial, deci poate conine i metode neabstracte i/sau variabile n afara metodelor abstracte.
Pentru a obtine clase instaniabile dintr-o clas abstract trebuie implementate toate metodele abstracte
motenite, respectnd declaraiiile acestora ( ca tip i ca argumente).
O clas abstract constituie o baz de plecare pentru definirea altor clase. Exemplu:
public final class Integer extends Number {
private final int value;
public Integer(int value) { this.value = value; }
// constructor
public Integer(String s) throws NumberFormatException { this.value = parseInt(s, 10); }
public static int parseInt(String s, int radix) throws NumberFormatException {. . . }
public static int parseInt(String s) throws NumberFormatException { return parseInt(s,10);
}
...
}
- 54 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

O clas abstract este de multe ori o implementare parial a unei interfee, pentru a simplifica definirea de
clase instaniabile care s respecte interfaa. In clasa abstract mai multe metode sunt definite n funcie de
cteva metode abstracte (cum ar fi cea care produce un iterator). Clasele concrete care vor extinde clasa
abstracta vor avea de definit numai cteva metode Exemplu:
public interface Collection { // declara metode prezente in orice colectie
int size();
// dimensiune colectie
boolean isEmpty();
// verifica daca colectia este goala

// alte metode
}
public abstract class AbstractCollection implements Collection {
public abstract int size();
// metoda abstracta
public boolean isEmpty ( return size()==0;} // metoda implementata

}
In bibliotecile de clase Java exist cteva clase adaptor, care implementeaz o interfa prin metode cu
definiie nul, unele redefinite n subclase. Ele sunt clase abstracte pentru a nu fi instaniate direct, dar
metodele lor nu sunt abstracte, pentru c nu se tie care din ele sunt efectiv necesare n subclase. Exemplu
de clas adaptor util n definirea de clase asculttor la evenimente generate de tastatur:
public abstract class KeyAdapter implements KeyListener {
public void keyTyped(KeyEvent e) { }
// la apasare+ridicare tasta
public void keyPressed(KeyEvent e) { }
// numai la apasare tasta
public void keyReleased(KeyEvent e) { } // numai la ridicare tasta
}
O subclas (care reacioneaz la evenimente generate de taste) poate redefini numai una din aceste metode,
fr s se preocupe de celalte metode nefolosite de subclas:
class KListener extends KeyAdapter {
public void keyPressed(KeyEvent e) {
char ch = e.getKeyChar();
// caracter generat de tasta apasata
...
// folosire sau afisare caracter ch
}
}

Clasele Reader i Writer din pachetul java.io sunt clase generale de citire sau scriere din/n fluxuri
de caractere care au doar dou metode abstracte: read() sau write() i close(). Ele au un numr mare
de subclase care adaug i alte metode specifice lor: FileReader, FilterReader, BufferedReader,
StringReader, , etc. Fragment din clasa Reader:
public abstract class Reader {
protected Reader();
abstract void close();
int read ( char[] buf);
int read();
void reset ();
.
}

// constrcuctor
// depinde de tipul fluxului
// apeleaza metoda abstracta
// citeste un caracter, apeleaza metoda abstracta
// la fel ptr orice flux
// alte metode neabstracte
- 55 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

IE.04.2 Interfee n Java


O interfa este o colecie de metode abstracte i (eventual) definiii de constante simbolice. Ea poate fi
considerat ca un caz particular de clas abstract, ceea ce i este n C++ (unde nu exist noiunea de
interfa ca n Java). Metodele declarate ntr-o interfa sunt implicit publice i abstracte. Din punct de
vedere sintactic, diferenele dintre clase abstracte i interfee sunt:
- cuvinte cheie diferite la definire: abstract class, interface
- cuvinte diferite la definirea de subclase: extends, implements
Scopul interfeelor este de a defini un tip compatibil simultan cu mai multe tipuri existente, dar fr riscul de
motenire multipl. Se mai spune c o interfa stabilete un contract care trebuie respectat de clasele care
implementeaz interfaa, n sensul c aceste clase se oblig s defineasc toate metodele din interfa (la care
se mai pot aduga i alte metode publice).
Utilizarea unei interfee comune mai multor clase permite unificarea metodelor i modului de utilizare a unor
clase cu acelai rol, dar i scrierea unor metode general aplicabile oricrei clase care respect interfaa
comun. Exemplu de interfa din JDK:
public interface CharSequence {
// orice secventa de caractere
char charAt (int i);
// caracterul din pozitia i a secventei
int length();
// lungimea secventei
String toString();
// sir echivalent secventei
CharSequence subSequence (int i, int j); // extrage o subsecventa
}
Aceast interfa este respectat ( implementat ) de clase ca String, StringBuffer, StringBuilder,
Segment, CharBuffer. Exemplu:
public final class String implements CharSequence, Serializable {
// date
private final char value[];
private final int count;
// constructori . . .
// metode
public int length() { return count; }
public String toString() { return this; }
...
}
Prin definirea unei interfee sau clase abstracte se creeaz un tip comun mai multor clase deoarece o variabil
(sau un argument) de un tip interfa poate fi nlocuit fr conversie explicit cu o variabil de orice subtip,
deci cu referine la obiecte care implementeaz interfaa sau care extind clasa abstract.
Nu pot fi create obiecte de un tip interfa sau clas abstract, dar se pot declara variabile, argumente formale
i funcii de un tip interfa sau clas abstract. Astfel de variabile vor fi nlocuite (prin atribuire sau prin
argumente efective) cu variabile de un tip clas care implementeaz interfaa respectiv. Exemplu care
folosete interfaa Collection pentrua compara la egalitate dou colecii de obiecte:

- 56 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

public static boolean equals (Collection a, Collection b) {


if (a.size() != b.size()) return false;
// size() este metoda din interfaa Collection
returns a.containsAll(b);
// containsAll() este metoda din interfaa Collection
}
O interfa poate extinde o alt interfa (extends) cu noi metode abstracte. Ca exemplu, interfaa List
extinde interfaa Collection cu metode de acces direct, prin indici, la elementele coleciei:
public interface List extends Collection {
void add ( int i, Object x);
// introduce pe x in pozitia i din colectie
Object get (int i);
// valoare element din pozitia i
Object set (int i, Object x);
// nlocuire element din pozitia i cu x
Object remove (int i);
// elimina si returneaza elementul din pozitia i
...
}

IE.04.3 Comparaie ntre interfee i clase abstracte


Diferena major este aceea c o interfa nu poate conine date i c o clas poate implementa simultan mai
multe interfee dar nu poate extinde dect o singur clas abstract (sau neabstract).
Clasele care implementeaz o aceeai interfa pot fi foarte diverse i nu formeaz o ierarhie de tipuri
compatibile. Un exemplu sunt clasele cu obiecte comparabile, care toate implementeaz interfaa
Comparable: String, Date, Integer, BigDecimal, .a.
O clas poate simultan s extind o clas (alta dect clasa Object, implicit extins) i s implementeze una
sau mai multe interfee. Altfel spus, o clas poate moteni date i/sau metode de la o singur clas, dar poate
moteni mai multe tipuri (poate respecta simultan mai multe interfee). De exemplu, mai multe clase
predefinite SDK, cu date, implementeaz simultan interfeele Comparable (obiectele lor pot fi comparate la
mai mic/ mai mare), Clonable (obiectele lor pot fi copiate), Serializable (obiectele lor pot fi salvate sau
serializate n fiiere disc sau pe alt mediu extern). Exemple:
public class String implements Comparable, Serializable { ...}
public class Date implements Serializable, Clonable, Comparable { ...}
O interfa fr nici o metod poate fi folosit pentru a permite verificarea utilizrii unor metode numai n
anumite clase, n faza de execuie. Un exemplu tipic este interfaa Clonable, definit astfel:
public interface Clonable { }

Clasa Object conine metoda clone(), folosit numai de clasele care declar c implementeaz interfaa
Clonable. Metoda neabstract clone() este motenit automat de toate clasele Java, dar este aplicabil numai
pentru o parte din clase. Pentru a semnala utilizarea greit a metodei clone() pentru obiecte ne-clonabile, se
produce o excepie de tip CloneNotSupportedException atunci cnd ea este apelat pentru obiecte din clase
care nu ader la interfaa Clonable.
O utilizare asemntoare o are interfaa Serializable, pentru a distinge clasele ale cror obiecte sunt
serializabile (care conin metode de salvare i de restaurare n / din fiiere) de clasele ale cror obiecte nu pot
fi serializate ( fr obiecte "persistente"). Practic, toate clasele cu date sunt serializabile.
Interfee ca Serializable si Clonable se numesc interfee de "marcare" a unui grup de clase (tagging
interfaces), pentru a permite anumite verificri.
- 57 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

O interfa care stabileste un tip comun poate fi att de general nct s nu conin nici o metod. Un
exemplu este interfaa EventListener (pachetul "java.util"), care stabilete tipul asculttor la evenimente,
dar metodele de tratare a evenimentului nu pot fi precizate nici ca prototip, deoarece depind de tipul
evenimentului. Interfaa este extins de alte interfee, specifice anumitor asculttori (pentru anumite
evenimente):
public interface ActionListener extends EventListener {
public void actionPerformed(ActionEvent e);
}
public interface ItemListener extends EventListener {
public void itemStateChanged(ItemEvent e);
}
O clas cu toate metodele abstracte i fr date poate fi definit fie ca o clas abstract, fie ca o interfa. In
Java 1 clasa abstract java.util.Dictionary coninea metode obligatorii pentru orice obiect dicionar, dar a
cror definire depinde de implementare. In Java 2 a fost introdus, ca alternativ preferabil, interfaa Map
care conine metodele din clasa Dictionary i alte metode abstracte.
Interfeele sunt preferabile n general claselor abstracte, pentru c ofer mai mult libertate subclaselor.
Avantajul soluiei interfa n raport cu o clas abstract este evident atunci cnd definim un dicionar
realizat ca un vector de perechi cheie-valoare: o clas derivat din clasa ArrayMap ar putea moteni metode
utile de la superclas, dar nu ar putea extinde i clasa abstract Dictionary. Exemplu:
public class ArrayMap extends ArrayMap implements Map { ... }
Interfeele si clasele abstracte nu trebuie opuse, iar uneori sunt folosite mpreun ntr-un framework cum este
cel al claselor colecie sau cel al claselor Swing (JFC): interfaa definete metodele ce ar trebui s existe mai
multe clase, iar clasa abstract este o implementare parial a interfetei, pentru a facilita definirea de noi clase
prin extinderea clasei abstracte. In felul acesta se obine o familie de clase deschis pentru extinderi
ulterioare cu clase compatibile, care nu trebuie definite ns de la zero. Un exemplu este interfaa Map i
clasa AbstractMap care permit definirea rapid de noi clase pentru dicionare (altele dect HashMap i
TreeMap), compatibile cu interfaa Map dar care beneficiaz de metode motenite de la clasa abstract.
Exemplu de dicionar realizat ca vector:
class ArrayMap extends AbstractMap {
// dictionar vector de perechi
private ArrayList entries ;
// perechi cheie-valoare
public ArrayMap (int n) {entries = new ArrayList(n); }
public Object put ( Object key, Object value) {
for (SimpleEntry e: entries)
// clasa SimpleEntry inclusa n AbstractMap
if (e.getKey().equals(key)){
// daca exista cheia in dictionar
Object v = e.getValue();
// pentru rezultatul metodei
entries.remove(e);
// inlocuire valoare prin eliminare
entries.add (new SimpleEntry(key,value)); // si adaugare
return v;
}
entries.add (new SimpleEntry(key,value)); // daca nu exista cheia in dictionar
return null;
}

- 58 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

public Set entrySet () {


// abstracta in AbstractMap
LinkedHashSet set = new LinkedHashSet();
for (int i=0;i<keys.size();i++)
set.add(new SimpleEntry(keys.get(i), values.get(i)) );
return set;
}
}

In general se recomand programarea la nivel de interfa i nu la nivel de clas particular, pentru a avea
programe mai generale i mai uor de modificat. Ideea este de folosi variabile de un tip ct mai general, care
se pot referi la obiecte de orice subtip compatibil cu acesta. Mai mult, modificarea tipului obiectului referit se
poate face la execuie. Un exemplu este o variabil mulime sau dicionar care va definit de tipul Set sau
Map, pentru ca ulterior (la atribuirea unei referine) s se poata preciza sau modifica tipul concret de
mulime sau de dicionar (HashSet, TreeSet, HashMap, TreeMap, etc.) Exemplu:
Map d = new HashMap(); // se poate nlocui cu:

d= new ArrayMap();

IE.04.4 Interfee Java pentru compararea de obiecte


In unele operaii cu vectori de obiecte (sortare, cutare binar, determinare maxim sau minim .a.) este
necesar compararea de obiecte (de acelai tip). Funcia de comparare depinde de tipul obiectelor comparate,
dar poate fi o funcie polimorfic, cu acelai nume, tip i argumente dar cu definiii diferite. In plus, dou
obiecte pot fi comparate dup mai multe criterii (criteriile sunt variabile sau combinaii de variabile din
aceste obiecte).
In Java, metoda compareTo() este destinat comparaiei dupa criteriul cel mai natural (cel mai frecvent iar
uneori i unicul criteriu). Pot fi comparate cu metoda compareTo() numai clasele care implementeaz
interfaa Comparable i deci care definesc metoda abstract compareTo():
public interface Comparable {
int compareTo (Object obj);
}

// rezultat <0 sau = 0 sau >0

Clasele care declar implementarea acestei interfee trebuie s conin o definiie pentru metoda
compareTo(), cu argument de tip Object. Exemple de clase Java cu obiecte comparabile : Integer, Float,
String, Date, BigDecimal .a. Exemplu:
public class Byte extends Number implements Comparable {
private byte value;
. . . // constructori, metode specifice
public int compareTo( Object obj) {
// compara doua obiecte Byte
return this.value- ((Byte) obj).value ;
}
}
Metoda compareTo() se poate aplica numai unor obiecte de tip Comparable i de aceea se face o conversie
de la tipul general Object la subtipul Comparable. Exemplu:
- 59 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

// determinare maxim dintr-un vector de obiecte oarecare


public static Object max (Object [ ] a) {
Comparable maxim = (Comparable) a[0];
for (int i=0;i<a.length;i++)
if ( maxim.compareTo(a[i]) < 0)
// daca maxim < a[i]
maxim=(Comparable)a[i];
return maxim;
}
Mai multe metode statice din clasele Arrays si Collections (sort(),max(),binarySearch()), care au ca
argument doar vectorul sau colecia, folosesc implicit metoda compareTo().
Interfaa Comparator a fost introdus pentru comparare de obiecte dup alte criterii dect cel natural; ea
conine n principal metoda compare(), cu dou argumente:
public interface Comparator {
int compare (Object t1, Object t2);
}

// implicit abstracta, ne-statica !

Functia Arrays.sort() are i o form cu dou argumente; al doilea argument este de tipul Comparator i
precizeaz funcia de comparare (alta dect compareTo()). Funcia care determin maximul dintr-un vector
de obiecte poate fi scris i astfel:
public static Object max (Object a[ ], Comparator c) {
Object maxim = a[0];
for (int k=1; k<a.length;k++)
if ( c.compare (maxim, a[k]) < 0) // c este un obiect comparator
maxim = a[k];
return maxim;
}
Funcia max() cu dou argumente este mai general i poate fi folosit pentru a ordona un acelai vector
dup diferite criterii (dup diverse proprieti). De exemplu, pentru ordonarea unui vector de iruri dup
lungimea irurilor, vom defini urmtoarea clas comparator:
class LengthComparator implements Comparator {
public int compare (Object t1, Object t2) {
return ((String)t1).length() - ((String)t2).length();
}
}
. . . // ordonare dupa lungime
String * + a = ,patru,trei,unu-;
Arrays.sort( a, new LengthComparator());
Funcia compare() din interfaa Comparator poart numele de funcie callback, deoarece este apelat de
metode existente (sort(), max() din clasele Arrays sau Collections) dar trebuie furnizat de aplicaia care
folosete una din aceste metode. La scrierea funciei de sortare nu se cunotea exact definiia funciei de
comparare (pentru c pot fi folosite diverse funcii de comparare), dar s-a putut preciza prototipul funciei de
comparare, ca metod abstract dintr-o interfa. Putem deci s scriem o funcie care apeleaz funcii nc
nedefinite, dar care respect toate un prototip (tip rezultat, tip i numr de argumente).
- 60 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Tehnica callback este folosit la scrierea unor clase de bibliotec, ale cror funcii apeleaz funcii din
programele de aplicaii, scrise ulterior de utilizatorii pachetului. Ideea general este c o parte din algoritmul
implementat de clasa de bibliotec depinde de specificul aplicaiei care foloseste acest algoritm. Un algoritm
de sortare foloseste o funcie de comparare, dar funcia de comparare face parte din aplicaie, pentru c ea
compar date din aplicaie. Situaia poate fi schematizat astfel: o funcie A (main(), de ex.) apeleaz o
funcie B (sort(), de ex.), iar B apeleaz o funcie X (compare()) dintr-un grup de funcii posibile. Adresa
funciei X este primit de B de la funcia A. De fiecare dat cnd A apeleaz pe B i transmite i adresa
funciei X, care va fi apelat napoi de B.

Aplicaie

Biblioteci JDK

main

sort

compare
IE.04.5 Interfee Java pentru enumerare
Interfaa mai veche java.util.Enumeration conine dou metode comune oricrei clase cu rol de enumerare
a elementelor unei colecii de obiecte:
public interface Enumeration {
boolean hasMoreElements();
Object nextElement();
}

// daca mai sunt elemente in colectie


// elementul urmator din colectie

Enumerarea unor obiecte poate fi privit ca o alternativ la crearea unui vector cu obiectele respective, n
vederea prelucrrii succesive a unui grup de obiecte. Dintre clasele care implementeaz aceast interfa,
sunt clasele enumerator pe vector i enumerator pe un tabel de dispersie Hashtable. Ulterior s-au adugat
metode din aceast interfa i clasei StringTokenizer, care face o enumerare a cuvintelor dintr-un text:
public class StringTokenizer implements Enumeration {
...
public boolean hasMoreElements() { return hasMoreTokens(); }
public Object nextElement() { return nextToken(); }
}
Exemplu de metod care calculeaz de cte ori apare un obiect ntr-o colecie de obiecte folosind numai
enumeratorul coleciei:
public static int count (Enumeration enum, Object obj) {
int m=0;
while (enum.hasMoreElements() )
if (enum.nextElement().equals(obj) )
m++;
return m;
}

- 61 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

In exemplul anterior, metoda elements() din clasa Vector are ca rezultat un obiect enumerator pe vector,
de tipul Enumeration. Exemplu de posibil implementare a metodei elements() :
public Enumeration elements() { return new VectorEnumerator (this);}
// definirea clasei iterator pe vector
class VectorEnumerator implements Enumeration {
private Vector v;
private int crt = 0;
// indice element curent din enumerare
public VectorEnumerator (Vector v) { this.v=v; }
public boolean hasMoreElements() { return crt < v.size(); }
public Object nextElement() { return v.elementAt (crt++); }
}
De observat c interfaa Enumeration nu are metode pentru modificarea obiectelor enumerate, care ar putea
veni n conflict cu metodele clasei colecie care adaug sau elimin elemente din colecie.
Incepnd din Java 2 s-a introdus interfaa java.util.Iterator ca alternativ la interfaa Enumeration:
public interface Iterator {
boolean hasNext();
Object next();
void remove();
}

// daca exista un element urmator in colectie


// extrage element curent si avans la urmtorul
// elimina element curent din colectie (optional)

Metoda iterator() din clasele colecie are ca rezultat un obiect Iterator i nlocuiete metoda elements() care
producea un obiect de tip Enumeration. Exemplu de clasa iterator pentru liste simplu nlnuite:
public class SimpleList extends AbstractList {
private Node head;
// inceput lista
private int n;
// nr de noduri in lista
public SimpleList () {
// constructor
head= new Node(null);
// santinela
}
public int size() { return n; }
public Iterator iterator () { return new SListIterator(); }
...
}
class SListIterator implements Iterator {
private Node pos=head.next;
public boolean hasNext () { return pos != null; }
public Object next() {
Object obj =pos.val; pos=pos.next;
return obj;
}
public void remove () { throw new UnsupportedOperationException(); }
}

Exemplu de utilizare a unui obiect iterator:

- 62 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

public static Object max (Collection c) {


Iterator it = c.iterator();
Comparable m=(Comparable) (it.next());
while (it.hasNext()) {
Comparable e=(Comparable) (it.next());
if (e.compareTo (m) > 0)
m=e;
}
return m;
}
Alt form de utilizare a unui iterator, ntr-o instruciune for:
for (Iterator it=c.iterator; it.hasNext(); ) {
Comparable e=(Comparable) (it.next());
...
}
Incepnd din Java 5 este posibil o utilizare implicit a unui obiect iterator, fr ca acesta s fie creat explicit.
Exemplu de concatenare iruri dintr-o colecie:
public static String concat (Collection a) {
String r="";
for (Object s: a )
// repeta pentru valori ale lui s n colectia a
r += s+" ";
return r;
}
Instruciunea urmtoare (for each)
for (Integer i: a) System.out.println(i);

// repeta pentru fiecare valoare i din a

este echivalent cu instruciunea


for (Iterator i = a.iterator(); i.hasNext();)
System.out.print ln(i.next());
Forma nou de iterator poate fi folosit pentru enumerarea obiectelor din orice clas care implementeaz
interfaa Iterable:
public interface Iterable {
Iterator iterator();
}

IE.04.6 Interfee Java pentru filtrare


Un filtru este un obiect care permite selectarea (sau respingerea) anumitor obiecte dintr-o colecie sau dintrun vector. Un filtru poate conine o singur metod cu rezultat boolean, care s spun dac obiectul primit ca
argument este acceptat sau respins de filtru. In bibliotecile Java filtrele se folosesc n clasa File pentru listare
selectiv de fiiere dintr-un director, dar pot fi folosite i n alte situaii.

- 63 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Clasa File din pachetul java.io poate genera obiecte ce corespund unor fiiere sau directoare. Ea este
destinat operaiilor de listare sau prelucrare a fiierelor dintr-un director i nu conine functii de citirescriere din/n fiiere. Cel mai folosit constructor din clasa File primete un argument de tip String ce
reprezint numele unui fiier de date sau unui fiier director. Cea mai folosit metod a clasei File este
metoda list() care produce un vector de obiecte String, cu numele fiierelor din directorul specificat la
construirea obiectului File. Exemplu de folosire a unui obiect File pentru afiarea coninutului directorului
curent:
public static void main (String arg[]) throws IOException {
String dir =".";
// "numele" directorului curent
File d =new File(dir);
// java.io.File d = new java.io.File(dir);
String [ ] files = d.list();
// vector cu fisierele din directorul curent
System.out.println ("Directory of "+ d.getAbsolutePath());
for (int i=0; i< files.length;i++)
System.out.println (files[i]);
}
Metoda listFiles() produce un vector de obiecte File ce corespund fiierelor din directorul pentru care se
apeleaz metoda. Metodele list()i listFiles() au i o variant cu un argument de un tip interfa ce specific
filtrul aplicat fisierelor, pentru extragere selectiv de fiiere din director:
- metoda list() cu argument de tip FilenameFilter
- metoda listFiles() cu argument de tip FileFilter sau FilenameFilter.
Interfeele FileFilter i FilenameFilter conin o singur metod accept(), care va fi apelat de list() sau
listFiles() pentru fiecare fiier din director i care spune dac acel fiier este sau nu acceptat n vectorul creat
de funcie.
public interface FilenameFilter {
// prezenta din jdk 1.0
boolean accept (File path, String filename);
// path=director(cale)
}
public interface FileFilter {
// prezenta din jdk 1.2
boolean accept (File path);
// path=nume complet fisier (cu cale)
}
Utilizatorul are sarcina de a defini o clas care implementeaz una din aceste interfee i de a transmite o
referin la un obiect al acestei clase fie metodei list() fie metodei listFiles(). Exemplu de filtru dup tipul
(extensia numelui) fisierelor:
class FileTypeFilter implements FileFilter {
// clasa pentru obiecte filtru
String ext;
// extensie nume fisier
public FileTypeFilter (String ext) { this.ext = ext; }
public boolean accept (File f) {
String fname = f.getName();
// nume fisier
return fname. endsWith("."+ext) ;
}
}
// utilizare
File d =new File(".");
// din directorul curent
File [ ] files = d.listFiles(new FileTypeFilter("java"));
- 64 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Acelai filtru (dup extensie fiier) n varianta cu interfaa FilenameFilter:


class DirFilter implements FilenameFilter {
String ftype;
public DirFilter (String ft) { ftype=ft;}
public boolean accept (File dir, String name) {
return name. endsWith("."+ftype) ;
}
}

// name= nume fisier


// daca numele contine tipul ca subsir

Funcia accept() din interfeele filtru este tot o funcie callback, apelat de metodele list() i listFiles() din
clasa de bibliotec File, dar definit ca parte din aplicaie pentru criteriul de filtrare dorit.
Exemplu de definire a unei interfee de tip filtru pentru orice fel de obiecte, utilizat pentru filtrarea unui
vector i creare a unui alt vector cu elementele selectate de filtru:
public interface Filter {
boolean accept (Object s);
}
public static Vector select (Vector v, Filter f) {
Vector r = new Vector();
Enumeration e = v.elements();
while (e.hasMoreElements()) {
Object elem = e.nextElement();
if (f.accept(elem))
r.add( elem);
}
return r;
}

Funcia select() poate primi ca argument i un obiect enumerator dar nu poate crea o enumerare cu rezultatele
filtrrii.

- 65 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Capitolul IE.05. Tehnici de programare orientat obiect n Java


Cuvinte cheie
Excepii, Reflecie,
Clase incluse, Clase interioare, Clase anonime
Fire de execuie, Sincronizare, Seciuni critice
IE.05.1 Excepii n Java
O excepie program este o situaie anormal aprut n execuie i care poate avea cauze hardware sau
software. Excepiile pot fi privite ca evenimente previzibile, ce pot aprea n anumite puncte din program i
care afecteaz continuarea programului, prin abatere de la cursul normal.
Existenta excepiilor este un mare avantaj al limbajului Java, pentru c permite semnalarea la execuie a unor
erori uzuale, prin mesaje clare asupra cauzei i locului unde s-a produs eroarea, evitnd efectele
imprevizibile ale acestor erori (ca n cazul limbajului C, de exemplu).
Excepiile Java sunt de dou categorii:
- Excepii care nu necesit intervenia programatorului (numite Runtime Exceptions), dar care pot fi
interceptate i tratate de ctre programator. Dac nu sunt tratate, aceste excepii produc afiarea unui mesaj
referitor la tipul excepiei i terminarea forat a programului. Aceste excepii corespund unor erori grave de
programare, care nu permit continuarea executiei i care apar frecvent n programe, cum ar fi: erori de
indexare a elementelor unui vector (indice n afara limitelor), utilizarea unei variabile referin ce contine
null pentru referire la date sau la metode publice, mprire prin zero, conversie prin operatorul cast ntre
tipuri incompatibile, .a.
- Excepii care trebuie fie tratate, fie "aruncate" mai departe, pentru c altfel compilatorul marcheaz cu
eroare functia n care poate apare o astfel de eroare (Checked Exceptions: excepii a cror tratare este
verificat de compilator).Aceste excepii corespund unor situaii speciale care apar la utilizarea unui program
(fiiere negasite, erori la operaii de citire-scriere, date incorecte), dar nu produc neaprat terminarea
programului. Urmtorul program poate produce excepii, dac este folosit greit:
class Exc {
public static void main (String arg[ ]) {
System.out.println ( Integer.parseInt(arg[0]));
}
}

// afiseaza primul argument

O comand pentru execuia programului anterior produce excepia ArrayIndexOutOfBoundException,


dac nu s-au transmis argumente prin linia de comand: vectorul "arg" are lungime zero i deci nu exist
arg[0] (nu exist indice zero).
O linie de comand de forma "java Exc 1,2" (argumentul arg[0] nu este un ir corect pentru un numr ntreg)
produce o excepie NumberFormatException, excepie generat n functia parseInt(). Ambele excepii
mentionate sunt excepii Runtime.
Excepiile generate de operaiile de intrare-ieire (inclusiv la consol) trebuie fie aruncate, fie tratate pentru
c suntem obligai de ctre compilatorul Java. Compilatorul tie care metode pot genera excepii i cere ca
funciile care apeleaz aceste metode s arunce mai departe sau s trateze excepiile posibile. Exemplu:
- 66 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

public static void main (String arg[ ]) throws Exception {


int ch= System.in.read ( );
// citeste un caracter de la tastatura
System.out.println ((char) ch);
// afisare caracter citit
}
Absena clauzei throws din functia main este semnalat ca eroare de compilator, pentru a obliga
programatorul s ia n considerare excepia ce poate apare la funcia de citire read(), datorit citirii
caracterului EOF (sfrsit de fiier) sau unei erori la citire.
O metod care apeleaz o funcie (metod sau constructor) ce arunc excepii verificate trebuie fie s
semnaleze mai departe posibilitatea apariiei acestei excepii (prin clauza throws), fie s trateze excepia
printr-un bloc try-catch care s includ apelul metodei. Exemplu cu aruncarea excepiilor:
// deschidere fisier nou
public static RandomAccessFile rewrite ( String fname ) throws IOException {
RandomAccessFile f=new RandomAccessFile (fname,"rw"); // arunca exceptie
return f;
}
public static void main (String[] arg) throws IOException {
RandomAccessFile f= rewrite ("numere.bin "); // arunca exceptie
for (int i=0;i<20;i++)
f.writeInt (i);
// arunca exceptie
f.close();
// arunca exceptie
}
Tratarea excepiilor necesit folosirea unui bloc try-catch pentru delimitarea seciunii de cod pentru care
excepiile posibile sunt redirectate ctre secvene scrise de utilizator pentru tratarea excepiilor produse.
Sintaxa unui bloc try-catch este : try { bloc1 } catch ( Exception e) { bloc2 }
unde:
bloc1 este un bloc de instruciuni n care se pot produce excepii la execuie
bloc2 este un bloc de instruciuni care trateaz excepiile produse n bloc1
Exception este tipul excepiei tratate (i tipul variabilei e)
Exemplul anterior cu tratarea simpl a tuturor excepiilor de I/E, indiferent cine le-a produs:
public static void main (String[] arg) {
RandomAccessFile f=null;
try {
f= new RandomAccessFile("numere.bin","rw");
for (int i=0;i<20;i++)
f.writeInt (i);
f.close();
} catch (IOException e) { e.printStackTrace();}
}
Dei blocul de instruciuni prin cuvntul catch poate lipsi, nu se recomand aceast tratare prin ignorare a
excepiilor care mpiedic aparitia unui mesaj de avertizare la producerea excepiei; este preferabil
aruncarea unei exceptii cu throws pentru c apare mesaj despre tipul de excepie. Exemplu:
- 67 -

INFORMATIC*I*

public static void main (String arg[]) {


Object ref=null;
try {int h = ref.hashCode(); }
catch (NullPointerException e) { }
}

IE. TEHNICI AVANSATE DE PROGRAMARE

// exceptie daca ref==null


// interzice afisare mesaj (nerecomandat!)

Tratarea excepiilor se reduce de multe ori la scrierea unui mesaj pe ecran sau ntr-un fiier, fie cu metoda
printStackTrace() din clasa Exception, fie cu o metod de scriere dintr-o clasa de tip Writer sau Printer.
Prima soluie are avantajul c prezint toat secvena de apeluri de funcii care a condus la producerea
excepiei i este folosi n depanarea programelor.
Exist i situaii cnd excepia trebuie tratat i altfel dect prin afiarea unui mesaj; exemplul urmtor arat
cum putem verifica dac un ir de caractere reprezint un numr corect (n orice format permis pentru
numere nentregi), fr a examina fiecare caracter n parte:
public static boolean isNumber (String s){
try { Double.parseDouble(s);
} catch(NumberFormatException ex) {return false;}
return true;
}
Este posibil i aruncarea unor excepii puin probabile (excepia de citire, de ex.) combinat cu tratarea altor
excepii (de exemplu excepia de sfrit de fiier).
Producerea unor excepii poate fi prevenit prin verificri efectuate de programator. Exemplu:
public static void main (String arg[ ]) {
if (arg.length == 0 ) { System.out.println ("No Argument"); System.exit(-1); }
System.out.println ( arg[0]);
// afiseaza primul argument
}

Uneori este preferabil verificarea prin program (ca n cazul unor conversii de tip nepermise), dar alteori este
preferabil tratarea excepiei (ca n cazul detectrii existenei unui fiier nainte de a fi deschis, sau a utilizrii
unor variabile referin ce pot fi nule).
In cazul programelor cu fiiere pot s apar mai multe tipuri de excepii (subtipuri de IOException) i ne
intereseaz ce tip particular de excepie s-a produs (deci cauza exact a excepiei). Avem dou soluii
posibile de interceptare a acestor excepii: cu mai multe blocuri try-catch pe fiecare instruciune sau cu un
singur bloc try care are mai multe clauze catch. Exemplu cu mai multe blocuri try:
public static void main (String[] arg) {
RandomAccessFile f=null;
try { f= new RandomAccessFile("numere.bin","r"); } // citire fisier
catch (IOException e) { System.out.println ("Eroare la deschidere" + .getMessage()); }
try {
while (true) System.out.println ( f.readInt());
}
catch (IOException e) { e.printStackTrace(); }
}

- 68 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

In acest caz (la citirea din fiiere binare de numere) excepia apare fie la sfrit de fiier (dar fr erori), fie n
cazul unei erori de citire din fiier; de aceea este preferabil un bloc try cu dou clauze catch:
public static void main (String[] arg) {
RandomAccessFile f=null;
try { f= new RandomAccessFile("numere.bin","r"); }
catch (IOException e) { System.out.println ("Eroare la deschidere" + e.getMessage()); }
try {
while (true)
System.out.println ( f.readInt());
}
catch (EOFException e) { System.out.println ("Sfrsit de fisier"); }
catch (IOException e) { System.out.println ("Eroare la citire din fisier"); }
}

IE.05.2 Reflecie n Java


Pentru fiecare clas ncrcat n maina virtual Java este creat automat cte un obiect de tip Class, cu
informaii despre clasa asociat (metadate). Obiectele Class sunt create automat i pentru interfee, clase
abstracte i vectori intrinseci Java.
Prin reflecie (reflection) se nelege obinerea de informaii despre o clas sau despre un obiect n faza de
execuie (este reflectat starea mainii virtuale). In plus, se pot crea i modifica dinamic obiecte n faza de
execuie. Reflecia este asigurat n principal de clasa numit Class, dar i de alte clase din pachetul
java.lang.reflect: Constructor, Method, Field, s.a.
O variabil de tip Class conine o referin la un obiect descriptor de clas; ea poate fi iniializat n mai
multe feluri:
- Folosind cuvntul cheie class ca i cum ar fi un membru public i static al clasei sau tipului primitiv :
Class cF = Float.class, cS = Stiva.class,
cf = float.class, cv =void.class,
cN= Number.class, cI=Iterator.class ;

// clase predefinite sau proprii


// tipuri primitive
// clase abstracte si interfete

- Folosind metoda static forName() cu argument nume de clas (ca ir de caractere):


Class cF = Class.forName(java.util.Float), cf = Class.forName (float);
- Folosind metoda getClass() pentru o variabil de orice tip clas (metoda getClass() este motenit de la
clasa Object, deci exist n orice clas):
Float f = new Float (3.14);

Class cF = f.getClass();

Clasa Class conine metode care au ca rezultat numele clasei, tipul clasei (clas sau interfa sau vector),
tipul superclasei, clasa extern, interfee implementate, tipul obiectelor declarate n clas, numele cmpurilor
(variabilelor clasei), numele metodelor clasei, formele funciilor constructor s.a.
Metoda getName() are ca rezultat un ir ce reprezint numele clasei al crui tip este coninut ntr-un obiect
Class. Exemplul urmtor arat cum se poate afia tipul real al unui obiect primit ca argument de tipul generic
Object:

- 69 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

void printClassName (Object obj) {


System.out.println ( obj.getClass().getName());
}
Crearea de obiecte de un tip aflat n cursul execuiei dar necunoscut la compilare (cu condiia ca tipul
respectiv s fi fost definit printr-o clas, iar fiierul de tip class s fie accesibil la execuie) se poate face
simplu dac n clas exist numai un constructor fr argumente . Exemplu:
public static Object getInstance (String clsname) throws Exception {
Class cl = Class.forName(clsname); // clsname = nume clasa (complet)
return cl.newInstance();
}
Deoarece putem obine toti constructorii unei clase, cunoscnd tipul argumentelor, se pot fabrica obiecte si
apelnd constructori cu argumente. Exemplu:
public static Object newObject (Constructor constructor, Object [ ] args) {
Object obj = null;
try {
obj = constructor.newInstance(args);
} catch (Exception e) { System.out.println(e); }
return obj;
}
// utilizare
Float x;
Class cls = Float.class;
Class[] argsCls = new Class[ ] {float.class};
// tip argumente constructor
Constructor constr = cls.getConstructor(argsCls);
// obtinere constructor
Object[] args = new Object[ ] { new Float(3.5) };
// argument efectiv ptr instantiere
x =(Float) newObject (constr,args);
Prin reflecie un asamblor de componente JavaBeans dintr-un mediu vizual poate s determine proprietile
si metodele proprii unor obiecte, s modifice proprietile acestor obiecte i s genereze apeluri de metode
ntre obiecte. In rezumat, reflecia permite operaii cu clase i cu obiecte necunoscute la scrierea
programului, dar care pot fi determinate dinamic, n cursul execuiei.
Dac se apeleaz metode polimorfice pentru obiecte de tip necunoscut, atunci se va apela automat varianta
definit n clasa respectiv, chiar dac programatorul (si nici compilatorul) nu tie care este tipul exact al
obiectului. Exemplu:
String s = v.elementAt(i).toString();
if ( v.elementAt(i).equals(obj)) ...

// se apeleaz Integer.toString()
// se apeleaz Integer.equals()

De aceea determinarea tipului unui obiect la executie, folosind obiectul Class asociat, este rareori necesar n
programele obinuite.

IE.05.3 Clase incluse


O clas Java poate conine, ca membri ai clasei, alte clase numite clase incluse (nested classes). In cazul unei
singure clase incluse, structura va arta astfel:

- 70 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

public class Outer {


...
// date si/sau metode ale clasei Outer
public class Inner {
...
// date si/sau metode ale clasei Inner
}
...
// alti membri ai clasei Outer
}

Clasa inclus poate fi o clas instaniabil, o clas static, o clas abstract sau o interfa.
Clasele incluse cu nume primesc de la compilator un nume compus din numele clasei exterioare, caracterul
$ i numele clasei interioare (Outer$Inner). Clasele care nu sunt incluse n alte clase se numesc clase de
nivel superior (top-level classes). Clasele incluse anonime, definite simultan cu instanierea, primesc un
nume format din numele clasei exterioare, caracterul $ i un numr.
Un exemplu din clasele JDK: Clasa interioar static ReverseComparator din clasa Collections, este
folosit de metoda static reverseOrder() prin intermediul unei variabilei statice:
public class Collections {
public static Comparator reverseOrder() {
// din clasa Collections
return REVERSE_ORDER;
}
private static final Comparator REVERSE_ORDER = new ReverseComparator();
private static class ReverseComparator implements Comparator,Serializable {
public int compare(Object o1, Object o2) {
Comparable c1 = (Comparable)o1;
return -c1.compareTo(o2);
}
}
. . . // alte metode si clase incluse din clasa Collections
}
Un exemplu de interes pentru definirea de noi clase dicionar este interfaa Entry, inclus n interfata Map,
cu metode asociate unei perechi cheie-valoare, ambele de tip Object:
public interface Map {
Object get (Object key);
Object put (Object key, Object value);
...
// alte metode abstracte din interfata Map
public interface Entry {
// acces la cheia si valoarea dintr-o pereche
Object getKey();
// cheia
Object getValue();
// valoarea
Object setValue(Object value);
// modifica valoarea
boolean equals(Object o);
// daca doua perechi sunt egale
}
}

Exemplu de clas care implementeaz interfata Map.Entry:

- 71 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

class Entry implements Map.Entry {


private Object key,val;
public Entry (Object k, Object v) { key=k; val=v; }
public String toString() { return key+"="+val;}
public Object getKey() { return key; }
public Object getValue() { return val;}
public Object setValue (Object v) { val=v; return v;}
public boolean equals (Object obj) {
return ((Entry)obj).getKey().equals(key);
}
}
Un alt exemplu din JDK este o clas iterator inclus n clasa colecie pe care acioneaz. In acest fel clasa
iterator are acces la variabile private sau protected ale coleciei, nu poate fi instaniat direct ci numai prin
intermediul coleciei (nu poate exista obiect iterator fr o colecie), fiind ascuns altor clase.
public class Vector {
protected int elementCount;
// nr de elemente in vector
protected Object elementData[];
// vector de obiecte
public Vector (){ elementData= new Object[10]; }
// metoda care produce obiect iterator
public Enumeration elements() {
return new VectorEnumeration();
}
// definirea clasei iterator pe vector (inclusa)
class VectorEnumeration implements Enumeration {
int count = 0;
// indice element curent din enumerare
public boolean hasMoreElements() {
return count < elementCount;
}
public Object nextElement() {
if (count < elementCount)
return elementData[count++];
else return null;
}
}
... // alte metode din clasa Vector
}
Uneori numele unei clase incluse apare o singur dat, pentru a crea un singur obiect de acest tip. In plus,
clasa inclus implementeaz o interfa sau extinde o alt clas i conine numai cteva metode scurte. Pentru
astfel de situaii se admite definirea ad-hoc de clase anonime, printr-un bloc care urmeaz operatorului new
cu un nume de interfa sau de clas abstract. Sintaxa definirii unei clase anonime este urmtoarea:
new Interf ( ) { ... // definiie clasa inclusa } ;
unde "Interf" este un nume de interfa (sau de clas abstract sau neabstract) din care este derivat
(implicit) clasa inclus anonim. O astfel de clas nu poate avea un constructor explicit si deci nu poate
primi date la construirea unui obiect din clasa anonim.

- 72 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

O situaie tipic pentru folosirea unei clase anonime definit simultan cu crearea unui obiect de tipul
respectiv este cea n care transmitem unei funcii un obiect de un subtip al interfetei Comparator (adresa
unei funcii de comparare). Exemplu de sortare a unei liste de obiecte n ordine descresctoare.
Collections.sort (list, new Comparator( ) {
// ordonare descrescatoare
public int compare (Object t1, Object t2) {
// incepe definitia clasei anonime
Comparable c1=(Comparable)t1, c2=(Comparable)t2;
return - c1.compareTo(c2);
// rezultat invers metodei compareTo
}
});
// aici se termina definitia clasei si instructiunea
O clas inclus nestatic este numit i clas interioar (inner class), pentru c fiecare obiect din clasa
exterioar va conine un obiect din clasa interioar. Cuvntul nested se refer la relaia sintactic dintre clase:
clasa inclus este definit n cadrul definiiei clasei exterioare; cuvntul inner se refer la relaia dintre
obiectele claselor incluse: un obiect al clasei exterioare conine n el un obiect al clasei incluse.
Exemplu de clasa interioar anonim pentru iterator pe vector:
public class Vector {
protected int elementCount;
// nr de elemente in vector
protected Object elementData[];
// vector de obiecte
public Vec (){ elementData= new Object[10]; }
// metoda care produce obiect iterator
public Enumeration elements() {
return new Enumeration(){
// definirea clasei iterator pe vector (inclusa)
int count = 0;
// indice element curent din enumerare
public boolean hasMoreElements() {
return count < elementCount;
}
public Object nextElement() {
if (count < elementCount)
return elementData[count++];
else return null;
}
};
// aici se termina instructiunea return
}
// aici se termina metoda elements
... // alte metode din clasa Vector
}
O alt form de clas interioar este o clas definit ntr-o metod a clasei externe. Exemplu de clas pentru
un obiect comparator inclus n funcia de ordomare:
static void sortByValue (Map m) { // ordonarea unui dictionar n ordinea valorilor
// clasa inclusa
class VComp implements Comparator {
// compara doua perechi cheie-val
public int compare (Object o1, Object o2) {
Map.Entry e1= (Map.Entry)o1;
// o pereche cheie-valoare
Map.Entry e2= (Map.Entry)o2;
// alta pereche cheie-valoare
return ((Integer) e1.getValue()).compareTo ((Integer) e2.getValue());
}
}
- 73 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Set eset = m.entrySet();


// multime de perechi cheie-valoare
ArrayList entries = new ArrayList(eset);
// vector de perechi cheie-valoare
Collections.sort (entries, new VComp()); // ordonare vector
System.out.println (entries);
// afisare perechi ordonate dupa valori
}

Prin definirea de clase anonime codul surs devine mai compact iar definiia clasei apare chiar acolo unde
este folosit, dar pot exista dificulti la ntelegerea codului i erori de utilizare a acoladelor i parantezelor.
Intre clasa interioar i clasa exterioar exist un "cuplaj" foarte strns; acest cuplaj poate fi un dezavantaj la
restructurarea (refactorizarea) unei aplicaii, dar poate fi exploatat n definirea unor clase de bibliotec (care
nu se mai modific).
Motivele definirii de clase interioare pot fi diverse:
- Pentru clase de interes local : clasa interioar este necesar numai clasei exterioare. Astfel se reduce
numrul de clase de nivel superior (top-level) i conflictele ntre nume de clase (ca urmare a unor instruciuni
import pentru pachete cu clase cu nume identice).
- Pentru a permite clasei exterioare accesul la membri private ai clasei interioare.
- Pentru a permite claselor interioare accesul la variabile ale clasei exterioare i deci o comunicare mai
simpl ntre clasele incluse (prin variabile externe lor).
- Pentru crearea rapida de obiecte functionale ( cu functii callback), unice, necesare ca parametri efectivi
altor metode (prin definirea de subclase simultan cu instanierea lor).
- Pentru ca o clas s poat moteni funcii de la cteva clase (motenire multipl).

IE.05.4 Fire de execuie ca obiecte


IE.05.4.1 Fire de execuie concurente
Paralelismul unor activiti se poate realiza la nivelul sistemului de operare pentru activiti ce rezult din
executarea unor programe independente (nu neaprat distincte), fiecare cu spaiul su de memorie, dar care
pot comunica prin intermediul sistemului de operare. La nivelul sistemului de operare activitile paralele
se numesc procese (n sisteme de tip Unix) sau taskuri (n sisteme Microsoft Windows ).
Un alt nivel de paralelism poate avea loc n cadrul fiecrui program (aplicaie), sub forma unor fire de
execuie (threads). Un proces poate conine mai multe fire (subprocese). In anumite aplicaii este necesar
ca mai multe activiti s progreseze n paralel, astfel nct se creeaz aparena c un acelai program
(calculator) poate efectua n paralel mai multe operaii. Cteva exemple tipice de aplicaii cu paralelism ntre
activitile din interiorul aplicaiei:
- Un program de tip server care trebuie s rspund cererilor adresate de mai muli clieni (programe
client), fiecare cu o conexiune separat la server;
- Un joc cu imagini multiple animate simultan;
- Algoritmi paraleli pentru mbuntirea performanelor unor operaii de cutare sau de alt tip.
Se spune c dou procese (fire) P1 i P2 (lansate n ordinea P1,P2) sunt concurente sau paralele atunci cnd
execuia lui P2 ncepe nainte de terminarea complet a lui P1. Altfel spus, cele dou procese pot evolua n
paralel, chiar pe un singur procesor care execut alternativ secvene de instruciuni din P1 i din P2.
- 74 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Paralelismul proceselor nu implic neaprat mai multe procesoare care lucreaz simultan, ci este o
alternativ la execuia strict secvenial a celor dou procese : se execut complet P1 i apoi se execut
complet P2 (fr ntreruperi). Este posibil ca n dou procese (fire) paralele s se execute aceeai secven de
instruciuni sau secvente de instruciuni complet diferite.
Java este primul limbaj care a inclus faciliti de programare cu subprocese concurente, n cadrul unei
aplicaii, paralelism suprapus peste concurena proceselor la nivelul sistemului de operare. In Java
paralelismul (aparent) are loc n cadrul unui singur program (sau aplet), iar numele folosit pentru o astfel de
activitate este acela de thread (fir de execuie) sau subproces (ligthweight process), deoarece folosete
acelai spatiu de memorie (i de nume) cu celelalte fire de execuie din acelai program. Planificatorul
(dispecerul) de procese este parte din maina virtual Java (JVM).
Cedarea controlului procesorului de ctre procesul activ (n executie) ctre dispecer se poate face voluntar (la
cererea sa, prin apelul unei metode) sau ca urmare a lansrii unei operaii de intrare-ieire.
Activitile paralele pot evolua complet independent unele de altele (asincron) sau pot utiliza anumite resurse
comune (zone de memorie, fiiere etc) i atunci este necesar sincronizarea lor n ncercarea de acces la o
resurs comun.
Dup crearea sa i nainte de terminare, un proces poate trece ciclic prin cteva stri, iar schimbarea strii
sale este cauzat fie de evenimente interne ( o aciune a procesului activ), fie de evenimente externe
procesului, cum ar fi o decizie a planificatorului de procese.
Principalele stri n care se poate afla un proces sunt:
- In execuie (running), cnd procesul este activ (deine controlul procesorului).
- Suspendat, sau blocat, sau n ateptare (waiting), cnd procesul asteapt producerea unui eveniment.
- Gata de execuie dar inactiv (ready), pentru c exist un alt proces mai important i gata de execuie.
Un singur proces poate fi n execuie, celelalte se afl fie n lista proceselor gata, fie n lista proceselor
suspendate sau blocate. Dintre procesele gata planificatorul alege pe cel cu prioritate maxim i care este
primul n coad (dac sunt mai multe procese gata cu aceeai prioritate).
Procesele paralele (concurente) i pot disputa anumite resurse comune (date din memorie, fiiere de date,
s.a.) sau i pot transmite date ntre ele (procese numite productor i consumator).
Interaciunile dintre procese (sau subprocese) paralele nu se fac prin apeluri directe ntre procese ci prin
intermediul dispecerului. Coordonarea i sincronizarea proceselor paralele necesit existena unor operaii
specifice, prin care procesele se adreseaz planificatorului.

IE.05.4.2 Fire de execuie n Java


In Java un fir de execuie este un obiect dintr-o subclas a clasei de bibliotec Thread. Operaiile prin care
un fir interacioneaz cu planificatorul sunt fie metode din clasa Object (wait, notify), fie metode din clasa
Thread (sleep, yield, join, .a.). Planificatorul activeaz un fir prin apelarea metodei run(), prezent n orice
fir de execuie (metod motenit de la clasa Thread).
In Java exist ntotdeauna un fir de execuie implicit (cu numele main), creat automat i n care se execut
funcia main cu rol de program principal. Alte fire de execuie pot fi create din firul main sau din alte fire
create anterior. Clasele pentru fire de execuie se definesc fie ca subclase ale clasei Thread (cu metoda run()
redefinit), fie pe baza unei clase care implementeaz interfaa Runnable (interfa care conine numai
metoda run()).
- 75 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Clasa Thread i interfaa Runnable se afl n pachetul java.lang i, alturi de cuvntul cheie synchronized
au existat nc din prima versiune Java. Incepnd cu versiunea 5 au fost introduse noi clase i metode pentru
execuia i sincronizarea firelor concurente cu resurse comune n pachetul java.util.concurrent.
Clasa
Thread contine cteva metode, unele apelate de dispecer iar altele care apeleaz dispecerul. Efectul metodei
run (apelat de dispecer) depinde de rolul pe care l are firul de execuie n cadrul unei aplicaii. In clasa
Thread metoda run() nu are nici un efect i de aceea trebuie definit o subclas, cu metoda run() redefinit:
class T extends Thread {
public void run() {
...
}
}
Crearea unui nou fir de execuie nseamn crearea unui nou obiect i se face ntr-un fir activ (care poate fi cel
implicit, pentru funcia main). Exemplu:
Thread fir1 = new T(); fir1.start();
Firul printe apeleaz de obicei o singur metod a firului fiu (metoda start()), pentru lansarea sa n
competiie cu celelalte fire; de aceea nici nu se mai creeaz uneori variabile de tipul subclasei. Exemplu:
new T( ).start();

// obiect anonim de tipul T

Apelul metodei start() dintr-un fir nu are ca efect imediat apelul metodei run() din acel fir, ci introducerea
firului respectiv n coada proceselor gata de execuie, ntr-o poziie care depinde de prioritatea firului. Dac
nu exist alte fire gata mai importante i dac task-ul Java este activ, atunci firul este activat imediat dup
apelul metodei start().
Firele din clase ce extind clasa Thread pot avea un constructor cu parametru de tip String, prin care se poate
da un nume firului creat. Metodele clasei Thread sunt de dou categorii: metode ale obiectelor i metode
statice. Metode care pot fi aplicate oricrui obiect fir de execuie:
start() : Cere lansarea unui fir dintr-un alt fir (printe), cnd este posibil.
isAlive() : Verifica dac firul pentru care se apeleaz s-a terminat definitiv sau nu.
interrupt(): Cere ntreruperea firului pentru care se apeleaz
getName() / setName() : Obine/modific numele firului pentru care se apeleaz
getPriority() / setPriority() : Obine/modific prioritatea firului pentru care se apeleaz
join(): Ateapt terminarea firului pentru care se apeleaz
Metode statice care pot fi folosite doar de firul n execuie (firul curent):
Thread currentThread(): referin ctre firul curent, n execuie
void sleep(long millis): autosuspendare fir curent pentru un timp specificat n milisecunde
boolean interrupted(): testeaz i anuleaz starea de ntrerupere a firului curent
Metodele urmtoare sunt motenite de la clasa Object dar se folosesc numai n obiecte de un tip derivat din
Thread sau Runnable :
wait() : Este apelat de firul activ pentru a se autosuspenda n asteaptarea unui semnal de la un alt fir paralel
(care deine o resurs comun)
- 76 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

notify(), notifyAll() : Firul activ notific (anun) firele n ateptare c s-a produs evenimentul ateptat prin
wait().
Metodele wait() si notify() pot fi folosite numai n secvene sincronizate, condiie care nu poate fi verificat
la compilare dar care produce la execuie excepia IllegalMonitorStateException.
Metoda run() din Thread se redefinete n fiecare fir definit de utilizatori i determin efectul executrii
acestui fir. De obicei metoda run() conine un ciclu n care se execut anumite operaii (afiare, desenare,
operaii cu fiiere etc.) i se apeleaz una din metodele prin care se cedeaz controlul celorlalte fire
concurente (yield(), sleep(), wait() etc.). Este posibil ca mai multe fire concurente s execute aceleai
operaii. Exemplu:
class T extends Thread {
// clasa pentru obiecte fire de executie
public T (String nume) { super(nume); }
// apel constructor clasa Thread
public void run () {
for (int i=1;i<10;i++) {
System.out.println (i + " " + getName());
// scrie numele procesului
try , sleep (time(i)); // doarme un timp
catch (InterruptedException e) { }
}
System.out.println (getName()+ " terminat");
// la terminarea procesului
}
private int time (int i) {return (int) (100*Math.random()); }
// creare si lansare procese paralele
public static void main (String [] arg) {
T p1 = new T("Unu");
T p2 = new T("Doi");
p1.start(); p2.start();
}
}
Succesiunea de afiare depinde de secvena de numere aleatoare generate, dar i de alte evenimente din
sistem (pentru un sistem de operare multi-tasking care aloc intervale de timp fiecrui task, cum este
Microsoft Windows ).
Metoda run(), aa cum este definit n interfata Runnable (pe care o implementeaz i clasa Thread), nu
poate arunca mai departe excepia InterruptedException i de aceea excepia trebuie prins i tratat n
metoda run(). Excepia InterruptedException apare atunci cnd se ncearc ntreruperea unui fir aflat ntr-o
stare de asteptare ca urmare a unui apel wait(), sleep(), join(); n aceste cazuri nu se produce ntreruperea
solicitat. Fiecare fir are asociat o variabil (boolean) cu starea sa de ntrerupere.
Cedarea controlului de ctre un fir se face i implicit, la iniierea unei operatii de I/E; terminarea operaiei
respective este un eveniment tratat de planificator. Exemplul urmtor pune n eviden aceast situatie:
// clasa pentru fire de executie reactivate la apasarrea unei taste
class Fir extends Thread {
public void run () {
try { while ( System.in.read() > 0 ); }
// asteapta tastarea unei clape
catch (IOException e) {}
}

- 77 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

public static void main (String [] arg) {


Fir t = new Fir ();
// creare fir de executie
t.start();
// activare fir de citire de la tastatura
while (t.isAlive()) {
// repeta mereu
System.out.print(".");
// afisare punct la fiecare 100 ms
try { Thread.sleep(100);} catch (Exception e) { }
}
}
}
Un fir este terminat definitiv fie prin terminarea instruciunilor din metoda run(), fie datorit unei excepii
propagate n afara metodei run(). Un program cu mai multe fire paralele se termin atunci cnd s-au terminat
toate firele (mai pot rmne fire de tip daemon dup terminarea unui program).
Fiecare fir are o prioritate asociat (un ntreg ntre 1 i 10), care arat importana relativ a acelui fir fa de
alte fire. La creare un fir primeste prioritatea implicit 5, dar aceas prioritate poate fi modificat prin metoda
setPriority(). Dac mai multe fire sunt gata de execuie, atunci cnd planificatorul preia controlul, este ales
firul cu prioritate maxim pentru a fi activat.
Definirea unei subclase a clasei Thread nu mai este posibil pentru procese paralele din cadrul unui aplet,
deoarece un aplet este o subclas a clasei JApplet i n Java nu este permis ca o clas s extind mai mult de
o singur clas. De aceea a fost creat i o interfa numit Runnable, care conine numai metoda run().
Metodele wait(), notify() i notifyAll() nu puteau face parte din aceat interfa deoarece ele nu pot fi
implementate de orice utilizator i de aceea fac parte din clasa Object, ca metode native i finale.
Crearea unui fir de execuie folosind interfaa Runnable necesit definirea unei clase care implementeaz
aceast interfa i definirea metodei run() din aceast clas. In aceast clas se pot folosi metodele statice
din clasa Thread : Thread.currentThread() si Thread.sleep ( milisec).
Lansarea n executie a unui fir se poate face numai prin apelul metodei start din clasa Thread , fie n
funcia main, fie ntr-o alt metod (dintr-un alt fir, de exemplu). De aceea trebuie creat cte un obiect
Thread pe baza fiecrui obiect Runnable, folosind un constructor al clasei Thread care admite un
parametru de tip Runnable. Exemplu:
class Proces implements Runnable {
// fire cu interfata Runnable
public void run () {
for (int i=1;i<8;i++) {
System.out.println (Thread.currentThread() + + i);
try { Thread.sleep(20); } catch (InterruptedException e) {}
}
}
// creare si lansare procese paralele
public static void main (String [] arg) {
new Thread ( new Proces ()).start();
new Thread (new Proces ()).start();
}
}

- 78 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

IE.05.4.3 Sincronizarea firelor de execuie Java


Firele paralele pot evolua un timp independent unele de altele, dar n anumite momente pot s-i dispute
resurse comune sau doresc s-i transmit date prin variabile comune. In ambele situaii trebuie reglementat
accesul la resursele comune, deoarece n caz contrar pot apare cazuri de blocare definitiv a unor procese,
sau de actualizare eronat a unor date comune sau de transmitere incorect a unor date ntre fire de execuie.
Sincronizarea firelor concurente cu resurse comune trebuie s asigure rezultate corecte indiferent de numrul
firelor, de ordinea lansrii lor, de timpul necesar fiecrui fir pentru operaiile cu resursa comun sau de ali
parametri care nu au legtur cu algoritmul aplicaiei cu fire multiple. Altfel spus, comportarea unui program
corect trebuie s fie reproductibil, indiferent de condiiile n care se execut programul.
Pentru a ilustra efectele nesincronizrii a dou fire cu o resurs comun vom considera exemplul a dou fire
care actualizeaz aceleai date (incrementeaz un acelai contor). Contorul este un obiect dintr-o clas
Contor definit de noi, cu dou metode publice: get() care citete valoarea curent a variabilei contor i
incr() care mrete cu 1 valoarea variabilei contor. Actualizarea se realizeaz prin mai multe operaii
(instruciuni main i/sau operaii de I/E) i aceast secvent de operaii poate fi ntrerupt (de planificator),
iar un alt proces reactivat poate dori s execute aceeasi secven de incrementare a aceluiai contor (cazul a
dou oficii din localiti diferite de la care se cere simultan rezervarea unui loc la un zbor sau la un tren).
Pentru un contor n memorie vom fora transferul controlului de la un fir la altul prin introducerea de apeluri
sleep() sau yield() ntre instruciunile care realizeaz actualizarea contorului.
class Contor {
// pentru obiecte folosite de fire
private int m;
public Contor () { m=0; }
public void incr () {
// incrementare m in trei pasi
int aux;
try {
aux=m;
// pasul 1
Thread.sleep((int) (Math.random()*20));
aux=aux+1;
// pasul 2
Thread.sleep((int) (Math.random()*20));
m=aux;
// pasul 3
} catch (InterruptedException e) {}
}
public int get () {
// citire valoare contor
return m;
}
}
// pentru obiecte fir de executie
class Fir extends Thread {
Contor c;
public Fir ( Contor c) { this.c=c; }
public void run () {
for (int i=0;i<5;i++){
try { sleep(10); } catch(InterruptedException e) {}
c.incr();
System.out.println (getName()+" "+c.get());
}
}
}

- 79 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

class ExFir {
public static void main (String args[]) {
Contor c= new Contor();
// contor folosit de cele doua fire
Fir f1 = new Fir ( c ); Fir f2 = new Fir ( c );
f1.start(); f2.start();
while ( f1.isAlive() && f2.isAlive() )
// asteapta terminare f1 si f2
try {Thread.sleep(100);} catch (Exception e) {}
System.out.println (c.get());
// valoare finala contor
}
}

Fiecare din cele dou fire face cte 5 incrementri ale contorului comun, dar valoarea final a contorului nu
este 10, ci este o valoare mai mic ( 5 pentru programul anterior). Rezultatul final depinde n general de
timpii de asteptare ai fiecrui fir (ntre operaii), de ordinea lansrii i de alte procese din sistem.
In acest exemplu firul f1 citeste n aux o valoare m a contorului, este ntrerupt de firul f2 care citete i el
n variabila sa proprie aux aceeasi valoare m; fiecare proces incrementeaz i scrie napoi n m aceeai
valoare a variabilei sale aux. Din aceast cauz valoarea contorului creste cu 1 i nu cu 2 cum ar fi trebuit
dac cele dou fire erau sincronizate fa de resursa comun.
Un exemplu asemntor foloseste un contor memorat ntr-un fiier disc i incrementat din mai multe fire
concurente; n acest caz pierderea controlului de ctre fiecare fir concurent se face automat, ca urmare a
initierii unor operatii de citire/scriere pe disc i nu prin cedarea voluntar a controlului.
In general, cnd un proces ncepe s modifice o resurs comun trebuie interzis altor procese s modifice
aceeasi resurs nainte ca procesul care a obtinut primul resursa s fi terminat operatiile de modificare a
resursei. Altfel spus, trebuie serializat accesul la resursa comun pentru procese (fire) concurente sau trebuie
asigurat excluderea mutual a firelor n raport cu resursa comun.
Seciunile de cod din fiecare proces care acceseaz resursa comun se numesc sectiuni critice sau regiuni
critice. Este important ca instruciunile dintr-o seciune critic s se execute nentrerupt pentru un anumit
proces i pentru un anumit obiect, fr ca un alt proces s poat executa i el aceleasi operatii pentru un
acelasi obiect. In Java o seciune critic este fie o metod, fie un bloc de instruciuni precedate de cuvntul
cheie synchronized.
Prima soluie Java pentru sincronizarea firelor de execuie a fost utilizarea cuvntului cheie synchronized n
declararea unor metode de acces la resurse comune (nainte de tipul metodei) sau ca atribut al unui bloc de
instruciuni. Sincronizarea se face la nivel de obiect i nu la nivel de funcie.
In exemplul anterior cu incrementarea unui contor din memorie, acest cuvnt se adaug metodei incr() :
public synchronized void incr () {
int aux;
try {
aux=m;
// pasul 1
Thread.sleep((int) (Math.random()*20));
aux=aux+1;
// pasul 2
Thread.sleep((int) (Math.random()*20));
m=aux;
// pasul 3
} catch (InterruptedException e) {}
}
- 80 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Dup ce firul f1 a intrat n execuia metodei sincronizate incr pentru un obiect c, nu se permite altui fir s
mai execute o metod sincronizat pentru acelasi obiect, iar firul f2 care ncearc acest lucru este pus n
ateptare pn la terminarea metodei sincronizate.
O metod sincronizat poate fi ntrerupt, dar nu poate fi reapelat pentru acelai obiect dintr-un alt fir
concurent. De asemenea, nu este permis apelarea din fire diferite a unor metode sincronizate diferite pentru
acelai obiect. De exemplu, nu este posibil ca dou fire s adauge n paralel elemente la un acelai vector
(metoda addElement()). Toate metodele de acces la un vector (din clasa Vector) sunt sincronizate pentru a fi
sigure la apelare din fire concurente.
Cuvntul synchronized ar trebui adugat oricrei metode care modific un obiect ce poate fi folosit n
comun de mai multe fire de execuie paralele. Multe din metodele claselor JDK sunt sincronizate.
Dup apelarea unei metode sincronizate pentru un obiect acest obiect este blocat cu un zvor sau
lact (lock) i nu mai poate fi apelat o alt metod sincronizat pentru acelasi obiect (dintr-un alt proces).
Deblocarea obiectului are loc la terminarea execuiei metodei sincronizate. Deoarece sincronizarea se face la
nivel de obiecte, datele comune proceselor trebuie ncapsulate n obiecte utilizate n comun. La crearea unui
proces care folosete o astfel de resurs comun (variabil, colecie, fiier) se transmite adresa obiectului ce
constituie resursa comun. Prin monitoare se asigur accesul strict secvenial al firelor concurente la operaii
critice asociate unui obiect. Un monitor este asociat unui obiect (sau unei clase) i nu unei metode.
Dou fire pot executa n paralel secvene din dou metode sincronizate, dar pentru obiecte diferite. De
asemenea, un fir poate executa o metod sincronizat i un alt fir o metod nesincronizat pentru un acelai
obiect. Sincronizarea unei metode se poate exprima n dou moduri:
synchronized void f() , -

sau

void f() , synchronized (this) , - -

O clas este sigur ntr-un context cu fire concurente (thread-safe) dac rezultatele metodelor sale sunt
aceleai indiferent din cte fire paralele sunt apelate aceste metode pentru acelea i obiecte. Practic, aceast
calitate a unei clase se obine prin adugarea atributului synchronized metodelor care modific date din
clas. Metodele sincronizate au performane mai slabe dect metodele nesincronizate i de aceea nu toate
clasele JDK sunt thread-safe.
Primele clase colecie (Vector, Hashtable) au avut metode sincronizate, dar ncepnd din Java 2 clasele
colecie nu sunt implicit thread-safe din motive de performan. Se pot obine ns clase colecie echivalente
sincronizate. Exemplu de vector cu acces sincronizat obinut din ArrayList:
List safelist = Collections.synchronizedList (new ArrayList());

- 81 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Capitolul IE.06. Colecii de obiecte n Java


Cuvinte cheie
Colecii Java, Colecii ordonate, Colecii generice, Liste, Mulimi,
Dicionare, Interfeele Collection ,List, Set, Map ,Iteratori, Generice
IE.06.1 Grupul claselor colecie
O colecie este un obiect ce conine un numr oarecare, variabil de obiecte. Coleciile se folosesc pentru
memorarea i regsirea unor date sau pentru transmiterea unui grup de date de la o metod la alta. Coleciile
Java sunt structuri de date generice, realizate fie cu elemente de tip Object, fie cu generice (cu tipuri
parametrizate) .
Grupul claselor colecie din Java cuprinde interfee, clase abstracte i clase direct utilizabile i se poate
extinde cu alte clase care respect aceleai interfee. Ele formeaz o infrastructur (Collection Framework),
adic o baz pe care se pot dezvolta alte clase colecie. Infrastructura coleciilor ofer clase direct utilizabile
i suport pentru definirea de noi clase (sub form de clase abstracte), toate conforme cu anumite interfee ce
reprezint tipuri abstracte de date (liste, mulimi, dicionare).
Un utilizator i poate defini propriile clase colecie, care respect aceste interfee impuse i sunt compatibile
cu cele existente (pot fi nlocuite unele prin altele).
Familia claselor colecie din Java este compus din dou ierarhii de clase :
- Ierarhia care are la baz interfaa Collection,
- Ierarhia care are la baz interfaa Map.

O colecie, n sensul Java, este un tip de date abstract care reunete un grup de obiecte de tip Object, numite
i elemente ale coleciei. Un dicionar (o asociere ) este o colecie de perechi chei-valoare (ambele de tip
Object); fiecare pereche trebuie s aib o cheie unic, deci nu pot fi dou perechi identice.
Interfaa Collection conine metode aplicabile pentru orice colecie de obiecte. Nu toate aceste operaii
trebuie implementate obligatoriu de clasele care implementeaz interfaa Collection; o clas care nu
definete o metod opional poate semnala o excepie la ncercarea de apelare a unei metode
neimplementate.
Urmeaz descrierea complet a interfeei Collection :

- 82 -

INFORMATIC*I*

public interface Collection {


int size();
boolean isEmpty();
boolean contains(Object element);
boolean add(Object element);
boolean remove(Object element);
Iterator iterator();
boolean containsAll(Collection c);
boolean addAll(Collection c);
boolean removeAll(Collection c);
boolean retainAll(Collection c);
void clear();
Object[ ] toArray();
}

IE. TEHNICI AVANSATE DE PROGRAMARE

// operatii generale ptr orice colectie


// dimensiune colectie (nr de elemente)
// verifica daca colectie vida
// daca colectia contine un obiect dat
// adauga un element la colectie
// elimina un element din colectie
// produce un iterator pentru colectie
// daca colectia contine elem. din colectia c
// adauga elem. din c la colectie
//elimina din colectie elem. colectiei c
// retine in colectie numai elem. din c
// sterge continut colectie
// copiere colectie intr-un vector

Din interfaa Collection sunt derivate direct dou interfee pentru tipurile abstracte:
- Set pentru mulimi de elemente distincte.
- List pentru secvene de elemente, n care fiecare element are un succesor i un predecesor i este
localizabil prin pozitia sa n list (un indice ntreg).
Clasele abstracte existente fac uz de iteratori i implementeaz aproape toate metodele unei clase colecie
folosind numai metoda iterator() (cu excepia metodelor de adugare obiect la colecie i de calcul numr de
elemente din colecie, care depind de structura fizic a coleciei).
Pentru fiecare din cele 3 structuri de date abstracte (list, mulime,dicionar) sunt prevzute cte dou clase
concrete care extind clase abstracte i implementeaz interfeele respective. Structurile de date concrete
folosite pentru implementarea tipurilor de date abstracte sunt : vector extensibil, list dublu nlnuit, tabel
de dispersie i arbore binar.

- 83 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Toate clasele colecie instaniabile redefinesc metoda toString(), care produce un ir cu toate elementele
coleciei, separate prin virgule i ncadrate de paranteze drepte. Afiarea continutului unei colecii se poate
face printr-o singur instruciune.
De asemenea sunt prevzute metode de trecere de la vectori intrinseci de obiecte (Object [] ) la colecii de
obiecte i invers: funcia Arrays.asList(), cu un argument vector intrinsec de obiecte i rezultat de tip List i
funcia toArray() din clasa AbstractCollection, de tip Object[]. Exemplu:
String sv*+ = ,unu,doi,trei-;
List list = Arrays.asList(sv);
System.out.println (list);
String aux[] = (String[ ]) list.toArray();

// nu este nici ArrayList, nici LinkedList !


// System.out.println (list.toString());
// aux identic cu sv

O a treia ierarhie are la baz interfaa Iterator, pentru metodele specifice oricrui iterator asociat unei
colecii sau unui dictionar. Toate coleciile au iteratori dar nu i clasele dicionar (se poate ns itera pe
mulimea cheilor sau pe colecia de valori).
Clasa Collections conine metode statice pentru mai multi algoritmi "generici" aplicabili oricrei colecii
(min(), max()) sau numai listelor (sort(), binarySearch(), reverse(), shuffle()). Ei foloseau iniial tipul
generic Object i metodele polimorfice equals(), compareTo() .a., dar acum folosesc tipuri parametrizate
(din versiunea 5). Exemple n forma mai veche dar mai simpl:
public static Object min (Collection col );
// obiect minim din colectia col
public static Object min (Collection col , Comparator cmp);
public static void sort (List lst);
// ordonare lista lst
public static void sort (List lst, Comparator cmp);

IE.06.2 Mulimi de obiecte


O mulime este o colecie de elemente distincte pentru care operaia de cutare a unui obiect n mulime este
frecvent i trebuie s aib un timp ct mai scurt.
Interfaa Set conine exact aceleai metode ca i interfaa Collection, dar implementrile acestei interfee
asigur unicitatea elementelor unei mulimi. Metoda de adugare a unui obiect la o mulime add() verific
dac nu exist deja un element identic, pentru a nu se introduce duplicate n mulime. De aceea obiectele
introduse n mulime trebuie s aib metoda equals() redefinit, pentru ca obiecte diferite s nu apar ca fiind
egale la compararea cu equals().
Clasele mulime predefinite i care implementeaz interfaa Set sunt:
HashSet : pentru o mulime neordonat realizat ca tabel de dispersie
TreeSet : pentru o mulime ordonat, realizat ca arbore binar echilibrat automat (Red-Black Tree).
Tabelul de dispersie asigur cel mai bun timp de cutare, iar arborele echilibrat permite pstrarea unei relaii
de ordine ntre elemente i un timp de cutare bun.
Operaiile cu dou colecii sunt utile mai ales pentru operatii cu mulimi:
s1.containsAll (s2)
s1.addAll (s2)
s1.retainAll (s2)
s1.removeAll (s2)

// true dac s1 contine pe s1 (includere de multimi)


// reuniunea multimilor s1 si s2 (s1=s1+s2)
// intersectia multimilor s1 si s2 (s1=s1*s2)
// diferenta de multimi (s1= s1-s2)
- 84 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Diferena simetric a dou mulimi se poate obine prin secvena urmtoare:


Set sdif = new HashSet(s1);
sdif.addAll(s2);
Set aux = new HashSet(s1);
aux.retainAll (s2);
simdif.removeAll(aux);

// reuniune s1+s2
// intersectie s1*s2 in aux
// reuniune minus intersectie

Exemplul urmtor arat cum putem folosi dou mulimi pentru afisarea cuvintelor care apar de mai multe ori
i celor care apar o singur dat ntr-un text. S-a folosit o mulime ordonat, pentru a permite afiarea
cuvintelor n ordine lexicografic.
public static void main (String arg[ ]) throws IOException {
Set toate = new HashSet ();
// toate cuvintele distincte din text
Set dupl =new TreeSet ();
// cuvintele cu aparitii multiple
Scanner sc = new Scanner (new File(arg[0]));
String word="";
// un cuvant din fisier
while ( sc.hasNext() ) {
// repeta cat mai sunt cuvinte in fisier
word= sc.next();
// scoate urmatorul cuvant
if ( ! toate.add (word) )
// daca a mai fost in toate
dupl.add (word);
// este o aparitie multipla
}
System.out.println ("multiple: "+ dupl); // afisare cuvinte repetate
Set unice = new TreeSet (toate);
unice.removeAll (dupl);
// elimina cuvinte multiple
System.out.println ("unice: " + unice);
// afiseaza cuvinte cu o singura aparitie
}
In general se recomand programarea la nivel de interfa i nu la nivel de clas concret. Asadar, se vor
folosi pe ct posibil variabile de tip Collection sau Set i nu variabile de tip HashSet sau TreeSet (numai la
construirea obiectului colecie se specific implementarea sa).
Nici una din mulimile HashSet sau TreeSet nu pstreaz ordinea de adugare a elementelor la mulime,
dar n clasa LinkedHashSet metoda toString() produce un ir cu elementele mulimii n ordinea adugrii
lor la mulime, dar are aceleai performane la cutare ca i clasa HashSet.
Interfaa SortedSet, implementat de clasa TreeSet, extinde interfaa Set cu cteva metode aplicabile numai
pentru colecii ordonate:
Object first(), Object last()
// primul si ultimul element din multime
SortedSet subSet(Object from, Object to) // submultimea definita prin 2 valori
SortedSet headSet(Object to)
// subSet (first(),to)
SortedSet tailSet (Object from)
// subSet (from, last())

IE.06.3 Liste (Secvene)


Interfaa List conine cteva metode suplimentare fat de interfaa Collection :
- Metode pentru acces pozitional, pe baza unui indice ntreg care reprezint poziia :
get (index), set (index,object), add (index, object), remove (index)
- 85 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

- Metode pentru determinarea poziiei unde se afl un element dat, deci cutarea primei i ultimei apariii a
unui obiect ntr-o list:
indexOf (object), lastIndexOf (object)
- Metode pentru crearea de iteratori specifici listelor:
listIterator (), listIterator (index)
- Metod de extragere sublist dintr-o list:
List subList(int from, int to);
Exist dou implementri pentru interfaa List:
ArrayList list vector, preferabil pentru acces aleator frecvent la elementele listei.
LinkedList list dublu nlnuit, preferat cnd sunt multe inserri sau tergeri de elemente n list.
In plus, clasei Vector i-au fost adugate noi metode pentru a o face compatibila cu interfaa List. Noile
metode au nume mai scurte i o alt ordine a argumentelor n metodele add() i set():
Forma veche (1.1)
Object elementAt (int)
Object setElementAt (Objext, int)
void insertElementAt (Object, int)

Forma nou (1.2)


Object get(int)
Object set (i, Object)
void add (i,Object)

Exemplu de funcie care schimb ntre ele valorile a dou elemente i si j:


static void swap (List a, int i, int j) {
Object aux = a.get(i);
a.set (i,a.get(j));
a.set (j,aux);
}

// din clasa Collections


// a.elementAt(i)
// a.setElementAt (a.elementAt(j) , i)
// a.setElementAt (aux , j)

De observat c metodele set() si remove() au ca rezultat vechiul obiect din list, care a fost modificat sau
eliminat. Metoda set() se poate folosi numai pentru modificarea unor elemente existente n list, nu i
pentru adugare de noi elemente.
Algoritmii de ordonare i de cutare binar sunt exemple de algoritmi care necesit accesul direct, prin
indici, la elementele listei; de aceea metodele sort() si binarySearch() din clasa Collections au argument de
tip List i nu Collection.
Accesul poziional este un acces direct, rapid la vectori dar mai puin eficient n cazul listelor nlnuite. De
aceea s-a definit o clas abstract AbstractSequentialList, care este extins de clasa LinkedList dar nu i de
clasa ArrayList. Metoda static Collections.binarySearch, cu parametru de tipul general List, recunoaste
tipul de list i face o cutare binar n vectori, dar o cutare secvenial n liste nlnuite.
Clasa LinkedList contine, n plus fa de clasa abstract AbstractList, urmtoarele metode, utile pentru
cazuri particulare de liste (stive, cozi etc.): getFirst(), getLast(), removeFirst(), removeLast(),
addFirst(Object), addLast(Object).
Din versiunea 5 au mai fost adugate interfeele Queue si Deque cu cteva metode noi, interfee
implementate de mai multe clase, printre care AbstractQueue, PriorityQueue, LinkedList, ArrayDeque.
Interfaa Queue extinde interfaa Collection cu o metod de adugare offer() care nu produce excepie dac
- 86 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

nu mai este loc n colecie i cu metode de acces la primul element din colecie (din coad) cu i fr excepie
n caz c nu exist (element() si peek() fr eliminare din coad, poll()i remove() cu eliminare din coad).
Interfaa Deque extinde interfaa Queue cu metode de acces i la primul si la ultimul element din list:
addFirst(), removeFirst(), getFirst(), addLast(), removeLast(), getLast()i variantele care nu produc
excepii: offer(), poll(), peek(), offerFirst(), offerLast(),
Cele mai multe clase de tip coad (ca BlockingQueue si SynchronousQueue) au fost introduse, alturi de
alte clase, n pachetul java.util.concurrent pentru programare cu fire de execuie concurente.
Pentru aplicaiile cu structuri de date sunt interesante clasele ArrayDeque si PriorityQueue; clasa
LinkedList implementeaz acum i interfaa Deque i de aceea nu exist o clas LinkedDeque.
Coada cu prioriti este implementat ca un vector heap extensibil (fr limite de capacitate). Indiferent de
ordinea de adugare la coad, elementul din fa (obinut prin una din metodele peek(), poll() sau remove())
este cel cu prioritatea minim. Prioritatea este determinat de ctre metoda compareTo() a obiectelor
introduse n coad (constructor fr argumente) sau de ctre metoda compare() a obiectului comparator
transmis ca argument la construirea unei cozi.

IE.06.4 Dicionare (Asocieri)


Interfaa Map conine metode specifice operaiilor cu un dicionar de perechi cheie valoare, n care cheile
sunt unice . Exist trei implementri pentru interfaa Map:
HashMap dicionar realizat ca tabel de dispersie, cu cel
mai bun timp de cutare.
TreeMap dicionar realizat ca arbore echilibrat, care
garanteaz ordinea de enumerare.
LinkedHashMap tabel de dispersie cu meninere ordine
de introducere (din versiunea 4)
Definitia simplificat a interfeei Map este urmtoarea:
public interface Map {
Object put(Object key, Object value);
// pune o pereche cheie-valoare
Object get(Object key);
// extrage valoare asociat unei chei date
Object remove(Object key);
// elimin pereche cu cheie dat
boolean containsKey(Object key);
// verifica daca exista o cheie data
boolean containsValue(Object value);
// verifica daca exista o valoare data
int size();
// dimensiune dictionar (nr de perechi)
boolean isEmpty();
void clear();
// elimina toate perechile din dictionar
Set keySet();
// multimea cheilor
Collection values();
// colectia valorilor din dictionar
Set entrySet();
// multimea perechilor cheie-valoare
}
Metoda get() are ca rezultat valoarea asociat unei chei date sau null dac cheia dat nu se afl n dicionar.
Metoda put() adaug sau modific o pereche cheie-valoare i are ca rezultat valoarea asociat anterior cheii
date (perechea exista deja n dicionar) sau null dac cheia perechii introduse este nou. Efectul metodei put
(k,v) n cazul c exist o pereche cu cheia k n dicionar este acela de nlocuire a valorii asociate cheii k prin
- 87 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

noua valoare v (valoarea nlocuit este transmis ca rezultat al metodei). Testul de apartenen a unei chei
date la un dicionar se poate face fie direct prin metoda containsKey(), fie indirect prin verificarea
rezultatului operaiei get().
Clasele care genereaz obiecte memorate ntr-un obiect HashMap sau HashSet trebuie s redefineasc
metodele equals() si hashCode(), astfel nct s se poat face cutarea la egalitate dup codul de dispersie.
In exemplul urmtor se afieaz numrul de apariii al fiecrui cuvnt distinct dintr-un text, folosind un
dicionar-arbore pentru scrierea cuvintelor n ordine.
class FrecApar {
// frecventa de aparitie a cuvintelor intr-un text
private static final Integer ONE= new Integer(1);
// o constanta
public static void main (String arg[]) {
Map dic = new TreeMap ();
// dictionar de cuvinte
String text = trei unu doi trei doi trei ; String word;
StringTokenizer st = new StringTokenizer (new String (text));
while ( st.hasMoreTokens()) {
word = st.nextToken();
// cuvantul urmator
Integer nrap = (Integer) dic.get(word);
// numar de aparitii
if (nrap == null)
// daca nu exista anterior
dic.put (word,ONE);
// prima aparitie
else
dic.put (word, new Integer (nrap.intValue()+1)); // alta aparitie
}
System.out.println (dic);
// afisare dictionar
}
}
Cheile dintr-un dictionar pot fi extrase ntr-o mulime cu metoda keySet(), iar valorile din dicionar pot fi
extrase ntr-o colecie (o list) cu metoda values(). Metoda entrySet() produce o mulime echivalent de
perechi "cheie-valoare", unde clasa pereche are tipul Entry. Entry este o interfa inclus n interfaa Map i
care are trei metode: getKey(), getValue()i setValue().
Clasa AbstractMap definete majoritatea metodelor din interfaa Map n funcie de metoda abstract
entrySet(), iar metoda put() nu este abstract dar nici nu este definit (arunc o excepie).
De observat c metodele entrySet(), keySet() i values() (definite n AbstractMap) creeaz doar imagini noi
(views) asupra unui dicionar i nu alte colecii de obiecte; orice modificare n dicionar se va reflecta
automat n aceste imagini, fr ca s apelm din nou metodele respective. O imagine (view)este creat
printr-o clas care definete un iterator pe datele clasei dicionar i nu are propriile sale date. Metodele clasei
imagine sunt definite apoi pe baza iteratorului, care d acces la datele din dicionar.
Diferena dintre clasele HashMap si LinkedHashMap apare numai n irul produs de metoda toString() a
clasei: la LinkedHashMap ordinea perechilor n acest ir este aceeai cu ordinea de introducere a lor n
dicionar, n timp ce la HashMap ordinea este aparent ntmpltoare (ea depinde de capacitatea tabelei de
dispersie, de funcia hashCode()i de ordinea de introducere a cheilor). Pentru pstrarea ordinii de adugare
se folosete o list nlnuit, iar tabelul de dispersie asigur un timp bun de regsire dup cheie.

IE.06.5 Colecii ordonate


Problema ordonrii este rezolvat diferit n Java pentru liste fa de mulimi i dicionare. Listele sunt
implicit neordonate (se adaug numai la sfrit de list) i pot fi ordonate numai la cerere, prin apelul unei
- 88 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

metode statice (Collections.sort()). Multimile, ca i dicionarele, au o variant de implementare (printr-un


arbore binar ordonat) care asigur meninerea lor n ordine dup orice adugare sau eliminare de obiecte.
Exemplu de ordonare a unei liste:
public static void main (String arg[ ]) {
String tab* + = ,"unu","doi","trei",patru,cinci-;
List lista = Arrays.asList (tab);
Collections.sort (lista);
System.out.println (lista);
// scrie: [cinci,doi,patru,trei,unu]
}
Putem s ne definim vectori sau liste ordonate automat, sau alte alte structuri compatibile cu interfaa List i
care asigur ordinea (un arbore binar, de exemplu).
O mulime ordonat este de tipul TreeSet iar un dicionar ordonat este de tipul TreeMap. Se pot defini i
alte tipuri de colecii sau dicionare ordonate, care implementeaz (optional) interfaa SortedSet, respectiv
interfaa SortedMap. Adugarea sau modificarea valorilor dintr-un arbore se face cu meninerea ordinii i nu
necesit reordonarea mulimii sau dicionarului. Obiectele introduse ntr-o colecie TreeSet sau TreeMap
trebuie s aparin unei clase care implementeaz interfaa Comparable i deci conine o definiie pentru
metoda compareTo().
Exemplu de ordonare a unei liste de nume (distincte) prin crearea unei mulimi ordonate:
SortedSet lst = new TreeSet (lista);

// sau se adauga cu metoda addAll

Iteratorul unei colecii ordonate parcurge elementele n ordinea dictat de obiectul comparator folosit
meninerea coleciei n ordine.
O problem comun coleciilor ordonate este criteriul dup care se face ordonarea, deci funcia de
comparaie, care depinde de tipul obiectelor comparate. Sunt prevzute dou soluii pentru aceast problem,
care folosesc dou interfee diferite: Comparable i Comparator.
Anumite metode statice (sort, min, max s.a.) i unele metode din clase pentru mulimi ordonate apeleaz n
mod implicit metoda compareTo(), parte a interfeei Comparable. Clasele JDK cu date (String, Integer,
Date s.a.) implementeaz interfaa Comparable i deci contin o metoda compareTo() pentru o ordonare
"natural" ( excepie face clasa Boolean, ale crei obiecte nu sunt comparabile).
Ordinea natural este ordinea valorilor algebrice (cu semn) pentru toate clasele numerice, este ordinea
numeric fr semn pentru caractere i este ordinea lexicografic pentru obiecte de tip String. Pentru alte
clase, definite de utilizatori, trebuie implementat interfaa Comparable prin definirea metodei
compareTo(), dac obiectele clasei pot fi comparate (i sortate).
Pentru ordonarea dup un alt criteriu dect cel natural i pentru ordonarea dup mai multe criterii se va folosi
metoda compare() dintr-o clas compatibil cu interfaa Comparator.
Rezultatul metodei compare(Object ob1, Object ob2) este acelai cu al metodei compareTo(), deci un numr
negativ dac ob1<ob2, zero dac ob1==ob2 i un numr pozitiv dac ob1>ob2.
Un argument de tip Comparator apare n constructorii unor clase i n cteva metode din clasa Collections
(sort, min, max) ce necesit compararea de obiecte.

- 89 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Pentru a utiliza o functie compare() trebuie definit o clas care conine numai metoda compare(), iar un
obiect al acestei clase se transmite ca argument funciei. Exemplu de ordonare a dicionarului de cuvintefrecven creat anterior, n ordinea invers a numrului de apariii:
Set entset = dic.entrySet();
ArrayList entries = new ArrayList(entset);
Collections.sort (entries, new Comp());
...
// clasa comparator obiecte Integer in ordine inversa celei naturale
class Comp implements Comparator {
public int compare (Object o1, Object o2) {
Map.Entry e1= (Map.Entry)o1, e2= (Map.Entry)o2; // e1,e2=prechi cheie-valoare
return ((Integer)e2.getValue()).compareTo ((Integer) e1.getValue());
}
}

IE.06.6 Iteratori
Una din operaiile frecvente asupra coleciilor de date este enumerarea tuturor elementelor coleciei (sau a
unei subcolecii) n vederea aplicrii unei prelucrri fiecrui element obtinut prin enumerare. Realizarea
concret a enumerrii depinde de tipul coleciei i foloseste un cursor care nainteaz de la un element la
altul, ntr-o anumit ordine (pentru colecii neliniare). Cursorul este un indice ntreg n cazul unui vector sau
un pointer (o referin) pentru o list nlnuit sau pentru un arbore binar.
Generalizarea modului de enumerare a elementelor unei colecii pentru orice fel de colecie a condus la
apariia claselor cu rol de iterator fa de o alt clas colecie. Orice clas colecie Java 2 poate avea o clas
iterator asociat. Pentru un acelasi obiect colecie (de ex. un vector) pot exista mai muli iteratori, care
progreseaz n mod diferit n cadrul coleciei, pentru c fiecare obiect iterator are o variabil cursor proprie.
Toate clasele iterator trebuie s includ urmtoarele operaii: poziionarea pe primul element din colecie,
poziionarea pe urmtorul element din colecie, obinerea elementului curent din colecie, detectarea
sfrsitului coleciei (test de terminare a enumerrii).
Interfaa Iterator este varianta mai nou a interfetei Enumerator si conine urmtoarele metode :
public interface Iterator {
boolean hasNext();
Object next();
void remove();
}

// daca exista un element urmator in colectie


// extrage element curent si avans la urmtorul
// elimina element curent din colectie (optional)

Exemplu de utilizare a unui iterator:


public static Object max (Collection c) {
// determinare maxim din colectia c
Iterator it = c.iterator();
Comparable m=(Comparable) (it.next());
while (it.hasNext()) {
Comparable e=(Comparable) (it.next());
if (e.compareTo (m) > 0)
m=e;
}
return m;
}
[Type a quote from the document or the summary of an interesting point. You can
- 90 position the text box anywhere in the document.
Use the Text Box Tools tab to
change the formatting of the pull quote text box.]

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

De observat c modificarea coninutului unei colecii se poate face fie prin metode ale clasei colecie, fie
prin metoda remove() a clasei iterator, dar nu ar trebui folosite simultan ambele moduri de modificare. In
exemplul urmtor apare o excepie la execuie:
ArrayList a = new ArrayList();
Iterator it = a.iterator();
for (int i=0;i<7;i++) {
a.add(i); it.remove();
}

Pentru fiecare clas concret de tip colecie exist o clas iterator. Un obiect iterator este singura posibilitate
de enumerare a elementelor unei mulimi i o alternativ pentru adresarea prin indici a elementelor unei liste.
Clasele iterator nu sunt direct instaniabile (nu au constructor public), iar obiectele iterator se obin prin
apelarea unei metode a clasei colecie (metoda iterator()). In felul acesta, programatorul este obligat s
creeze nti obiectul colecie i numai dup aceea obiectul iterator. Mai muli algoritmi generici realizai ca
metode statice (n clasa Collections) sau ca metode ne-statice din clasele abstracte folosesc un obiect iterator
pentru parcurgerea coleciei. Exemplu:
public static void sort (List list) {
Object a[] = list.toArray();
// transforma lista in vector intrinsec
Arrays.sort(a);
// ordonare vector intrinsec (mai eficienta)
ListIterator i = list.listIterator();
for (int j=0; j<a.length; j++) { // modificare elemente din lista
i.next(); i.set(a[j]);
}
}
Fragmentul urmtor din clasa AbstractCollection arat cum se pot implementa metodele unei clase colecie
folosind un iterator pentru clasa respectiv:
public abstract class AbstractCollection implements Collection {
public boolean contains(Object o) {
// fara cazul o==null
Iterator e = iterator();
while (e.hasNext())
if (o.equals(e.next()))
return true;
return false;
}
public Object[] toArray() {
Object[] result = new Object[size()];
Iterator e = iterator();
for (int i=0; e.hasNext(); i++)
result[i] = e.next();
return result;
}
...
}

- 91 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Interfaa ListIterator conine metode pentru traversarea unei liste n ambele sensuri i pentru modificarea
elementelor enumerate : hasNext(), next(), hasPrevious(), previous(), nextIndex(), previousIndex(),
remove(), set (Object o), add(Object o). Exemplu de parcurgere a unei liste de la coad la capt:
List a = new LinkedList();
for (ListIterator i= a.listIterator (a.size()); i.hasPrevious(); )
System.out.println (i.previous());

O clas dicionar (Map) nu are un iterator asociat, dar este posibil extragerea unei mulimi de chei sau unei
mulimi de perechi cheie-valoare dintr-un dicionar, iar aceste mulimi pot fi enumerate.
Secvena urmtoare face o enumerare a perechilor cheie-valoare dintr-un dicionar, folosind interfaa public
Entry, definit n interiorul interfeei Map:
for (Iterator it= map.entrySet().iterator(); it.hasNext();) {
Map.Entry e = (Map.Entry) it.next();
System.out.println ( e.getKey()+:+e.getValue());
}

IE.06. 7 Generice
Clasele colecie cu tipuri parametrizate au fost introduse n versiunea 5, ca soluii alternative pentru coleciile
de obiecte Object. Aceste clase au fost numite generice (generics) i nu clase ablon (templates) pentru c
dei se definesc i se folosesc aproape la fel cu clasele ablon din C++ ele difer prin implementare: n C++
din clasa ablon se genereaz diverse clase prin substituia parametrilor tip din clasa ablon, dar n Java
exist o singur clas generic (surs i compilat) n care se nlocuiesc parametrii formali cu parametrii
efectivi, ca i la apelul de funcii. Intr-o colecie generic tipul obiectelor din colecie apare ca parametru-tip
dup numele clasei. Exemple:
ArrayList<Integer> a = new ArrayList<Integer>();
ArrayList<String> b = ArrayList<String> (100);
ArrayList<TNode> c = ArrayList<TNode> (n);
ArrayList<LinkedList<Integer>> graf;
// initializata ulterior
TreeMap<String, Integer> d ;
// cheie=String, valoare=Integer
Ultimul exemplu arat c o clas poate avea mai muli parametri-tip.
Avantajele sunt acelea c se poate verifica la compilare dac se introduc n colecie numai obiecte de tipul
declarat pentru elementele coleciei, iar la extragerea din colecie nu mai este necesar o conversie de la tipul
generic la tipul specific aplicaiei. Exemplu cu un vector de obiecte Integer:
ArrayList<Integer> list = new ArrayList<Integer>();
for (int i=1;i<10;i++)
list.add( new Integer(i) );
// nu se poate adauga alt tip decat Integer
int sum=0;
for (int i = 0; i< list.size();i++) {
Integer val= list.get(i);
// fara conversie de tip !
sum += val.intValue();
}
- 92 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Sursele unor clase colecie s-au modificat substanial prin trecerea la generice. Exemplu:
public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V> {
//
public V get (Object key) , public V put ( K key, V value) , Set<K> keySet() , Set < Map.Entry<K,V>> entrySet() , Collection<V> values() , V remove (Object key) , int size() , boolean containsKey (Object key) , . boolean containsValue (Object value) , void putAll( Map <? extends K, ? extends V> m) ,void clear() , }

Exemplu de utilizare dicionar cu valori multiple pentru problema listei de referine ncruciate - n ce linii
dintr-un fiier text apare fiecare cuvnt distinct :
public static void main (String[ ] arg) throws IOException {
Map<String,List<Integer>> cref = new TreeMap<String,List<Integer>>( );
BufferedReader in = new BufferedReader (new FileReader (arg[0]));
String line, word; int nl=0;
while ((line=in.readLine()) != null) {
++nl;
StringTokenizer st = new StringTokenizer (line);
while ( st.hasMoreTokens() ) {
word=st.nextToken();
List<Integer> lst = cref.get (word);
if (lst==null)
cref.put (word, lst=new LinkedList<Integer>());
lst.add (new Integer (nl));
}
}
System.out.println (cref);
}
Compilatorul Java emite averismente la utilizarea formei mai vechi pentru colecii (cu elemente de tip
Object), iar documentaia claselor a fost rescris pentru forma cu parametri-tip. Clasele mai vechi care
foloseau colecii nu au mai fost modificate; un exemplu este clasa DefaultMutableTreeNode.
Pentru colecii generice s-a introdus o form mai simpl de iterare. Exemplu:

- 93 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

public static void main (String arg[]){


String sa[]={"unu","doi","trei"};
TreeSet<String> a = new TreeSet<String> ();
for (int i=0;i<sa.length ;i++)
a.add(sa[i]);
String r="";
for (String s: a )
// iterator Java versiunea 5
r += s+-";
System.out.println( r); // doi-trei-unu}
Trecerea de la un tip primitiv la tipul clas corespunztor i invers se face automat n versiunea 5, operaii
numite autoboxing i unboxing. Exemplu:
LinkedList<String> list = new LinkedList<String>();
for (int x=1;x<9;x++)
list.add(x+"");
String sb="";
for (String s : list)
sb += s;
// concatenare de siruri extrase din vector

La declararea unui parametru tip se poate folosi i caracterul wildcard ? cu sensul de orice tip :
// functie generic de afisare a oricrei colectii
static void printCol (Collection<?> c) {
for (Object e : c) System.out.println(e);
}
Exemplu de funcie incorect i utilizare care produce erori la compilare:
// functie naiv de afisare a unei colectii generice
static void printCol (Collection<Object> c) {
for (Object e : c) System.out.println(e);
}
// utilizare incorect
HashSet<String> m = new HashSet<String> (); printCol (m);
O colecie Collection<Object> nu este un supertip al unei colectii Collection<T> chiar dac tipul Object
este supertip al oricrui tip clas T din Java. In concluzie Collection<?> este supertipul oricrei colecii de
obiecte, iar caracterul '?' are sensul de "tip necunoscut".
Declaraia Collection<Object> nu este echivalent cu declaraia Collection<?>.
Tipurile necunoscute pot fi limitate inferior sau superior (Bounded wildcards) folosind sintaxa
extends T> pentru tipuri limitate superior i <? super T> pentru tipuri limitate inferior.Exemplu:

<?

static double sum (Collection<? extends Number> c) { ...}


deci funcia sum() poate opera cu o colecie de obiecte de orice subtip al lui Number (Byte, Short, Integer,
Long, Float, Double). Se spune c Number este limita superioar a tipului necunoscut '?'.
- 94 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Nu numai clasele pot avea parametri tip dar i metodele (numite metode generice). Exemplu:
// transforma un vector intr-o colectie (gresit)
static void arrayToCol (Object[] a, Collection<?> c) {
for (Object o : a)
c.add(o);
// eroare la compilare
}
// transforma un vector intr-o colectie (corect)
static <T> void arrayToCol (T[] a, Collection<T> c) {
for (T o : a)
c.add(o);
// correct
}
// utilizare (fara argumente efective de tip la apel)
String[] sa = new String[100];
Collection<String> cs = new LinkedList<String>();
arrayToCol (sa, cs); // T presupus a fi String

- 95 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Capitolul IE.07. Diagrame de clase n UML


Cuvinte cheie
UML, Atribute, Operaii, Stereotip, Asociere, Generalizare
Diagrame statice, Diagrame dinamice, Diagrame de stare,
Diagrame fizice, Cazuri de utilizare, Diagrama de clase,

IE.07.1 Standardul UML


UML (Unified Modelling Language) este un standard pentru reprezentarea grafic a claselor, obiectelor i a
relaiilor statice i dinamice dintre acestea. UML este independent de un anumit limbaj de programare i
permite vizualizarea relaiilor dintre mai multe clase (obiecte) dintr-o aplicaie sau a unei pri din aplicaie.
Pentru pstrarea independenei fa de orice limbaj standardul UML folosete cuvinte diferite n general de
cuvintele folosite n limbajele existente la vremea elaborrii sale: atribute pentru datele sau variabilele clasei,
operaii pentru metodele clasei, stereotip pentru atributele unei clase sau unei relaii, asociere pentru relaia
numit delegare sau compunere, generalizare pentru derivare etc.
Standardul UML pune la dispoziie mai multe categorii de diagrame:
- Diagrame statice n care apar clase, obiecte, colecii i relaiile statice dintre ele : implementare, derivare,
compunere, includere, etc.
- Diagrame dinamice care arat cum interacioneaz obiectele software n cursul execuiei aplicaiei i
evenimentele semnificative din cursul execuiei.
- Diagrame de stare dup modelul mainilor cu stri finite (FSM)
- Diagrame fizice care reprezint entitti din aplicaie (fiiere, biblioteci)
- Diagrame pentru cazuri de utilizare a aplicaiei de ctre diverse categorii de utilizatori (Use Cases)
Diagramele UML pot fi la diferite niveluri de detaliu i sunt utile ca:
-

Reprezentare conceptual a funconrii aplicaiei

Specificaii de proiectare a programelor (nainte de implementare)

Documentaie de implementare a aplicaiei (dup implementare)

De observat c exist diferite programe care pot genera diagrame de clase din cod surs (Java) i c unele
dintre acestea se mai abat puin de la standardul UML. Diagramele prezentate aici sunt create de o versiune
mai veche (6.7.1) a mediului integrat pentru dezvoltarea de programe NetBeans.
Este posibil i operaia de generare de cod din diagrame de clase.

IE.07.2 Diagrame de clase n UML


Diagrama UML a unei clase este un dreptunghi cu trei seciuni dispuse pe vertical: numele clasei, datele i
metodele clasei.

- 96 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Variabilele clasei, numite "atribute" n diagrama UML, au de obicei modul de acces private sau protected
pentru a respecta principiul ncapsulrii datelor n clase i sunt marcate cu minus (-). Constructorii i
metodele publice (numite operaii n UML) sunt marcate cu plus (+).
Uneori se reprezint numai metodele cele mai folosite sau caracteristice, fr metode motenite de la alte
clase (de la clasa Object, de ex.).
Exemplu de definire a unei clase:
public class MyVector {
protected Object data[];
protected int count;
public MyVector( int n) {
data = new Object[n];
}
public MyVector () { this(10); }
// metode publice
public int size ( ) { return count; }
public String toString ( )
String str="[";
for (int i=0;i<count;i++)
str = str+ data[i] +" ";
return str+"]";
}
public void add (Object obj) {
if ( count >= data.length )
resize();
data[count++]= obj;
}
}

// date din vector


// nr de elemente din vector
// count=0 implicit

// redefinita metoda din Object

// adaugare la vector

Diagrama acestei clase n NetBeans arat astfel:

- 97 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

IE.07.3 Relaia de generalizare n UML


In diagrama UML relaia de generalizare (derivare, extindere) este reprezentat printr-o sgeat vertical de
la subclas la superclas iar n subclas apar doar metodele noi i cele redefinite.
Exemplul urmtor este o clas Stiva, derivat din clasa MyVector, pornind de la observaia c o stiv este
un caz particular de vector. Diagrama este generat de NetBeans din codul surs urmtor:
class Stiva extends MyVector {
public void push (Object item) {
add (item);
}
public Object pop() {
if (empty( )) return null;
Object obj = data[count-1];
removeAt(count);
return obj;
}
public boolean empty () {
return size( )==0;
}
}

IE.07.4 Relaii de asociere n UML


Relaia de asociere (compunere sau delegare) dintre dou clase se reprezint printr-o sgeat orizontal de la
clasa obinut prin delegare la clasa delegat, cu un romb n punctul de plecare.

- 98 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

UML deosebete dou tipuri de asocieri: compoziie i agregare. Diferena este aceea c rombul este alb
(agregare) sau negru (compozitie). In Java cele dou tipuri sunt identice dar n C++ pot fi diferente.
Asocierile UML pot avea o multiplicitate, dac n clasa compus exist un vector sau alt colecie de obiecte
din clasa coninut. Multiplicitatea se poate exprima n mai multe moduri:

cifr = numrul exact de variabile n colecie


Domeniu (2..5) = orice numr ntre aceste limite
Asterisc (*) = oricte variabile (posibil zero)

Exemplu de asociere a unei clase cu ea nsi: un nod de arbore binar conine dou referine ctre nodurile fii
(stnga i dreapta):
public class BinaryTreeNode {
private BinaryTreeNode leftNode;
private BinaryTreeNode rightNode;
}
In cazul unui nod de arbore multici cu numr nelimitat de fii n locul lui 2 va fi caracterul asterisc *.
Exemplu de asociere prin delegare ntre clasa Stiva i clasa MyVector:

public class Stiva {


private MyVector items;
// variabila delegat
public Stiva( ) { items = new MyVector(); }
public void push (Object item) {
items.add(item);
}
public Object pop( ) {
int len = items.size( );
if (len == 0)
throw new EmptyStackException();
Object obj = items.get (len - 1);
items.removeAt (len - 1);
return obj;
}
public boolean empty( ) { return (items.size( ) == 0); }
}

Diagrama de clase UML pentru


codul surs anterior:

- 99 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

IE.07.5 Relaia de includere n UML


In Java se poate defini o clas interioar ca membru al unei clase exterioare n scopul de a simplifica
comunicarea ntre clasa exterioar i clasa inclus. Relaia de includere apare n reprezentarea UML printr-o
linie cu extremitate diferit n clasa exterioar (un '+' ntr-un cerculet).

Codul Java care a stat la baza acestei diagrame:

public class ObjList {


// clasa inclusa ptr nod de lista
class ListNod {
Object val;
ListNod leg;
public ListNod (Object v) {
val=v; leg=null;
}
}
// membrii ai clasei exterioare
protected ListNod cap;
// inceput de lista
public ObjList() {
// constructor
cap=new ListNod("");
}
public String toString ( ) {
String aux=""; ListNod p= cap.leg;
while ( p != null ) {
aux=aux + p.val.toString()+" ";
p=p.leg;
}
return aux;
}
public void add (Object v) {
ListNod nou= new ListNod(v);
ListNod p=cap;
while (p.leg != null )
p=p.leg;
p.leg=nou;
}
}

- 100 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

IE.07.6 Clase abstracte i interfee n UML


Clasele abstracte i interfeele sunt privite n UML ca orice alt clas (instaniabil) i nu au o reprezentare
diferit de cea a claselor. Singura diferen este aceea c numele clasei este precedat de stereotipul
<<abstract>> sau <<interface>> i c numele metodelor abstracte sunt scrise nclinat (cu italice). Pentru o
clas abstract numele clasei poate fi scris i el cu italice, fr a mai fi precedat de <<abstract>>.
In exemplul alturat clasa StackList moteneste mai multe metode definite n clasa AbstractList, mai
puin metodele get()i size() care trebuie definite. Operaiile cu stiva sunt delegate ctre obiectul "stack
al crui tip este stabilit la instanierea clasei StackList.
class StackList extends AbstractList {
private AbstractList stack;
public StackList (List list) {
stack=(AbstractList)list;
}
public Object push (Object obj) {
stack.add (0,obj);
return obj;
}
public Object pop () {
Object obj= get(0);
stack.remove(obj);
return obj;
}
public int size() {
return stack.size();}
public Object get (int i) {
return stack.get(i); }
}
class UseStack {
public static void main (String arg[]) {
StackList st1 = new StackList
(new ArrayList());
StackList st2 = new StackList
(new LinkedList());
String d[] = { "1","2","3","4","5"};
for (int i=0;i<d.length;i++) {
st1.push(d[i]); st2.push (d[i]);
}
System.out.println (st1+"\n"+st2);
}
}

Urmeaz un exemplu cu o clas abstract i cu o interfa:

- 101 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

class ArraySet extends AbstractSet {


Object a[]; int n,nmax;
public ArraySet (int max) {
a= new Object[max]; nmax=max; n=0;
}
public boolean add(Object obj) {
if ( contains(obj)) return false;
if ( n==nmax) throw new OutOfMemoryError();
a[n++]=obj;
return true;
}
public int size( ) {return n; }
public Iterator iterator() {
return new ArrayIter (this);
}
}
Clasa iterator:
class ArrayIter implements Iterator {
private int k; private ArraySet as;
ArrayIter( ArraySet set) { k=0; as=set; }
public Object next() {
if (k < as.n) return as.a[k++];
else return null;
}
public boolean hasNext() { return k < as.n; }
public void remove () { throw new UnsupportedOperationException(); }
}

- 102 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

IE.07.7 Studiu de caz


Aplicaia menine o agenda personal cu numere de telefon i alte date despre o serie de persoane.
Desenul urmtor ilustreaz diverse cazuri de utilizare a aplicaiei n versiunea UML:

Diagrama static de clase:

- 103 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Diagrama la nivel
conceptual:

Diagrama clasei Person:

Diagrama clasei AddressBook:

- 104 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Diagramele
operaiilor
addPerson()
saveAddressBook()

- 105 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Capitolul IE.08. abloane de proiectare cu clase


Cuvinte cheie
ablon de proiectare, Iterator, Observator, Adaptor,
Compozit, Decorator, Fabric de obiecte, Fabric abstract
MVC(Model-View-Controller), Injectarea dependenelor
IE.08.1 Proiectarea orientat pe obiecte
Proiectarea unei aplicaii cu obiecte nseamn selectarea unor clase existente i definirea unor noi clase care,
prin instaniere vor produce obiectele care vor realiza funcionalitatea aplicaiei. Stabilirea claselor necesare
i a relaiilor dintre ele este o problem cu mai multe soluii posibile i care necesit cunotine din domeniul
proiectrii cu obiecte. Principalele obiective urmrite n proiectare sunt satisfacerea cerinelor beneficiarilor
i uurina ntreinerii i modificrii ulterioare a codului surs; obiective legate ntre ele doarece i cerinele
se modific n timp, pe msura folosirii aplicaiei.
Alt obiectiv al proiectrii este optimizarea performanelor aplicaiei, ca timp de execuie i ca memorie
utilizat; dar acesta vine de multe ori n contradicie cu obiectivul uurinei de extindere i de adaptare a
aplicaiei la noi cerine. Un program compact, cu puine obiecte puternic cuplate, este n general mai greu de
modificat dect un program cu mai multe obiecte slab cuplate i cu mai multe linii surs.
Se consider de multe ori c scopul unei bune proiectri este obinerea unei aplicaii care s evite
urmtoarele defecte (caracteristici ale unei proiectri deficitare): rigiditate, fragilitate i imobilitate. Un
sistem de clase este rigid dac este greu de modificat datorit dependenelor dintre clase, mai ales a celor
propagate (transitive). Un sistem fragil este cel n care modificrile produc erori neateptate. Un sistem
imobil are pri dificil de reutilizat n alte aplicaii datorit dependenelor de alte pri ale aplicaiei.
Pentru obinerea acestor caliti se recomand cteva principii ale proiectrii orientate obiect:
- Principiul responsabilitii unice (SRP=Single Responsability Principle): Fiecare funcie din sistemul
proiectat trebuie s corespund unei clase; modificri ntr-o clas din sistem nu trebuie s conduc la
modificri n celelalte clase.
- Principiul deschis-nchis (OCP =Open-Close principle): O clas trebuie s fie deschis pentru extinderi dar
nchis pentru modificri ale clasei; adugarea de funcii unei clase nu se va face prin modificarea clasei ci
prin reutilizarea ei n alte clase (prin derivare sau delegare ).
- Principiul substituiei de tipuri (LSP=Liskov Substitution Principle): Inlocuirea unui subtip S cu tipul mai
general T nu trebuie s afecteze comportarea programului; nu orice ierarhie de clase corespunde unei ierarhii
de tipuri.
- Principiul separrii interfeelor (ISP=Interface Segregation Principle): Dependenele dintre dou clase
trebuie s se bazeze pe o interfa minim; un client nu trebuie s depind de o interfa pe care nu o
folosete.
Principalele recomandri care rezult din analiza soluiilor de proiectare confirmate de practic sunt:
- Compoziia (delegarea) este preferabil de multe ori extinderii (derivrii).
- Proiectarea cu interfee i clase abstracte este preferabil fa de proiectarea cu clase concrete, pentru c
permite separarea utilizrii de implementare.
- Este recomandat crearea de clase i obiecte suplimentare, cu rol de intermediari, pentru decuplarea unor
clase cu roluri diferite

- 106 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

IE.08.2 abloane de proiectare


Experiena acumulat n realizarea unor aplicaii cu clase a condus la recunoaterea i inventarierea unor
scheme de proiectare sau abloane de proiectare (Design Patterns), adic a unor grupuri de clase i obiecte
care coopereaz pentru realizarea unor funcii. In cadrul acestor scheme exis clase care au un anumit rol n
raport cu alte clase i care au primit un nume ce descrie acest rol; astfel exist clase iterator, clase observator,
clase fabric de obiecte, clase adaptor s.a. Dincolo de detaliile de implementare se pot identifica clase cu
aceleai responsabiliti n diferite aplicaii.
Cteva definii posibile pentru abloanele de proiectare folosite n aplicaii cu clase:
- Soluii optime pentru probleme comune de proiectare (Best practices).
- Abstracii la un nivel superior claselor, obiectelor sau componentelor.
- Scheme de comunicare (de interaciune) ntre clase i obiecte.
Argumentul principal n favoarea studierii i aplicrii schemelor de clase este acela c aplicarea acestor
scheme conduce la programe mai uor de modificat. Aceste obiective pot fi atinse n general prin clase
(obiecte) slab cuplate (care tiu ct mai puin unele despre altele) i prin introducerea de obiecte
suplimentare fa de cele rezultate din analiza aplicaiei. Dei efortul de scriere iniial a codului folosind
abloanele de proiectare ar putea fi mai mare, efortul de meninere ulterioar a codului este mai mic.
O clasificare uzual a schemelor de proiectare distinge trei categorii:
- Scheme de creare (Creational patterns) prin care se genereaz obiectele necesare.
- Scheme structurale (Structural patterns), care grupeaz mai multe obiecte n structuri mai mari.
- Scheme de interaciune (Behavioral patterns), care definesc comunicarea ntre clase.
O parte dintre aceste abloane de proiectare sunt utilizate i n clasele Java din bibliotecile SDK: iterator,
adaptor, observator, MVC, fabric de obiecte .a. Multe din abloanele de proiectare sunt aplicate i pot fi
exemplificate prin aplicaii Java cu interfa grafic.

IE.08.3 ablonul Singleton


Uneori este nevoie de un singur obiect de un anumit tip, deci trebuie interzis instanierea repetat a clasei
respective, numit clas Singleton. Exist cteva soluii:
- O clas fr constructor public, cu o metod static care produce o referin la unicul obiect posibil.
- O clas static inclus i o metod static (n aceeai clas exterioar) care instaniaz clasa (pentru a-i
transmite un parametru).
Un exemplu este metoda createEtchedBorder() din clasa BorderFactory care creeaz referine la un obiect
chenar unic :
JButton b1 = new JButton (Etched1), b2= new JButton(Etched2);
Border eb = BorderFactory.createEtchedBorder();
b2.setBorder (eb);

Variante de implementare:
a) Metoda are ca rezultat o referin la un obiect creat la ncrcarea clasei:

- 107 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

public class BorderFactory {


private BorderFactory () , // neinstantiabil
static final EtchedBorder sharedEtchedBorder = new EtchedBorder();
public static Border createEtchedBorder() {
return sharedEtchedBorder;
}
...
// alte metode
}

Clasa BorderFactory (pachetul javax.swing) reunete mai mai multe metode ce produc obiecte chenar de
diferite forme pentru componentele vizuale Swing. Toate obiectele chenar aparin unor clase care respect
interfaa comun Border i care sunt fie clase predefinite, fie clase definite de utilizatori. Exemple de clase
chenar predefinite: EmptyBorder, LineBorder, BevelBorder, TitleBorder i CompundBorder.
b)- Metoda creeaz un obiect numai la primul apel, dup care nu mai instaniaz clasa:
public class BorderFactory {
private EtchedBorder sharedBorder= null;
public Border createEtchedBorder() {
if (sharedBorder==null)
sharedBorder = new EtchedBorder()
return sharedBorder;
}
...
}
Metoda care creeaz obiectul unic este o metod fabric de obiecte, dar care fabric un singur obiect.
Alte exemple pot fi ntlnite n clasa Collections (neinstaniabil) pentru a se crea obiecte din colecii mai
speciale : colecii cu un singur obiect (SingletonSet, SingletonList, SingletonMap) i colecii vide
(EmptySet, EmptyList, EmptyMap). Exemplu:
public class Collections {
public static Set singleton(Object o) {
return new SingletonSet(o);
}
private static class SingletonSet extends AbstractSet {
private Object element;
SingletonSet(Object o) {element = o;}
public int size() {return 1;}
public boolean contains(Object o) {return eq(o, element);}
... // public Iterator iterator() { ... }
}
...
}
// utilizare: crearea unui vector de multimi cu cte un element initial
sets = new ArrayList (n);
for (int i=0;i<n;i++)
sets.add (new TreeSet (Collections.singleton ( new Integer(i) ) ));

- 108 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

IE.08.4 ablonul Iterator


Un iterator este un mecanism de enumerare a componentelor unui obiect agregat, cum ar fi o colecie de
obiecte sau un text format din cuvinte, ntr-un mod unitar i independent de particularitile colectiei.
Desenul urmtor pune n eviden principala metod a unui iterator next(), care furnizeaz urmtorul obiect
din grup, la care se adaug n Java i metoda hasNext() care spune dac mai sunt obiecte n grup sau nu. In
plus, se vede c exist o interfa iterator i, posibil, o interfa pentru obiectele agregat.

Obiectul iterator poate fi creat direct prin instanierea unei clase, cum este StringTokenizer, iar obiectul
agregat (de tip String) este primit ca argument de constructorul obiectului iterator. Clasa StringTokenizer
implementeaz interfaa Enumeration. Exemplu :
String str = " 1, 2 . 3 ; 4. ";
StringTokenizer st = new StringTokenizer(str," .,;");
while (st.hasMoreElements())
System.out.println (st.nextElement());
Pentru coleciile din Java obiectul iterator este creat printr-o metod din clasa colecie (metoda elements()
sau iterator()) i nu prin instaniere direct, deoarece un iterator este asociat unei colecii i nu poate fi creat
dect dup crearea coleciei. Aceste metode ilustreaz ablonul metod fabric de obiecte:
Vector v = new Vector();
for (int i=1; i<9;i++) v.add(i);
Enumeration e = v.elements();
while (e.hasMoreElements())
System.out.print (e.nextElement()+",");

In Java mecanismul iterator a evoluat n timp de la interfaa Enumeration cu dou metode, la interfaa
Iterator cu trei metode i la o form simplificat de iterare prin colecii si vectori, ce corespunde unei
instruciuni "for each" din alte limbaje. Pentru liste Java exist un iterator bidirecional cu metode de
naintare (next()) i de revenire la elementul anterior (previous()). De observat c pentru mulimi iteratorul
este singura posibilitate de acces la elementele mulimii deoarece nu este posibil accesul prin indici (nu
exist noiunea de poziie a unui element n mulime).
Implementarea unui iterator folosete un cursor care depinde de tipul obiectului agregat: pentru extragere de
cuvinte (tokens) cursorul este un indice n cadrul textului, pentru vectori cursorul este un indice ntreg iar
pentru liste nlnuite cursorul este un pointer (o variabil referin n Java). Exemplu:

- 109 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

class StrTok {
String str;
// sirul analizat
int crt;
// pozitia curenta in sir
// constructor
public StrTok (String s) {
str=s; crt=0;
}
public boolean hasMoreTokens () {
return crt < str.length();
}
public String nextToken () {
while ( crt < str.length() && str.charAt(crt)==' ')
++crt;
// ignora spatii
int start= crt;
// inceput de cuvnt
crt= str.indexOf (' ',start); // sfrsit de cuvnt
if ( crt < 0) crt= str.length(); // ultimul cuvnt din sir
return str.substring (start,crt);
}
}

IE.08.5 ablonul Observator


In aceast schem exist un obiect observat care poate suferi diverse modificri i unul sau mai multe
obiecte observator, care trebuie anunate (notificate) imediat de orice modificare n obiectul observat,
pentru a realiza anumite aciuni. Obiectul observat conine o list de referine la obiecte observator i, la
producerea unui eveniment, apeleaz o anumit metod a obiectelor observator nregistrate la el.
Desenul urmtor ilustreaz componentele schemei Observator:

Schema observat-observator a generat clasa Observable i interfaa Observer din pachetul java.util.
Programatorul de aplicaie va defini una sau mai multe clase cu rol de observator, compatibile cu interfaa
Observer. Subiectul supus observaiei conine metode de adugare sau de eliminare a unor observatori. In
desen aceste metode se numesc attach()i detach(), iar n Java se numesc addObserver()i deleteObserver();
metoda notify() din desen se numeste notifyObservers() in clasa Observable.
Interfaa Observer conine o singur metod update(), apelat de un obiect observat la o schimbare n starea
sa i care poate interesa obiectele observator :
public interface Observer { void update(Observable o, Object arg); }
Clasa Observable nu este abstract dar nici nu este direct utilizabil; programatorul de aplicaie va defini o
- 110 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

subclas care preia toate metodele clasei Observable i adaug o serie de metode specifice aplicaiei, care
apeleaz metodele superclasei setChanged() i notifyObservers(). Metoda notifyObservers() apeleaz
metoda update() pentru toi observatorii introdui n vectorul "observers". Metoda getChanged() poate fi
folosit pentru a vedea dac s-a modificat starea subiectului observat, iar metoda setChanged() modific o
variabil intern pentru a semnala modificarea strii subiectului observat.
Urmeaz un exemplu simplu care folosete clasele Java pentru ablonul Observator:
class Observat extends Observable {
private int x;
public void setValue (int x) {this.x=x;}
public int getValue() {return x;}
public void change() { setChanged(); notifyObservers(x); }
}
class Observator implements Observer {
private String nume;
public Observator(String nume){ this.nume=nume;}
public void update( Observable obs, Object x ) {
System.out.println (nume + " " +x);
}
}
class Main {
public static void main (String args[]) {
Observat subiect = new Observat();
Observator ob1 = new Observator("unu");
Observator ob2 = new Observator("doi");
subiect.addObserver(ob1); subiect.addObserver(ob2);
for (int i=1;i<10;i++){
subiect.setValue(i); subiect.change();
}
}
}
O alt utilizare a ablonului Observator este n aplicaiile Java cu interfa grafic: practic toate obiectele
grafice Swing sunt obiecte observabile i genereaz evenimente Swing ca urmare a gesturilor operatorului
(clic pe buton de mouse sau apsare tast de consol); producerea unui eveniment este notificat unor obiecte
numite asculttor (cu rol de observator) nregistrate anterior la sursa de evenimente (subiectul supus
observaiei).
Ordinea n care sunt notificai observatorii sau asculttorii nu este aceeai cu ordinea de adugare a lor la
subiectul observat (n Java este chiar ordinea invers celei de la adugare).

IE.08.6 ablonul Adaptor


Schema "adaptor" permite adaptarea apelurilor de
metode dintr-o clas "Client" la metodele diferite
ca prototip dar echivalente ca efect ale unei clase
"Adaptee". Clientul apeleaz metoda operation()
din adaptor, care va delega execuia ei, prin
variabila
adaptee,
ctre
metoda
adaptedOperation().
- 111 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Schema "Adaptor" o ntlnim la clasele InputStreamReader si OutputStreamWriter care sunt clase


adaptor ntre clasele Stream i clasele Reader-Writer. Clasa adaptor InputStreamReader extinde clasa
Reader (Writer) i conine o variabil de tip InputStream (OutputStream); o parte din operaiile impuse
de superclas sunt realizate prin apelarea operaiilor pentru variabila flux (prin delegare). Este deci un alt
caz de combinare ntre extindere i agregare. Un obiect InputStreamReader poate fi folosit la fel ca un
obiect Reader pentru citirea de caractere, dar n interior se citesc octei i se convertesc octei la caractere.
Exemplul urmtor este o clasa adaptor ntre interfaa Iterator i interfaa mai veche Enumeration, care
permite utilizarea noilor metode pentru clase mai vechi cum este Hashtable.
public class EnumAdapter implements Iterator {
Enumeration enum;
public EnumAdapter (Enumeration enum) { this.enum=enum; }
public Object next() {
return enum.nextElement();
}
public boolean hasNext() {
return enum.hasMoreElements ();
}
public void remove () { }
}
In Java noiunea de clas adaptor este folosit i pentru clase care implementeaz prin metode cu efect nul o
interfa cu mai multe metode. In acest ultim caz se simplific definirea unor clase care implementeaz
numai o parte din metodele interfeei. De exemplu, interfaa MouseInputListener conine metode apelate la
aciuni pe mouse (apsare sau eliberare buton: mouseClicked(), mousePressed(), mouseReleased()) i
metode apelate la deplasare mouse (mouseMoved(), mouseDragged()). Clasa MouseInputAdapter ofer o
implementare nul pentru toate cele 7 metode.

IE.08.7 ablonul Compozit


Schema "compozit" se aplic structurilor ierarhice, n care orice component este compus din alte
componente. Un arbore general (multici) este imaginea cea mai bun pentru o structur compozit:
elementul "Leaf" din figur este un nod frunz, iar elementul "Component" este un nod interior, care poate fi
privit ca rdcina unui subarbore. Fiecare component (nod) poate fi tratat ca un obiect separat sau ca un
grup de obiecte, folosind aceeai interfa. Exemple concrete de structuri compozit sunt arbori DOM pentru
documente HTML/XML, arbori pentru expresii din limbajele de programare, liste de produse BOMP (Bill of
Material Processor) .a.

- 112 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Exemplul urmtor arat cum se poate face evaluarea unor expresii aritmetice care conin doar numere ntregi
ca operanzi i caiva operatori binari, expresii reprezentate prin arbori. Interfaa "Expression" din program
corespunde interfeei "Component" din figur iar metoda eval() din program corespunde metodei
operation() din figur.
interface Expression { int eval(); }
public class Expr implements Expression {
protected TNode node;
public Expr(TNode node) { this.node=node;}
public int eval () {
if (node==null) return 0;
if (node.isLeaf()) return new Leaf(node).eval();
else return new BinExpr(node).eval();
}
}
class Leaf extends Expr implements Expression {
public Leaf(TNode node){ super(node);}
public int eval() {
return (Integer)node.getUserObject();
}
}
class BinExpr extends Expr implements Expression {
public BinExpr(TNode node){ super(node);}
private Expr left,right;
public int eval(int op) {
return evalBin( op,left.eval(), right.eval() );
}
int evalBin (int op, int lval, int rval){
switch (op){
case '+': return lval+rval;
case '-': return lval-rval;
case '*': return lval*rval;
}
return 0;
}
}

IE.08.8 ablonul Decorator


Schema "decorator" permite adugarea
dinamic (la execuie) de noi responsabiliti
i moduri de comportare unor obiecte, atunci
cnd nu se poate folosi doar derivarea n acest
scop. Se spune c o clas primete noi
"decoraiuni" (faciliti) de la clasa decorator.
Un decorator nu adaug funcii noi clasei
decorate dar modific aciunea unor metode
existente prin delegare ctre metode ce provin
din obiectul transmis ca argument la
construirea unui obiect decorator (i care nlocuiete o variabil de tip interfa din clasa decorator).

- 113 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Clasele filtru de I/E din Java fac parte din categoria claselor decorator. Principalele clase filtru de I/E sunt:
FilterInputStream, FilterOutputStream i FilterReader, FilterWriter. Clasele de tip filtru sunt clase
intermediare, din care sunt derivate clase care adaug operaii specifice (de prelucrare): citire de linii de
text de lungime variabil, citire-scriere de numere n format intern, scriere numere cu conversie de format
s.a. O clas anvelop de I/E conine o variabil de tipul abstract OutputStream sau InputStream, care va fi
nlocuit cu o variabil de un tip flux concret (FileOutputStream s.a.), la construirea unui obiect de un tip
flux direct utilizabil. Clasa FilterInputStream este derivat din InputStream i conine o variabil de tip
InputStream. Metoda read() este o metod polimorfic, iar selectarea metodei necesare se face n functie de
tipul concret al variabilei "in" (transmis ca argument constructorului). Metoda read() din clasa
FilterInputStream preia functionalitatea metodei read() din clasa delegat, sau deleag operatia de citire
ctre clasa folosit la construirea obiectului filtru.
public class FilterInputStream extends InputStream {
protected InputStream in;
protected FilterInputStream (InputStream in) { // constructor
this.in=in;
// stabilire tip obiect "flux de I/E"
}
// citirea unui octet
public int read () throws IOException {
return in.read ();
// citirea depinde de tipul fluxului
}
... // alte metode
}
Clasele DataInputStream, BufferedInputStream, PushbackInputStream, LineNumberInputStream
sunt derivate din clasa FilterInputStream si contin metode de prelucrare a datelor citite. Cea mai folosit
este clasa DataInputStream care adaug metodelor de citire de octeti mostenite si metode de citire a tuturor
tipurilor primitive de date: readLine(), readInt(), readFloat() etc.
// "decorare" repetata, cu adaugare de facilitati la op. de I/E
public static void main (String arg[]) throws IOException {
FileInputStream fis= new FileInputStream (arg[0]);
// flux cu suport
fisier
BufferedInputStream bis = new BufferedInputStream (fis); // plus buffer de
citire
DataInputStream dis = new DataInputStream (bis); // plus operatii de citire de
linii si numere
String linie;
while ( (linie=dis.readLine()) != null)
System.out.println (lnis.getLineNumber()+" "+linie);
}

IE.08.9 ablonul Fabric de obiecte


Crearea de noi obiecte se face de obicei prin instanierea unei clase cu nume cunoscut la scrierea
programului. O soluie mai flexibil pentru crearea de obiecte este utilizarea unei fabrici de obiecte, care
las mai mult libertate n detaliile de implementare a unor obiecte cu comportare predeterminat. O fabric
de obiecte (Object Factory) permite crearea de obiecte de tipuri diferite, dar toate subtipuri ale unui tip
comun (interfa sau clas abstract).

- 114 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Utilizarea fabricilor de obiecte poate fi privit ca un pas nainte pe calea separaiei interfa-implementare, n
sensul c permite oricte implementri pentru o interfa, cu orice nume de clase i cu orice date iniiale
necesare fabricrii obiectelor.
O fabric de obiecte se poate realiza n dou forme:
- Ca metod fabric (de obicei metod static) dintr-o clas, care poate fi clasa abstract ce definete tipul
comun al obiectelor fabricate. Aceast soluie se practic atunci cnd obiectele fabricate nu difer mult ntre
ele.
- Ca o clas fabric, atunci cnd exist diferene mari ntre obiectele fabricate. Alegerea (sub)tipului de
obiecte fabricate se poate face fie prin parametri transmisi metodei fabric sau constructorului de obiecte
fabric, fie prin fiiere de proprieti (fiiere de configurare).
O metod fabric poate fi o metod static sau nestatic. Metoda fabric poate fi apelat direct de
programatori sau poate fi apelat dintr-un constructor, ascunznd utilizatorilor efectul real al cererii pentru
un nou obiect. Desenul urmtor corespunde unei metode fabric din clasa Creator avnd ca rezultat un
obiect de tipul general Product.

Se folosesc metode fabric atunci cnd tipul obiectelor ce trebuie create nu este cunoscut exact de
programator, dar poate fi dedus din alte informaii furnizate de utilizator, la execuie. Rezultatul metodei este
de un tip interfa sau clas abstract, care include toate subtipurile de obiecte fabricate de metod.
Un exemplu de metod fabric controlabil prin argumente este metoda getInstance() din clasa Calendar,
care poate crea obiecte de diferite subtipuri ale tipului Calendar , unele necunoscute la scrierea metodei dar
adugate ulterior. Obiectele de tip dat calendaristic au fost create iniial n Java ca instane ale clasei
Date, dar ulterior s-a optat pentru o soluie mai general, care s in seama de diferitele tipuri de calendare
folosite pe glob. Clasa abstract Calendar (din java.util) conine cteva metode statice cu numele
getInstance() (cu i fr parametri), care fabric obiecte de tip Calendar. Una din clasele instaniabile
derivat din Calendar este GregorianCalendar, pentru tipul de calendar folosit n Europa. Metoda
getInstance() fr argumente produce un obiect din cel mai folosit tip de calendar:
public static Calendar getInstance() { return new GregorianCalendar(); }
Obiectele de tip Calendar se pot utiliza direct sau transformate n obiecte Date:
Calendar azi = Calendar.getInstance();
Date now = azi.getTime();
// conversie din Calendar in Date
System.out.println (now);
Metoda getInstance() poate avea unul sau doi parametri, unul de tip TimeZone i altul de tip Local, pentru
adaptarea orei curente la fusul orar (TimeZone) i a calendarului la poziia geografic (Local). Tipul
obiectelor fabricate este determinat de aceti parametri.
- 115 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Alte metode fabric care produc obiecte adaptate particularitilor locale (de ar) se afl n clase din
pachetul java.text: NumberFormat, DateFormat, s.a. Adaptarea se face printr-un parametru al metodei
fabric care precizeaz ara i este o constant simbolic din clasa Locale. Afiarea unei date calendaristice
se poate face n mai multe forme, care depind de uzanele locale i de stilul dorit de utilizator (cu sau fr
numele zilei din sptmn, cu nume complet sau prescurtat pentru lun etc.). Clasa DateFormat conine
metoda getDateInstance() care poate avea 0,1 sau 2 parametri i care poate produce diferite obiecte de tip
DateFormat. Exemple:
Date date = new Date();
DateFormat df1 = DateFormat.getDateInstance ();
DateFormat df2 = DateFormat.getDateInstance (2, Locale.FRENCH);
System.out.println ( df1.format(date));
//luna, an, zi cu luna in engleza
System.out.println ( df2.format(date));
// zi,luna,an cu luna in franceza

IE.08.10 ablonul Fabric abstract


Obiectele de tip fabric pot fi la rndul lor fabricate printr-o metod, atunci cnd ele au subtipuri ale unui
tip comun. Fabrica de fabrici se numete fabric abstract (AbstractFactory). Ideea este de a decupla
beneficiarul (clientul) unor servicii de particularitile furnizorului de servicii, atunci cnd exist mai multi
furnizori posibili sau se anticipeaz c pot aprea i alte implementri pentru fabrica de obiecte.
Desenul urmtor arat cum clientul folosete un tip general (abstract) pentru fabrica de obiecte, obiectele
produse fiind i ele de un tip mai general (interfa sau clas abstract):

Exemple de servicii: acces la orice baz de date relaional (JDBC), comunicarea prin mesaje (JMS), analiz
de fiiere XML. Un parser XML de tip DOM este un program care analizeaz documente XML, semnaleaz
erori formale i creeaz un arbore echivalent documentului XML. Exist mai multe programe parser de la
diferii furnizori i este posibil s apar si alte parsere DOM mai performante n viitor. Deci nu exist o
singur clas parser DOM dar exist o interfa numit DocumentBuilder ce corespunde interfeei
AbstractProduct din desenul anterior. Toate clasele parser DOM trebuie s respecte aceast interfa, cu
metode de acces la arborele DOM. Numele i numrul acestor clase parser nu este cunoscut, deci nu se poate
obine un obiect parser prin instanierea unei clase. Numele clasei parser nu apare n aplicaie pentru a nu fi
necesar modificarea surselor aplicaiei la schimbarea tipului de parser (decuplare utilizare de
implementare). Numele clasei parser este determinat la execuia aplicaiei de ctre o metod fabric
newInstance(), care selecteaz acest nume dup un algoritm: dintr-un fiier de proprieti sau o clas parser
implicit dac nu apare alta n fiierul de proprieti. Fabrica de clase parser este DocumentBuilderFactory
i corespunde clasei AbstractFactory din desen; metoda newInstance() corespunde unei metode
createProduct() din desen.
- 116 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Secvena urmtoare arat cum se obine i cum se folosete un obiect parser DOM . Acest cod nu conine
nici un nume de clas parser; obiectul parser este produs de metoda fabric newDocumentBuilder() aplicat
unui obiect produs de metoda fabric static newInstance().
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); // obiect fabric
DocumentBuilder builder = factory.newDocumentBuilder(); // obiect parser
Document doc = builder.parse( new File(arg[0]) );
// creare arbore DOM dintr-un fisier

IE.08.11 ablonul Model-View-Controller


Schema MVC (Model-View-Controller) extinde schema "Observat-observator". Un obiect model este un
obiect observat ( ascultat), care genereaz evenimente pentru obiectele receptor nregistrate la model.
Arhitectura MVC foloseste clase avnd trei roluri principale:
- Clase controller, cu rol de comand a unor modificri n model ca urmare a unor evenimente externe.
- Clase model, cu rol de obiect observat care conine date i prelucrri ale acestor date.
- Clase view, cu rol de redare vizual a strii modelului, fiind obiect observator al modelului.

Schema MVC a aprut n legtur cu programele de birotic (pentru calcul tabelar i pentru editare de texte),
de unde i numele alternativ de Document-View-Controller. Separarea net a celor trei componente (M, V si
C) permite mai mult flexibilitate n adaptarea i n extinderea programelor, prin uurina de modificare
separat a fiecrei pri (n raport cu un program monolit la care legturile dintre pri nu sunt explicite).
Astfel, putem modifica structurile de date folosite n memorarea foii de calcul (modelul) fr ca aceste
modificri s afecteze partea de prezentare, sau putem aduga noi forme de prezentare a datelor coninute n
foaia de calcul sau noi forme de interaciune cu operatorul (de exemplu, o bar de instrumente toolbar).
Separarea de responsabiliti oferit de modelul MVC este util pentru realizarea de aplicaii sau pri de
aplicaii: componente GUI, aplicaii Web de tip client-server s.a.
Practic toate aplicaiile Web sunt construite n prezent dup schema MVC, care se reflect i n structura de
directoare a aplicaiei. In aplicaiile Web partea de model conine clasele ce corespund tabelelor bazei de
date (inclusiv logica de utilizare a acestor date), partea de vizualizare corespunde interfeei cu utilizatorul
(obiecte grafice afiate n browser, validri asupra datelor introduse de operator, animaie i alte efecte
vizuale), iar partea de comand (controller) corespunde prelurii cererilor HTTP i transmiterii rspunsurilor
corespunztoare (care include de obicei date din model ).
Unele componente Swing sunt construite dup schema MVC i au n componena lor un obiect model:
JButton, JList, JTable, JTree .a. Modelul este o structur de date care poate genera evenimente i este
specific fiecrei componente: DefaultButtonModel, DefaultListModel, DefaultTableModel, etc.
- 117 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Exemplul care urmeaz folosete dou butoane i un cmp text i este structurat dup arhitectura MVC.
Componenta model (clasa Model) conine ca date un numr ntreg i genereaz evenimente la modificarea
valorii acestui numr. Clasa Controller trateaz evenimentele de la butoane, prin care operatorul aplicaiei
poate modifica starea modelului (valoarea din model). Clasa View reunete toate componentele de interfa
grafic (butoane i cmp text) i modific afisarea din cmpul text ca urmare a modificrii modelului
(reflect starea modelului).
Clasa controler reunete asculttorii la butoanele care controleaz starea modelului:
class Controller implements ActionListener {
private Model m;
public Controller (Model m) { this.m=m; }
public void actionPerformed (ActionEvent evt){
JButton b = (JButton) evt.getSource();
String txt = b.getActionCommand();
int x= m.getElement();
if (txt.equals("+")) m.setElement (x+1);
if (txt.equals("-")) m.setElement (x-1);
}
}
Clasa model genereaz eveniment PropertyChangeEvent la modificarea valorii memorate n model:
class Model extends JComponent {
int value;
// date din model (proprietate a componentei JFC)
public void setElement (int x) {
// la modificare proprietate
firePropertyChange ("value",value,value=x);
}
public int getElement () {return value; } // valoare proprietate
}
Clasa cu imaginea aplicaiei:
class View extends JFrame implements PropertyChangeListener {
JButton b1,b2;
JTextField t = new JTextField (6);
Model m; Controller c;
public View(Model m, Controller c) {
this.m=m; this.c=c;
b1= new JButton("+"); b2= new JButton("-");
m.addPropertyChangeListener ("value",this);
setLayout (new FlowLayout());
add (t); add(b1); add(b2);
b1.addActionListener (c); b2.addActionListener (c);
setSize(200,100); setVisible(true);
}
// reactioneaza la evenimente din model
public void propertyChange (PropertyChangeEvent ev) {
int x = m.getElement(); t.setText (""+x);
}
}
- 118 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Dependentele dintre clase sunt transmise aici prin contructori, dar n general se folosesc metode care transmit
unui obiect adresa unui alt obiect (injectare dependente prin metode):
public static void main (String args[]) {
Model m = new Model ();
Controller c = new Controller (m);
View v = new View(m,c);
v.go();
// pornire aplicatie
}

E.08.12 ablonul Injectarea Dependenelor


Un principiu general de proiectare a aplicaiilor complexe este acela c ntre modulele unei aplicaii cuplajul
trebuie s fie ct mai slab, astfel ca nlocuirea unui modul cu un altul s nu necesite (multe) modificri n
celelalte module care depind de cel nlocuit. Avantajele aplicaiilor formate din obiecte slab cuplate sunt:
nlocuirea unui obiect cu altul care respect aceeai interfa este mai simpl i mai rapid, reutilizarea unor
pri dintr-o aplicaie n alte aplicaii este facilitat, la realizarea aplicaiei pot lucra mai multe persoane
(echipe) n paralel, ntreinerea (modificarea) codului este simplificat, testarea unitar a codului este
simplificat.
Cuplajul slab folosete interfee sau clase abstracte: un obiect vede obiectele cu care colaboreaz ca
interfee deci ca abstracii ale obiectelor reale. Soluiile de realizare a unui cuplaj slab ntre obiectele care
comunic fac parte din schemele de proiectare bazate pe bune practici (Design Patterns) i au evoluat de la
fabrici de obiecte la localizarea serviciilor (Service Locator) i la injectarea dependentelor (Dependency
Injection). Schemele Service Locator si Dependency Injection nu se exclud reciproc, iar containerele Apache
Avalon i Google Guice injecteaz n aplicaii referine la obiecte ServiceLocator.
La injectarea dependentelor se vorbete despre o inversare a controlului, n sensul c gestiunea legturilor
dintre componente nu mai revine aplicaiei ci unui asamblor de componente, numit container sau
framework, care injecteaz n aplicaie referinele la obiectele apelate prin nume simbolice.
Relaia dintre dou obiecte care colaboreaz este privit uneori ca relaie dintre un obiect care ofer anumite
servicii (Service Object) i un obiect care foloseste sau consum aceste servicii (Client Object). In testarea
unitar relaia dintre obiecte este privit ca o dependen: un obiect (client) depinde de serviciile oferite de
un alt obiect (furnizor de servicii).
Ca exemplu vom considera un obiect filtru care selecteaz dintr-o colecie de obiecte pe cele care satisfac o
anumit condiie. Colecia complet de obiecte este produs de un obiect de tip DAO (Data Access Object)
care extrage aceste date dintr-o baz de date sau dintr-un fiier. In practic DAO este o clas abstract sau o
interfa, care suport diverse implementri ce depind de modul de acces la datele externe: JDBC, Hibernate,
JPA, JDO, etc. In cazul nostru interfaa Dao are o singur metod findAll(), dar de obicei are mai multe
metode. Interfeele i clientul pentru serviciile Dao pot arta astfel:

- 119 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

public interface Dao { // orice obiect Dao va contine metoda findAll


public List findAll ();
}
public interface Filter { // orice obiect Filter va contine metoda accept
public boolean accept (Object obj);
}
public class DaoClient { // foloseste obiecte de tip Dao
private Dao dao;
public List findBy (Filter filter){
List all = dao.findAll ();
for (Iterator it= all.iterator();it.hasNext();)
if (! filter.accept(it.next())) // daca nu e acceptat de filtru
it.remove();
// se elimina din lista
return all;
}
}
Prin definirea interfeei Dao s-a realizat o decuplare parial a obiectului DaoClient de implementarea
efectiv a metodei findAll() i de organizarea datelor externe, care se poate modifica oricnd fr s necesite
modificri i n clasa client. Putem avea diverse clase care implementeaz interfaa Dao i care obin datele
din fisiere text sau XML, dintr-un tabel SQL sau prin intermediul unui serviciu Web.
Pentru a obine o aplicaie executabil trebuie s putem lega un obiect client de un obiect al unei clase
DaoImpl (care implementeaz interfaa Dao) i de un obiect filtru. Aceast legare (binding) sau asamblare
de obiecte se face dup compilare (dar nainte de execuie) i poate fi realizat de:
- Obiectul client, care folosete o fabric de obiecte compatibile cu interfaa Dao: schema Object Factory
- Obiectul client, care caut (localizeaz) obiectul DaoImpl folosind un serviciu de nume i directoare
(compatibil JNDI pentru aplicaii Java): schema Service Locator.
- Un container (un framework) care injecteaz n obiectul client o referin ctre obiectul care
implementeaz interfaa Dao: schema Dependency Injection.
In primele dou cazuri obiectul client mai depinde i de un alt obiect: fabrica de obiecte sau serviciul de
localizare (care este un dicionar ce asociaz nume cu referine la obiecte).
Exemplu de utilizare a unei fabrici de obiecte (ca metod static):
class DaoFactory {
private static Dao dao= new DaoImpl();
public static Dao getInstance() { return dao; }

}
// utilizare
public class DaoClient {
public List findBy (Filter f) {
Dao dao= DaoFactory.getInstance();
List all = dao.findAll ();

}
}
- 120 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Obiectul care injecteaz dependenele trebuie s dispun de informaii despre obiectele pe care le injecteaz
(nume i referine); aceste informaii se transmit de ctre persoana care dezvolt aplicaia fie prin fisiere de
configurare XML, fie prin adnotri Java introduse n codul surs.
Injectarea ntr-un obiect a unei
referine ctre un alt obiect se poate face n trei moduri:
- Prin constructorul clasei (Constructor Injection)
- Printr-o metod a clasei (Setter Injection)
- Printr-o interfa de injectare (Interface Injection)
Injectarea prin constructor necesit adugarea unui constructor cu argument de tip Dao:
public class DaoClient {
private Dao dao;
public DaoClient (Dao dao) { this.dao=dao;}
public List findBy (Filter filter) , }
Injectarea printr-o metod necesit adugarea unei metode de modificare a variabilei dao:
public class DaoClient {
private Dao dao;
public setDao (Dao dao) { this.dao=dao;}
public List findBy (Filter filter) , }
Injectarea prin interfa necesit definirea unei interfee, iar clasa client va implementa aceast interfa:
public interface InjectDao { void injectDao (Dao dao); }
public class DaoClient implements InjectDao {
private Dao dao;
public void injectDao(Dao dao){ this.dao=dao; }
public List findBy (Filter f) , }
Exemplu de transmitere ctre container a informaiilor necesare injeciei (Spring framework):
<beans>
<bean id="DaoClient" class="spring.DaoClient">
<property name="dao">
<ref local="Dao"/>
</property>
</bean>
<bean id="Dao" class="spring.DaoImpl">
<property name="file">
<value>date.txt</value>
</property>
</bean>
</beans>

Exemplu de utilizare a metodei findBy() n Spring:

- 121 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

public void testWithSpring() throws Exception {


ApplicationContext ctx = new FileSystemXmlApplicationContext("spring.xml");
DaoClient finder = (Dao) ctx.getBean("Dao");
List result = finder.findBy( new MyFilter());
}

Produsele de tip container (Framework) cu injectare dependene pentru aplicaii Java pot fi clasificate n:
- Produse simple, pentru verificarea aplicabilitii schemei DI pe aplicaii cu cerine reduse:
Pico Container & NanoContainer, Avalon (Apache), HiveMind (Apache), s.a.
- Produse complexe, folosite efectiv pentru aplicaii reale:
Spring Framework, Guice (Google), Weld/ Web Beans (JBoss)
Pe platforma .Net (C#) exist de asemenea mai multe containere DI:
StructureMap, ObjectBuilder, SpringFramework.Net, Unity , MEF (Microsoft Extensibility Framework).
Tendinele mai noi n realizarea unor containere cu injectarea de dependene sunt:
- Utilizarea de adnotri Java n locul fiierelor de configurare pentru specificarea obiectelor care vor fi
injectate de container i a punctelor de injectare (JEE6, Guice, Spring Framework);
- Asocierea unui context (unui ciclu de viat) obiectelor injectate i gestiunea strii obiectelor de ctre
container, de unde i denumirea de CDI (Context and Dependency Injection) din JEE6.
- Inseria de ctre container a unor secvene de cod n puncte specificate, deci programare orientat pe
aspecte (AOP) sau interceptori sau orthogonal concerns. AOP (Aspect Oriented Programming) nseamn
pe scurt injectarea unor secvene pentru apelarea unor servicii n diverse puncte specificate de programator,
dar care nu corespund n general cu fluxul logic. Un exemplu este inseria de apeluri ctre un serviciu de
logger pentru nscrierea de mesaje ntr-un fiier de tip log (jurnal de evenimente).

- 122 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Capitolul IE.09. Interfee grafice i programare orientat pe evenimente


Cuvinte cheie
Interfa grafic, Componente vizuale, Fereastr,
Componente atomice, Container Swing, Clase model,
Evenimente Swing ,Asculttori, Programare bazat pe evenimente

IE.09.1 Aplicaii cu interfa grafic


Comunicarea dintre un program de aplicaie i utilizatorul aplicaiei poate folosi ecranul n modul text sau n
modul grafic. Majoritatea aplicaiilor actuale preiau datele de la operatorul uman n mod interactiv, printr-o
interfa grafic, pus la dispoziie de sistemul de operare gazd. Interfaa grafic cu utilizatorul (GUI =
Graphical User Interface) este mai sigur i mai "prietenoas", folosind att tastatura ct i mouse-ul pentru
introducere sau selectare de date afisate pe ecran.
O interfa grafic simpl const dintr-o singur fereastr ecran a aplicaiei pe care se plaseaz diverse
componente vizuale interactive, numite i controale (controls) pentru c permit operatorului s
controleze evoluia programului prin introducerea unor date sau opiuni de lucru (care, n mod text, se
transmit programului prin linia de comand). Uneori, pe parcursul programului se deschid i alte ferestre, dar
exist o fereastr iniiala cu care ncepe aplicaia. O fereastr (Window) este o zon dreptunghiular din
ecran, cu nargini orizontale si verticale.
Programele cu interfa grafic sunt controlate prin evenimente externe, produse fie de apsarea unei taste
fie de apsarea unui buton de mouse. Un eveniment des folosit este cel produs de poziionarea cursorului pe
suprafaa unui buton desenat pe ecran i apsare (clic) pe butonul din stnga de pe mouse. Tipul
evenimentelor este determinat de componenta vizual implicat dar i de operaia efectuat. De exemplu,
ntr-un cmp cu text terminarea unei linii de text (cu tasta Enter) genereaz un tip de eveniment, iar
modificarea unor caractere din text genereaz un alt tip de eveniment.
Un mare avantaj al limbajului Java, fa de limbaje ca C, C++ este acela c programele Java cu interfa
grafic nu depind de sistemul de operare gazd, clasele i metodele folosite fiind aceleai. Limbajul Java
permite, fat de alte limbaje, programarea mai simpl i mai versatil a interfeei grafice prin numrul mare
de clase i de faciliti de care dispune. De exemplu, aspectul (Look and Feel) componentelor vizuale poate
fi ales dintre patru variante, indiferent de sistemul de operare gazd.
In termenii specifici Java, componentele vizuale sunt de dou categorii:
- Componente atomice, folosite ca atare i care nu pot conine alte componente (un buton este un exemplu
de component atomic);
- Componente container, care grupeaz mai multe componente atomice i/sau containere. Componentele
container sunt i ele de dou feluri:
- Containere de nivel superior (top-level) pentru fereastra principal a aplicaiei;
- Containere intermediare (panouri), incluse n alte containere i care permit operaii cu un grup de
componente vizuale (de exemplu, poziionarea ntregului grup).
Componentele atomice pot fi grupate dup rolul pe care l au :
- Butoane de diverse tipuri: butoane simple, butoane radio
- Elemente de dialog
- Componente pentru selectarea unei alternative (opiuni)
- 123 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

- Indicatoare de progres a unor activiti de durat


- Componente cu text de diverse complexiti: cmp text, zon text, documente
- Panouri cu derulare vertical sau orizontal (pentru liste sau texte voluminoase)
- Meniuri i bare de instrumente
In programarea cu obiecte fiecare component a unei interfee grafice este un obiect dintr-o clas predefinit
sau dintr-o subclas a clasei de bibliotec. Colecia claselor GUI constituie un cadru pentru dezvoltarea de
aplicaii cu interfa grafic, n sensul c asigur o baz de clase esentiale i impune un anumit mod de
proiectare a acestor aplicaii i de folosire a claselor existente. Acest cadru (Framework) mai este numit i
infrastructur sau clase de baz (Foundation Classes).
Ca infrastructur pentru aplicaiile Java cu interfa grafic vom considera clasele JFC (Java Foundation
Classes), numite i Swing, care reprezint o evoluie fa de vechile clase AWT (Abstract Window Toolkit).
Multe din clasele JFC extind sau folosesc clase AWT. Clasele JFC asigur elementele necesare proiectrii de
interfee grafice complexe, atrgtoare i personalizate dup cerinele aplicaiei i ale beneficiarilor,
reducnd substanial efortul de programare a unor astfel de aplicaii (inclusiv editoare de texte, navigatoare
Web i alte utilitare folosite frecvent).

IE.09.2 Clase Java pentru o interfa grafic


Pachetul javax.swing conine un numr mare de clase pentru interfee grafice; o parte din ele sunt folosite ca
atare (prin instaniere) iar altele asigur doar o baz pentru definirea de clase derivate.
Clasele JFC ar putea fi grupate astfel:
- Componente atomice: JButton, JLabel, JTextField, JList, JTable, JTree, etc.
- Clase container: JFrame, JPanel, JDialog, JApplet, etc.
- Clase auxiliare: clase pentru dispunerea componentelor atomice ntr-un container (Layout Manager), clase
asculttor la evenimente, clase model, clase pentru borduri (margini), etc.
O alt clasificare a claselor Swing n raport cu clasele AWT este urmtoarea:
- Clase JFC care au corespondent n clasele AWT, avnd aproape acelai nume (cu prefixul 'J' la clasele JFC)
i acelai mod de utilizare: JComponent, JButton, JCheckBox, JRadioButton, JMenu, JComboBox,
JLabel, JList, JMenuBar, JPanel, JPopUpMenu, JScrollBar, JScrollPane, JTextField, JTextArea.
- Clase JFC noi sau extinse: JSlider, JSplitPanel, JTabbedPane, JTable, JToolBar, JTree, JProgressBar,
JInternalFrame, JFileChooser, JColorChooser etc.
- Clase de tip model, concepute conform arhitecturii MVC (Model-View-Controller):
DefaultButtonModel, DefaultListSelectionModel, DefaultTreeModel, AbstractTableModel etc.
Clasele JFC container de nivel superior sunt numai trei: JFrame, JDialog si JApplet. Primele dou sunt
subclase (indirecte) ale clasei Window din AWT. Toate celelalte clase JFC sunt subclase directe sau
indirecte ale clasei JComponent, inclusiv clasa container intermediar JPanel.
Controalele JFC pot fi inscripionate cu text i/sau cu imagini (ncrcate din fiiere GIF sau definite ca iruri
de constante n program). In jurul componentelor pot fi desenate borduri , fie pentru delimitarea lor, fie
pentru crearea de spaii controlabile ntre componente vecine.
Un program minimal cu clase JFC, creaz i afieaz componentele vizuale pe ecran, fr s trateze
evenimentele asociate acestor componente. Cea mai mare parte dintr-un astfel de program creaz n memorie
structurile de date ce conin atributele componentelor vizuale i relaiile dintre ele: se creaz un obiect
fereastr (panou), care constituie fundalul pentru celelalte componente; se creaz componente atomice i se
adaug la panou obiectele grafice create de programator (cu metoda add()).
- 124 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

In final, se stabilesc dimensiunile ferestrei principale (metoda setSize() sau pack()) si se comand afiarea
ferestrei principale (metoda setVisible() sau show()). Fereastra principal a aplicaiei este n general de tipul
JFrame i conine o bar de titlu i trei butoane standard n colul dreapta-sus al ferestrei pentru operaii
de micsorare (minimizare), mrire (maximizare) i nchidere fereastr(X) .
Exemplul urmtor afieaz o fereastr cu titlu, dar fr alte componente vizuale :
import javax.swing.*;
class EmptyFrame {
public static void main ( String args[]) {
JFrame frm = new JFrame(EmptyFrame);
frm.setSize(500,300)
// sau frm.pack();
frm.setVisible (true);
// sau frm.show();
}
}

In lipsa unui apel al metodelor setSize() sau pack() , fereastra principal se afieaz iniial ntr-o form
redus la bara de titlu cu cele 3 butoane generale, dup care poate fi mrit. Metoda setSize() permite
afiarea ferestrei JFrame de la nceput cu dimensiunile dorite.
Adugarea de componente atomice la containerul JFrame se face cu metoda add(), aceeai metod de
adugare a unui nou element la un vector (obiect de tip Vector), deoarece clasa JFrame folosete un vector
ca o colecie de obiecte grafice. Exemplu de interfa cu o etichet JLabel:
public static void main (String args[ ]){
JFrame frame = new JFrame();
JLabel label = new JLabel ("Folder");
frame.add(label);
frame.setSize(200,200);
frame.setVisible(true);
}

// fereastra aplicatiei
// creare eticheta
// adauga eticheta la fereastr
// dimensiuni fereastra
// afisare continut fereastr

Dup apelul metodei setVisible() sau show() nu mai trebuie create i adugate alte componente vizuale
ferestrei JFrame, chiar dac se modific datele prezentate n unele din aceste componente (prin metode ale
claselor Swing respective) .
Efectuarea unui clic pe butonul de nchidere al ferestrei principale (X) are ca efect nchiderea ferestrei, dar
nu se termin aplicaia dac nu estre tratat evenimentul produs de acest clic. De aceea este necesar tratarea
acestui eveniment, sau terminarea programului de ctre operator, prin Ctrl-C. O soluie simpl de terminare a
aplicaiei la nchiderea ferestrei principale este apelul unei metode din JFrame:
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);

Adugarea mai multor obiecte grafice la JFrame ridic problema modului de dispunere (Layout) a acestor
componente unele fa de altele, n fereastr.

IE.09.3 Plasarea componentelor


Plasarea componentelor grafice pe un panou se poate face i prin poziionare n coordonate absolute de ctre
programator, dar este mult mai simplu s apelm la un obiect de control al a ezrii n panou (Layout
- 125 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Manager), obiect selectat prin metoda setLayout() din clase container (JFrame,JPanel, .a.) i care
stabilete automat dimensiunile i poziia fiecrei componente ntr-un panou. Pentru fereastra JFrame este
implicit modul de asezare BorderLayout, mod care folosete un al doilea parametru n metoda add() pentru
poziia componentei. Exist 5 poziii posibile: central, sus (nord), jos (sud), stnga (vest) i dreapta (est).
Poziia poate fi specificat fie printr-o constant din clasa BorderLayout, fie printr-un sir de caractere:
Center, North, South, East, West. Exemplu cu o etichet i un cmp text:
class DefaultLayout {
public static void main (String args[ ]) {
JLabel lbl1 = new JLabel ("Directory");
JTextField txt1 = new JTextField (16);
JFrame frm = new JFrame("Simple GUI");
frm.add (lbl1,"West"); frm.add(txt1,"Center");
frm.setVisible(true);
}
}
Dac nu se specific poziia la adugare, atunci componenta este centrat n fereastr, iar dac sunt mai
multe componente, atunci ele sunt suprapuse pe centrul ferestrei i nu se vede dect ultima adugat.
Pentru exemplul anterior este preferabil, ca aspect, s folosim modul de asezare FlowLayout:
public static void main (String arg[]) {
JLabel lbl1 = new JLabel ("Directory");
JTextField txt1 = new JTextField (16);
JFrame frm = new JFrame("Simple GUI");
frm.setLayout (new FlowLayout());
frm.add (lbl1); frm.add(txt1);
frm.setSize (300,80);
frm.show();
}
Modul FlowLayout plaseaz componentele una dup alta de la stnga la dreapta i de sus n jos n funcie de
dimensiunile lor i ale ferestrei principale, ceea ce este foarte comod pentru nceput. Dezavantajul acestui
mod este acela c asezarea componentelor se modific automat atunci cnd se modific dimensiunile
panoului, dimensiunile sau numrul componentelor. Exist diverse metode de a menine poziia relativ a
dou sau mai multe componente vizuale, indiferent de dimensiunile ferestrei.
Alte modaliti de dispunere a componentelor ntr-un panou sunt GridLayout (o matrice de componente
egale ca dimensiune), GridBagLayout, BoxLayout ( aezare compact pe vertical sau pe orizontal, la
alegere) si CardLayout ( componente / panouri care ocup alternativ acelai spaiu pe ecran).
Modurile de aezare mentionate sunt moduri utilizabile n programarea manual a interfeelor grafice,
deoarece un mediu vizual ca NetBeans folosete alte clase (GroupLayout, SpringLayout) pentru plasarea
automat a componentelor ntr-o fereastr, ca urmare a aciunilor de tragere (dragging) a componentelor
de ctre operator pe suprafaa vizual. In cazul unor interfee grafice cu un numr mai mare de componente
este preferabil utilizarea unui mediu vizual pentru aezarea componentelor, codul Java fiind generat
automat.
Utilizarea de containere intermediare JPanel este una din metodele pentru controlul plasrii de obiecte
grafice. Un panou JPanel are modul implicit de plasare FlowLayout, dar care poate fi modificat. Exemplu
de afiare a unui mic formular cu dou rubrici, fiecare cu o eticheta n stnga casetei text unde se vor
- 126 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

introduce datele specificate de etichet:


public static void main (String arg[]) {
JLabel l1 = new JLabel ("Numele");
JLabel l2 = new JLabel ("Adresa ");
JTextField t1 = new JTextField (16);
JTextField t2 = new JTextField (16);
JPanel p1= new JPanel();
JPanel p2= new JPanel();
JFrame frm = new JFrame();
Frm.setLayout(new FlowLayout ( ));
p1.add (l1); p1.add (t1); add (p1);
p2.add (l2); p2.add (t2); add (p2);
frm. setSize (300,200); frm.
setVisible(true);
}

IE.09.4 Structura programelor cu interfa grafic


Crearea i afisarea unei interfee grafice necesit urmtoarele operaii din partea programatorului aplicaiei:
- Crearea unui obiect fereastr principal, de tip JFrame sau de un subtip al tipului JFrame, i stabilirea
proprietilor ferestrei (titlu, culoare, dimensiuni etc.)
- Crearea componentelor atomice i stabilirea proprietilor acestora (dimensiuni, text afisat, culoare, tip
chenar etc.)
- Gruparea componentelor atomice n containere intermediare, care sunt obiecte de tip JPanel sau de un
subtip al acestei clase.
- Adugarea containerelor intermediare la fereastra aplicaiei i stabilirea modului de aezare a acestora,
dac nu se prefer modul implicit de dispunere n fereastr.
- Tratarea evenimentelor asociate componentelor i ferestrei principale, prin definirea de clase de tip
asculttor la evenimentele generate de componentele vizuale.
- Afiarea ferestrei principale, prin metodele clasei JFrame setVisible() sau show().
Exemplele anterioare nu reprezint soluia recomandat pentru programarea unei interfee grafice din mai
multe motive:
- Partea de interfa trebuie separat de partea de logic a aplicaiei, prin clase separate.
- Variabilele referin la obiecte Swing nu vor fi locale metodei main pentru c ele sunt folosite i de alte
metode, inclusiv metode activate prin evenimente.
- Metoda static main trebuie s fie ct mai scurt, redus la crearea unui obiect grafic i, eventual, la
apelarea unei metode pentru acel obiect (obiect dintr-o clas definit de programator pe baza clasei JFrame).
Vom prezenta n continuare trei variante uzuale de definire a prii de interfa grafic dintr-o aplicaie Java
n cazul simplu al unui cmp text nsoit de o etichet ce descrie coninutul cmpului text.
Prima variant folosete o subclas a clasei JFrame:

- 127 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

class GUI1 extends JFrame {


private JLabel lbl1 = new JLabel ("Directory");
private JTextField txt1 = new JTextField (16);
// constructor
public GUI1 ( String title) {
super(title); init();
}
// initializare componente
private void init() {
setLayout(new FlowLayout());
add (lbl1); add(txt1);
setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
setSize (300,100);
}
// activare interfata grafica
public static void main (String arg[]) {
new GUI1("GUI solution 1").show();
}
}
Varianta a doua folosete delegarea sarcinilor legate de afisare ctre un obiect JFrame:
class GUI2 {
private JFrame frame;
private JLabel lbl1 = new JLabel ("Directory");
private JTextField txt1 = new JTextField (16);
// constructor
public GUI2 ( String title) {
frame = new JFrame(title);
init(); frame.show();
}
// initializare componente
private void init() {
frame.setLayout(new FlowLayout());
frame.add (lbl1); frame.add(txt1);
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
frame.setSize (300,100);
}
}
Varianta 3 definete clasa GUI ca o subclas a clasei JPanel:

- 128 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

class GUI3 extends JPanel {


private JLabel lbl1 = new JLabel ("Directory");
private JTextField txt1 = new JTextField (16);
// constructor
public GUI3 () {
init();
}
// initializare componente
private void init() {
add (lbl1);
add(txt1);
// txt1.addActionListener (new TxtListener());
}
public static void main (String arg[]) {
JFrame frame = new JFrame ("GUI solution 3");
frame.add (new GUI3());
// frame.setContentPane(new GUI3());
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
frame.setSize(300,100); frame.show();
}
}
Clasele asculttor la evenimente (TxtListener si altele) sunt de obicei clase incluse n clasa GUI pentru a
avea acces la variabilele ce definesc obiecte JFC.
Variabilele de tipuri JFC ( JLabel, JTextField, s.a) pot fi iniializate la declarare sau n constructorul clasei
GUI, deoarece va exista un singur obiect GUI. Metoda init() de ini ializare a componentelor JFC poate lipsi
dac are numai cteva linii. De observat c pentru clasele GUI constructorul este cea mai important func ie
i uneori singura funcie din clas.

IE.09.5 Programarea bazat pe evenimente


O interfa grafic servete nu numai pentru afiarea de componente grafice pe ecran dar i pentru
introducerea de date sau de comenzi de ctre operatorul aplicaiei. In acest fel se asigur caracterul interactiv
al aplicaiilor cu interfa grafic. Operatorul uman poate folosi mouse-ul sau tastatura pentru a selecta
anumite componente grafice afiate pe ecran. Selectarea nseamn poziionarea cu dispozitivul mouse (sau
cu touchpad) pe o component grafic i click pe butonul din stnga. Selectarea unor componente grafice se
poate face i din tastele cu sgei de pe tastatur. In cazul unui buton afiat (obiect JButton) spunem c n
acest fel se apas pe buton. Majoritatea componentelor Swing afiate pot genera evenimente la selectarea
i apsarea lor. In cazul componentei JTextField se genereaz eveniment i la apsarea tastei Enter pentru
terminare introducere text. Excepie face JLabel care nu poate genera evenimente. Aplicaia cu interfa
grafic trebuie s conin cod care s reacioneze la evenimentele generate de interfaa grafic.
Prelucrrile dintr-o aplicaie cu interfa grafic au loc ca rspuns la evenimente generate de operatorul uman
al aplicaiei. Evenimentele generate de interfaa grafic sunt cele care activeaz funcii (metode) asculttor la
evenimente i nu apeluri efectuate din alte funcii. Acest stil de programare se numete Event Driven
Programming sau Event Based Programming, deci programare bazat pe evenimente.
Programarea dirijat de evenimente (Event Driven Programming) se refer la scrierea unor programe care
reacioneaz la evenimente externe programului (cauzate de operatorul uman care foloseste programul). Prin
eveniment se ntelege aici un eveniment asincron, independent de evoluia programului i al crui moment
de producere nu poate fi prevzut la scrierea programului. Evenimente tipice sunt: apsarea unei taste,
- 129 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

acionarea unui buton de mouse, deplasare mouse s.a. Noiunea de eveniment a aprut ca o abstractizare a
unei ntreruperi externe .
Un program controlat prin evenimente nu iniiaz momentul introducerii datelor, dar poate reaciona prompt
la orice eveniment produs de o aciune a operatorului. Funciile care preiau date nu sunt apelate direct i
explicit de alte funcii din program, ci sunt apelate ca urmare a producerii unor evenimente.
Structura unui program dirijat prin evenimente difer de structura unui program obisnuit prin existena
funciilor speciale de tratare a evenimentelor (Event handlers), care nu sunt apelate direct din program. Intrun program dirijat de evenimente exist dou tipuri principale de obiecte:
- Obiecte generatoare de evenimente (sursa unui eveniment);
- Obiecte receptoare de evenimente (obiecte asculttor).
Clasele generator sunt n general clase JFC sau AWT si ele creeaz obiecte eveniment ca efect al aciunii
operatorului pe suprafaa componentei respective.
Clasele receptor de evenimente sunt scrise de ctre
programatorul aplicatiei pentru c metodele de tratare a evenimentelor observate sunt specifice fiecrei
aplicaii. Aceste clase trebuie s implementeze anumite interfete JFC, deci trebuie s conin anumite metode
cu nume i semntur impuse de clasele JFC.
In Java un eveniment este un obiect de un tip clas derivat din clasa EventObject. Declanarea unui
eveniment are ca efect apelarea de ctre obiectul generator a unei metode din obiectul asculttor, care
primete ca argument un obiect eveniment. Tipul obiectului eveniment este determinat de tipul componetei
GUI care a generat evenimentul dar i de actiunea operatorului uman. De exemplu, un clic pe butonul de
nchidere a unei ferestre JFrame genereaz un alt eveniment dect un clic pe butonul de micorare a
ferestrei.
Evenimentele JFC pot fi clasificate astfel:
- Evenimente asociate fiecrei componente vizuale (buton, cmp text, etc.), generate fie prin mouse, fie din
taste (apsare buton, tastare Enter, .a.).
- Evenimente asociate dispozitivelor de introducere ( mouse sau tastatur).
La fiecare obiect generator de evenimente se pot nregistra (se pot nscrie) mai multe obiecte asculttor
interesate de producerea evenimentelor generate. Operaia de nregistrare se face prin apelarea unei metode
de forma addXListener (din obiectul generator), unde X este numele (tipul) evenimentului si care este
totodat i numele unei interfee.
Un eveniment Swing poate avea mai muli asculttori i un asculttor poate asculta la mai muli generatori
de evenimente. De exemplu, terminarea introducerii ntr-un cmp text se poate face fie prin tasta Enter
(eveniment ActionEvent), fie prin taste cu sgei sau prin mutarea cursorului pe un al cmp (eveniment
FocusLost); ambele evenimente pot avea un singur asculttor.

IE.09.6 Evenimente Swing


Evenimentele generate de componentele JFC pot fi clasificate n:
- Evenimente comune tuturor componentelor JFC: ActionEvent, FocusEvent, KeyEvent, MouseEvent,
ComponentEvent

- 130 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

- Evenimente specifice fiecrui tip de component: ChangeEvent, MenuEvent, ListDataEvent,


ListSelectionEvent, DocumentEvent etc.
Evenimentele comune, motenite de la clasa Component, pot fi descrise astfel:
- ActionEvent : produs de aciunea asupra unei componente prin clic pe mouse.
- ComponentEvent : produs de o modificare n dimensiunea, poziia sau vizibilitatea componentei.
- FocusEvent : produs de focalizarea claviaturii pe o anumit component JFC, pentru ca ea s poat
primi intrri de la tastatur.
- KeyEvent : produs de apsarea unei taste i asociat componentei pe care este focalizat tastatura.
- MouseEvent : produs de apsare sau deplasare mouse pe suprafaa componentei.
Numele evenimentelor apar n clasele pentru obiecte eveniment i n numele unor metode:
add*Listener, remove*Listener.
Un buton este un obiect Swing de tip JButton care genereaz cteva tipuri de evenimente: ActionEvent
(dac s-a acionat asupra butonului), ChangeEvent (dac s-a modificat ceva n starea butonului) s.a. La
apsarea unui buton se creeaz un obiect de tip ActionEvent i se apeleaz metoda numit
actionPerformed() (din interfata ActionListener) pentru obiectul sau obiectele nregistrare ca receptori la
acel buton (prin apelul metodei addActionListener()). Tratarea evenimentului nseamn scrierea unei metode
cu numele actionPerformed care s produc un anumit efect ca urmare a apsrii butonului (prin clic pe
suprafaa sa).
In general nu se trateaz toate evenimentele ce pot fi generate de o component JFC. Dei un buton poate
genera peste 5 tipuri de evenimente, n mod uzual se foloseste numai ActionEvent si deci se apeleaz numai
metoda actionPerformed() din obiectele nregistrate ca receptori pentru butonul respectiv. Se poate spune c
se produc efectiv numai evenimentele pentru care s-au definit asculttori i deci metode de tratare a
evenimentelor. Exemplu de tratare a evenimentului de clic pe un buton, prin emiterea unui semnal sonor la
fiecare clic:
// clasa ptr obiecte ascultator de evenimente
class Listener implements ActionListener {
public void actionPerformed(ActionEvent e) {
Toolkit.getDefaultToolkit().beep();
}
}
// creare buton si asociere cu ascultator
class Beeper {
public static void main ( String args[]) {
JFrame frame = new JFrame();
JButton buton = new JButton("Click Me");
frame.getContentPane().add(buton, BorderLayout.CENTER);
button.addActionListener(new Listener()); // inscriere receptor la buton
frame.setVisible(true);
}
}

- 131 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Pentru a obine acelai efect si prin apsarea unei taste asociate butonului (de exemplu combinaia de taste
Ctrl-C) este suficient s adugm o instruciune: buton.setMnemonic (KeyEvent.VK_C);
Se observ c am folosit clasa asculttor o singur dat, pentru a crea un singur obiect. De aceea se practic
frecvent definirea unei clase asculttor anonime acolo unde este necesar:
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
Toolkit.getDefaultToolkit().beep();
}
});

// definitia clasei receptor

Diferena dintre evenimentul generat de un buton i un eveniment generat de clic pe mouse este c primul
apare numai dac dispozitivul mouse este poziionat pe aria ocupat de buton, n timp ce al doilea apare
indiferent de poziia cursorului mouse pe ecran. In plus, evenimentele generate de componente JFC conin n
ele sursa evenimentului i alte informaii specifice fiecrei componente.

IE.09.7 Structura programelor dirijate de evenimente


Intr-un program care reacioneaz la evenimente externe trebuie definite clase asculttor pentru aceste
evenimente. De multe ori clasele asculttor trebuie s comunice ntre ele, fie direct, fie prin intermediul unei
alte clase. In astfel de situaii avem de ales ntre mai multe posibiliti de grupare a claselor din program,
fiecare cu avantaje i dezavantaje.
Pentru a ilustra variantele posibile vom folosi un exemplu simplu cu dou butoane i un cmp text. In cmpul
text se afieaz un numr ntreg (iniial zero); primul buton (+) are ca efect mrirea cu 1 a numrului afiat
iar al doilea buton (-) produce scderea cu 1 a numrului afisat. Dei foarte simplu, acest exemplu arat
necesitatea interaciunii dintre componentele vizuale i obiectele asculttor.
Prima variant foloseste numai clase de nivel superior (top-level): o clas pentru fereastra principal i dou
clase pentru tratarea evenimentelor de butoane. Obiectele asculttor la butoanele + i - trebuie s
acioneze asupra unui cmp text i deci trebuie s primeasc o referin la cmpul text (n constructor).
class B1L implements ActionListener {
// ascultator la buton "+"
JTextField text;
// referinta la campul text folosit
public B1L (JTextField t) { text=t; }
public void actionPerformed (ActionEvent ev) {
int n =Integer.parseInt(text.getText()); // valoarea din campul text
text.setText(String.valueOf(n+1));
// modifica continut camp text
}
}

- 132 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

class B2L implements ActionListener { // ascultator la buton "-"


JTextField text;
// referinta la campul text folosit
public B2L (JTextField t) { text=t; }
public void actionPerformed (ActionEvent ev) {
int n =Integer.parseInt(text.getText()); // valoarea din campul text
text.setText(String.valueOf(n-1));
// modifica continut camp text
}
}
// Clasa aplicatiei: butoane cu efect asupra unui camp text
class MFrame extends JFrame {
JButton b1 = new JButton (" + ");
JButton b2 = new JButton (" - ");
JTextField text = new JTextField (6);
public MFrame() {
text.setText(0);
b1.addActionListener (new B1L(text) );
b2.addActionListener (new B2L(text) );
setLayout (new FlowLayout());
add(b1); c.add(b2);
add (text);
}
// pentru verificare
public static void main (String args[ ]) {
JFrame f = new MFrame();
f.pack(); f.setVisible(true);
}
}
Pentru acest exemplu putem defini o singur clas asculttor la ambele butoane. Atunci cnd exist un singur
asculttor la mai multe evenimente se pune problema recunoaterii componentei care a generat fiecare din
evenimentele produse. Swing ofer dou posibiliti:
- Metoda getSource(), cu rezultat Object, prezent n orice clas eveniment (rezultatul este adresa obiectului
care a generat evenimentul).
- Metoda getActionCommand(), cu rezultat String, prezent numai n anumite clase Swing (rezultatul este
irul inscripionat pe buton sau pe alt component).
Exemplu de asculttor la butoanele inscripionate cu +i cu - (sau Incr i Decr).
class BListener implements ActionListener {
static int n=0; JTextField text;
public BListener (JTextField t) {
text=t; text.setText (" "+ n);
}
public void actionPerformed (ActionEvent ev) {
String b = ev.getActionCommand();
if (b.contains("+")>=0) ++n;
// if (b.contains("Incr") n++;
else --n;
text.setText(" "+ n);
}
}
- 133 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

O variant cu numr minim de clase este definirea clasei cu fereastra aplicaiei ca asculttor la evenimente,
ceea ce elimin clasele separate cu rol de asculttor :
class MFrame extends JFrame implements ActionListener {
JButton b1 = new JButton (" + ");
JButton b2 = new JButton (" - ");
JTextField text = new JTextField (6);
int n=0;
public MFrame() {
Container c = getContentPane();
b1.addActionListener (this);
b2.addActionListener (this);
c.setLayout (new FlowLayout());
c.add(b1); c.add(b2);
text.setText(" "+n); c.add (text);
}
public void actionPerformed (ActionEvent ev) {
Object source =ev.getSource();
if (source==b1) ++n;
else if (source==b2) --n;
text.setText(" "+n);
}
}
Pentru reducerea numrului de clase de nivel superior i pentru simplificarea comunicrii ntre clasele
asculttor la evenimente putem include clasele receptor n clasa cu fereastra aplicaiei:
class MFrame extends JFrame {
JButton b1 = new JButton (" + "), b2 = new JButton (" - ");
JTextField text = new JTextField (6);
int n= 0;
public MFrame() {
Container c = getContentPane();
b1.addActionListener (new B1L()); b2.addActionListener (new B2L());
c.setLayout (new FlowLayout());
c.add(b1); c.add(b2);
text.setText(" "+n);
c.add (text);
}
class B1L implements ActionListener {
// clasa inclusa in MFrame
public void actionPerformed (ActionEvent ev) {
text.setText(" "+ ++n);
}
}
class B2L implements ActionListener {
// clasa inclusa in MFrame
public void actionPerformed (ActionEvent ev) {
text.setText(" "+ --n);
}
}
}
- 134 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Utilizarea de clase incluse anonime reduce i mai mult lungimea programelor, dar ele sunt mai greu de citit i
de extins n cazul unor interaciuni mai complexe ntre componentele vizuale.
In examinarea unor variante pentru aplicaia anterioar am urmrit reducerea lungimii codului surs i al
numrului de clase din aplicaie, dar acestea nu reprezint indicatori de calitate ai unui program cu obiecte i
arat o proiectare fr perspectiva extinderii aplicaiei sau reutilizrii unor pri i n alte aplicaii. Un
dezavantaj comun soluiilor anterioare este cuplarea prea strns ntre obiectele asculttor la butoane i
obiectul cmp text unde se afieaz rezultatul modificrii ca urmare a acionrii unui buton: metoda
actionPerformed() apeleaz direct o metod dintr-o alt clas (setText() din JTextField). Dei programarea
este mai simpl, totui tratarea evenimentului de buton este specific acestei aplicatii iar clasele asculttor nu
pot fi reutilizate si n alte aplicaii.
In cazul programelor Java cu interfa grafic generat de un mediu vizual (soluie recomandat) structura
este stabilit automat de IDE i nu este alegerea programatorului.

IE.09.8 Aplei Java


Cuvntul aplet (applet) desemneaz o mic aplicaie care folosete ecranul n mod grafic, dar care depinde
de un alt program gazd pentru crearea fereastrei principale (care nu trebuie creat de programatorul
apletului). Programul gazd este fie un program navigator (Web browser), fie programul appletviewer,
destinat vizualizrii rezultatului execuiei unui aplet. Codul unui aplet (fiierul .class) este de obicei adus de
ctre browser de la un alt calculator din retea dect cel pe care se execut.
Din punct de vedere sintactic un aplet este o clas Java, derivat din clasa Applet sau din JApplet.
Clasa JApplet este indirect derivat din clasa Panel , care asigur oricrui aplet o fereastr cu butoane de
nchidere, mrire i micsorare. Fereastra de afiare a unui aplet nu poate fi manipulat direct de operatorul
uman ci numai indirect, prin fereastra programului browser.
Programarea unei interfee grafice ntr-un aplet este puin mai simpl dect ntr-o aplicaie deoarece apletul
moteneste de la clasa Panel (i de la clasele Container si Component) o serie de metode utile (inclusiv
metoda windowClosing()). Exemplu de aplet scris n varianta Swing:
public class Aplet extends JApplet {
JLabel et= new JLabel ("Eticheta", JLabel.CENTER);
public void init () {
add (et);
}
}
Fiierul class generat de compilator pentru un aplet este specificat ntr-un fiier html, mpreun cu
dimensiunile ferestrei folosite de aplet, ntre marcajele <applet> i </applet>. Exemplu de fisier html necesar
pentru execuia apletului precedent:
<applet code="Aplet.class" width="250" height="100"> </applet>
In comanda appletviewer este specificat numele fiierului html i nu apare direct numele fisierului class.
Dimensiunile ferestrei folosite de aplet se dau n fisierul de tip html i nu n codul Java.
De remarcat c o clas care corespunde unui aplet trebuie s aib atributul public i nu contine o metod
main. Clasa aplet motenete i redefinete de obicei metodele init(), start(), paint() i alte cteva metode,
apelate de programul gazd la producerea anumitor evenimente.
- 135 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

O clas aplet poate fi transformat ntr-o aplicaie prin scrierea unei funcii main() n care se construieste un
obiect JFrame, la care se adaug un obiect aplet si se apeleaz metoda init():
public static void main (String args[ ]) {
JFrame f = new JFrame();
JAplet aplet = new JAplet();
f.getContentPane().add (aplet);
aplet.init();
f.setVisible (true);
}

// se adauga la clasa JAplet

Din punct de vedere funcional un aplet contine cteva funcii, care trebuie (re)definite de utilizator i sunt
apelate de programul gazd. Un aplet care trateaz evenimente externe trebuie s conin i metodele de
tratare a evenimentelor, pentru c nu se admit alte clase asculttor, separate de clasa aplet. Obiectul
asculttor la evenimente este chiar obiectul aplet, ceea ce conduce la instruciuni de forma urmtoare
comp.addXXXListener(this);

// comp este numele unei componente din aplet

Exemplul urmtor este un aplet care afieaz un buton n centrul ferestrei puse la dispoziie de programul
gazd i emite un semnal sonor (beep) la "apsarea" pe buton, adic la acionarea butonului din stnga de pe
mouse dup mutare mouse pe zona ecran ocupat de buton.
public class Aplet extends JApplet implements ActionListener {
JButton button;
public void init() {
button = new JButton("Click Me");
getContentPane().add(button, BorderLayout.CENTER);
button.addActionListener(this);
// obiectul receptor este chiar apletul
}
public void actionPerformed(ActionEvent e) {
// tratare eveniment buton
Toolkit.getDefaultToolkit().beep();
// semnal sonor
}
}

Metoda "init" este apelat o singur dat, la ncrcarea codului apletului n memorie, iar metoda "start" este
apelat de fiecare dat cnd programul browser readuce pe ecran pagina html care contine i marcajul
<applet ...>. Metoda "paint" are un parametru de tip Graphics, iar clasa Graphics contine metode pentru
desenarea de figuri geometrice diverse i pentru afiarea de caractere cu diverse forme i mrimi:
public void paint (Graphics g) {
g.drawRect (0, 0, getSize().width - 1, getSize().height - 1); // margini fereastra
g.drawString ("text in aplet", 10, 30);
// afisare text
}

IE.09.9 Clase Swing cu model


Un obiect vizual folosit ntr-o interfa grafic ndeplinete mai multe funcii:
- Prezint pe ecran date ntr-o imagine specific (controlabil prin program).
- 136 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

- Preia aciunile transmise prin mouse sau prin tastatur obiectului respectiv.
- Permite modificarea datelor ca rspuns la aciuni ale operatorului uman sau la cereri exprimate prin
program si actualizeaz imaginea de pe ecran a acestor date.
Arhitectura MVC (Model-View-Controller) separ n cadrul unei componente vizuale cele trei funcii
eseniale ale unui program sau ale unui fragment de program: intrri (Controller), date i prelucrri (Model),
iesiri (View).
Partea numit model reprezint datele i funcionalitatea componentei, deci definete starea i logica
componentei. Imaginea (view) red ntr-o form vizual modelul, iar partea de comand (controller)
interpreteaz gesturile utilizatorului i acioneaz asupra modelului (defineste comportarea componentei).
Poate exista i o legtur direct ntre partea de control i partea de redare, n afara legturilor dintre model i
celelalte dou pri (imagine i comand).
Comunicarea dintre cele trei pri ale modelului MVC se face fie prin evenimente, fie prin apeluri de
metode. Modelul semnaleaz prii de prezentare orice modificare n starea sa, prin evenimente, iar partea de
imagine poate interoga modelul, prin apeluri de metode. Partea de comand este notificat prin evenimente
de aciunile (gesturile) operatorului uman si modific starea modelului prin apeluri de metode ale
obiectului cu rol de model; n plus poate apela direct i metode ale obiectului de redare (pentru modificarea
imaginii afisate).
Clasele JFC folosesc o variant a modelului MVC cu numai doi participani: o clas model i o clas
delegat care reunete funciile de redare i de control pentru a usura sarcina proiectantului, deoarece
comunicarea dintre controler i imagine poate fi destul de complex.
Componentele JComboBox, JList, JTable, JTree, JMenuBar includ ntotdeauna un obiect model care
poate fi extras printr-o metod getModel() pentru a se opera asupra lui. Obiectul model poate fi creat automat
n constructor, pe baza unor colectii, sau poate fi creat de programator i transmis clasei care asigur
prezentarea
datelor
din
model.
Exist
clase
predefinite
pentru
obiecte
model
(DefaultComboBoxModel,DefaultListModel, DefaultTreeModel) dup cum se pot defini i alte clase
model care s respecte interfete impuse.
Un model este o structur de date care poate genera evenimente la modificarea datelor i conine metode
pentru adugarea i eliminarea de asculttori la evenimentele generate de model. Clasele JList,JTable .a.
sunt asculttori la evenimente generate de clasele model respective, deci modificarea datelor din model va
modifica automat i afisarea pe ecran (se vor afia noile date din obiectul model).
Datele prezentate ntr-un obiect JList, JTable, JTree s.a. se pot modifica n cursul execuiei programului,
iar afiarea trebuie s reflecte aceste modificri. De exemplu, se afieaz date din directoare sau din fiiere al
cror nume se introduce sau se modific de ctre operator dup afiarea interfeei grafice (prin introducere n
cmpuri text, de exemplu).
Ca tehnic general, nu se construiesc alte obiecte vizuale (JList, JTable, JTree) cu noile date dup afisarea
interfeei grafice i nici nu se apeleaz metode de reafiare (repaint() sau altele), ci se apeleaz metode care
transmit la obiectul vizual un alt model (setModel()), sau se apeleaz metode de modificare a obiectului
model.
Modificrile asupra obiectului model sunt redate automat pe ecran deoarece obiectul vizual este asculttor la
evenimente generate de model. In general, clasele model contin i metode de modificare a datelor (interfeele
claselor model nu impun astfel de metode).
- 137 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

O alt posibilitate este s se creeze un nou model (de exemplu dup reordonarea unui vector sau unui tabel)
i s se retransmit noul model la acelai obiect vizual din interfaa grafic.
Utilizatorii au posibilitatea s-i defineasc alte clase model, dar aceste clase trebuie s respecte anumite
interfee Java (ListModel, ComboBoxModel, TableModel, TreeModel). Pentru facilitarea definirii de noi
clase model (model de list sau de tabel) exist clase abstracte care implementeaz parial interfeele
mentionate: AbstractListModel, AbstractTableModel. Clasele model gata definite au un nume care ncepe
cu Default (DefaultListModel, DefaultTableModel, DefaultTreeModel) i constructori ce primesc ca
argument un vector (model de list), o matrice (model de tabel) sau un nod rdcin (model de arbore).
Clasele cu model au att constructor cu argument model, ct i constructori cu diverse structuri de date, pe
baza crora se construiesc automat obiecte model; de aceea exist metode getModel() n toate aceste clase,
indiferent dac s-a transmis un model creat separat sau nu (model creat implicit).
Componenta vizual JList afiseaz pe ecran o list de valori, sub forma unei coloane, i permite selectarea
uneia dintre valorile afiate, fie prin mouse, fie prin tastele cu sgei. Datele afiate pot fi de orice tip clas i
sunt memorate ntr-un obiect colecie (Vector) sau model; o referin la acest obiect este memorat n
obiectul JList de constructorul obiectului JList. Exist mai muli constructori, cu parametri de tipuri diferite:
vector intrinsec, Vector sau ListModel. Exemple:
String v =,unu,doi,trei-;
JList list1 = new JList (v);
// vector intrinsec
Vector vec = new Vector ( Arrays.asList(v));
JList list2 = new JList(vec);
// obiect de tip Vector
JList list3 = new JList (new DefaultListModel());
Clasa predefinit DefaultListModel pentru model de list are un singur constructor, fr argumente, dar are
metode de adugare si de modificare a obiectelor din vectorul folosit de obiectul model. Un obiect JList cu
coninut variabil se poate folosi i fr obiect model creat explicit, prin retransmiterea unui vector cu date la
obiectul JList (metoda setListData()). Exemplu de afiare ntr-un obiect JList a numelor fiierelor dintr-un
director al crui nume se introduce (sau se modific) ntr-un cmp text:
class FileList extends JFrame implements ActionListener{
JList jlist = new JList();
// pentru continut director
JTextField tf = new JTextField(12);
// pentru nume director
public FileList() {
Container cp = getContentPane();
cp.add (tf,"North"); cp.add (new JScrollPane(jlist));
tf.addActionListener (this);
setSize(300,600); show();
}
public void actionPerformed (ActionEvent ev) {
File d=new File(tf.getText());
// creare ob. File cu nume director
if (! d.isDirectory ()) return;
String files[] = d.list();
// vector cu nume de fisiere
Vector v = new Vector (Arrays.asList(files));
jlist.setListData(v);
// transmite vector la JList
}
}

- 138 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Modificarea datelor din vector (vector intrinsec sau obiect Vector) nu are efect asupra datelor afiate n
obiectul JList dect dac se apeleaz la fiecare modificare i metoda setListData(), care apeleaz metoda
setModel() din JList. Modificarea datelor din model (prin metode ca addElement(), setElementAt(),
removeElementAt()) se reflect automat pe ecran, deoarece obiectul JList este asculttor la evenimentele
generate de model. Exemplu:
class FileList extends JFrame implements ActionListener{
DefaultListModel model = new DefaultListModel();
JList jlist = new JList(model);
JTextField tf = new JTextField(12);
public FileList() {
Container cp = getContentPane();
cp.add (tf,"North");
cp.add (new JScrollPane(jlist));
tf.addActionListener (this);
setSize(300,600); show();
}
public void actionPerformed (ActionEvent ev) {
File d=new File(tf.getText());
if (! d.exists()) return;
String files[] = d.list();
model.clear();
// sterge continut anterior model
for (int i=0;i<files.length;i++)
// adauga nume fisiere la model
model.addElement(files[i]);
// modelul modifica si obiectul JList !
}
}

- 139 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Capitolul IE.10. Mediul de programare NetBeans


Cuvinte cheie
Dezvoltarea de aplicatii, Construirea de aplicatii,Mediu integrat IDE,
Proiect, Depanare, Puncte de oprire, Refactorizare,Testare unitar
Programare vizual, Mediu vizual,

IE.10.1 Dezvoltarea de aplicaii Java


Dezvoltarea de aplicaii (Application Development) este un termen care reunete totalitatea operaiilor
necesare pentru obinerea i meninerea unui produs software comercial: scrierea iniiala de module, legarea
modulelor ntr-un program unitar, testarea i depanarea produsului, actualizarea programului la modificarea
unor cerine sau extinderea programului cu noi funcii, arhivarea ntr-un singur fiier, instalarea programului
pe calculatorul beneficiarului sau pe un server de aplicaii (Deployment), etc.
Dezvoltarea aplicaiilor mici i medii se poate face n modul linie de comand, cu comenzi introduse manual
pentru fiecare dintre aceste operaii i cu utilizarea unor instrumente pentru construirea de aplicaii (Build
Tools) i pentru meninerea de versiuni succesive (Version Control System).
In dezvoltarea unei aplicaii se repet anumite operaii necesare pentru obinerea unui executabil dup
modificarea surselor: compilare, tergere i creare de fisiere i/sau foldere, copiere de fiiere, .a. Aceste
operaii (aciuni) sunt cuprinse ntr-un fiier de construire aplicaie (Build File) sau proiect, care este de
obicei un fiier XML i care este folosit de ctre un instrument (Build Tool). In plus, pentru aplicaiile Java
se folosesc de obicei mai multe biblioteci de clase, sub form de arhive jar, care pot avea i ele diferite
versiuni. Pentru limbajul Java cele mai utilizate instrumente pentru construirea de aplicaii sunt: Ant (plus
Ivy), de la Apache i Maven. Maven permite reutilizarea bibliotecilor de clase aflate ntr-un depozit
central (repository) i accesate automat prin Internet.
Exemplu de fiier (proiect) pentru programul Ant:
<project name="StringUtilsBuild" default="package"
xmlns:ivy="antlib:org.apache.ivy.ant" xmlns="antlib:org.apache.tools.ant">
<target name="clean">
<delete dir="target"/>
<delete dir="lib"/>
</target>
<target name="compile" depends="-init-ivy">
<mkdir dir="target/classes"/>
<javac srcdir="src/main"
destdir="target/classes"/>
</target>
<target name="compileTest" depends="compile">
<mkdir dir="target/test-classes"/>
<javac srcdir="src/test"
destdir="target/test-classes">
<classpath>
<pathelement location="target/classes"/>
<fileset dir="lib" includes="*.jar"/>
</classpath>
</javac>
</target>
- 140 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

</project>
Gruparea mai multor operaii n aciuni numite target, permite reutilizarea acestora n diferite proiecte.
Multe dintre aplicaiile Java sunt aplicaii Web, care necesit instalarea pe un server Web pentru testare.
Timpul necesar dezvoltrii de aplicaii mai mari poate fi mult redus prin utilizarea unui mediu integrat de
dezvoltare (IDE= Integrated Development Environment), care asigur o serie de faciliti pentru editarea
programelor, pentru depanarea lor, pentru construirea de aplicaii i pentru testarea lor, toate cu o interfa
grafic prietenoas i usor de utilizat. Un astfel de produs integreaz mai multe programe diferite utilizate n
linie de comand: editor de texte, compilator, depanator, suport pentru teste unitare (JUnit), constructor de
aplicaii, server Web, etc.
Pentru editare (scrierea i modificarea surselor) un IDE este de ajutor prin semnalarea unor erori nainte de
compilare (se face o analiz sintactic pe msur ce se introduc instruciuni), prin autocompletarea unor
nume de clase sau metode, prin ajutor (Help) cu documentaia claselor, prin refactorizare s.a. Pentru
construirea de aplicaii se creeaz automat fiiere build Ant pentru fiecare proiect. Unitatea de lucru a unui
IDE este un proiect (project), care grupeaz ntr-o structur de foldere fiiere diverse: surse, fiiere
rezultate din compilare, biblioteci, fiiere de proprieti, fisiere build, s.a. In general un proiect corespunde
unei aplicaii dar este posibil ca o aplicaie s fie dezvoltat prin cteva proiecte, unele pentru biblioteci de
clase folosite n aplicaie i un proiect pentru pornirea aplicaiei (cu metoda main()).
Cele mai utilizate produse IDE pentru Java sunt Eclipse, NetBeans si Intellij IDEA care permit dezvoltarea
de aplicaii n mai multe limbaje: Java, C, C++, PHP, Groovy, .a. In plus, ele pot fi folosite i ca medii
vizuale, pentru crearea interfeelor grafice ale aplicaiilor fr programare manual: utilizatorul alege
componentele grafice, le configureaz proprietile i le plaseaz pe o suprafa ce reprezint fereastra
principal a aplicaiei, iar IDE genereaz codul surs pentru a realiza interfaa grafic desenat de utilizator i
ajut la tratarea evenimentelor generate de componentele grafice.

IE.10.2 Mediul integrat NetBeans


Eclipse i NetBeans sunt cele mai folosite medii IDE datorit facilitilor oferite i pentru faptul c sunt
complet gratuite. Alegerea ntre cele dou este relativ subiectiv i poate fi determinat de specificul
aplicaiilor dezvoltate, n sensul c unul sau altul este preferabil dintr-un anumit punct de vedere.
Mediul NetBeans poate fi descrcat n cteva variante: numai pentru aplicaii Java standard (SE = Standard
Edition), numai pentru aplicaii C,C++, numai pentru aplicaii PHP, pentru aplicaii Web n Java ( JEE =
Java Enterprise Edition) sau pentru toate variantele anterioare plus alte faciliti (Java ME, Groovy, Java
Card). In varianta SE se aduce i SDK (compilator, biblioteci s.a.) dar nu i documentaia Javadoc pentru
clasele Java; pentru instalarea documentaiei n NetBeans se alege din meniu:
Tools> Java Platform > Javadoc > Add ZIP/Folder > C:/jdk-7-doc/api
Orice aplicaie dezvoltat sub NetBeans necesit crearea unui proiect. Crearea unui nou proiect se face prin
selectarea opiunii File din meniul principal i apoi a opiunii New Project (din File) sau prin scurttura
Ctrl-Shift-N.

- 141 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Urmeaz alegerea tipului de proiect; vom alege un proiect standard Java (Java Application):

Urmeaz stabilirea numelui i locaiei folderului care va conine proiectul; se pot accepta propunerile IDE
sau se pot modifica numele i locul proiectului.

- 142 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Dac s-a ales generarea clasei Main, atunci NetBeans va crea un schelet care va fi completat de utilizator.
Exemplu:
/* To change this template, choose Tools | Templates and open the template in the editor. */
package helloworldapp;
/* @author <your name> */
public class HelloWorldApp {
/* @param args the command line arguments */
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
Ecranul unui proiect activ (n lucru) conine mai multe seciuni, aa cum se vede din figura urmtoare

- 143 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Compilarea se face automat la salvarea textului introdus. Execuia se comand fie din meniu
(Run>RunMainProject), fie cu tasta F6. Rezultatele apar n fereastra cu titlul Output, deschis automat:

Aplicaiile reale conin multe clase i alte fiiere. Beneficiarul aplicaiei primete de obicei o arhiva de tip
jar n care se mpacheteaz toate fiierele necesare folosirii aplicaiei. Crearea arhivei se face fie din
meniu: Run > Clean and Build Main Project sau cu scurttura Shift-F11. Arhiva este plasat n subdirectorul dist (pentru distribuie) din directorul proiect.
Pentru includerea n proiect a unor biblioteci de clase Java (altele dect cele standard SDK):
Extindere nod proiect > clickdreapta pe Libraries > Add JAR/Folder > selectare nume/cale fiier de tip
jar sau folder.
Depanarea programelor (Debugging) se face prin selectarea opiunii Debug din meniul principal sau prin
Ctrl-F5. In acest mod se pot utiliza urmtoarele procedee: Stablilirea unor puncte de oprire temporar
(Breakpoints), Execuia pas-cu-pas (Step-Over) a instruciunilor surs, Execuia pn la poziia cursorului,
Inspectarea coninutului unor variabile din program, Modificarea valorii unor variabile din panoul de
variabile.
Comenzi utilizabile n modul depanare:
Continue : se continu execuia pn la urmtorul punct de oprire sau pn la terminarea programului
Step-into : se intr n execuia pas cu pas a instruciunilor unei funcii (metode) apelate; n mod normal
funciile apelate nu se execut pas cu pas.
Step-out : se iese din execuia pas-cu-pas a unei funcii i se trece la funcia care a facut apelul.
Run-to-cursor : alternativ la breakpoint pentru execuia unei secvene de instruciuni (pn la poziia
cursorului)
Finish : ieire din modul debugging

Stabilirea unor puncte de oprire (Breakpoints) se poate face si prin clic pe bara din marginea din stnga a
ferestrei cu sursa programului:
- 144 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Instruciunea din program care urmeaz a fi executat este marcat cu o linie verde:

Exemplu de tabel NetBeans cu valorile variabilelor din program:

IE.10.3 Editorul Java din NetBeans


La introducerea textului surs mediul NetBeans ofer urmtoarele faciliti:
Colorare sintactic: comentariile cu gri, cuvintele cheie cu albastru, variabile i cmpuri cu verde, oarametri
cu oranj, clase sau metode nvechite (deprecated) subliniate cu o linie ondulat, iar membrii nefolositi tiai
cu o linie. Exemplu:

- 145 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Marcare erori (Hints for Syntax errors) : instruciunile cu erori sunt marcate cu un punct rou la stnga;
dac se apas pe becul afiat sau se folosesc tastele Alt-Enter atunci se afieaz cauza erorii.Erorile de
compilare sunt semnalate chiar de la introducerea textului surs n fereastra de editare, prin subliniere cu
rou. Exemplu:

O eroare frecvent este absenta instructiunii import la introducerea unui nume de clas; pentru corectare se
face clic dreapta pe numele clasei i se alege Fix Import.:
Completare automat (Auto-complete ) : dup introducerea parial a numelui unei clase sau metode se
apas Ctrl-space pentru afiarea opiunilor posibile de completare automat a ntregului nume. Exemplu:

- 146 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Sugestiile editorului se aplic i pentru cuvinte cheie, variabile i parametrii de funcii. Exemple:

Editorul NetBeans semnaleaz clasele din pachetele neimportate i adaug la cerere instruciunile import
necesare (cu combinaia de taste Ctrl-Shift-I). Exemplu:

La selectarea unei clase pentru completare automat se adaug si instruciunea import necesar.
Editorul NetBeans poate genera automat cod Java pentru constructori, metode, metode suprascrise, metode
delegate s.a. folosind tastele Alt-Insert . In exemplul urmtor se cere generarea unui constructor

Afiare documentaie Javadoc: Clic dreapta pe numele metodei > Show Javadoc sau Alt-F1. Alt variant:
se pune cursorul pe numele unei metode sau clase i se apas Ctrl-space pentru afiarea parial a
documentaiei referitoare la metoda sau clasa respectiv. In continuare se poate tasta din nou Ctrl-space
pentru lista metodelor sau se folosesc butoanele afiate n fereastr pentru a alege afiarea documentaiei
pentru clasa respectiv ntr-un browser Web
sau afiarea sursei clasei
(dac este disponibil mediului
NetBeans). Exemplu:

- 147 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

abloane de cod (Code templates) : se pot defini forme prescurtate pentru secvene uzuale folosind tasta
TAB; de ex. sout n loc de System.out.println sau fori pentru un ciclu for. Exemplu:

Pentru adugarea sau modificarea unui ablon de cod se procedeaz astfel:


-

Tools > Options > Editor > Code templates

Se alege limbajul (Java); se vor afisa abloanele existente

Butoanele New si Remove permit adugarea sau eliminarea unui ablon de cod

Pentru editare se alege un ablon existent si se modific n fereastra .

Se alege tasta pentru expandarea abloanelor (implicit este TAB)

Numerotare linii (Line Numbers): click-dreapta pe marginea din stnga a unei instruciuni pentru afiare
numere linii surs
Format: Formatare cod surs prin Alt-Shift-F sau click-dreapta (Source din meniu) i Format pentru
indentare i formatare cod surs
Comentare temporar bloc de cod surs : selectare bloc i Source->Toggle Comment din meniu

- 148 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Navigare prin codul surs: fie prin activare Navigator,


fie prin scurtturi (combinaii de taste). Pentru activare
navigator selectm din meniu Window > Navigating >
Navigator (sau Ctrl-7); se va afia o fereast cu structura
fiierului surs din care se poate selecta un element:

IE.10.4 Refactorizare n NetBeans


Refactorizarea codului surs se refer la modificarea disciplinat a codului fr a modifica efectul codului la
execuie. Refactorizarea conduce la surse mai uor de neles, de modificat (de ntreinut) i permite gsirea
i eliminarea unor erori.
Cea mai folosit operaie de refactorizare este schimbarea numelui unui pachet sau unei clase, unei metode
sau unei variabile. NetBeans modific toate apariiile acelui nume, inclusiv referiri la el. Pentru schimbarea
unui nume avem dou posibiliti: clic dreapta pe nume > Refactor > Rename sau din meniu selectm
Refacor > Rename.

- 149 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Exemple de alte operaii de refactorizare:


-

Inlocuirea unui bloc de cod cu o metod prin introducerea definiiei metodei i apelului metodei
(Introduce Method).
Generarea metodelor get()i set() pentru un cmp i nlocuirea referinelor la cmp prin apeluri de
metode (Encapsulate Fields)
Mutarea unei clase ntr-un alt pachet (Move Class)
tergere sigur (Safely Delete), dac nu mai sunt referinte la acel element.
Modificarea parametrilor unei metode (Change Method Parameters)

IE.10.5 Testarea programelor Java n NetBeans


Testarea unitar este parte din procesul dezvoltrii de programe, iar pentru aplicaiile Java se folosete
preponderent biblioteca de clase JUnit. In NetBeans se pot folosi att versiunea 4 JUnit, cu adnotri, ct i
versiunea 3 fr adnotri.
Testarea unitar verific, pentru fiecare unitate de program (metod Java), faptul c, pentru anumite date
iniiale, rezultatele sunt cele ateptate. In acest scop se scrie pentru fiecare metod testat o funcie de test n
care se folosesc aseriuni. Se poate folosi instruciunea assert din Java sau aseriuni JUnit. O aseriune este o
afirmaie care poate fi adevrat sau fals; dac este adevrat programul continu, iar dac este fals atunci
se produce excepia AssertionFailedError. Exemple de aseriuni:
assertTrue (boolean condition)
assertEquals(Object expected,Object actual)
assertEquals (int expected, int actual)
assertSame(Object expected, Object actual)
assertNull(Object object)

Trece dac condiie adevrat


Trece dac obiectele sunt egale dup metoda equals()
Trece dac cele dou valori sunt egale (==). Valorile
pot fi de orice tip primitiv Java.
Trece dac cele dou obiecte sunt identice
Trece dac argumentul este null

Fiecare metod de tip assert poate avea un parametru suplimentar de tip String care este un mesaj afiat n
caz c aseriunea (condiia) este fals.
In funciile de test se folosesc n general obiecte ale clasei testate; aceste obiecte pot fi create n interiorul
metodei sau n afara metodelor de test. In acest scop sunt prevzute n clasa de test metodele cu numele
setUp() si tearDown() (JUnit 3) sau metode cu orice nume dar adnotate cu @Before si @After. Metoda
setUp() creeaz obiectele necesare metodelor de test i initializeaz variabile ale clasei care vor fi folosite n
metodele de test, nainte de fiecare test. Metoda pereche tearDown() anuleaz operatiile din setUp()i reface
starea iniial, dac e necesar.
Testele unitare pot fi clasificate n trei categorii:
- 150 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

- teste pozitive : se verific rezultatul ateptat al unei aciuni


- teste negative: se verific comportarea n cazul unor date de intrare (parametri) cu erori
- teste de producere excepii: se verific dac sunt tratate excepiile posibile
Exemplul folosit aici este o clas cu dou metode: nmulire i mprire de ntregi:
public class Calc {
public int mul (int a, int b) { return a*b; }
public int div (int a, int b) { return a/b; }
}
Exemplu de fiier cu codul de testare a clasei Calc scris manual folosind JUnit 3:
import org.junit.*;
import static org.junit.Assert.*;
import junit.framework.*;
public class UnitTest1 extends TestCase {
Calc c;
public void setUp(){
c=new Calc();
}
public void testMul() {
assertEquals (c.mul(2,3),6) ;
// assertTrue ( c.mul(2,3)==6);
}
public void testDiv() {
assertEquals (c.div(6,3),2) ;
// assertTrue ( c.div(6,3)==2);
}
}
class Runner {
public static void main (String a[ ]){
org.junit.runner.JUnitCore.main("UnitTest1");
}
Pentru generarea de teste JUnit n NetBeans se face click dreapta pe numele clasei sau pe numele pachetului
de clase (dac sunt mai multe clase supuse testelor), se selecteaz
Tools > Create Tests > Framework > JUnit
Putem apoi alege ntre versiunile 3 i 4 de JUnit. Efectul este acela de generare a unui nou pachet de clase n
directorul TestPackages cu clase de test pentru fiecare clas din aplicaie. In cazul clasei Calc se genereaz
clasa de test urmtoare dup selecia variantei JUnit 3:
import junit.framework.TestCase;
public class CalcTest extends TestCase {
public CalcTest(String testName) {
super(testName);
}
@Override
protected void setUp() throws Exception {
super.setUp();
}
- 151 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

@Override
protected void tearDown() throws Exception {
super.tearDown();
}
public void testDiv() {
System.out.println("div");
int a = 0;
int b = 0;
Calc instance = new Calc();
int expResult = 0;
int result = instance.div(a, b);
assertEquals(expResult, result);
// TODO review the generated test code and remove the default call to fail.
fail("The test case is a prototype.");
}
}
. . . // testMul
Aa cum indic i comentariile vom elimina liniile finale care apeleaz metoda fail() si vom cere execuia
testelor n una din variantele:
- Din meniul principal: Run > Test Project
- Click dreapta pe numele proiectului > Test (sau Alt-F6)
Deoarece se genereaz automat date de test (a,b) cu valoarea zero se va produce o excepie neprevzut i
netratat n metoda div(), iar testul eueaz (Test failed) din cauza acestei erori.
Pentru testarea metodelor care pot genera excepii se poate verifica n metoda de test dac excepia a fost
tratat sau nu n metoda verificat. Dac adugm metodei div tratarea exceptiei aritmetice atunci testul va
trece cu bine Exemplu:
public void testDiv() {
int a = 0; int b = 0;
int result=0;
Calculator instance = new Calculator();
int expResult = 0;
try {
result = instance.div(a, b);
} catch (ArithmeticException ex){
fail ("ArithmeticException");
}
assertEquals(expResult, result);
}
Teste generate n varianta JUnit 4:
public class CalcTest {
public CalcTest() { }
@BeforeClass
public static void setUpClass() { }
@AfterClass
public static void tearDownClass() { }
@Before
public void setUp() { }
@After
- 152 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

public void tearDown() { }


@Test
public void testMul() {
System.out.println("mul");
int a = 0;
int b = 0;
Calc instance = new Calc();
int expResult = 0;
int result = instance.mul(a, b);
assertEquals(expResult, result);
// TODO review the generated test code and remove the default call to fail.
fail("The test case is a prototype.");
}
@Test
public void testDiv() {
...
}
}
Dac metoda testat arunc o excepie (tratat n alt metod din aplicaie) atunci putem specifica n metoda
de test c se asteapt producerea acelei excepii:
@Test (expected=ArithmeticException.class)
public void testDiv() , -

IE.10.6 Programare vizual n NetBeans


Termenul de programare vizual, ca alternativ la programarea manual se refer la un mod de lucru n
care codul surs este generat de ctre un mediu vizual pe baza desenului interfeei realizat pe ecran de ctre
utilizator (numit form n documentaia NetBeans), desen format din formele componentelor predefinite
(butoane, cmpuri text, etichete, etc). Pe ecran se afieaz o palet de componente i o foaie de
proprieti pentru fiecare component selectat. Utilizatorul aduce (drag and drop) fiecare component
necesar pe o suprafa de asamblare a componentelor i stabileste sau modific proprietile lor (multe
proprieti au valori implicite). Mediul vizual genereaz cod surs pe baza ansamblului de componente.
Legturile (interaciunile) dintre componente pot s apar grafic sau nu.
Una dintre aplicaiile importante ale programrii vizuale a fost generarea de cod pentru interfeele grafice din
aplicaii, folosind drept componente obiecte grafice (controale) ce compun aceste interfee. Ideea este c
dimensiunile obiectelor grafice, dispunerea lor relativ pe ecran i modificri ale acestor atribute se pot face
mult mai uor prin vizualizarea lor i tragerea obiectelor sau a marginilor lor, dect prin programare manual
i execuii repetate pentru a vedea efectul modificrilor efectuate n surse. Medii vizuale au existat i exist
pentru diferite limbaje: Delphi pentru Pascal, Microsoft Visual Studio pentru C++ i Basic, NetBeans i
Eclipse pentru Java .a.
Inaintea versiunii 7 NetBeans se putea alege un tip de proiect Java Desktop Application pentru a intra n
editorul vizual, dar dup aceast versiune se pot crea vizual interfee grafice pentru proiecte standard Java
Application, prin adugarea la proiect a unui nou element de tip JFrame. Descrierea modului de lucru se face
pentru NetBeans 7.2.
Indiferent de versiunea utilizat, n modul de lucru vizual ecranul mai conine pe lng fereastra proiectului
si fereastra de rezultate (Output) o fereastr n care putem comuta ntre dou ecrane diferite: ecranul numit
- 153 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Design (cu suprafata JFrame, paleta de componente Palette si foile de proprietti) i ecranul Source cu codul
surs generat de NetBeans pe baza desenului din ecranul Design.

Primul exemplu este un buton care genereaz un semnal sonor la actionarea sa. Se creeaz un nou proiect, se
accept numele propuse pentru proiect i pentru clasa JFrame i se trage pe suprafata de proiectare o
component JButton. Se editeaz proprietatea text (Edit Text) pentru modificarea inscripiei de pe buton:
Clic dreapta pe buton > Edit Text > Click Me

- 154 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

In modul Design se pot muta (trage) imaginile componentelor, se pot trage de marginile lor pentru
modificarea dimensiuilor i se pot ajusta spaiile libere (intervalele) dintre componente.
Imaginea din ecranul Design nu este identic cu interfaa afisat la execuia codului generat; pentru a vedea
cum va arta la execuie fie executm aplicaia, fie afim un Preview folosind butonul .

Pentru asocierea unei aciuni la acionarea butonului trebuie tratat evenimentul generat de apsarea sa prin:
Clic dreapta pe buton > Events > Action > actionPerformed.

- 155 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

IDE genereaz scheletul metodelor asculttor i asocierea lor cu componentele respective, iar utilizatorul
poate s completeze manual, n modul Source, instruciunile din metodele asculttor specifice aplicaiei.

Vom introduce o singur instruciune, pentru a genera un semnal beep:

- 156 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Codul surs generat are seciuni care nu pot fi modificate manual (marcate cu un fond colorat) i seciuni
care pot fi modificate direct de utilizator. Seciunile nemodificabile sunt cele care conin declaraii de
variabile i funcia initComponents() care iniializeaz aceste variabile i care stabilete modul de dispunere
(GroupLayout). Numele variabilelor sunt generate de IDE pe baza numelor componentelor Swing (jButton1,
jButton2,...) i pot fi schimbate numai din modul Design (clic dreapta > Change Variable Name).
In al doilea exemplu se dezvolt o aplicaie cu interfa grafic
pentru simularea unui calculator de buzunar cu patru operaii
aritmetice. Interfaa grafic conine urmtoarele componente:
trei cmpuri text pentru introducerea celor dou numere i
pentru rezultat, trei etichete pentru fiecare cmp text i patru
butoane pentru comanda operaiilor.
Se va crea un proiect nou de tip Java Application dar fr bifarea
casetei Create Main Class. Se va aduga acestui proiect o
fereastra JFrame astfel:
Clic dreapta pe nume proiect > New > Other > JFrame Form

Se aduc apoi succesiv pe suprafaa de lucru JFrame componentele din paleta de componente: clic stnga pe
numele i desenul componentei din fereastra Palette, deplasare n poziia dorit din fereastra central i clic
stnga pentru aducerea componentei selectate (n forma i cu numele propuse de IDE). Pentru modificarea
unei proprieti se face clic dreapta pe componenta respectiv i se alege proprietatea; de exemplu pentru a
schimba numele etichetei (din jLabel1, jLabel2, etc) se alege Edit Text i se introduce alt nume pe desenul
componentei.
- 157 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Pentru tratarea evenimentelor generate de o component se face clic dreapta pe component, se alege Events
i apoi tipul de eveniment i numele metodei asculttor. Pentru butonul de adunare se va alege Events >
Action > actionPerformed, dup care IDE comut pe ecranul Source n poziia unde trebuie inserate
instruciuni n metoda actionPerformed(). Exemplu de instruciuni introduse:
float num1 = Float.parseFloat(jTextField1.getText());
float num2 = Float.parseFloat(jTextField2.getText());
float result = num1+num2;
jTextField3.setText(String.valueOf(result));
Pentru verificarea se execut aplicaia:

Run > Run Main Project (F6)

Dac se cere numele clasei cu metoda main() atunci se accept sau se introduce numele clasei cu interfaa
grafic (de ex. NewJFrame).
Pentru execuia aplicaiei fr NetBeans (n linie de comand) trebuie creat o arhiv jar cu rol de fiier
executabil (n subdirectorul dist al proiectului, pentru distribuirea aplicaiei catre clieni):
Run > Clean and Build Main Project (Shift-F11)

- 158 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Capitolul IE.11. Platforma Java


Cuvinte cheie
Platforma Java, JVM (Masina virtuala Java),
Groovy, Scala, Limbaje statice, Limbaje dinamice, Scripting,
Functori (Closure), Metaprogramare, Limbaje specializate (DSL)

IE.11.1 Java ca platform orientat obiect


Java a nceput ca un limbaj de programare dar n prezent a devenit o platform de programare pe care se
pot utiliza mai multe limbaje (Java, Groovy, Scala, JRuby, Jython, Clojure, s.a.) care au n comun acelai
cod intermediar, aceeai main virtual Java i aceleai biblioteci de clase (extinse de obicei).
Codul intermediar generat de compilatoarele Java (numit bytecode) este interpretat sau executat ntr-o
main virtual Java (JVM). Maina virtual Java mpreun cu bibliotecile standard de clase Java formeaz
mediul de execuie Java (JRE=Java Runtime Environment).
O parte dintre aceste noi limbaje au i cte un framework pentru dezvoltarea rapid de aplicaii Web:
Grails pentru Groovy, Lift pentry Scala, Django pentru Python (Jython), Ruby on Rails pentru JRuby.
Interpretorul Java ncarc automat sau la cerere clasele necesare (din fiiere de tip class sau de tip jar
locale sau aduse prin reea de la alte calculatoare). Acest mod de lucru face posibil utilizarea de clase cu
nume cunoscut doar la execuie sau nlocuirea unor clase, fr intervenie n codul surs (cu condiia ca
aceste clase s respecte anumite interfee). Impreun cu codul clasei (metodele clasei n format compilat) se
mai ncarc i informaii despre clas, numite i metadate: tipul clasei (sau interfeei), numele superclasei,
numele variabilelor din clas, numele i tipul metodelor clasei, formele de constructori pentru obiectele
clasei .a. Aceste metadate permit obinerea de informaii despre clase la execuie, instanierea de clase
cunoscute numai la execuie, apeluri de metode determinate la execuie i alte operaii imposibile pentru un
limbaj compilat.
Semnalarea erorilor prin excepii i informaiile furnizate despre excepii se datoreaz tot execuiei
programelor Java sub controlul mainii virtuale. Codul intermediar Java este asistat (supravegheat) la
execuie de ctre maina virtual, ceea ce a dat natere expresiei de cod controlat (managed code).
Aceste faciliti, alturi de independena fa de procesorul pe care se execut, explic de ce limbajele mai
noi orientate pe obiecte (Java, C#, Ruby s.a.) sunt (parial) interpretate ntr-o main virtual.
Limbajele moderne de programare pot fi mprite n dou categorii mari:
-

Limbaje statice, cu tipuri de date declarate i verificate la compilare : Java, Scala .a.

Limbaje dinamice, cu tipuri de date stabilite i modificate la execuie: Javascript, PHP, .a.

Limbajele dinamice sunt de obicei interpretate, fr o compilare anterioar, fiind numite si limbaje de
scripting (script= program scurt direct interpretat pentru a produce rapid rezultate). Limbajul Groovy
poate fi folosit att ca limbaj compilat ct si ca limbaj interpretat (de scripting); el permite i tipurile de date
statice din Java dar i tipuri dinamice, deduse din modul lor de utilizare.

IE.11.2 Limbajul Groovy


Dintre limbajele utilizabile pe platforma Java cel mai apropiat ca sintax de Java i cel care o recunoatere
oficial ( JSR#241, JSR= Java Service Request) este limbajul Groovy.
- 159 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Groovy este un limbaj utilizabil pe maina virtual Java, cu o sintax asemntoare cu Java dar mai simpl,
care poate fi utilizat ca limbaj de scripting sau ca limbaj compilat. Codul surs Groovy este mult mai
compact dect codul Java echivalent dar i mai uor de citit pentru c are constructii mai naturale.
Groovy are faciliti inspirate din Ruby, Python, Smalltalk si ilustreaz multe concepte moderne n
programare: programare orientat pe obiecte avansat (fr tipuri primitive, cu obiecte colecie, .a.) lucrul
cu expresii regulate, faciliti de prelucrare si de creare documente XML, functori (closure), obiecte colecie
cu o sintax simpl (fr instaniere de clase), tipuri definite implicit prin valoarea atribuit (duck types) si
dinamice (o variabil i poate modifica tipul), metaprogramare (Meta Object Protocol) care permite
adugarea de noi metode la execuie fie unei clase fie unui obiect, definirea i utilizarea de limbaje
specializate n Groovy (DSL=Domain Specific Languages), adugarea simpl de teste unitare i de obiecte
surogat (Mock Objects), integrarea n limbaj a unor instrumente de gestiune a proiectelor software (Ant,
Maven), .a.
Groovy folosete i extinde JDK: bibliotecile de clase Java, unele extinse cu noi metode, la care se adaug
clase specifice Groovy (GDK). Oricare alte biblioteci de clase Java pot fi folosite n Groovy.
Cele mai importante medii integrate pentru dezvoltare de programe Java (Eclipse, NetBeans, IDEA) au
suport i pentru limbajul Groovy (recunoatere sintax, documentaie, integrare cu JUnit).

IE.11.3 Simplificarea codului surs n Groovy


Groovy aduce, fat de Java, unele simplificri n sensul eliminrii unor elemente de cod neeseniale astfel
nct programatorul s se poat concentra pe logica programului, eliberat fiind de unele constrngeri
sintactice, care l-ar putea distrage de la esena programului. Se spune c Groovy cere mai puin protocol
dect Java (mai puine declaraii, instruciuni, paranteze, virgule sau ali separatori ). In plus, un script
Groovy poate s conin direct instruciuni i variabile, fr a fi nevoie s declarm o clas i o funcie
main pentru a compila i executa acele instruciuni. Exemplu de script Groovy care ordoneaz o list :
list=[4,2,8,6]
list.sort { a,b -> b-a}
println list
- Pachete de clase importate implicit n Groovy (fr a mai folosi instruciuni import):
java.lang.*, java.util.*, java.io.*, java.net.*, groovy.lang, groovy.util
- Metodele print() i println() au fost adugate clasei Object i sunt folosite n locul metodelor
System.out.print() i System.out.println().
- Terminatorul de instruciune ';' poate lipsi dac acea instruciune este singur pe o linie. Exemplu:
println ( "Today is" + new Date() )
- Parantezele (cu sau fr argumente) folosite la apelarea metodelor pot lipsi n general (dar exist i situaii
cnd ele sunt necesare). Exemplu:
println "Today is " + new Date()
Parantezele sunt totui necesare pentru a deosebi un apel de funcie fr parametri de o variabil (n scripturi
i n functori).
- Se poate da factor comun tipul mai multor argumente succesive. Exemplu:
- 160 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

def rest(int a,b) { return a%b }


- Se poate omite tipul variabilelor sau argumentelor de funcii; acest tip este considerat provizoriu ca fiind
Object pn la atribuirea unei valori care va determina tipul efectiv al variabilei. Exemplu:
def rest(a,b) { return a%b }
Tipul variabilelor i al funciilor poate fi specificat explicit sau rezult implicit din valoarea atribuit acelei
variabile (ca i n alte limbaje dinamice). Cuvntul cheie def se foloseste pentru a declara variabile cu tip
neprecizat. Dac nu se declar un tip explicit trebuie folosit def. Exemple:
Date date = new Date()
def date = new Date()
def now ( ) { return new Date( ) }
def nl ( ) { println }
- Instruciunea return poate lipsi din definiia unor metode, iar rezultatul metodei se consider a fi rezultatul
ultimei instruciuni executate:
def rest(a,b) { a%b }
Uneori instruciunea return este necesar n definiia unei funcii sau a unui functor.
- In Groovy exist dou clase pentru iruri: String si GString. Constantele de tip String se scriu ntre
apostrofuri, iar constantele de tip GString ntre ghilimele. Intr-un sir GString se pot folosi substituii de
variabile si expresii de forma $var sau ${expr}.
Concatenarea de iruri constante cu iruri variabile (valori ale unor variabile sau rezultat al unor funcii)
poate fi evitat prin includerea ntr-un ir cu ghilimele (duble) a unor expresii de forma $var sau ${exp} care
nlocuiesc numele variabilei sau expresia cu valorile lor (ca iruri). Exemple:
println "Today is ${new Date()}"
def msg="Azi este "
def date= new Date(); println "$msg $date"
- In definirea de clase se poate omite cuvntul "public" att pentru clase ct i pentru metode, deoarece este
implicit (clasele i metodele sunt implicit publice, dar pot fi declarate i private sau protected). Ex:
String toString() { "($re,$im)" } // din clasa Complex

IE.11.4 Operatori i instruciuni Groovy


- Operatorul Groovy '?.' se poate folosi n locul operatorului '.' pentru o derefereniere "sigur", care s evite
producerea excepiei NullPointerException. Exemplu:
book?.title

// are rezultat null daca book este null, dar nu produce exceptie

- Constantele numerice sunt tratate n Groovy ca obiecte (din clasele Integer, Float, Double) i nu mai
exist tipurile primitive din Java. Clasa Integer are si metode noi, cum ar fi metoda times care repet o
secven de cod ( un functor, mai exact) de un numr de ori egal cu valoarea obiectului ntreg. Exemplu:
3.times {println}

// scrie 3 linii albe

- Instruciunea for poate avea si o form care foloseste cuvntul cheie in i repet ciclul pentru valori ale
variabilei contor dintr-un subdomeniu (range) sau dintr-o colecie. Exemple:
- 161 -

INFORMATIC*I*

for ( k in 0..3) println

IE. TEHNICI AVANSATE DE PROGRAMARE

// scrie trei linii albe

String[ ] days= ['Luni','Marti','Joi','Vineri']


for ( day in days) println day
Pentru comparaie urmeaz versiunea Java :
String[ ] days= {'Luni','Marti','Joi','Vineri'};
for ( String day: days) System.out.println (day);
De observat i sintaxa diferit de iniializare a unui vector n Groovy faa de Java.
- Comparaia de obiecte la egalitate se face n Groovy cu operatorul '==' (tradus n Java prin metoda equals()
sau prin compareTo()). Exemplu:
s1='Groovy'; s2= new String('Groovy')
println s1==s2 ? 'egale' : 'diferite'
Dac se dorete compararea la identitate (egalitate de adrese ale obiectelor) atunci se folosete metoda is().
Exemplu:
obj1.is(obj2) // true/false
- Nici o excepie nu mai trebuie tratat obligatoriu n Groovy, dar este posibil tratarea lor explicit la fel ca
n Java (prin try..catch). Toate excepiile sunt deci considerate ca fiind de tipul RunTime Exception.
Aceast facilitate, mpreun cu noi metode n clasele de intrare/iesire simplific mult programarea operaiilor
cu fluxuri de intrare-ieire.
- Groovy extinde expresiile cu rezultat boolean dincolo de expresiile condiionale astfel c i alte valori sau
obiecte pot fi testate ca nite condiii (n instruciuni if, while, assert .a.):
variabile referin (false dac null, true dac !null )
colecii i dicionare (false dac colecie vida, true dac are cel puin un element)
numere (false dac zero)
iruri (false dac ir vid)
potrivirea unui ir cu o expresie regulat (false dac nici o potrivire(match))
iteratori (false dac nu mai sunt elemente de enumerat)
IE.11.5 Clase Groovy
- O clas se definete ca i n Java, dar metodele get() i set() sunt generate automat i nu mai trebuie
definite. Exemplu:
class Book {
Integer id
// sau int id ( generat automat ptr clase domeniu)
String title
int price
// sau Integer price
}
// utilizare
def b = new Book()
b.setTitle('POO')
b.setPrice(10)
- 162 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Variabilele dintr-un obiect, numite i "proprieti", pot fi accesate ca i n Java, prin metode get() i set()
(generate automat) sau mai simplu, ca membri ai unei structuri (ca i cum ar fi variabile publice). Selectarea
unei proprieti se poate face i cu operatorul [ ].
// varianta de utilizare
def b = new Book()
b.title='POO'
// b.setTitle ('POO')
b.price=10
println b.title+' '+ b.price
// println b.getTitle()+ ' '+ b.getPrice()
b['title']='POO'
b['price']=10

IE.11.6 Diferene Groovy- Java


- Este posibil utilizarea direct de obiecte colecie (liste, dicionare) fr instanierea unor clase. Ex:
[3,7,2,8,4].sort()

// [2,3,4,7,8]

- Argumente cuvinte cheie n funcii: La apelul constructorilor si metodelor se pot folosi parametri cu nume.
In cazul unui constructor numele parametrului efectiv este acelai cu numele cmpului din clas care este
iniializat cu valoarea parametrului (este numele unei proprieti). Exemplu:
def b= new Book (price:10, title:'POO')
- Chiar dac se folosesc tipuri generice n colecii, Groovy le trateaz ca pe colecii de obiecte Object i pot
primi date de orice tip. Exemplu:
TreeSet<String> a = new TreeSet<String>()
a.add(123)
- In Groovy este posibil suprancrcarea operatorilor, prin asocierea fiecrui operator (ce poate fi redefinit)
cu un nume de metod. Exemple de operatori i metode echivalente:
a+b
a%b
a++,++a

a.plus(b)
a.mod(b)
a.next()

Definirea acestor metode ntr-o clas permite apelarea lor (i) prin operatori. Ex:
class Complex {
private double re,im
Complex (double re, double im) { this.re=re;this.im=im }
def plus (Complex x) { this.re+=x.re; this.im+=x.im; return this }
String toString() {" ($re,$im)" }
}
Complex a=new Complex(3,4), b= new Complex(7,6)
println a+b
// sau a.plus(b)
- Utilizarea de functori, adic scrierea operaiilor care realizeaz o prelucrare acolo unde este nevoie de acea
prelucrare, fr a defini i instania o clas cu o funcie care s conin acel cod. Exemplu:
println ( [3,7,2,8,4]. findAll { x-> x< 6} )

// [3,2,4]
- 163 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Cnd exist un singur argument ntr-un functor, atunci se poate folosi cuvntul it pentru acest argument, care
nu se mai declar explicit. Exemplu:
println ( [3,7,2,8,4]. findAll { it < 6} )
- Existena unor metode suplimentare n clase, multe din ele avnd ca argument un functor. Ex:
println ([1,2,3,2,3,3].unique())
// [1,2,3]
new File(.).eachFileRecurse ,println it- Cuvinte cheie noi n Groovy: def, as, in, it
it este folosit ca argument unic implicit n functori
def folosete la declararea unor variabile/metode de un tip neprecizat
as folosete la definirea de nume alternative (alias) pentru clase i metode (ntr-o instruciune import) dar i
pentru atribuirea de tip unui bloc. Exemple:
import static Math.random as rand
import groovy.lang.ExpandoMetaClass as EMC
double value=rand()
def metaClass= new EMC(Integer)

IE.11.7 Metode noi n clase preluate din Java


Metode echivalente unor operatori i care permit redefinirea acestor operatori:
Operator
a+b
ab
a*b
a/b
a%b
a++,++a
a--, --a
a**b
a|b
a&b
a^b
~a
a[b]
a[b] = c
Array
a << b
a >> b
a >>> b
a == b
a != b
a <=> b
a>b
a >= b
a<b
a <= b
a as type
switch(a){
case b:
}

Nume

Metoda

Operanzi

Plus
a.plus(b)
Minus
a.minus(b)
Star
a.multiply(b)
Divide
a.div(b)
Modulo
a.mod(b)
Increment
a.next()
Decrement
a.previous()
Power
a.power(b)
Or
a.or(b)
And
a.and(b)
Xor
a.xor(b)
Complement a.negate()
Subscript
a.getAt(b)
Subscript
a.putAt(b, c)

Number, string, collection


Number, string, collection
Number, string, collection
Number
Integral number
Number, string, range
Number, string, range
Number
Integral number
Integral number
Integral number
Integral number, string
Object, list, map, String, Array
Object, list, map, StringBuffer,

Integral number, append to


StringBuffers, Files, Writers, Lists
Right shift
a.rightShift(b)
Integral number
RSh unsign
a.rightShiftUnsigned(b)
Integral number
Equals
a.equals(b)
Object
Not equal
! a.equals(b)
Object
Spaceship
a.compareTo(b)
java.lang.Comparable
Greater than a.compareTo(b) > 0
Greater or equal a.compareTo(b) >= 0
Less than
a.compareTo(b) < 0
Less or equal a.compareTo(b) <= 0
Type coercion a.as
Type(typeClass) Any type
Classification b.isCase(a)
Object, range, list, collection, pattern, closure;
Left shift

a.leftShift(b)

- 164 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Metode noi n clasa String:


String capitalize()
String center (Number size)
Object eachLine (Closure clos)
String getAt(int k)
String padLeft (Number size)
String padRight (Number size)
int size()
String stripIndent()
List tokenize()
List tokenize(Character c)
List tokenize(String delim)

Prima litera din sir devine litera mare, daca nu era deja
Centrare sir pe o lungime data, cu adaugare de spaii
Aplica un functor pe fiecare linie din sir
Extrage caracterul din pozitia k (alternativa la operator de indexare)
Adauga spaii la stnga pn la lungimea size
Adauga spaii la dreapta pn la lungimea size
Lungime sir (echivalent cu length())
Eliminare spatii din fata fiecarei linii din sir
Creare lista de cuvinte separate prin spaii n sir
Creare lista de cuvinte separate prin caractere c n sir
Creare lista de cuvinte separate prin sirul delim n sir

Metode noi n clase de I/E


Metode din clasa Reader:
String getText()
Citeste coninut obiect Reader ca sir
List readLines()
Citeste toate liniile intr-o lista de linii
Iterator iterator()
Creare iterator pe liniile citite
Object eachLine (Closure cls) Pentru fiecare linie citit aplic un functor cls

Metode din clasa InputStream:


Object eachLine (Closure fun) Aplica un functor fun fiecrei linii citite
Iterator iterator()
Creare iterator pe octei cititi
String getText()
Creare sir cu toti octeii cititi
List readLines()
Creare lista cu toate liniile citite

Exist metode pentru citire linii n toate clasele Reader i InputStream deci i pentru System.in.
Metode din clasele PrintWriter, PrintStream:
void print (Object obj) Scrie valoarea obiectului obj formatat n stil Groovy
void println (Object obj) Scrie valoarea obiectului obj formatat n stil Groovy si trecere la linie nou

Exemple de citire linii de la consol i creare multime de cuvinte distincte extrase din aceste linii:
String text= System.in.getText()
Set words = text.tokenize() as Set

IE.11.8 Utilizarea de expresii regulate (RegEx)


Expresiile regulate folosesc la cutarea ntr-un text a unor secvene care se potrivesc (matches) cu un
ablon dat. Un ablon (pattern) descrie un format comun mai multor siruri (care pot avea si lungimi diferite)
folosind anumite caractere speciale, cu o anumit semnificaie. Exemple de caractere utilizate n iruri
sablon:
.
\d
\D
x*

orice caracter
orice cifra zecimala
orice caracter diferit de cifre zecimale
oricte caractere x consecutive (eventual zero)

Groovy foloseste clasele Java pentru expresii regulate, la care adaug civa operatori:
- 165 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

pentru siruri sablon (pattern), obiect de tip java.util.regex.Pattern


pentru metoda find (cutare cu sablon pentru o potrivire partial)
pentru metoda match (o potrivire complet cu sablon)

~String
=~
==~

Pentru a evita utilizarea de secvente escape n irul sablon, n Groovy o constant ir poate fi delimitat i
de caractere slash (/), pe lng delimitatorii ghilimele () folositi n Java. Exemplu:
n loc de \\d\\w

/\d\w/

Operatorii =~ i ==~ au ca rezultat un obiect de tip java.util.regex.Matcher, iar pentru acest obiect,
considerat ca o colecie de secvente potrivite cu ablonul, putem folosi metodele:
size() ca s aflm numrul de potriviri.
each() ca s aflm fiecare potrivire a ablonului n irul unde se caut.
replaceAll() ca s nlocuim toate secvenele care s-au potrivit cu un alt ir
Exemple:
pattern = ~"(G|g)roovy"
text = 'Groovy is groovy really groovy'
def m= (text =~ ~/Ggr/)
println m.size()? 'gasit' : 'negasit'
assert (text ==~ pattern) == false
pattern
// mai multe potriviri ale sablonului in text
m= (text =~ pattern)
m.each {println it}
for ( i in 0..m.size()-1) println m[i][0]
println ((text =~ /groovy/).replaceAll('nice'))

// negasit
// nu este o potrivire completa text cu

// afiare potriviri (secvente, sablon)


// afiare numai secvente din text
// Groovy is nice really nice

IE.11.9 Functori (Closures) n Groovy


Noiunea de closure (nchidere) este preluat din limbajele funcionale, ca i cea de functor (obiect funcie);
limbajul C# folosete cuvntul delegate pentru aceeai construcie (o funcie tratat ca obiect).
In Groovy un functor este o secven de cod ntre acolade (cu parametri) care poate fi atribuit unei variabile
(referin), poate fi transmis ca argument unei funcii (sau unui alt functor) si care poate constitui rezultatul
unei funcii (sau unui functor). Un functor poate fi folosit la fel ca orice alt obiect si are tipul implicit
Closure (tip care poate fi folosit i n declararea unor variabile sau argumente).
In Java o clas cu o singur funcie poate fi definit ca o clas top-level sau ca o clas inclus cu sau fr
nume; clasa trebuie instaniat pentru a folosi un obiect ce contine o funcie. Forma Java cea mai apropiat
de un functor Groovy este o clas inclus anonim definit n momentul instanierii ei (instaniere care poate
avea loc chiar n instruciunea care foloseste obiectul).
Un functor Groovy nu necesit definirea unei clase care s respecte o anumit interfa (un functor nu este
legat de o anumit interfa). In Groovy exist mai multe funcii predefinite care au ca argument un functor;
acest functor se poate defini n prealabil (i capt un nume) sau chiar n momentul folosirii lui (functor
anonim). Utilizarea de functori are ca efect un cod surs mai compact i mai usor de neles (permit o
exprimare mai direct i mai natural a unor aciuni).

- 166 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

IE.11.9.1 Sintaxa pentru definirea si utilizarea de functori


Instruciunile dintr-un functor sunt ncadrate de acolade, dar compilatorul Groovy deosebete un bloc de cod
de un functor. Un bloc poate s apar n definiia unei clase, a unei interfee sau a unei metode, n
instruciunile if, while, for, do, switch, try sau n iniializari (de vectori, de ex.). Orice alt utilizare a unui
bloc ntre acolade este considerat ca un functor. Primul exemplu este un functor fr parametri care
afieaz o linie alb:
def nl ={ println ''} // definire functor cu nume
3.times (nl)
// utilizare functor nl
3.times nl
// alta utilizare functor nl
De multe ori functorul este definit chiar n locul unde este folosit i nu are nume. Exemplu:
3.times { println ()} // scrie 3 linii albe
De observat absena parantezelor pentru argumentul funciei times(); forma anterioar este o forma abreviat
pentru:
3.times ( { println()} )
Funcia println() din functor trebuie s aib fie paranteze, fie un argument deoarece, n lipsa acestora, este
considerat ca o variabil din scriptul (din spaiul de nume) n care este definit functorul, dar nu exist o
variabil cu acest nume.
Un functor poate fi apelat ca o funcie folosind metoda call() (din clasa Closure). Exemplu:
def wline = { def ln=''; 50.times{ln+='-'}; println (ln)}
wline.call()
Un functor poate avea un rezultat. In exemplul urmtor functorul are ca rezultat un sir:
def line = { def ln=''; 50.times{ln+='-'};return ln}
print line.call()
Instruciunea return poate lipsi dac rezultatul functorului este acelai cu rezultatul ultimei instruciuni:
def line = {def ln=''; 50.times {ln +='-'}; ln+='\n'}
Obiectele functor aparin clasei groovy.lang.Closure, iar cuvntul Closure poate fi folosit n declararea de
variabile (inclusiv proprieti ale unei clase), de argumente i de funcii, ca orice alt tip clas. Exemplu:
// calcul timp de rulare 'action' de n ori
def calcTime(n,Closure action) {
start=System.currentTimeMillis()
n.times {action (222,5)}
stop=System.currentTimeMillis()
return stop-start
}
println calcTime (1000,rec) // repeta de 1000 de ori calculul cmmdc(222,5)

Dup contextul n care este definit un functor putem avea urmtoarele situaii:
- 167 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

- Functor definit ntr-un script;


- Functor definit ntr-un obiect (ntr-o clas)
- Functor definit n alt functor

IE.11.9.2 Functori cu argumente


Un functor poate avea argumente; dac este un singur argument, acesta poate folosi numele implicit it i nu
trebuie declarat explicit (dar poate fi). Exemplele urmtoare folosesc argumentul implicit it:
// functor anonim definit ad-hoc
1.upto(10) { println "Radical din $it = ${Math.sqrt(it)} " }
// functor cu nume
def sqrt= { println "Radical din $it = ${Math.sqrt(it)} " }
for (k in 1..10) sqrt.call(k)
// forma extinsa de folosire
for (k in 1..10) sqrt(k)
// forma scurta
Parametrii efectivi pot fi transmii prin metoda call() din clasa Closure sau direct dup numele functorului
(utilizat ca o funcie).
In cazul parcurgerii unui dicionar cuvntul cheie it se refer la o pereche cheie-valoare. Exemplu de creare a
unui dicionar invers (n care cheia din dictionarul initial devine valoare iar valoarea devine cheie n noul
dictionar):
romeng =['unu':'one','doi':'two','trei':'three']
romeng.each { println it.key+'='+it.value}
engrom=[:]
romeng.each {engrom[it.value]=it.key }
println engrom

// roman-englez
// afiare
// englez-roman
// afiare cu Map.toString

Exemplu de functor cu dou argumente folosit drept comparator la sortarea unei liste:
fruit = [ "apple", "Orange", "Avocado", "pear", "cherry" ]
fruit.sort { a,b -> a.size()- b.size() }
// odonare dupa lungime siruri
Este posibil s definim i tipul argumentelor, pentru a face codul mai usor de neles. Exemplu:
def word = { String s, int k -> s.split(' ')[k] }

// functor cu doua argumente

Exemplu de functor care extrage un cuvnt dintr-un ir:


def word = { s, k -> s.split(' ')[k] }
// functor cu doua argumente
// utilizare functor word
str="unu doi trei patru "
for (k in 0..3) println word(str,k) // unu,doi,trei,patru
Pentru a introduce o nou metod word() n clasa String trebuie s adugm metaclasei un functor, care va
aciona asupra obiectului pentru care se apeleaz metoda (delegate):
String.metaClass.word={ delegate.split(' ')[it] }
// utilizare
for (k in 0..3) println str.word(k) // unu,doi,trei,patru

- 168 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

IE.11.9.3 Aplicaii uzuale pentru functori


Functori cu rol de functii callback
Rolul unei funcii callback n programare poate fi ilustrat prin funcia de comparare de obiecte care trebuie
transmis unei funcii de ordonare (sau de cutare ntr-o colecie ordonat): definitia funciei de comparare
depinde de tipul obiectelor comparate dar ea poate avea acelai prototip indiferent de tipurile comparate
(folosind tipul generic Object n Java sau void* n C). Pentru a avea o singur functie de sortare pentru orice
list (cu date de orice tip) vom transmite acestei funcii ca argument funcia de comparare. Exemplu de
ordonare descresctoare a unui vector de obiecte n Java:
Arrays.sort (a, new Comparator() {
// definire clasa anonima
public int compare (Object o1, Object o2) { // cu o singura functie
Comparable c1=(Comparable)o1;
Comparable c2=(Comparable)o2;
return c2.compareTo(c1);
}
});
In Groovy metoda "sort" se poate aplica oricrui obiect de tip Collection, are ca rezultat un obiect de tip List
i poate avea ca argument un obiect de tip Comparator sau un functor. Exemplu cu argument Comparator:
list=['unu','doi','trei']
println list.sort()
// crescator
println list.sort (new Comparator() {int compare(a,b){ b.compareTo(a)} })
Varianta cu functor este mai scurt si este n spiritul limbajului Groovy:
println list.sort {a,b -> b.compareTo(a)}
In Groovy metodele care pot avea ca parametru (i) un functor sunt fie metode noi, fie metode Java care au
fost suprancrcate cu o noua form.
Functori ca aciuni repetate ntr-un ciclu sau ntr-o enumerare
Primul exemplu este soluia alternativ Groovy pentru programarea unui ciclu prin introducerea n clasa
Number a unor metode noi cu argument functor:
times(Closure cl), upto (Number to, Closure cl), each (Closure cl)
Exemple:

// calcul factorial 5!
nf=1
(1..5).each {nf *= it }
1.upto(5) {nf *=it}

// varianta 1
// varianta 2

boolean prim(int n) {
// definire functie de test daca numar prim
este=true
3.upto(n-1){ if(n%it==0) este=false}
return este
}
5.upto(50), print prim(it)? it+' ':''- // utilizare functie prim

- 169 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Deseori apare situaia n care o colecie de obiecte este parcurs pentru a prelucra elementele coleciei sau
pentru a cuta un anumit obiect sau pentru a selecta obiectele care satisfac anumite condiii. Pentru fiecare
element din colecie se execut o actiune (calcule, comparaii). In Java se foloseste de obicei un iterator pe
colecie sau un ciclu cu regsire prin indici asociai elementelor coleciei (numai pentru liste):
for (Iterator it=list.iterator(); it.hasNext();) {
Integer x = (Integer) it.next();
System.out.println ( x%2==0 ? x+" par" : x+" impar");
}
Incepnd cu Java 5 este simplificat iterarea pe o colecie generic:
for (Integer x: list)
System.out.println ( x%2==0 ? x+" par" : x+" impar");

In practic exist anumite prelucrri tipice pe colecii : cutarea primului obiect sau tuturor obiectelor care
satisfac anumite condiii, aplicarea unor operaii (transformri) fiecrui element din colecie, pe loc sau cu
crearea unei noi colecii cu rezultatele operaiilor. Pentru aceste prelucrari s-au definit n Groovy noi metode
aplicabile tuturor coleciilor: find(), findAll(), each(), collect(), sum() .a. Aceste metode primesc ca
argument un functor ce defineste fie criteriul de cutare, fie operaia aplicat elementelor coleciei.
Argumentul implicit din functor desemneaz elementul curent din colecie. Exemple:
int[] a =[1,2,3,4,5,6,7,8,9]
a.each { println " $it ${it%2==0?'even':'odd'}" }
a.findAll { it % 2 } // scrie numerele impare (1 3 5 7 9)
Anumite metode din interfaa Java Collection au fost suprancrcate cu o form care admite ca argument un
functor. Exemplu de eliminare a duplicatelor dintr-o list :
a =[1,2,3,1,1,4,4,2] ; a.removeAll { a.count (it)>1 }
println a.sort() // [ 1 2 3 4 ]
Metoda each() este aplicabil i caracterelor dintr-un ir. Exemplu:
'abcd'.each { print it+' ' } // scrie: a b c d
In clasa File s-au introdus metode de enumerare a fisierelor dintr-un director (eachFile) si de enumerare a
subdirectoarelor (eachDir) cu parametri functor. Exemplu de definire a unui functor recursiv:
def listFiles
// declaratie necesara inaintea apelului recursiv
listFiles = {
println "Dir ${it}"
it.eachDir (listFiles)
// parametru nume de functor
it.eachFile { if(! it.isDirectory()) println " File ${it}" }
}
// utilizare
listFiles ( new File ("d:/groovy"))
Variant de funcie pentru listare recursiv fiiere dintr-un director:

- 170 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

def files (File f) {


f.eachFile { if( it.isDirectory()) files(it)
else println it
}
}
In Groovy aceast operaie se poate face mai simplu cu o noua metod:
new File(".").eachFileRecurse {println it}
Metoda eachLine() din clasa File repet un functor pentru fiecare linie dintr-un fiier, incluznd deschiderea,
inchiderea fiierului i tratarea eventualelor excepii. Exemplu de afiare cu numerotare linii:
int k=1
new File("a.txt").eachLine { println k++ +' '+it } // { println "$k $it";k++}
Deoarece permit o exprimare mai natural a unor operaii (aciuni) functorii se folosesc n crearea de limbaje
specializate DSL.

IE.11.10 Colecii Groovy


Tipurile colective n Groovy sunt:
-

domenii de valori (ranges)


liste (lists)
asocieri sau dictionare (maps)

Un domeniu este specificat folosind operatorul .. (sau ..<) ntre dou valori ce reprezint limita inferioar
i limita superioar a domeniului de valori. Exemple:
1..10
1..<10
10..1
def a=1..9

// inclusiv limitele 1 si 10
// exclusiv limita superioar 10
// domeniu inversat
// obiect domeniu cu nume

Ca obiecte dintr-o clas implicit (Range), domeniile suport anumite metode: contains, size, each, s.a. Un
domeniu se poate folosi ntr-o instruciune for astfel:
def log = '' "
for (x in 1..9)

log += x

// for ( x in a)

O alt utilizare este ntr-o instructiune switch pentru mprtirea unor valori n (sub)clase:
age = 36
switch(age) {
case 16..20 : insuranceRate = 0.05 ; break
case 21..50 : insuranceRate = 0.06 ; break
case 51..65 : insuranceRate = 0.07 ; break
default: throw new IllegalArgumentException()
}
Metoda each() aplic un functor fiecrei valori din domeniu. Exemplu:
def cls= {x-> println " $x ${x%2==0?'impar':'par'}" }
// definire functor cu nume
(1..9).each (cls)
// utilizare functor cls
- 171 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Limitele unui domeniu pot fi obiecte de tip Date sau din orice clas care conine metoda compareTo()
(implementeaz interfata Comparable) sau care implementeaz metodele next() si previous() (echivalente
operatorilor ++ si ).
O list Groovy este o colecie cu elemente accesibile prin indici, i care se extinde automat prin atribuire
ctre elemente cu indici mai mari ca dimensiunea listei. O list Groovy combin avantajele vectorilor cu
dimensiune fix (selecia de elemente prin indici) cu avantajele obiectelelor din clasa ArrayList (extindere
automat, compactare dup eliminare de elemente, s.a.). Listele au implicit tipul ArrayList si se pot construi
prin includerea elementelor listei ntre paranteze drepte si separate prin virgule. O list vid se noteaz ca [ ].
Exemple de definire si utilizare a unei liste de siruri:
def a = ['zero','unu','doi','trei']
// un obiect de tip List
println a[1]
// scrie unu
println a.size()
// scrie 4 (dimensiune lista)
a << 'patru'
// adaugare la sfarsit de lista
println a
// afisare continut lista
a[8]='opt'
// extindere lista
println a.size()
// scrie 9 (dimensiune lista)
Pentru afiarea elementelor unei liste, cte unul pe o linie, avem mai multe posibiliti:
a.each { println it }
println a.join('\n')

// adauga \n fiecarui element din lista

Se poate folosi selecia prin indici i extinderea prin folosirea de indici mai mari ca cei existeni i pentru
obiectele de tip LinkedList. Exemplu:
def a=['a','b','c'] ; def list= new LinkedList (a)
list[3]='d' ; println list
Operatorul de indexare [ ] este echivalent metodelor getAt() (n dreapta) i putAt() (n stnga). Folosind acest
operator se pot insera sau elimina mai multe elemente dintr-o list. Exemple:
myList = ['a','b','c','d','e','f']
myList [0..2] = ['x','y','z']
myList[3..5]=[ ]

// devine *x,y,z,d,e,f+
// devine *x,y,z+

Pentru adugare de elemente la o list se pot folosi i operatorii + sau <<, iar pentru eliminare de
elemente se poate folosi operatorul -. Exemple:
a=[]; a+=*1,2+ ; a<<3<<4
a -= *4+
// sau a-=2
Ca i domeniile, listele se pot folosi n instruciuni for,switch i n expresii regulate. Exemplu:
def isPrime = {n->
def primes=[2,3,5,7,11,13]
if (n in primes ) return 'prim'
for (m in primes) {if (n%m==0) return 'neprim'}
return 'prim'
}
(6..20).each {println it+": "+ isPrime(it)}
- 172 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

In Groovy exist o mulime de metode noi aplicabile listelor: sort, reverse, intersect, disjoint, remove,
removeAll, findAll, unique, collect etc. Metoda collect() aplicat unei liste va crea o nou list cu rezultatele
aplicrii unui functor asupra elementelor listei iniiale. Exemplu:
println ((2..20).asList().collect (isPrime))

// nu pot lipsi parantezele !

Orice list se poate folosi ca stiv prin metodele pop() i push() (echivalent cu <<). Exemplu:
def stiva=[]
(1..5).each { stiva.push(it)}
while (stiva.size()>0)
print stiva.pop()+" "
Un exemplu de utilizare a listelor este si sortarea quicksort recursiv:
def quickSort(list) {
if (list.size() < 2) return list
def pivot = list[list.size().intdiv(2)]
def left = list.findAll {item -> item < pivot }
def middle = list.findAll {item -> item == pivot }
def right = list.findAll {item -> item > pivot }
return (quickSort(left) + middle + quickSort(right))
} Dictionare (Asocieri)

IE.11.10.1 Dicionare
O asociere (sau dicionar ="Map") este o list de perechi cheie-valoare, la care cheia poate fi folosit ca
indice. Se poate extinde ca i o list. Un obiect dicionar vid are forma [:]
Sintaxa general a unui obiect dicionar este:

[ key1:value1, key2:value2,..]

Exemple:
def b=['unu':1,'doi':2,'trei':3]
// un obiect asociere
println b['doi']
// scrie 2
println b.doi
// scrie 2
b.patru=4
// extindere dictionar
b['sase']=6
// extindere dictionar
println b
// ["unu":1, "doi":2, "trei":3, "patru":4, "sase":6]
println b.size()
// scrie 5 (dimensiune dictionar)
Pentru chei de tip String se pot omite ghilimelele, dac nu sunt cuvinte cheie ale limbajului i nu conin
caractere speciale. Exemplu:
def b=[unu:1,doi:2,trei:3]
Selectarea valorii asociate unui chei se poate face n mai multe feluri:
- prin indexare nume dicionar cu valoarea cheii: println b['doi']
- prin notatia map.key : println b.doi
- prin metoda get(): println b.get(doi)

- 173 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Metoda get() poate primi dou argumente; dac nu se gseste cheia (primul argument) n dicionar atunci se
adaug la dicionar o pereche cu argumentele metodei get().
Pentru asocierile Groovy se pot folosi metodele din interfaa Map din Java: entrySet, keySet, values,
containsKey, containsValue, .a. plus metode noi ca any() i every().
Pentru a itera pe un dictionar putem folosi un ciclu for ( x in map) sau metoda each().
Alte metode noi pentru asocieri sunt:
- subMap() pentru extragerea perechilor care au anumite chei:
myMap = [a:1, b:2, c:3] ; def abMap = myMap.subMap(['a','b'])
- findAll() caut perechile care satisfac un functor: def found = myMap.find { entry -> entry.value < 2}
- find() caut o pereche care satisface un functor
- collect() adun ntr-o list perechile care satisfac un functor:
def doubled = myMap.collect { entry -> entry.value *= 2}
In cazul unei metode folosirea unui parametru cu nume este de fapt transmiterea unui dicionar, n care cheile
sunt nume de argumente iar valorile asociate sunt valorile argumentelor. Pot lipsi parantezele drepte dar nu i
parantezele rotunde care ncadreaz lista de argumente (care este un dicionar). Exemplu:
def f (Map args) { ['a','b','c'].each {args.get(it,0) }
println f ([b:4, a:2])
println f (a:3, b:1, c:2)
println f ( c:1)

return args.a - args.b + args.c }

Exemplul urmtor folosete un dictionar pentru afiarea frecvenei cuvintelor distincte dintr-un text:
def text="unu doi trei trei doi trei"
def words = text.tokenize()
def wordFrequency = [:]
words.each { word ->
wordFrequency[word] = wordFrequency.get(word,0) + 1
}
def wordList = wordFrequency.keySet().toList()
wordList.sort { wordFrequency[it] }
def statistic = "\n"
def n=wordList.size()
wordList[0..n-1].each { word ->
statistic += word.padLeft(12) + ': '
statistic += wordFrequency[word] + "\n"
}
println statistic

IE.11.10.2 Metode Groovy pentru liste i dicionare


Metode noi n interfaa Collection:
- 174 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

List collect (Closure f)

aplica functorul f fiecarui element din colecie si creeaza o lista

Number count (Object value)

numara de cate ori apare value in colecie

Object find (Closure f)

cauta elementul din colecie care satisface condiia f

Collection findAll (Closure f)

creare colecie cu elementele care satisfac condiia f

Collection plus (Collection c)

reunirea acestei colecii cu colecia c

List sort ()

ordonare colecie cu rezultat lista folosind comparatorul implicit

List sort (Closure f)

ordonare folosind drept criteriu un functor f

Collection split (Closure f)

sparge colecia n doua pe baza functorului f

Collection unique()

elimina elementele duplicat folosind comparatorul implicit

Collection unique(Closure f)

elimina elementele duplicat folosind functorul f

Exemple de utilizare:
def odd = [1,2,3,4,5].findAll { item ->item % 2 == 1 }
assert [1,2,3,4,5] == [1,[2,3],[[4]],[],5].flatten()

// odd=[1,3,5]

Metode noi n interfaa List:


Object getAt (int k)

pentru redefinire operator de selecie element din lista: a[k]

List getAt (Range r)

ptr redefinire operator de selecie de forma a[1..2]

List minus (Object obj)

ptr redefinire operator - ptr eliminare din lista

Object pop()

scoate si elimina ultimul element din lista

boolean push (Object obj)

adauga obj la aceasta lista

void putAt(int k, Object obj)

ptr redefinire operator de indexare la atribuire: a[k]=obj

List reverse()

inversare ordine elemente din lista

List reverseEach(Closure f)

aplica functorul f cu iterare in ordine inversa

IE.11.11 Metaprogramare n Groovy


IE.11.11.1 Manipularea dinamic de clase si obiecte n Java
Groovy este un limbaj dinamic, adic folosete tipuri dinamice (modificate la atribuire), permite modificarea
la execuie a tipurilor stabilite la compilare, permite definirea de noi tipuri n cursul execuiei, are un
mecanism mai flexibil de apelare/interceptare a metodelor i permite evaluarea de cod la execuie.
- 175 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

In Java se poate explora n cursul executiei, prin reflecie, structura unui program, astfel c putem afla
numele claselor folosite, ce metode i constructori au, .a. Aceast structur este stabilit la compilare (la
scrierea programului) i poate fi folosit la execuie (de ex. pentru a instania clase obtinue la execuie), dar
nu mai poate fi modificat.
Fiecare clas Java are asociat un obiect de tip Class care conine informaii despre clasa respectiv i care
constituie suportul pentru utilizarea de clase cunoscute numai la execuie i pentru alte operaii de reflecie
sau introspectie. Exemplu de instaniere clas cu nume necunoscut la scrierea programului dar care respect
o interfa (numele poate fi citit la execuie dintr-un fiier de proprieti):
public static Comparator ObjectFactory (String className) {
Comparator obj=null;
try {
Class cls = Class.forName(className);
obj =(Comparator) cls.newInstance();
} catch (Exception e) { e.printStackTrace() ;}
return obj;
}
// utilizare
String className="MyComp";
// se putea citi dintr-un fisier
Comparator comp = Factory.ObjectFactory(className);
// obiect comparator
Collections.sort (list,comp);
In Java legarea (Binding) corpului metodei de un apel al metodei (nestatice) se face la execuie si nu la
compilare, ceea ce permite polimorfismul. Se spune c pentru metodele obiectelor are loc o legare
ntrziat (Late Binding), spre deosebire de legarea timpurie (la compilare) de metodele statice.
Facilitile de metaprogramare din Groovy pot fi privite ca o extindere a refleciei din Java prin adugarea
unei metaclase fiecrei clase sau obiect. Spre deosebire de obiectul Class din Java, metaclasa Groovy
permite adugarea de noi proprieti si metode claselor Groovy (sau Java). In plus se pot intercepta apelurile
de metode existente sau inexistente, pentru adugarea de noi operaii sau pentru nlocuirea operaiilor
existente. In timp ce obiectul Class descrie comportarea unei clase la compilare, metaclasa Groovy descrie
comportarea la execuie a obiectelor unei clase.
Exemplul urmtor pune n evident diferenta Groovy-Java la implementarea polimorfismului. In Groovy se
va scrie string iar n Java programul urmtor va scrie object:
class Foo {
// Groovy
def print (Object o) , println object" def print (String s) , println string" }
Object obj = "string"
new Foo().print(obj)
class Foo {
// Java
void print (Object o) { System.out.println ("object"); }
void print (String s) { System.out.println ("string"); }
public static void main (String a[]){
Object obj = "string" ;
new Foo().print(obj);
}
}
- 176 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

IE.11.11.2 Facilitti de metaprogramare n Groovy


Prin metaprogramare se ntelege posibilitatea de modificare a programelor n cursul execuiei, inclusiv
posibilitatea de a evalua expresii simbolice. Mecanismul de implementare a modificrii unui program de
ctre acesta se numeste protocol meta-obiect (MOP=Meta-Object Protocol).
Groovy MOP permite interceptarea apelurilor de metode ctre o clas, adugarea de noi metode claselor
existente i chiar sintetizarea de metode i clase n mod dinamic (la execuie). Aparent, obiectele i
modific comportarea (deci tipul i clasa) n cursul execuiei.
Groovy MOP se bazeaz att pe utilizarea noilor metode prezente n clasele Groovy (invokeMethod() .a.)
ct si pe utilizarea de metaclase, care sunt generate de compilator pentru clasele Groovy, dar pot fi adugate
i claselor Java care implementeaz o anumit interfa.
In Groovy exist mai multe faciliti care pot fi asociate cu metaprogramarea:
Evaluarea de cod:

evaluate(def add = ,x, y -> x + y-)

Interceptarea tuturor apelurilor de metode (invokeMethod())


Interceptarea apelurilor de metode inexistente (methodMissing())
Interceptarea accesului la proprieti (getProperty(), setProperty())
Adugarea dinamic de metode, constructori si proprieti (ExpandoMetaClass)
Preluarea temporar de metode de la alte clase (Categories)
Adugarea de metode de la alte tipuri (Mixins)
Modalitatea de modificare a metodelor unei clase depinde de situaia clasei respective:
- Dac dispunem de sursa clasei Groovy i o putem modifica atunci se redefinete metoda invokeMethod
i/sau metoda missingMethod, prezente n clasele Groovy si n clasele Java care implementeaz interfaa
GroovyObject;
- Dac nu dispunem de sursa clasei atunci se folosete o clas ExpandoMetaClass generat de compilator
pentru clasa care trebuie modificat si care conine metodele invokeMethod i missingMethod. Metaclasa
unei clase se obtine printr-o proprietate a oricrei clase. Exemplu:
Foo.metaClass
Dintre utilizrile actuale ale metaprogramrii n Groovy menionm:
- Programarea orientat pe aspecte (AOP), adic injectarea de cod nainte (before), dup (after) sau n locul
(around) codului unei metode (cod scris de programator).
- Crearea de teste unitare (clase si metode de test generate automat).
- Crearea de obiecte surogat (Mock objects) pentru testare.
- Crearea de metode de interogare a bazelor de date adaptate claselor domeniu (dynamic finders).
- Crearea de generatori (builders) pentru structuri ierarhice.
- Definirea de noi limbaje specializate (DSL=Domain Specific Languages)
- 177 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

IE.11.11.3 Crearea de noi clase n Groovy


Aa cum sugereaz i numele, clasa Expando se poate extinde dinamic; ea nu are iniial metode sau
proprieti, dar acestea se adaug ulterior. Metodele se definesc prin functori.
Exemplu de creare obiect dintr-o clas generat la execuie dintr-un Expando:
def counter= new Expando()
def count= 0
counter.incr= { count++; show() }
counter.decr= { count--; show() }
counter.show= { timesShown++; count }
counter.timesShown= 0
counter.incr(); counter.incr(); counter.decr(); counter.incr()
counter.show()
// 2
O nou clas poate rezulta i din reunirea (mixin) metodelor altor clase sau interfee, ceea ce are efectul
unei moteniri multiple. Exemplu:
class Superman { def fly() { println "fly" }
class Ninja { def fight() { println "fight" } }
class Person { def sleep () { println "sleep" } }
Person.mixin Superman, Ninja
p = new Person()
p.sleep() ; p.fly() ; p.fight()

IE.11.11.4 Metaclase n Groovy


Obiectele utilizate n Groovy sunt de trei feluri:
- POJO (Plain Old Java Object), care extind clasa Object din Java (instanieri de clase Java).
- POGO (Plain Old Groovy Object), care extind clasa Object si implementeaza interfaa GroovyObject.
- Interceptori, care sunt obiecte POGO cu posibiliti de interceptare,preluate prin implementarea interfeei
GroovyInterceptable.
Un obiect POGO are n plus fa de un obiect POJO urmtoarele metode:
public interface GroovyObject{
Object invokeMethod(String name,Object args);
Object getProperty(String property);
void setProperty(String property,Object newValue);
MetaClass getMetaClass();
void setMetaClass(MetaClass metaClass);
}
Clasele Java (prelucrate de compilatorul Java) pot implementa interfaa GroovyObject pentru a se comporta
asemntor (dar nu identic) cu clasele Groovy.
Clasele Groovy i Java, prelucrate de compilatorul Groovy, implementeaz automat interfaa GroovyObject
(au o implementare implicit pentru metodele din interfa); fiecare clas va avea asociat o metaclas si se
- 178 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

poate folosi metode getMetaClass() sau proprietatea metaClass. Exemplu de acces la metaclasa unei clase
JDK:
def ByteMeta = Byte.metaClass
println ByteMeta.methods.join ('\n')

// java.lang.Byte
// metode din clasa Byte si metode din GroovyObject

Exemplu de acces la metaclasa unei clase Groovy:


class Book {
String title; Date year
}
println Book.metaClass.methods.join ('\n')
In exemplul anterior se afieaz i metodele generate automat pentru acces la proprietile clasei Book:
public String getTitle(), public void setTitle (String title), public .Object Book.getProperty(String), public
void Book.setProperty(String,Object), .a.
Interfaa GroovyInterceptable extinde interfaa GroovyObject fr s adauge alte metode; pentru obiectele
care implementeaz aceast interfa toate apelurile de metode sunt interceptate de metoda invokeMethod().
Metaclasa Groovy conine metadate despre clasa asociat (cmpuri, metode, proprieti) i implementeaz
urmtoarele metode:
Object invokeMethod(Object obj, String methodName, Object args)
Object invokeMethod(Object obj, String methodName, Object[] args)
Object invokeStaticMethod(Object obj, String methodName, Object[] args)
Object invokeConstructor(Object[] args)
Implementarea implicit a metodei invokeMethod() din GroovyObject apeleaz metoda cu acelai nume
din metaclas:
public Object invokeMethod(String s, Object obj) {
return getMetaClass().invokeMethod(this, s, obj);
}
public Object getProperty(String s) { return getMetaClass().getProperty(this, s); }
Toate metaclasele sunt reunite ntr-un registru de metaclase astfel nct o metaclas s poat fi regsit dup
numele clasei asociate. In cazul claselor Groovy este posibil accesul la metaclas i pornind de la un obiect al
clasei. Metaclasa unui obiect Groovy poate fi diferit (cu metode n plus) de metaclasa clasei de care aparine
acel obiect (se pot injecta metode la nivel de obiect).
Pentru a obtine metaclasa asociat unei clase Groovy se foloseste metoda getMetaClass() sau proprietatea
metaClass. Metaclasa unei clase A are metametode ce corespund metodelor clasei A, cu acelasi nume si
argumente. Exemplu de obtinere a numelui unei metametode din metaclasa clasei String:
println String.getMetaClass().getMetaMethod ('trim')
println String.metaClass.getMetaMethod ('trim')
Rezultatul metodei getMetaClass() sau al proprietii metaClass aplicate unui obiect este un obiect de tipul
HandleMetaClass, un tip clas care implementeaz interfaa MetaClass.
ExpandoMetaClass este o alt implementare a interfeei MetaClass si este diferit de HandleMetaClass.
Un obiect ExpandoMetaClass asociat unei clase se poate obtine i prin instaniere:
class Person ,- 179 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

def emc= new ExpandoMetaClass(Person)


Metaclasa are aceleai metode ca i clasa asociat (String n exemplul anterior), inclusiv metodele
invokeMethod()i missingMethod().
Exemplu de apelare a unei metametode (ntr-un script Groovy):
mytrim= String.getMetaClass().getMetaMethod ('trim')
mystr= mytrim.invoke(' abc ')
println mystr.size()
// scrie: 3
De observat c numele (meta)metodei poate fi obinut n cursul execuiei (ntr-o variabil de tip String) i c
n locul numelui clasei String putem folosi o variabil de tip String pentru obtinerea metaclasei.
Metoda respondsTo() din orice metaclas ne permite sa aflm dac o clas conine sau nu o metoda cu nume
cunoscut. Metoda respondsTo() are ca rezultat o list de metametode cu numele indicat din metaclas; lista
poate fi vid dac nu exist nici o metod cu acel nume i cu acel tip (i/sau numr) de argumente. Exemplu:
str='abc'
println str.metaClass.respondsTo(str,'trim')?'yes':'no' // yes

IE.11.11.5 Extinderea dinamic a claselor Groovy


Adugarea unei noi metode la o clas se face prin adugarea unei metametode la metaclasa asociat folosind
sintaxa urmtoare:
metaclasa.metoda = { bloc }
Exemplu:

// metoda definita printr-un functor

String.metaClass.trimAll = {
// elimina toate blancurile dintr-un sir
result=new StringBuffer()
delegate.each { if (it !=' ')result.append(it) }
result
}
println 'a b c d'.trimAll()
// abcd
Exemplu de adugare la clasa String a metodei "word(int)" pentru extragerea unui cuvnt cu indice dat
dintr-un ir (ir cu mai multe cuvinte separate prin cte un spaiu):
String.metaClass.word={ delegate.split(" ")[it] }
str="unu doi trei patru "
for (k in 0..3) println str.word(k) // unu,doi,trei,patru
Pentru a folosi noua metod fr paranteze (facilitate util la definirea de limbaje specializate), se va defini
aceast metod ca o metod de acces la o proprietate (iar numele metodei devine nume de proprietate).
Exemplu :
String.metaClass.getTrimAll = { ... } // aceeasi definitie ca mai sus
String.metaClass.getSize = { delegate.size() }
assert s1.trimAll.size == s2.trimAll.size
De asemenea se pot aduga metode statice unor clase Groovy. Exemplu:
Integer.metaClass.static.isEven={val->val%2==0}
- 180 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

println "Is2even?" + Integer.isEven(2)


Pentru adugarea unui nou constructor unei clase sintaxa este puin diferit:
Integer.metaClass.constructor << { Date d -> d.getDate() }
println new Integer(new Date()) // numarul zilei in luna curenta
Metodele injectate prin ExpandoMetaClass nu sunt apelabile din programe Java (compilate cu un
compilator Java).
Adugarea de noi proprieti unei clase se poate face fie prin redefinirea metodelor getProperty() si
setProperty(), fie prin metaclas.
Proprietatea properties pentru o clas produce o list cu toate metodele si cmpurile clasei, iar pentru un
obiect al clasei produce un dicionar cu numele i valorile cmpurilor, inclusiv cmpurile adugate de
compilator class i metaClass. Exemplu de afisare a numelor de cmpuri dintr-un obiect, dup excluderea
celor adugate de compilator:
println new Book().properties.keySet().findAll { !(it =~ /lass/)} // keySet=nume de campuri
Exemplu de adugare a unei metode toString() unei clase, care creeaz un ir cu numele i valoarea fiecrui
cmp dintr-un obiect:
Book.metaClass."toString" = {
def s=""
def props= delegate.properties.findAll { !(it =~ /lass/)}
props.each { s+= it.key +':'+ it.value + ' '}
return s
}
// utilizare
def b= new Book(title:'Java',author:'Gosling',year:1995)
println b.toString()
// println b afiseaza adresa obiectului !

IE.11.11.6 Interceptarea de metode n Groovy


In Groovy intercepia i inseria de cod se pot face fie direct asupra unui obiect, fie prin intermediul
metaclasei sale.
Dac o clas Groovy implementeaz interfaa GroovyInterceptable atunci toate apelurile ctre obiecte din
aceasta clas apeleaz invokeMethod(), iar dac este o clas Groovy "normal" atunci se va apela
invokeMethod() numai n caz c se apeleaz metode inexistente n clasa de care aparin obiectele (n realitate
logica de apelare a metodelor Groovy este mai complicat).
Metoda invokeMethod() este cea care redirecteaz un apel ctre o alt metod (eventual sintetizat ad-hoc n
functie de proprietile clasei) i are ca argumente numele i parametrii metodei ctre care se face
redirectarea. Metoda invokeMethod() permite programarea orientat pe aspecte prin invocarea unei metode
ce trebuie executat nainte (sau dup) mai multe metode din una sau din mai multe clase.
Exemplu de clasa Calc, cu dou metode (mul,div) pentru care se dorete trasarea apelurilor de metode prin
afiare pe ecran a numelui fiecrei metode apelate mpreun cu valorile argumentelor acestora :

- 181 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

class Calc implements GroovyInterceptable {


def mul (int a,b) {return a*b}
def div (int a,b) {return a/b}
def logon () { System.out.print "logon " }
def invokeMethod (String name,args){ // name= nume metoda apelata
if (name != 'logon')
Calc.metaClass.getMetaMethod('logon').invoke(this,null)
// insertie apel logon
System.out.println name+' '+args
def method=Calc.metaClass.getMetaMethod(name,args)
// nume metoda apelata
if (method!= null)
// daca exista metoda 'name'
method.invoke(this,args) // atunci se apeleaza
else return Calc.metaClass.invokeMethod(this,name,args)
}
}
calc=new Calc()
// verificare
println calc.mul(2,3)
println calc.div(3,2)
Interceptarea de metode prin intermediul metaclasei este aplicabil si claselor Java.

IE.11.11.7 Utilizri practice ale metaprogramrii


Delegarea de operatii ctre obiecte din alte clase (n vederea reutilizrii lor) este destul de incomod n Java,
deoarece trebuie scrise apelurile de metode pentru obiectele delegat. Ex:
class StaffMemberUsingDelegation {
private delegate = new Person()
def salary
def getName() { delegate.name }
def setName(name) { delegate.name = name }
def getAge() { delegate.age }
def setAge(age) { delegate.age = age }
def getNationality() { delegate.nationality }
def setNationality(nationality) { delegate.nationality = nationality }
}

O utilizare posibil a metaprogramrii este delegarea executrii unor metode ctre metode din alte clase, fr
a scrie aceste apeluri explicit n clasa care face delegarea. Versiunea Groovy pentru aceast clas (i pentru
altele cu mai multe apeluri la delegat):

- 182 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

class StaffMemberUsingMOP {
private delegate = new Person()
private hasLocalProperty(name) {
metaClass.properties.collect{ it.name }.contains(name)
}
def salary
StaffMemberUsingMOP(Map map) {
map.each{ k, v -> setProperty(k, v) }
}
void setProperty(String name, value) {
if (hasLocalProperty(name)) this.@"$name" = value
else delegate.setProperty(name, value)
}
def getProperty(String name) {
if (hasLocalProperty(name)) return this.@"$name"
else return delegate.getProperty(name)
}
}
Metaprogramarea este folosit n Grails pentru generarea unor metode de cutare (dynamic finders) cu nume
specific clasei domeniu (se caut ntr-un tabel al bazei de date cu acelai nume ca i clasa domeniu). Fie o
clas Person cu cmpurile firstName,lastName, age (care corespund unor coloane din tabelul SQL);
fr
s fi fost declarate anterior se pot apela metode cu nume ca findByFirstName(),
findByFirstNameAndAge() .a. Corpul metodei se genereaz n functie de numele metodei: find() implic o
cutare, update() va efectua o salvare n baza de date.
In aplicaiile Web dar i n alte aplicaii este nevoie ca s atam mai multor funcii (metode) anumite
operaii executate fie nainte, fie dup instruciunile din functia respectiv. Aceste operaii se numesc i
method advice sau cross-cutting concern n AOP, pentru c ele se execut oarecum perpendicular pe fluxul
de apelare a funciilor din program (pe logica programului).
Utilizrile tipice sunt: jurnalizarea (logging) ntr-un fisier a apelurilor de metode, efectuarea de validri
asupra datelor primite de metode, autentificarea dreptului de acces la metode (log-in) sau aplicarea altor
"filtre" la execuia unor metode.
Aceast augmentare a codului se poate face manual (cu riscul
introducerii unor erori) sau automat, prin interceptarea apelurilor si insertia de cod n punctele dorite.

- 183 -

INFORMATIC*I*

IE. TEHNICI AVANSATE DE PROGRAMARE

Bibliografie
[B01] Bloch J. Effective Java, Editura Addison-Wesley, 2008
[C01] Cooper J: Design Patterns-Java Companion, Editura Addison-Wesley, 1998
[E01] Eckel B. Thinking in Java, Editura Prentice Hall, 2003
[M01] Moraru F., Odubteanu C. Programare orientat pe obiecte, Editura Bren, Buc., 2005
[N01] NetBeans General Java Development Learning Trail https://netbeans.org/kb/trails/java-se.html
[O01] Oracle, The Java Tutorials, http://docs.oracle.com/javase/tutorial/
[R01] Reed P. Developing Applications with Java and UML, Editura Pearson Education, 2002
[T01] Tnas S., .a., Java de la zero la expert, Editura Polirom, 2005

- 184 -

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