Sunteți pe pagina 1din 290

Prof. univ. dr.

Horia GEORGESCU

IN T R O D U C E R !
in
UIUIVERSUL
JAVA

EDITURA TEHNICA
Bucurefti, 2002
PREFA

n mod obinuit, o prefa ncepe prin a convinge c subiectul tratat este


important. Acest lucru este n cazul de fa inutil. Java s-a impus rapid ca un
standard n programare, aa cum la timpul lor au fost limbajele Fortran, Pascal C
i C++.
Java este un limbaj complet orientat pe obiecte. Programele Java sunt
portabile, pot f i executate pe o larg gam de platforme, pot executa simultan mai
multe procese i pot f i ncrcate dinamic prin refele. Aceste caracteristici, dublate
de o mare varietate de faciliti puse la dispoziia utilizatorului, au fcut ca Java
s devin un lider n multitudinea limbajelor de programare existente.
De fapt Java este mai mult dect un limbaj sau mediu de programare: este
un mediu de executare din care putem ntreprinde aciuni specifice sistemelor de
programare, putem lansa fire de executare, putem executa pe maina proprie
programe aflate pe o alt main i putem comanda unei alte maini s execute
diverse programe pentru date pe care i le punem ia dispoziie.

Cartea se bazeaz pe cursurile inute de autor timp de mai muli ani ia


Universitatea din Bucureti, Academia de Studii Economice Bucureti, precum i
Ia Universitatea Ovidius din Constana. Observaiile studenilor au fost totdeauna
binevenite lituie considerave.
Stilul imprimat crii este preponderent didactic. Nu se urmrete
dobndirea de cunotine aproximative n 8, 12 sau 16 lecii, ci se ncearc o
introducere sistematic a noiunilor, prin care cititorul s neleag bine
mecanismele folosite de Java. Accentul este pus n primul rnd pe aceste
mecanisme i nu pe simpla ilustrare a noiunilor prin exemple. De aceea nu i-au
gsit loc n aceast carte multe instrumente uzuale pentru un programator avansat
n Java: crearea i exploatarea bazelor de date, arhive JAR, servlet-uri, interfee
grafice ce utilizeaz Swing, Java Beans, CORBA i multe altele. Am preferat s nu
le includem dect s facem o prezentare superficial a lor. Unele dintre aceste
subiecte pot face obiectul unei cri de sine stttoare i desigur binevenit.
S-a urmrit folosirea im ii limbaj ct moi simplu, scopul fiind de a~l atrage
pe cititor i nu de a~l convinge de erudiia autorului.
6 PREFA

Direciile dezvoltate alegerea exemplelor au inerent un caracter


subiectiv. n aceast carte ele corespund domeniilor de interes ale autorului:
tehnici de programare i programare concurent, paralel i distribuit.
Programele au fost scrise in Java 2 SDK versiunea 13.0, folosind sistemul
de operare Windows.

Cartea este structurat n trei pri.


Prima parte, cuprinznd 7 capitole, ncearc o prezentare sistematic a
elementelor de baz ale limbajului Java. Sunt introduse noiunile fundamentale de
clas, metod, obiect, variabil, operatori i mstruciuni. Este prezentat apoi
modul n care putem structura codul n unifi de compilare i pachete. O atenie
deosebit este acordat mecanismului de extindere a claselor, parte esenial a
paradigmei programrii orientate pe obiecte. Sunt studiate metodele i clasele
abstracte, interfeele i metodele interne. Este explicat mecanismul tratrii
excepiilor. n aceast prim parte cuvintele cheie apar ngroate.
A dona parte conine elemente avansate de programare n Java. n
Capitolul 8 sunt prezentate principalele faciliti standard puse ta dispoziie de
Java. Capitolul 9 explic modul n care pot f i create i lansate firele de executare,
cu aplicaii ia programarea paralel i concurent. Fluxurile de intrare/ieir6 fac
obiectul urmtorului capitol; s-a urmrit o prezentare sistematic a lor, pentru a
"naviga1' uor n foarte multele faciliti puse la dispoziie. n capitolul 10 sunt
studiate intefeele grafice, punndu-se accent pe mecanismele de baz ale
programrii orientate pe evenimente.
Ultima parte a crii este dedicat programrii distribuite. Dup
prezentarea mecanismului de serializure a obiectelor, este descris modul n care
putem comunica n reea cu ajutorul socket-urior; sunt incluse mai multe aplicaii
standard, precum i modul de utilizare a semnturilor digitale. n capitolul 14 este
descris modelul RMJ pentru invocarea la distan a metodelor. Ultimul capitol
trateaz apple-urie, punnd n eviden facilitile, dar i restriciile la core este
supus lucrul cu aceste miniaplicaii.

Cartea se adreseaz unui public foarte larg. Se cer cunotine minime n


limbaje de programare (inclusiv recursmtate), sisteme de operare i navigare pe
Internet De exemplu un absolvent al clasei a X-a de la profilul Matematic-
Informatic are o baz suficienta pentru abordarea crii.

Autorul ateapt cu interes opiniile cititorilor (mai ales pe cele critice!) la


adresa: hgQphobos, c s . unibuc. ro.

Prof. univ. dr. Horia Gcorgescu Februarie, 2002


C U P R IN S

1. O PRIM INCURSIUNE N LIMBAJUL JAVA

1. Introducere
1.2. Un prim program scris n Java
1.3. O clas folosit pentru intrrile i ieirile standard
1.4. Clase, cmpuri i metode
1.5. Simularea nregistrrilor n Java
1.6. Exemplu: crearea unei liste nlnuite
1.7. Introducere n programarea orientat pe obiecte (OOP)

2* ELEMENTE DE BAZ ALE LIMBAJULUI JAVA


2.1. Caractere
2.2. Identificatori
2.3. Constante
2.4. Comentarii
2.5. Variabile
2.6. Operatori
2.7. Instruciuni
2.8. Despre recursivitate n limbajul Java

3. ALTE ELEMENTE DE BZ ALE LIMBAJULUI JAVA.


APLICAII
3.1. Lucrul cu tablouri n Java
3.2. Aplicaia 1 : Parcurgerea n adncime a unui graf neorientat
3.3. Referina t h i s i blocuri de iniializare
3.4. Iniializarea claselor
3.5. Aplicaia 2 : Generarea tuturor (n,k) - combinrilor
8 CUPRINS

4. PACHETE. ACCES I VIZIBILITATE 55


4.1. Pachete ' 55
4.2. Vizibilitate i acces 60

5. EXTINDEREA CLASELOR 65
5.1. Cum se definesc clasele extinse 65
5.2. Din nou despre iniializare i constructori 67
5.3. Rescrierea metodelor i ascunderea cmpurilor 70
5.4. Cuvntul cheie su p e r 73
5.5. Motenire, polimorfism i legare dinamic 74
5.6. Din nou despre modificatori 76

6. METODE I CLASE ABSTRACTE.


INTERFEE. CLASE INTERNE 80
6.1. Metode i clase abstracte 80
6.2. Noiunea de interfa 81
6.3. Extinderea interfeelor 83
6.4. Implementarea interfeelor 85
6.5. Iniializarea interfeelor 86
6.6. Rezolvarea n Java a problemei motenirii multiple 87
6.7. Clonarea obiectelor 89
6.8. Clase interne 92

7. EXCEPII. CONVERSII 97
7.1. Excepii 97
7.2. Conversii 106

8. FACILITI STANDARD 109


8.1. Funcii matematice 109
8.2. Clasa Random 110
8.3. Clasele nfurtoare pentru tipurile primitive 110
8.4. Aritmetica numerelor mari 112
8.5. Lucrul cu iruri de caractere 113
8.6. Prelucrri asupra tablourilor 1 117
8.7. Organizri ale datelor 119
8.8. Lucrul cu clase. Clasele C la s s i Method 128
8.9. Clasa System 132
CUPRINS 9

9. FIRE DE EXECUTARE.
PROGRAMARE PARALEL I CONCURENT 134
9.1. Crearea firelor de executare 135
9.2. Un prim mod de sincronizare 138
9.3. Despre programarea paralel 139
9.4. Implementarea n Java a metodei arborelui binar 141
9.5. Despre programarea concurent 144
9.6. Rezolvarea excluderii reciproce n Java 147
9.7. Primitive de sincronizare. Problema Productor - Consumator 150
9.8. Lucrul cu semafoare n Java 153
9.9. Alte faciliti oferite de clasa Thread 158

10. FACILITI DE INTRARE/IEIRE 160


10.1. Schema general. Fluxuri de intrare/ieire 160
10.2. Fiuxuri ce lucreaz ia nivel de octet 163
10.2.1. O structur simplificat de clase 163
10.2.2. O structur extins de clase 171
10.3. Fluxuri ce lucreaz la nivel de caracter 178
10.3.1. O structur simplificat de clase 178
10.3.2. O structur extins de clase 182
10.4. Analizorul lexical S tream T o k e n iz er 187
10.5. Fiiere cu acces direct Clasa RandomAccessFile 190
10.6. Clasa File 192

11. INTERFEE GRAFICE 194


11.1. Un prim exemplu 194
11.2. Schema general de lucru cu AWT 200
11.3. Containere. Fonturi i culori 207
11.4. Componente elementare 210
1 L5, Gestionari de poziionare 22
5
11.6. Evenimente 230

12. SERIALIZAREA OBIECTELOR 233


12.1. Necesitatea serializrii i deserializrii obiectelor 233
12.2. Un prim exemplu 234
12.3. Ce se transmite la seriaiizare? 236
12.4. Interfee i clase folosite la serializare/deseriaiizare 238
12.5. Serializarea claselor ce extind alte clase i implementeaz interfee 240
12.6. Cazul claselor ale cror superclase sunt neserializabiie 241
10 CUPRINS

44
13. SISTEME DISTRIBUITE SOCKET-URI

2

4
13.1. Sisteme distribuite

2
9
4
13.2. Comunicare prin socket-uri

2
2
5
13.3. Aplicaii

2
5
9
13.4. Semnarea digital a mesajeor

263
14. INVOCAREA LA DISTAN A METODELOR (RM)

3
6
2
14.1. Introducere

6
6
2
14.2. Principiile modelului RMI

0
7
2
14.3. Faciliti Java pentru invocarea ia distan

7
3
2
14.4. Apeluri inverse

6
7
2
14.5. ncrcarea dinamic a claselor

2
8

15. FE SCURT DESPRE APPLET-URI

*
2 2 2 2 2
8
^
15. Ce sunlapplet-urile?

8
~ ^ J
5.2. Faciliti de lucru cu applet-urile

9
15.3. Lucrul cu imagini i fiere audio

9

15.4. Comunicarea ntre applet-uri

9

15.5. Restricii n lucrul cu applet-uri

^ i.
BIBLIO G RAFIE SELEC TIV

INDEX 299
O P R IM IN C U R S IU N E
S N L IM B A J U L JA V A

1 Introdecere

n anul 1990 firma Sun M ic r o s y s te m s a nceput cercetrile pentru


proiectarea unui nou limbaj de programare, care s aduc un plus de flexibilitate,
s fie portabil i s nlture inconvenientele constatate la limbajele de programare
folosite la acel moment. La acest proiect a lucrat o ntreag echip de cercettori,
n care personajele principale au fost James Gostling, Bill Joy i Patrick
Naughton. -
Firma Sun a fcut public specificaia limbajului n anul 1995. De atunci
limbajul Java s-a impus rapid i a cucerit o larg recunoatere i utilizare.

Atragem atenia c, la fel ca n cazul altor limbaje de programare,


prezentarea Msecvenial,( a limbajului Java nu este posibil. De aceea, n mod
inerent, Ia nceput multe aspecte vor fi prezentate incomplet, scopul fiind ca
cititorul s ajung ct mai repede n situaia de a scrie, compila i executa
programe.

Iat pe scurt avantajele utilizrii limbajului Java, aa cum au fost ele


evideniate de Sun Microsystems, cu meniunea c acest paragraf conine i
elemente care nu pot fi explicate in cteva cuvinte, dar asupra crora se va reveni
ulterior.

Sim plitate. Dei sintaxa limbajului este bazat pe cea a limbajului C++,
limbajul Java este considerabil mai simplu. Au fost eliminate multe cuvinte
cheie, nu mai exist un preprocesor, iar limbajul este mbogit cu o bibliotec
mult mai bogat de unelte de dezvoltare. Nu mai exist funcii independente,
variabile globale, instruciunea g o to i lucrul liber cu pointed. Pointerii sunt
nlocuii cu referine, dar nu mai exist o aritmetic a pointerilor. n acest mod
sunt eliminate multe surse de erori de programare, ceea ce conduce la
programe corecte i robuste.
12 1. O PRIM INCURSIUNE IN LIMBAJUL JA VA

O rientarea spre obiecte. Limbajul Java a fost conceput de la nceput pentru a


respecta principiile programrii orientate pe obiecte. Ca i C++, Java folosete
clase pentru organizarea logic a codului; clasa este unitatea de baz n
elaborarea programelor. Nu exist variabile sau funcii n afara claselor. La
executare, programul creeaz obiecte de tipul claselor; aceste obiecte pot fi
gndite ca nite ajutoare (persoane) care execut ele funciile (numite metode)
ale clasei. Este admis i larg utilizat motenirea claselor, dar nu este permis
motenirea multipl (ea este suplinit de o alt facilitate, numit interfa).

Java este proiectat pentru lucru n reea. Chiar de la nceput, limbajul Java
a fost gndit pentru Internet. Dei este posibil s construim programe care
folosesc numai resurse locale, Java pune la dispoziie o mulime de faciliti
pentru programare n reele, pentru a face conexiuni ntre calculatoare server i
client i pentru executare n medii ca de exemplu un browser WWW.

Com pilare prealabil u rm at de executare pe maina gazd. Un program


surs Java trebuie mai nti compilat; ca rezultat se obine un fiier "byte
code" (o secven de instruciuni de asamblare pentru o main imaginar,
numit maina virtual Java), care nu depinde de maina gazd pe care va fi
executat programul. Programul byte-code poate fi apoi transferat pe orice
main. Fiecare main gazd capabil s execute programe Java dispune de
un interpretor, care convertete reprezentarea "byte-code" n instruciuni
main proprii, care apoi sunt executate; conversia are Ioc la lansarea
executrii i anume instruciune cu instruciune. n acest mod este asigurat
portabilitatea i independena de platform. Dezavantajul acestui mod de lucru
const n timpul mare de executare. O variant pentru interpreter o constituie
compilatoarele JIT (Just In Time), care transform programul byte-code na
instruciune cu instruciune, ci n ntregime (ia lansarea executrii) ntr-o
form executabil pe maina gazd, ceea ce conduce la o cretere
semnificativ a vitezei de executare. n continuare vom lucra n varianta
clasic, cea a utilizrii unui interpretor.

Posibilitatea lansrii mai m ultor fire de executare. Limbajul permite


lansarea mai multor fire de executare, permindu-se astfel executarea
concurent a mai multor aciuni. n acest mod este larg deschis drumul ctre
programarea paralel i concurent. La modul ideal, n momentul n care
interpretorul detecteaz mai multe procesoare pe maina gazd, acestea sunt
efectiv folosite pentru executarea concurent a mai multor aciuni; n
momentul de fa aceast "detectare" nu este nc implementat n mod
standard.

Colectorul de reziduuri. Java permite crearea explicit de obiecte (de tipul


unei clase). Distrugerea acestor obiecte este preluat de colectorul de reziduuri
(garbage collector), care marcheaz obiectele ce nu mai sunt folosite i
J.I. introducere 13

elibereaz spaiul ocupat de ele; eliberarea nu se face neaprat imediat, ci


periodic sau atunci cnd spaiul disponibil curent nu mai poate satisface o
nou cerere de alocare de memorie.

Securitate ridicat. Java asigur un grad de securitate ridicat, uneori cu un


plus de efort din partea programatorului. Accesul la memorie este posibil
numai prin verificarea prealabil a drepturilor de acces. Lipsa poiaterilor face
ca accesarea unor zone de memorie pentru care accesul nu este autorizat sa nu
fie posibil. Limbajul oblig programatorul s prevad aciunile ce trebuie
ntreprinse la diferitele erori (numite excepii) posibile. De exemplu, chiar o
simpl operaie de citire trebuie nsoit de codul ce trebuie executat ia
detectarea unei excepii; de asemenea se verific permanent, la executare,
valorea indicelui unui tablou nainte de accesarea componentei respective.

Extensibilitate. Limbajul Java permite includerea de metode native, adic de


funcii scrise n alt limbaj (de obicei C-H-). Metodele native sunt iegate
dinamic !a programul Java !a momentul executrii, rolul lor fiind n principal
de a mri viteza de executare pentru anumite secvene din program,
I

C laritate. Aa cum s-a menionat, eliminarea unor faciliti neeseniale din


C++ conduce la programe mai uor de neles. n plus se consider c limbajul
Java este uor de nvat, cu condiia ca cel care l prezint s fi neles el
nsui foarte bine mecanismele puse la dispoziie (uor de spus, greu de
realizat!). Trebuie ns menionat c dac iniial limbajul a fost gndit a fi
simplu i compact, acceptarea sa unanim a condus la dezvoltarea sa continu,
astfel nct n momentul de fa a devenit deosebit de complex.

Tipizare strict. Fiecare variabil i expresie are un tip cunoscut chiar ia


momentul compilrii.

Applet-uri. Programele Java se mpart n dou categorii. O prim categorie


este constituit de programele obinuite, de sine stttoare (stand afone),
' numite aplicaii. A doua categorie o constituie applei-unle. Este folosit acelai
limbaj, dar difer modalitatea de lansare n executare. Cnd utilizatorul
vizualizeaz o pagin Web ce include un applet, maina Ia care este conectat
transmite applet-ul mainii gazd, care este cea pe care se execut applet-ul (se
presupune c maina pe care lucreaz utilizatorul are un interpretor Java).
Applet-urile constituie o alternativ larg folosit pentru aplicaiile Java.
Menionm c apple-urile pot ngloba elemente de grafic, animaie, sunet,
jocuri etc., ceea ce Ia face foarte atractive.

n cele ce urmeaz ne vom ndrepta atenia asupra aplicaiilor Java,


urmnd ca applet-urile s fie descris^ ntr-un capitol separat.
14 1. O PRIM INCURSIUNE IN LIMBAJUL JA VA

12. Un prim program scris n Java

Nu vom cuta s fim originali cu orice pre, ci vom prezenta un prim


program clasicn:
import java.i o .^;
class unu { -
public static void main(String!] sir) {
for (int i=0; i<sir.length i++)
System.out.println(sir[i]);

Dei scurt, programul necesit o serie ntreag de explicaii.


Programul de mai sus este compus dintr-o singur cias i anume cea cu
numele unu; s presupunem c "programul surs", numit n Java u n ita te d e
c o m p ila r e , este Prog.java (extensia java este obligatorie). Scrierea programului
poate fi realizat cu orice editor text.
Clasa unu conine doar o funcie (numit n Java m e to d ), cu numele
main. Aceasta este metoda "principal"; la executarea programului sistemul
detecteaz i execut metoda main a clasei al crei nume coincide cu numele
fiierului byte-code rezultat n urma compilrii clasei ce conine metoda principal.
Declararea:
im port j a v a . i o .*;
asigur accesul la diverse metode ce permit operaii de intrare/ieire (n programul
nostru este foiosit metoda println).
Metoda main trebuie declarat cu atributele (numite n Java m o d ific a to r i)
public i static. Semnificaia lui void este urmtoarea: metoda nu ntoarce
vreo valoare. In metoda main apare n mod obligatoriu un parametru de tip tablou
de iruri de caractere. Cum tablourile sunt indexate n Java ncepnd cu 0 i cum
lungimea tabloului s i r poate fi referit prin s i r . len g th , instruciunea for
tiprete pentru flecare i lund valori n intervalul 0. . s i r . le n g th -1 irul de
caractere s i r [ i ]; este folosit metoda p r in t ln , care realizeaz tiprirea la
ieirea standard (identificat prin System . out), urmat de trecerea la linia
urmtoare.

Menionm de asemenea c m Java se face distincie ntre literele mici i


literele mari; de exemplu unu i Unu sunt doi identificatori diferii.
Operatorul ~ utilizat mai sus este operatorul de atribuire.
Cuvintele cheie apar n tex ngroate, pentru a fi mai uor identificate

Reamintim c numele unitii de compilare este Prog.java. Cum


extensia este format din 4 caractere, se recomand s nu folosim pentru editare,
copiere etc. produse care au limitri asupra lungimii numelui i extensiei fiierelor
(ca de exemplu Norton Commander). De altfel lucrnd din modul linie de
J.3. O clasfolosit pentru intrrile i ieirile standard 15

comand, este totdeauna preferabil s utilizm comenzile de baz ale sistemului de


operare gazd.
Compilarea se face folosind compilatorul ja v a c . exe astfel:
jav ac Prog. jav a
n urma compilrii ia natere fiierul unu.class; mai general, pentru
orice unitate de compilare (format din mai multe clase), va lua natere pentru
fiecare clas un fiier avnd numele clasei i extensia c la s s ). Pentru acest fiier
putem comanda executarea sa apeind interpretorui j a v a . exe astfel:
jav a unu li s t a d e id e n tific a to r i
De exemplu pentru programul de mai sus, dup ce s-a trecut de faza de
compilare, dac dm comanda:
java unu Unu Doi Trei
vectorul sir va fi format din trei componente, iar la ieire va aprea:
Unu
Doi
Trei

Este indicat, dar nu obligatoriu (aa cum se vede din exemplul prezentat),
ca numele unitii de compilare s coincid cu numele clasei ce conine metoda
principal; n primele versiuni ale limbajului exista ns aceast obligativitate. n
versiunile recente nici precizarea atributului p u b lic pentru metoda principal nu
mai este obligatorie.

Modul de compilare i executarea a programelor Java descris mai sus este


cel mai simplu posibil. Ei poate fi folosit utiliznd J a v a Development Kit,
Menionm ns c n prezent exist mai multe medii d e programare Java ca de
exemplu J a v a Cafi (Symantec), Java Visual Age (), Visual J++, K a w a ,
JBuilder etc.

1.3. O clas folosit pentru intrrile i ieirile standard

Prezentm n continuare o clas menit s realizeze citirea i scrierea de


la/ia dispozitivele de intrare/ieire standard, ntr-un mod apropiat de folosirea
fiierelor text n Pascal. Cititorul este invitat s se rezume doar Ia modul de
utilizare a metodelor clasei.
iznport java.io. *;
p u b lic c l a s s IO {
s t a t i c InputStreamReader reader =
new InputStreamKeader(System.in);
p u b l i c s t a t i c StreamTokenizer f =
new StreamTokenizer(reader)
p u b l i c s t a t i c d o u b le read() {
t r y { f .nextTokenO ; }
16 1. O PRIM INCURSIUNE N LIMBAJUL JA VA

catch (OException e} { }
if {f .ttype == -2) r e tu r n (f . n v a l) ;
else return(Double.N aN) ;

public static char readch{) {


try { return (char) System.in.read()}
catch (IOException e) { return 1# 1; }
}
public static String readstring() {
try { f.nextToken()}
catch (IOException e) { }
if (f.ttype == 1\ " ') return(f.sval);
else return( * * * * " )

public static void writeln(String s)


{ S y ste m .out.p r i n t l n ( s ) ; }
public static void write(String s) { System.out.print(s)}

Ne mrginim la a descrie efectul apelrilor metodelor acestei clase, cu


precizarea c rezultatul compilrii (fiierul i o . c l a s s ) trebuie s se afle n acelai
director cu programul ce folosete metodele clasei IO.
- IO .r e a d () ntoarce urmtorul numr zecimal fr exponent din fluxul
de intrare de la dispozitivul standard de intrare (tastatura);
- X. re a d c h () ntoarce unntorul caracter;
- IO. r e a d s t r i n g O ntoarce urmtorul ir de caractere (cuprins ntre
ghilimele);
- i o . w r i t e (s> tiprete irul s la dispozitivul standard de ieire (ecranul);
- 1 0 .w r i t e l n (s) tiprete irul s i trece la rnd nou.

Amnunte asupra acestei clase i n general asupra operaiilor de


intrare/ieire vor fi date ntr-un capitol separat. Scopul introducerii acestei clase
este de a citi i scrie uor la dispozitivele standard de intrare/ieire numere,
caractere i iruri de caractere. Vom face totui uneie comentarii.

Aa cum am anunat n primul paragraf al acestui capitol, limbajul Java


asigur un grad de securitate ridicat, care ns presupune un mic efort suplimentar
la redactarea programului. Concret, chiar o citire simpl de la dispozitivul standard
de intrare trebuie nsoit de msuri de precauie.
n clasa de mai sus am folosit, printre altele, metoda re a d , care nu are nici
un parametru, a clasei n p u ts tre a m din pachetul j a v a , i o al produsului Java
(pentru moment, putem gndi un pachet de clase ca un director). Ca urmare a
invocrii System.i n .read ) este citit i ntors un byte de a intrare, dac nu s-a
ajuns la sfrit de fiier. Valoarea ntoars este un numr ntreg din intervalul
1.4. Clase, cmpuri i metode 17

O,.255. Interpretarea acestei valori ca fiind caracterul cu numrul de ordine


respectiv ne conduce la obinerea caracterului care a fost citit. Interpretarea
menionat se realizeaz printr-o conversie explicit la tipul c h a r, realizat prin
prefixarea apelului cu (char), Rezumnd, dac ch este o variabil de tip caracter,
atunci prin:
ch = {char) System.in.read()
se obine n ch urmtorul caracter din fluxul de intrare, dac exist un astfel de
caracter. Aceast instruciune trebuie plasat n contextul:
try {
. . . ch = (char) S ystem , i n . re a d () ;
}
c&tch (IOException e) { ... }
pentru a spune explicit c, n cazul cnd intervine o eroare la citire, este executat
secvena de instruciuni cuprins ntre acolade ce urmeaz lui c a tc h .

1.4. Clase, cmpuri i metode


Clasa este unitatea de programare fundamental n Java. Vom presupune
pentru moment c o clas nu poate s conin alt clas (de fapt exist i aa
numitele clase interne, despre care vom vorbi n capitolul 6). Orice cias este
format din cmpuri^ metode i constructori. Cmpurile i metodele unei clase
formeaz mpreun membrii acelei clase.

Cmpurile unei clase sunt variabile ataate ciasei respective.

Metodele sunt funciile declarate n interiorul clasei. O metod nu poate


conine alt metod. Numele funciei este prefixat cu tipul rezultatului ntors de
funcie (sau void dac metoda nu ntoarce vreo valoare) i urmat de lista
parametrilor, cuprins ntre paranteze rotunde; cele dou paranteze rotunde trebuie
specificate chiar dac nu exist parametri. Lista tipurilor parametrilor, n ordinea
lor de apariie, formeaz signatura metodei. n aceeai clas pot aprea mai multe
metode cu acelai nume, dar cu signaturi diferite. Prin urmare, nu este permis
apariia a dou metode cu acelai nume i aceeai signatur, indiferent de tipul
rezultatului ntors.

Clasele sunt considerate tipuri. Entitile ai cror tip este o clas se


numesc obiecte ale clasei respective. Se mai spune c obiectele sunt instanieri
{instane) ale claselor.

Constructorii unei clase seamn cu metodele, dar numele lor este


obligatoriu numele clasei i nu ntorc valori. Unui dintre constructori este automat
invocat Ia crearea unui obiect de tipul clasei respective. Aciunea constructorilor
poate fi orict de complex, dar n principal sunt folosii pentru iniializarea unor
18 1. O PRIM INCURSIUNE N LIMBAJUL JA VA

cmpuri ale obiectului. Ca i pentru metode, pot exista mai muli constructori dar
cu signaturi diferite.
Aceast posibilitate de a exista mai muli constructori, respectiv mai multe
metode cu acelai nume, dar cu signaturi diferite, poart numele de suprancrcare
{overloading).

Obiectele sunt create cu ajutorul operatorului new. Un obiect poate folosi


o variabil pentru a pstra o referin ctre ei. Mai multe variabile pot referi
acelai obiect.

Exemplul L Dac C este o cias, atunci crearea unui obiect de tipul clasei
C se poate face astfel:
1) new c ( . . . )
prin care este creat un obiect anonim de tipul C
2) c Ob Ob = new C ( . . . ) sau prescurtat: C Ob = new C ( . . . ) ;
prin care este creat un obiect de tipul C la care ne putem referi prin variabila b
(avnd evident tipul C).
La creare este invocat constructorul corespunztor (cu aceeai signatur cu cea din
lista de argumente). Dac n clasa C nu exist vreun constructor, se presupune c
"existMtotui un constructor f^r parametri, care nu prevede nici o aciune. Drept
urmare, la creare trebuie folosit forma: new C ( )
Variabila referin Ob poate fi folosit pentru accesarea cmpurilor i
metodelor clasei. Astfel, dac x este un cmp al clasei, el poate fi referit prin
O b.x, iar dac met este o metod a clasei, ea poate fi invocat prin
Ob.met ( . . . ) (evident, este invocat acea metod care are aceeai signatur cu
cea din lista de argumente). Mai spunem c Ob.x, respectiv o b .m e t sunt calificri
ale obiectului Ob cu cmpul x, respectiv metoda met.
Un obiect are o comportare, concretizat prin metodele clasei a crei
instaniere este. Deci un obiect poate fi privit ca o persoan, care la creare are nite
date (cmpurile) i modaliti de a opera asupra lor (metodele). Invocarea unei
metode pentru un obiect revine la a pune acel obiect (acea persoan) s execute
codul metodei respective.

n afar de clase, Java permite declararea de interfee, care difer de clase


prin aceea c pentru metode este precizat signatura lor, dar nu este specificat
corpul lor; cu alte cuvinte, metodele apar doar ia stadiul de "intenie". De aceea nu
pot fi create direct obiecte de tipul unei interfee. Lucrul cu interfee va fi prezentat
ntr-un capitol separat. Am spus aici cteva cuvinte despre aceast noiune
deoarece anumite aspecte sunt comune att claselor ct i interfeelor, iar unele
dintre ele vor fi prezentate nainte de capitolul menionat.

O variabil poate fi de un tip primitiv (numeric, caracter etc.)


referin. Vom vedea c variabilele folosite n Java pentru tablouri sunt variabile
de tip referin (tablourile sunt obiecte!). De asemenea, irurile de caractere (tipul
1.4. Clase, cmpuri i metode 19

String) sunt referine; pentru ele se poate folosi operatorul + cu semnificaia de


concatenare.
O variabil de tip referin poate avea valoarea n u li, care indic o
referin ctre "nimic"; drept urmare variabila nu conine o referin valid, deci
nu poate fi folosit pentru a accesa cmpuri sau invoca metode.
O variabil de tip referin, a crei valoare nu este n u li, poate fi gndit
ca o adres la o zon de memorie ce conine n esen cmpurile obiectului
respectiv i referine la codurile metodei clasei.
P rec iza re . n limbaje ca de exemplu C++ se lucreaz cu pointeri. Acetia
nu trebuie confundai cu referinele din Java, deoarece singurele operaii asupra
variabilelor de tip referin sunt atribuirile i comparrile, deci nu exist o
aritmetic a referinelor.
La apelarea (invocarea) oricrei funcii (metode), tra n sm iterea
Vom explica mai amnunit acest mod de
a rg u m en telo r se f a c e p r in v a lo a re.
transmitere, deoarece n unele cri se afirm n mod greit c pentru referine se
folosete apelul prin referin.
La invocarea unei metode este creat cte o variabil local pentru fiecare
parametru al metodei. nainte de executarea metodei, variabila parametru este
iniializat cu valoarea argumentului corespunztor din invocare. De exemplu,
dac argumentul este de tip referin, variabila parametru corespunztoare este
iniializat cu respectiva referin; drept urmare argumentul i variabila parametru
sunt referiri la acelai obiect.
O metod poate modifica cmpurile obiectului i valoarea variabilelor
parametru. Aceasta nu va conduce ns la modificarea valorii argumentului
(eventual numai cmpurile sale sunt modificate, dar nu referina la obiect).
Aceeai relaie exist ntre o variabil parametru i argumentul
corespunztor, cnd tipul acesteia este un tip primitiv.

E x e m p lu l 2. S considerm urmtorul program (unitate de compilare):


C {
int i; static int iO;
0 0 { iO - 100; scrieO ; }
C(iat j) { i = }
v oid scrieO { IO.writeln{iO + K + i) }
v oid modif() { i = -i; }
void modif(C Ob) { i = Ob. i }
)
Obiect {
p u b lic t t ic v oid main{String[] args) {

Obi = new (1); Obl.scrie();
2 = new (2)? 2.scrie{);
IO.writeln(+ ( 2 ) );
= ; .modif () ; . scrieO
20 1. O PRIM INCURSIUNE IN LIMBAJUL JA VA

O-writelnt + (Obl==Oto3));
2 .modif () ; 2 .scrie ();
I O . w r i t e l n ( ( 2 ) );
}
}
n care operatorul == este operatorul de egalitate, iar + este fie operatorul de
adunare, fie cel de concatenare (n situaia n care cel puin un membru este un ir
de caractere, caz n care i ceilali membri sunt convertii la iruri de caractere).
n acest program apare o noiune nou i anume modificatorul s t a t i c cu
care este declarat cmpul ntreg iO din clasa C. Aceasta face ca iO s fie comun
tuturor obiectelor de tipul C. Existena unui cmp static nu depinde de obiecte ce
instaniaz clasa. Cmpul .respectiv poate fi adresat din afara clasei prin numele
clasei calificat cu numele cmpului (C. iO); evident, pentru orice obiect Ob de tipul
C, cmpul poate fi adresat n continuare prin Ob. iO.
Analog, modificatorul s t a t i c poate fi folosit i pentru metodele unei
clase. Din afara clasei, metoda poate fi invocat prin numele clasei calificat cu
numele metodei i urmat de lista argumentelor. Metodele statice sunt n general
folosite pentru modificarea cmpurilor statice ale clasei. Cunoatem deja un
exemplu de folosire a acestui modificator; el nsoete "metoda principal" m ain
acest lucru este necesar deoarece nu este creat un obiect de tipul clamei din care
face parte aceast metod, ci este folosit un "ncrctor de clas", care trebuie s
aib acces la metoda main.
Mai menionm c, n mod implicit (prin lips), cmpurile unui obiect
primesc la creare o valoare (0 pentru tipuri numerice); de exemplu la crearea unui
obiect de tipul C, cmpul i are implicit valoarea 0.

La executarea programului, vor fi tiprite n ordine urmtoarele rezultate:


100 o ca urmare a executrii instruciunii new c ( ) , care iniializeaz
cmpul static iO cu valoarea 100 i tiprete valorile lui iO i i; s
observm c a fost folosit constructorul fr parametri;
100 101 ca urmare a crerii obiectului prin invocarea constructorului cu
un parametru i a executrii metodei s c r i e ;
100 102 ca urmare a crerii obiectului 0b2 prin invocarea constructorului cu
un parametru i a executrii metodei s c r i e ;
fa ls e deoarece ia fiecare creare a unui obiect prin new se obine o nou
referin, deci este diferit de 0b2;
100 - 101 ca urmare a invocrii metodelor m od if (fr parametru) i s c r i e de
ctre obiectul Ob3; s remarcm faptul c referinele i 0b3
coincid. Ele sunt referine ctre acelai obiect; mai spunem c ob3
este un "alias" al lui ;
tru e din motivele expuse mai sus;
100 -1 0 1 ca urmare a invocrii metodelor m odif (cu argumentul Obl) i s c r i e
de ctre obiectul 0b 2 ; cmpul i al lui 0b2 primete valoarea
cmpului i a lui o b l. Reamintim c dac n aceast metod m odif
LS, Simularea nregistrrilor n Java 21

am fi adugat o instruciune de tipul O b .i= 7 , aceasta ar fi modificat


un cmp al obiectului referit prin , dar nu valoarea referinei o b l;
fa ls e deoarece referinele i 0b2 sunt diferite (chiar dac obiectele
respective au aceleai valori ale cmpurilor).

L5. Sim ularea nregistrrilor o Java

n limbajul Java nu exist structuri de date eterogene (nregistrri), adic


ceva analog cu tipul record din Pascal. innd cont c la invocarea metodelor se
face apel prin valoare, putem s ne punem ntrebarea cum poate o metod s
ntoarc mai multe rezultate. n Java, nregistrrile pot fi simulate folosind clase
(eventual fr metode). Acest lucru este ilustrat de urmtorul program, care arat
cum o metod poate ntoarce mai multe vaiori:
c I&bs Record {
int i; boolean b
R e c o r d (int i i , boolean bb) C i - ii; b = bb; }
}
clase C {
R ecord m etoda ( i n t i ) {
R ecord R == new R e c o r d ( il , i < 0 ) ;
return R
}
}
clase Doi {
public static void main{String[] sir) {
int i; Record R;
i = (int) IO.read();
C Ob = new C O ; R = Ob. m etoda ( i )
1 0 .w r i t e l n ( R . i + " " -f R .b );
}
} -

Legat de acest program simplu se impun mai multe precizri:


- comanda de compilare a clasei D oi va atrage automat dup sine
compilarea claselor R ecord i C (n ipoteza, pe care o folosim n continuare, c
plasm toate f i i e r e l e surs n aceiai director)',
- clasa R ecord nu are metode, ceea ce este permis, dar nu vine n
concordan cu programarea orientat pe obiecte, mai precis cu caracteristica de
ncapsulare, care presupune includerea n aceeai clas a unor date i a metodelor
care Ie prelucreaz;
- dup citirea unui numr real de Ia intrare, trebuie ca nainte de a fi
atribuit unei variabile ntregi, s fie convertit explicit la acest tip, ceea ce am i
ftcut pentru variabila i; precizm c la conversie se face trunchiere-,
22 1. O PRIM INCURSIUNE fN LIMBAJUL JA VA

- deoarece cmpurile R .i i R.b ale obiectului R nu sunt de tip ir de


caractere n apelul i o . w r i t e l n ( . . . ) trebuie s apar, n concatenare (realizat
prin operatorul +) cel puin un ir de caractere; drept urmare ceilali membri ai
concatenrii sunt convertii implicit la iruri de caractere;
- dac este citit valoarea 5, la ieire va aprea: 6 fa ls e
- dac este citit valoarea -5, la ieire va aprea: -4 tr u e

1.6. Exemplu: crearea unei liste nlnuite

Exemplul 4, Prezentm o modalitate de a crea i prelucra o list nlnuit,


ale crei elemente alegem s fie caractere.

Dup cum tim, idea de baz este de a forma "celule" care s conin un
element efectiv i "adresa" urmtoarei celule. Pentru aceasta vom defini o clas
elem format din:
- cmpurile c (de tip caracter) i le g (de tip eiem);
- cmpurile statice p i u, coninnd referinele spre primul i ultimul
element al listei;
- un constructor ISr parametri, care este folosit pentru crearea n metoda
principal a obiectului Ob;
- un constructor, care are un parametru de tip caracter; la crearea unui nou
obiect de tip elem, obiectul va primi n cmpul c caracterul transmis la invocarea
constructorului, iar cmpul le g va deveni n mod implicit referina nul n u l i ;
- metoda c r e a r e , care creeaz un prim element al listei (memornd
referina la el n variabilele p i u) i apoi n mod repetat, pn cnd este citit
caracterul *$ % obiectul u creeaz, folosind metoda adaug, un nou obiect pentru
noul caracter citit i actualizeaz referina u pe baza rezultatului ntors;
- metoda adaug, care creeaz un nou obiect i ntoarce o referin ctre el;
- metodele d i r e c t i in v e rs ce au un parametru x de tip elem i ntorc
un rezultat de tip ir de caractere ce corespunde parcurgerii n ordine normal (de
la stnga la dreapta), respectiv n ordine invers, a irului de caractere ce ncepe de
la "adresa" x.
n clasa L is ta , n metoda principal, este invocat metoda c re a r e i apoi
metodele d i r e c t i in v e rs, prin intermediul unui obiect Oh de tipul elem,
ultimele dou avnd ca argument cmpul static p ai clasei elem.
Programul corespunztor este prezentat n continuare.
class elem {
char c elem le g ; static elem p ,u ;
elem{} { }
elem (char ch) { c = ch; }
elem ad au g (char ch) {
elem x - new elem(ch); leg = x; return x;
}
1.6. Exemplu: crearea unei liste nlnuite 23

void creare () {
char ch - IO.readch()p = new elem(ch)u = p;
ch = IO.readch);
w h ile (ch!- ' $ ' ) { u = u ,adaug(ch ) ch = IO.readch() }
}
String direct(elem x) {
1 (x~~null) return "
1@ return x.c + direct(x.leg) ;
}
String invers(elem x) {
if (x =^ qu 11) @&1 f

1 return invers {x .leg)+ x .c


}
}
bista {
' p u b lic e t a t i c v oid main{String [] s) {
Ob = @1 ( )
Ob.creare); .
IO.wrifceln( Ob.direct (elem.p} );
IO.writeln( Ob.invers{elem.p ) )

unde operatorul ! = are sensul "diferit den. S observm c metodele d i r e c t i


In v e rs puteau fi invocate i cu argumentul Ob.p.

S analizm pe un exemplu modul de funcionare a programului de mai


sus. S presupunem c la intrare apare: a b c $ c l
Este citit caracterul 1a * i este creat un nou obiect de tipul elem , ai crui
cmp c este caracterul ' a ' i al crui cmp le g este n u li. Variabila u de tip
elem pstreaz referina ctre acest obiect. Pentru claritate, s notm cu pa acest
obiect. Variabilele p i u memoreaz o referin Ia obiectul px.
n continuare este citit caracterul ' b 1. Apoi obiectul Px (referit prin u) este
npus la lucru". EJ creeaz un nou obiect de tip elem , ai crui cmp c este
caracterul 'b ' i al crui cmp le g este n u li; fie P2 acel obiect. Cmpul le g al
lui Pi este actualizat i devine referina la P2. Variabila u va conine acum o
referin la obiectul P2.
n continuare este citit caracterul ' c '. Apoi obiectul P2 este "pus la lucru".
EI creeaz un nou obiect de tip elem , al crui cmp c este caracterul ' c ' i ai
crui cmp l e g este n u li; fie P3 acel obiect. Cmpul l e g al lui p2 este actualizat
i devine referina la P3. Variabila u va conine acum o referin la obiectul p3.
Cum urmtorul caracter citit de Ia intrare este ' $ ' crearea listei de obiecte
este ncheiat.

S analizm efectul executrii instruciunii


I O .w r i t e l n ( O b .d i r e c t ( p ) } ;
2 4 ____________________________ I. O PRIM INCURSIUNE N LIMBAJUL JA VA

care prevede scrierea la ieire a irului de caractere ntors de invocarea


p direct (pb
ntruct variabila p memoreaz o referin la obiectul pb obiectul Pi va
invoca metoda d i r e c t cu parametrul Este ntors irul format din caracterul
' a 1 la care se concateneaz irul ntors de invocarea metodei d i r e c t efectuat
pentru referina P2. Acest apel ntoarce irul format din caracterul ' b 1, la care se
concateneaz irul ntors de invocarea metodei d i r e c t efectuat pentru referina
P3. Cum aceast din urm invocare ntoarce irul vid (deoarece cmpul le g al Iui
p3 conine n u li) , rezult c Ia ieire va aprea:
abc
n mod analog, executarea instruciunii:
IO.writeln(Ob.invers(p));
face ca la ieire s apar:
cba

Vom face n continuare cteva precizri suplimentare privind colectorul de


reziduuri. Interpretorul Java este capabil de a detecta momentul n care un obiect
nu mai este referit i l poate "distruge", sarcin preluat de colectorul de reziduuri.
Aa cum am menionat, aceasta nu implic eliberarea imediat a spaiului alocat
obiectului. Este posibil ca interpretorul Java s termine executarea programului
naintea colectorului de reziduuri (acesta nu a eliberat nc toate spaiiie inutile); n
aceast situaie, resursele rmase alocate vor fi eliberate de sistemul de operare.
De asemenea menionm c orice aplicaie Java presupune executarea
concurent a cel puin dou fire de executare: cel care execut programul
utilizatorului i cel ce gestioneaz colectorul de reziduuri.

1. Introducere n program area orientat pe obiecte (OOP)


ncepem prin recapitularea unor noiuni deja prezentate:
- clasa este unitatea de baz n elaborarea programelor;
- orice obiect este o instan a unei clase;
un obiect ncapsuleaz stri (valorile cmpurilor casei) i comportament
(metodele clasei);
- un obiect i etaleaz comportamentul n momentul n care este invocat
o metod prin intermediul su.

Este foarte important a nelege deosebirea ntre apelarea m e i funcii (de


exemplu n limbajul Pascal) i invocarea unei metode prin intermediul unui obiect.
La apelarea unei funcii controlul este deinut n continuare de unicul
"executant" al programului.
La invocarea unei metode prin intermediul unui obiect, acelui obiect i
revine sarcina de a executa aciunile prevzute n metod. Aciunea const deci n
transmiterea unui mesaj obiectului, care este pe post de receptor. Mesajul conine:
- numele obiectului (receptorului);
L 7. Introducere n programarea orientat pe obiecte (OOP) 25

- aciunea ce trebuie ntreprins (numele metodei);


- informaii suplimentare necesare pentru ntreprinderea aciunii
(argumentele cu care este invocat metoda).
n plus, dup cum vom vedea, uneori receptorul este cunoscut doar n
timpul executrii.
S observm c nu este necesar s fie cunoscut modalitatea n care
obiectul i duce Ia bun sfrit aciunea cerut; de exemplu clasa a crei instaniere
este obiectul poate fi furnizat nu ca unitate de compilare, ci ca rezuitat ai
compilrii unitii. Mai trebuie menionat c invocarea unei metode cu acelai
nume i aceeai list de parametri pentru un alt obiect, instan a unei aite clase, va
conduce la o ait aciune.
Cele de mai sus au implicaii importante:
- ascunderea (secretizarea) informaiilor : sunt cunoscute rezultatul
compilrii unei clase, constructorii i cmpurile claselor, precum i antetul
metodelor mpreun cu o informaie general asupra aciunii metodelor (ce
realizeaz metoda i nu cum are loc aceast realizare);
- delegarea responsabilitilor : clasa de al crei tip este obiectul este
responsabil de corecta desfurare a activitilor;
- ncrederea n soft-/! sen's de aZfh : oat cu folosirea unei clase trebuie
s avem total ncredere n corectitudinea ei, deci n soft-ul pus ia dispoziie de ali
programatori; nu are sens ca la scrierea unui nou program s "inventm din nou
lumea", n loc s folosim soft deja existent i verificat.
- dezvoltarea componentelor reuilizabie ; este o consecin a celor de mai
sus i const printre altele n dezvoltarea unor clase deja existente prin extinderea
lor (adugarea unor noi cmpuri i metode, eventual redefinirea unor metode, dar
cu posibilitatea de a folosi i cmpurile i metodele clasei iniiale).
Este momentul de a enuna un principiu fundamental al programrii
orientate pe obiecte: Un program orientat pe obiecte este o comunitate de ageni
(obiecte) care i desfoar fiecare activitatea lui, dar i inieracioneaz ntre
ele. Interaciunea const n esen n faptul c fiecare obiect poate cere altui obiect
s ntreprind anumite aciuni.

Exemplul din paragraful precedent ilustreaz doar parial principiul


enunat anterior, datorit secvenialitii inerente n lucrul cu liste. Totui merit
accentuat un aspect legat de variabila le g ce apare n metoda adaug i anume c
este vorba de cmpul le g al obiectului prin care a fost invocat metoda, adic al
obiectuiui u. Acest aspect trebuie s stea n permanen n atenia programatorului:
totdeauna trebuie s tim care este "obiectul curent", adic cel care execut
activitatea curent.

Prezentm n continuare ua exemplu mai sugestiv.


5. Dei vom vorbi despre interfee grafice doar n a doua parte a
E x e m p lu l
crii, cu puin imaginaie putem nelege cele ce urmeaz. S considerm o clas
28 2. E L E M E N T E D E B A Z A L E L IM B A J U L U I JA V A

\b = \u0008 (backspace) 4 \f = \uOOOc (form-feed)


\r = \u000d (return) V =\u0022 (ghilimele)

Motivaia utilizrii setului Unicode este integrarea n limbaje de tip HTML


care s permit circulaia pe Internet.

22. Identificatori
n Java identificatorii ncep cu o liter (inclusiv i ' $ 1) i pot
continua cu litere sau i i cifre; este totui indicat s nu includem n identificatori
caracterul ' $ f, deoarece el este folosit de compilatorul lava pentru a genera
identificatori interni, despre care nu vom vorbi aici. Prin "litere" nelegem att pe
cele obinuite (literele mici i mari din alfabetul englez), ct i pe cele din alte
limbi. Un identificator poate avea orice lungime; de aceea este indicat s folosim
identificatori ct mai sugestivi pentru rolul pe care l joac, timpul Hpierdut" la
scrierea programului fiind recuperat din plin atunci cnd revedem programul peste
cteva iuni sau cnd trebuie ca ei s fie neles de alte persoane.
Anumii identificatori au o semnificaie predefmit, ce nu poate fi
modificat, i nu pot fi folosii n alt context dect cei intenionat de ctre autorii
limbajului. Ei se numesc c u v in te c h e ie . O prim list de cuvinte cheie este
urmtoarea:
abstract boolean break byte case
catch char class coninu default
do double else eKtens final
finally float for if ijxiplemeiibs
import instanceof int interface long
new null package private protected
public return short static super
switch synchronized this throw
throws try void while

Aa cum am precizat n capitolul anterior, n programe sau secvene de cod


aceste cuvinte cheie vor aprea ngroate pentru a veni n ajutorul cititorilor.

2 3 . Constante
n limbajul Java, constantele mai poart i numele de lite r a li. Vom
prezenta doar o parte a acestor constante (de exemplu nu vom vorbi de literali
ntregi octali i hexazecimali):

1) L ite r a lii n tr e g i sunt de dou tipuri:


- n o r m a li, reprezentai pe 32 de bii i pentru care scrierea este cea uzual;
2.4. Comentarii 29

- lu n g i, reprezentai pe 64 de bii, identificai prin faptul c au sufixul 11 sau

2) L ite r a lii r e a li (n v ir g u l m o b il ):
- d u b lii reprezentai pe 64 de bii, pentru care scrierea este cea uzual. Este vorba
de numere zecimale ce conin opional punctul zecimal i pot fi urmate de un
exponent prefixat cu e sau E. De exemplu urmtorii trei literali reprezint aceeai
valoare:
21. 2 .le i .21E2
- n o rm a li, reprezentai pe 32 de bii. Aceti literali au aceeai form ca cei dubli,
dar au n plus sufixul 1f ' sau !F '.
Conform standardului IEEE 754, sunt inclui i literali pentru "nu este un
numr", i
Double . NaN D ouble . NEGATIVENFINITY i D ouble . POSITIVEINFINITY
(pentru aritmetica pe 8 octei);
F lo a t . NaN, F l o a t . NEGATIVEINFINITY i F lo a t . POSITIVEINFINITY
(pentru aritmetica pe 4 octei).
Valoarea NaN apare ca rezultatul unor operaii ca de exemplu mprirea la
zero; ea nu este HordonatH: compararea ei cu orice valoare produce rezultatul
f a ls e . n schimb valorile corespunztoare lui -i + sunt ordonate: pentru orice
literal "efectiv" v a l, avem

Cele mai mici valori pozitive pentru literalii normali i dubli sunt:
F lo a t .MINVALUBl .-4 3 - 4 5 f i D ouble .HXNVALUE=5e-324
iar cele mai mari vaiori posibile pentru literalii n virgul mobil sunt:
F l o a t . / =3.4 0 2 8 e + 3 8 f i D ouble .MAXVALUE=1.79769e+308,

3) L ite r a lii b o o le e n i sunt tr u e i f a l s e .

4) L ite r a lii d e tip c a r a c te r au forma ' c ', unde c este un caracter sau o
secven Escape; aceste secvene au fost prezentate mai sus.

5) L it e r a li i d e tip i r d e c a r a c te r e sunt cuprini ntre ghilimele.


Menionm c irurile de caractere sunt instane ale clasei S t r in g
declarat standard n Java. Iat cteva exemple:
" ( irul vid) ; _'ab\nn" (unde apare secvena Escape ' \ n ' ) .

6) L ite r a lu l r e fe r in este nuli.

2. Com entarii
Comentariile sunt folosite n principal pentru explicitarea aciunilor
ntreprinse de cod; d e simt ignorate de compilator.
30 2 . E L E M E N T E D E B A Z L E L IM B A J U L U I J A V A

Exist trei tipuri de comentarii:


- de s f r it de lin ie : ncep cu / / i se termin la sfritul liniei;
- generale: ncep cu / * i se termin la prima succesiune */.
- de documentare: ncep cu /** i se termin la prima succesiune */.
Acest tip de comentariu poate fi plasat doar imediat naintea unei clase, unui
membru al unei clase sau a unui constructor. Utilitarul ja v a d o c este capabil s
colecteze comentariile de documentare din codu! surs al claselor i s le introduc
n documente HTML.
Din cele de mai sus rezult c nu exist comentarii n comentarii.
iru! /* * / este considerat un comentariu de documentare, n timp ce /*
* / este un comentariu general.

2.5. Variabile

Forma general folosit pentru declararea variabilelor este:


< ir de modificatori > < tip > < list d e identificatori > ?
unde prezena modificatorilor este opional. Informaiile din irul de modificatori
sunt separate prin spaii albe, iar cele din lista de identificatori prin virgul. Dac
dorim s specificm i o valoare iniiam pentru un ideritifieator, acesta trebuie
urmat de semnul = i de un literal, ca de exemplu n: i n t a - 3
Menfionm pentru moment doar urmtorii modificatori:
- modificatori de acces (p u b lic , p r i v a t e , p r o te c te d ) ; dac nu este
specificat nici unul dintre aceti modificatori, se consider c este ataat un
modificator implicit;
- s ta tic ;
- fin a l .
Modificatorii pot nsoi nu numai cmpurile, ci i clasele i metodele, dar
despre acest aspect vom vorbi ntr-un capitol urmtor.
La declararea cmpurilor unei clase se recomand precizarea
modificatorilor n ordinea de mai sus.
Aa cum am menionat n capitolul anterior, modificatorul static
specific faptul c respectivul cmp este unic pe clas, deci comun tuturor
obiectelor ce sunt instane ale clasei (joac rolul de memorie comun, pentru toate
obiectele ce instaniaz clasa); cmpul static poate fi referit din afara clasei ca
orice cmp, dar i prin precalificare cu numele clasei.

O declarare poate s apar oriunde !n cadrul unei clase, metode sau a unui
bloc de iniializare, deci nu neaprat la nceputul lor.
Limbajul Java atribuie valori iniiale implicite cmpurilor claselor. Ele
sunt:
f a l s e (pentru b o o le a n ) ; * 0000' (pentru e h a r ) ; n u l i (pentru r eferin e).
0 (pentru orice tip ntreg) ;+0 . 0f sau +0 . d (pentru flost i d o u b le ) ,
2.5. 31

unde tipurile menionate sunt descrise n continuare. n schimb nu este atribuit


vreo valoare iniial prin lips variabilelor locale din metode, constructori i
blocuri de iniializare i de aceea aceste variabile trebuie s primeasc valori
nainte de a fi utilizate; nerespectarea acestei reguli conduce la semnalarea unei
erori.
O variabil declarat cu modificatorul f in a l este iniializat implicit sau
explicit prin declararea sa; aceast valoare nu mai poate fi schimbat ulterior.
Atenie: pentru o variabil de tip referin, aceast regul nseamn c ea
nu i m ai poate modifica valoarea; nu rezult ns de aici c nu poate fi modificat
valoarea unui cmp al obiectului respectiv, aa cum arat urmtorul program:
c la s s C { in t a; }
c la s s Clasa {
f in a l = new ;
void m o d ify(in t i) { Ob.a = i }
}
c la s s F inal {
s t a t i c p u b lic void m ain (S trin g[] a r g s) {
Clasa Ob = new C la sa ()
Ob.modify O.write{Ob.Ob4a + H
Ob.modify(2) O.writeln(Ob.Ob.a + " 11)
}
}
care produce la ieire valorile 1 i 2.

O variabil are un nume (care este un identificator) i un tip, despre care


tim c este un tip primitiv sau un tip referin. Enumerm n continuare tipurile
primitive (de baz).

1) Tipul boolean. Variabilele de acest tip pot lua doar valorile t r u e i


false.

2) Tipul char. Variabilele de acest tip sunt reprezentate pe 16 bii i pot


primi ca valoare orice simbol din codul Unicode. O variabil de tip caracter poate
fi folosit oriunde poate aprea,o valoare ntreag: este considerat numrul su de
ordine n setul de caractere Unicode.

3) Tipuri ntregi. Ele sunt urmtoarele:


byte (octet) short (ntreg scurt) in t (ntreg) long (ntreg lung)
reprezentate n ordine pe 1,2,4, 8 octei. Valorile maxime sunt n ordine:
255 32767 =2xl09 =9xlOi8
Precizm c n calcule tipurile byte i short sunt convertite la in t.

4) Tipurile n virgul mobil f lo a t i double, reprezentate respectiv pe 4


i 8 octei.
32 2. ELEMENTE DE BAZ ALE LIMBAJULUI JA VA

Fiecrui tip primitiv din Java i corespunde o clas definit standard n


Java: B oolean , C h a ra cter, B y te, S h ort, I n te g e r , Long, F lo a t i D ouble. n
aceste clase apar constante i metode utile. Am prezentat deja cteva constante din
aceste clase n discuia asupra literalilor n virgul mobil. Mai menionm metoda
isNaN din clasele F lo a t i D ou b le metoda primete o valoare de tipul
corespunztor i ntoarce o valoare boolean, care este t r u e dac i numai dac
argumentul nu este o valoare numeric valid; am folosit aceast metod n clasa
0 prezentat n primul capitol.

2.6. O peratori

Menionm c Java pune ia dispoziia utilizatorului aproximativ 40 de


operatori, dintre care unii sunt descrii n continuare. Trebuie precizat c
programatorul poate defini metode noi, dar nu i operatori noi.

Operatori aritmetici
Aceti operatori sunt urmtorii;
4- ~ * / %.
De asemenea este folosit operatorul unar - pentru schimbarea semnului,
precum i operatorul unar + (introdus pentru simetrie).
n aritmetica ntreag trebuie s inem cont de urmtoarele reguli:
- orice valoare ce depete limita admis este redus modulo aceast
limit; de aceea nu exist depiri { o v e r flo w i u n derflow )',
- mprirea ntreag se face prin trunchiere; de exemplu - 8/ 3 = =~ 2 , iar
8/3=^2

- operatorul %este definit prin: __


(x/y) *y+x%y= X
De exempiu 8%3 =~2t iar -8%3~=-2.

Operatorii de incrementare i decrementare


Este vorba de operatorii unari i care pot fi aplicai operanzilor
numerici (ntregi sau n virgul mobil) att n form prefixat ct i n form
postfixat.
Expresiile x+- i ++x sunt echivalente cu x=x+l, cu dou excepii:
- sunt a to m ic e (considerate ca o unic operaie, nu ca o incrementare
urmat de o atribuire). Acest aspect este relevant doar cnd mai multe fire de
executare acioneaz asupra unei aceleiai variabile;
- operandul x este evaluat o s in g u r d a t . Aceast excepie are n vedere
instruciuni de tipul a [ in d ic e {) ] =a [in d ic e () ] +1, n care este folosit o
metod ce ntoarce un ntreg; astfel, n exemplul de mai sus, invocarea metodei
2.6. Operatori 33

in d ic e va avea loc o singur dat (n caz contrar este posibil ca n membrul stng
i cel drept s nu se refere la aceeai component a tabloului a, de exemplu dac
metoda ntoarce n mod aleator un indice).
Diferena ntre x++ i ++x const n faptul c incrementarea este realizat
dup, respectiv nainte de utilizarea lui x n contextul n care apare. Astfel, dac
valoarea curent a iui x este 4, atunci:
- evaluarea expresiei 2 * --x conduce Ia rezultatul 10,
- evaluarea expresiei 2 * x++ conduce Ia rezultatul 8,
dup care valoarea lui x va fi n ambele cazuri 5.
Evident, operatorul se supune unor reguli analoagc.
O construcie de tipurile x + + , x - ~ # ++x, -~ x reprezint o expresie
aritmetic, dar i o instruciune (valoarea expresiei nu este folosit, ns x este
incrementat sau decrementat).
Operatorii de mai sus pot fi aplicai i pentru tipul c b a r, semnificnd
trecerea la precedentul, respectiv urmtorul caracter din setul de caractere
Unicode.

Operatorii de atribuire
Pe lng operatorul ~ folosit standard pentru atribuire, mai pot fi folosii i
operatorii;
+ !S = f = '* %5S

care reprezint scrieri prescurtate. Astfel x+=y este echivalent cu x=x+y, cu


excepia faptului c evaluarea adresei lui x se face o singur dat (vezi paragraful
precedent). Desigur, operatorul %= va fi folosit doar pentru aritmetica ntreag.

Operatorii relaionali
Este vorba de urmtorii operatori:
> (mai ca) >= (mai mare sau egal cu) == (egal cu)
< (mai mic ca) <= (mai mic sau egal cu) ! = (diferit de)

Operatori booleeni
! Este vorba de urmtorii operatori:
j ! (disjuncia iogic, sau) && (conjuncia logic, i) ! (negaie)
cu meniunea c ta evaluare se face s c u r tc ir c u ita r e (pe scurt, dac la evaluarea
unei expresii booleene devine la un moment dat clar valoarea ei, nu se mai
continu n mod inutil evaluarea; de exemplu dac expresia este disjuncia logic a
trei termeni i valoarea primului este t r u e , nu se mai evalueaz ceilali termeni).
34 2 . E L E M E N T E D E B A Z A L E L IM B A J U L U I J A V A

O peratori pe bii
Este vorba de operatorii binari | i & care realizeaz disjuncia logic i
conjuncia logic ia nivel de bit, pentru fiecare pereche de bii de pe aceeai poziie
din reprezentarea operanzilor.

O peratorul condiional ? %

Acest operator se utilizeaz n expresii sub forma:


( cond 7 el \ el)
a crei valoare este / dac co/zd este t r u e respectiv dac este f a l s e ;
cond trebuie s fie o expresie de tip boolean.
Pentru a nu intra n amnunte, vom impune deocamdat regula ca el i e2 s aib
acelai tip.

O peratori postfix
Includem aici:
- cuprinderea ntre paranteze a indicilor (cu []);
- operatorul de calificare ( .) folosit pentru accesarea membrilor claselor;
- parantezele rotunde folosite pentru specificarea listei de parametri din
invocri;
- operatorii de incrementare/decrementare ++ i - - de mai sus.

O peratorul de conversie a tipurilor


Ne mrginim la a preciza c o conversie explicit de tip are forma:
(tip) expresie
urmnd s discutm ulterior condiiile n care poate avea loc o astfel de conversie.

O peratorul + pentru iucrul cu iruri


Acest operator este folosit pentru concatenarea irurilor. Trebuie
menionat c dac un membru al unei sume este un ir de caractere, atunci are loc
o conversie implicit a celorlali membri ai sumei (devenit acum concatenare) la
iruri de caractere; aceast facilitate a fost de altfel des folosit n programele
prezentate anterior, de exemplu n cadrul invocrii x. w r i t e (. . .) . Adugm
doar c printre membrii sumei pot aprea i variabile referin!

Operatorii pentru referine


Sunt utilizai urmtorii operatori:
2.6. Operatori 35

- accesul la cmpuri (prin calificare);


- invocarea metodelor (prin calificare);
- operatorul de conversie;
- operatorii == i != ;
- operatorul condiional;
- operatorul n s t a n c e o f folosit n contextul:
Ob iziat&nceof Clasa
care produce o valoare boolean ce este t r u e dac i numai dac obiectui b este
diferit de n u l i i este o instan a clasei C la sa sau poate f i convertit la tipul
C lasa (despre conversiile de tip vom vorbi ntr-un capitol aparte).

Precedena operatorilor
Ordinea n care are loc efectuarea prelucrrilor determinate de operatori
este dat n urmtorul tabel de prioriti ale operatorilor (de la prioritate maxim ia
prioritate minim):
- operatorii postfix
- operatorii unari de incrementare/decrementare, operatorii + i - unari
operatorul de negaie !
- operatorul n@w de creare de obiecte i cei de conversie: ( tip)
e x p r e s ie
operatorii multiplicativi: * / %
- operatorii aditivi: + -
- operatorii relaionali i n s ta n c e o f
- operatorii de egalitate: == !&
- operatorul &
- opratorul I
- conjuncia logic &&
- disjuncia logic | |
- operatorul condiional ( ? )
operatorii de atribuire.

Observaii:
- la prioritate egal, operatorii "vecini" acioneaz conform regulilor de
asociativitate prezentate n continuare;
- utilizarea parantezelor este mai puternic dect prioritatea operatorilor.
Astfel, spre deosebire de x+y*z, n (x+y) *z prima operaie care va fi executat
este adunarea.

@ Asociativitate
Regula general o constituie asociativitatea la stnga. Fac excepie
urmtorii operatori, pentru care este folosit asociativitatea la dreapta:
36 2. E L E M E N T E D E B A Z A L E L IM B A J U L U I JA V A

- operatorii unari;
- operatorii de atribuire.
- operatorul ( ? ).

E x e m p le :
1) n expresia x~y+z nti se va efectua scderea i apoi adunarea;
2) Instruciunea:
x = = z = 0;
este echivalent cu:
x= (y = (z=0));
i are ca efect atribuirea vaiorii 0 variabilelor x , y, z. Explicaia const n aceea c
efectuarea unei atribuiri conduce i la obinerea unui rezultat (valoarea care a fost
atribuit) i care poate fi folosit ca n exemplul de mai sus.
3) Secvena de program;
i n t a = 5 # b=10/ c=15;
a += b -=c %= 4;
lO .w rite ln (a + " + b + " " + c } ;
produce la ieire:
12 7 3

2.7. Instruciuni
Limbajul Java prevede mai multe tipuri de instruciuni:
Instruciunea co m p u s grupeaz mai multe instruciuni prin includerea
lor ntre acolade; ia natere astfel un bloc. Un bloc este considerat a fi o unic
instruciune.
In stru ciu n ea d e d e c la ra re asociaz unei variabile un anumit tip i
eventual i atribuie o valoare iniial; variabila devine lo c a l celui mai interior
bloc care o conine, n sensul c exist atta timp ct se execut instruciuni ale
blocului. O instruciune de declarare poate s apar oriunde n interiorul unui bloc.
nainte de utilizarea for, variabilele locale trebuie s fi primit valori fie prin
iniializare la declarare, fie printr-o instruciune de atribuire (n caz contrar va fi
semnalat o eroare la compilare).
Invocarea unei m eto d e, indiferent dac ea ntoarce sau nu o valoare.
Incrementrile, ce folosesc forma prefixat sau postfixat a lui ++ i --
In stru ciu n ea d e a trib u ire conine semnul =, eventual prefixat cu un
operator.
In stru ciu n ea vid este format numai din i care nu prevede vreo
prelucrare. t
In stru ciu n ea prin c a r e este c r e a t un o b ie c t folosete n acest scop
operatorul new.
In stru ciun ile ce c o n tro le a z o rd in ea d e executare, ca de exemplu: i f -
m lm m , fo r , w h ile etc. Ele vor fi prezentate detaliat n continuare.
2,7 Instruciuni 37

Trecem la descrierea instruciunilor ce controleaz ordinea de executare.


Instruciunile care apar n cadrul lor vor fi notate prin i n s t r , i n s t r l etc.

Instruciunea i f - e i s e . Ea are una dintre formele:


i f (e x p r e s ie _ b o o le a n ) i n s t r l
sau
i f (e x p r e s ie _ b o o le a n ) i n s t r l
6la e i n s t r 2
Este evaluat expresia boolean. Dac rezultatul este tr u e , atunci se
execut i n s t r l , iar n caz contrar se execut i n s t r 2 (sau nimic pentru forma
scurt).
Clauza e l s e este asociat celui mai recent i cruia nu i s-a asociat un
e ls e . Astfel n :
i f (a==0 ) b = l ; i (c==l) b=2 e l s e b=3
clauza e l s e este asociat celui de al doilea i f . Pentru a face lucrurile clare, este
indicat ca fiecare i f s fie nsoit de un e l s e (urmat eventual de instruciunea
vid).

Instruciunea w h ile are forma:


w h ile (e x p r e s i e__bool ean) i n s t r
Se ncepe cu evaluarea expresiei booleene i se execut n mod repetat
instruciunea i n s t r atta timp ct expresia boolean are valoarea tr u e .

Instruciunea d o -w h ile are forma:


do i n s t r 'whLX. {expresie__boolean) }
Se ncepe cu executarea instruciunii i n s t r i se reia executarea ei atta
timp ct expresia boolean are valoarea tr u e .

Instruciunea f o r are forma:


to x ( i n i i a l i z r i ; e x p r e s ie _ b o o le a n ; a c t u a l i z r i ) i n s t r
unde:
- iniializrile i actualizrile (de obicei incrementri i/sau decrementri)
sunt liste de instruciuni separate prin virgul; listele pot fi eventual vide;
- expresia boolean poate i ea lipsi, caz n care se presupune c ea are
implicit valoarea tr u e .
Efectul instruciunii poate fi descris astfel:
in iia liz r i
w h ile (e x p r e s ie ^ b o o le a n ) {
in s tr ; a c tu a liz r i
}
Cadrul tipic de utilizare este n iteraii. De exemplu, suma primelor n
numere naturale poate fi obinut astfel:
8 =0
f o r ( i= 0 i< n ;i+ + ) s+ = i;
38 2 . E L E M E N T E D E B A Z A L E L IM B A J U L U I JA V A

Mai prezentm nc un exemplu: dei n-am vorbit nc despre tablouri,


menionm c pentru inversarea ordinii elementelor unui tablou (unidimensional)
a este suficient o instruciune f o r (indexarea elementelor tablourilor ncepe cu
0):
f o r ( i= 0 , j = a . l e n g t h - 1 i < j i + + , j - - )
{ b = a [ i ] a [ i ] = a [ j ] ; a [ j ] = b }

Un caz limit este:


f o r ( ) in s tr '
care desemneaz repetarea "la infinit'1 a executrii lui i n s t r . Evident, n cazul
folosirii acestei forme, asigurarea ieirii din ciclu cade n sarcina instruciunii
in s tr .
n iniializrile din f o r este permis s facem declarri, ca de exemplu:
f o r ( i n t i = l i< = n i++) s + = i ;
dar numai dac i nu este deja declarat; precizm c n aceast situaie variabila i
este local instruciunii fo r .

nainte de a prezenta alte instruciuni, menionm c o instruciune poate fi


etichetat. Etichetarea ei se face astfel:
efciaheta:
unde e t i c h e t a este un identificator. n acest mod va fi posibii s facem referire
(trimitere) la instruciunea respectiv.

Instruciunea b re a k este folosit pentru a iei dintr-un bloc. O prim


form este: .
&!i
prin care se iese din cea mai interioar instruciune f o r , w h ile , do sau sw itc h ,
sau bloc ce conine aceast instruciune.
Forma:
b re a k e t i c h e t a ;
unde e t i c h e t a este eticheta unui bloc sau a uneia dintre cele 4 tipuri de
instruciuni menionate, ce conine instruciunea b re a k . Ca efect, controlul este
transferat la instruciunea cu eticheta respectiv. Se poate astfel iei de exemplu
din dou instruciuni f o r imbricate. S remarcm faptul c nu este posibil s
trecem controlul oricrei alte instruciuni (ca pentru g o to din alte limbaje), deci
transferul este controlat i respect structurarea programului.

Instruciunea c o n tin u e are forma:


c o n tin u e ;
i este folosit n cadrul instruciunilor w h ile , do i fo r . Efectul ei este saltul la
condiia care controleaz reluarea acestor instruciuni de ciclare.
Ca i n cazul instruciunii b re a k , poate fi folosit i varianta etichetat,
prin care se face salt Ia condiia de control a unei instruciuni w h ile , do sau f o r
cu eticheta respectiv, care o "acoper" (include) la un nivel superior.
2t7. Imtruciwi 39

In stru ciu n ea sw itch evalueaz o expresie ntreag, a crei valoare este


folosit pentru a detecta o secven de instruciuni ce urmeaz a fi executat. O
prim form a ei este:
switch {e x p r e s i e ) {
case val2 s e c v e n i n s t r u c i u n i i

case v a l k : secven_instruciunik
default : secven_instruciuni
}
unde:
- ipui expresiei poae fi numai char, byte, short sau int;
- v a l l v a l k sunt constante (literali sau cmpuri statice finale
iniializate cu expresii constante) de acelai tip cu al expresiei;
- alternativa d e fa u lt este opional.
Executarea instruciunii are loc dup cum urmeaz. Este calculat vaioarea
expresiei, care este apoi comparat pe rnd cu v a l 2, v a l ki pn cnd se
detecteaz prima dat egalitate. Urmeaz executarea secvenei de instruciuni
corespunztoare, dar i a celor care u rm eaz; executarea acestora poate fl limitat
prin folosirea instruciunii break. Dac nu se detecteaz nici o egalitate, atunci se
execut secvena de instruciuni corespunztoare lui d e fa u lt (dac aceast
alternativ este prezent) sau nu se execut nimic (n caz contrar).
Mai general, o alternativ poate avea mai multe valori, ca n exemplul
urmtor:
cai 1 case 3 : case 5 b; b a

E x e m p lu . Programul urmtor:
o l Switch {
t t i c v oid numr (irit i) {
witch (i) {
& 1 lO.writef"unu " )
case 10.write ("doi
case IO.writeln{"trei " )

public static void main (String[] args) {


numr(3) numr(2); numr(1);
}
}
va produce ia ieire:
trei
doi tr e i
unu doi tr e i
Instruciunea return are una dintre formele:
rtu m ; '
rtum ex p resie
40 2. E L E M E N T E D E B Z A L E L IM B A J U L U I J A VA

i furnizeaz valoarea care va fi ntoars (n cazul cnd metoda prevede ntoarcerea


unei valori) i termin executarea metodei n care apare.
Putem folosi return i pentru a iei dintr-un constructor sau dintr-un bloc
de iniializare static.

2.8. Despre recursivitate n lim bajul Java

Acest paragraf este menit a face mai puin arid prezentarea de mai sus i
de a face unele precizri suplimentare.

O metod poate invoca o alt metod (eventual pe ea nsi). Invocarea se


poate face pe baza obiectului curent sau pe baza unui alt obiect (cmp al clasei sau
parametru al metodei).
Programul urmtor implementeaz m e to d a so rt rii cu a ju to ru l a r b o r ilo r
d e so rta re . Reamintim c un arbore de sortare este m arbore binar (fiecare vrf are
cel mult doi descendeni) n care valoarea ataat fiecrui vrf este mai mare dect
valorile vrfurilor din subarborele stng i mai mic dect valoarea vrfurilor din
subarborele drept. Un exemplu de arbore de sortare este urmtorul;

^ 7 10

Arborele s-a obinut n urma citirii de la intrare a valorilor 6, 9, 2,10 4, 7.


Dac urmtoarea valoare citit va fi 8, se va crea un vrf ca descendent drept al
celui ce conine valoarea 7, iar noul vrf va conine (va fi etichetat cu) valoarea 8.

Este folosit clasa IO descris n capitolul anterior. Esena programului


este cuprins n clasa elem.
Cmpurile clasei sunt variabila ntreag v i referinele s t i dr de tip
elem, corespunztoare unei nregistrri asociate unui vrf, care memoreaz
valoarea asociat vrfului i adresele descendenilor stng i drept. De asemenea
apare cmpul ra d cu modificatorul efcatic deoarece d reprezint referina la
rdcina arborelui, deci n mod natural este comun tuturor obiectelor de tipul
elem.
Constructorul elem cu un parametru iniializeaz cmpurile obiectului
care a produs invocarea sa cu valoarea asociat i cu referinele nule, adic este
creat o frunz n arbore.
2 Despre recursivitate n limbajul Java 41

Constructorul fr nici un parametru nu prevede nici o aciune. tim din


primul capitol c n lipsa vreunui constructor prezena sa este implicit, dar cum
clasa elem include un constructor, el trebuie specificat explicit.
Metoda creare creeaz arborele de sortare astfel:
- este citit un numr ntreg i este creat arborele (frunza) ce conine acea
valoare; "adresa" sa este ntoars n referina static rad;
- atta timp ct Ia intrare urmeaz valori numerice (prima valoare
nenumeric este detectat cu ajutorul metodei isNaN), ele sunt citite i adugate,
prin invocarea metodei adaug, arborelui de sortare curent.
Metoda adaug primete referina ctre un vrf i o valoare ntreag. Este
creat o nou frunz cu ajutorul constructorului e l e m i e s te ntoars M
adresaMei
astfel nct frunza s devin descendentul stng sau drept al unei frunze din
arborele de rdcin x. Determinarea vrfului la care este "atrnat" noua frunz se
face recursiv prin invocarea metodei pentru descendentul stng sau cel drept, dup
cum valoarea este mai mic sau mai mare dect dect informaia din vrful primit
6a parametru; valoarea ntoars este atribuit respectivului descendent.
Metoda parcurg ntoarce un ir ce conine, n inordine valorile din
subarborele de rdcin x (parairetrui metodei).
Clasa principal ArbSort, prin metoda main, creeaz o instan Ob a
clasei elem i, prin intermediul acestui obiect, invoc metodele creare i
parcurg ale acestei clase. Pentru metoda parcurg este prevzut argumentul
elem. rad, adic rdcina arborelui de sortare.
V

Pentru o mai bun nelegere, s presupunem c obiectul rad are ca


descendent stng obiectul rads, iar ca descendent drept obiectul radd. n cazul
adugrii unei valori val n arborele de rdcin rad, lucrurile se petrec dup cum
urmeaz. Obiectul rad este pus s execute metoda sa adaug. Dac v a l este mai
mic sau egal cu cmpul numeric al obiectului rad, atunci rad "comand M
obiectului rads s execute metoda sa adaug, adic s insereze valoarea val n
subarborele de rdcin rads. Cazul complementar este tratat analog.
ela elem {
i n t v; elem st,dr; t t i c elem rad;
elem{) '{ }
elem( i n t val) { v = val; }
v o id creare() {
d o u b le val
for ( ) {
val = IO. read U;
if ( Double.isNaN(val) ) b r e a k
@1@ rad = adaug(rad, (int) val)
}
i
elem adaug(elem x , i n t val) {
(x = = n u ll) x = nmv elem(val)
42 2, E L E M E N T E D E B A Z A L E L IM B A J U L U I JA V A

lee i (val<x.v) x.st=adaug(x.st,val);


else x.dr=adaug(x.dr,val);
return x
}
String parcurg(elem x) {
if (x==null) return
else return parcurg(x.st) + x.v parcurg(x.dr);

clasa ArbSort {
p u b l i c s t a t i c v o id main(String[] arg) {
elern Ob = new elem{)
Ob.creare(); XO.writeln(Ob.parcurg(elem.rad))
}
}
Observm c este respectat unul dintre principiile programrii orientate
spre obiecte i anume ncapsularea: clasa elem "pune la un loc'1 cmpuri i
operaii (metode) prin care aceste cmpuri sunt prelucrate.

Programul de mai sus se preteaz la o scurt (i incomplet) discuie


asupra noiunii de tip de date.
S considerm de exemplu tipul primitiv i n t . n multe locuri, chiar acest
tip simplu este prezentat incorect: se reduce noiunea de tip Ia mulimea valorilor
posibile. n realitate este vorba nu numai de aceast mulime, ci i de prelucrrile
ce se pot efectua asupra valorilor de tipul respectiv (adunare, scdere etc.).
Lucrurile devin mai complexe pentru clase. O clas este un tip caracterizat
prin:
- cmpuri (cu tipurile lor);
- constructori (cu signaturile i corpurile lor);
- metode (cu signaturile i corpurile lor, precum i cu tipul rezultatului
ntors)
- drepturile de acces la fiecare constructor, cmp i metod;
- drepturiie de motenire referitoare la cmpuri i metode.
Despre drepturile de acces i motenire vom discuta n capitolele urmtoare.
ALTE ELEM ENTE DE BAZ ALE
^ LIMBAJULUI JAVA. APLICAII

. Lucrul ce tablouri n Java

Prezentm n acest paragraf elementele de baz legate de tablouri i lucrul


cu ele.
Un ta b lo u este o secven de componente de acelai tip. Acest tip poate fi
un tip primitiv sau un tip referin (deci putem lucra cu tablouri de obiecte).
Un tablou a poate fi declarat folosind una dintre urmtoarele modaliti:
tip[] a;
tip a [];
unde t i p este tipul componentelor tabloului. n continuare vom folosi numai
prima form.
Declararea unui tablou nu are drept consecin crearea sa. Crearea
tabloului a declarat mai sus trebuie Mcut explicit, prin:
a = new t i p [ n ]
unde n este o constant sau o variabil ntreag ce a primit o valoare strict
pozitiv.
Cele de mai sus devin clare dac specificm faptul (menionat i n primul
capitol) c un ta b lo u e s te un tip r e fe r in . Prin creare se obine un obiect de tip
tablou (obiect numit prin abuz de limbaj tot tablou).
Componentele tabloului pot fi referite prin a [ i ] , cu i lund valori n
intervalul 0 . . n - l ; dac i nu este n acest interval, va fi semnalat o eroare la
executare. Lungimea tabloului poate 0 referit prin a . le n g th .

Declararea i crearea pot fi fcute i simultan prin:


t i p [] a = new t i p [ n ]
sau printr-o iniializare efectiv, ca de exemplu:
lnfc[] a = {0,3,2,5,1}
prin care, evident, a . le n g t h devine 5.

Cmpul le n g t h al unui (obiect de tip) tablou este un cmp constant (cu


modificatorii p u b l i c i f i n a l ) de tip in t ; decis odat creat, un obiect tablou nu
44 3, ALTE ELEMENTE ALE LIMBAJULUI J VA. APLICA II

i poate schimba dimensiunea (numrul de componente). Pe de alt parte,


variabilei referin la tablou i se poate asocia o referin la un tablou de acelai tip.

Exemplul 1. Urmtoarea secven de program:


tip [] a
a = new t i p [10] ...
a = new t i p [20 ]
este corect. Evident, noul tablou nu are nici o legtur cu cel vechi (n particular
nu se pstreaz valoarea nici unei componente a tabloului vechi).

E x e m p lu l 2e Pentru interschimbarea coninutului a dou tablouri se poate


proceda la fel ca pentru interschimbarea valorilor a dou variabile primitive;
int [] a = { 1 ,2 ,3 ,4 } # b = {11 2 } , c;
c = a a=b; b=c;
deci practic se interschimb referinele Ia cele dou tablouri.

Exemplul J , Deoarece un tablou este un tip referin, transmiterea sa ca


argument la invocarea unei metode se supune regulilor deja cunoscute referitoare
la apelul prin valoare. Astfel, executarea urmtorului program:
c la s s C (
void mat(int[] a) {
a[0]=9;
a = n @ w iafe[5J; for {Int i-0; i<5; i++) a[i]=0;
}
}
class Tablou2 {
public static void main{String[ s) {
int[] a = {1,2,3,4};
C Ob = n e w C ( ) ; O b . z n e t : ( a ) ;
for, (iat 1=0 ; i<a.length; .1([1] + n;
}
}
va produce ia ieire:
9 2 3 4

Exemplul 4. Urmtorul program este menit s reaminteasc efectul


modificatorului final pentru variabile de tip referin, in particular pentru
tablouri:
class A {
static final int{] x = {1,2};
void modify() { x[0] = 11; }
}
clasa TabFinal {
public static void main ( S t r i n g [] args) { .
A a = new A () ; a,modify ();
to x ( in t i = 0 ; i < A . x . l e n g t h ; X O .w rite { A . x [ i ] +
i./. Lucrul cu tablouri n limbajul Java 45

i va produce la ieire:
11

Mai precizm c un tablou de caractere nu este un ir de caractere.


De asemenea sunt permise tablouri avnd ca tip o interfa sau o clas
abstract. Precizrile necesare apar n capitolele ce urmeaz.

Limbajul Java permite lucrul cu tablouri multidimensionale. De exemplu


expresia C [ ] [ ] este un tip ce reprezint tablouri bidimensionale ale cror
componente au tipul C.
Tablourile multidimensionale trebuie gndite ca tablouri unidimensionale
ale cror elemente su n t tablouri unidimensionale etc. De aceea referirea la un
element ai unui tablou ! a se face prin:
a [ in d ic e i] . . . [ i n d i c e n] .
Este suficient s reducem discuia la tablouri bidimensionale,
generalizarea fiind imediat. S considerm urmtorul exemplu:
i n t [] (] a = nw i n t [3 ] [ ]
a (0] i n t [3 ]
& 1 MW i n t [ 4
a 2 ] m w i n t [ 2 ];
Ia natere astfel un tablou de forma:

ceea ce arat c n Java tablourile nu sunt neaprat dreptunghiulare; aceasta


conduce desigur la economie de spaiu.
Evident, a [ 1 ] . len g th = 4 .
La aceeai structur se poate ajunge i printr-o iniializare efectiv:

care n plus atribuie valori clementelor tabloului.


Dac n referirea la un element al unui tablou unui dintre indici nu este In
intervalul corespunztor, va aprea eroarea (numit n Java excepie) cu numele:
IndexO utO fB oundsE xception.
Reamintim c unei referine la un tablou i se poate asocia o referin la un
alt tablou. Astfel, pentru exemplul de mai sus poate apare n continuare:
a [ 1] new i n t [7 ]
w a ce permite s schimbm parte'* dintr-un tablou fr a defini un altul i a
copia prile comune. De asemenea putem de exemplu s interschimbm dou
"linii" ale tabloului de mai sus prin:
i n t [] tem p
temp = a [0 ] [ 0 ] = [ 2 ]; [ 2 ] = tem p
46 3, ALTE ELEMENTE ALE LIMBAJULUI JAVA. APLICAII

3.2. Aplicaia 1 : Parcurgerea n adncime a imul g raf


neorieotat
Parcurgerea grafurilor apare n multe probleme din teoria grafurilor. Ea
const n a pleca dintr-un vrf al grafului i de a trece, mergnd pe muchii, prin
toate celelalte vrfuri. Un vrf poate fi atins de mai multe ori, dar este pus n
eviden numai o singur dat atingerea sa5 numit v iz ita r e , ce corespunde unei
prelucrri a vrfului respectiv, prelucrare specific fiecrei probleme concrete.
Evident, plecnd dintr-un vrf putem atinge doar vrfurile din componenta
sa conex. De aceea n continuare se va uece Sa un vr*f ce nu a fost atins, deci din
alt component conex.
Graful este reprezentat prin lista vecinilor fiecrui vrf. Vom folosi pentru
exemplificare urmtorul graf:

pentru care listele vecinilor vrfurilor sunt:


L- { 3 ,l} ; 4 }; L2={5,7}; L3={0,4,1};
L4= {3 1}; L5= {27}; L6=0; L7={2,5}.

Prezentm n continuare algoritmul DF (Z>epth First) de parcurgere n


adncime a unui graf neorientat cu n vrfuri.
1) se citete valoarea n;
2) se citesc listele vecinilor vrfurilor;
3) ntr-un tablou boolean a t i n s de dimensiune n se iniializeaz
elementele sale cu f a l s e , pentru a marca faptul c nici un vrf nu a fost nc
vizitat; la vizitarea unui vrf, elementul respectiv va primi valoarea tru e;
4) se execut instruciunea (scris n pseudocod):
for i = 0 , n - l
i f ]a t in i then DF(i)
en d if
enor
' .
unde metoda DF are corpul:
s c r ie v a lo a r e a iui i a t i n i <r- tr u e ;
f o r toi j GLi (n ordinea n care apar n )
i f 1a t in s j
then DF(j )
endi
endfor
3.2. Aplicaia I: Parcugerea n adncime a unui g ra f neorientai 47

Drept rezultat, vrfurile vor aprea n.ordinea:


0 3 4 1 2 5 7 6
Programul care urmeaz implementeaz algoritmul descris mai sus,
memornd listele vecinilor vrfurilor ntr-un tablou bidimensional. Nu sunt deci
utilizate liste nlnuite.

Clasa principal este ParcDP. Metoda main creeaz un obiect Ob al clasei


df, iar apoi i folosete pentru invocarea metodei parcurg ai acestei clase. Este
folosit i clasa IO prezentat anterior.
Clasa d f utilizeaz n principal urmtoarele cmpuri:
- n = numrul de vrfuri din graf;
mat = matricea (tabloul bidimensional) care va conine listele vecinilor
fiecrui vrf;
- a t i n s = tablou care memoreaz pentru fiecare vrf dac el a fost sau nu
vizitat Ia momentul curent al parcurgerii.

Constructorul clasei nu are parametri i are rolul de a face iniializri. Se


ncepe prin citirea numrului n de vrfuri ale grafului. Sunt create tabloul temp de
dimensiune n i tabloul mat de aceeai dimensiune, ale crui elemente sunt
tablouri. n continuare, pentru fiecare vrf i se citesc n temp vecinii si pn cnd
este detectat la intrare altceva dect un numr; pentru aceasta, la intrare lista
vecinilor unui vrf se va termina (de exemplu) cu o liter; prin program acest
"delimitator" este detectat de funcia standard Double. isNaN. Numrul vecinilor
lui i este calculat n ntemp, iar vecinii sunt citii n primele ntemp componente
ale lui temp. Apoi este creat vectorul mat [ i] de lungime ntemp i sunt mutate n
el primele ntem p componente ale lui temp.
Este evident c tabloul bidimensional mat nu este n general unul
dreptunghiular, deoarece numrul vecinilor unui vrf poate s difere de numrul
vecinilor altui vrf, aa cum se ntmpl i n exemplul considerat.

Metoda p a r c u rg mai folosete variabila cc a crei valoare reprezint


numrul ultimei componente conexe determinate. Este folosit i apelat recursiv
metoda d f ,a crei aciune a fost descris anterior.

S observm c din afara clasei d f tim doar c ea conine un constructor


i metoda p a rc u rg , ambele fr nici un parametru. n acest mod toat esena
problemei este ncapsulat i ascuns n clasa d f, urmndu-se unul dintre
imperativele programrii orientate spre obiecte.
c la s a df {
i n t [ ] [ ] m at; i n t n b o o le a n [] a t i n s
d f() {
d o u b le d; i n t [] tem p i n t ntem p
IO .w r i t e ( Hn = "}; n = ( i n t ) IO .r e a d () ;
m at = new i n t [ n ] [ ] temp = new i n t [ n ]
48 J. ALTE ELEMENTE ALE LIMBAJULUI JA VA. APLICA II

for (int i=0; i<n; i++) {


10,write("Vecinii lui H + i + :
ntemp = 0 d = 10.read{);
while( ! Double.isNaN(d))
{ temp[nteinp++3 = (int) d; d = 10.readU ; }
mat [i] = new int[ntemp];
for {int j-0; j<ntempj++) mat[i][j] = temp[j];
}
IO.writeln("*********")

v o id listare (} {
f o r ( i n t x=0; i<n i++) {
IO.writeti + \tn);
f o r ( i n t j=0 ; j<mat[i].length j++)
O.write(mat[i][j]+ ;
IO,writeln ()
}
0 writeln("*********"};

v o id parcurg{) {
atins = n@w booXean[n]
i n t cc=0, i
f o r (i=0i<n; i++) atins[i] = false
f o r (i=0i<ni++)
i ( ! atins[i] ) {
10.write{"Comp. conexa " + ++cc +
\t");
DF {i ); IO.writelnO ;

p r i v a t e v o id DF( i n t i ) {
in t j , k
atins[i] = true; O.writefi + H w
f o r {j=0 j<mat[i].lengthj++) {
-mat[i]{j ]; f ( ! atins[k] ) DF(k);
}

c l a s s ParcDF {
p u b l i c s t a t i c v o id main(String[] s) {
df Ob = new df(); Ob.listare()0b.parcurg();
}
}

Pentru exemplul considerat, programul de mai sus va produce la ieire:


Comp. co n ex a 1 : 0 3 4 1
Comp. co n ex a 2 : 2 5 7
Comp. con exa 3 6
3.3. Referina t h i s i blocuri de iniializare 49

3.3. Referina this i blocuri de iniializare

ntr-o metod care nu este declarat cu modificatorul static, putem


utiliza referina obiect t h i s pentru a ne referi la obiectul curent, adic cel care a
invocat metoda. Prezentm doar trei situaii n care aceast referin special este
de obicei folosit: _

1) n interiorul constructorilor:
class clasa {

clasa(int i) { tbis.i=i;}

} .
prin care cmpul i al clasei c l a s a primete valoarea i transmis Ia crearea
obiectului prin utilizarea constructorului de mai sus. n acest mod este clar
distincia ntre cmpui i i parametrul i. Evident, am putea renumi parametrul:
c la s a ( i n t i i ) { i = i i ; }
ceea ce poate conduce ns uneori ia confuzii privind semnificaia variabilelor.

2) La apelarea unei metode, cnd dorim s transmitem ca parametru


obiectul curent. Aceasta este util de exemplu cnd vrem s crem un nou obiect
care s pstreze referina ctre cel curent:
clase Clasa {
int i , j ; C la s a Ob

Clasa{int i, Clasa Ob) {thie.i=i thle.Ob=Ob;}

Ob=new C l a s a ( j , t h i s ) ;

3) Cnd dorim ca rezultatul ntors de o metod s fie obiectul curent.


Este suficient s includem instruciunea:
re tu rn t h i s

Un ai doilea aspect de care ne vom ocupa n acest paragraf l constituie


blocurile de iniializare.
O clas poate avea unul sau mai multe blocuri de iniializare. Ele trebuie
declarate cu modificatorul s t a t i c :
t tic { .. . }
Blocurile statice pot opera numai asupra unor entiti statice. n principal,
ele sunt folosite pentru iniializarea unor cmpuri statice ale clasei crora dorim s
Ie atribuim de la nceput alte valori dect cele implicite. Iniializrile statice,
realizate n cadrul blocurilor de iniializare, se fac n ordinea n care apar acestea
n cadrul clasei. ntr-un bloc static nu putem folosi r e t u r n sau t h i s .
50 3. ALTE ELEMENTE ALE LIMBAJULUI JAVA. APUCAII

Declararea cmpurilor asupra crora acioneaz un bloc de iniializare


trebuie, n mod logic, s precead acel bloc. Astfel, n exemplul urmtor:
class C {
static int[3 a = new int[10]
static {
for (int i-0 i<a.length i++) a[i]=1;

este clar c blocul de iniializare trebuie precedat de crearea vectorului a.


Executarea blocului static iniializeaz componentele vectorului a cu 1.

3.4. Iniializarea claselor

Discuia de mai sus asupra blocurilor de iniializare ridic urmtoarea


problem: cnd sunt ele executate? Pentru aceasta trebuie vorbit nti despre
iniializarea claselor.

ncepem prin a preciza c un cmp se numete constant dac este declarat


cu modificatorii sfcafcic i f i n a i i n plus n declarare este iniiali
2at o o
expresie constant. O expresie constant poate conine numai:
- literali avnd tipuri primitive sau tipul S tr in g ;
- conversii Ia un tip primitiv sau la tipul S tr in g ;
- operatorii urmtori:
+ - ! * / % , > < - > - & & I I operatorul ( ? )
(deci nu ++, - - sau instanceof)
- variabile (eventual precalificate) declarate cu final i iniializate cu
expresii constante.
Expresiile constante sunt evaluate n faza de compilare. De asemenea
cmpurile constante sunt iniializate la compilare.

O clas este iniializat !a prima utilizare activ a ei, adic atunci cnd:
este invocat o metod declarat n clasa respectiv;
- este invocat un constructor al clasei;
- este creat un tablou ale crui elemente sunt de tipul clasei;
- este folosit un cmp neconstant declarat n clas sau se atribuie o valoare
unui astfel de cmp.
Dup cum vom vedea n capitolul referitor la extinderea claselor, nainte
ca o clas s fie iniializat este iniializat superclasa sa.
Cnd o clas este iniializat, are loc iniializarea cmpurilor i blocurilor
statice, exact n ordinea n care apar. n consecin o iniializare poate conine
referiri numai la cmpuri declarate anterior. Astfel secvena de declarri:
static int i = j
static int j = 1
3.5. Aplicaia 2 : Generarea tuturor (n f k ) - combinrilor 51

este incorect i va fi semnalizat o eroare la compilare.


Regula dp mai sus nu se extinde ns asupra metodelor. Astfel urmtorul
program este corect:
alass C {
static int s c r i e () { return j }
t& tic i n t i = s c r i e { )
s ta tic In t j = 1
}
clase Init {
public static void main(String[] sir) {
XO,writeln(C =i + "H)
}
}

i produce la ieire valoarea 0, deoarece iniializarea cu 1 a variabilei j are loc


dup ce i a primit valoare prin invocarea metodei scrie.

3.5. Aplicaia 2 :Generarea tuturor - combinrilor

Fie date numerele naturale n, cu n>k>0. Numim (n #k) - combinare un


k-uplu {ai# . . . a k)e {1 , 2 , . . . , n}k cu ax<a2< . . . <ak. Fie CCn, k) mulimea ior.
Se tie c numrul (n, k) - combinrilor este , adic |C(n,k)|. Ne propunem n
continuare s scriem lin program care s produc toate (n, k) - combinrile.
Evident, nu este vorba de a calcula , ci de a produce elem entele lui
C (n; k); altfel spus, cerinele problemei nu sunt de natur cantitativ, ci calitativ.
Totui, aparent paradoxal, vom pleca de la formulele cantitative:
C n -l (1)

cn ~ ck ~ l + c n- l Pentru n > k ()
Formulele cantitative de mai sus sunt uor de demonstrat prin inducie i
apar n orice culegere de probleme ce acoper clasa a X-a. Ce nu apare n aceste
culegeri, isnci s se cread c este vorba numai de artificii de caicui, este
aspectul lor calitativ. Mai precis, semnificaia lui (!') este:

C (n,k) = X J C (i - l , k - l ) (2)
i=k
unde C { i ~ l , k - 1 ) este mulimea obinut prin adugarea elementului i la fiecare
dintre vectorii de lungime k -1 din C ( i - 1 , k - 1). Vom nota acest lucru prin:
C (i~ l, k -1 ) = C ( i- 1 ,
S exem plificm cele de mai sus pentru n = 4 , k=2.
C(4f2) = ( 1 ) 2 U C ( 2 , l ) 3 U C ( 3 , l } 4 =
= {( 1) }2 U { ( 1 ) / (2)13 U { (1) 2 ) ) }4 -
= { ( 1 , 2 ) } U { { 1 #3 ) f ( 2 , 3 5 } U { { 1 ; 4 ) , ( 2 , 4 ) # ( 3 , 4 ) ) -
- { ( 1 , 2 ) , ( 1 , 3 ) # ( 2 #3 ) , { 1 , 4 ) , { 2 #4 ) , { 3, 4} }
52 3. A L T E ELEMENTE ALE LIMBAJULUI JAVA. A P L IC A II

S mai observm c elementul care se concateneaz unui C ( i, k) este i + l,


deci aceast din urm valoare este bine determinat i nu mai trebuie "inut
minte" explicit.

Este clar c:
- dezvoltarea nodurilor din arbore se oprete cnd devine 0;
- ( 4 ,2 } - combinrile se regsesc parcurgnd drumul de la frunze ctre
rdcin.

Plecnd de la cete de mai sus, vom construi un arbore de obiecte pentru


care legturile merg spre tatl lor. Cmpurile obiectelor vor fi constituite din
valorile n, proprii i referina ctre obiectul precedent.
Dorim deci s obinem urmtorul arbore de obiecte (n care obiectele au
primit nume doar pentru claritate):
A
D

arbore n care dac parcurgem drumurile de Ia frunze ctre rdcin, cmpurile n


ale obiectelor de pe aceste drumuri (fr a considera ns rdcina) produc o
(n #k) - combinare. De exemplu plecnd de la obiectul H, vom obine ( 2 ,4 ) .

Putem trece acum la descrierea programului.


Metoda principal construiete un obiect Ob de tipul clasei elem pe baza
cruia este invocat metoda p r e l a clasei elem.
Clasa elem cuprinde cmpurile n, i t a t a ( t a t a indic spre tatl
obiectului curent n structura de arbore). Constructorul fr parametri nu prevede
vreo aciune, iar constructorul cu trei parametri creeaz un obiect i stabilete
legtura ctre tatl su.
Metoda p r e l citete n cmpurile statice n0 i k0 valorile iniiale ale Iui n
i k, iar apoi creeaz obiectul r a d prin intermediul cruia invoc metoda p.
Metoda p construiete descendeni ai nodurilor arborelui atta timp ct
0; dac s-a ajuns la k=0, atunci se invoc metoda p r i n t pentru parcurgerea
S.5. Aplicaia 2 : Generarea tuturor (n , k ) combinrilor 53

drumului de la frunz spre rdcin i implicit pentru listarea (nfk) -combinrii


asociate.
S considerm de exemplu situaia n care obiectul E invoc metoda p
(ftr parametri). Cum k=0, obiectul E va tipri valoarea lui cnk (vezi mai jos)
urmat de rezultatul ntors prin executarea metodei print fr parametrii. Ca
va fi ntors irul format din 1 (valoarea expresiei n+l, unde n este cmpul
lui E, acesta fiind obiectul ce realizeaz invocarea), concatenat cu rezultatul
invocrii . print (). Dar acest din urm rezultat este irul format din 3 (valoarea
expresiei n+l, unde n este cmpul Sui B)turmat de rezultatul invocrii rad.pO
c Tv sstc iru vid deoarece cmpul tata al obiectului rad este t m l l . n
consecin la ieire va aprea combinarea (1 ,3 ).
n clas a mai fost folosit cmpul static cnk ce numr, pentru verificare,
cte (n, k) - combinri au fost generate. Aa cum am vzut, metoda principal va
tipri i aceast valoare.
Programul este urmtorul:
c la s e elem {
in t n,kelem tata;
static in t cnk
elem(in t n n t in t kk. elem x) { n - nn - kk; tata = x }
String print() {
if (tata= = au ll) r e tium

e ls e return n+1 tata.print()

v oid p() {
elem x=nullint i
i f ( == 0) IO.writeln(++cnJc + *\t: + print ())
e l s e fo r (i = i<=n i++) {
x = new elem(i~l, -l, this); x.p ()
}
) .

c la s s Comb {
p u b lic s t a t i c v oid main( String[] arg) {
10.write("n# =");
in t n= (in t) 10.read(); in t k= (in t} 10.read();
elem prim = new elem{n,k,null); ,
prim.pU ;
IO.writeln("n= " +n +" k= *+ k+ cnk= " +elem.chk)

Atragem din nou atenia asupra importanei cunoaterii exacte a obiectului


curent, aa cum s-a vzut la interpretarea corect a semnificaiei lui n n metcxia
print.
56 4. PACHETE, ACCES I VlZiBiUTATE

un pachet fr nume, constituit din aceste uniti; dar n acest mod clasele
pachetului fr nume pot fi accesate numai din interiorul pachetului, ceea ce
evident reprezint un dezavantaj.
Ne ndreptm n continuare atenia asupre pachetelor cu nume. Pachetele
sunt organizate n directoare n sistemul de fiiere al mainii gazd.
Un pachet poate conine:
- subpachete ale pachetului;
- tipuri (clase sau interfee) declarate n unitile de compilare ale
pachetului (avnd toate aceeai declarare package).

Pentru a crea ntr-un director un pachet, al crui nume dorim s fie


p a c h e t, trebuie creat un subdirector cu numele p a c h e t i apoi introduse n
subdirector unitile de compilare ale pachetului.
Fiecare unitate de compilare din pachetul p a c h e t trebuie s nceap cu
declararea:
package p a c h e t
care d informaii compilatorului asupra numelui pachetului din care face parte
unitatea de compilare.

Dac o unitate de compilare face referire la o clas C din pachetul p a c h e t,


atunci ca prima linie a acestui fiier trebuie plasat declararea im port :
im p o rt p a c h e t . C;
Dac dorini acces la toate clasele pachetului, putem folosi urmtoarea
form pentru declarare:
import p a c h e t . *

Structura de pachete este ierarhic (formeaz un arbore); un pachet PI


poate avea un subpachet P2. Aceast structur trebuie urmat i n declarrile
import, n care trebuie precizat P I . P2 (vezi exemplul de mai jos).

O clas sau interfa dintr-un pachet poate fi accesat din afara pachetului
doar dac are modificatorul public* Aceeai regul este valabil pentru accesarea
direct a membrilor unei clase a pachetului. Pentru constructori trebuie procedat Ia
fel, afar de cazul n care se folosete constructorul implicit, care este considerat ca
avnd modificatorul p u b lic.

Exemplul L Considerm urmtoarea structur de directoare:


c
HG
A -


UTIL

unde directorul HG conine pachetul A, care are ca subpachet pe . n a se afl


unitile de compilare Unu. ja v a , D oi .j a v a i T r e i .j a v a , n subdirectorul al
4.1. Pachete 57

lui A se afl unitatea de compilare P a tr u , ja v a , iar n subdirectorul al lui X se


afl unitatea de compilare T e s t . ja v a , descrise n cele ce urmeaz. Cum toate
unitile de compilare folosesc clasa IO. ja v a , unitatea cu acest nume este plasat
n pachetul UTIL.

Unitatea de compilare Unu. java:


package A;
import UTIL .*
p u b lic c la s a Unu {
in t k - 1
p u b lic v o id met( } { 1 0 .w r ite ln (k ); }

Unitatea de compilare D o i . java:


package A
is^ort UTIL.*;
p u b lic class Doi {
public static c2 j
p u b lic s t a t i c void met() { I O .w r ite ln (H Doi ; }

Unitatea de compilare Trei .ja v a :


package A
import UTIL.*
public c la s e Trei {
s t a t i c v oid met() { I O .w r it e ln ("Trei " ) }
}
Unitatea de compilare Patru ja v a :
package A.B;
im port UTIL .*
publicc c la s s P a tru {
publi e s t a t i c v o id m e t<) { I O .w r it e ln ( " P a t r u M);
}

Unitatea de compilare T e s t . j ava:


import A. *
isoport A . .*
is^ orfc UTIL .*
c la s e T est {
p u b lic s t a t i c v oid m a in ( S t r i n g [] s) {
Unu Ob = new Unu{ ); O b .m et( ) ;
S y s t e m .o u t .p r i n t ( D o i. k ) ; D o i.m e t ()
P a t r u .m e t ()

n plus, n unitatea IO. ja v a vom aduga ca prim linie:


package UTIL;
58 4. PACHETE, ACCES I VIZIBILITATE

n a in te d e a d e s c r ie m o d u l n c a r e s t e e x e c u ta t a p lic a ia , s u n t n e c e s a r e
c te v a p r e c i z r i s u p lim e n ta r e r e la tiv e la c o m e n z ile j a v a i j a v a c i la v a r ia b ila
d e m e d iu C L A S S P A T H .

La executarea unor comenzi ale mainii virtuale Java, ca de exemplu


jav ac i ja v a (ce vor fi descrise mai jos), are loc c/ave adic de
fiiere cu extensiile .ja v a i . c la s s . Pentru precizarea locului unde vor fi cutate
aceste clase, Java prevede v a r ia b ila d e m e d iu C L A S S P A T H . Valoarea variabilei
(numit i c a le a p e n tr u c o d ) este o mulime de ci, referit n continuare prin
p a t h ; cile din p a th sunt separate ntre ele prin caracterul ' '.
Caiea pentru cod p a t h poate fi setat la pornirea sistemului; de exemplu
pentru Windows 98, setarea se poate face n a u to e x e c .b a t. Este considerat
implicit i directorul curent. Apoi variabilei CLASSPATH i se poate atribui o
valoare prin comanda:
SET CLASSPATH^path
sau prin opiunea c l a s s p a t h din comenzile ja v a i ja v a c .
n comanda s e t , este indicat s precizm calea cu specificarea partiiei (de
exemplu C \ . . . ) pentru ca ea s fie regsit chiar dac lucrm din alt partiie. n
unele situaii este util s precizm o cale vid:
SET CLASSPATH=
Ordinea n care apar cile n p a th determin ordinea de cutare a claselor.
Atribuirea unei valori variabilei CLASSPATH anuleaz atribuirea
precedent. In particular, pentru pstrarea directorului curent trebuie inclus explicit
caracterul ' . ' .
Precizrile de mai sus sunt valabile i pentru setrile prin opiunea
c la s s p a th din comenzile ja v a c i ja v a , cu observaia c n acest caz noua
setare este valabil numai pentru comanda respectiv.

Executarea comenzii ja v a c are ca efect compilarea uneia sau a mai multor


uniti de compilare, ce conin definiii de clase sau interfee. Sunt compilate toate
tipurile (clase sau interfee) din unitile respective, dar i toate tipurile referite din
ele i care sunt regsite n calea pentru cod.
O form restrns a comenzii este;
jav a c opt u n it
unde att opiunile din lista op t, ct i unitile de compilare din lista u n i t sunt
separate ntre ele prin blancuri.
Dintre opiuni vom meniona numai urmtoarele dou:
-d d i r
-c la s s p a th p a th sau, prescurtat: ~cp p a t h
Prima opiune permite plasarea fiierelor byte-code, rezultate n urma
compilrii, n directorul d ir ; n lipsa acestei opiuni, drept d i r este considerat
directorul curent.
A doua opiune permite precizarea unei noi ci de cod, n care se va
ncerca regsirea (cutarea) claselor. Cutarea include att fiierele cu extensia
4.1. Pachete 19

.ja v a , ct i cele cu extensia . c l a s s . La cutarea unui tip (clas sau interfa)


t i p deosebim trei cazuri:
1) este gsit doar t i p . c l a s s : este folosit acest fiier byte-code;
2) este gsit doar t i p . ja v a este compilat acest tip i este folosit
rezultatul compilrii;
3) sunt gsite att t i p . c l a s s ct i t i p . ja v a : este folosit t i p . c l a s s
doar dac acest fiier este mai recent dect tip. java.

Executarea comenzii jav a pornete o aplicaie Java. Prezentm aici doar o


form restrns a ei:
java opt clasa
unde o p t este o list de opiuni, iar c l a s a este o clas care conine metoda
principal declarat prin:
public static void main(String sir)
Ca efect este ncrcat clasa i invocat metoda principal.
Dintre opiuni menionm doar:
- c la s s p a t h p a t h sau, prescurtat: -c p p a th
-D pro p -va l
Prima opiune de mai sus precizeaz o nou cale pentru cod.
A doua opiune seteaz valoarea v a l pentru o proprietate p ro p a
sistemului. Vom folosi aceast opiune n capitolul referitor la invocarea la distan
a metodelor, unde vom face i precizrile de rigoare.

Revenim la exemplul considerat, prezentnd o modalitate de executare a


aplicaiei.
Dac ne aflm n directorul c:\HG\B vom compila fiierul surs
Test.java cu comanda:
javac -classpath . Test.java
Nu este necesar ca unitile aflate n diferitele pachete s fie anterior
compilate.
Executarea va fi comandat prin;,
java -classpath ..t Test
prin care Ia ieire va aprea;
1 Unu
2 Doi
Patru

A fost folosit folosit opiunea de compilare c l a s s p a th . Explicaiile


sunt urmtoarele:
- am presupus n mod tacit c, ia pornirea sistemului, n calea pentru cod a
fost introdus calea c \ ja v a \b in . n caz contrar, trebuie asigurat explicit accesul
(att pentru compilare, ct i pentru executare) Ia ,fcasele eseniale" furnizate de
Java; aceasta se poate realiza de exemplu introducnd n opiunea c la s s p a th i
calea c : \ j a v a \ l i t A . Reamintim c la nceputul capitolului s-a fcut
presupunerea c Java a fost instalat n c \ java.
4. PACHETE. ACCES I VIZIBILITATE

- informaiile din p ack ag e i im p o rt urmresc ca, mergnd n sus in


arborele determinat de structura de subdirectoare, s se ajung la un subdirector
comun (n exemplul nostru este vorba de c \ hg);
- la executare trebuie precizat i directorul curent, pentru a avea acces la
fiierul Test. c l a s s .
Evident, subdirectorul comun menionat mai sus poate fi specificat i
explicit n comenzi:
javac -classpath c \HG\ Test.java
java -classpath . c\HG\ Test

Dac din metoda principal a clasei Test am fi inclus invocarea:


Trei.met();
s-ar fi obinut o eroare la compilare, deoarece n clasa Trei metcxla met nu are
modificatorul p u b lic . De asemenea cmpul static din clasa Doi trebuie s aib
neaprat modificatorul p tib lic pentru a putea fi referit din afara pachetului A
analog, o referire lacmpul Ob. din clasa Test este incorect.
Menionm c nu este neaprat nevoie s compilm n prealabil unitilede
compilare din directorul h i subdirectorul su , acest lucru fiind fcut automat la
compilarea clasei Test. De asemenea atragem atenia c dac unitatea de
compilare Patru, java ar fi inclus i n pachetul A, Ia executare s-ar fi semnalat
o eroare, datorit ambiguitii invocrii Patru.met { din clasa Test.java.

Un director poate conine mai multe pachete. De exemplu, pentru ca


directorul x s conin i un pachet cu numele AA, trebuie creat un subdirector AA al
lui X, n care s introducem unitile de compilare ale pachetului AA.
ncheiem acest paragraf cu observaia (evident) c dac folosim un mediu
de programare (de exemplu Kawa), compilarea i executarea devin mult mai uor
de efectuat, dar ideile de baz rmn aceleai.

4.2. Vizibilitate i acces


Pachetele, clasele, metodele, cmpurile i variabilele sunt identificate prin
numele lor. Problema care se pune este de a stabili din ce loc putem face referire la
aceste nume (cu semnificaia dorit), adic de a preciza domeniul lor de vizibilitate.
Cu acest prilej vom face o discuie mai amnunit referitoare la
modificatori, relund i unele aspecte deja prezentate.
Discuia va fi restrns la stadiul actual al prezentrii, care face abstracie
de facilitatea de extindere a claselor, i va fireluat ulterior. -

Variabile locale l etichete


Prin bloc nelegem o secven (eventual vid) de instruciuni, cuprins
ntre acolade. Un bloc este o instruciune i de aceea poate fi folosit n orice loc
unde poate s apar o instruciune.
4.2. Vizibilitate i acces 61

De exemplu orice metod i orice constructor sunt formate dintr-un antet


urmat de un bloc. n schimb ceea ce urmeaz dup modificatorii i numele unei
clase nu constituie un bloc, dei apar acoladele deschis i nchis: coninutul unei
clase nu este o succesiune de instruciuni.
Orice bloc poate conine la rndul su un alt bloc, putnd astfel lua natere
o structur imbricat de blocuri.

Prin variabil local nelegem o variabil declarat n interiorul unui bloc,


inclusiv ntr-o instruciune fo r .
Domeniul de vizibilitate al unei variabile locale este constituit din partea
din blocul n care a fost declarat, ce urmeaz declarrii. Prin urmare o variabil
local nu poate fi referit nainte de a fi declarat. Variabilele locale exist numai
pe perioada n care blocul n care sunt declarate este n curs de executare.
Nu putem folosi facilitatea de imbricare a blocurilor pentru a redeclara o
variabil local. O variabil local nu poate fi redefinit nici n blocul n care a fost
declarat, nici ntr-un bloc inclus n acesta.
Regulile care guverneaz domeniul de vizibilitate si etichetelor sunt
aceleai ca pentru variabilele locale.

@ Param etrii metodelor ! constructorilor


Numele parametrilor dintr-o metod sau dintr-un constructor sunt vizibile
doar In interiorul acestora, adic n blocul care urmeaz antetului metodei sau
constructorului. Este ns posibil ca ntr-un bloc dintr-o metod sau dintr-un
constructor s redeclarm numele unui parametru; n acest caz, n partea din bloc
ce urmeaz redeclarrii, numele respectiv este considerat ca avnd semnificaia
dat de redeclarare.
. Cu alte cuvinte, domeniul de vizibilitate al unui parametru este constituit
din corpul metodei sau constructorului n care apare, mai puin blocurile (evident
disjuncte) n care este redeclarat.

Vizibilitatea n Interiorul unei clase


tim c o clas este constituit din cmpuri, constructori (folosii la crearea
de obiecte) i metode (folosite la invocarea lor). Din orice constructor i din orice
metod putem s ne referim la orice cmp sau metod a clasei. De asemenea dintr-
un constructor putem apela alt constructor prin t h i s urmat, ntre paranteze, de o
list de argumente ce respect signatura noului constructor.
Ordinea n care apar cmpurile nestatice i metodele n cadrul clasei nu
este relevant (de exemplu nu conteaz dac un cmp nestatic este declarat la
nceputul sau la sfritul clasei).
Totui, dac numele unui cmp este redeclarat ntr-o metod (este folosit
ca nume al unui parametru sau declarat ntr-un bloc), atunci declararea cea mai
interioar este cea care primeaz cnd se face o referire la acel nume (identificator).
62 4. PACHETE. ACCES I VIZIBILITATE

Putem spune c un parametru poate ascunde un cmp, iar o variabil local poate
ascunde un parametru i/sau un cmp.
Dup cum vom vedea n continuare, numele unei metode nu poate fi
ascuns.

@ Modificatorul f i n a l

Modificatorul final poate fi ataat att variabilelor (locale sau cmpuri),


ct i metodelor.
n cazul variabilelor locale, variabilei i se atribuie valoare Ia declarare sau
nainte de a f folosit; variabila nu poate primi de dou ori valoare. Menionm c
final este singurul modificator ce poate fi ataat unei variabile locale.
Unui cmp final trebuie s i se atribuie valoare fie prin iniializare, fie prin
constructori. Cnd cmpul este static, exist posibilitatea de a i se atribui o valoare
printr-un bloc de iniializare static;

Exemplul 2. Urmtorul program:


class Clasa {
static final int x static { x=~l;}
public static void met{) {
IO.write(x);
final int x x=3 IO.writeln{" " + x);
}
}
public class temp {
public static void main (String!3 s) {
Clasa Ob = new ClasaU; Ob.met{};
}
}
produce la ieire valorile:
-1 3

Menionm c n general modificatorul final este folosit mpreun cu


static, pentru a trata un cmp ca o "constant cu nume'.
Efectul modificatorului final asupra metodelor i claselor va fi prezentat
atunci cnd vom vorbi despre extinderea claselor.

Modificatorul s t a t i c
Modificatorul static poate fi folosit la declararea cmpurilor i
metodelor unei clase, precum i pentru a anuna un bloc de iniializare static.
O variabil local nu poate fi declarat cu s t a t i c .
Fie c un cmp declarat cu etatio n clasa Clasa. Aceast declarare are
dou consecine:
4,2. Vizibilitate i acces 63

- cmpul c este comun tuturor obiectelor de tipul Clasa;


- referirea la cmp din exteriorul clasei se face fie conform regulii generale
(prin crearea i utilizarea unei instane a clasei c la sa ), fie direct, prin
precalificarea cmpului cu numele clasei (C la s a . c).
Dup cum s-a precizat anterior, iniializarea cmpurilor statice se face la
iniializarea clasei.
pie acum met o metod declarat cu modificatorul t a t i o n clasa
C lasa; ea se numete m eto d s ta tic sau m e to d d e clas. Invocarea ei se poate
face fie conform regulii generale (prin crearea i utilizarea unei instane a clasei
C lasa), fie direct, prin precalificarea metodei cu numele clasei:
C la sa.m e t ( . - . )
De aceea ntr-o metod static nu poate fi folosit referina thi.
O metod static poate accesa numai cmpurile i metodele statice ale
clasei din care face parte sau a altei clase. Metodele statice (de clas) sunt folosite
de obicei pentru a efectua prelucrri asupra cmpurilor statice ale clasei. Putem
Hocolif, Ins aceast regul de exemplu astfel:
- ia invocarea metodei i transmitem ca parametru o referin la un obiect;
- n metod construim explicit un obiect de tipui clasei la ale crei metode
l cmpuri dorim s ne referim.
Lucrul cu blocuri de iniializare statice a fost descris anterior.

Modificatorii de acces 0
Ne mrginim n acest paragraf ia o succint prezentare a acestor
modificatori. O discuie mai detaliat va fi fcut dup ce vom vorbi despre
extinderea claselor.
Toate cmpurile i metodele unei clase sunt accesibile (pot fi referite) din
interiorul clasei.
Rolul modificatorilor p u b lic , p r o te c te d , p r i v a t e i cel implicit
(numit uneori p a c k a g e ) referitor la accesul din exteriorul unei clase Ia membrii si
este sintetizat n urmtorul tabel:

M o d ific a to r M em b rii c la sei cu a c e st


m o d ific a to r su n t a c c e s ib ili ...
p u b lic de oriunde clasa este accesibil
p ro te c te d din cod din acelai pachet
implicit ( p a c k a g e ) din cod din acelai pachet
p riv a te numai din interiorul clasei

Reamintim c modificatorii de mai sus joac un rol nu numai n privina


accesului, dar i pentru facilitatea de extindere a claselor, ceea ce va face diferena
ntre modificatorul p r o t e c t e d i cel implicit.
64 4. PACHETE. ACCES I VIZIBILITATE

Determinarea semnifleaiei uimi mrnie


Pentru un identificator folosit ca nume de variabil (local sau cmp),
metod sau clas, semnificaia sa se obine la prima cutare ncununat de succes
din urmtorul ir de cutri succesive:
1) variabilele locale declarate ntr-un bloc sau un ciclu fo r ;
2) numai dac suntem n interiorul unei metode sau a unui constructor:
parametrii metodei sau constructorului;
3) membrii clasei, inclusiv cei rezultai prin extinderea claselor (vezi
capitolul urmtor)
4) tipuri importate explicit;
5) tipuri declarate n acelai pachet;
6) tipuri importate implicit;
7) pachete disponibile pe sistemul gazd.

Mai mult, se face distincie clar ntre tipurile de identificatori: nume de


variabile (locale), de pachete, de clase, de metode i de cmpuri; iat de ce numele
unei metode nestadce nu poate fi ascuns. Aceasta permite s folosim un acelai
identificator pentru a numi una sau mai multe astfel de entiti.

Exemplul J. Urmtoarea clas este corect din punct de vedere sintactic,


compilatorul nesemnalnd vreo eroare:
c l a s e obsesie {
obsesie obsesie;
obsesie() { obsesie - n@w obsesie(); }
o b s e s ie o b s e s ie ( o b s e s ie o b s e s ie ) {
o b s e s ie :
w h ile (o b s e s ie != n u l i )
i ( o b s e s i e .o b s e s i e ( o b s e s ie ) = = o b s e s ie ) b re a k o b s e s i e ;
r e t u r n o b s e s ie ;
}

Nu recomandm ns s abuzm n acest mod de distincia menionat.


Clasa de mai sus poate fi scris sub urmtoarea form mai clar i "neobsesiv":
c l & o b s e s ie {
obsesie C;
o b s e s i e () { C = new o b s e s i e ( ) }
obsesie met (obsesie param) {
et _
w M l (param != msll) { -
i ( param.met(param)==param > break et;
} 1

rO EXTINDEREA
CLASELO R

Aa cum am menionat de la nceput, limbajul Java a fost conceput ca un


limbaj orientat pe obiecte. Am prezentat deja una dintre caracteristicile orientrii
spre obiecte i anume ncapsularea (datele mpreun cu operaiile asupra lor sunt
f,puse la un loc'* i anume Intr-o clas).
Vom studia acum modul n care Java trateaz alte aspecte ale programrii
orientate pe obiecte: extinderea claselor, polimorfismul i legarea dinamic.

5.1. Cum se definesc clasele extinse


Limbajul Java pune la dispoziie i o alt facilitate important legat de
OOP (programarea orientat pe obiecte): posibilitatea de extindere a claselor.
Foarte pe scurt, deci incomplet i nu n ntregime riguros, aceasta const n:
- o clas poate fi extins, adugndu-se noi cmpuri i noi metode, care
permit considerarea unor atribute suplimentare (dac ne gndim la cmpuri) i unor
operaii noi (asupra cmpurilor "iniiale", dar i asupra cmpurilor nou adugate);
- unele metode ale clasei pe care o extindem pot fi redefinite, iar anumite
cmpuri ale acestei clase pot fi "ascunse";
- un obiect avnd ca tip clasa extins poate fi folosit oriunde este ateptat
un obiect al clasei care a fost extins.

La prima vedere, rezolvarea problemelor de mai sus se poate face simplu:


modificm clasa, introducnd sau/i modificnd cmpurile i metodele clasei. n
practica programrii, aceast soluie este de neconceput. Pe de o parte se pot
introduce erori, iar pe de alt parte utilizatorii clasei vechi nu vor mai putea folosi
clasa aa cum o fceau nainte i cum vor n continuare s o fac, nefiind interesai
de noile faciliti; clasa (firma care a elaborat-o) i va pierde astfel vechii clieni.
De aceea vechea clas trebuie s rmn nemodificat, iar actualizarea ei trebuie
fcut prin mecanismul de extindere a claselor, prezentat n continuare.
S reinem deci ca o regul general de programare faptul c nu trebuie
modificat o clas testat i deja folosit de muli utilizatori; cu alte cuvinte, nu
trebuie modificat "contractul" ce a dus la scrierea clasei.
66 5. EXTINDEREA CLASELOR

Exemplul 1. S presupunem c dorim s unnrim micarea unui punct n


plan. Vom ncepe prin a considera clasa:

c l a s s Punct {
i n t x , y ; Punct urm;
P u n c t ( in t x , i n t y) { t h i s . x = x t h i s .y= y; }
v o id O r i g i n e ( ) { x = 0 ; y - 0 }
Punct M i c a r e ( ia t x , i n t y) {
Punct p = new P u n c t ( x , y ) urm=p r e t u r n p
1
}
Clasa P unct conine:
- cmpurile x , y , urm;
- constructorul Punct cu signatura ( i n t , i n t ) ;
- metoda O r ig in e cu signatura () i metoda M ica re cu signatura
(In t, i n t ) ,

Vom extinde clasa Punct astfei nct punctul s aib i o culoare:

c l a s s P ix e l e x te n d s P unct {
String culoare;
P i x e l ( i n t x , i n t , S t r in g c u lo a r e ) {
s u p e r ( x , } t h i s . c u lo a r e = c u lo a r e ;
}
v o id O r i g i n e () { s u p e r . O r ig in e { ); c u lo a r e = " a lb " ; }
}
Clasa p i x e l conine:
- cmpurile x^y^urm { m o te n ite de la clasa P unct) i c u lo a r e (care a
fost adugat prin extindere);
- constructorul P ix e l cu signatura ( i n t , i n t , S t r i n g ) ;
- metoda M ica re cu signatura ( i n t , i n t ) , motenit de la clasa Punct,
precum i metoda O r ig in e cu signatura (5, care r e d e fin e te metoda O r ig in e a
clasei Punct.

Este adoptat urmtoarea terminologie: clasa P unct este s u p e r c la s a lui


P ix e l , iar P ix e l este s u b c la s (clas extins) a lui Punct.
n Java, clasele formeaz o structur de arbore n care rdcina este clasa
O b ject, a crei definiie apare n pachetul j a v a . lan g. Orice clas extinde direct
(implicit sau explicit) sau indirect clasa o b j e c t . tim c n informatic arborii
ncresc n jos", deci rdcina (clasa O b ject) se afl pe cel mai de sus nivel.
Termenii de superclas i subclas se refer exclusiv la relaia tat o fiu,
conform relaiei de extindere, n arborele de clase. E s te in c o r e c t d e a in te r p r e ta
a c e ti te r m e n i n s e n s u l d e in clu ziu n e l
n exemplul de mai sus, apelurile su p er .O r ig in e () i eu p er ( x , y ) se
refer respectiv la metoda O r ig in e i la constructorul din superclas Punct a lui
P ix e l. Vom reveni ns cu toate detaliile legate de su p er. . :
S.2. Din nou despre iniializare i constructori 67

Fie Sub o clas ce extinde clasa Super. Sunt importante urmtoarele


precizri:
- obiectele de tip Sub pot fi folosite oriunde este ateptat uti obiect de tipul
Super. De exemplu dac un parametru al unei metode este de tipul Super, putem
invoca acea metod cu un argument de tipul Sub;
-spunem c Sub extinde comportarea lui Super;
- o clas poate fi subclas a unei singure clase (motenire simpl) deoarece,
reamintim, clasele formeaz o structur de arbore. Drept consecin o clas nu
poate extinde dou clase, deci nu exist motenire multipl ca n alte limbaje
(exist ns mecanisme pentru a simula aceast facilitate i anume interfeele)',
- o metod din superclas poate fi rescris n subclas. Spunem c metoda
este redefmit (dac nu este static) sau ascuns (dac este static). Evident, ne
referim aici la o rescriere a metodei folosind aceeai signatur, pentru c dac
scriem n subclas o metod cu o signatur diferit de signaturile metodelor cu
aceiai nume din superclas, atunci va fi vorba de o metod nou. La rescriere nu
putem modifica tipul valorii ntoarse de metod. Accesul la metoda cu aceeai
signatur din superclas se face, dup cum vom vedea, prin precaiificare cu su p er;
-un cmp fedeclarat n Sub cmpul cu acelai rmme din Super;
- cmpurile neascunse i metodele nerescrise sunt automat motenite de
subclas (n exemplul de mai sus este vorba de cmpurile x i i de metoda
M icare);
, - apelurile super din constructorii subclasei trebuie s apar ca prim
aciune.

5.2. Din bou despre Iniializare i constructori


Relativ Ia blocurile de iniializare, adugm Ia cele deja tiute faptul c
nainte de iniializarea unei clase sunt iniializate superclasele ei, dac n-au fost
deja iniializate.

Exemplul 2. S considerm clasele:


qXabs S uper {
e t a t i o { IO.writeln{"BlocstaticSuper")}
}
a l a s Sub x t n d e S uper {
tmtio { IO.writeln(wBloc_static_Subw); }

La crearea unui obiect prin nw sub {) vor fi tiprite urmtoarele dou


rnduri:
B l o c _ s t a t ic S uper
Bloc_static_Sub (
68 5 . EXTINDEREA CLASELOR

Exemplul 3. n schimb programul:


clasa Super { static int i f 5; }
clasa Sub extends Super {
static { IO.writeln("Sub"); }
.,

Test {
public static void m a i n (String[] s) {
IO.writeln(Sub.i + ");

va tipri valoarea 5: clasa Sub nu este iniializat, deoarece se face referire la un


cmp declarat n clasa Super, deci nu este vorba de o utilizare activ a clasei Sub.

Suntem acum n msur s prezentm mai complet i aciunile ntreprinse


Ia crearea unui obiect.
Prima aciune const n a atribui cmpurilor valorile iniiale implicite:
0 - pentru tipuri numerice
\u 0 0 0 0 - pentru tipul char
fa ls e - pentru tipul boolean
n u li - pentru referine (Ia obiecte, inclusiv tablouri i s tr in g ).
n continuare este invocat constructorul corespunztor (determinat de
signatur, n aceiai mod ca pentru metode); aciunea sa cuprinde trei faze:
) Invocarea unui constructor al superclasei i anume:
~ explicit o i e e ) ;
- implicit: este vorba de constructorul fr argumente.
2) Executarea, n ordinea n care apar, a iniializrilor directe ale
cmpurilor;
3) Executarea corpului constructorului.

Observaii:
- un constructor poate invoca un alt constructor i anume prin t h is ( . . . ) ;
aceast invocare poate avea loc numai ca prim aciune a constructorului (deci nu
pot fi invocai doi constructori). n schimb acest mecanism nu poate fi folosit
pentru a invoca, din corpul unei metode, un constructor;
- un constructor poate invoca o metod, caz n care se consider
implementarea metodei corespunztoare tipului real al obiectului (vezi subcapitolul
urmtor).
- dac din constructorul P i x e l din Exemplul 1 am elimina invocarea
su p er ( x , y ) compilatorul ar semnala o eroare deoarece, conform mecanismului
descris mai sus, constructorul P i x e l va invoca implicit constructorul fr
argumente at superclasei, care ns nu exist (el exist implicit doar dac nu s-a
specificat un alt constructor).
5.2. Din nou despre iniializare i constructori 69

S considerm clasele:
c la s e a {
i n t va-1, v;
a() { v=va }
}
c l a s s b e x te n d s a {
i n t vb=2
b ( ) { v=va+vb; }
}

La crearea unui obiect de tipul b, prin new b ( ), au loc n ordine


urmtoarele aciuni:
- cmpurile v, va, vb primesc valoarea implicit 0;
- este invocat constructorul b;
- este invocat constructorul a (al superclasei);
am loc iniializarea dimct a lui va, care primete valoarea 1;
- este executat corpul constructorului a i ca urmare v primete valoarea 1;
are loc iniializarea direct a lui vb, care primete valoarea 2;
- este executat corpul constructorului b i ca urmare v primete valoarea 3.

Dac o clas este declarat cu modificatorul p u b lic , constructorul implicit


are automat acest modificator.
Constructorii unei clase nu sunt considerai membri ai clasei. De aceea ei
nu pot fi motenii sau redeclarai.
Constructorilor li se pot ataa modificatori de acces la fel ca metodelor
(vezi subcapitolele urmtoare). Dar spre deosebire de metode, un constructor nu
poate fi declarat cu ali modificatori dect cei de acces.
ntr-un constructor poate fi folosit instruciunea r e t u r n , dar nensoit de
o expresie.
Dac un constructor se invoc (direct sau indirect) pe ei nsui, la
compilare este semnalat o eroare.
!ntr-o invocare explicit a unui constructor, argumentele nu po fi
instanieri de cmpuri declarate n aceeai clas sau ntr~o superclas; de asemenea
nu este permis utilizarea lui t h i s i s u p e r n expresii.
Exemplificm n continuare acest aspect pentru cmpuri.
Exemplul 5. S considerm urmtoarea clas;
ol&ss C {
in t x; in t y
C() { t h i s ( x ) }
C ( in t x) { = x }
} ^
70 5 . E X T IN D E R E A C LA SE LO R

n clasa c, constructorul fr parametri invoc pe cel cu un parametru. Va


fi semnalat o eroare la compilare. n schimb clasa va fi corect dac de exemplu
cmpul x ar fi fost declarat cu modificatorul static.

5.3. Rescrierea metodelor i ascunderea cm purilor


Cmpurile pot fi a s c u n s e prin rededararea lor ntr-o subclas. Cmpul cu
acelai nume din superclas nu mai poate fi accesat direct prin numele su, dar ne
putem referi la el folosind super (vezi subcapitolul urmtor) sau o referin !a
tipul superclasei,

O metod declarat ntr-o clas poate fi rescris ntr-o subclas prin


declararea ei n subclas cu acelai nume, aceeai signatur i acelai tip al valorii
ntoarse.
n metoda rescris putem schimba modificatorul de acces, cu condiia ca
dreptul de acces s creasc; reamintim c modificatorii de acces, n ordine de ia cel
mai restrictiv la cel mai permisiv, sunt: private, protected, cel implicit
{p a c k a g e ) i public.

Spunem c metodele rescrise sunt a sc u n s e (dac e vorba de metode statice)


sau r e d e f m ite (n cazul metodelor nestatice). Nu este vorba numai de o diferen de
terminologie, deoarece metodele statice pot fi rescrise (ascunse) numai de metode
statice, iar metodele nestatice pot fi rescrise (redefmite) numai de metode nestatice.
Alte precizri vor fi fcute n continuare.

Fie A o clas i fie o subclas a sa. S considerm urmtoarele patru


aciuni echivalente din punctul de vedere al obiectului a ce ia natere:
1) A a; a = new (...)
2 ) = new ( . . . )
3) ; b; b = new (...) = ;
4) ; ; b = new ( . . . ) ; = () ;
S observm c este vorba de o conversie de ia o subclas la o superclas,
conversie numit u p c a stin g ; ea poate fi implicit (ca n primele trei aciuni) sau
explicit (ca n cea de a patra aciune).

Vom spune c obiectul a are tip u l d e c la r a t A i tip u l r e a l B, ceea ce pune n


eviden noiunea de p o lim o r fis m .
Tipul real al unui obiect coincide cu tipul su declarat (este cazul obiectului
b) sau este o subclas a tipului declarat (vezi obiectul a).

Fie camp un cmp al clasei A, ce este redeclarat (ascuns) n subclasa B.


Dac obiectul a face referire la cmpul cmp, atunci este vorba de cmpul declarat
n clasa A, adic este folosit tipul declarat al obiectului.
$ J r Rescrierea metodelor i ascunderea cmpurilor 71

Fie met o metod a clasei A, care este rescris n subclasa B. La invocarea


metodei met de ctre obiectul a, este folosit fie implementarea corespunztoare
metodei ascunse (dac este static), fie cea corespunztoare metodei redefmite
(dac este nestatic). Cu alte cuvinte, pentru metode statice este folosit tipul
declarat (la fel ca pentru cmpuri), iar pentru metode nestatice este folosit tipul real
obiectului. n ambele cazuri, se pleac de la tipul indicat mai sus i se merge n
sus spre rdcin (clasa O b je c t) n arborele de clase pn cnd se ajunge la primul
tip n care apare metoda respectiv (evident cu signatura corespunztoare);
inexistenta unui astfel de tip este semnalat chiar n faza de compilare.

Exemplul 6. Urmtorul program;


o la e e Super {
fcfcic w i d metl () { IO. writeln (*'staticSuper")}
Yid met2() { 0.writeln("Super")}
)
e lftse Sub Super {
i static void m e t l O { IO,writeln{'^tatic^Sub'1) ; }
v o id m e t2 {) { I O . w r i t e l n ( HSub" ) ; }

e la s s T e s tl {
p u b lic s t a t i c void main(String ) {
Super Ob = n#w Sub()Ob.metl(}0b.met2()
)
)
produce Ea ieire:
Btatlc^Super
Sub

Exemplul 7. Considerm o nou form a claselor din Exemplul 2:


01 A {
i u t v a = l, v
A() { v = v a IO .w r it e ( Hn+met { )) ; }
in t m e t () { return v a }

@1 @3t A {
; 1 vb-2, v
B{) { v=va+vb; }
in t met O { return v b }

clase C o n str {
p u b lic t t i c v o id main ( S t r i n g [ ] s) {
A a = a@w () ;
0 .writeln (\t"+a.met ()};
72 5. EXTINDEREA CLASELOR

Rezultatele tiprite de programul de mai sus sunt 0 i 2, deoarece:


- la invocarea metodei met din cadrul constructorului clasei A este folosit
tipul real al obiectului, adic este ntors rezultatul furnizat de metoda met
redeclarat n Bla momentul invocrii, valoarea curent a lui vb este 0 (vezi
subcapitolul precedent).
- invocarea metodei met n metoda principal, realizat de obiectul a, se va
referi tot la metoda met din clasa .
Dac ns n clasa am nlocui declararea nt v b =2 a lui vb prin:
static int v b = l
static { vb=2 }
atunci Ia ieire vor aprea numerele 2 i 2.

E x e m p lu l 8 . S considerm urmtorul program:

class A {
S t r in g s= " S u p er" ;
void scrie{) { IO.writeln{nA H+s) }
}
class A {
S t r in g s = MSub";
void s c r i e () { I O . w r i t e l n ( MB *+s) }
}
class AB1 {
public static void m a in ( S t r in g [] s) {
b = new ( ) ; A a = b;
a .scrie()b.scrie() '
10.writeln(a.s + "\t" + b .s )
}

La executare sunt tiprite urmtoarele:


: Sub
: Sub
Super Sub
adic rezultatele ateptate, innd cont c:
- pentru obiectul b: tipul declarat coincide cu cel real i este
- pentru obiectul a: tipul declarat este Af iar tipul real este B.

S considerm o clas c i dou subclase x i y ale sale, precum i


urmtoarea secven de instruciuni;
C Oh;
Ob :- now X (.
Oh == new (.
Ob == nmw Y (.
5.4. Cuvtu cheie su p er 73

n care b are mai nti tipul real x, apoi tipul real C, apoi tipul real Y. Spunem c
Ob este o variabil polimorflc, deoarece are pe rnd forma (comportamentul) a
mai multor clase.
Din exemplul de mai sus rezult clar c doar ia momentul executrii putem
determina necesarul de memorie pentru obiectul Ob, ceea ce justific de ce Ia
creare obiectele sunt "stocate" n heap-ul memoriei. Mai precis, la crearea unui
obiect este alocat spaiu pentru toate cmpurile nestatice din clas, inclusiv pentru
cele ascunse.

5.4. Cuvntul cheie su p er

Putem folosi cuvntul cheie s u p e r n orice metod nestatic a unei clase


extinse, i anume sub una dintre formele:
- s u p e r (. . .) : pentru a invoca un constructor al superclasei clasei
curente;
- s u p e r .m et ( . . . ) : pentru a invoca o metod a superclasei, metod ce a
fost redefinit n clasa curent;
- s u p e r . c : pentru a accesa un cmp c al superclasei, cmp ce a fost
ascuns n clasa curent prin redefmirea sa.
Observm c la accesarea unui cmp sau a unei metode, s u p e r acioneaz
ca referin la obiectul curent ca instaniere a superclasei sale.

Exemplul 9. Programul urmtor:


c la s s A {
S tr in g s = " S u p e r "
void scrie() { IO.writeln("A "+s); }
void metoda() { IO.writeln("A:tt); }

class extends A {
String s="Sub";
void scrie() { IO.writeln("B "+s+" "+supr.s};)
v o id metoda() { scrie( ) ; s u p e r . scrie( ) ; s u p e r . metoda(}
}
class AB2 {
p u b l i c s t a t i c v o id m a i n ( S t r i n g ! ] x) {
b = new {); b.metoda(); lO.writeln(b.s);
IO.writeln (* * * * * * * * * * * * * * * * * ' )
A a; a = b; a .m e to d a {) l O . w r i t e l n ( a . s ) ;
1 0 w iri t I n ("*** * * *}
A c = new A(); c .metoda{}IO.writeln{c.s)

produce la ieire urmtorul rezultat:


74 5. EXTINDEREA CLASELOR

: Sub Super
A : Super '
A:
Sub
* * **** ****
Sub Super
A : Super
A:
Super

A:
Super

Sunt incorecte, nencadrndu-se n formele prezentate mai sus de folosire a


lui s u p e r, construcii de forma b. s u p e r .m etoda ( (care ar inteniona ca pentru
obiectul b s invocm metoda m etoda din superclasa clasei de tipul creia este)
sau urcarea mai multor niveluri n arborele de clase prin sup er. super. Pentru a
avea acces a un cmp ascuns aflat cu dou niveluri mai sus n arborele de clase
putem proceda de pild ca n exemplul urmtor.
E x e m p lu l 10. Executarea programului:

class A {
int x=l;
void met() { 10.w rite("\t"+x) ; }
}
class extends A {
boolean x^false;
void met() { 10.write{"\t"+x) super.met() }
}
class C extends {
double x=3.14;
void met() { 10.write("\t"+x) super.met() }
}
class SubSup {
public static void main (String[} s) {
C Ob = new C {}; Ob.met(};
}
}
produce la ieire:
3 .14 false 1

5.5. Motenire, polimorfism i legare dinamic


Reamintim urmtoarele:
SJ. Motenire, polimorfism i legare dinamic 75

- orice obiect care instaniaz o clas poate fi folosit n orice cod menit s
lucreze cu instanieri ale superclaselor sale;
- orice obiect care instaniaz o clas poate folosi (n modurile descrise mai
sus) codul supraclasei.

La aceste dou caracteristici legate de motenire (extinderea claselor), Java


adaug polimorfismul i legarea dinamic, ntre care exist o strns relaie.
Polimorfismul const n posibilitatea ca o invocare Ob.met ( . . . ) s aib
drept consecin invocarea unei anumite metode cu numele met, n funcie de tipul
real al obiectului b. Unii autori consider c i cele dou faciliti enunate mai
sus fac parte din conceptul de polimorfism.
Legarea dinamic identific metoda met respectiv la executarea
programului. Polimorfismul i legarea dinamic sunt dou caracteristici eseniale
ale programrii orientate pe obiecte i vor fi analizate n acest subcapitol.

Aa cum am precizat n subcapitolul precedent, fiecare obiect are un tip


declarat i un tip real; tipul real coincide cu cel declarat sau este un subtip al
acestuia. La invocarea metodelor nestatice se folosete tipul real, iar Ia invocarea
metodelor statice i la referirea cmpurilor se folosete tipul declarat.
Menionm c n literatura consacrat programrii orientate pe obiecte nu
este agreat opiunea Java de a folosi pentru cmpuri tipul declarat i nu pe cei real.
Pentru metode nestatice se folosete tipul real ai obiectelor care le invoc
deoarece:
- cronologic, superclasa a fost scris naintea clasei i este de presupus c a
fost folosit de mai muli utilizatori, care vor n continuare s lucreze cu ea;
- n metodele noii clase se pot face referiri la cmpuri nou definite, ceea ce
nu este posibil pentru metodele superclasei.
Utilizarea tipului declarat pentru metodele statice se datoreaz urmtorului
fapt: compilatorul "face tot ce poate" pentru a detecta metoda ce trebuie invocat.

Java folosete legarea dinamic, adic identificarea metodei nestatice


concrete care este folosit la o invocare se face Ia executare i nu la compilare. De
aceea legarea dinamic se mai numete legare trzie.
Necesitatea legrii dinamice apare din urmtorul exemplu:

Exemplul L Fie A o clas n care este definit o metod met, iar o


subclas a sa n care metoda met este redefmit. Secvena de instruciuni:
double d = IO.read(); A Ob;
i (d>0) Ob = new A (...)
lee Ob = new (...);
Ob. met ( . . . ) ;

arat c doar la momentul invocrii metodei devine clar care dintre cele dou
metode met va fi invocat.
76 5 . EXTINDEREA CLASELOR

S. Din noii despre modificatori


Relum discuia despre modificatori, pentru a include i aspectele legate de
extinderea claselor.

Lista complet a modificatorilor folosii n Java este urmtoarea:


- modificatorii de acces (public, protected, private i cel implicit);
- abstract, static, final, synchronized, native, transient,
volatile.
Ei pot fi foiosii astfei:
- pentru clase: public i cel implicit, abetract, final;
- pentru interfee: modificatorii de acces;
pentru constructori: modificatorii de acces;
- pentru cmpuri: modificatorii de acces, final, static, traaeient,
volatile;
- pentru metode: modificatorii de acces, final, static, abstract,
synchronized, native.

Despre modificatorul a b s t r a c t vom vorbi n subcapitolul urmtor.


Despre interfee, ca i despre unii dintre modificatorii t r a n s i e n t ,
volatile, synchronized i native, vom vorbi n capitolele care urmeaz.
Modificatorul f i n a l poate fi asociat (n afara variabilelor locale i
cmpurilor) i metodelor i claselor. EI trebuie neles n sensul de "variant
final":
- o metod cu acest modificator nu poate fi rescris ntr-o subclas;
- o clas cu acest modificator nu poate fi extins.
Metodele declarate cu private sau/i static sunt echivalente cu f i n a l ,
din punctul de vedere al redefinirii: nu pot fi redefinite*
Dac o metod este final, "ne putem baza" pe implementarea ei
(bineneles dac nu invoc metode nefmae). n unele situaii, este bine s marcm
toate metodele cu final, dar nu i clasa.

Precizri asupra noiunii de membru al unei entiti


Membrii unui pachet sunt clasele ce intr n componena sa.

Membrii unei clase sunt:


- cei declarai n corpul clasei;
- cei motenii de la superclass sa direct (doar clasa O b je c t nu are o
superclas);
- cei motenii de la superinterfeele directe ale clasei.
5,6 Din nou despre modificatori 77

Membrii unui tablou sunt:


- cei motenii de la superclasa implicit O b jec t;
- cmpul le n g th , care este un cmp constant (are implicit modificatorii
public i final) al fiecrui tablou; tipul su este int, iar cmpul memoreaz
numrul de componente ale tabloului.

Membrii unei interfee (despre interfee vom vorbi n capitolul urmtor)


sunt:
- membrii declarai n corpul interfeei;
- membrii motenii de la orice superinterfa direct.

n discuia anterioar din capitolul 3 asupra vizibilitii, Ia determinarea


semnificaiei unui identificator, am rmas datori cu explicarea celei de a treia
.cutri; ea are n vedere luarea n consideraie a membrilor clasei, deci i a
membrilor motenii de Ia superclase.

: Despre modiflcatorii de acces


\
\ Referitor la modificatorii de acces, elementele noi ce intervin la extinderea
claselor se refer la motenirea lor n subclase.
i Accentum faptul c accesul este diferit de domeniul de vizibilitate.
Accesul se refer la poriunea din cod din care o entitate poate fi referit, pe cnd
domeniul de vizibilitate reprezint poriunea din cod n care o entitate declarat
poate f referit i recunoscut ca avnd tipul declarat respectiv.
Descriem n continuare influena modificatorilor.I.

I. Accesibilitatea unui pachet este determinat de sistemul de operare gazd.


II.Dac o clas sau interfa este declarat cu public, atunci ea poate f accesat
din orice cod ce poate accesa pachetul n care este declarat. In caz contrar (dac
nu apare modificatorul public), ea poate fi accesat doar din pachetul n care ea
este declarat.
III.Un membru (cmp sau metod) al unui tip referin (clas, tablou sau interfa)
ca i un constructor al unei clase este accesibil numai dac tipul referin este
accesibil i membrul sau constructorul permite (prin modificatorii si) accesul.
Acest al doilea aspect poate fi detaliat astfel:
.1. Dac membrul sau constructorul este declarat cu public, accesul este
permis. Membrii interfeelor sunt implicit declarai cu public.
Vi IIL2* Dac membrul sau constructorul este declarat cu prot@et@d, accesul
. este permis numai din:
II1.2.1. pachetul ce conine clasa n care entitatea respectiv este declarat
sau
.2.2. o subclas a clasei n care entitatea respectiv este declarat (a se
i: vedea i precizrile ce urmeaz).
78 5 . EXTINDEREA CLASELOR

111.3. Dac membrul sau constructorul nu este declarat, deci are modificatorul
implicit, accesul este permis numai din pachetul n care entitatea respectiv
este declarat,
111.4. Dac membrul sau constructorul n care entitatea respectiv este
declarat cu p r i v a t e , accesul este permis doar din interiorul clasei n care
entitatea respectiv este declarat,

Membrii unei clase sunt motenii astfel:


- n subclase, dac au modificatorul p u b l i c sau pe cel implicit;
- n subclase din acelai pachet, dac au modificatorul implicit;
- nu sunt motenii, dac au modificatorul private.

Cele de mai sus sunt sintetizate n urmtorul tabel:

Modificator Membrii clasei cu acest Membrii clasei cu acest


modificator sunt accesibili... modificator ...
p u b lic de oriunde clasa este accesibil sunt motenii n subclase
p ro te c te d din cod din acelai pachet i din sunt motenii n subclase
subclasele clasei respective
Implicit din cod din acelai pachet sunt motenii numai n
{package) subclase din acelai pachet
p riv a te numai din interiorul clasei nu sunt motenii n subclase

Precizm efectul lui p r o te c te d : un membru declarat cu protected


poate fi accesat dintr-o clas numai prin intermediul unor obiecte al cror tip este
un descendent al clasei n arborele de clase. S considerm urmtorul subarbore de
clase:
A

D
Presupunem c n clasa A apare un cmp x declarat cu protected. S
presupunem c din facem o referire la acest cmp prin c .x , unde c este un obiect
de tipul C. Aceast referire nu este permis (exceptnd cazul n care clasele i C
apar n acelai pachet) deoarece ieim din subarborele din care se face referirea.
Restricia de mai sus nu mai funcioneaz pentru membrii declarai cu
p r o t e c t e d , dar i cu s t a t i c : orice metod din , C, D poate accesa cmpul x
prin referine avnd oricare dintre tipurile , , C, D. 1

i constructorilor le putem ataa modificatori de acces. Un caz limit este I


cel n care ntr-o clas C exist cel puin un constructor i toi constructorii sunt
declarai cu p r i v a t e . n acest caz nu putem construi direct din afara clasei un
5.6. Din nou despre modificatori 79

obiect avnd ca tip aceast clas. Astfel de clase sunt folosite de obicei pentru a
Htca" metode i cmpuri statice, un exemplu fiind clasa System. Dar aceasta nu
nseamn c nu putem folosi o construcie indirect: din afara clasei putem invoca
de exemplu o metod static a lui C ce construiete un obiect de tipul C i l
ntoarce ca rezultat:
class C {
private C () {}
static C met () { return new ; }
void scrie() { IO.writeln"O.K.")}

Ol&ee Constrf {
public static void main (Stringt] s) {
C Ob = C.metO; Ob.scrieO;
/L METODE I CLASE ABSTRACTE
0 INTERFEE. CLASE INTERNE .

6.1. Metode i clase abstracte


Se ntmpl frecvent ca atunci cnd lucrm cu clase extinse, pentru o clas
s nu putem preciza implementarea unei metode, deoarece n subclasele sale ea va
fi specific fiecreia dintre ele. Atunci metodele din aceast categorie vor fi
marcate cu cuvntul cheie abstract i se vor reduce la antetul lor; n acelai timp
i clasa trebuie nsoit de atributul abstract. Fiecare metod abstract trebuie
implementat, adic (re)definit n orice subclas care nu este la rndul su
abstract.
Nu este posibil s crem obiecte ca instane ale unei clase abstracte. Pe de
alt parte, ntr-o subclas putem s redefinim o metod a superclasei transformnd-
o ntr-o metod abstract; aceasta are sens de exemplu dac n subarborele avnd
ca rdcin subclasa, comportamentul materializat prin acea clas nu mai este
valabil n subarbore i este specific fiecrei extensii a subclasei.

Exemplul 1. Urmtoarea clas are ca scop s msoare timpul necesitat de


executarea unei metode oarecare fr parametri i care nu ntoarce vreun rezultat:
abstract olaes C {
abstract void met();
public long timp() {
long tO = System.currentTimeMillis{);
met();
return System.currentTimeMillis() -tO;
}
}
unde a fost folosit metoda static currentTimeMillis () a clasei System,
metod care ntoarce timpul curent n milisecunde. ntr-o clas ce extinde c, se
poate redefini metoda met i apoi, folosind un obiect ce este o instaniere a noii
clase, putem apela metoda timp pentru a determina timpul de executare a metodei
met, ce are acum o implementare precis:
6.2. Noiunea de interfa 81

class Cl extends C {
void met () {
int x-0
for (int i = 0 ; i < 1 0 0 0 0 0 0 ; i++) x = x + l~ l;

clase Abstr {
public static void main{String[3 s) {
Cl Ob = new Cl();
IO.writeln "durata"+0b.timp());

Legat de exemplul de mai sus, nu trebuie s ne mire c e posibil ca la


executri diferite s obinem timpi diferii: aceasta este o consecin a faptului c
pe perioada executrii programului nostru sistemul gazd "mai face i altceva", sau
C a intervenit colectorul de reziduuri.

6.2. Noiunea de interfa


Aa cum s-a menionat anterior, este posibil s declarm clase abstracte n
care toate metodele sunt abstracte. Acest lucru poate fi realizat i prin intermediul
interfeelor. n plus, aa cum vom vedea n continuare, e!e reprezint mecanismul
propus de Java pentru tratarea problemelor ridicate de motenirea multipl.
Motenirea multipl este facilitatea oferit de unele limbaje de programare
ca o clas s moteneasc (prin extindere) membri ai mai multor ciase. Evident,
aceast caracteristic important a programrii orientate pe obiecte nu este neglijat
n Java. Modul n care aceast facilitate poate fi implementat n Java va fitratat n
continuare.

Interfeele reprezint o modalitate de a declara un tip constnd numai din


constante i din metode abstracte. Ca sintax, o interfa este asemntoare unei
clase, cu deosebire c n loc de c l a s s trebuie precizat i n t e r f a c e , iar metodeie
nu au corp, acesta fiind nlocuit cu ' '.
Putem spune c interfeele reprezint numai proiecte, pe cnd clasele sunt
o combinaie de proiecte i implementri.
Ca i n cazul claselor abstracte, este evident c nu pot fi create obiecte de
tipul unei interfee.
Cmpurile unei interfee au n mod implicit modificatorii static i
f i n a l , deci sunt constante.
Metodele interfeelor sunt totdeauna publice i au n mod implicit
modificatorul abstract. n plus ele nu pot fi statice, deoarece fiind abstracte, nu
pot fi specifice claselor.
B2 6. METODE l CLASE ABSTRACTE. INTERFEE. CLASE INTERNE

Orice interfa este gndit pentru a fi ulterior im p le m e n ta t de o clas, n


care metodele interfeei s fie redefinite,'adic s fie specificate aciunile ce trebuie
ntreprinse. Faptul c o clas c implementeaz o interfa I trebuie specificat prin
inserarea informaiei im p le m e n t I n antetul clasei,

Exemplul 2. Prezentm un prim exemplu de implementare a unei interfee.


interface I {
char c=,a ,int i=0
void scrie();
}
class C implements I {
public v o id scrie () { XO.writeln (c+" " -fi} }
}

Precizm urmtoarele:
- o interfa poate extinde oricte interfee. In acest mod interfeele permit
motenirea unor Hcontracten (numele i signaturile unor metode) ftr motenirea
implementrii;
- dac o clas implementeaz doar unele din metodele unei interfee, atunci
ea trebuie deciara cu a b s tr a c t;
spre deosebire de interfee (care sunt limitate la constante i anunuri de
metode), clasele abstracte pot avea implementri pariale, metode statice, membri
cu modificatorul protected, cmpuri care nu sunt finale etc.;
- o clas poate implementa oricte interfee, dar poate extinde o singur
clas.
Dac o clas extinde o alt clas i implementeaz una sau mai multe
interfee, atunci trebuie anunat nti extinderea i apoi implementarea, ca n
exemplul urmtor:
class C extends iuqplLements 1 ,1 2 ,1 3 ;

Aa cum vom vedea n continuare, facilitatea ca interfeele i clasele s


poat extinde oricte interfee reprezint modalitatea prin care Java rezolv
problema motenirii multiple.
Dac s-ar permite ca o clas s extind mai multe clase, ar aprea
neclariti legate de semnificaia numelor. Astfei, dac ar fi posibil urmtoarea
structur de clase extinse:
w

z
i n clasele w, x i Y ar fi definit (respectiv redefmit) un cmp c, atunci pentru un
obiect b de tipul Z semnificaia lui . c ar fi neclar.
6 J, Extinderea interfeelor 83

Faptul c n Java o clas poate extinde cel mult o clas nu rezolv ns


automat problema conflictelor de nume, problem care va fi tratat n continuare.

Suntem acum n msur s completm discuia despre supertipuri i


suhtipuri.
Supertipurile unei clase sunt clasa pe care o extinde, interfeele pe care le
implementeaz, precum i supertipurile acestei clase i acestor interfee. Drept
urmare o referin la un obiect de tipul clasei poate fi folosit oriunde este ateptat
un obiect al oricrui supertip al su (vezi i discuia despre upcasting din capitolul
referitor la extinderea claselor).
r Mai menionm c putem declara variabile avnd ca tip numele unei
interfee. Unei astfel de variabile i poate fi atribuit un obiect care implementeaz
interfaa (are ca tip reai o clas ce implementeaz interfaa).
Un exemplu ce ilustreaz aceste elemente va fi prezentat n paragraful
destinat implementrii interfeelor.

6.3. Extinderea interfeelor

Ca i clasele, interfeele pot fi extinse. O interfa poate extinde oricte


interfee, n acest mod adugndu-se la x noi constante i (anunuri de) metode.
Este permis ca o interfa ce extinde alt interfa s conin o constant cu
acelai nume. De exemplu pentru urmtoarea structur de interfee;
w

X Y

/ ,
z
este posibil ca n una sau mai multe dintre interfee s fie declarat o constant c.
Deosebim dou cazuri:
1) Constanta c este redeclarat n interfaa Z : o referire la c constituie o
referire la constanta c din z. Putem face ns referire i la constantele din celelalte
interfee prin x . c, Y. c i W. c. '
2) Constanta c nu este redeclarat n interfaa z : o referire la c este corect
dac exist un unic drum de interfee ce "coboar" n z, drum n care c poate fi
declarat de mai multe ori; n acest caz referirea are ca obiect cea mai ^recent"
declarare a cmpului, adic cea din interfaa cea mai apropiat de z. Dac c este
declarat pe mai multe drumuri de interfee ce "coboar** n z, compilatorul va
semnala c este vorba de o referire ambigu. Dac n z constanta c nu poate fi
regsit pe nici un drum de interfee ce ajunge n z, atunci va fi semnalat din nou
eroare.
84 6. METODE I CLASE ABSTRACTE. INTERFEE. CLASE INTERNE

Rmnnd ia structura de interfee de mai sus, s presupunem acum c n X


i n Y (sau n supertipuri ale lor) apare o metod cu acelai nume. Deosebim
situaiile:
1) dac metodele au signaturi diferite, vor fi motenite ambele metode;
2) dac metodele au aceeai signatur i aceiai tip pentru valoarea
ntoars, va fi motenit o singur metod;
3) dac metodele au aceeai signatur, dar tipurile valorilor ntoarse difer,
atunci motenirea nu va fi posibii (eroare de compilare).

Este posibil ca de exemplu n X i n Z (sau, mai general, ntr-un drum de


interfee extinse) s anunm cte o metod cu acelai nume i aceeai signatur.
Atunci o clas care implementeaz interfaa z va implementa ambele metode.

Exemplul 3, Programul urmtor:


interface W { char c = 'a '; }
i n t e r f a c e X _xtzui V7 { i n t c = l ; v o id met ) ; }
i n t e r f a c e Y { b o o le a n c = tr u e ; }
interface 2 extends X , { int c=99; void m e t ( ) ; }

cl& C iiaplemat {
public void met () { IO.writeln(++++++) }
}
class D iznplmente 2 {
public void met () { IO.writeln(******") }
}
class I n t e r f e e i ixnplomonte Z {
public void m e t () { }
public static void main (S t r i n g [] s) {
C Obi new ; .m et ( ) ;
D 0b2 = new D ? 0b2 .m et ( ) ;
int c=-88; // met();
I O . w r i t e l n ( c + n "+W.C+" "+.+ "+Y.C+ "+Z_c );

produce ia ieire:
+++++
*****
-88 a 1 true -99

Se impun urmtoarele observaii:


1) In clasele C i D, redefmirea metodei met s-a fcut cu pr
modificatorului p u b lic . Acest lucru este obligatoriu, pentru c atfe! ar fi fost
folosit modificatorul implicit, dar o redeflnire nu poate fi mai restrictiv n privina
drepturilor de acces;
6.4, Implementarea interfeelor 85

2) Din metoda principal nu putem invoca implementarea lui me


I n t e r f e e i , deoarece o metod static poate accesa numai cmpurile i metodele
statice ale clasei; pe de alt parte ns, o metod anunat ntr-o interfa nu poate
fi redefinit printr-o metod static, deci nu putem preciza atributul s t a t i c pentru
metoda m et din I n t e r f e e i .

6.4. Im piem entarea interfeelor


n subcapitolul de fa prezentm modul n care sunt rezolvate conflictele
de nume ce pot aprea la implementarea interfeelor.
Fie C o clas care implementeaz una sau mai multe interfee i extinde
eventual o clas.

Presupunem mai nti c n unul sau mai multe dintre aceste tipuri apare un
cmp (constant n cazul interfeelor) cu acelai nume c. Atunci discuia este
analoag cu cea referitoare Ia extinderea interfeelor, cu urmtoarea adugire: dac
c este declarat att n Z, ct i n clasa pe care o extinde, va trebui s specificm
s u p e r. c pentru cmpul din superclas.

Trecem acum la cazul metodelor. Motenirea metodelor interfeelor are Ioc


n modul descris ia extinderea interfeelor. Drept urmare, toate metodele motenite
din interfee trebuie implementate.
Dac o metod cu acelai nume i aceeai signatur apare n supercias i
n interfeele implementate, atunci:
- dac precizm n C o implementare a metodei, ea va constitui o redefmire
a metodei din superclas; la aceasta din urm putem face ns apel prin su p e r;
- dac n c nu este precizat o implementare a metodei, atunci metoda
(motenit) din superclas constituie implementarea metodei din interfee, cu
condifia ca ea s aib modificatorul p u b lic .

Exemplul 4. Programul urmtor:


in te rfa c e A {
i n t x = l v o id s c r i e ( )
}
in te rfa c e {
i n t x=2 v o id s c r i e (};
}
class C {
i n t x=3;
p u b lic v o id s c r i e {) {
IO*write(A.;x:+" +. ,
86 6. METODE l CLASE ABSTRACTE. INTERFEE. CLASE INTERNE j

class D extends C iroplements , {


int x=4 4
}
class Interfete2 {
public static void m a i n ( S t r i n g [] w) {
D Ob = n e w D { ) O b . s c r i e ( ) ; I O . w r i t e l n { " " - f O b . x )
A b l = n e w D () O b l . s c r i e ) 0 . w r i t e l n (_' " + 0 . x )
}
}
produce la ieire:
12 3 4
12 3 1

Sunt necesare explicaii doar referitor la obiectul O b l . El are tipul declarat


A i tipul real D, ceea ce face ca invocarea metodei s c r i e prin intermediul acestui
obiect s se refere la metoda s c r i e din clasa C iar referina O b l . x s se adreseze
constantei x din interfaa A.

6.5, Iniializarea interfeelor


Cum cmpurile unei interfee sunt statice, este important ordinea n care
ele sunt declarate, aa cum am atras atenia la iniializarea claselor.
Iniializarea unei interfee nu implic iniializarea superinterfeelor sale.
Exemplul care urmeaz face mai clar acest aspect.

Exemplul 5 . Urmtorul program:


interface X {
int x = 1, xx = Initinter.out("xx",2)
}
interface Y extends X {
int = Initlnter.out(rty",3), yy = Initinter.out{"yy",4);
}
interface Z extends Y {
int z ~ Initlnter.out ("z 5);
}
clase Initlnter {
public static void main{String[3 s) {
XO.writeln{Y,x + !t "} IO.writeln (Z .y -f H H)

static int out(String s, int i) {


0.writeln(s + ' i) ; return i;
}
6,6. Rezolvarea n Java a problemei motenirii multiple 87

produce la ieire;
1
3 ;
K 4
3
din urmtoarele motive:
- y.x din metoda principal este o referire la un cmp constant, deci nu
conduce la iniializarea interfeei x
-z .y din metoda principal este o referire ia un cmp neconstan declarat
n Y i ca urmare aceast interfa este iniializat. Aceasta nu conduce ns la
iniializarea superinterfeei x. De asemenea nici interfaa z nu este iniializat, dei
numele ai apare n referirea z .y.

6.6. Rezolvarea n Java a problemei motenirii multiple

S presupunem c plecnd de la clasele Cl, C 2 , , cn dorim s


construim o nou clas care s moteneasc unele dintre metodele lor. Java permite
doar motenire simpl, deci va fi necesar s apelm la interfee.
Modalitatea de rezolvare a problemei motenirii multiple pe care o
prezentm n continuare este independent de numrul de clase motenite. Vom
folosi urmtoarea structur de interfee i clase:
II 12 In

n aceast structur clasele Cl, C2, Cn implementeaz respectiv


metodele anunate n interfeele l , 1 2 , , i n, iar clasa c implementeaz toate
interfeele XI, 12, . . , rn. Este suficient s prezentm modul n care clasa c
motenete implementrile din CI ale metodelor anunate n l, lucrurile
decurgnd analog pentru celelalte interfee i clase pe care le implementeaz. De
aceea n c o n t in u a r e v o m p r e s u p u n e c C tr e b u i e s e x ti n d d o a r c l a s a CI; evident
presupunerea este fcut doar pentru o prezentare mai concis, deoarece pentru
extinderea unei singure clase nu apare necesitatea folosirii interfeelor.
n clasa C vom declara i crea un obiect Obl de tipul c i (se presupune c
n clasa C se tie ce implementare a interfeei I I trebuie folosit). Atunci pentru
fiecare metod met implementat de CI introducem n clasa c metoda met cu
aceeai signatur i avnd una dintre formele:
tip met (. . .) { r e tu r n Obl .m et ( . . . ) ; }
void m e t (...) { O b l . m e t (...);)
dup cum metoda ntoarce sau nu o valoare.
88 6. METODE I CLASE ABSTRACTE. INTERFEE. CLASE INTERNE

Exemplul 6. Programul urmtor:


interface X {
w id xl ( ) ;
int x2 ()?
}
cl& CX lxnplments {
public void xl() { 10.write("xl ); }
public int x2 ( { return 1; }

s C ixnplttmazitB {
X ObX= a@w CX(); I I Clasa C "stiee ca trebuie sa foloseasc
I I implementarea CX a interfeei X
public void xl() { ObX.xl (} }
public int x2() { return ObX.x2 () }

clase Muli {
public static void main (String[] a) {
ObC = new ;
.) ; IO.writeln(
, +0.2
}

produce la ieire :
xl 1

S reamintim ns c putem declara variabile avnd ca tip numele unei


interfee i putem atribui unei astfel de variabile un obiect care implementeaz
interfaa. Aceast facilitate permite o mai mare libertate de aciune. Astfel, n
exemplul de mai sus nu mai este necesar ca C s tie care este clasa ce
implementeaz pe l, d poate afla acest lucru prin intermediul unui constructor; cu
alte cuvinte, la crearea unei instanieri a lui c, putem preciza ce implementare a lui
l s foloseasc. Mai mult, pentru redefnirea unor metode diferite ale aceleai
interfee, putem folosi implementri diferite.
Aceste aspecte sunt ilustrate n Exemplul 7 de mai jos, n care interfaa x
este implementat de clasele CX1 i CX2, dar i de clasa C ale crei metode folosesc
acelai mecanism: invoc n fapt metodele cu acelai nume ale claselor c x i i GX2
prin instanieri ale acestora.

Exemplul 7. n urma executrii programului:


interface X {
void xl ()
int x2();
6.7. don area obiectelor 89

class CXI implements X {


public void x l () { 1 0 . w r i t e ( 1 w); }
public int x2() { return 1; }

class CX2 ixnplemonts X {


public void x l () { 1 0 . w r i t e ( 2 " ) ; }
public int x2() { return 2; }

class C implements X {
X 0 b l( 0b2;
C(X Obi, X 0b2) { this.Obi=0bl; this.Ob2=Ob2;}
public void xl{) { Obl.xlO; }
public int x2() { return 0b2.x2(); }

class Mult2 {
public static void main (String[] s) {
X Obi = nw CXI(); X 0b2 = new CX2();
= new (0 ,0b2};
ObC.xl () ; lO.writet" '*+0bC.x2 ())
}

se obine la ieire:
xl 2

Dac ns am nlocui a doua linie din metoda principal cu:


X Obl = new CX2(); X 0b2 = new CX1();
la ieire s-ar obine:
x2 1 (

S remarcm c n metodele x l i x2 ale clasei C nu apare nici un indiciu


asupra tipului real al obiectelor care sunt delegate s execute metodele cu aceleai
rnsme ale claselor pe care le instaniaz. De asemenea, posibilitatea de a folosi mai
multe implementri pentru o interfa i de a folosi una sau alta dintre ele n funcie
de context (de exemplu n funcie de valoarea unei variabile) arat pe de o parte c
introducerea interfeelor ofer utilizatorului un instrument puternic i flexibil de
lucru, iar pe de alt parte justific nc o dat de ce Java utilizeaz legarea dinamic
(trzie).

6.7. Clonarea obiectelor


Subcapitolul de fa exemplific utilizarea interfeelor pentru problema
donrii obiectelor. '
90 6. METODE CLASE ABSTRACTE. INTERFEE. CLASE INTERNE

n multe cazuri suntem pui n situaia ca plecnd de la un obiect deja


construit, s trebuiasc s construim un alt obiect 0b2 care s copieze pe Obl,
urmnd ca n continuare cele dou obiecte s-i desfoare independent aciunile.
Cu alte cuvinte, vrem s crem o nou instan 0b 2 care s cunoasc tot ce
cunoate Obi h un anumit moment de timp (spunem c Ob2 pe Obl), dar
n continuare cele dou obiecte s acioneze independent.
ncercarea de a rezolva problema prin instruciunea de atribuire Ob2=Obl
este sortit eecului. ntr-adevr, prin aceast atribuire variabilele i 0b 2 devin
dou referiri la acelai obiect.

Pentru realizarea donrii obiectelor, Java pune la dispoziie interfaa


C lo n e a b le i metoda c lo n e ftr parametri a clasei f,rdcinMO b jec t.
Metodei c lo n e este declarat prin:
p u b lic O b je c t c l o n e () throw s C lo n eN o tS u p p o rted E x ce p tio n
i ntoarce un obiect nou, n ale crui cmpuri sunt copiate cmpurile obiectului
curent. Metoda c lo n e poate lansa excepia meriionat.
Interfaa public C lo n e a b le din pachetul j a v a . l a n g nu are metode;
rolul ei este de a stabili dac o clas este sau nu clonabil. Ea trebuie s fie
implementat de clasa n care este invocat metoda c lo n e , Modui tipic de lucru
este urmtorul: dac C este clasa ae crei obiecte urmeaz a fi donate, vom
specifica faptul c ea implementeaz interfaa C lo n e a b le i vom include o
metod care invoc pe clo n e.
Metoda c lo n e a clasei O b je c t verific dac clasa a crei instaniere este
obiectul curent implementeaz Cloneable= n caz afirmativ, este ntors un obiect
nou ale crui cmpuri sunt iniializate ca avnd aceleai valori ca i cmpurile
obiectului curent. In caz negativ, este lansat excepia specificat mai sus.

Exemplul 8. Programul urmtor;


class C Implements Cloneable {
int x;
void inc() { x++ }
C Clone( {
try C return (C) clone( ) }
catch (CloneNotSupportedException e) { return null}

class Copiei {
public static void main {String[] s) {
= n@w ); Ob2 - .Clone ();
IO .writeln ( .x+n +2 .);
.inc {) ; 2 .inc () ; 2 .inc ();
IO .writeln (Obi.+" "-fOb2 .);
}
}
6.7. donarea obiectelor 91

produce la ieire:
0 0
1 2
Sunt necesare urmtoarele precizri:
- este obligatorie conversia explicit a rezultatului ntors de clo n e la tipul
dorit;
- am inclus invocarea lui c lo n e ntr-o metod C lone din clasa C deoarece
acolo i este n mod natural locul (este o prelucrare ce se refer la clasa c); pe de
alt parte nu puteam s invocm c lo n e din metoda principal, deoarece nu este
static;
- despre t r y i c a tc h vom vorbi pe larg n capitolul urmtor.

Exemplul 9. Dorim s donm un obiect care gestioneaz o stiv. Vrem ca


noul obiect s plece de la acelai coninut al stivei ca i cel vechi, dar n continuare
s lucreze independent, adic stivele gestionate de cele dou obiecte s fie
distincte.
Stiva este memorat n tabloul v i gestionat prin intermediul metodelor
pop (extragere) i p u sh (adugare n stiv). Constructorul clasei s t i v a creeaz
vectorul de lungimea transmis ca parametru i iniializeaz cmpul to p cu -1
(top este poziia corespunztoare vrfului stivei). Metoda C lone are acelai rol ca
n programul precedent, iar metoda scrie produce la ieire coninutul stivei.
Pentru moment vom face abstracie de comentariul de sfrit de linie din
metoda C lone.
clase Stiva Inqpleiaente Cloneable {
private int[] v private int top;
Stiva Clone() {
try {
Stiva ObNou - (Stiva) clone();
I I ObNou.v = ( intfj ) v .clone();
return ObNou;
}
catch (CloneNotSupportedException e) { return null }

Stiva(int nrmax) { v = new int[nrmax]top = -1; }


void push(int val) ( v[++top]= val; }
int pop() { return v[top--} }
void scrie{) {
for (int i=0 i<=top; i+ +) IO.write (v[i] +
IO.writeln()
92 6. METODE I CLASE ABSTRACTE. INTERFEE. CLASE INTERNE

class Clonare {
public static void main(String[] s) {
Stiva SI = new Stiva(10);
5 1 . push(l); SI.push(3) ; SI.push( 5) ; SI.push(7);
Stiva S2 = SI.Clone();
52. pop(); S2.pop(); S2.push(13);
SI.scrie()S2.scrie{);

La ieire va aprea:
-1 3 13 7
1 3 13
care nu este rezultatul dorit. Explicaia const in faptul c la clonare, Ia copierea
cmpurilor n noul obiect S2, a fost copiat adresa tabloului v (tipul tablou este un
tip referin), deci se lucreaz cu aceeai stiv; cmpul top este ns distinct pentru
cele dou obiecte.
Pentm a lucra cu stive distincte, v va trebui conat explicit. Aceasta se
realizeaz transformnd comentariul din Clone n instruciune efectiv. Cu aceast
modificare, programul va produce acum la ieire rezultatele dorite:
13 5 7
1 3 13

6.8. Oase interne


Pn acum am lucrat sub restricia c o clas nu poate conine o alt clas.
Dar Java permite s definim clase nu numai ca membri ai pachetelor, dar i ca
membri ai unei clase, n interiorul unei metode sau a unui bloc. Mai mult, aa cum
vom vedea mai jos, pot aprea clase fr nume.
Clasele care sunt membrii unui pachet sunt considerate clase de nivel
superior.
Clasele declarate ntr-o clas se mpart n dou categorii:
- clase de nivel superior: este vorba de membrii statici ai unei clase de
nivel superior; aceste clase au deci acelai statut cu clasele membre ale unui
pachet;
- clase interne: clasele care nu sunt de nivel superior.

ntr-o clas de nivel superior putem plasa i o interfa.


Aa cum am menionat, ntr-un bloc sau corpul unei metode putem defini
clase la fel cum putem defini variabile locale; aceste clase sunt clase interne.
O clas intern poate conine la rndul ei o clas intern.

Instanierea unei clase interne este asociat instanierii curente a clasei care
o conine; drept urmare clasa intern poate accesa direct cmpurile clasei ce o
cuprinde.
6.8. Clase interne 93

Cele de mai sus nu mai rmn valabile pentru clasele de nivel superior: o
clas care este membru static al unei clase nu poate folosi direct cmpurile clasei ce
o cuprinde (dar putem realiza acest lucru n mod indirect, prin crearea unui obiect
ce instaniaz clasa al crui membru este).

O clas intern nu poate fi folosit direct dect n clasa n care a fost


declarat i n descendenii (n arborele de clase ai) acesteia. Domeniul ei de
vizibilitate este cel al unui cmp, respectiv al unei variabile locale.

Avantajul utilizrii claselor locale const n primul rnd n faptul c


permite includerea lor exact acolo unde trebuie s apar din punct de vedere logic,
dar i n uurina folosirii lor (reamintim c din interiorul unei clase interne putem
s ne referim direct la cmpurile clasei ce o conine).

Exemplul 10. Parcurgerea pe niveluri a arborilor.


Parcurgerea pe niveluri a arborilor const n ordine n:
- vizitarea rdcinii (vrfului de pe nivelul 0);
- vizitarea vrfurilor de pe nivelul 1 (descendenii direci ai vrfurilor de pe
nivelul 1);
- vizitarea vrfurilor de pe nivelul 2 (descendenii direci ai vrfurilor de pe
nivelul 2);
etc.
Vizitarea vrfurilor se reduce la tiprirea numerelor lor de ordine.
Pentru reprezentarea arborilor am ales ca pentru fiecare vrf s specificm
fiul i fratele lui: un obiect de tipul v r f are cmpurile f i u i f r a t e .
Algoritmul folosete o coad C n care iniial apare doar rdcina r a d a
arborelui:
C <= 0 ; C <= ra d
w h ile C ^ 0
i <= C; viziteaz i
f o r toi j fii ai lui i
w j

enor
enwhle
Pentru implementarea cozii am folosit o list nlnuit, n care primul
element este fals (deci coada propriu-zis ncepe de la al doilea element al listei).

Programul corespunztor este urmtorul:


class v r f {
in t v; v rf f i u , f r a t e ; s ta tic v rf ra d
v r f (). { }
v r f ( i n t v a l ) { v = v a l }
94 6. METODE I CLASE ABSTRACTE. INTERFEE. CLASE INTERNE

v o id creare(} {
i n t i
i = (int) 10.read(); rad = new vrf(i); creare(rad);

v o id creare(vrf x) { //ataeaz un fiu i un frate lui x


i n t i d o u b le d; vrf y;
If (x==null) return;
10.write("Fiul lui " ^ x.v + " : "); d = I0.read();
if (! Double.isNaN{d) ) {
i = (int) d; x.fiu = new vrf(i); creare{x.fiu)
}
10.write {"Fratele lui " 4- x.v - ft H) d = IO. read ) #
*
if (! Double.isNaN(d) ) {
i = (int) d x.frate = new vrf(i)creare(x.frate)
}

class elem {
vrf inf; elem leg;
elem (vrf v} { inf = v }

String niveluri() {
elem p,u,xvrf ; String - ""/
p = new elem(null)u = new elem{rad); p.leg = u
while ( p != u ) {
x - p . legs x.inf.v 4- 11 '' P.leg = x.leg;
if (p,leg = = n u l l ) u = p //
x inffiu;
w h ile ( l = n u l l ) {
= nw elem(y); u.leg = x;^ u = X = .frate;
}
}
r e t u r n s
}
}
c l a s s Niveluri {
p u b lic s t a t i c v o id main ( String[ 3 arg) {
vrf Ob = nw vrf();
Ob
creare();
IO.writeln( "Niveluri " + '\t' -f Ob. niveluri {} };
}
}

Se observ c n clasa v r f apare clasa intern elem ; elementele listei


nlnuite ce implementeaz coada sunt obiecte de tipul elem . Includerea clasei
elem n clasa vrf apare ca natural, deoarece elem este folosit pentru prelucrri
efectuate asupra instanelor clasei v r f .
6.81Clase interne 95

Am menionat mai sus c exist i clase fr nume (anonime). O clas


anonim apare ntr-o expresie de forma:
m v SuperA (. ..) {. ..}
prin care clasa anonim extinde o clas sau implementeaz o interfa SuperA i
prin care este creat un obiect al clasei anonime.

Observaie, Crearea de clase anonime permite extinderea implicit a unei


clase i implementarea implicit a unei interfee ( & folosi xtn sau
Drept urmare codul devine mai scurt i mecanismul este folosit Mla
iocul potrivit", Aceast tehnic este larg folosit de exemplu n lucrul cu interfee
grafice.

Exemplul 11, S considerm urmtorul program:


ubitraot clae A {
A{int i) { IO.writeln(i)}
void met() { }

olass A_C {
static A ObA
public etatc void main(Stringt] s) {
, ObA = aw A(3) {
void m e t f) { IO.writeln{"0,K. " ) }
};
ObA.met{);
}
}
Clasa abstract a are un constructor i o metod care nu prevede nici o
aciune. Pare ciudat faptul c dei metoda nu este abstract, clasa a fost declarat ca
fiind abstract; acest "artificiu" este de fapt o invitaie la a extinde clasa i a preciza
aciuni specifice pentru metode.
n clasa AC apare metoda principal, n care obiectul ObA (avnd tipul
declarat a ) este creat ca avnd ca tip reai o clas anonim care extinde clasa
abstract A. Clasa anonim este o clas intern. Dup invocarea constructorului este
invocat metoda met; este vorba bineneles de metoda m et redefinit n clasa
anonim. Drept urmare la ieire va aprea;
3
O.K.

Exem plul 12. Spre deosebire de exemplul precedent, aici am ales ca o


clas anonim s implementeze o interfa;
In te r fa c e I {
void met{);
}
96 6. METODE I CLASE ABSTRACTE. INTERFEE. CLASE INTERNE

class IC {
static I 0;
p u b l i c s t a t i c v o id m a i n (S t r i n g [] s) {
= new I () {
p u b l i c v o id m e t () { I O . w r i t e l n { " O . K . " ) ; }
};
Obi.met();

Din nou este creat o clas (intern) anonim i un obiect avnd ca tip real
HC&clSta. c in S a j lVOCa TlvtM XUSu r v ^ v f lr iit Sl d ^ S u utidliT iU i
Executarea programului produce la ieire:
O.K,
O interfa nu poate avea constructori explicii. Exist ns constructorul
implicit cu aciune nul; acest constructor a fost folosit n exemplul de mai sus.
Este interesant de subliniat nc un aspect. Clasa C are modificatorul de
acces implicit, dar n interiorul ei apare o metod cu modificatorul (mai permisiv)
p u b lic . Acesta se datoreaz faptului c metoda redefinete o metod (public)
dintr-o interfa.

Clasele interne se dovedesc un instrument foarte util i uor de mnuit i se


va face apel la ele n continuare. Clasele anonime apar iniial ca fiind mai puin
"naturale", dar avantajele (menionate mai sus) ale acestei tehnici fac ca ea s fie
foarte util i deci folosit, aa cum vom face n lucrul cu interfee grafice.
Q E X C E P II
U C O N V E R S II

7 Excepii
Noiunea de excepie
Un aspect important de care trebuie inut cont ori de ce ori scriem un
program este de a asigura robusteea sa. Prin aceasta nelegem identificarea
situaiilor nedorite (de exemplu introducerea unor date eronate, eecul la
ncercarea de a avea acces la Internet etc.) i specificarea aciunile
corespunztoare.
Exist ns i reversul aspectului descris mai sus. Introducerea de verificri
prin instruciuni de control face programul greu de citit i afecteaz buna sa
structurare.
Ceea ce dorim este s avem un mecanism care:
- s permit ca fiecare condiie legat de robusteea programului s fie
verificat exact acolo unde poate s apar;
- atunci cnd condiia apare (suntem n situaia c s-a ntmplat ceva
nedorit), controlul s fie trecut automat unei seciuni de cod aflat n program
"ntrun loc potrivit" (care poate fi departe" de locul unde condiia a fost
detectat), cod care realizeaz aciunea ce trebuie ntreprins. Acest cod va fi
numit handler (mnuitor) de excepie.

Limbajul Java rezolv problema de mai sus printr-un mecanism numit


excepie. Excepia semnaleaz faptul c a intervenit o anumit condiie special
(nedorit); spunem c segmentul de cod care a detectat condiia lanseaz o
excepie de tipul corespunztor. Lansarea unei excepii atrage dup sine captarea
ei de ctre un handler de excepie; n lipsa acestuia, programul se va ncheia cu un
mesaj de eroare.
Mai precis, trebuie s realizm urmtoarele:
- s definim tipurile de excepie care s permit lansarea excepiilor dorite;
- s lansm o excepie la "locul potrivit" n program;
- s prevedem la "locul potrivit" un handler de excepie, care s capteze
excepia i s ntreprind aciunile corespunztoare.
100 7. EXCEPII. CONVERSII

Sunt importante urmtoarele precizri:


- precizarea tipului de excepie prin clauza th row s este important pentru
c programatorul (ca i compilatorul) trebuie s tie ce excepie poate fi lansat i
care este tipul ei, ia fel cum trebuie s cunoasc tipul valorii ntoarse de o metod;
- dac din interiorul metodei dorim s prevedem lansarea mai multor
excepii, atunci toate tipurile lor trebuie precizate n clauza throw s, desprite
ntre ele prin virgul;
- o metod poate lansa numai excepiile care sunt precizate n antetul su
(m^i precis n clauza throw s); lansarea poate avea loc din interiorul metodei sau
din interiorai altei metode pe care ea o invoc;
- nu este permis s lansm excepii din interiorul iniializrilor statice; n
schimb acest lucru este permis din interiorul constructorilor;
- la redefinirea unei metode ntr-o subclas, nu putem preciza n throws
excepii suplimentare.

Construcia tr y

Mecanismul incipient descris mai sus permite crearea unei excepii i


invocarea unui constructor al su. Dar o excepie lansat n corpul unei metode
trebuie s aib drept consecin executarea unor aciuni cuprinse ntr-un handler de
excepie prezent tot n corpul metodei. Tipul de excepie respectiv este ns o
clas, care poate avea i metode. n handlerul de excepie este posibil invocarea
unor metode ale clasei a crei instaniere este obiectul n discuie. Toate aceste
aspecte sunt rezolvate de construcia tr y .

Construcia t r y are forma:


tr y b l o c
c a t c h (E__l e _ l ) b l o c l
c a t c h (E_2 e 2) b l o c 2

fin a lly b lo c _ f in a l
unde:
- E__l, E_2, . . . sunt tipuri de excepie (clase ce extind E x cep tion );
- e 1, e _2 , . . . sunt identificatori;
- clauza f i n a l l y este opional;
- blocurile reprezint tocmai handlerele de excepie.

Dac n blocul b l o c asociat lui t r y nu este lansat nici o excepie, atunci


se trece de ultimul c a tc h .
S presupunem acum c din b l o c este lansat o excepie; fie E tipul su.
Se ncearc pe rnd, n ordinea n care apar clauzele c a tc h , asocierea ei cu una
dintre ele. Dac E coincide cu E_1 sau este derivat din (extinde pe) e__1, atunci se
execut blocul h l o c _ l , dup care se trece de ultima clauz c a tc h . n caz contrar
se ncearc pe rnd asocierea excepiei cu E2, E_3 etc. Dac nu s-a reuit o
7 Excepii 101

asociere, se merge "la un nivel superior" ntr-o construcie t r y care o cuprinde pe


cea n discuie etc. Dac nici n acest mod nu s-a identificat o asociere, se trece n
codul care a invocat metoda curent etc. n final se va reui o asociere, deoarece
altfel ar apare o eroare chiar n faza de compilare.
Tot o eroare la compilare va apare i dac de exemplu E_2 este derivat
din E_l; explicaia const n faptul c lansarea unei excepii de tipul E2 nu va
putea conduce la captarea ei de ctre clauza identificat prin E2 (excepia va fi
captat de clauza c a tc h precedent).
Conform celor dc mai sus, este posibil ca o construcie t r y s nu aib
ataat nici o clauz c a tc h .
.
S mai observm c la lansarea unor excepii din b l o c (vezi forma
general a construciei tr y ) , instruciunile care i urmeaz n acest bloc nu vor mai
fi executate. Mai este clar i c o construcie t r y poate fi utilizat pentru captarea
mai multor excepii.

Aa cum am anunat anterior, o construcie fcry poate avea i o clauz


f i n a l l y . Aceasta permite executarea anei secvene de instruciuni indiferent dac
din blocul b lo c este lansat sau nu o excepie. Odat inclus, clauza f i n a l l y nu
poate fi n nici un fel ocolit i blocul b l o c _ f i n a l este totdeauna executat. Un
caz limit este de exemplu urmtorul:
try ( . re tu r n 0 }
fin a lly { re tu rn 1 }
pentru care valoarea ntoars este totdeauna 1.
De obicei clauza f i n a l l y este folosit pentru a elibera anumite resurse,
ca de exemplu resurse grafice sau fiiere (prin nchiderea lor).

Tratarea excepiilor
Descriem n continuare modul tipic de utilizare a excepiilor. Pentru
simplificare vom considera un singur tip de excepie cu un unic constructor i o
unic metod.
La construcia urmtoarei clase:
olaee Clasa {
Clasa(.) {.}
Met(. . ) t hrow* Excepie {

i f ( . . } th ro w new Excepie( ..)

programatorul a identificat n metoda Met o condiie deosebit care ar putea


interveni i de aceea a conceput i clasa E x c e p ie pentru a putea prevedea
aciunile ce trebuie ntreprinse la ndeplinirea condiiei:
102 7. EXCEPII CONVERSII

class Excepie extends Exception {


Excepie{ . . . ) ( . . . )
. . . MetExc . {. . .}
} ^
n mod normal, aceste activiti sunt ntreprinse o singur dat, n vederea
unor aplicaii ce urmeaz a fi dezvoltate. Pe de alt parte, clasa E x c e p ie poate fi
folosit i de alt clas dect C la s a de exemplu att pentru lucrul cu stive, ct i
pentru cei cu cozi, prelucrrile prevzute pentru o ncercare de adugare a unui
element n stiva/coada plin pot fi aceeai. De aceea de multe ori este natural ca
cele dou clase s se afle n uniti de compilare separate.

Ulterior, programatorul scrie un program care cuprinde o clas C, din care


este invocat metoda Met a clasei Clasa, ceea ce poate conduce la lansarea
excepiei respective. Este clar c aici este locul cel mai potrivit pentru a specifica
aciunea ce trebuie ntreprins ia lansarea excepiei. Pentru aceasta este folosit
construcia t r y , care capteaz obiectul excepie i prin intermediul lui invoc
metoda MetExc a clasei Excepie:
class C {
Clasa Ob = new Clasa(...};

try {

Ob.Met (...);

}
catch (Excepie e){
" . e .MetExc (...};

S-a prevzut invocarea metodei Met a clasei C la sa din interiorul


construciei try. n cazul n care apare condiia n discuie, este creat un obiect de
tipul Excepie prin invocarea constructorului su. Apoi controlul este trecut
clauzei catch care capteaz (primete n parametrul su) obiectul creat, ceea ce
permite invocarea metodei MetExc din Excepie.
Acum discuia de la nceputul capitolului capt consisten: o excepie de
tipul Excepie este lansat din clasa Clasa i este captat n clasa C.

Un exemplu
Vom aplica cele de mai sus la rezolvarea urmtoarei probleme:
Un vector a de lungime n conine n caractere. Ele trebuie mutate ntr-o
ordine oarecare n vectorul bt prin intermediul unui vector auxiliar s t a c k de
lungime lu ng, care implementeaz o stiv. Operaiile permise sunt:
7 Excepii 103

-mutarea unui element din a n vectorul stack :elementul curent (cel cu


numrul de ordine cel mai mic) din a este mutat dup elementele deja existente n
stiv;
-extragerea (inclusiv tergerea) unui element din vrful stivei i nscrierea
sa n b, dup ultimul element nscris n b.

Dificultatea problemei const n tratarea cazului n care se ncearc


extragerea unui element din stiva vid i a cazului n care se ncearc introducerea
unui element n stiva plin.
Prezentm n continuare programul, urmat de explicaiile necesare.

Unitatea de compilare P l i n a . ja v a :
clase Plina extends Exception {
* void print(String s) { IO.write(s); }

Unitatea de compilare V id a .java :


a i a s s Vida Kt@nds E x c e p tio n {
void print(String s) { 10.w r i t e (s) }
}
Unitatea de compilare S .java
clase S {
int lung, ns char[] stack;
S (int lung) { this.lung=lung stack = new char[lung] }
void pune(char c) throws Plina {
if (ns==lung) throw new Plina();
else { 10.write(" P"+c); stack[ns]=cns++; }
}
ohar ia() throws Vida {
if (ns==0) throw new Vida();
lee {
10ewrite(" IM+stack[--ns]); return stack[ns];
1 }
}

Unitatea de compilare St i va.java


import java.u t i l . * ;
olatft Stiva {
public etatic void main(String[3 sir} {
int n=10,na,nb,i; char[] a,b; char c
a = new ohar [n]; b = new char [n];
Random H = new Random {);
for (c='a',i=0i<n; i++,c++) a[i]=c
na=0; nb=0; S Ob = new S {3);
whiltt (nb!=n) {
try { 4
if (R.nextlnt ()<0 ScSc na<n) { 0b.pune (a [na]) na++; }
else { b[nb] - 0b.ia(); nb++} }
104 7. EXCEPII. CONVERSII

catch (Vida e) {e .print {" ; }


catch ( Plina e) { e .print(" -PH) ; }
}
I O .writeln(}; for (1=0 i<n; i++) 10.write(b[i]
I O .writeln{);

Clasa principal este Stiva. Metoda sa main foiosete, n afar de


vectorii a i b, urmtoarele: .
-variabila na desemneaz poziia din a de pe care va fi mutat un element
n stiv;
- variabila nb desemneaz poziia din b pe care va fi nscris urmtorul
element;
- obiectul R de tipui Random (clas din pachetul java.util) este folosit
pentru apelarea metodei next Int fr argumente ce ntoarce n mod aleator un
numr ntreg;
- obiectul Ob de tipui s, unde clasa S implementeaz operaiile asupra
stivei: metoda pune are un parametru de tip char pe care i adaug stivei, iar
metoda i a fr parametri ntoarce elementul din vrful stivei.
Metoda main din Stiva repet, atta timp ct n b nu au fost nscrise n
caractere, urmtoarele aciuni:
-este generat aleator un nou numr ntreg;
-dac valoarea sa este negativ i mai exist elemente n a, este invocat
metoda pune din clasa S cu intenia de a muta un element din a n stiv; invocarea
este urmat de mrirea lui na cu o unitate. n caz contrar este invocat metoda ia
cu intenia de a obine un element din stiv ide a-i muta n vectorul b;
-n final sunt listateelementele lui b.
Observm c nu sunt tratate aici cazurile de excepie (adugare la stiv
plin sau extragere din stiva vid), aceste verificri cznd n sarcina clasei S.
Utilizarea clasei Random permite un ncdeterminism n succesiunea de operaii
asupra stivei, ceea ce va conduce la vectori b diferii de la o executare la alta.

n clasa S este folosit vectorul s ta c k de lungime lung pentru


implementarea stivei. n ns este memorat numrul de elemente din stiv. n antetul
metodei pune este declarat tipui de excepie plina cruia i corespunde clasa
plina ce extinde clasa Exception. Deosebim dou situaii;
-dac stiva este plin (ns=lung), atunci prin throw este creat o excepie
(un obiect de tip Plina). Controlul este trecut acelei clauze catch din Stiva care
este identificat prin tipul plina al excepiei. Obiectul creat este transmis n e.
Prin invocarea e ,print (... > este apelat metoda p r i n t a clasei Plina care
tiprete mesajul primit Ia invocare. S observm c n acest mod se evit
incrementarea lui na;
- dac stiva nu este plin, atunci este nscris un nou element n stiv.
Modul n care acioneaz metoda i a este analog.
7. 1. Excepii 105

Este uor de observat c s-a folosit exact schema descris anterior, cu


clasele Plina i Vida n rolul clasei Excepie, cu S n postura clasei Clasa i
cu Stiva n locul clasei c.

Clasa E xcep tion

In pachetul java.lang apare urmtoarea ierarhie de clase:


Object
.a Throwable
Error
Exception

unde indentarea corespunde extinderii: de exempiu clasa Error extinde clasa


Throwable.

Throwable este superciasa tuturor erorilor i excepiilor din Java. Numai


obiecte ce instaniaz aceast clas sau subclase ale ei pot fi lansate prin throw .
Pe de alt parte, n clauza c a tc h poate aprea ca tip numai aceast clas sau
subclase ale ei. Toate aceste clase au un constructor fr parametri, precum i un
constructor cu un parametru de tip String, prin care se poate specifica un mesaj
de eroare.
Spre deosebire de clasa Exception, clasa Error este conceput pentru
condiii anormale (erori majore), pentru care nu este rezonabil s prevedem aciuni
prin mecanismele descrise mai sus.

Prezentm clasele din pachetul j a v a .l a n g , derivate din (care extind)


clasa Exception:

ClassNotFoundException
CloneNotSupportedException
XllegalAccessException
InstantiationException
InterruptedException
NoSuchFieldException
NoSuchMethodException
HuntimeException
ArithmeticException
ArraystoreException
ClassCastException
IllegalArgxamenfcException
IllegalThreadStateException
NumberFormatException
IllegalMonitorStateException
s IllegalStateException
IndexOutOfBoundsException
ArraylndexOutOfBoundsException
StringlndexOutOfBoundsException
106 7. EXCEPII CONVERSII

NegativeArraySizeException
NullPointerException
Security-Exception
UnsupportedOperationException

12. Conversii
Java acord o atenie deosebit tipurilor. Fiecare expresie are un tip ce
poate fi dedus din structura expresiei i din tipul entitilor ce intr n alctuirea sa:
literali, variabile i invocri de metode. Sunt ns permise, n anumite condiii bine
precizate, conversii de la un ip ia un al tip; acest aspect este subiectul acestui
subcapitol.
Evident, nu orice conversie este admis. De exemplu expresia ce apare n
instruciunea i f poate avea numai tipul b o o lean , n caz cdhtrar semnalndu-se o
eroare chiar la compilare. Mai precizm c o conversie (admis) poate conduce la
o aciune corespunztoare n faza de executare, aa cum vom vedea mai jos; aceste
aciuni pot conduce n anumite cazuri ia lansarea unei excepii.
Conversiile pot aprea n urmtoarele contexte;
- ia atribuire, cnd tipul unei expresii trebuie convertit la tipul variabilei ce
primete valoarea expresiei;
- la invocarea unei metode sau a unui constructor, cnd are loc transferul
argumente > parametri;
- la conversii ce implic tipul S tr in g : orice tip poate fi convertit la
String
- la evaluarea unei expresii numerice: operanzii trebuie adui la un tip
comun, astfel nct expresia s poat fi evaluat;
- ia o conversie explicit.
Ne propunem s prezentm numai principalele aspecte legate de conversii.

@ Conversii implicite
n aceast categorie intr conversiile efectuate automat, fr vreo precizare
explicit n program.

Pentru tipurile primitive, urmtoarele conversii sunt implicite:


b y te > s h o r t, n t , lo n g , f l o a t , d o u b le
s h o r t > i n t , lo n g , f l o a t , d ouble;
c h a r > i n t , lo n g , f l o a t , d ouble; i n t > lo n g , f l o a t , d o u b le
lo n g > f l o a t , d o u b le; f l o a t > double.
Unele dintre aceste conversii pot conduce la o pierdere a preciziei. De
exemplu conversia de la lo n g la f l o a t poate afecta cifrele cele mai puin
semnificative ale valorii iniiale. ntr-adevr, executarea secvenei de cod:
int i = 1234567890; float f ^ i; O.writei H\t" f);
7.2, Conversii 107

produce la ieire:
1234567890 1.234567894E9

Pentru tipurile referin, conversiile implicite sunt cele de la tipul la tipul


At unde:
-clasa este o subclas a clasei A
-interfaa este o subinterfa a interfeei a
- clasa implementeaz interfaa A
- este n u li, iarA este orice clas, interfa sau tablou.
Discuia anterioar asupra noiunilor de tip declarat i tip real conduce la
concluzia c o conversie de !a o superclas ia o subclas nu poate fi totdeauna
acceptat. Astfel, dac este subclas a lui A, o secven de tipul:
b; a = new A (...)b = a;
nu este acceptabil, deoarece de exemplu clasa poate defini noi cmpuri.
Conversiile legate de tipul S tr i n g se aplic numai operanzilor
operatorului +, cnd cel puin unul dintre aceti operanzi este de tipul strin g ; n
acest caz operanzii de un tip diferit sunt convertii (ntr-un mod specific tipului lor)
la String,
Conversia implicit poate fi folosit i ia transferul argumente >
parametri. Un literal ntreg nu pot fi ns transmis unui parametru de tip ntreg al
crui domeniu de valori este mai restrns. Astfel, invocarea metodei:
void m e t (short i ) { }
prin met (1 );
conduce la o eroare de compilare.

Conversii explicite
Cunoatem deja c o conversie explicit la un tip T se face prin prefixare
cu (T ), ca de exemplu n;
T ObT = (T) Ob;
Evident, nu este permis orice conversie (chiar explicit) de la un tip ia un
alt tip.

Pentru tipurile primitive sunt admise, n plus fa de cele implicite,


urmtoarele conversii explicite:
byte > char; short byte, char;
ohar byte, abort in t byte, short, char;
long byfce#ehort, char, in t, long
flo a t >byte short, ohar, in t, long;
double b y t e , hort, char, in t, long, flo a t.
La fiecare astfel de conversie are loc o prelucrare specific, ce poate
conduce la o pierdere de precizie, dar i la o modificare a ordinului de mrime.
Dintre aceste prelucrri menionm urmtoarele:
108 7. EXCEPII. CONVERSII

- la conversia de la un tip ntreg la un tip ntreg cu domeniu de vaiori mai


restrns se taie biii din stnga (deci nu se mai pstreaz neaprat semnul);
- la conversia de la un tip ntreg la tipul char se pstreaz numai cei 16
bii din dreapta;
- ia conversia de la un tip n virgul mobil la un tip ntreg, partea
fracionar se pierde, f^cndu-se rotunjire spre 0;
-la conversia de la double la float se poate pierde din precizie, dar se
poate obine i 0 sau "infinit" (vezi capitolul 2).

E x e m p lu . Secvena de cod urmtoare:


int i=,\ufff,, j=97+65536; short s ~ -130;
IO.writeln( (short) i + M\ttt + (byte) s + "\t" (char) j )
IO.writeln( (int) -2.8 )
double d=5e-300; IO.writeln(d + "\t" + (float) d);
d=l.8e300; IO.writeln(d + "\t" + (float) d);
produce la ieire:
-1 126 a
-2
5.0E-300 0.0
1.8E300 Infinity

Pentru tipurile referin intr n discuie pentru a fi permise, n plus fa de


ed e implicite doar cele de Ja un dp A un subtip ai su. Dac A este o ifHerfa{
i o clas, nu poate fi declarat cu modificatorul final dect dac
implementeaz interfaa A.
Condiiile de mai sus sunt necesare, dar nu suficiente,
n generai, o conversie de la o superclas la o subclas (numit
downcasting) este permis numai dac este fcut explicit i numai dac referina
la superclas este de fapt o referin la subclas. Iat un cadru tipic n care se
realizeaz acest lucru (n continuare A este superclas a lui ):
; ,b2 ;
bl = new (...); ...
. ~ / , . #
2 = (
)
;

Pentru a verifica dac conversie este permis, putem folosi operatorul


instanceof. Pentru tipurile , i a un obiect de tipul A, modul tipic de utilizare
este:
if instanceof B) { .. }
(a

n cazul n care conversia de la tipul A ia tipul nu poate intra n discuie


(vezi mai sus), aceast instruciune provoac o eroare de compilare. In caz contrar,
expresia din if are valoarea tr u e sau f a l s e , dup cum conversia este permis
sau nu. ,
ncercarea de a efectua o conversie nepermis conduce la lansarea
excepiei ClassCastException.
FACILIT I
STAND A]m

Prezentm n acest capitol cteva dintre multiplele faciliti oferite de Java


pentru aplicaii standard, numite i programe utilitare: lucrul cu funcii matematice,
lucrul cu tablouri i iruri de caractere, organizri standard ale datelor, sortri etc.,
dar i aspecte mai deosebite (lucru! cu clase). Vor fi prezentate clase, interfee i
metode ale lor care pun la dispoziie astfel de faciliti.

8 Funcii matematice
Java pune la dispoziia utilizatorilor o larg gam de funcii matematice,
prin clasa Math din pachetul java.lang:
public final class Math extends Object

Clasa Math furnizeaz constantele E i PI de tip d o u b le (corespunz


toare lui e i n), precum i metode publice staticeunele menionate n continuare.

Metodele abs pentru determinarea valorii absolute au forma:


tip abs ( t i p t)
unde t i p este i n t, long, f l o a t sau double.

Urmtoarele metode au un parametru de tip d o u b le i ntorc o valoare de


acelai tip:
sin, cos i tan ; pentru calculul funciilor trigonometrice respective;

- asin, acos i atan : pentru calculul funciilortrigonometrice inverse;


- exp i log : pentru calculul exponenialei i logaritmului n baza e\
- s q r t : pentru calculul rdcinii ptrate.

Metoda:
double pow(double a, double b)
ntoarce valoarea ab.
Metoda random fr parametri ntoarce o valoare aleatoare de tip d o u b le
din intervalul [0 , 1 ).
110 8. FACILITI STANDARD

Metoda:
in t ro u n d (flo a t f )
ntoarce valoarea ntreag cea mai apropiat de f .

8.2. Clasa Random

Clasa R a n d o m apare n pache tul j a v a . u t i l :


p u b lic c la s s Random e x t e n d s O b j e c t
i are un constructor fr parametri.

Metodele publice:
b o o l e a n n e x t B o o l e a n ()
i n t n e x t l n t {)
l o n g n e x t L o n g {)
d o u b l e n e x t D o u b l e ()
f l o a t n e x t F l o a t ()
ntorc urmtoarea valoare aleatoare de tipul respectiv.

Metoda:
i n t n e x t l n t ( i n t n)
ntoarce urmtoarea vaioare ntreag aleatoare din intervalul [ 0 , n ) .
Metoda:
v o i d n e x t B y t e s f b y t e [ ] b)
ntoarce, n tabloul furnizat ca argument, valori aleatoare de tip b y te .

8 Clasele nfurtoare pentru tipurile primitive


Java asociaz tipurilor primitive aa-numitele clase nfurtoare, conform
urmtoarei ierarhii:
O b je c t
B o o le a n
C h a ra c te r
Number (clas abstract)
B y te
S h o rt
In te g e r
Long
F lo a t
D o u b le

Clasele nfurtoare, cuprinse n pachetul ja v a . la n g i declarate cu


modificatorul f i n a l , pun la dispoziie metode publice i statice utile, ca de
exemplu cele pentru transformarea unui ir de caractere ntr-un ntreg. Ele mai
permit crearea de obiecte pentru pstrarea valorii unui tip primitiv; aceste obiecte
SJ. Clasele nfurtoare pentru tipurile primitive 111

pot fi folosite n contextele n care este ateptat un obiect i nu un tip primitiv. De


asemenea clasele nfurtoare constituie locul potrivit pentru anumite constante
(ca de exemplu MllVAbUE p SITIVE_i n f init y ) i anumite metode (de
exemplu isNaN)

Toate clasele nfurtoare n afar de Boolean pun la dispoziie


constantele m i n _v a l u s im a x __v a l u e ,reprezentnd cea mai mic i cea mai mare
valoare de tipul respectiv; n cazul claselor Double Float, MINVALUE este cea
mai mic valoare pozitiv.
n clasele Double i Float mai apar i constantele NaN,
NEGATIVEINFINITY i POSITIVEINFINITY menionate n capitolul 2.

Fie t i p unul dintre tipurile primitive b o o lean , c h a r, b y te , short, i n t ,


long, f l o a t i d o u b le i fie Tip clasa nfurtoare corespunztoare. Toate
clasele T i p au modificatorii p u b l i c i f i n a l i au constructorii:
T i p i t i p t)
T i p ( S t r i n g s)
prin care este creat un obiect pe baza valorii trimise ca argument, fie prin utilizarea
tipului primitiv respectiv, fie prin transmiterea unui ir de caractere ce este
transformat ntr-o valoare de acel tip; transmiterea unui ir de caractere ce nu este o
reprezentare valid pentru tipul respectiv lanseaz excepia:
NumberForma tException.
De asemenea clasele T i p au metodele publice:
String toString {} ;ntoarce reprezentarea ca irde caractere a obiectului;
tip tipValue () :ntoarce valoarea de tip primitiv asociat obiectului;
boolean equals (Object ob) : ntoarce true dac ob nu este nuli i
reprezint aceeai valoare de tipul t i p ca i obiectul ce a invocat metoda;
i n t compareTo(Tip t) : invocat de un obiect Ob de tipul Tip, metoda
ntoarce un rezultat negativ, zero sau pozitiv, dup cum valoarea (primitiv) a
lui ob este mai mic egal sau mai mare dect valoarea lui t.

Clasele T i p numerice (cele ce extind Number) mai includ metoda:


static tip parseTip(String s)
ce ntoarce valoarea de tipul primitiv t i p a irului s; pentru tipul integer,
metoda are numele parseint. Dac s nu este o reprezentare valid a unui literal
de tipul tip, va fi lansat excepia: NumberFormatException..

n clasele Double i Float apar i metodele:


boolean isNaN(double d) i boolean isNaN(float d)
despre care am vorbit n capitolul 2.

Clasa Character mai conine urmtoarele metode utile:


boolean isLowerCase (charc)t:verific dac c este "liter mic"
boolean isUpperCase (charc) ;verific dac c este "liter mare"
boolean isSpacechar c) :verific dac c este un spaiu alb;
112 8. FACILITI STANDARD

char toLowerCase (char c) :ntoarce "literamic" ce corespunde lui c;

char toUpperCase (char c) : ntoarce "litera mare" corespunztoare lui c.

Un obiect de tipul unei clase nfurtoare mai poate fi obinut i prin


invocarea metodei:
static Ti p valueOf(String s)
din clasa Tip, ce reprezint o alternativ la constructorul cu un parametru.

8.4. Aritmetica numerelor mari


Java permite efectuarea de calcule asupra numerelor orict de mari.
Instrumentele necesare se afl n clasele din urmtoarea ierarhie din pachetul
java. math:
Object
Number
Biglnteger
BigDecimal

Clasele Biglnteger i BigDecimal pun la dispoziie metode pentru 0


mare varietate de operaii aritmetice asupra numerelor ntregi, respectiv zecimale,
de orice mrime.

Vom restrnge prezentarea la clasa Biglnteger.


Att clasa Biglnteger, ct i constructorii i metodele sale sunt publice.

Ne mrginim a prezenta numai constructorul:


Biglnteger(String s}
care creeaz un obiect a crei valoare este valoarea ntreag reprezentat de s i
care poate lansa excepia NumberFormatException.

Metodeie acestei clase permit operaiile uzuale cu ntregi, adaptndu-le la o


lungime arbitrar a acestora. In cazul n care o metod nu poate ntoarce un rezultat
de tipul anunat, este lansat excepia ArithmeticHxception. Prezentm n
continuare cteva dintre aceste metode i rezultatul ntors de invocarea lor de ctre
obiectul a de tip Biglnteger:

Metod Rezultat ntors


Biglnteger add(Biglnteger b) a+b
Biglnteger subtract{Biglnteger b)
Biglnteger multiply(Biglnteger b} a*b
Biglnteger divide(Biglnteger b) a/b
Biglnteger remainder(Biglnteger b) a%b
Bianfceaer[] divieAndRemainder a/b i a%b
{Biglnteger b)
Biglnteger abs() |a(
8.5. Lucrul cu iruri de caractere 113

B ig ln t e g e r n e g a t e () -a
B ig ln t e g e r g c d ( B ig ln t e g e r b) cnmdc (a, b)
B ig ln t e g e r p o w (B ig ln te g e r b) ato
i n t sig n u m () s ig n ( a )
B ig ln t e g e r m od(B ig n t e g e r b) a mod b
B ig ln t e g e r a n d ( B ig ln t e g e r b) . &
B ig ln t e g e r o r ( B i g l n t e g e r b) 1 b
B ig ln t e g e r n o t ( B ig ln t e g e r b) ! b
B ig ln t e g e r x o r ( B i g l n t e g e r b) a xor b
B ig ln t e g e r s h i f t L e f t ( i n t n) a n
B ig ln t e g e r s h i f t R i g h t {i n t n) a >> n
i n t c o m p a r e T o (B ig ln te g e r b) -1 , 0 sau 1 (dup cum a<b(
a=b sau a>b)
B ig ln t e g e r m in ( B ig ln t e g e r b) m in (a ,b )
B ig ln t e g e r m ax( B ig ln t e g e r b) m a x (a ,b )
in t in t V a lu e ( B ig ln t e g e r b) (in t) a
lo n g lo n g V a lu e ( B ig ln t e g e r b) (lo n g ) a
f l o a t f lo a t V a l u e ( B i g l n t e g e r b) (flo a t) a
d ou b le d o u b le V a lu e ( B ig ln t e g e r b) (d o u b le) a
S tr in g t o S t r in g O reprezentarea lui a ca ir
b o o lea n e q u a l s ( B ig ln t e g e r b) a==b (ca valori numerice)

cu precizarea c spre deosebire de rem ainder, mod ntoarce o valoare pozitiv.

O ultim metod pe care o prezentm este:


b o o lea n is P r o b a b le P r im e (i n t p)
care ntoarce tr u e dac probabilitatea ca a s fie numr prim este mai mare dect
1-1/2P. Timpul necesar executrii metodei este proporional cu valoarea lui p.

8.5. Lucrul cu iruri de caractere


irurile (de caractere) din Java sunt obiecte standard. Orice ir este un
obiect al clasei s t r i n g , ce apare n pachetul j a v a . lang:
p u b lic f i n a l c l a s s S t r in g e x te n d s O b ject
Cunoatem deja civa operatori pentru lucrul cu iruri:
- operatorul +, folosit pentru concatenare:
- operatorul +=, ce creeaz un nou ir prin concatenarea irului din stnga
operatorului cu irul din dreapta sa.
Un (obiect de tip) ir nu poate fi modificat (este "read-only") dar, prin
utilizarea metodelor clasei s t r i n g putem obine pe baza lui noi iruri.

Clasa s t r i n g conine constructorii:


p u b lic S t r i n g () i p u b lic S t r i n g ( S t r i n g s)
care permit s construim un nou ir iniializat cu irul vid, respectiv cu irul s.
114 8. FACILITI STANDARD

Toate metodele clasei s t r i n g au modificatorul de acces p u b lic . Trecem


la prezentarea ctorva dintre ele.

Metodele eseniale ale clasei S tr i n g sunt:


i n t le n g th () : ntoarce lungimea irul curent (care a invocat metoda);
c h a r ch arA t ( i n t i ) : ntoarce caracterul de pe poziia i din irul curent.
S observm diferenele fa de lucrul cu tablouri. Dac s este un ir, iar a
un tablou, atunci:
- s . l e n g t h {) este lungimea irului, iar a . l e n g t h este lungimea
tabloului;
- s .c h a r A t ( i ) este caracterul de pe poziia i din ir, iar a [ i ] este
elementul de pe poziia i din tablou.
Invocarea metodei c h a rA t cu un indice n afara irului lanseaz excepia:
indexO u tO fB ou n d sE xcep tion . Aceast excepie mai poate fi lansat i de alte
metode prezentate n continuare (identificarea lor se face cu uurin).

Metode pentru aflarea u n u i indice din ir

Urmtoarele metode ale clasei S tr i n g ntorc un rezultat de tipul i n t , ce


reprezint o poziie cu o anumit proprietate dirx irul s prin care au fost invocate
(dac o astfel de poziie nu exist, este ntoars valoarea - 1).

Metod ntoarce indicele din ir depe


in d e x O f(ch a r ch) prima poziie pe care apare ch
in d e x O f(ch a r c h l i n t p) prima poziie, mai mare sau egal cu
p, pe care apare ch
in d e x O f(S t r in g sub) prima poziie ncepnd de la care
apare irul sub
in d e x O f(S t r in g su b , i n t p) prima poziie, mai mare sau egal cu
p, ncepnd de la care apare irul sub
l a s t l n d e x o f (ch ar ch) ultima poziie pe care apare ch
l a s t l n d e x o f {char ch , i n t u) ultima poziie, cel mult egal cu u, pe
care apare ch
l a s t l n d e x o f ( S t r in g sub) ultima poziie ncepnd de la care
apare irul sub
l a s t l n d e x o f ( S t r in g sub^ i n t u) ultima poziie, cel mult egal cu u,
ncepnd de la care apare irul sub

Exemplul 1. Urmtorul program citete dou iruri i determin numrul


de apariii al celui de al doilea n primul. irurile sunt introduse la executare din
linia de comand.
c l a s s n r_ap ar {
s t a t i c i n t n r a p a r ( S t r in g s , S t r in g su b s) {
8.5. Lucrul cu iruri de caractere 115

int nr=0, indice, poz=0


indice - s .indexOf(subs#poz);
while (indice>=0 &e indice<s.length ()) {
nr++poz++
indice = s .indexOf(subs,poz);
}
r e tu r n nr;
}
p u b lic s t a t i c v o id m a in ( S t r i n g [] ) {
I O .w r i t e l n { "
+ n rap ar (s [0] , s [ 1 ] ) )
}
}

@ Compararea irurilor

Clasa S t r in g prevede metode pentru compararea coninutului irului care


invoc metoda cu coninutul unui ir transmis ca argument. Vom presupune c irul
care invoc metodele este s. Compararea se refer la iruri n totalitatea lor sau la
subsecvene ale lor.
Compararea se face conform ordinii lexicografice: compararea a dou
caractere const !n compararea numerelor lor de ordine n setui de caractere
Unicode.

b o o lea n e q u a l s ( S t r i n g s i ) :
ntoarce tr u e dac irurile coincid;
i n t CompareTo(S t r in g s l ) :
ntoarce o valoare negativ (dac e < s l) s zero (dac s = s l ) sau o valoare
pozitiv (dac s > s l);
b o o lea n r e g io n M a tc h e s ( i n t p , S t r in g s l , i n t p l , i n t l u n g ) :
compar secvenele de lungime lu n g ce ncep n s de pe poziia p, respectiv
n s l de pe poziia p l; este ntoars valoarea tr u e dac i numai dac aceste
secvene coincid;
b o o lea n s t a r t s W it h ( S t r in g p re) : ntoarce tr u e dac irul p re este prefix
al lui s i f a l s e altfel;
b o o lea n endsW ith (S t r in g s u f ) : ntoarce t r u e dac irul s u f este sufix al
lui s i f a l s e altfel.

S remarcm c metoda e q u a ls nu poate fi suplinit de operatorul ==


deoarece prin s= = sl se compar dou referine i nu coninutul lor.

O alt modalitate de a compara iruri este furnizat de metoda:


S tr in g i n t e r n ()
care ntoarce un ir cu acelai coninut ca cel al irului care invoc metoda, avnd
n plus urmtoarea proprietate: pentru orice dou iruri cu acelai coninut,
116 8. FACILITI STANDARD

valoarea ntoars de metoda intern este aceeai. Drept urmare putem verifica
dac dou iruri au acelai coninut prin:
s l .intern{} == s 2 .intern(}
care este mai rapid dect:
s l .equals s2).

Determinarea urnii subir cu o anumit proprietate

Metodele clasei String ce se ncadreaz aici sunt urmtoarele (vom


presupunde din nou c irul care invoc metoda este notat prin s):
String substring(int p )
este ntors subirul lui s ce ncepe de pe poziia p;
String substring(int p, int u } :
este ntors subirul lui s ce ncepe de pe poziia p i se termin pe poziia u-1;
String replace(char cl, char c2}:
este ntors irul obinut din s prin nlocuirea tuturor caracterelor cl prin
caracterul c 2;
String toUpperCase{):
fiecare caracter este nlocuit cu echivalentul su majuscul, dac acesta exist;
String toLowerCase():
fiecare "liter mic este nlocuit cu "liter mare" dac aceast
coresponden exist;
String trim():
ntoarce irul obinut din s prin eliminarea spaiilor albe de la nceputul i
sfritul su;
String concat(String sl):
ntoarce irul s-t-sl.

iruri i tablouri de caractere

Clasa string prevede metode pentru transformarea irurilor n tablouri de


caractere, precum i pentru transformarea invers;
Metoda toCharArray () invocat de un ir s ntoarce un tablou de
caractere de aceeai lungime i cu aceleai elemente,
Metoda static copyValueOf are dou forme:
String copyValueOf(char[] a)
String copyValueOf(char[] a, int p, int lung)
i ntoarce irul corespunztor tabloului a de caractere, respectiv numai acea
secven din tablou ce ncepe pe poziia p i are lungimea lung.

Exemplul 2. Pentru a determina irul obinut din irul s prin considerarea


elementelor sale n ordine invers, putem scrie urmtoarea metod:
8,6. Prelucri asupra tablourilor 117

public static String invers(String s) {


char c
char a = s .toCharArray( )
for {int p=0,u=a.length-l p<u; p++,u-- {
c=a[p] a[p]=a[u] a[u]=c
}
return String.copyValueOf(a)

Conversii
n multe cazuri suntem pui n situaia de a converti valori numerice n
iruri sau de a trebui s lucrm cu o valoare numeric memorat ntr-un ir.
irul ce corespunde unei valori numerice sau booleene x se obine simplu
prin:
String.valueOf{x}
Metoda valueOf a clasei S t r i n g mai poate invocat i pentru un
caracter: va fi ntors irul format din acel unic caracter.
Transformarea invers (de la un ir ce conine un literal boolean sau
numeric) Ia acel literal se poate realiza folosind metodele puse Ia dispoziie de
clasele nfturtoare.

O alt clas util pentru lucrul cu iruri este clasa StringTokenizer,


care permite detectarea i extragerea de entiti dintr-un ir. Aceast clas va fi
prezentat n subcapitolul despre organizri ale datelor.

8e6e Prelucrri asupra tablourilor*


n acest subcapitol vom prezenta cteva faciliti oferite de Java pentru
unele prelucrri asupra tablourilor, cum ar fi sortarea elementelor tabloului sau
cutarea binar a unei valori n tablou (n cazul n care elementele tabloului sunt
deja sortate).
Aceste prelucrri au la baz o relaie de ordine total. Dac pentru tipurile
primitive ea este implicit, pentru tipurile referin (reamintim c elementele unui
tablou pot ft de orice tip) ea trebuie definit explicit.

Interfaa Cosnparator

Interfaa Comparator:
public interface Comparator
apare n pachetul java.util i n ea este anunat metoda:
public int compare(Object Obi, Object Ob2)
menit s compare cele dou argumente conform unei relaii de ordine totale,
specificate n implementrile metodei. Dac notm relaia de ordine prin <t atunci
rezultatul ntors trebuie s fie negativ, egal cu zero sau pozitiv, dup cum
118 8, FACILITI STANDARD

0 <02, = 2 sau 0>02. Cade n sarcina programatorului s defineasc


n mod corect relaia de ordine total.
Odat definit un comparator (un obiect al unei clase ce implementeaz
Com parator), el poate fi folosit n diferite contexte, de exemplu pentru sortarea
elementelor unui tablou pe baza unei relaii de ordine stabilit de programator.

Clasa Arrays

Clasa A rrays:
public class Arrays extends Object

apare n pachetul j a v a . u t i l i pune Ia dispoziie mai multe metode (toate publice


i statice) pentru prelucrri asupra tablourilor.
n cele ce urmeaz, prin t i p este desemnat orice tip primitiv.

Metodele de sortare sunt definite astfel:


v o id s o r t ( t i p [ ] t )
void sort(Object[] 0, Comparator c)
i realizeaz sortarea elementelor tabloului pe baza relaiei implicite de ordine
pentru tipurile primitive, respectiv pe baza comparatorului specificat ca argument.
Mai sunt utile i variantele:
void sort(fcip[] t, int p, int u)
v o id s o r t (O b j e c t [] O, i n t p , i n t u , Com parator c)
prin care se poate sorta numai poriunea din tablou cu indicii p . . u -1 . n acest caz
trebuie ca pentru tabloul ta b primit ca argument s fie verificat relaia
0<=p<u<=tab. le n g th , n caz contrar fiind lansat una dintre excepiile:
I lle g a lA r g u m e n tE x c e p tio n sau A rraylndexO u tO fB ou ndsE xception.

Metodele de verificare a egalitii a dou tablouri sau a dou poriuni ale


lor determin dac dou tablouri sunt egale, adic dac au acelai numr de
elemente i elementele de pe aceleai poziii sunt egale.
boolean equals(tip[] tl, tip[3 t2)
b o o le a n e q u a l s ( O b j e c t [] 0 1 , O b j e c t [] 0 2 , Com parator )
b o o le a n e q u a l s ( t i p [] tl, t i p [ ] t 2 t i n t p , i n t u)
b o o le a n e q u a l s ( O b j e c t [] 0 1 , O b j e c t [] 0 2 , i n t p , i n t u,
Com parator c)
cu aceleai precizri ca mai sus.

Metodele de cutare a unui element ntr-un tablou ordonat de elemente:


i n t b in a r y S e a r c h (Tip[] t, T ip x)
i n t b in a r y S e a r c h ( O b j e c t [] 0, Object x, Comparator c)
verific dac x este unul dintre elementele tabloului. n c a z a f i r m a ti v , e s t e ntoars
poziia pe care se afl x. n caz contrar, este ntoars valoarea (negativ!) -p -1 ,
unde p este poziia pe care ar trebui inserat x. n prima form, T i p este tipul unei
clase nfurtoare i nu este necesar un comparator explicit, dac relaia de ordine
8.7. Organizri ale datelor 119

cu care lucrm este cea uzual pentru tipul primitiv corespunztor. n a doua form
se specific explicit un comparator.

E x e m p l u l 3 , Este creat un tablou cu trei componente de tipul elem, care


definete doar dou cmpuri ntregi. Mai este folosit un comparator care specific
ordinea lexicografic pentru compararea obiectelor de tipul elem.

import java.util .*
class elem {
in t x i n t y;
elemfint i , in t j ) { x = i ; y = j }

class comp implements Comparator {


public int compare(Object
, Object ff} {
elem e = (elem)
elem f = (elem)ff
if (e.x==f.x ScSc e.y==f.y) return 0;
else if ( e .x<f.x || e.x==f.x && e.y<f
y ) return -1
else return 1;
}

class Compar {
public static void main(String[] s) {
elem[3 tab ^
{new elem(1,2), new elem(3,1), new elem(1,1));
comp c = new comp ()
Arrays.sort(tab,c);
for (int i=0 i<tab.lengthi++) {
System.out.println(tab[i] .x + 11 + tab[i] .y)
}

8.7. Organizri ale datelor


Pe lng tablouri, Java pune Ia dispoziie o larg varietate de organizri ale
datelor, nsoite de modaliti de gestionare a lor: adugare, tergere, regsire etc.
Prezentm ierarhia de interfee din pachetul j a v a . u t i l ce st la baza
diferitelor organizri ale datelor:

Collection
S e t
List
Map
Enumeration
120 8. FACILITI STANDARD

Interfaa Collection este rdcina ierarhiei de colecii din Java.


O c o le c ie este un grup de elemente, nu neaprat distincte.
Interfaa Collection nu are clase care o implementeaz direct. Ea anun
metode ca de exemplu add, remove, contains, isEmpty, size cu semnificaie
evident.
O m u lim e (corespunztoare interfeei Set) este o colecie care nu conine
duplicate i este menit s abstractizeze noiunea matematic de mulime.
O "Wt (corespunztoare interfeei List) este o colecie ordonat, eventual
cu duplicate. Ea anun n plus metode pentru extragerea unei subliste4 pentru
nlocuirea unui element de pe o anumit poziie cu un alt element etc.
O m a p a r e (corespunztoare interfeei Map) este o funcie (n sens
matematic), ce asociaz unei c h e i o anumit v a lo a r e . Funcia nu este neaprat
injectiv, deci mai multor chei li se poate asocia aceeai valoare. Att cheile, ct i
valorile sunt obiecte. O mapare permite trei abordri distincte, n funcie de:
mulimea de chei, colecia de valori sau mulimea de perechi (c h e ie , v a lo a r e ),
O e n u m e r a r e (corespunztoare interfeei Enumeration) permite ca un
obiect de acest tip" s genereze cte un element prin invocarea metodei
nextElement. Aceast interfa mai anun metoda hasMoreElements. De
exemplu clasa Vect rscare va fi prezentat pe larg n continuare, include metoda

elements care ntoarce un obiect de tip Enumeration, ce poate fi folosit de

exemplu pentru listarea elementelor unui vector v:


f o r ( E n u m e r a t i o n e = v.e l e m e n t s ( ) e . h a s M o r e E l e m e n t s ( ) ; )
S y s t e m . o u t . p r i n t l n ( e . n e x t E l e m e n t () + " " )

Dintre clasele care implementeaz interfeele de mai sus, enumerm


urmtoarele:
class LinkedList implements hist (pentru lucrul cu liste nlnuite)
class HashTable implements Map (pentru stocarea iregsirea informaiilor
folosind tabele de dispersie)
precum iclaseleVector i StringTokenizer, ce vor f
iprezentate ulterior.

O clas folositoare din pachetul java.util este urmtoarea:

class Collections extends Object


care pune la dispoziie diverse operaii asupra coleciilor (n special asupra listelor),
prin metodele sale statice. Aceast clas va fi i ea prezentat n continuare.

Clasa Vector:
public class Vector implements List

permite lucrul cu un tablou de elemente oarecare, dar cu multe faciliti


suplimentare. Un v e c to r (obiect de tip Vector) are dimensiune variabil, spre
deosebire de un tablou obinuit, care are lungime fix. ntr-un vector putem insera
pe orice poziie noi elemente, dimensiunea sa crescnd automat. De asemenea
putem extrage elemente din vector.
8.7i Organizri ale datelor 121

La fiecare moment de timp, vectorul feste caracterizat prin:


- tabloul curent asociat vectorului, n care sunt pstrate elementele
vectorului;
- capacitate: mrimea tabloului curent;
- lungime: numrul de elemente efective din vector. Lungimea este
totdeauna cel mult egal cu capacitatea, iar elementele efective apar pe primele
poziii ale vectorului (ncepnd cu poziia 0);
- increment: cantitatea cu care crete automat capacitatea vectorului atunci
cnd, a o operaie de inserare a unui nou element, lungimea este egal cu
capacitatea. Gestionarea incrementului se poate face att implicit, ct i explicit.

m Clasa V ecto r are urmtorii constructori:


Vector()
Vector(int c)
Vector(int c , i n t i)
prin invocarea cruia ia natere un vector vid (de lungime 0), pentru care putem
specifica (opional) o capacitate i un increment.
Cmpurile clasei sunt urmtoarele:
protected int elementCount;
protected Object[] elementData
reprezentnd lungimea vectorului, respectiv tabloul asociat vectorului.
Toate metodele clasei sunt publice.
n cele ce urmeaz vom numi indice valid un indice din intervalul
i .. lungime-1, unde i apare ca parametru n metodele ce urmeaz. La specificarea
unui indice nevalid, este lansat excepia A rraylndexO u tO fB oundsE xception.

Metodele ce modific vectorul sunt urmtoarele;


void. setElementAt (Object , int i)
adaug obiectul b pe poziia i , peste cel existent; i trebuie s fie un indice
valid;
v o id rem oveE lem en tA t(i n t i )
elimin elementul de pe poziia i i deplaseaz la stnga elementele de pe
poziiile urmtoare; i trebuie s fie un indice valid;
v o id in s e r t E le m e n t A t (O b ject Ob, i n t i )
deplaseaz la dreapta elementele de pe poziiile i . . lungime i insereaz
obiectul Ob pe poziia i; i trebuie s fie un indice valid;
void addElement(Object Ob)
adaug obiectul Ob !a sfritul vectorului;
boolean removeElement(Object Ob)
elimin, cu deplasarea la stnga a urmtoarelor elemente, prima apariie n
vector a obiectului Ob. Dac obiectul Ob nu apare n vector, efectul este nul.
Metoda ntoarce rezultatul cutrii;
void removeAllEleinents ()
elimin toate elementele vectorului.
122 8. FACILITI STANDARD

Metodele ca re exam in ea z con in u tu l v e cto ru lu i sunt urmtoarele:


int size()
ntoarce lungimea vectorului;
boolean isExnpty ()
verific dac vectorul este vid;
boolean contains(Object Ob)

verific dac obiectul Ob apare n vector;


int indexOf(Object Ob)
ntoarce prima poziie pe care Ob apare n vector, respectiv -1 dac Ob nu
apare n vector;
int lastlndexOf(Object Ob)
ntoarce ultima poziie pe care Ob apare n vector, respectiv -1 dac Ob nu
apare n vector;
Object elementAt(int i)
ntoarce elementul din vector de pe poziia i; i trebuie s fie un indice valid;
Object[] toArray{)
ntoarce un tablou cu elementele (efective ale) vectorului;
Object firstElement()
ntoarce primul element al vectorului;
Object lastEiement{)
ntoarce ultimul element al vectorului.
Ultimele dou metode lanseaz excepia NoSuchElementExcept io n
dac vectorul este vid.

Mai prezentm i metodele:


void setSize(int lung)
stabilete o nou lungime pentru vector. Dac lu n g > lu n g im e 9 se adaug
obiecte nule. Dac l\m g < lu n g im e , sunt eliminate elementele de pe poziiile
lu n g . J u n gim e;
boolean equals(Object Ob)
verific dac vectorul care a invocat metoda este egal cu Ob (se verific att
lungimea, ct i egalitatea elementelor corespunztoare).
E x e m p lu l 4 . P a rcu rg e re a p e n ivelu ri a g ra fu rlo r neorientate.
n capitolul 2 am prezentat un program pentru parcurgerea DF a grafurilor
neorientate, iar n capitolul 6 am prezentat un program pentru parcurgerea pe
niveluri a arborilor. Prezentm acum o implementare a parcurgerii pe niveluri a
unui graf neorientat oarecare. Pentru simplificare, vom considera c graful este
conex,

Parcurgerea pe niveluri a unui graf presupune alegerea unui vrf drept vrf
iniial i vizitarea vrfurilor grafului n ordinea distanelor lor fa de vrful iniial.
Prin v iz ita r e a unui vrf se nelege efectuarea unor prelucrri, ce depind de
problema concret, asupra vrfului. n cele ce urmeaz, parcurgerea unui vrf va
consta n scrierea numrului su de ordine.
5. 7. Organizri ale datelor 123

Parcurgerea pe niveluri este util de exemplu n situaiile n care cutm


vrful cel mai apropiat de vrful iniial i care are o anumit proprietate (evident, n
acest caz vizitarea vrfurilor include verificarea proprietii respective).
S considerm de exemplu urmtorul graf:

pentru care listele vecinilor vrfurilor sunt urmtoarele;


1,2,3}; L M A) Li={A} L3={0,5};
LMIX5}: L5={3,4,6} ; U=[5}.
Dac alegem vrful 0 drept vrf iniial, parcurgerea pe niveluri trebuie s
listeze vrfurile n ordinea: 0 1 2 3 4 5 6.

Pentru a evita vizitarea repetat a unui acelai vrf, vom ataa fiecrui vrf
o variabil v i ce are valoarea t r u e sau f a l s e dup cum vrfu a fost sau nu
vizitat. Algoritmul folosete o coad C:

Vi f a l s e , pentru orice vrf i


C<= 0 ; C <= 0 {vrful iniial}; v < t r u e
w h ile ^ 0
i C; viziteaz i
f o r toi je L i
i f ! Vj th e n C <==Vj vj < t r u e
e n d if
n d fo r
n d w h ile

Programul are aceeai structur ca cel din capitolul 2, menionat mai sus.
Numele casd d f a fost schimbat n n i v e l . n tabioul temp, al cnii numr curent
de elemente este ntemp, sunt citite succesiv listele vecinilor vrfurilor. Metoda
p a rc u rg implementeaz algoritmul de mai sus.
import java.util .*
clasa nivel {
CIPRIAN COMA
i n t [][3 m a t i n t n Nr 4 b
nivel) {
int[] temp int ntemp; double d
10.write("n= "); n = (int) 10.read()
mat - new int[n][]; temp = new int[n ]
for (int i=0; i<n; i++) {
' C K w rite " V e c in ii l u i " -f 1 ")
124 8. FACILITI STANDARD

ntemp = 0; d = IO.read ();


while( ! Double.isNaN(d))
C te m p [n te m p + + ] (in t) d; d = 1 0 . r e a d () }
m a t [ i ] ~ new i n t [ n t e m p ] ;
for {int j=0; j<ntemp; j++) mat[i][j] = temp[j ]
}
10.writeln("*********"};
}
void parcurg() {
boolean[] v = new boolean[n]; Integer Int int i,j,;
Vector coada = new Vector();
coada.addElement(new Integer{0 ))v[3 = true;
while { ! coada.isEmpty() ) {
Int = (Integer) coada.firstElement ()
coada.removeElementAt(0);
i = Int.intValue() 1 0 . write(i+H\t")
for (k=0 k<mat[i].length; k++) {
j = mat[i][k];
if( ! v(j] {
coada.addElement(new Infceger(j ))v[j]=fcrue;
}

class Niveluri {
public static void main(StringE] s) {
nivel 0b ~ new nivel Ob.parcurg{);
}
}

Pentru implementarea cozii a fost folosit vectorul coada. Conform


disciplinei de coad, extragerile din vector s-au fcut de pe poziia 0, iar adugrile
s-au fcut ia sfritul vectorului.
S observm c pentru a introduce n vector numerele ataate vrfurilor, a
fost nevoie s apelm la clasa i n t e g e r , deoarece vectorii pot avea ca elemente
doar obiecte i nu tipuri primitive.

Clasa Stack:
p u b lic c l a s s S ta c k e x te n d s V e c to r
adaug clasei V e c to r facilitile uzuale de lucru cu stive.

Clasa S ta c k are un constructor fr parametri, care creaz o stiv vid,


precum i urmtoarele metode publice:
Object push(Object 0b)

adaug obiectul b n vrful stivei i l ntoarce ca rezultat;


8,7, Organizri ale datelor 12S

b oolean empty () '


verific dac stiva este vid;
in t s e a r c h (O b je c t Ob)
dac obiectul b nu apare n stiv, este ntoars valoarea -1 . Dac Ob apare n
stiv, este ntoars poziia lui Ob relativ la vrful stivei (se consider c vrful
stivei apare pe poziia 1).
Object pop)
elimin obiectul din vrful stivei i l ntoarce ca rezultat;
O bject p e e k (O b je c t Ob)
ntoarce obiectul din vrful stivei, fr a-1 elimina din stiv.
Ultimele dou metode lanseaz excepia E m p tyS tack E xcep tion n cazul n care
stiva este vid.

Clasa StringTokenizer:
public class StringTokenizer extends Object
im p lem en ts E num eration
furnizeaz metode pentru a extrage entiti dintr-un ir. Entitiie sunt separate ntre
ele prin unul sau mai multe caractere, cu rol de delimitatori. Delimitatorii implicii
sunt ' \ t \ ' \ n ' , ' \ r ' i ' \ f ' putem ns specifica explicit o mulime de
delimitatori. De asemenea putem alege ntre a considera sau nu un delimitator ca
fiind o entitate.
Detectarea entitilor se face secvenial de la nceputul irului spre sfritul
su.

Observaie. Desprirea unui ir n entiti se poate face i apelnd la


metodele clasei str e a m T o k e n iz e r folosit n clasa IO prezentat n ai doilea
capitol. Aceast clas detecteaz entiti mai "fine" (de exemplu literali) i va fi
prezentat n capitolul dedicat facilitilor de intrare/ieire.

Constructorii clasei StringTokenizer sunt urmtorii:


public StringTokenizer(String s)
public StringTokenizer(String si String delim)
public StringTokenizer{String s, String delim, boolean b)

unde s este irul ce urmeaz a fi separat n entiti, delim este un ir de caractere


ce cuprinde mulimea de separatori aleas de utilizator, iar b permite s alegem
ntre a considera sau nu delimitatorii drept entiti.

Principalele metode puse la dispoziie de clasa StringTokenizer sunt:


public boolean hasMoreTokens{)
public String nextToken()

unde hasM oreTokens verific dac mai exist entiti n ir dup poziia curent,
iar nextT oken ntoarce urmtoarea entitate; aceast a doua metod lanseaz
excepia N oSu ch E lem en tE xcep tion dac dup poziia curent nu mai urmeaz
nici o entitate.
126 8. FACILITI STANDARD

Modalitatea tipic de utilizare a acestei clase pentru un ir s, n ipoteza c


suntem "mulumii" cu delimitatorii implicii i nu dorim s-i considerm ca
entiti, este urmtoarea:

StringTokenizer st =* new StringTokenizer (s);


String e;
while (st.hasMoreTokens) {
e = st.nextToken()prel(e);
}
unde metoda prel realizeaz o prelucrare a entitii (subirului) e, specific
aplicaiei curente.
Aa cum am menionat mai sus, clasa StringTokenizer este mai
restrictiv dect StreamTokenizer, dar poate fi folosit cu succes i pentru
detectarea literalilor, cnd cunoatem precis succesiunea tipurilor lor n ir i
apelm ia metodele claselor nfurtoare.

Exemplul 5. Dac irul supus prelucrrii conine numai literali ntregi,


acetia pot fi obinui astfel:
import java.util.*
class Test {
public static void main(String[3 sir) {
String s = " 23 \t 45\n" e=/
StringTokenizer st = new StringTokenizer(s)
while( st.hasMoreTokens() ) {
e = st.nextToken(); IO.writeln(""^Integer.parselnt(e))
}
}
}

Clasa collections

Clasa C o l l e c t i o n s din pachetul ja v a . u t i l :


public class Collections extends Object
pune la dispoziia utilizatorului metode publice i statice pentru operaii asupra
coleciilor, dintre care menionm urmtoarele:

v o id reverse( L is t l i s t a ) :
inverseaz ordinea elementelor din list;
v o id s h u f f l e ( L i s t l i s t a ) :
permut aleator ordinea elementelor din list;
v o id c o p y ( L i s t l i s t a i , L i s t l i s t a 2 )
copiaz l i s t a i n l i s t a 2 ; u
v o id sort ( L is t l i s t a . Comparator c ) :
sorteaz, prin metoda sortrii prin interclasare i conform ordinii stabilite prin
comparatorul c, lista primit ca argument;
8.7. Organizri ale datelor 127

int binarySearch(List lista. Object x, Comparator c):

folosete metoda cutrii binare pentru a verifica dac obiectul x apare n lista
l i s t a , ordonat conform comparatorului c. n caz afirmativ, este ntoars
poziia pe care se afl x. n contrar, este ntoars valoarea (negativ!) - p -
1, unde p este poziia pe care ar trebui inserat x.
Object min(Collection col, Comparator comp):

ntoarce cel mai mic element din list (conform ordinii stabilite prin
comparatorul c);
Object max(Collection col, Comparator comp):
ntoarce cel mai mare element din list (conform ordinii stabilite prin
comparatorul c).
Pentru ultimele patru metode exist i varianta de a nu specifica explicit un
comparator. Aceast variant nu este aplicabil n general, deoarece la ncercarea
de a compara dou obiecte nu e clar modalitatea de comparare i drept urmare va
fi lansat excepia ClassCastException. Varianta poate fi totui folosit de
exemplu cnd elementele din list au acelai tip i anume o clas nfurtoare.

Exemplul 6. Citim succesiv de la intrare cte dou numere ntregi x i y.


Dac este diferit de 0, construim un obiect de tipul elem (vezi Exemplul 3), iar n
caz contrar construim un obiect de tipul I n t e g e r pe baza valorii lui x. Citirea, i
deci crearea de noi obiecte, se oprete imediat ce pentru x am citit valoarea 0.
Dorim s sortm obiectele folosind metoda sortrii prin inserie binar. Pentru
compararea a dou obiecte folosim urmtoarele reguli:
- dac ambele sunt de tipul elem, se folosete ordinea lexicografic, aa
cum am procedat i n Exemplul 3\
- orice element de tip i n t e g e r este considerat mai mic dect orice obiect
de tipul elem;
- pentru dou elemente de tipul i n t e g e r se folosete ordinea natural a
valorilor lor primitive.

Pentru rezolvare, vom introduce succesiv obiectele create ntr-un vector Y


i anume prin inserie binar: prin invocarea metodei binarySearch a clasei
Collections cu comparatorul c corespunztor, obinem poziia din V unde
trebuie inserat noul obiect; apoi inserm obiectul pe acea poziie. S observm c
n loc de vector nu putem folosi un tablou, deoarece elementele nu au acelai tip; n
plus tablourile au dimensiune fix, deci nu putem efectua inserarea. Pentru
detectarea tipului real al elementelor lui V apelm la operatorul instanceof.

Programul corespunztor este urmtorul:


import j a v a . util.*; .
class elem {
int x,y
elem(int x ,int y) { this.x=x this.y=y; }
void print() { IO.writeln(x + " " +y); }
}
128 8. FACILITI STANDARD

class comp implements Comparator {


public int compare{Object
, Object ff) {
boolean bl =
instanceof elem,
b2 = ff instanceof elem;
if(bl && b2) {
elem e = (elem); elem f = (elem)ff
if (e.x==f.x && e.y==f.y) return 0
else if ( e .x<f.x || e.x==f.x && e.y<f.y ) return ~1
else return 1;

else if(b2) return -1;


else if(bl) return 1
else return
((Integer)).compareTo((Integer)ff);

}
class Sort {
public static void main(String s) {
int x,y,poz Object Ob; comp c = new comp)
Vector V = new Vector();
x = (int) XO.readU; = {int} 10.read (}
while { x != 0 ) {
if(y !~ 0) Ob = new elem(x,y )
else Ob = new Integer(x)
poz = Collections.binarySearch(V,Ob,c);
if (poz<0) poz = -poz-l V.insertElementAt(Ob#poz)
x = (int) 10.read() ; ~ (int) .;
}

for(int 1=0 i<V.size( ) i++} {


Ob = V,elementAt{ij;
if(Ob instanceof elem) ((elem)Ob).print();
else 10.writeln{ ((Integer)Ob).intValue{) +
} *

8.8. Lucrul cu clase. Clasele class i Method


Aa cum tim, clasa reprezint unitatea fundamental de programare n
Java, iar obiectele de tipul unei clase reprezint instrumentul folosit pentru
invocarea metodelor clasei. Pn acum atenia principal a fost ndreptat asupra
modului n care acioneaz obiectele, cu scopul de a ndeplini dezideratele
programatorului.
Java permite ns s lucrm i cu clase, nu numai cu instanieri ale lor.
8.8, Lucrul cu clase. Clasele C lass i Method 129

n centrul lucrului cu clase st clasa C la s s , care apare n pachetul


j a v a . la n g i este declarat prin:
p u b lic f i n a l c l a s s C la s s e x te n d s O b ject
Un / (obiect de tip C la s s ) este o reprezentare a unei clase
dintr-o aplicaie n curs de executare. n reprezentare sunt incluse informaii despre
numele clasei, modificatorii si, constructorii, cmpurile i metodele sale etc.
Un obiect clas poate fi obinut prin invocarea metodei g e t c l a s s a clasei
C la ss. De exemplu prin:
C la ss C_Ob = O b . g e t c l a s s ()
obinem obiectul clas COb ce sintetizeaz informaii despre clasa a crei
instaniere este obiectul Ob. Este important de precizat c obiectul C_Ob
sintetizeaz informaii despre clasa ce constituie tipul real al obiectului ob.
Informaiile despre clasa ce constituie tipul real al lui Ob se pot obine prin
invocarea, prin intermediul acestui obiect, a metodelor clasei C lass.

Clasa C la s s nu are constructori i nici cmpuri.


Dintre metodele, toate publice ale clasei C la s s prezentm deocamdat
doar urmtoarele:
S tr in g gefcName()
ntoarce numele clasei care este asociat obiectului curent (obiectului clas ce
a invocat metoda);
b o o lea n i s ln s t a n c e ( O b j e c t Ob)
este echivalentul dinamic al operatorului in s t a n c e o f : ntoarce tr u e dac i
numai dac obiectul Ob poate fi convertit la tipul obiectului curent;
S tr in g g e t S u p e r C la s s ()
ntoarce numele superclasei asociate obiectului curent;
C la s s [] g e t l n t e r f a c e s ()
ntoarce un tablou cu interfeele implementate de clas, n ordinea n care apar
n clauza im plem ents;
C la s s [ g e t C I a s s e s {)
ntoarce un tablou cu clasele i interfeele publice care sunt membri ai clasei
repezentate de obiectul curent;
in t g e t M o d i f i e r s ()
ntoarce modificatorii clasei, codificai ca un ntreg (vezi documentaia).

E x e m p lu l 7. Urmtorul program:

in t e r f a c e I { }
c l a s s A im p lem en ts I { }
c l a s s e x te n d s A { }
c l a s s C la sa {
s t a t i c v o i d p r i n t ( C l a s s C) {
C la s s D = C. g e t S u p e r c l a s s ()
10.writeln(C.getName()+" +D.getName())
130 H. FAC1UT1 STANDARD

public static void main(String[3 sir) {


A Ob = new A {)
Obi = new A(); Class Cl = .getClass(); print(Cl);
A ObA = new (); Class C - ObA.getClass(); print(C);
10.writeln("" + C .islnstance(Ob ))
ObA = new A ()C ()print(C)
= ObA.getClass
10.writeln("" + C.islnstance(Ob))

produce la ieire:
A java.lang.Object
BA
false
A java.Object
true

Clasa Class mai conine i metode care ntorc i informaii despre


constructorii, cmpurile i metodele clasei reprezentate de obiectul curent care
invoc aceste metode. Aceste informaii sunt de tipurile claselor din urmtoarea
ierarhie din pachetul java. lang.reflect:

Member (interfa)
Constructor
Field
Method

Vom restrnge prezentarea la clasa Method,

Clasa Method este declarat prin:


final class Method implements Member

Un obiect de tip Method constituie reprezentarea unei metode i


furnizeaz, prin invocarea metodelor acestei clase, informaii despre metoda
asociat obiectului. Clasa Method nu are constructori, dar un obiect de acest tip
poate fi creat prin invocarea metodelor getMethod i getMethods ale clasei
Class
Method[] getMethods()

ntoarce un tablou coninnd obiectele de tip Method asociate metodelor ce


sunt membri publici ai clasei reprezentate de obiectul curent;
Method getMethod(String nume, Class[] tipuri)

ntoarce obiectul de tip Method asociat metodei cu numele nume i signatura


tipuri ce este membru public al clasei reprezentate de obiectul curent. Dac

metoda cutat nu exist, este lansat excepia NoSuchMethodException.

Urmtoarele metode ale clasei Method sunt toate publice i furnizeaz


informaii despre metoda asociat obiectului curent:
H.S. Lucrul cu clase. Clasele C la s s i Method 131

S tr in g getN am e()
ntoarce numele metodei;
in t g e t M o d i f i e r s ()
ntoarce modificatorii metodei, codificai ca un ntreg; pentru decodificare
trebuie folosit clasa M o d ifie r (vezi documentaia);
C la ss g e tR e tu r n T y p e ()
ntoarce tipul rezultatului produs de metod;
C la s s [] g e tP a r a m e te r T y p e s{)
ntoarce signatura metodei;
C la s s [3 g e tE x c e p tio n T y p e s ()
ntoarce un tablou cu tipurile excepiilor declarate de metod.

Prezentm i o ultim, dar foarte important metod a clasei Method:


Object invoke{O bject Ob, O b je c t[] args)
care realizeaz invocarea metodei reprezentat de obiectul curent; b este obiectul
care invoc metoda, iar argumentele sunt sintetizate n tabloul args. Pentru
metodele statice, Ob este ignorat.
Metoda invoke poate lansa diferite excepii, pe care nu Ie vom enumera
aici de exemplu n situaii ca: Ob nu este n msur s invoce metoda, a rg s nu
coincide cu signatura metodei, obiectele din arg s nu pot fi convertite la tipurile
din signatura metodei etc.

E x e m p l u l 8 . Exemplul i propune s furnizeze un mecanism prin care,


cunoscnd irul de caractere ce reprezint numele unei metode, s invoce acea
metod.
Prezentm programul, n care (pentru simplificare) am folosit calea
nerecomandat de a nu identifica toate excepiile ce pot fi lansate.
Unitatea de compilare I n v o c M e t . java:
import java.lang.reflect.Method;
public class XnvocMet {
public static void invoc(Object Ob, String nume,
.Object[] args) throws Exception {
Class ObC - Ob.getClass
Method met=null
Class" argsTypes = new Class [args .length]
for (int i=0 i<args.length i++)
argsTypes[i]-args[i}.getClass{ )
met ~ ObC.getMethodinume^rgsTypes);
met.invoke(Ob,args);
}
}

Unitatea de compilare Metoda.java:


c la s s C { -
public void rnetl (){ IO.writln ("1");)
132 8. FACILITI STANDARD

public void met2(Integer i)


{ IO.writeln{ "2 "-i .toString)); }
}
public class Metoda {
public static void main{String[} sir) throws Exception {
C Ob = new CO;
Object[] arg = new 0bject[ 3;
InvocMet.invoc(Ob,HmetH+1,arg )
Integer Int = new Integer(55>;
arg = new Object[1]; arg[0] = Int;

nvocMet.invoc (Ob
,"met
+2 arg> ;

Metoda invoc din clasa InvocMet prevede urmtoarele aciuni:


- primete un obiect Ob, numele nume al unei metode i un tablou a r g s de
obiecte; '
- creeaz obiectul clas Obc ce reprezint tipul iui Ob;
- pe baza tabloului a rg s , construiete n tabloul arg sT y p es o signatur i
atribuie elementelor acestui tablou valoriie din args;
- obine obiectul met de tipul Method corespunztor metodei ce trebuie
invocat, pe baza numelui su i a signaturii construite;
-prin "met.invoke (Ob, args) " realizeaz invocarea dorit.

8.9. Clasa System

Clasa System apare n pachetul j a v a . lang:


public final class System extends Object
i cuprinde cmpuri i metode publice i statice utile.

Cmpurile (constantele) clasei sunt urmtoarele:


final InputStream in
final PrintStream out
final PrintStream err
i corespund fluxurilor de intrare, ieire i de eroare (n care vor fi tiprite mesajele
de eroare). n mod standard, in corespunde tastaturii, iar o u t i e r r corespund
ecranului.
Amnunte despre InputStream i PrintStream pot fi gsite n capitolul
referitor la facilitile de intrare/ieire.

Dintre metodele clasei menionm urmtoarele:


void setln(InputStream in)
fluxul de intrare devine in;
void setOut{PrintStream out)
fluxul de ieire al datelor devine o u t;
8.9. Clasa System 133

void setErr(PrintStream out)


fluxul de ieire al mesajelor de eroare devine out;
long currentTixneMillis ()
ntoarce timpul curent, relativ la 1 ianuarie 1970, n milisecunde;
void exit{int s)
termin aplicaia curent.

Alte metode importante ale clasei sunt cele ce vizeaz proprietile


sistemului i gestionarul de securitate. Ne mrginim deocamdat ia a semnala
existena lor, dar vom reveni asupra acestor aspecte n ultimele capitole ale crii.
F IR E D E E X E C U T A R E . P R O G R A M A R E
f PARALEL I CONCURENT

Programarea obinuit presupune existena unui procesor (dispozitiv de


executare a instruciunilor); instruciunile unicului program sunt executate
secvenial de ctre unicul procesor existent.
n viaa real asistm n permanen la mai multe aciuni ce se desfoar
n acelai timp. Unele dintre ele sunt independente, altele au un grad mai mic sau
mai mare de dependen: ncep n acelai timp, se ateapt unele pe altele, sunt
serializate etc.
Analog, calculatoarele moderne realizeaz, att prin resurse software ct i
hardware, desfurarea concomitent a mai multor aciuni. Posibilitatea de a lansa
i gestiona mai multe fire de executare (procese) este principala noiune nou
introdus de sistemul de operare Windows.
Aciunile ce se: desfoar concomitent pot fi foarte variate: programe
"tradiionale", secvene de animaie, sunet etc. n acest capitol vom presupune c
aciunile sunt secvene de instruciuni.

Conceptual, se presupune prezena pe sistemul gazd a mai multor


procesoare.
Pentru prelucrarea separat a fiecrei aciuni, va fi lansat un fir de
executare, care va prelua sarcina de a executa aciunea respectiv; n cazul ideal,
acela n care exist un procesor liber, aceast sarcin este materializat de un astfel
de procesor. n cazul existenei unui singur procesor sau (mai general) atunci cnd
numrul de aciuni ce trebuie executate concomitent depete numrul de
procesoare libere, executarea concurent este simulat: unitatea central aloc
pentru fiecare fir de executare cuante de timp.

Elementele legate de programarea firelor de executare fac parte integrant


din limbajul Java, n acest mod compilatorul Java putnd "vedea" aceste fire. De
aceea este justificat afirmaia c Java este un mediu de executare.
Chiar dac aplicaia nu apeleaz la fire de de executare, n fapt exist dou
astfel de fire: cel curent i cel folosit de colectorul de reziduuri.
9J. Crearea firelor de executare 135

9.1. Crearea firelor de executare

Clasa Thread

O prim modalitate de a crea i lansa n executare fire (de executare) este


de a folosi clasa Thread din pachetul java.lang:
public class Thread extends Object implements Runnable
unde despre interfaa Runnable vom vorbi mai jos.

Pentru a crea un fir de executare, trebuie nceput prin a crea un obiect de


tipul Thread:
Thread fir = new Thread);

Dup ce obiectul este creat, el poate fi configurat i apoi se poate trece la


executarea sa. Configurarea cuprinde elemente ca de exemplu precizarea unui
nume, a unei prioriti etc. Cnd firul este gata de executare, se invoc metoda sa
s t a r t fr argumente. Ca urmare firul de executare ncepe s execute metoda sa
run.
Cnd metoda ru n se ncheie, firul de executare se termin.
Prezentm n continuare schema general a strilor n care se poate afla un
proces (fir ds executare).

Un fir (de executare) este gata de executare dac ndeplinete toate


condiiile pentru a se trece la executarea sa, dar nu i s-a alocat nc un procesor;
cnd un procesor liber preia firul, acesta trece n starea n curs de executare.
Blocarea unui fir de executare poate fi realizat pe baza unei condiii (de exemplu
un semafor); ca urmare firul trece n starea blocat. La deblocarea sa, realizat prin
mecanisme dintre care unele vor fi prezentate n continuare, el revine n starea gata
de executare, ateptnd ca un procesor s devin liber i s reia executarea sa.

Metoda run din clasa Thread nu prevede vreo aciune. De aceea trebuie
ca programatorul s extind clasa Thread i s rescrie (suprapun) metoda run,
preciznd aciunea dorit.

Se impun cteva precizri privind firele de executare.


Firul principal de executare fo