Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

523
1 Severin BUMBARU PROGRAMAREA ORIENTATĂ PE OBIECTE ÎN LIMBAJUL JAVA Editura Fundaţiei Universitare "Dunărea de Jos" - Galaţi, 2002

description

programming

Transcript of Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Page 1: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

1

Severin BUMBARU

PROGRAMAREA ORIENTATĂ PE OBIECTE

ÎN LIMBAJUL JAVA

Editura Fundaţiei Universitare

"Dunărea de Jos" - Galaţi, 2002

Page 2: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

2

Severin Bumbaru

Programarea orientată pe obiecte în limbajul Java

Editura Fundaţiei Universitare "Dunărea de Jos" din Galaţi - 2002

ISBN 973-8352-53-3

Referent ştiinţific: prof.dr.ing. Cornelia NOVAC

Page 3: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

3

CUPRINSUL

0. Introducere 4

1. Scurtă prezentare a platformei Java şi a programării orientate pe

obiecte

7

2. Şiruri. Elemente lexicale ale limbajului Java. Variabile şi tipuri de

date primitive

27

3. Expresii. Instrucţiuni simple şi instrucţiuni structurate. Tratarea

excepţiilor în limbajul Java

66

4. Tipul referinţă. Utilizarea claselor din pachetul java.lang. Tablouri.

Utilizarea parametrilor din linia de comnadă

99

5. Declararea claselor 137

6. Caracteristicile obiectelor şi claselor şi reflectarea lor în declararea

claselor. Interfete. Clase imbricate

163

7. Interfeţe utilizator grafice şi programarea orientată pe evenimente 198

8. Componentele grafice din JFC/Swing 240

9. Utilizarea ferestrelor de dialog. Desenarea 267

10. Introducere în HTML. Crearea şi utilizarea de appleturi 291

11. Fluxuri de intrare/ieşire şi fişiere 306

12. Fire de execuţie 333

Index de clase şi interfeţe 363

Bibliografie 458

Anexă : Fişierele sursă ale claselor date ca exemple 460

Page 4: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

4

Introducere

Obiectivele cursului 4

Cum este structurat acest curs 5

Recomandări privind modul de lucru 5

Obiectivele cursului

Cursul "Programare orientată pe obiecte în limbajul Java" se adresează studenţilor profilelor

"Ingineria sistemelor şi calculatoarelor" şi "Electronic" de la Universitatea "Dunărea de Jos"

din Galaţi şi îşi propune următoarele obiective:

însuşirea conceptelor de bază ale programării orientate pe obiecte;

însuşirea limbajului de programare Java;

formarea deprinderilor privind realizarea de aplicaţii şi miniaplicaţii în limbajul Java;

iniţiere în utilizarea bibliotecilor de clase Java;

însuşirea proiectării interfeţei grafice utilizator şi a programării orientate pe

evenimente;

iniţiere în utilizarea fluxurilor de date şi fişierelor în limbajul Java;

iniţiere în programarea concurentă (realizarea de programe cu mai multe fire de

execuţie).

Cursul poate fi folosit şi de toţi cei care doresc să se iniţieze în utilizarea limbajului Java şi în

programarea orientată pe obiecte.

Page 5: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

5

Cum este structurat cursul

Cursul este structurat ca un ciclu de 12 lecţii, care cuprind atât prezentarea conceptelor care

trebuie însuşite de studenţi, cât şi indicaţii asupra lucrărilor practice şi exemple de întrebări

pentru verificarea cunoştinţelor.

Cursul se prezintă în format electronic (hipertext), fiind alcătuit dintr-un ansamblu de pagini

legate între ele. Din punct de vedere al obligativităţii citirii şi însuşirii cunoştinţelor conţinute,

aceste pagini sunt situate pe patru niveluri, care difera între ele prin culoarea fundalului

(background):

Nivelul 0: Informaţii cu caracter organizatoric. Trebuie citite şi respectate, dar nu constituie

subiect de examinare.

Nivelul 1: Concepte de bază cu caracter obligatoriu. Fără cunoaşterea lor nu poaste fi

promovată această disciplină.

Nivelul 2: Concepte necesare pentru o bună cunoaştere a programării orientate pe obiecte şi

a limbajului Java. Constituie subiecte de verificare şi sunt luate în consideraţie la stabilirea

notei.

Nivelul 3: Documentaţie necesară pentru elaborarea aplicaţiilor şi miniaplicaţiilor în

limbajul Java: descrierea unor clase si interfete, prezentarea pachetelor s.a. Nu se cere

memorarea acestei documentaţii, dar la sustinerea programelor elaborate trebuie sa

cunoaşteti semnificaţia tuturor componentelor utilizate.

Nivelul 4: Informaţii suplimetare, utile pentru o bună întelegere şi însuşire a disciplinei, dar

care nu constituie subiecte de examinare.

Cursul conţine, de asemenea, un index de clase si interfeţe, în care se dau legături către pagini

care prezintă unele clase şi interfeţe din bibliotecile platformei Java (Java API) utile în

realizarea aplicaţiilor.

Recomandări privind modul de lucru

Cercetările în domeniul psihologiei educaţionale au dus la concluzia că învăţarea este

eficientă atunci când studentul contribuie activ, analizând critic materialele studiate,

experimentând şi susţinându-şi opiniile în faţa altora.

În consecinţă, pentru o bună însuşire a acestei discipline, vă recomandăm:

să lucraţi în echipă;

fiecare membru al echipei, după ce şi-a însuşit conceptele de bază ale unei lecţii:

o propune şi realizează experimente pentru clarificarea acestor concepte;

o discută cu colegii cele constatate în urma experimentelor efectuate;

Page 6: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

6

membrii echipei îşi împart între ei temele de aplicaţii şi miniaplicaţii primite la

laborator, concep şi realizează aceste aplicaţii (miniaplicaţii);

la elaborarea aplicaţiilor şi miniaplicaţiilor, folosiţi atât acest curs, cât şi alte surse de

documentare, în special documentaţia originală;

dacă, în timpul realizarii aplicaţiei, întâmpinaţi dificultăţi, consultati-vă cu colegii sau

cu cadrul didactic îndrumător. Faceţi aceasta numai dacă sunteţi convins că nu puteţi

rezolva singur;

după realizarea aplicaţiei, explicaţi colegilor de echipă cum aţi realizat-o şi ce

dificultăţi aţi avut;

deşi accentul se pune pe experimentare, atragem atenţia că obiectivul principal al

cursului este însuşirea conceptelor care sunt puse în evidenţă în fiecare lecţie. Numai

că această însuşire de concepte se realizează nu doar prim simpla citire a materialului

documentar, ci prin experimentare, dezvoltare de aplicaţii şi schimb de opinii.

Page 7: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

7

Scurtă prezentare a platformei Java şi a

programării orientate pe obiecte

O prima cunoştinţă cu limbajul şi platforma Java 7

Scurt istoric al limbajului şi platformei Java 17

Introducere în programarea orientată pe obiecte 18

Prezentarea principalelor tipuri de produse software care se pot scrie în

limbajul Java

19

Şablonul unei aplicaţii simple în limbajul Java 20

Aplicarea acestui şablon la realizarea unei aplicaţii simple, în care se

afişează un text pe ecran;

21

Editarea, compilarea şi execuţia aplicaţiilor Java 21

Întrebări 26

O primă cunoştinţă cu limbajul şi platforma Java

În informatică, Java este

un limbaj de programare, ale cărui calităţi i-au permis răspândirea rapidă, fiind în

prezent unul din limbajele cele mai larg folosite. Limbajul este simplu, orientat pe

obiecte, robust, sigur, portabil, interpretat, neutru faţă de arhitectură, concurent,

dinamic si distribuit;

un mediu de execuţie pentru aplicaţiile Java, numit în prezent în engleză "Java 2

Runtime Environment", care conţine maşina virtuală Java şi un nucleu al bibliotecilor

de clase Java;

o platformă pentru dezvoltarea de aplicaţii în care se foloseşte limbajul Java, care se

numeşte în prezent în engleză "Java 2 Platform" şi conţine:

o compilatorul Java (Java Compiler);

o maşina virtuală Java (Java Virtual Machine);

o bibliotecile de clase Java (Java Class Libraries);

o vizualizatorul de appleturi Java (Java AppletViewer);

o depanatorul Java (Java Debbuger) şi alte instrumente de dezvoltare;

o documentaţia;

o tehnologie software puternică şi modernă, care corespunde cerinţelor lucrului în

reţele de calculatoare.

Există, desigur, şi alte semnificaţii ale cuvântului Java, care însă nu au legatură directă cu

informatica.

Limbajul Java

Java este un limbaj de programare de utilizare largă, care are următoarele proprietăţi:

Page 8: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

8

este simplu: deşi sintaxa se aseamănă cu cea a limbajelor C/C++, au fost eliminate

acele aspecte care constituiau surse de erori sau produceau confuzii;

este orientat pe obiecte: în limbajul Java nu este posibil să se scrie aplicaţii care nu

respectă normele programării orientate pe obiecte;

este robust: programele scrise în Java sunt foarte fiabile, deoarece sunt prevăzute

numeroase verificări atât la compilare, cât şi în timpul executării;

este sigur: fiind destinat lucrului în reţele de calculatoare, la realizarea sistemului Java

s-a avut în vedere necesitatea ca programele să nu poată aduce daune calculatoarelor

pe care rulează, cum ar fi accesul neautorizat la informaţie sau chiar distrugerea

acesteia;

este portabil, adică programul poate fi mutat de pe un calculator pe altul, de alt tip

hardware şi/sau cu alt sistem de operare;

este compilat şi interpretat: programul sursă, scris în limbajul Java, este translatat de

către compilatorul Java într-un program intermediar sub formă de cod de octeţi

(engleza: bytecode). În timpul execuţiei, acest cod de octeţi este interpretat de către

maşina virtuală Java, care conţine un interpretor;

este neutru faţă de arhitectură: codul de octeţi generat de compilatorul Java nu

depinde de arhitectura echipamentului pe care acesta va fi executat, deoarece el nu

este executat direct de către procesorul hardware al acestui echipament, ci este

interpretat de către maşina virtuală Java;

permite programarea concurentă: în limbajul Java se pot scrie programe cu mai multe

fire de execuţie (engleza: multithreading), care pot fi executate simultan şi

sincronizate;

este dinamic, deoarece legarea între ele a claselor şi obiectelor nu se face static (la

compilare), ci dinamic (în momentul execuţiei);

este distribuit, adică permite realizarea de programe utilizabile în reţele heterogene

(care conţin calculatoare de tipuri diferite);

În enumerarea de mai sus, care nu este nicidecum completă apar, probabil, şi unii termeni

care vă sunt, deocamdata, neclari sau necunoscuţi. Unii din aceşti termeni vor fi clarificaţi

chiar în acest capitol, alţii - în capitolele următoare.

Atenţie! Deşi sintaxa limbajului Java se aseamănă cu cea a limbajelor C sau C++, Java nu

este C. Pe parcursul lecţiilor următoare vom atrage atenţia programatorilor de C/C++ asupra

principalelor deosebiri dintre Java şi aceste limbaje.

Simplificări făcute în Java faţă de C/C++

Deşi sintaxa limbajului Java a fost inspirată de cea a limbajelor C şi C++, autorii limbajului

Java au eliminat acele aspecte care produceau dificultăţi programatorilor, constituind surse de

erori şi confuzii. Dintre acestea menţionăm:

reducerea numărului de tipuri de date primitive prin eliminarea tipurilor fără semn

(unsigned);

introducerea tipului de date boolean, astfel încât datele logice să nu se mai confunde

cu cele întregi;

şirurile de caractere nu mai sunt tablouri, ci obiecte ale clasei String;

tablourile sunt ele însele obiecte;

în timpul execuţiei se verifică dacă indicele se încadrează în dimensiunea tabloului şi

se generează o excepţie în caz contrar;

Page 9: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

9

s-au eliminat pointerii şi operaţiile cu pointeri, menţinându-se numai tipul referinţă

din C++;

s-a renunţat la supraîncărcarea operatorilor;

limbajul este strict tipizat, adică se verifică atât la compilare, cât şi în timpul execuţiei

(în operaţiile de atribuire şi de calcul şi la transferul de parametri către subprograme),

corectitudinea tipurilor de date utilizate şi se semnalează excepţiile;

s-a renunţat la moştenirea multiplă (care există în C++), menţinându-se numai

moştenirea simplă. Ca urmare, toate clasele formează o ierarhie unică, avand ca

radacină clasa Object;

distrugerea obiectelor care nu mai sunt necesare se face automat, de către un "colector

de reziduuri" (în engleză: garbage collector), deci nu mai trebuie făcută prin program.

Neutralitatea arhitecturală

În mod ideal, un program sub forma de cod de octeţi (bytecode) ar trebui să poată fi executat

pe orice tip de calculator, indiferent de arhitectura acestuia, tipul procesorului, capacitatea de

memorie etc, deci să fie independent de platformă. În realitate, calculatorul trebuie să aibă o

memorie disponibilă suficient de mare pentru a conţine cel puţin maşina virtuală Java (JVM).

Apare deci o contradicţie: pentru a executa programe mari, JVM trebuie să aiba o memorie

mare, deci şi calculatorul gazdă trebuie să aibă o memorie mare. Pe de altă parte, pentru a

putea executa programe Java pe calculatoare de capacitate foarte mică (cum sunt cele

încorporate în diverse aparate electrocasnice, aparate de automatizare etc) este necesară o

JVM cu memorie mică. Un program destinat unui calculator mic poate fi executat şi pe unul

cu memorie mare, dar nu şi invers. Aceasta a condus la necesitatea de a avea mai multe

"medii de execuţie Java", în funcţie de dimensiunile şi destinaţia calculatorului pe care se

instalează, iar între caracteristicile programelor Java nu se mai mentioneaza "independenţa de

platformă" ci "neutralitatea faţă de arhitectură".

Neutralitatea faţă de arhitectură înseamnă, de fapt, că arhitectura maşinii virtuale Java, care

este ea însăşi un calculator abstract (organizarea memoriei, convenţiile de reprezentare a

datelor în memorie, setul de instrucţiuni al procesorului etc) nu depinde de arhitectura

calculatorului pe care aceasta se instaleaza. Întrucat codul de octeţi obţinut din compilarea

programului Java nu se execută nemijlocit pe calculatorul gazdă, ci pe maşina virtuală Java,

el poate fi acelaşi pe orice calculator pe care este instalata o astfel de maşină, deci este neutru

faţă de arhitectura calculatorului gazda.

Este însa necesar să precizăm că maşina virtuală Java însăşi este un produs software, care este

instalat şi funcţionează direct pe calculatorul gazdă, deci respectă convenţiile arhitecturale ale

acestuia. În consecinţă, pe fiecare tip de calculator trebuie instalată o maşină virtuală Java

corespunzătoare. Se poate, deci, vorbi de neutralitatea faţă de arhitectura a programelor Java,

dar nu şi a maşinii virtuale Java.

Page 10: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

10

Calculatoare abstracte. Modelul von

Neuman

Conceptul de calculator abstract

Sistemele de calcul reale sunt extrem de complicate, astfel că cel care doreşte să le cunoască

în detaliu are nevoie de cunoştinţe aprofundate în domenile tehnice cărora le aparţin

echipamentele care le compun (electronica, electrotehnica, mecanica etc.). Din fericire,

asemenea cunostinţe nu sunt absolut necesare pentru a programa un calculator, deşi uneori

pot fi utile.

În realitate, programatorul nu scrie programul pentru calculatorul real, ci pentru un calculator

abstract, dat sub forma unui model care elimina detaliile, păstrând numai acele elemente care

sunt necesare pentru limbajul de programare folosit. Asa dar, la stabilirea schemei

calculatorului abstract, trebuie să se ţină seama atât de calculatorul real pe care îl modelează,

cât şi de limbajul de programare folosit. Este deci posibil ca, pentru acelaşi calculator

concret, să existe mai multe modele abstracte, folosite pentru diferite limbaje. Este însă, de

asemenea, posibil ca pentru mai multe calculatoare concrete să se folosească acelaşi

calculator abstract, diferenţa între ele manifestandu-se prin acele detalii, care se pierd la

abstractizare.

În general, un calculator abstract are un set de instrucţiuni, un set de regiştri şi un model de

memorie.

Modelul de memorie

Memoria calculatorului abstract este o succesiune de locaţii de memorie. Fiecare locaţie de

memorie este privită ca o "casetă" care conţine un numar fix de cifre binare (biţi). Numărul

de ordine al locaţiei (care arată poziţia acesteia în cadrul memoriei) se numeste adresă. În

consecinţă, memoria calculatorului este adresabilă. Locaţia este cea mai mică zonă de

memorie care poate fi citită sau înregistrată. La orice operaţie de citire/scriere se transferă un

numar întreg de locaţii.

În principiu, modelele de memorie pot să difere între ele prin numărul de biţi conţinut în

locaţia de memorie (prin "lungimea" locaţiei). Totuşi, la majoritatea calculatoarelor actuale,

locaţia de memorie conţine opt biţi şi se numeşte octet (engl.: byte). Iată un exemplu de

model de memorie organizată pe octeţi:

Page 11: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

11

În acest model, în coloana din stânga apar adresele locaţiilor. Le-am scris în sistemul de

numeratie zecimal, pentru a fi mai uşor de urmărit. De obicei însă, ele se exprimă în sistemul

binar, sau în cel hexazecimal. Numărul de locaţii este însă în realitate, desigur, mult mai

mare, exprimandu-se de regulă în megaocteţi. În coloana din dreapta au fost reprezentate

locaţiile de memorie, conţinând fiecare exact opt cifre binare. Conţinutul a fost aici ales,

desigur, arbitrar.

Capacitatea de memorie

Capacitatea memoriei calculatorului se poate exprima în biţi. Totuşi, întrucât majoritatea

calculatoarelor moderne au memoria organizată pe octeţi, se obisnuieşte să se folosească

drept unitate de masură octetul sau multiplii acestuia.

Reamintim că nu trebuie sa confundam un bit cu un octet (engl.: byte). Primul este unitatea

binara, exprimându-se prin cifrele binare 0 si 1. Numele este o prescurtare de la denumirea

din engleză a unităţii binare: binary unit, de la care s-au luat începutul şi sfârşitul. Un octet

(byte) este însă un număr format din 8 cifre binare, deci din 8 biţi.

Multiplii octetului sunt kilooctetul, megaoctetul, gigaoctetul si teraoctetul. Având în vedere

că sistemul de numeraţie folosit în memoria internă a calculatorului este cel binar, pentru

multipli nu s-au folosit puterile lui 10, ca în sistemul zecimal, ci puterile lui 2 cele mai

apropiate de acestea:

1 kilooctet (engl. kilobyte) = 1024 octeţi = 210

octeţi, prescurtat K sau Ko sau KB ;

1 megaoctet (engl. megabyte) = 1024 kiloocteţi = 1'048'576 octeţi, prescurtat M

sau Mo sau MB ;

1 gigaoctet (engl.: gigabyte) = 1024 megaocteţi = 1'073'741'824 octeţi, prescurtat

G sau Go sau GB ;

1 teraoctet (engl: terabyte) = 1024 gigaocteţi =1'099'511'627'776 octeţi, prescurtat

T sau To sau TB ;

Procesorul abstract

Procesorul abstract este caracterizat printr-un set de regiştri şi un set de instrucţiuni.

Regiştrii procesorului sunt, la fel ca locaţiile de memorie, dispozitive în care se memorează

numere binare de lungime fixă, specifică procesorului respectiv. Aceasta este, în general un

multiplu de 8, deci într-un registru pot fi "încărcaţi" un număr întreg de octeţi.

Page 12: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

12

Instrucţiunile sunt codificate intern tot prin numere binare, formate din cel puţin două părţi:

un cod al operaţiei şi adresa operandului (uneori adresele operanzilor). Exemple de operaţii:

- încărcarea, adică transferul unui operand din memorie într-un registru; instrucţiunea

conţine codul operaţiei de încarcare, adresa din memorie a operandului şi numărul registrului

în care se încarcă;

- memorarea, adică inregistrarea la o anumită adresă din memorie a conţinutului unui

registru; se dau: codul operaţiei, numărul registrului de origine şi adresa din memorie a

destinaţiei;

- operaţii de calcul (aritmetice sau logice), care se efectueaza fie între operanzii din

registre, fie între un operand dintr-un registru şi unul din memorie. În instrucţiune se dau

codul operaţiei şi numerele registrelor între care se face aceasta, sau numărul unui registru şi

o adresă din memorie. Rezultatul operaţiei rămane, de regulă, într-un registru;

- instrucţiuni de salt, prin care se modifică fluxul normal (secvenţial) al executării

instrucţiunilor. În mod normal, după ce s-a executat o instrucţiune din program, se trece la

cea imediat următoare, în ordinea în care acestea sunt situate în memorie. Instrucţiunea de

salt indică trecerea la executarea unei instrucţiuni situată la o altă adresă din memorie.

Fiecare instrucţiune este înregistrată în memorie pe o lungime unul sau mai multi octeţi.

Maşina von Neumann

Matematicianul american de origine maghiară John von Neumann a publicat în anul 1945

prima descriere a unui calculator cu program memorat, care ar fi putut fi construit. Această

descriere a avut o influenţă foarte mare asupra evoluţiei ulterioare a calculatoarelor şi este

cunoscută sub numele "maşina von Neumann".

Maşina von Neumann este formată din:

- o unitate aritmetică şi logică;

- o unitate de control;

- o unitate de intrare/ieşire;

- o unitate de memorie.

Unitatea aritmetică şi logică şi unitatea de control formează împreună procesorul (unitatea

centrală) de la calculatoarele actuale.

Page 13: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

13

Maşina von Neuman lucrează numai cu numere întregi. Unitatea aritmetică şi logică

efectuează operaţiile de calcul (adunare, scădere, înmulţire, împărţire întreagă, valoare

absoluta). Ea conţine doi regiştri, dintre care unul se numeste registru acumulator. Orice

operaţie se face folosind regiştrii unităţii centrale:

- încărcarea este transferul unui operand din memorie în unul din registri;

- memorarea este transferul continutului registrului acumulator la o anumită adresă din

memorie;

- operaţiile de calcul (adunare, scădere, înmulţire, împărţire) se fac între numerele din cei

doi regiştri, iar rezultatul rămâne în registrul acumulator;

- operaţiile de intrare/ieşire se fac între registrul acumulator şi unitatea de intrare/ieşire.

Dacă, de exemplu, dorim să se efectueze calculul c=a+b, aceasta înseamnă că se vor executa

următoarele instructiuni:

încarcă în registrul A operandul situat în memorie la adresa a;

încarcă în registrul R operandul situat în memorie la adresa b;

adună operanzii din cei doi regiştri (rezultatul rămâne în registrul acumulator A);

memorează conţinutul registrului A la adresa c din memorie.

Bineînţeles, aceste instrucţiuni vor fi reprezentate în cod binar, adica atât operaţiile, cât şi

adresele din memorie vor fi exprimate prin numere în sistemul de numeraţie cu baza 2.

Caracteristica principală a maşinii von Neuman este ca funcţionarea ei este un proces

secvenţial: la un moment dat se execută o singură instrucţiune, iar executarea unei

instrucţiuni poate să înceapă numai după ce s-a încheiat executarea celei precedente. În toate

operaţiile participă unitatea centrală şi regiştrii acesteia.

Primele generaţii de calculatoare construite au respectat destul de fidel modelul maşinii von

Neuman. Chiar dacă, ulterior, evoluţia calculatoarelor şi a sistemelor de operare a suferit

abateri de la acest model (s-a introdus accesul direct la memorie al unităţilor de intrare/ieşire,

au aparut calculatoare cu mai multe procesoare, care funcţionează în paralel, etc.), limbajele

de programare au continuat, în majoritatea lor, să fie făcute pentru calculatoare abstracte de

tip von Neumann. Exemple bine cunoscute de astfel de limbaje sunt Fortran, Cobol, Basic,

Pascal, C, C++ ş.a.

Limbajul Java face parte din categoria limbajelor pentru procese concurente, în sensul că el

permite să existe în paralel mai multe fire de executie, ale căror operaţii pot, în principiu, să

se realizeze pe procesoare diferite. Este unul din motivele pentru care acest limbaj nu mai are

la bază maşina von Neumann, ci pentru el a fost conceput un alt calculator abstract, numit

maşina virtuală Java.

Mediul de execuţie Java

Mediul de execuţie Java, numit în engleză Java Runtime Environment, conţine maşina

virtuală Java şi un nucleu de clase Java. Acest mediu trebuie instalat pe orice calculator, pe

care se doreşte să se execute programe Java.

Maşina virtuală Java (engleză: JVM - Java Virtual Machine) este, în general, implementată

software sub forma unui produs program adecvat calculatorului pe care acesta se instalează.

Page 14: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

14

Ideea de bază a limbajului şi tehnologiei Java, este ca - pe baza acestora - să se poată creea

produse software neutre faţă de arhitectura sistemului de calcul, deci care să poată fi

executate pe orice echipament, de la produse de uz casnic comandate numeric (televizoare,

telefoane, maşini de spălat, frigidere, etc) pană la supercalculatoare. Ea se exprimă prin

sloganul "Write Once, Run Anywhere" (scrie o singură dată şi rulează oriunde), care arată că

un program, după ce a fost scris şi compilat, poate fi executat (rulat) pe orice calculator.

Pentru realizarea acestui obiectiv, s-a decis ca în tehnologia Java portabilitatea programelor

sa se realizeze la nivel de cod de octeţi (bytecode), adică sub forma de cod binar destinat unui

calculator abstract, numit maşina virtuală Java. În acest scop:

s-a întocmit o descriere riguroasă numită specificaţia maşinii virtuale Java, (The

Java Virtual Machine Specification), în care se prezintă în detaliu arhitectura şi

funcţionarea acestei maşini;

pe fiecare calculator, pe care se execută programe Java, trebuie sa existe o

implementare (o realizare concretă sub forma de produs software sau hardware) a

maşinii virtuale Java, care execută efectiv programul dat sub forma de cod de octeţi.

Nucleul de clase: Limbajul Java este orientat pe obiecte. Orice program este un ansamblu de

clase şi de obiecte, care sunt instanţieri ale claselor. În mediul de execuţie Java este inclusă şi

o bibliotecă de clase predefinite. Este vorba, în special, de acele clase care asigură

comunicarea dintre programul Java şi sistemul de operare al calculatorului gazdă. Deşi

interfaţa acestor clase cu programul Java nu depinde de tipul calculatorului gazdă,

implementarea lor este dependenta de platformă, la fel ca şi cea a maşinii virtuale Java.

Implementarea maşinii virtuale Java

De regulă, arhitectura şi setul de instrucţiuni al calculatorului, pe care se execută un program

Java, diferă de cele ale maşinii virtuale Java. În consecinţă, codul de octeţi generat de

compilatorul Java nu poate fi executat nemijlocit de procesorul (procesoarele) calculatorului

pe care acesta se execută.

Dacă este realizată software (aşa cum se întamplă în majoritatea cazurilor), maşina virtuală

Java este ea însăşi un produs program, care este scris şi compilat special pentru tipul de

calculator pe care se instalează, deci foloseşte setul de instrucţiuni nativ al acestuia. Acest

produs program trebuie să respecte specificaţia maşinii virtuale Java, dar realizarea concretă

depinde de tipul de calculator pe care se instalează. Mai mult, pentru acelaşi calculator pot fi

realizate mai multe maşini virtuale Java, care toate respecta specificaţia, dar diferă între ele

prin modul de realizare.

În principiu, componenta principală a maşinii virtuale Java este un interpretor, adică un

program care parcurge instrucţiunile conţinute în codul de octeţi Java din memoria maşinii

virtuale Java şi le converteşte în instrucţiuni native, care pot fi executate de procesorul

calculatorului gazdă. Această conversie necesită un anumit timp, din care cauză durata de

execuţie a unui program interpretat este intotdeauna mai mare decât a unuia compilat direct în

codul nativ. Din această cauză, principala deficienţă care se semnala la primele implementări

ale maşinii virtuale Java era că durata de execuţie a programelor era sensibil mai mare decât a

celor scrise in limbaje "tradiţionale" compilate, cum ar fi C, C++, Pascal, Fortran etc.

Page 15: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

15

Implementările moderne ale maşinii virtuale Java se caracterizează prin mărirea sensibilă a

vitezei de executie, care se apropie deja de cea a programelor compilate. Aceasta se

realizează, în special, prin introducerea unei compilări "just in time": codul de octeţi este

compilat, în momentul execuţiei, in cod nativ pentru calculatorul gazdă şi abia apoi este

executat.

Desigur că cea mai eficientă reducere a duratei de execuţie se produce atunci când maşina

virtuală Java este implementata hardware, astfel încât codul de octeti Java (bztecode) este cod

nativ al acestei maşini. În acest caz, durata de execuţie a programului este aceeaşi cu cea a

unui program compilat tradiţional.

Platforma Java 2

Un mare avantaj al programatorilor in limbajul Java este că au la dispoziţie un set puternic de

instrumente de dezvoltare a programelor: compilator, depanator, bibliotecă de clase,

documentaţie etc. La început, acesta s-a numit "setul de dezvoltare Java" (în engleza: JDK -

Java Development Kit). Au existat mai multe versiuni succesive: JDK 1.0, JDK 1.1, JDK 1.2

aparute, respetiv, in anii 1996, 1997 si 1998.

O componentă importantă pentru programatori a setului de dezvoltare Java este "Interfaţa

pentru programarea de aplicaţii" (API - Application Programming Interface). Aceasta este

acea parte din documentaţie, în care se dă specificaţia claselor, adică descrierea riguroasă a

modului în care clasă respectivă este vazută de către programul de aplicaţie.

Trecerea de la JDK 1.0 la JDK 1.1 a reprezentat o revizuire de concepţie, în special în ce

priveşte API, astfel că numeroase clase existente în JDK 1.0 au devenit depreciate în JDK

1.1, fiind înlocuite cu clase noi. La trecerea de la JDK 1.1 la JDK 1.2 nu a mai apărut o astfel

de situaţie, dar numărul de clase a fost sensibil mărit. În consecinţă, nu se mai recomanda

folosirea în programele Java a JDK 1.0.

În anul 1998 s-a introdus denumirea de "Platforma Java 2", care se referă la întregul complex

de specificaţii, resurse software şi documentaţie puse la dispoziţie programatorilor şi

utilizatorilor de Java. Ca urmare, JDK 1.2 a fost redenumit "Java 2 Platform SDK, SE v1.2"

(SDK - Software Development Kit, SE - Standard Edition, v - version). In prezent, se

utilizează deja "Java 2 Platform SDK, SE v1.4".

Platforma Java 2 se oferă în prezent de firma Sun Microsystems în trei variante:

Java 2 Platform, Standard Edition (J2SE) - pentru dezvoltarea aplicaţiilor şi

miniaplicaţiilor obişnuite (de pe staţiile de lucru);

Java 2 Platform, Enterprise Edition (J2EE) - pentru dezvoltarea de aplicaţii pentru

serverele de întreprindere;

Java 2 Platform, MicroEdition (J2ME) - pentru utilizarea pe calculatoare de capacitate

foarte mică, încorporate în echipamente electrice sau electronice.

În cursul nostru vom folosi J2SE, iar din documentaţia oferită de firma Sun vom folosi în

special documentaţia API pentru această platformă.

Page 16: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

16

Tehnologia Java

Datorită caracteristicilor sale, Java nu mai poate fi considerat doar un limbaj de programare

asociat cu o platformă de dezvoltare de aplicaţii, ci a devenit o veritabilă tehnologie software.

Când s-a trecut de la programarea procedurală la programarea orientată pe obiecte, s-a arătat

că aceasta poate fi comparată cu trecerea de la fabricaţia artizanală la cea industrială:

programul nu mai trebuie creat "de la zero", ci poate fi conceput ca un ansamblu de

componente (obiecte) "prefabricate". Programatorii se pot împărţi în două categorii: cei care

creeaza clasele de obiecte şi le oferă "pe piaţa" şi cei care, din aceste componente, crează

aplicaţii (produse software finite) oferite utilizatorilor.

Limbajele orientate pe obiecte existente anterior (C++, Object Pascal, etc) nu au reuşit, totuşi,

să stea la baza unei astfel de "industrializări". Cauza principală este că, fiind limbaje

compilate, nu puteau sta la baza producerii unor componente utilizabile pe orice platformă

hardware şi sub orice sistem de operare şi - deci - nu puteau fi folosite fara dificultăţi într-o

reţea de calculatoare eterogenă.

Deşi a apărut recent, răspândirea foarte rapidă a platformei Java se datoreşte tocmai faptului

că apariţia ei a corespuns cu dezvoltarea amplă a reţelelor de calculatoare, în special a

Internet-ului. Un număr foarte mare de firme producătoare de software şi numeroşi

programatori individuali din intreaga lume s-au angajat în dezvoltarea de clase, componente

şi aplicaţii programate în Java. Numărul de clase din Java SDK creşte continuu, fiind

utilizabile în domenii din ce în ce mai variate: prelucrări de date numerice, prelucrări de

texte, interfaţa grafică cu utilizatorul, lucrul cu fişiere, comunicatii în reţele, legătura cu baze

de date, securitatea datelor, calcul distribuit, etc. În afară de clasele din SDK (puse la

dispoziţie de firma Sun Microsystems), programatorii pot folosi un numar mare de clase şi

componente Java ("Java beans") oferite de alte firme, multe din ele disponibile liber pe

Internet. Ca urmare, se poate spune că baza tehnologică a programării în Java creşte

exponenţial.

Limbajul Java în sine este simplu şi uşor de învăţat. Forţa tehnologiei Java constă nu în

limbajul folosit, ci în numărul din ce în ce mai mare de clase reutilizabile, pe care

programatorii le au la dispoziţie, şi în faptul că programele realizate pot fi utilizabile practic

oriunde, fără a fi necesar sa fie refăcute când se trece de la un tip de calculator la altul.

Aceasta presupune însă, ca în orice alta tehnologie, şi necesitatea unei standardizări, a

introducerii unor norme pe care să le respecte întreaga comunitate a programatorilor. Acest

rol il îndeplinesc acum specificatiile: specificatia limbajului Java, specificatia maşinii virtuale

Java, Java API, etc. Întreţinerea şi dezvoltarea acestor specificaţii este facută, deocamdată,

de firma Sun Microsystems. Nu este exclus ca, cu timpul, acest rol sa fie conferit unui

organism de standardizare internaţional, pentru a nu se creea avantaje unui anumit producător

de software.

Dintre resursele cele mai importante puse la dispoziţia programatorilor de tehnologia Java,

menţionăm:

Java API - specificaţia claselor interfeţei de programare de aplicaţii Java şi

bibliotecile care implementează aceste clase;

Page 17: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

17

JFC (Java Foundation Classes) - biblioteca de clase pentru realizarea unor interfeţe

grafice cu utilizatorul independente de sistemul de operare utilizat. Începând cu

Platforma Java 2 este inclusă în Java API;

Java Beans - o arhitectură de componente reutilizabile, neutre faţă de tipul

calculatorului şi sistemul de operare, care pot fi utilizate în medii de programare

vizuale. Se ofera şi instrumente de dezvoltare pentru astfel de componente: BDK

(Beans Development Kit) pentru dezvoltarea de componente, Java Plug-in (pentru

legătura cu Active-X de la Microsoft), JAF (JavaBeans Activation Framework) pentru

identificarea, localizarea componentelor şi altele;

JDBC (Java Data Base Connectivity) - componente pentru legătura cu baze de date;

JINI - tehnologie bazată pe Java, pentru asigurarea conectivităţii echipamentelor în

reţele de calculatoare;

tehnologia agenţilor software - produse software care se pot deplasa de la un

calculator la altul într-o reţea şi pot îndeplini în mod autonom pe calculatorul de

destinaţie sarcinile pentru care au fost trimise. Platforma Java este foarte convenabilă

pentru crearea şi utilizarea agenţilor în reţele eterogene. Exemple sunt tehnologia

agleţilor oferita de firma IBM, cadrul de dezvoltare a agentilor Java Java Agents

Framework (JAF) de la Universitatea din Massachutess, etc.

şi multe altele.

Există, de asemenea, numeroase medii de programare pentru Java, oferite de diverse firme,

cum sunt:

Forte for Java - un mediu de programare vizual, realizat si oferit gratuit pentru

utilizări necomerciale de firma Sun MicroSystems.

WebGain VisualCafe - un mediu de programare vizual, realizat de firma WebGain;

Borland JBuilder - un mediu de programare vizual, realizat de firma Borland;

VisualAge for Java - un mediu de programare vizual realizat de firma IBM;

Visual J# .NET - un mediu de dezvoltare vizual al firmei Microsoft

şi altele.

În acest curs, ne vom rezuma la însuşirea limbajului Java şi a unor componente din Java API,

folosind numai Java 2 SDK, Standard Edition.

Scurt istoric al platformei Java

În anul 1990, un grup de programatori de la firma Sun Microsystems, între care şi James

Gosling, lucrau la proiectul "Green", al cărui obiectiv era realizarea de software pentru

aparate electrocasnice cu comanda numerică (maşini de spălat, frigidere, cuptoare cu

microunde, telefoane, televizoare etc.). S-a încercat, pentru început, să se folosească pentru

programare limbajul C++, dar s-a constatat rapid că acesta nu corespundea scopului urmărit,

deoarece programele obţinute erau prea mari şi nu erau portabile la nivel de cod binar. S-a

ajuns astfel la concluzia că este necesar un nou limbaj de programare, care să fie simplu, uşor

de învăţat şi de utilizat, iar programul binar obţinut prin compilare să poată fi rulat pe

calculatoare de capacitate mică şi cu arhitecturi diferite. Acest nou limbaj a fost numit Oak

(în romaneste "nuc"; se spune că atunci când a trebuit sa-i dea un nume, Gosling s-a uitat pe

fereastră şi a văzut un nuc în faţa ei), prima lui variantă fiind gata la mijlocul lui 1991.

Page 18: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

18

Desi s-a realizat o cantitate mare de software, s-a constatat că, în vremea respectivă,

orientarea către aparatura electrocasnică ("de consum"), nu corespundea încă cerinţelor pieţei.

După o serie de alte încercări, s-a ajuns la concluzia că cea mai buna utilizare a noului limbaj

este realizarea de software pentru reţelele de calculatoare. Întrucat denumirea "Oak" nu a

putut fi înregistrată oficial, în timpul unei discuţii "la o ceaşcă de cafea", autorii au decis sa-i

dea limbajului numele Java, care a fost şi înregistrat ca marcă comerciala (TM - Trade Mark).

Iată dece acest nume apare frecvent scris sub forma JavaTM

.

Prima utilizare comercială a acestui limbaj a fost includerea unui interpretor Java în

navigatorul (browserul) de Web al firmei Netscape. Introducerea de appleturi (miniaplicaţii)

Java în paginile de Web a permis ca acestea sa devina interactive, deci să capete o

componentă dinamică.

In continuare, folosirea limbajului şi apoi a tehnologiei Java a căpătat o dezvoltare

exponenţială. Iată câteva date:

- ianuarie 1996 - lansarea JDK 1.0;

- decembrie 1996 - lansarea JDK 1.1, versiunea beta;

- februarie 1997 - lansarea versiunii finale a JDK 1.1;

- martie 1998 - se lansează JFC (Java Foundation Classes);

- decembrie 1998 - se lansează "Java 2 Platform";

- iunie 1999 - se anunta trei ediţii ale platformei Java 2: J2SE, J2EE si J2ME.

- mai 2000 - se lansează platforma J2SE v 1.3.

- februarie 2002 - este lansată platforma J2SE v 1.4

Introducere în programarea orientată pe

obiecte

Programarea orientată pe obiecte (POO) este o formă de programare, în care programatorii

definesc clase de obiecte, iar programul conţine un ansamblu de clase şi obiecte, care

comunică între ele prin mesaje.

Clasa este o extensie a conceptului de tip de date şi conţine o structură de date, împreună cu

metodele (functiile) care se aplica acestor date.

Obiectul este o instantiere (o instanta) a clasei. In acelasi program se pot folosi mai multe

obiecte apartinand aceleeasi clase, sau unor clase diferite. Fiecare obiect se caracterizeaza

prin stare si comportament. Starea obiectului depinde de datele pe care acesta le contine, in

timp ce comportamentul este dat de metodele clasei respective.

In general, comunicarea prin mesaje consta in invocarea de metode. Daca obiectul a invoca o

metoda a obiectului b, aceasta poate avea ca efect modificarea starii obiectului b (adica

modificarea unor date continute in structura de date a lui b) si/sau poate primi o valoare

intoarsa de metoda respectiva. Se considera ca, prin invocarea metodei, obiectul a a transmis

un mesaj obiectului b, ceeace a provocat din partea acestuia un anumit raspuns (deci b a

manifestat o anumita comportare).

Page 19: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

19

Exemplu

Sa consideram clasa poligoanelor regulate. Structura de date contine doua variabile: numarul

de laturi (care este o variabila de tip intreg) si lungimea unei laturi (care este o variabila de tip

real). Metodele pot fi, de exemplu, mici programe (functii) prin care se calculeaza aria,

perimetrul, apotema, raza cercului circumscris etc. Pot exista si metode prin care se modifica

numarul de laturi sau lungimea laturii, deci se modifica starea poligonului. Clasa are un

nume (de ex. PoligonRegulat). Pot exista, evident, mai multe instante (obiecte) ale acestei

clase, care toate sunt poligoane regulate, dar difera intre ele prin numarul de laturi si/sau prin

lungimea laturii.

Fie p un PoligonRegulat cu 4 laturi de lungime 3.5. Invocarea metodei p.arie() are ca efect

calcularea functiei arie()pentru obiectul p, deci se va obtine ca raspuns valoarea 12.25. Prin

invocarea acestei metode, s-a transmis obiectului p mesajul ca se cere calcularea ariei, iar

comportamentul acestui obiect a constat in punerea in executie a metodei invocate si

intoarcerea valorii calculate a ariei. Valoarea intoarsa depinde, evident, de starea in care se

gaseste p in momentul invocarii metodei, adica de numarul de laturi si de lungimea laturii.

Atat variabilele, cat si metodele pot fi statice sau nestatice.

Variabilele statice (ale clasei) apartin clasei, adica au aceeasi valoare pentru toate obiectele

clasei respective.

Variabilele de instanta (nestatice) apartin obiectului (instantei), deci au valori diferite de la

un obiect la altul.

De exemplu, daca clasa Pasare contine variabila numarAripi, aceasta variabila va avea

valoarea 2 pentru toate pasarile, deci pentru toate instantele clasei respective, fiind o variabila

statica sau a clasei. In schimb, variabila varsta va avea valori diferite pentru fiecare pasare,

deci este o variabila a instantei (nestatica).

Metodele statice (ale clasei) pot folosi numai variabilele statice ale clasei respective, in timp

ce metodele nestatice pot folosi atat variabilele statice, cat si pe cele ale instantei.

Din punct de vedere al modului de acces, datele si metodele unei clase pot fi publice sau

private. Cele publice sunt accesibile din orice alta clasa, in timp ce cele private sunt

accesibile numai din clasa careia ii apartin.

Tipuri de produse software scrise în Java

Limbajul Java este folosit cel mai frecvent pentru a scrie urmatoarele trei tipuri de programe:

aplicaţie - este un produs software care se instalează pe un anumit calculator şi

funcţionează direct sub controlul sistemului de operare, având acces la toate resursele

calculatorului respectiv. Una din clasele aplicaţiei trebuie sa conţină metoda principală, cu

care începe execuţia aplicatiei. Această metodă se numeşte main şi are forma:

Page 20: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

20

public static void main(String args[]) { // corpul metodei }

applet (miniaplicaţie) - este un program care se transmite sub formă de cod de octeţi

(bytecode) prin reţeaua de calculatoare şi este executat în cadrul unui navigator (browser) de

Web, fără a avea acces la fişierele sau sistemul de intrare/ieşire al calculatorului pe care se

execută;

servlet - un program care se execută pe un server dein reţea.

Un şablon de aplicaţie simplă în limbajul

Java

În prima parte a acestui curs, în aplicaţiile făcute la curs şi la laborator vom utiliza următorul

şablon:

class <nume_clasa> { public static void main(String args[]) { // corpul metodei main } }

Părţile scrise cu negru (inclusiv parantezele şi acoladele) le vom considera obligatorii, iar cele

scrise cursiv cu roşu sunt la latitudinea programatorului.

<nume_clasa> - este numele clasei, fiind ales de către programator cu respectarea

următoarelor condiţii:

- numele clasei trebuie să înceapă cu o literă şi este format numai din litere, cifre şi -

eventual - liniuţa de subliniere;

- prin convenţie (deşi aceasta nu este o regulă de sintaxă), numele de clasă începe

întotdeauna cu o majusculă;

- în cazul numelor compuse din mai multe cuvinte, fiecare cuvânt începe cu majusculă;

- lungimea numelui nu este limitată, dar nu este recomandabil sa fie prea mare.

// corpul metodei main - este o succesiune de instrucţiuni şi comentarii care respectă

sintaxa limbajului Java.

Părţile componente ale acestui şablon pot fi explicate pe baza cunoştintelor pe care le avem

deja despre programarea orientată pe obiecte şi despre limbajele de programare.

- descrierea (definirea) unei clase începe prin cuvantul class, urmat de numele clasei;

- corpul clasei este cuprins între acolade { ... }

- în cazul nostru, corpul clasei conţine o singura metodă;

- metoda are forma unei funcţii, care se numeşte main şi are un singur argument numit args.

Vom vedea ulterior că acesta este un tablou de obiecte din clasa String, adică un tablou de

şiruri de caractere. Tot atunci vom vedea că acest argument serveşte pentru preluarea

parametrilor din linia de comandă;

Page 21: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

21

- metoda main (metoda principală) este publică, adică poate fi utilizată de obiecte din alta

clasă (în cazul nostru, ea este apelată de maşina virtuală Java la punerea în execuţie a

aplicaţiei);

-metoda main este statică, deci apartine clasei şi nu instanţelor acestei clase;

- privită ca o funcţie, metoda main trebuie, în principiu, să întoarcă o valoare. În acest caz,

metoda nu întoarce o valoare, deci tipul valorii întoarse este void (loc gol, lipsă).

Exemplu de aplicaţie simplă

Dăm aici un exemplu de aplicaţie simplă scrisă în limbajul Java. Aplicaţia este o clasă Java,

care conţine metoda main.

Exemplul 1 Considerăm următorul program:

class PrimaAplicatie { public static void main(String args[]) { System.out.println("Prima noastra aplicatie a reusit!"); } }

Remarcăm urmatoarele:

programul respectă şablonul de aplicaţie simplă adoptat de noi;

numele clasei este PrimaAplicatie;

corpul clasei este constituit dintr-o singură instrucţiune, prin care este invocată

metoda println a obiectului out din clasa System.

Deşi nu cunoaştem încă modul în care se definesc şi se utilizează clasele şi obiectele în

limbajul Java, menţionam aici că instrucţiunea de forma

System.out.println(<sir_de_caractere>);

are ca efect afişarea pe ecran a şirului primit ca argument. În limbajul Java, instrucţiunile

simple se termină cu caracterul ; (punct şi virgulă).

Efectul executării acestei aplicaţii este că se afişează pe ecran textul Prima noastra aplicatie a reusit!

Editarea, compilarea şi executarea

aplicaţiilor Java

Fiecare aplicaţie Java parcurge următoarele etape: editarea programului sursă, compilarea şi

eliminarea erorilor sintactice, testarea şi eliminarea erorilor de concepţie, executarea. În acest

scop, pe calculatorul pe care lucraţi trebuie sa existe un set de dezvoltare Java, preferabil Java

2 Platform SDK, Standard Edition. Pentru a dezvolta aplicaţii Java:

Page 22: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

22

dacă lucrati sub Windows, veţi folosi o fereastră MS-DOS (Command Prompt);

dacă lucraţi sub Linux sau Unix, veţi folosi o fereastră de X-Terminal. Sub Linux vă

recomandăm sa folosiţi KDE, sub care să selectaţi din bara de scule pictograma

"Terminal Emulation", sau din meniul Applications sa alegeti optiunea "X Terminal".

Editarea fisierului sursă

Pentru început, vom considera că aplicaţia este constituită dintr-o singură clasă, care respectă

şablonul indicat anterior. Programul sursă pentru această clasă va fi editat sub forma unui

fişier separat, care are acelaşi nume cu clasa şi are extensia .java.

De exemplu, clasa PrimaAplicatie va fi editată sub forma unui fişier de text cu numele

PrimaAplicatie.java. Este preferabil să puneţi acest fişier într-un subdirector separat. De

exemplu puteti crea un subdirector numit javaLab, în care să creaţi un alt subdirector numit

sapt1, în care sa puneţi fişierul PrimaAplicatie.java.

Pentru crearea fişierului se va folosi un editor de text simplu, care generează numai text

neformatat, de exemplu "Notepad" daca lucraţi sub Windows sau sub Linux cu WinLinux99,

respectiv "Text Editor" sau "Advanced Editor", daca lucraţi sub Linux cu KDE.

Compilarea şi eliminarea erorilor semnalate de compilator

Translatarea programului sursă în program sub forma de cod de octeţi (bytecode) se face cu

ajutorul compilatorului Java, numit javac. În acest scop, va deplasaţi în subdirectorul în

care se găseşte programul sursă pe care doriţi să-l compilaţi şi daţi comanda javac <fisier_sursa>

De exemplu, pentru a compila fişierul care conţine clasa PrimaAplicatie mergeti în

subdirectorul în care se găseste fişierul respectiv şi daţi comanda javac PrimaAplicatie.java

După ce aţi dat această comandă, veţi obţine unul din următoarele rezultate:

1. Pe ecran apare din nou promptul sistemului de operare, fără a se afişa un mesaj de

eroare. În acest caz, compilarea a decurs normal, iar dacă daţi comanda dir veţi

constata ca în subdirectorul curent a apărut un nou fişier, care poartă numele clasei şi

extensia class. Acesta este fişierul care conţine bytecode-ul clasei compilate.

2. Obţineţi un mesaj de eroare, care indică fie că există erori în program, care au fost

sesizate de compilator, fie că există erori în linia de comandă prin care aţi cerut

compilarea. În ambele cazuri, este necesar să eliminaţi erorile şi să reluaţi compilarea.

Exemplu de utilizare corectă

Sa considerăm ca am creat corect fişierul sursă PrimaAplicatie.java, după care dăm

comanda javac PrimaAplicatie.java Constatăm că pe ecran nu apare nici un mesaj de eroare, ci apare din nou promptul sistemului

de operare. Dacă dăm acum comanda dir

Constatăm, de asemenea, că în lista de fişiere care se afişează apar: PrimaAplicatie.class PrimaAplicatie.java

Dintre acestea, PrimaAplicatie.java este fişierul sursă editat de noi, în timp ce

Page 23: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

23

PrimaAplicatie.class este fişierul de cod de octeti rezultat în urma compilării.

Exemplul 1 de eroare

Considerăm că, după ce aţi creat fişierul sursă PrimaAplicatie.java, daţi comanda jamac PrimaAplicatie.java în care numele compilatorului este introdus greşit (jamac în loc de javac). Ca efect, veţi

obtine un mesaj prin care se arată că cuvantul jamac nu este o comandă corectă (nu este

numele unei comenzi interne a sistemului de operare sau numele unui program executabil),

de exemplu: jamac: command not found

Exemplul 2 de eroare

Să considerăm acum că numele fişierului sursă este introdus greşit, de exemplu: javac PimaAplicatie.java

În acest caz, mesajul de eroare este can't read: PimaAplicatie.java adică "nu pot citi: PimaAplicatie.java", ceeace înseamnă că un astfel de fişier nu există în

directorul curent.

Exemplul 3 de eroare

Să urmărim ce se întâmplă dacă introducem comanda javac PrimaAplicatie

în care numele fişierului este corect, dar lipşeste extensia. În acest caz, obtineţi următorul

mesaj: PrimaAplicatie is an invalid option or argument. usage: javac <options> <source files>

urmat de o lista de opţiuni. Aceasta înseamnă că nu s-a respectat sintaxa comenzii, care cere

ca comanda javac să fie urmată (eventual) de una sau mai multe opţiuni din lista dată, după

care trebuie să apară numele fişierului (fişierelor) sursă care trebuie compilate. Aceste nume

de fişiere trebuie sa conţină obligatoriu extensia java.

Exemplul 4 de eroare

Să considerăm acum că fişierul sursă editat de noi conţine erori. Un exemplu este fişierul

PrimaAplicatie1.java, care are următorul conţinut:

class PrimaAplicatie1 { void main(String args[]) { System.ont.println("Prima noastra aplicatie a reusit!"); } }

Compilând acest fişier obţinem următorul mesaj de eroare: PrimaAplicatie1.java:3: No variable ont defined in class Java.lang.System System.ont.pintln("Prima noastra aplicatie a reusit!"); ^

Acest mesaj se interpretează astfel: în fişierul PrimaAplicatie1.java, linia 3, în locul

marcat mai jos prin ^, apare variabila ont, care nu există în clasa System din pachetul

(biblioteca) java.lang.

Într-adevar, eroarea constă în faptul că apare ont în loc de out. Observăm că a fost reprodusa

linia din program în care apare eroarea şi s-a marcat prin ^ locul apariţiei erorii.

Dacă dăm comanda dir, constatam că în directorul curent nu a apărut clasa

PrimaAplicatie1.class. Făcând corecţia în fişier şi compilând din nou, constatăm că nu

mai apare nici un mesaj de eroare, deci compilatorul nu a mai sesizat nici o eroare şi a creat

fişierul care conţine codul de octeţi corespunzător.

Remarcăm că, totuşi, programul nu este corect, deoarece - conform şablonului dat anterior,

Page 24: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

24

prima linie din metoda main trebuia să aibă forma public static void main(String args[]){ Compilatorul nu a sesizat această eroare deoarece, în principiu, clasa poate sa conţina şi o

metoda main de forma celei date în acest fisier. Vom vedea, însă, că eroarea apare la

executarea programului.

Exerciţiu

Încercaţi să faceţi şi alte modificări în programul sursă şi să constataţi ce erori apar la

compilare. De exemplu:

scrieti incorect cuvintele public, static, main, string, System. println;

omiteţi unele dintre acolade sau paranteze;

puneţi acolade sau paranteze în plus.

Puteţi introduce intenţionat şi mai multe din erorile de mai sus simultan. Compilaţi fişierul

astfel modificat şi interpretati mesajele de eroare obţinute.

Executarea aplicaţiei

Dacă în directorul curent există fişierul <nume_aplicaţie>.class, executarea acestei

aplicaţii se solicită prin comanda java <nume_aplicaţie>

Remarcăm că se dă ca parametru numai numele clasei, fără extensia class. Efectul acestei

comenzi este, fie executarea aplicatiei, fie aparitia unui mesaj de eroare de execuţie.

Prin comanda java se pune în execuţie interpretorul maşinii virtuale Java. Acest interpretor

verifică dacă în directorul curent există fişierul <nume_aplicaţie>.class. Daca acesta

există, încarcă în memorie codul de octeţi pe care îl conţine şi pune în execuţie metoda

public static void main(). Dacă fişierul nu există, sau dacă el nu conţine o astfel de

metodă, se semnalează printr-un mesaj de eroare.

Exemplul 1

Considerăm că a reuşit compilarea fişierului corect PrimaAplicatie.java şi s-a obţinut

astfel fişierul PrimaAplicatie.class, după care se dă comanda java PrimaAplicatie

Ca rezultat, pe ecran apare textul Prima noastra aplicatie a reusit!

Exemplul 2

Să dăm acum comanda java PimaApicatie

în care numele clasei este dat greşit. Ca rezultat, obţinem mesajul de eroare Exception in thread "main" java.lang.NoClassDefFoundError: PimaApicatie Acest mesaj arată că nu s-a găsit definiţia clasei PimaAplicatie (Eroarea constatată se deduce

din numele acesteia: NoClassDefFoundError provine de la "no class definition found error",

adica nu a fost găsită definiţia clasei PimaApicatie.

Exemplul 3

Să considerăm acum că am eliminat erorile de compilare din fişierul PrimaAplicatie1.java

şi am obţinut fişierul PrimaAplicatie1.class, dar că metoda main a rămas fără

modificatorii public static. Am arătat că lipsa acestor modificatori nu dă eroare de

compilare. Dând acum comanda java PrimaAplicatie1 se obţine mesajul de eroare

Page 25: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

25

Exception in thread "main" java.lang.NoSuchMethodError: main "No such method" se traduce prin "nu exista o astfel de metoda". Urmeaza două puncte şi

numele metodei care nu există: main.

Noi ştim că, în realitate, în clasa PrimaAplicatie1 exista o metodă numita main, numai că

nu este cea pe care o caută interpretorul java pentru a pune aplicaţia in execuţie: acesta caută

metoda public static void main(String args[]) care, în această clasă, nu există.

Întrebări

Nivel 1

1. Ce este Java?

2. Ce calităţi are limbajul de programare Java?

3. Ce conţine mediul de execuţie Java?

4. Ce conţine platforma Java?

5. Ce este programarea orientată pe obiecte?

6. Ce este clasa?

7. Ce este obiectul şi ce legatură există între clasă şi obiect?

8. Prin ce se determină starea obiectului?

9. Prin ce se defineşte comportamentul obiectului?

10. Ce deosebire există între variabilele statice şi cele nestatice?

11. Ce deosebire există între metodele statice şi cele nestatice?

12. Ce deosebire există între datele sau metodele publice şi cele private?

13. Care sunt principalele tipuri de produse software care pot fi scrise în limbajul Java?

14. Ce deosebire există între applet şi aplicatie?

15. Ce deosebire exista între applet şi servlet?

16. Care este metoda care trebuie să existe în mod obligatoriu în orice aplicaţie?

17. Ce este un fişier sursă Java şi cum se stabileşte numele lui?

18. Ce fel de editor se foloseşte pentru crearea fişierului sursă?

19. Prin ce comandă se cere compilarea unui fişier sursă Java?

20. Ce se obţine în cazul în care compilarea a decurs corect?

21. Ce se obţine dacă compilarea nu a reuşit?

22. Prin ce comandă se cere executarea unei aplicaţii?

Nivel 2

1. Dece limbajul Java este mai simplu decât C/C++?

2. Limbajul Java este compilat sau interpretat?

3. Ce fel de cod generează compilatorul Java?

4. Ce se înţelege prin portabilitatea programelor?

5. Dece limbajul Java este neutru faţă de arhitectură?

6. Dece limbajul Java permite programarea concurentă?

7. Ce este maşina virtuală Java?

8. Ce deosebire este între specificaţia maşinii virtuale Java şi implementarea acesteia?

Page 26: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

26

9. Ce sunt JDK 1.0, JDK 1.1 şi JDK 1.2?

10. Ce este SDK si ce legatura există între JDK şi SDK?

11. Ce este API?

12. Ce platforme de dezvoltare pentru Java se folosesc în prezent?

13. Ce este un navigator de Web?

14. Ce este un browser?

15. Ce este WWW?

16. Ce navigatoare de Web cunoaşteti?

17. Daţi şablonul unei aplicaţii simple şi explicati părţile componente.

18. Ce se întâmplă dacă în comanda javac numele fişierului sursă este introdus greşit?

19. Ce se întâmplă dacă în comanda javac numele fişierului sursă este introdus fără

extensia java?

20. Cum sunt semnalate de compilator erorile care apar în program?

21. Ce se întâmplă dacă în faţa metodei main se omit modificatorii public static?

Page 27: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

27

Şiruri. Elementele lexicale ale limbajului

Java. Variabile şi tipuri de date primitive

Comentarii în fişierul sursă 27

Şiruri; concatenarea şirurilor; 28

Metode pentru afişarea pe ecran a şirurilor; 29

Unităţi lexicale ale limbajului Java 30

identificatori 30

cuvinte cheie şi cuvinte rezervate 31

literali 32

separatori şi operatori 32

spaţii şi comentarii 34

Variabile; 34

Declararea şi iniţializarea variabilelor; variabile finale; 35

Tipuri de date primitive şi declaraţii de tip 36

tipul boolean 39

tipuri numerice 41

tipuri de date întregi 45

tipuri de date în virgulă mobilă 57

tipul char 61

Întrebări 63

Comentarii în fişierul sursă

Comentariile sunt texte care pot fi introduse în programul sursă, dar nu sunt luate în

consideraţie de compilator şi deci nu au efect în timpul executării programului. Comentariile

sunt utile pentru o mai buna înţelegere a programului de către om.

În programele Java, se pot folosi trei feluri de comentarii:

a/ comentarii care se pot extinde pe una sau mai multe linii şi au forma /* <comentariu> */

b/ comentarii de sfarsit de linie, care incep cu simbolul // si continua pana la sfarsitul

liniei respective, deci au forma // <comentariu>

c/ comentarii care sunt destinate reproducerii în documentaţia clasei şi au forma /** <comentariu>*/

deci se deosebesc formal de cele de la punctul a numai prin faptul ca incep cu simbolul /**.

Primele două forme de comentariu există şi în limbajul C++, în timp ce ultima este specifică

numai limbajului Java.

Page 28: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

28

Exemplu

Dăm aici ca exemplu fişierul Comentarii.java, care are la bază fişierul

PrimaAplicatie.java, dar acesta fost completat cu comentarii.

/** Aplicatie in care se exemplifica folosirea celor trei tipuri de

comentarii permise in limbajul Java */

class Comentarii { // aici incepe definitia clasei Comentarii

/* metoda main este metoda principala a clasei, cu care incepe executarea programului */

public static void main(String args[]) {

/* Urmeaza instructiunea prin care se invoca metoda println pentru afisarea unui text */ System.out.println("Prima noastra aplicatie a reusit!");

} // sfarsitul metodei main

} // sfarsitul clasei Comentarii

Dacă vom compila şi pune în executie această aplicaţie, vom constata că efectul este acelaşi

ca în cazul clasei PrimaAplicaţie, deoarece comentariile introduse în fişierul sursă nu au efect

în timpul execuţiei programului.

OBSERVAŢIE: Comentariile sunt absolut necesare pentru înţelegerea programului. În

acelaşi timp, abuzul de comentarii poate să facă urmarirea acestuia dificilă. Este, deci,

recomandabil să se introducă în program toate comentariile necesare pentru o bună înţelegere

a acestuia, dar nu mai mult. La aprecierea programelor scrise de Dvs. se va lua întotdeauna în

consideraţie prezenţa şi calitatea comentariilor.

Şiruri

Şirul se reprezintă în program printr-o succesiune de caractere cuprinsă între ghilimele. Iată

câteva exemple de şiruri: "sir de caractere" "ABCDefgh" "1A23bc7" "*+_/?" ""

Ultimul exemplu este un şir vid (care nu conţine nici un caracter).

Concatenarea şirurilor

Asupra şirurilor se poate aplica operaţia de concatenare, reprezentata prin operatorul +.

Expresia şir1+şir2, în care operatorul + este plasat între două şiruri, are ca rezultat un nou şir,

care conţine cele două şiruri-operanzi puse unul după altul. De exemplu, expresia "abcde"+"fgh"

dă ca rezultat şirul "abcdefgh".

Page 29: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

29

Operaţia de concatenare este asociativă, dar nu este comutativă.

De exemplu, expresiile următoare sunt echivalente, ca urmare a asociativităţii: "ABC"+"DEF"+"GH" ("ABC"+"DEF")+"GH" "ABC"+("DEF"+"GH") "ABCDEFGH"

În schimb, expresia "uvw"+"ab" este echivalentă cu "uvwab", în timp ce expresia

"ab"+"uvw" este echivalentă cu "abuvw", deci concatenarea nu este comutativă.

Metode pentru afişarea pe ecran a şirurilor

În capitolul precedent, am folosit deja pentru afişarea şirurilor de caractere metoda System.out.println(<şir>)

la care vom adăuga acum şi metoda System.out.print(<şir>)

În ambele metode, argumentul <şir> este un şir de caractere, care se afişeaza pe ecran.

Deosebirea dintre ele constă în faptul că, după afişarea şirului, metoda println transmite şi

comanda de trecere la linie nouă, în timp ce metoda printnu transmite o astfel de comandă.

În consecinţă, în cazul afişării cu println, următoarea afişare se va face de la început de linie

nouă, iar la afişarea cu print afişarea următoare se va face în continuare, pe aceeaşi linie.

Numele metodei println provine de la print line, care se traduce prin "tipăreşte o linie".

Metodele println siprint aparţin obiectului out din clasa System.

În limbajul Java, clasa System conţine metodele prin care se comunică cu sistemul de

operare al calculatorului, iar obiectul out al acestei clase reprezintă dispozitivul de ieşire

standard al sistemului, care este de obicei unitatea de afişare de la consolă (ecranul).

Metoda println actionează la fel ca metoda print, cu deosebirea că adaugă la sfârşitul

şirului afişat caracterul de control \n care constituie comanda de trecere la linie nouă (New

Line).

Exemplu

Considerăm urmatoarea aplicaţie, conţinută în fişierul AfisareSiruri.java:

/* Exersarea metodelor print si println */

class AfisareSiruri { public static void main(String args[]) { System.out.println("sirul 1"); System.out.println("sirul 2"); // se afiseaza sub sirul 1 System.out.println("AB"+"CDE"); // se afiseaza ABCDE System.out.println("ab"+"cd"+"ef"); // se afiseaza abcdef System.out.println(("ab"+"cd")+"ef"); // asociativitate System.out.println("ab"+("cd"+"ef")); /* Urmatoarele trei instructiuni afiseaza in continuare, pe o singura linie. */ System.out.print("pqrst"); // nu se trece la linie noua System.out.print("UVW"); // se afiseaza in continuare System.out.print("xyz\n"); // echivalent cu println("xyz") /* Trecerea la linia urmatoare se face datorita prezentei

Page 30: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

30

caracterului \n in sirul "xyz\n" */ System.out.println("ultima linie afisata"); } }

Compilând şi executând acest program, putem constata că:

după executarea fiecărei metode println se trece pe ecran la o linie noua;

expresiile "ab"+"cd"+"ef", ("ab"+"cd")+"ef" si"ab"+("cd"+"ef") dau

rezultate identice.

print("xyz\n") are acelasi efect cu println("xyz").

Unităţile lexicale ale limbajului Java

Unităţile lexicale, numite şi lexeme (engl. token, lexeme) sunt construcţiile elementare ale

limbajului ("atomii" acestuia). Acestea sunt simboluri, formate din unul sau mai multe

caractere, care au o anumită semnificaţie în limbaj. După rolul îndeplinit, unităţile lexicale

sunt: identificatori, cuvinte cheie, cuvinte rezervate, literali, separatori,operatori, comentarii

şi spaţii.

De exemplu, în programul din fişierul AfisareSiruri.java distingem urmatoarele unităţi

lexicale:

- cuvinte cheie: class, public, static, void;

- identificatori: AfisareSiruri, main, String, args, System, out, print,

println;

- literali: "sirul 1", "sirul 2", "AB", "CDE", "ab", "cd", "ef", ;

- separatori: { } ( ) [ ] , ;

- operator: +;

- comentarii: /* Exersarea metodelor print si println */ // se afiseaza sub sirul 1

Vom analiza acum separat fiecare din aceste categorii de unităţi lexicale.

Identificatori

Numele date programelor sau componentelor acestora (clase, variabile, metode etc.) se

numesc identificatori. Identificatorii se aleg de către programator, respectând anumite reguli.

În limbajul Java, identificatorii sunt şiruri formate din litere, cifre şi caractere de subliniere

('_'), care încep cu o literă. Lungimea identificatorului nu prezintă importanţă, însă acesta nu

poate conţine spaţii libere sau alte caractere, decât cele menţionate aici.

Exemple de identificatori valabili:

Page 31: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

31

PrimaClasa aplha viteza v15XB7 pretDeVanzare pret_de_vanzare

Este clar acum că şi exemplele date anterior ( Afisari, main, String, args, System,

out, print, println) sunt, de asemenea, identificatori.

Se obişnuieşte ca numele de clase să înceapă cu literă majusculă. De asemenea, se obisnuieşte

ca separarea între cuvinte, în cadrul identificatorilor compuşi din mai multe cuvinte ale

limbajului natural, să se facă incepând fiecare cuvant nou cu literă majusculă, dar se poate

face şi prin caracterul de subliniere '_'. Acestea nu sunt însă reguli sintactice, ci doar

convenţii neobligatorii.

Programatorul poate adopta orice identificatori care respectă regulile şi convenţiile de mai sus

şi care nu sunt cuvinte cheie sau cuvinte rezervate. Desigur însă că folosirea unor

identificatori care au semnificaţie pentru om, cum ar fi viteza sau PretDeVanzare este

preferabilă celor fără semnificaţie, cum ar fi v15XB7, deoarece uşurează înţelegerea şi

urmărirea programului. Amintim însa că, pentru calculator, identificatorii nu au nici o alta

semnificaţie, deci, din acest punct de vedere, toate exemplele de identificatori date aici sunt la

fel de bune.

Cuvinte cheie

În orice limbaj de programare, există un set de cuvinte, numite cuvinte cheie, care sunt

considerate simboluri sintactice şi nu pot fi folosite în program ca identificatori.

În limbajul Java, există următoarele cuvinte cheie:

abstract double int strictfp

boolean else interface super

break extends long switch

byte final native synchronized

case finally new this

catch float package throw

char for private throws

class goto protected transient

const if public try

continue implements return void

default import short volatile

do instanceof static while

Dintre acestea, const şi goto nu sunt folosite în prezent, dar ele au fost introduse în tabela

cuvintelor cheie în vederea unei eventuale utilizări viitoare.

Observăm acum că toate exemplele de cuvinte cheie date la începutul acestei secţiuni

(class, public, static, void) sunt prezente în tabela de mai sus.

Page 32: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

32

Cuvinte rezervate

Se consideră cuvinte rezervate acele cuvinte, care nu pot fi folosite ca identificatori, având

semnificaţii speciale. Cuvintele cheie sunt şi ele considerate în majoritatea limbajelor,

inclusiv Java, drept cuvinte rezervate. În afară de acestea, în limbajul Java există urmatoarele

cuvinte rezervate: true, false, null. Primele două sunt valorile logice adevărat şi fals, iar al treilea are semnificaţia de referinţă

nulă. De fapt, aceste cuvinte rezervate sunt forme speciale de literali.

Literali

Literalii sunt reprezentările în fişierele sursă ale valorilor constante. Exemple de literali:

- caractere: 'a', 'A', '+', '$', '5';

- şiruri de caractere: "sir de caractere", "abc$79.28#^z";

- numere întregi: 14726, -25413;

- numere reale: 12.7389, -0.05673, 2.3075E12, -1.4237E-5;

- valori logice: true, false;

- referinţa nulă: null.

Am subliniat faptul că literalul este forma sub care o anumita valoare este reprezentată în

fişierul sursă, deci în programul scris în limbaj de nivel superior (în cazul nostru în limbajul

Java). Vom arăta ulterior că forma de reprezentare a aceloraşi valori în memoria internă a

calculatorului (forma internă) este diferită de cea externă. Vom reveni asupra regulilor de

scriere a literalilor când vom prezenta tipurile de date din limbajul Java.

Separatori

Separatorul este un caracter care delimitează formele sintactice sau le separă între ele. În

limbajul Java se folosesc următorii separatori:

{ } ( ) [ ] ; , .

Spaţiul liber şi operatorii indeplinesc, de asemenea, rolul de separatori.

Aproape toţi aceşti separatori au fost deja folosiţi în exemplele date în acest capitol.

Operatori

Operatorii sunt simboluri ale unor operaţii. Am folosit deja simbolul + ca operator de

concatenare (deci simbol al operaţiei de concatenare). Operatorul poate fi format din unul sau

mai multe caractere. Entitatea asupra căreia se aplică operatorul se numeşte operand. După

numărul de operanzi, operatorii pot fi unari, binari sau ternari.

După numărul de operanzi deosebim:

operatori unari, care se aplică unui singur operand, de ex. operatorul - în expresia -x;

utilizarea operatorului unar se face, de regula, sub forma "prefix" operator operand, în

care operatorul se pune în faţa operandului; uneori însă se foloseste şi forma "postfix" operand operator în care operatorul se pune după operand;

Page 33: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

33

operatori binari, care se aplică asupra a doi operanzi, operatorul fiind situat între aceştia;

de ex. operatorul de concatenare + în expresia "acesta este " + "un exemplu" sau

operatorul de adunare a două numere + în expresia 17+28.Operatorii binari se folosesc sub

forma "infix"

operand1 operator operand2

în care operatorul este situat între cei doi operanzi;

operatori ternari, care se aplică asupra a trei operanzi; în limbajul Java există un singur

operator ternar ( ? :) folosit în expresiile condiţionale. Operatorul ternar se scrie sub forma operand1 ? operand2 : operand3

în care operand1 are o valoare logică (true sau false), iar ceilalti doi operanzi sunt

expresii aritmetice sau logice (dar de acelaşi tip).

Din exemplele de mai sus, observăm că semnificaţia unui operator poate să depindă de

context, ca în cazul operatorului +, care a fost folosit atât pentru operaţia de concatenare a

şirurilor, cât şi pentru cea de adunare a numerelor.

Din punct de vedere matematic, operatorii sunt funcţii cu unul, două sau trei argumente

(argumentele fiind operanzii). De exemplu, expresia a+b, în care + este un operator binar, iar

a şi b sunt operanzi, este o funcţie de argumente a si b, care are ca valoare suma valorilor

celor două argumente.

După efectul operatorului asupra operanzilor, operatorii pot fi fără efect lateral, care lasa

valorile operanzilor nemodificate, şi cu efect lateral, care modifică valorile operanzilor.

Astfel, operatorul + din exemplul anterior, este un operator fără efect lateral. În schimb, în

expresia ++a operatorul de incrementare ++ are efect lateral deoarece, în urma efectuarii

operaţiei, valoarea operandului a creşte cu o unitate.

Dăm aici o listă a operatorilor folosiţi în limbajul Java.

Operatori unari:

+ - ++ -- new ! ~ () [] {}

Operatori binari

+ - * / % == <= >= != & | ^ && || << >> >>> = += -= *= /= &= |= ^= ~= <<= >>= >>>= . instanceof

Operator ternar

?:

Remarcăm că operatorii + şi - pot fi atât unari ( ca în expresiile +a sau -a), cât şi binari (ca

Page 34: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

34

în expresiile a+bsaua-b).

Semnificaţiile operatorilor vor fi arătate când se vor prezenta tipurile de date şi expresiile.

Comentarii

După cum s-a aratat deja, în fişierele sursă pot fi introduse comentarii, care au rolul de a da

omului,care citeşte programul respectiv, anumite explicaţii necesare pentru o mai buna

înţelegere a acestuia. Din punct de vedere sintactic, întregul comentariu este privit ca o

singură unitate lexicală, care este ignorată de către compilator, deci nu are efect asupra

codului de octeţi generat de acesta.

Spaţii

Între unităţile lexicale ale programului pot fi introduse oricât de multe spaţii libere, fără ca

acestea să aibă influenţă asupra sintaxei sau semanticii programului. Mai multe spaţii libere

succesive sunt tratate de compilator ca şi când ar fi un singur spaţiu.

Variabile

In matematică, variabila este un simbol dat unei valori, care aparţine unei mulţimi de valori

ce constituie domeniul de definiţie al variabilei respective.

În programare, variabila este un nume căruia i se asociază o valoare. Numele variabilei este

un identificator, iar valoarea variabilei trebuie să aparţină unui anumit tip de date. Asupra

valorilor variabilelor pot fi efectuate prin program anumite operaţii.

Exemplul 1

In expresia x=a+2, x şi a sunt variabile. Operaţiile efectuate sunt următoarele: se adună

valoarea variabilei a cu valoarea 2 (dată aici sub formă de literal), iar rezultatul se atribuie

ca valoare variabilei x; în consecinţă, valoarea variabilei a ramâne nemodificată, în schimb

variabila x primeşte o nouă valoare. Operatorul = nu exprima aici relaţia de egalitate, ci

operaţia de atribuire a unei valori unei variabile.

Exemplul 2

Expresia System.out.println(a) are ca efect afişarea pe ecran a valorii variabilei a.

Valoarea variabilei trebuie să fie reprezentată în memoria calculatorului la o anumită adresă

şi să ocupe acolo un anumit spaţiu (un anumit număr de biţi). În consecinţş, numim

variabilă o zonă de memorie care poarta un nume şi care conţine o anumită valoare,

apartinând unui tip de date.

Programatorul care foloseşte un limbaj de nivel înalt, cum este şi limbajul Java, nu trebuie să

cunoască adresa de memorie, la care este plasată valoarea variabilei, şi nici reprezentarea

Page 35: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

35

internă a acesteia, fiind suficient să-i cunoasca numele şi tipul. Alocarea de spaţiu în memorie

pentru fiecare variabilă se face, după caz, de către compilator sau interpretor. În schimb,

numele şi tipul variabilei trebuie declarate de către programator.

Remarcăm că în matematică operaţiile cu variabile se fac, de cele mai multe ori, la nivel

abstract, asupra simbolurilor variabilelor şi nu asupra valorilor acestora. De exemplu, în

identitatea a+a=2.a nu are importanţa ce valoare are variabila a, egalitatea fiind

întotdeauna adevarată.

În programare se are în vedere faptul că, atât timp cât ea exista în memorie, variabila are

întotdeauna o valoare (deoarece zona de memorie aferentă nu poate fi vidă), iar operaţiile se

fac asupra valorilor variabilelor şi nu asupra numelor acestora.

Declararea şi iniţializarea variabilelor

În limbajul Java, orice variabilă trebuie declarată înainte de a fi utilizată. Prin declararea

variabilei se înţelege precizarea, pentru compilator, a tipului şi numelui acesteia.

Iniţializarea variabilei se face atunci, când acesteia i se dă pentru prima dată o valoare şi

deci i se alocă spaţiu în memorie. Dacă, la declararea variabilei, aceasta nu este şi iniţializată

în mod explicit, atunci ea este iniţializata cu o valoare implicită, care va fi specificată la

descrierea fiecărui tip.

Iată un exemplu de declaraţie de variabilă:

int alpha, beta=3702, k;

Aceasta este o instrucţiune din program, prin care se specifică următoarele:

alpha, beta şi k sunt numele unor variabile de tipul int;

variabilei beta i se dă valoarea iniţiala 3702;

variabilelor alpha si k li se dau valori iniţiale implicite corespunzătoare tipului

int (în cazul de faţă valoarea 0).

Din exemplul de mai sus, se observă că declaraţia de tip are urmatoarea formă:

tip variabila_1, ..., variabila_n;

în care:

tip - numele tipului de date căruia îi aparţin variabilele declarate;

variabila_i - specificarea numelui unei variabile, urmat opţional de valoarea

variabilei respective precedată de simbolul =.

Remarcam că:

declaraţia de tip este o instructiune care se termină obligatoriu prin simbolul ; (punct

şi virgulă);

este posibil ca, într-o singură declaraţie, să apară mai multe variabile; în acest caz,

Page 36: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

36

specificaţiile variabilelor respective sunt separate prin virgule;

indicarea valorii variabilei este opţională.

În declaraţia de tip, valoarea iniţială a variabilei poate fi dată sub forma unui literal sau a

unei expresii. În ultimul caz, este necesar ca expresia să fie calculabilă, deci toate variabilele

pe care le conţine să aiba deja valori date anterior.

Prin convenţie, în limbajul Java numele de variabile încep întotdeauna cu literă mică. Este

permis însă ca, în interiorul numelui, sa existe şi litere mari. Aceasta se întamplă atunci când

numele variabilei este format din mai multe cuvinte ale limbii naturale, de exemplu

vitezaMedie.

Ulterior, la descrierea fiecărui tip de date, vom da şi exemple de declarare a variabilelor de

tipul respectiv.

Variabile finale

În limbajul Java, se numesc variabile finale acele "variabile", ale căror valori nu pot fi

modificate prin program. Acestea sunt deci, de fapt, nişte constante cu nume. Ele se

aseamănă cu variabilele propriu-zise prin faptul că sunt tot perechi nume - valoare, numai că

valoarea lor se dă o singură dată, sub forma de iniţializare în declaraţia de tip sau sub forma

de atribuire, după care nu mai poate fi modificată. Se obişnuieşte ca numele de variabile

finale să fie scrise în întregime cu majuscule.

Declaraţia de tip este la fel cu cea pentru variabile obişnuite, dar are in faţă modificatorul

final, care este un cuvânt cheie.

De exemplu, declaraţia final int ALPHA=17, BETA=-1453;

serveşte pentru a specifică faptul că ALPHA şi BETA suntvariabile finale de tip int, ale

caror valori sunt, respectiv, 17 si -1453 şi nu mai pot fi ulterior modificate (deci ALPHA

şi BETA sunt, de fapt, nişte constante).

Tipuri de date primitive

Tipul de date este unul din conceptele fundamentale ale programării calculatoarelor. Tipul

de date este o mulţime de valori, asociată cu o mulţime de operaţii care se pot face asupra

valorilor respective.

În limbajul Java, tipurile de date se împart în două categorii: tipuriprimitive şi tipuri

referinţă.

Page 37: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

37

Tipurile de date primitive sunt predefinite în limbaj. Aceasta înseamnă că numele, mulţimea

de valori, mulţimea de operaţii şi tipul rezultatului operaţiilor pentu fiecare tip primitiv sunt

impuse prin limbaj şi, deci, nu trebuie definite şi nu pot fi modificate de programator.

Tipurile de date primitive în limbajul Java se clasifică astfel:

tipul boolean;

tipurile numerice

o tipuri intregi: byte, short, int, long;

o tipuri reale: float si double;

o tipul char

Pentru fiecare tip de date vom arăta reprezentarea externă, reprezentarea internă, operaţiile

şi operatorii corespunzători.

Prin reprezentare externă, înţelegem regulile după care se scriu valorile datelor respective în

programe, în documente sau pe ecranul calculatorului. Reprezentarea externă a valorii într-un

program se numeşte literal.

Prin reprezentare internă, înţelegem forma sub care datele respective apar în memoria

maşinii virtuale Java. O proprietate foarte importantă a reprezentării interne a datelor este că

aceasta, fiind destinată maşinii virtuale Java, nu depinde de calculatorul concret pe care se va

executa programul.

Vom începe studiul cu tipul de date boolean, apoi vom studia tipurile numerice propriu-zise

(intregi şi reale), după care vom studia tipul char, ca un tip numeric special.

Operaţii şi operatori

Pentru fiecare tip primitiv de date vom arăta, de asemenea, operaţiile specifice şi operatorii

corespunzători. Pentru început, vom prezenta aici operaţia de atribuire şi operatorii

relaţionali == şi != care se aplică tuturor tipurilor de date. Celelalte operaţii şi operatorii

corespunzători se vor fi prezenta odată cu tipurile de date cărora li se aplică.

Operaţia de atribuire

Prin operaţia de atribuire se dă (se atribuie) unei variabile o nouă valoare, care o înlocuieşte

pe cea deja existentă. Operatorul de atribuire este = (semnul egal, care însă aici se citeşte "se

atribuie") este un operator binar cu efect lateral. Expresia a=b, în care a este o variabila, iar b

este un operand care poate fi un literal, o variabilă sau o expresie, are semnificaţia "se

atribuie variabilei a valoarea operandului b". Atribuirea este posibilă numai daca valoarea

operandului b este de acelasi tip cu variabila a, sau dacă se poate converti implicit la acest

tip. Atribuirea este o operaţie cu efect lateral, deoarece produce modificarea valorii

operandului situat în partea stânga a operatorului de atribuire.

Exemplu

Fie x o variabilă de tip int. Expresia x=-17 se citeste "se atribuie lui x valoarea -17".

Efectul operaţiei de atribuire este, în acest caz, că valoarea anterioară a variabilei x se

înlocuieşte în memorie prin noua valoare. În partea dreaptă a operatorului de atribuire putea fi

nu numai un literal, ca în cazul nostru, ci orice altă expresie cu valoare de tip int.

Page 38: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

38

Operatorii == şi !=

Pentru toate tipurile de date se pot aplica operatorii relaţionali == si !=. Aceştia sunt

operatori binari fără efect lateral. La aplicarea unui astfel de operator, rezultatul operaţiei

este valoarea booleană true (adevărat) sau false (fals).

Operatorul == (se citeşte "este egal cu") exprimă relaţia de egalitate. Expresia a==b, unde a

şi b sunt doi operanzi care pot fi literali, variabile sau expresii, are valoarea logică (booleana)

true dacă valoarile celor doi operanzi sunt egale, sau are valoarea logică false, dacă

egalitatea nu este satisfacută.

Cei doi operanzi trebuie sa fie comparabili, deci fie ambii de tip boolean, fie ambii numerici.

Atragem atenţia asupra deosebirilor esenţiale dintre operatorul de atribuire = si operatorul de

egalitate ==.

a/ Operatorul de atribuire = impune ca operandul din partea stangă sa fie o variabilă, în

timp ce în cazul operatorului de egalitate == ambii operanzi pot fi expresii.

b/ Operatorul de atribuire = are efect lateral, care constă în modificarea valorii variabilei din

partea stangă, în timp ce operatorul == nu are efect lateral, deci valorile ambilor operanzi

rămân neschimbate;

c/ Valoarea expresiei de atribuire a=b este identică cu valoarea atribuita variabilei a şi are

deci tipul acesteia, în timp ce valoarea expresiei a==b este întotdeauna de tip boolean,

indiferent de tipul operanzilor.

Operatorul != (se citeşte "este diferit de") exprimă relaţia de inegalitate a celor doi

operanzi. Expresia a!=b, unde a şi b sunt doi operanzi care pot fi literali, variabile sau

expresii, are valoarea logică (booleană) false dacă valoarile celor doi operanzi sunt diferite,

sau are valoarea logică true, dacă operanzii au valori egale.

Declaraţii de tip

Declararaţiile de tip sunt instrucţiuni prin care se specifică tipul, numele şi, dacă este necesar,

valoarea iniţială a variabilelor folosite în program. În limbajul Java, declaraţiile de tip au

forma: tip variabila1, variabila2, ..., variabilaN; în care:

tip - tipul variabilelor care se declară;

variabila- numele variabilei sau, daca este necesar, numele şi valoarea iniţială date

sub forma nume_variabilă = valoare_iniţială

nume_variabila este un identificator; în limbajul Java se obişnuieşte ca numele de

variabile să înceapă cu literă mică, deşi aceasta nu este o regulă de sintaxă;

valoare_initiala este o valoare de acelaşi tip cu variabila, care se dă variabilei la

iniţializare (în momentul când i se alocă spaţiu în memorie). Această valoare poate fi dată sub

forma unui literal sau a unei expresii calculabile (în care toate variabilele au valori atribuite

anterior).

Remarcăm că specificaţiile variabilelor se separă între ele prin virgule, iar la sfârşitul

declaraţiei se pune simbolul ; (punct şi virgulă) care, în limbajul Java, este terminatorul de

Page 39: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

39

instructiune.

Limbajul Java este strict tipizat, deci orice variabilă trebuie să fie declarată înainte de a fi

folosită. În plus, compilatorul Java verifică dacă, în momentul primei ei utilizări într-o

expresie, variabila are deja o valoare.

Exemplu

Prin instrucţiunea int alpha, beta=-723, gamma=beta+7;

se declară că variabilele alpha, beta şi gamma sunt de tip int. Variabila alpha nu este

iniţializată, beta primeşte valoarea iniţială -723, iar gamma primeşte ca valoare rezultatul

calculării expresiei beta+7. Această expresie este calculabilă, întrucât beta are deja o

valoare.

Tipul boolean

Mulţimea de valori a acestui tip este {true, false}. Ea conţine cele două valori admise de

logica booleană: true înseamnăadevărat, iar false înseamnă fals. Asupra datelor din acest

tip pot fi aplicate operaţiile de atribuire, de comparaţie (== si !=) şi operaţiile algebrei

booleene (operaţiile logice).

Operatorii booleeni

Operatorul de negaţie este un operator unar fără efect lateral şi se reprezintă prin simbolul !

(semnul exclamării). Expresia !a, în care a este un operand boolean, se citeşte non-a şi se

interpretează ca negaţia lui a: daca a are valoarea true, atunci !a are valoarea false şi

invers.

Operatorii logici binari sunt operatori fără efect lateral, prin care se realizează operaţiile

logice ŞI, SAU şi SAU-EXCLUSIV.

- Operatorii & si && realizeaza operatia logica ŞI. Expresiile a&b şi a&&b ,în care a şi

b sunt operanzi de tip boolean, are valoarea true(adevărat) dacă şi numai dacă atât a cât şi

b au valoarea true. În celelalte cazuri expresia are valoarea false.

- Operatorii | si || realizează operaţia logică SAU. Expresiile a|b şi a||b , în care a

şi b sunt operanzi de tip boolean, are valoarea false dacă şi numai dacă ambii operanzi au

valoarea false. În celelalte cazuri expresia are valoarea true.

- Operatorul ^ realizează operatia logică SAU-EXCLUSIV. Expresia a^b , în care a şi

b sunt operanzi de tip boolean, are valoarea true dacă şi numai dacă cei doi operanzi au

valori diferite (unul este adevărat, iar celălalt fals). Dacă cei doi operanzi au valori identice,

valoarea expresiei este false.

Deosebirile între operatorii & şi &&, respectiv între | şi || sunt următoarele:

- în cazul operatorilor & şi | se evaluează în mod obligatoriu ambii operanzi;

- în cazul operatorului &&, numit ŞI-condiţional, evaluarea celui de al doilea operand se

face numai dacă primul operand are valoarea true; altfel, se consideră că operaţia dă

valoarea false, fără a se mai evalua valoarea celui de al doilea operand;

Page 40: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

40

- în cazul operatorului ||, numit SAU-condiţional, evaluarea celui de al doilea operand se

face numai dacă primul operand are valoarea false; altfel, se consideră ca operaţia dă

valoarea true, fără a se mai evalua valoarea celui de al doilea operand.

Vom reveni asupra acestor deosebiri când vom arăta cum sunt tratate în Java expresiile logice

mai complicate.

Acţiunea operatorilor logici este prezentată sintetic în tabela de mai jos, în care a şi b sunt

doi operanzi logici.

a b a&b a&&b a|b a||b a^b

true true true true true true false

true false false false true true true

false false false false false true true

false false false false false false false

În programul din fişierul TipBoolean.java se testează unele din aceste operaţii booleene.

/* Testarea declararii variabilelor booleene si a efectului operatiilor logice */

class TipBoolean { public static void main(String args[]) { boolean alpha=true, beta=false, p, q, r,s; p=!alpha; q=alpha&&beta; r=alpha||beta; s=alpha^beta; System.out.println(" alpha="+alpha+" beta="+beta+" p="+p+ " q="+q+" r="+r+" s="+s); System.out.println("alpha&&beta="+(alpha&&beta)+

"alpha||beta="+(alpha||beta)); System.out.println("alpha==beta: "+(alpha==beta)); System.out.println("alpha!=beta: "+(alpha!=beta)); } }

Executând acest program se obţine următorul rezultat afişat pe ecran:

alpha=true beta=false p=false q=false r=true s=true alpha&&beta=false alpha||beta=true alpha==beta: false alpha!=beta: true

Se observă cu uşurinţă că rezultatele sunt corecte.

Page 41: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

41

Pentru programatorii de C/C++

În limbajele C/C++ nu există tipul de date boolean, astfel că în locul acestuia se folosesc

datele întregi. În consecinţă, în aceste limbaje, operatorii & si | nu sunt consideraţi

operatori booleeni ci operatori logici pe biţi.

În Java nu este permis să se utilizeze expresii aritmetice în locul unor expresii logice

(booleene), aşa cum se întâmplă în C/C++.

Tipuri numerice

Sub aspect conceptual, datele care aparţin acestor tipuri sunt numere, asupra cărora pot fi

aplicate operaţiile aritmetice (adunare, scădere, înmulţire, împărţire) şi operaţiile de

comparaţie aritmetică (mai mic, mai mare, egal, diferit de).

Din punct de vedere matematic, aceste date pot fi numere întregi sau reale. Existenţa mai

multor tipuri în cadrul fiecăreia din aceste două categorii se datoreşte particularităţilor de

reprezentare a datelor în memorie.

Tipurile de date numerice în Java sunt următoarele:

tipuri întregi: byte, short, int, long;

tipuri reale (în virgulă mobilă): float şi double;

tipul char

Inainte de a trece la studierea fiecărui tip de date în parte, vom prezenta unele operaţii care se

aplică tuturor tipurilor de date numerice: atribuirea, conversia de tip, operatiile ariţmetice şi

comparaţia. Exemple pentru aplicarea acestor operaţii se vor da la studierea diferitelor tipuri

concrete de date numerice.

Operaţia de atribuire

Operaţia de atribuire se poate aplica tuturor tipurilor de date, deci şi celor numerice. În

expresia

variabilă = expresie

daca variabila din partea stângă aparţine unuia din tipurile numerice, atunci valoarea

expresiei din partea dreaptă trebuie sa fie, de asemenea, numerică şi să aibă un tip compatibil

cu cel al variabilei din partea stângă. Prin tip compatibil înţelegem fie acelaşi tip cu cel al

variabilei din stânga, fie un tip numeric care poate fi convertit implicit la acesta.

Dacă tipul operandului din dreapta este numeric, dar nu se converteşte implicit la cel din

stânga, se poate folosi conversia de tip explicită prin operatorul cast. În acest caz, însă, există

pericolul ca valoarea să se altereze prin conversie.

Conversia de tip

Dacă este necesar, datele pot fi convertite dintr-un tip în altul. După caz, conversia se poate

face implicit, sau poate fi cerută explicit prin program.

Page 42: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

42

În limbajul Java, conversia de tip implicită se face atunci când prin conversie nu se pierde

informaţie. De exemplu, dacă în expresia a=b variabila a este de tip int, iar b este de tip

short sau byte, valoarea variabilei b va fi automat convertită la tipul int înainte de

atribuire.

În tabela de mai jos sunt indicate cu X toate conversiile de tip care se pot realiza inplicit. În

coloana din stânga este tipul datei care este supusa conversiei, iar în capul tabelei (pe prima

linie) tipul către care se face conversia.

byte short int long float double

byte X X X X X

short X X X X

char X X X X

int X X X

long X X

float X

De exemplu, tipul int se poate converti implicit în oricare din tipurile long, float sau double,

dar nu şi în tipurile byte sau short.

Conversia de tip explicită se face prin operatorul unar numit cast, care are forma (tip),

adică este format din numele tipului către care se face conversia, cuprins între paranteze.

Acesta este un operator fără efect lateral, deci care nu modifică valoarea operandului. De

exemplu, expresia (byte)a se va folosi pentru a converti valoarea operandului a la tipul

byte. Aceasta înseamnă că valoarea variabilei a rămâne neschimbată, însă valoarea expresiei

(byte)a se obţine din cea a lui a prin convertirea ei la tipul byte.

Utilizarea operatorului cast se justifică atunci când, în situaţia respectivă, conversia implicită

nu este posibilă. Nu este însă greşit dacă folosim acest operator chiar şi când conversia

respectivă se poate face şi implicit.

Utilizarea operatorului cast arată faptul că programatorul doreşte să se faca o anumită

conversie, chiar dacă prin aceasta se poate pierde informaţie. Asupra efectelor pe care care

le are conversia explicită vom reveni la prezentarea diferitelor tipuri de date numerice.

Operaţiile aritmetice

Operaţiile aritmetice sunt cele care se aplică unor operanzi numerici, având ca rezultate tot

numere. După numărul de operanzi, ele pot fi unare sau binare. Unele operaţii aritmetice

unare au şi efect lateral.

Tipul rezultatului operaţiilor aritmetice depinde de tipul operanzilor şi va fi discutat la fiecare

din tipurile numerice în parte.

Page 43: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

43

În exemplele de expresii din această secţiune, vom considera că a şi b sunt doi operanzi

numerici.

În limbajul Java există următorii operatori aritmetici:

Operatori unari fără efect lateral:

Operator Exemplu de expresie Valoarea expresiei

+ +a aceeaşi cu valoarea operandului

- -a valoarea operandului cu semn schimbat

Operatori unari cu efect lateral

Operatorii de incrementare ++ şi decrementare -- au ca operanzi variabile numerice.

Operatorul de incrementare ++ are ca efect lateral creşterea cu o unitate a valorii variabilei-

operand, iar operatorul de decrementare -- are ca efect lateral micşorarea cu o unitate a

acestei valori. Acest efect are loc indiferent dacă operatorul este plasat înaintea operandului

sau după acesta. În schimb, poziţia operatorului faţă de operand are importanţă la stabilirea

valorii expresiei rspective. Daca operatorul este plasat în fata operandului, operaţia de

incrementare sau decremantare are loc înainte de a se stabili valoarea expresiei; dacă, însă,

operatorul este plasat dupa operand, valoarea expresiei se stabileşte înainte de a se face

incrementarea sau decrementarea. Efectul operaţiilor este prezentat în tabelul de mai jos.

Operator Expresie Operatie Valoarea expresiei Efect lateral

++ ++a preincrementare a+1 valoarea variabilei a creste cu 1

++ a++ postincrementare a valoarea variabilei a creste cu 1

-- --a predecrementare a-1 valoarea variabilei a scade cu 1

-- a-- postdecrementare a valoarea variabilei a scade cu 1

Operatori binari

Operatorii binari nu au efect lateral - deci nu modifică valorile operanzilor - şi sunt daţi în

tabela de mai jos.

Operator Expresie Operatie Valoarea expresiei

+ a+b adunare suma valorilor operanzilor

- a-b scadere diferenta valorilor operanzilor

* a*b inmultire produsul valorilor operanzilor

/ a/b impartire catul (rezultatul impartirii) primului operand la al doilea

% a%b modulo restul impartirii intregi a primului operand la al doilea

Page 44: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

44

Prin împărţire întreagă înţelegem împărţirea făcută astfel, încât câtul sa fie un număr întreg

(fără extragerea părţii fracţionare (situate dupa virgulă).

Operaţii de atribuire compusă

Urmând tradiţia limbajului C, în limbajul Java există şi operatori de atribuire compusă, în

care operaţia de atribuire este combinată cu una din operaţiile aritmetice.

Operatorii de atribuire compusă sunt următorii: +=, -=, *=, /=, %=, &=, |=, ^=, <<=,

>>=, >>>=.

Se observă că fiecare din aceşti operatori are forma op= în care op este un operator aritmetic

binar. Expresia variabila op= operand

în care op este un operator aritmetic binar, este echivalentă cu expresia variabila = variabila op operand şi se evaluează astfel:

- se calculează mai întâi valoarea expresiei (variabila op operand)în care variabila

intră cu valoarea sa anterioară;

- valoarea astfel calculată se atribuie ca noua valoare a variabilei din partea stânga.

Aceasta nouaă valoare este, totodată, şi valoare a expresiei.

Constatăm astfel că operatorii de atribuire compusă au efect lateral, la fel cu cei de atribuire.

Exemplu

Fie x=3.72 si y=0.19 două variabile de tip double. Expresia x+=y se calculeaza, la fel ca

expresia x=x+y, în modul următor:

- se calculează valoarea expresiei x+y, care este 3.91;

- se atribuie variabilei x valoarea 3.91 (efectul lateral);

- valoarea astfel atribuită (3.91) este considerată şi drept valoare a expresiei x+=y.

Comparaţia

Comparaţiile sunt operaţii binare fără efect lateral, în care se compară două numere,

obţinându-se ca rezultat o valoare de tip boolean. Operatorii prin care se efectuează

comparaţia a două numere se numesc operatori relaţionali şi sunt daţi în tabela de mai jos.

Operator Semnificatie

< mai mic decât

<= mai mic decât sau egal cu

> mai mare decât

>= mai mare decât sau egal cu

== este egal cu

!= este diferit de

Operatorii relaţionali se aplică tuturor tipurilor de date numerice, inclusiv celor de tip char.

Se permite ca cei doi operanzi sa fie de tipuri diferite, de exemplu să se compare o valoare de

tip byte cu una de tip double sau cu una de tip char.

Page 45: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

45

Să consideram, de exemplu, expresia a<b, unde a şi b sunt operanzi de tipuri întregi. Dacă

valoarea operandului a este mai mică decât cea a operandului b, atunci valoarea acestei

expresii este true (adevărat). Dacă însă valoarea lui a nu este mai mică decât cea a lui b, ca

rezultat se obţine valoarea false (fals). Menţionăm că valorile logice true şi false sunt cele

două valori ale tipului de date boolean

Tipuri de date întregi

Tipurile de date întregi sunt byte, short, int, long şi char. Conceptual, datele care

aparţin tipurilor byte, short, int şi long sunt numere întregi, în timp ce tipul char

conţine caractere (litere, cifre, semne de punctuaţie etc).

Întrucât caracterele se codifică în memoria calculatorului prin numere întregi fără semn, în

limbajul Java asupra lor se pot aplica toate operaţiile pentru numere întregi. Totusi, datorită

particularităţilor pe care le prezintă, noi vom trata tipul char separat.

Mulţimile de valori ale tipurilor întregi

Tipurile de date întregi propriu-zise sunt date în tabela de mai jos.

Tipul Lungimea Intervalul de valori

byte 1 octet (8 biţi) [-128, 127]

short 2 octeţi (16 biţi) [-32768, 32767]

int 4 octeţi (32 biţi) [-2147483648, 2147683647]

long 8 octeţi (64 biţi) [-9223372036854775808, 9223372036854775807]

Se observă, deci, că deosebirea dintre diferitele tipuri de date întregi constă în lungimea

reprezentării lor interne, care condiţionează şi mulţimea de valori a tipului respectiv. Este

evident că mulţimea de valori a fiecăruia din aceste tipuri este numai o submulţime a

mulţimii numerelor întregi.

Reprezentarea internă a datelor de tip byte, short, int si long se face sub forma de

numere întregi cu semn, în sistemul de numeraţie binar. Primul bit al reprezentării interne

este interpretat drept semn (0 pentru + si 1 pentru -). Numerele întregi pozitive se

reprezintă, deci, prin numere binare care încep cu cifra 0. Numerele întregi negative se

reprezintă prin complementul la doi al modulului lor.

Avand în vedere că cu n cifre în baza 2 se pot reprezenta 2n valori, se obţin domeniile de

valori indicate în tabelul de mai sus. De exemplu, pentru tipul byte există 28=256 valori.

Limitele domeniilor de valori pentru fiecare tip întreg se pot exprima în binar în funcţie de

numărul de biţi astfel:

- tipul byte: -27

... 27-1;

- tipul short: -215

... 215

-1;

- tipul int: -231

... 231

-1;

- tipul long: -264

... 264

-1.

Page 46: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

46

Sa luăm ca exemplu numerele de tip byte, care se reprezintă intern pe o lungime de 8 biţi.

Cel mai mic numar pozitiv este, în acest caz, 00000000 (deci 0 extins pe toţi cei 8 biţi), iar

cel mai mare numar pozitiv este01111111, care este în sistemul zecimal 27-1, adica 127.

Pentru reprezentarea numerelor negative se foloşeste complementul la 2, care se obtine

astfel: se ia modulul numărului respectiv (în binar) şi se inverseaza toti biţii (din 0 în 1 şi

invers), după care se adună 1 la valoarea astfel obţinută. De exemplu, numarul -108 se va

reprezenta astfel: se ia modulul acestuia, 108, care se reprezinta în binar pe 8 biţi sub forma

01101100. Înversând biţii se obtine 10010011. Adunând 1 (în binar) la acest număr se

obţine 10010100 care este reprezentarea internă a numarului negativ -108 şi are primul bit

1.

Remarcam că numarul -1 se reprezinta intern pe 8 biţi prin 11111111, iar numărul -128 prin

10000000.

Literali de tip întreg

Literalii de tip întreg servesc pentru reprezentarea în program a valorilor numerice de tip

întreg şi pot fi clasificaţi astfel:

după tipul de date: literali de tip int şi de tip long

după sistemul de numeraţie: literali zecimali, octali sau hexazecimali.

Nu există in limbajul Java literali de tip byte sau short. Literalii de tip long se deosebesc de

cei de tip int prin faptul ca se termină prin litera L sau l. Se prefera litera majuscula L,

deoarece litera mică l se poate confunda cu cifra 1.

În sistemul zecimal, literalii întregi sunt şiruri de cifre zecimale care pot fi precedate de

semn şi nu conţin în interiorul lor separatori, cum sunt punctul, virgula sau apostroful (care se

folosesc de noi în scrierea uzuală a numerelor) şi nu incep cu cifra 0.

Exemple corecte de literali întregi în sistemul zecimal:

- de tip int: 0 -5 276315 -176426

- de tip long: 0L -5L 3567286542987L

Exemple de literali întregi scrişi greşit:

27.653.816 (conţine puncte); 5,187 (conţine virgula);

3'876'293 (conţine apostrofuri);

069354 -084931 (încep cu cifra 0).

În sistemul octal, literalii întregi sunt numere cu sau fără semn, scrise în sistemul de

numeraţie octal (cu baza opt) şi care încep cu cifra 0. Amintim că cifrele sistemului octal

sunt 0, 1, 2, 3, 4, 5, 6, 7.

Page 47: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

47

Exemple de literali corecţi în sistemul octal: 016724 -04507

În sistemul hexazecimal, literalii întregi sunt numere cu sau fără semn, scrise în sistemul de

numeraţie hexazecimal (cu baza 16) şi care încep cu prefixul 0x. Amintim că cifrele

sistemului hexazecimal sunt: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F. În locul majusculelor

se pot folosi şi minusculele corespunzătoare.

Exemple de literali corecţi în sistemul hexazecimal: 0x37B2E -0x2ab7f3

Sistemele octal şi hexazecimal prezintă avantajul că au ca baze puteri ale lui 2. Din această

cauză, conversia din aceste sisteme de numeraţie în binar pentru numerele pozitive se face

simplu: fiecare cifra octală se reprezintă în binar prin trei biţi, iar fiecare cifră fexazecimală

prin patru biţi.

De exemplu, numărul octal 15132 (corespunzător literalului 015132) se va reprezenta în

binar prin 001101001011010, iar numărul hexazecimal 6ac3 (corespunzator literalului

0x6ac3) se converteşte în binar prin 0110101011000011.

La conversia inversă, din binar în octal, se grupează cifrele numarului binar câte trei de la

dreapta la stânga, după care se înlocuieşte fiecare grup de trei biţi prin valoarea

corespunzătoare în octal. În mod corespunzător, la conversia din binar în hexazecimal, se

grupează biţii câte patru de la dreapta la stânga şi se înlocuieşte fiecare grup prin cifra

hexazecimală corespunzătoare. De exemplu, numărul binar 0110110010110011 corespunde

numerelor 066263 în octal şi 6cb3 in hexazecimal.

Operaţii şi operatori pentru date de tip întreg

Asupra datelor de tip întreg se pot aplica operaţii de atribuire, de conversie de tip, operaţii

aritmetice, de comparaţie, operaţii de deplasare binară, operaţii logice pe biţi şi operaţii de

atribuire compusă. Primele trei au fost discutate anterior şi vom indica aici numai unele

particularităţi ale aplicării lor în cazul datelor de tipuri întregi.

Conversia de tip şi atribuirea

Diferitele tipuri de date întregi diferă între ele prin lungimea reprezentării lor interne. La

convertirea unui tip mai scurt în unul mai lung (de exemplu a unui byte sau short în int)

valoarea numărului rămâne neschimbată. Din această cauză, această conversie se poate face

implicit. În schimb, la conversia de la o lungime mai mare la una mai mică, se reţin numai

octeţii situaţi în partea dreaptă a numărului, eliminându-se octeţii din stânga care depăşesc

noua lungime. Prin aceasta este posibil să se modifice valoarea numărului şi chiar semnul

lui. Din această cauză, la efectuarea unor astfel de conversii, programatorul trebuie să-şi

asume raăspunderea folosind operatorul cast.

Exemplu

Să considerăm urmatoarea aplicaţie din fişierul CastInt.java.

/* Verificarea actiunii operatorului (cast) in cazul numerelor intregi */

class CastInt {

Page 48: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

48

public static void main(String args[]) { /* Declararea si initializarea variabilelor */ byte b1=73, b2=-107, b3, b4, b5; int i1=91, i2=-103, i3=22195, i4, i5; /* Atribuiri cu conversie implicita de la byte la int */ i4=b1; i5=b2; /* Atribuiri care necesita conversie explicita de la int la byte */ b3=(byte)i1; b4=(byte)i2; b5=(byte)i3; /* Afisarea rezultatelor */ System.out.println("i4="+i4+" i5="+i5+"\nb3="+b3+" b4="+b4+ " b5="+b5); } }

Compilând şi rulând pe calculator această aplicaţie obţinem următorul rezultat afişat pe ecran:

i4=73 i5=-107 b3=91 b4=-103 b5=-77

Analizând aceste rezultate, constatăm că:

- valorile variabilelor i3 şi i4 au fost atribuite corect, deoarece conversia s-a făcut de la

lungimea de un octet la cea de 4 octeţi, astfel că nu s-au alterat valorile;

- valorile variabilelor b3 şi b4 au fost atribuite corect, deşi conversia s-a făcut prin (cast) de

la lungimea de 4 octeţi la cea de 1 octet. Explicaţia este că valorile atribuite se încadrau în

intervalul de valori permise pentru tipul byte;

- în cazul variabilei b5 s-a atribuit valoarea -77, deşi în instrucţiunea b5=(byte)i3

variabila i3 are valoarea 22195. Prin conversie s-au modificat deci atât valoarea, cât şi

semnul, deoarece 22195 nu se încadrează în mulţimea de valori a tipului byte.

Pentru cei interesaţi, putem urmări cum s-au facut efectiv aceste conversii, luând în

consideraţie reprezentările interne.

a/ Atribuirea i4=b1 unde b1 are valoarea 73.

b1 se reprezinta intern prin octetul 01001001. Când se face conversia de la byte la int

se extinde aceasta reprezentare externa prin adaugarea la stânga a trei octeţi nuli. Se obţine

astfel numărul de tip int 00000000000000000000000001001001 care este valoarea 73 pe

4 octeţi.

b/ Atribuirea i5=b2 unde b2 are valoarea negativă -107.

b2 se reprezintă intern prin octetul 10010101 (folosind codul complementar pentru

numere negative). Intrucât primul bit este 1, când se face conversia de la byte la int se

adaugă la stânga trei octeţi completaţi în întregime cu cifra 1, obţinându-se reprezentarea

internă 11111111111111111111111110010101. În acest fel s-a conservat semnul,

obţinându-se tot numărul -107, dar reprezentat pe 4 octeţi.

Page 49: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

49

c/ Atribuirea b3=(byte)i1 unde i1 are valoarea 91. Reprezentarea internă a lui i1 este

00000000000000000000000001011011 şi se extinde pe 4 octeţi. Prin conversia de la int la

byte se elimină cei trei octeţi din stânga, obţinându-se reprezentarea pe un octet 01011011.

Întrucât s-au eliminat numai zerouri din stânga, valoarea a rămas neschimbată.

d/ Atribuirea b4=(byte)i2 unde i2 are valoarea negativă -103. Reprezentarea internă a

lui i2 este 11111111111111111111111110011001 fiind complementul lui 103 extins pe 4

octeţi. Prin conversie la tipul byte se elimină cei trei octeţi din stânga, obţinându-se

10011001 care este tot numărul -103, dar reprezentat pe un singur octet.

e/ Atribuirea b5=(byte)i3, unde i3 are valoarea 22195. Reprezentarea internă a lui i3 pe

patru octeti este 00000000000000000101011010110011. Prin conversie la tipul byte se

elimina cei trei octeţi din stânga, reţinându-se octetul 10110011 care se atribuie ca valoare a

lui b5. Deoarece începe cu bitul 1, aceasta se interpreteaza ca valoarea negativă -77.

Constatăm astfel că prin conversie s-au modificat atât valoarea, cât şi semnul. Aceasta s-a

întâmplat întrucât valoarea de la care a pornit conversia nu se încadra în mulţimea de valori

a tipului byte, iar la eliminarea celor trei octeţi din partea stangă s-au pierdut cifre

semnificative.

Operaţii aritmetice cu numere întregi

Asupra datelor de tip întreg se pot aplica toţi operatorii aritmetici prezentaţi anterior. Vom

prezenta aici numai unele particularităţi ale operaţiilor aritmetice cu numere întregi şi vom da

exemple.

Tipul rezultatului operaţiilor aritmetice cu numere întregi se stabileste astfel:

a/ în cazul operaţiilor de incrementare (++) şi decrementare (--) tipul rezultatului este

acelaşi cu tipul operandului;

b/ pentru toate celelalte operaţii, dacă cel puţin unul din operanzi este de tip long, atunci

rezultatul este de tip long; altfel, rezultatul este de tip int.

Remarcăm, deci, că singurele operaţii aritmetice care pot da rezultat de tip byte sau short

sunt cele de incrementare sau decrementare.

Împarţirea întreagă

O consecinţă a modului de stabilire a rezultatului operaţiilor aritmetice este că, atunci când

se face o operaţie de împărţire (/) între două numere întregi, rezultatul este un numar întreg

(de tip int sau long, după caz). La împărţire se calculează, deci, numai partea întreagă a

câtului.

Excepţia de împărţire la zero

Este posibil ca, în operatia de împarţire întreagă, al doilea operand (împărţitorul) să fie egal

cu zero. În acest caz, maşina virtuală Java generează o excepţie de împărţire la zero, care face

parte din clasa ArithmeticException. În programul de mai jos, din fişierul

ImpartireZero.java, se testează o astfel de situaţie.

Page 50: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

50

/* Testarea exceptiei de impartire la zero */

class ImpartireZero { public static void main(String args[]) { int a=5, b=0, c=0; System.out.println(a/b); } }

Se observă că în expresia a/b opeandul b are valoarea zero. La executarea acestui program se

afişeaza pe ecran următorul mesaj:

Exception in thread "main" java.lang.ArithmeticException: / by zero at

ImpartireZero.main(ImpartireZero.java:6)

Acest mesaj se interpretează astfel: s-a produs o excepţie din clasa ArithmeticException în

firul de execuţie "main"; excepţia constă în împărţire (/) la zero şi a apărut în metoda main a

clasei ImpartireZero, fiind localizată în fişierul sursă ImpartireZero.java linia 6. Se poate

constata cu uşurinţă că, într-adevar, operaţia care a produs excepţia se găseşte în locul indicat.

Înlocuind în acest fişier operaţia a/b prin c/b (astfel încât ambii operanzi sunt nuli)

caonstatăm că, dacă repetăm compilarea şi execuţia, obţinem aceeaşi excepţie. Aşa dar, la

depistarea excepţiei de împărţire la zero, maşina virtuală Java testează numai împărţitorul, nu

şi deîmpărţitul.

Depăşirea binară

La efectuarea unor operaţii cu numere întregi este posibil ca rezultatul să fie un numar binar

mai lung decât spaţiul alocat în memorie pentru tipul de date respectiv. De exemplu, dacă se

înmulţesc două numere de tip int (reprezentate pe 32 biţi fiecare), rezultatul poate fi un

numar mai lung de 32 biţi, deci a cărui valoare nu se mai încadrează în mulţimea de date a

tipului int. O astfel de situaţie se numeşte depăşire binară. În limbajul Java, apariţia

depăşirii binare nu este considerată o excepţie, ci calculul continuă, dar se reţin numai octeţii

din dreapta ai rezultatului, atâţi cât corespund reprezentării interne a tipului de date respectiv

(4 octeţi pentru int şi 8 octeţi pentru long). În consecinţa se pierd octeţii cei mai

semnificativi şi are loc, deci, modificarea valorii şi chiar a semnului rezultatului, la fel ca în

cazul conversiei de la un tip cu lungime mai mare la unul cu lungime mai mică.

Exemplu

În următoarea aplicaţie din fişierul Intregi.java se fac unele teste privind operaţiile cu numere

întregi.

class Intregi { public static void main(String args[]) { byte b1=73, b2=-109, b3, b4, b5; short s1=9000, s2=-11000, s3; int i1=900000, i2=-1100000, i3, i4, i5; long m1=10000000000L, m2=-200000000000L, m3, m4; b3=(byte)(-b2);

Page 51: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

51

b4=(byte)(b1+b2); b5=++b1; s3=(short)(s2/s1); s4=(short)(s2%s1); // restul impartirii s2/s1 i3=i1+i2; i4=i1*i2; i5=(int)(m2/i1); m3=m2-m1; m4=m2*m1; System.out.println("b3="+b3+" b4="+b4+" b5="+b5); System.out.println("s3="+s3+" s4="+s4); System.out.println("i3="+i3+" i4="+i4+" i5="+i5); System.out.println("m3="+m3+" m4="+m4); System.out.println("b5*b2="+(b5*b2)+ "s1*s2="+(s1*s2)); } }

Remarcăm că la calcularea valorilor variabilelor b3, b4 şi s3 a fost necesar să se folosească

conversia explicită (cast), deoarece valorile expresiilor din paranteze din partea dreaptă a

operandului de atribuire sunt de tip int, în timp ce variabilele din partea stânga sunt de tip

byte sau short. În mod similar s-a folosit castul la calcularea lui i5, deoarece expresia

m2/m1 este de tipul long. Se poate constata cu usurinţă, suprimând din program operatorii

cast din expresiile respective, că dacă nu se folosesc aceşti operatori sunt semnalate erori de

compilare. În schimb, nu a fost necesar să se recurgă la cast la calcularea valorii lui b5,

deoarece expresia ++b este de tip byte.

Executând acest program, se obţin pe ecran următoarele rezultate:

b3=109 b4=-36 b5=74 s3=-1 s4=-2000 i3=-200000 i4=2137445376 i5=-222222 m3=-210000000000 m4=-7751640039368425472 b5*b2=-8066 s1*s2=-99000000

Din aceste rezultate constatăm că:

- s-a obţinut s3=-1 si nu s3=-1.222222... deoarece în expresia s2/s1 ambii operanzi sunt

de tipuri întregi, deci rezultatul este întreg (împărţire întreagă). Din acelaşi motiv s-a obţinut

i5=-222222 si nu -222222.222222....;

- la calcularea lui i4 nu s-a obţinut valoarea corectă -990000000000, ci valoarea

2137445376. Cauza este că valoarea depăşeşte marginea superioară a valorilor de tip int,

deci s-a produs o depăşire binară şi s-au trunchiat octeţii cei mai semnificativi. Tot o depăşire

binară s-a produs şi la calcularea lui m4 (de data aceasta pentru tipul long);

- valorile produselor b5*b2 şi s1*s2 au fost calculate şi afisate corect, deşi ele depăşesc

limitele mulţimilor de valori de tip byte, respectiv de tip short. Aceasta s-a produs deoarece

expresiile respective sunt de tip int.

Comparaţia

Operatorii de comparaţie pot fi aplicaţi pentru orice fel de operanzi numerici. Ca exemplu, în

fişierul ComparInt.java se da un program, în care se compară diferite numere întregi şi se

Page 52: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

52

afişează rezultatele.

/* Testarea operatorilor de comparatie in cazul tipurilor de date intregi */

class ComparInt { public static void main(String args[]) { byte b1=48, b2=-17; short s1=2765, s2=-12970; int i1=762983, i2=48, i3=-12970; long m1=876432906528L, m2=48; System.out.println(b1==b2); System.out.println(b1==i2); System.out.println(s1!=i2); System.out.println(i2!=m2); System.out.println(m2>i2); System.out.println(m2>=i2); System.out.println(s2<i3); System.out.println(i3<=s2); } }

Executând acest program se obţin pe ecran următoarele rezultate sub forma de valori

booleene:

false

true

true

talse

true

talse

true

Page 53: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

53

Având în vedere că true înseamnă adevărat, iar false înseamnă fals, se poate constata cu uşurinta că aceste rezultate sunt corecte. Remarcăm, de asemenea, că rezultatul comparaţiei depinde numai de valorile numerelor comparate, nu şi de tipul acestora. Operaţii de deplasare binară

Urmând "tradiţia" limbajului C, limbajul Java conţine şi operatori de deplasare binară.

Aceştia sunt operatori binari (cu doi operanzi) fără efect lateral. Tipul rezultatului operaţiei se

stabileşte la fel ca în cazul operaţiilor aritmetice cu numere întregi. Valoarea rezultată se

stabileşte astfel: se ia reprezentarea internă a primului operand şi se deplasează la stânga sau

la dreapta cu un numar de poziţii binare egal cu cel de al doilea operand.

Operatorii de deplasare şi efectele lor sunt prezentate în tabela de mai jos, în care a şi s sunt

operanzi care aparţin unor tipuri întregi.

Operator Expresie Efect

<< a<<s deplasare la stânga cu s poziţii binare

>> a>>s deplasare la dreapta cu s poziţii binare, cu conservarea semnului

>>> a>>>s deplasare la dreapta fără semn, cu s poziţii binare

Deplasarea la stânga cu s poziţii este echivalenta cu înmulţirea numărului cu 2s. Dacă s este

suficient de mare, poate avea loc o depăşire binară, la fel ca în cazul înmulţirii aritmetice (cu

operatorul *).

Deplasarea la dreapta cu s poziţii cu operatorul >> este echivalenta cu împărţirea întreagă

la 2s.

Deplasarea biţilor la dreapta cu s pozitii cu operatorul >>> are asupra numerelor pozitive

acelaşi efect ca cel al operatorului >>. În schimb, în cazul operanzilor negativi, în cazul

operatorului >>> nu se mai conservă semnul, iar modulul numărului se modifică. Aceasta se

întâmplă, întrucât pe poziţiile eliberate din partea stângă se înserează bitul 0.

Exemplu

În fişierul Deplasari.java se dă un exemplu de aplicaţie, în care se testează acţiunea

operatorilor de deplasare binară.

/* Testarea operatiilor de deplasare binara */

class Deplasari { public static void main(String args[]) { byte b1=15, b2; int i1=1024, i2=-1024; b2=(byte)(b1<<3); System.out.println("b1="+b1+" b2="+b2); System.out.println("i1<<4="+(i1<<4)+" i1>>4="+(i1>>4)+ " i1>>>4="+(i1>>>4));

Page 54: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

54

System.out.println("i2<<4="+(i2<<4)+" i2>>4="+(i2>>4)+ " i2>>>4="+(i2>>>4)); } }

Rezultatele afişate la executarea acestui program sunt următoarele:

b1=15 b2=120 i1<<4=16384 i1>>4=64 i1>>>4=64 i2<<4=-16384 i2>>4=-64 i2>>>4=268435392

Având în vedere că 23=8 şi 2

4=16, rezultatele obţinute pot fi verificate cu uşurinţă. Constatăm

ca singura deosebire dintre efectele operatorilor >> şi >>> apare când primul operand este

negativ.

Operatorul >>> nu există în limbajul C, el fiind introdus numai în Java.

Pentru a inţelege mai bine efectul operatorilor de deplasare, să urmărim ce se întâmplă în

exemplul de mai sus la nivelul reprezentării interne a datelor (în binar).

Având în vedere că 1024=210

, reprezentările interne ale operanzilor i1 şi i2 sunt

următoarele: i1=00000000000000000000010000000000 i2=11111111111111111111110000000000 După aplicarea operatorului << (deplasare binară la stânga cu inserare de zerouri pe spaţiile

libere din dreapta) obţinem:

- pentru operaţia i1<<4: 00000000000000000100000000000000

- pentru operaţia i2<<4: 11111111111111111100000000000000

ceeace reprezintă în zecimal numerele 214

=16384 si, respectiv, -214

=-16384.

După aplicarea operatorului >> (deplasare la dreapta cu conservarea semnului) se obţine:

- pentru operaţia i1>>4: 00000000000000000000000001000000

- pentru operaţia i2>>4: 11111111111111111111111111000000

ceeace reprezintă în sistemul zecimal numerele 26=64 şi, respectiv, -2

6=-64. Remarcăm că

în cazul operandului negativ i2, la deplasarea la dreapta s-a înserat pe poziţiile libere bitul 1

pentru a se conserva semnul.

După aplicarea operatorului >>> (deplasare la dreapta fără conservarea semnului) se obţine:

- pentru operaţia i1>>>4: 00000000000000000000000001000000

- pentru operaţia i2>>>4: 00001111111111111111111111000000

Pentru operandul pozitiv i1 s-a obţinut un rezultat identic cu cel precedent. În schimb, în

cazul operandului negativ i2, pe poziţiile eliberate din partea stângă s-a înserat bitul 0,

ceeace a dus la schimbarea semnului şi a valorii rezultatului faţă de cazul deplăsarii cu

conservarea semnului.

Operaţii logice pe biţi

Tot urmând "tradiţia" limbajelor C/C++, în limbajul Java se pot utiliza pentru tipurile de date

Page 55: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

55

întregi şi operatorii logici pe biţi ~, &, | si ^. Aceştia sunt operatori fără efect lateral.

Operaţiile logice se fac la nivel de bit, adică între fiecare bit al operandului din stânga şi bitul

corespunzător al operandului din dreapta, considerându-se ca 0 este echivalent cu false, iar

1 este echivalent cu true.

Operatorul unar ~ exprimă negaţia logică, deci înlocuirea lui 0 cu 1 şi invers.

Operatorii binari &, | si ^ acţionează la fel ca în cazul tipului boolean, numai că se

aplică la nivel de bit.

Acţiunea operatorilor este dată în tabela de mai jos, în care a şi b sunt cei doi operanzi, iar ai

si bisunt biţii de pe pozitia i a acestor operanzi. În tabelă se dă efectul fiecărei operaţii asupra

bitului i al rezultatului.

ai bi ~a a&b a|b a^b

0 0 1 0 0 0

0 1 1 0 1 1

1 0 0 0 1 1

1 1 0 1 1 0

Exemplu

În fişierul LogicaBiti.java este dat un exemplu de program, în care se testează operaţiile

logice pe biţi. Pentru a se verifica manual mai uşor, am considerat că opraţiile se fac asupra

datelor de tip byte. Este bine să avem însă in vedere că rezultatele operaţiilor sunt de tip

int. Aceasta se poate constata cu usurinţa dacă încercăm să eliminăm castul din instrucţiunea

în care se calculează b3.

/* Testarea operatiilor logice pe biti */

class LogicaBiti { public static void main(String args[]) { byte b1=17, b2=-95, b3; b3=(byte)(b1&b2); // este necesara conversie de la int la byte System.out.println("~b1="+(~b1)+" b1&b2="+b3+" b1|b2="+(b1|b2)+ " b1^b2="+(b1^b2)); } }

Rezultatele afişate la executarea acestui program sunt următoarele:

~b1=-18 b1&b2=1 b1|b2=-79 b1^b2=-80

Iată şi cum decurg operaţiile din exemplul de mai sus la nivel de bit:

b1: 00010001 echivalent cu 17

b2: 10100001 echivalent cu -95

~b1: 11101110 echivalent cu -18

Page 56: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

56

b1&b2: 00000001 echivalent cu 1

b1|b2: 10110001 echivalent cu -79

b1^b2: 10110000 echibalent cu -80

Bineînţeles că toate aceste rezultate ar trebui exprimate pe 32 biţi, prin prelungire la stânga

cu cate 18 cifre de 0 sau de 1 după caz, astfel încât să se conserve semnul.

Aplicarea operatorilor de atribuire compusă

Pentru operanzii de tipuri întregi se pot aplica toţi operatorii de atribuire compusă +=, -=,

*=, /=, %=, &=, |=, ^=, <<=, >>=, >>=.

Exemplu

În programul din fişierul AtribComp.java se testează unele operaţii de atribuire compusă. Iată

acest program:

/* Testarea operatorilor de atribuire compusa */

class AtribComp { public static void main(String args[]) { int m=176, b=-15, c=16, d=-28; System.out.println(m+" "+(m+=b)+" "+m); System.out.println((m/=d)+" "+m); System.out.println(b+" "+(b<<=2)+" "+b); System.out.println(c+" "+(c|=b)+" "+c); } }

La executarea programului se obţin pe ecran următoarele rezultate:

176 161 161 -5 -5 -15 -60 -60 16 -44 -44

Prima linie afişată conţine:

- valoarea variabilei m înainte de evaluarea expresiei m+=b;

- valoarea expresiei m+=b; ea este egală cu m+b adică cu 176-15;

- valoarea variabilei m după calcularea acestei expresii.

Recomandăm sa explicaţi în mod similar şi celelalte linii afişate.

Page 57: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

57

Tipuri de date în virgulă mobilă

Mulţimile de valori pentru tipurile de date în virgulă mobilă

Conceptual, datele care aparţin acestor tipuri sunt numere reale. În limbajul Java există două

tipuri de date reale (numite şi tipuri de date flotante sau în virgulă mobilă):

Tipul Lungimea Intervalul de valori

float 4 octeti (32 biti) [-3.402347e+38f, ... 3.402347e38f]

double 8 octeti (64 biti) [-1.7976931348623157e+308, ... 1.7976931348623157e308]

Reprezentarea internă a datelor în virgulă mobilă adoptată pentru maşina virtuală Java

corespunde standardului ANSI/IEEE 754-1985.

Reprezentarea externă a numerelor în virgulă mobilă se poate face în următoarele moduri:

a/ ca numere reale fără exponent, în care partea întreagă este separată de cea fracţionara

prin punct;

b/ ca numere reale cu exponent, în care un număr întreg sau unul real fără exponent, numit

mantisa sau coeficient, este urmat de un exponent zecimal, format din litera e sau E urmata

de un numar intreg. Semnificaţia este că mantisa se înmulteşte cu 10 ridicat la o putere egală

cu exponentul.

O caracteristică importantă a numerelor în virgulă mobilă este precizia. Se numeşte precizie

numărul maxim de cifre semnificative pe care îl poate avea mantisa pentru tipul de date

respectiv. Aceasta depinde de numărul de biţi alocaţi mantisei în reprezentarea internă. În

cazul limbajului Java, datele de tip float pot avea cel mult 7 cifre semnificative, iar cele de

tip double cel mult 16 cifre semnificative. În reprezentarea externă a numărului se pot

folosi şi mai multe cifre, dar cele care depăşesc lungimea admisă nu vor fi luate în

consideraţie la conversia din forma externă în cea internă.

Cifrele semnificative sunt cifrele mantisei numărului, care încep de la prima cifră diferită de

zero şi se termină cu ultima cifra diferita de zero. De exemplu, numărul 000102.3015000 are

7 cifre semnificative (cele subliniate), deoarece zerourile de la început şi de la sfârşit nu

influenţează valoarea numărului.

Acelaşi număr poate avea diferite reprezentări externe, de exemplu: 102.3015,

10.23015E1, 1.023015E2, 0.1023015E3, 0.01023015E4 etc. Pentru toate aceste numere,

reprezentarea internă va fi aceeaşi.

Menţionăm că numerele de mai sus, deşi au numai 7 cifre semnificative, vor fi reprezentate

intern ca numere de tip double, deci pe 8 octeţi fiecare. Pentru a fi reprezentate intern ca

date de tip float (pe 4 octeti) trebuie scrise cu litera f sau F la sfârşit, de exemplu 102.3015f.

În afară de valorile numerice, pentru datele în virgulă mobilă sunt prevăzute şi următoarele

valori speciale:

Page 58: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

58

Infinity - corespunde valorii plus infinit;

-Infinity - corespunde valorii minus infinit;

NaN - reprezintă ceva care nu este număr (Nota Number).

În consecinţă, în cazul datelor de tipuri reale, dacă a este un numar real pozitiv, operaţia

a/0.0 dă ca rezultat Infinity, iar operaţia a/(-0.0) da rezultatul -Infinity. Operaţia

0.0/0.0 dă rezultatul NaN.

Atenţie: valorile Infinity, -Infinity şi NaN sunt formele externe sub care acestea se

afişează pe ecran, se tipăresc la imprimantă sau se scriu într-un fişier de text. Fiecăreia dintre

ele îi corespunde o reprezentare internă, sub forma unui şir de 4 sau 8 octeţi, corespunzător

tipului float sau double. Aceste reprezentări interne respectă regula, conform căreia, dacă

sunt interpretate ca numere în virgulă mobilă, îndeplinesc următoarele condiţii:

Infinity este mai mare decat orice valoare de tipul respectiv;

-Infinity este mai mică decât orice valoare de tipul respectiv.

În acest fel, valorile menţionate păstrează consistenţa operaţiilor de comparaţie.

Literalii în virgulă mobilă

Literalii în virgulă mobilă sunt reprezentările valorilor reale în programele Java. La scrierea

literalilor se respectă formele externe de numere reale fără exponent sau cu exponent

prezentate mai sus, cu precizarea ca literalii de tip float se termina cu litera f sau F, în timp

ce literalii de tip double nu au un astfel de sufix.

Exemple de literali în virgulă mobilă

a/ literali de tip float fără exponent: 123.7f, -1876.53f;

b/ literali de tip float cu exponent:

7.28765e12f (echivalent cu 7.28765x1012

)

5.0754286e-8f (echivalent cu 5.075428x10-8

)

-3.9104e3f (echivalent cu -3.9104x103)

c/ literali de tip double fără exponent: 154236789.20973, -3401.76398653;

d/ literali de tip double cu exponent: 2935.87628091e-12 -1.20937543872E23

12e23 (echivalent cu 12.0x1023

)

Atât la tipul float, cât şi la tipul double, valoarea 0.0 are semn: poate exista atât +0.0 cât şi

-0.0. Un 0 fără semn este echivalent cu +0.0. Pentru tipul float, aceste valori sunt scrise

sub forma +0.0f şi -0.0f.

Valorile speciale Infinity, -Infinity şi NaN nu sunt literali, ci doar forme externe de

afişare a valorilor interne corespunzătoare. În consecinţă, ele nu pot fi folosite în programele

sursă. De exemplu, daca x este o variabilă în virgulă mobilă, nu putem face atribuirea

x=Infinity.

Operaţii şi operatori pentru date în virgulă mobilă

Asupra datelor în virgulă mobilă se pot aplica operaţii de atribuire, de conversie de tip,

operaţii aritmetice şi de comparaţie, atribuirea compusă. Acestea au fost deja prezentate,

Page 59: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

59

astfel că vom indica aici numai unele particularităţi ale aplicării lor în cazul datelor în virgulă

mobilă.

Conversia de tip şi atribuirea

S-a arătat deja ca orice dată numerică de tip întreg se poate converti implicit în oricare din

tipurile în virgulă mobilă. De asemenea, are loc conversie implicită de la float la double. În

consecinţă, folosirea conversiei explicite (cast) este necesară atunci când se trece de la

double la float, sau de la un tip în virgulă mobilă la unul întreg.

Conversia din double în float nu conduce niciodata la alterarea valorii, ci numai la pierderea

de precizie. Aceasta se produce, întrucat se trece de la o mantisă de 52 de biţi la una de 24 biţi

, deci de la cca 17 cifre semnificative la numai cca 7 cifre semnificative în sistemul zecimal.

În schimb, conversia explicită de la date în virgulă mobilă la oricare din datele de tip întreg

poate duce la denaturarea valorii şi a semnului numărului, la fel ca în cazul tipurilor intregi.

Aceasta se întâmplă atunci când valoarea care trebuie convertită nu se încadrează în mulţimea

de valori specifică tipului în care se face conversia.

Unei variabile în virgulă mobilă i se pot atribui orice valori de tipuri numerice.

Operaţii aritmetice cu numere reale

Asupra datelor în virgulă mobilă se pot aplica toţi operatorii aritmetici prezentaţi anterior,

inclusiv operatorii de incrementare (++), decrementare (--) şi restul împărţirii întregi (%).

Vom prezenta aici numai unele particularităţi ale operaţiilor aritmetice în virgulă mobilă şi

vom da exemple.

O particularitate importantă a operaţiilor aritmetice în virgulă mobilă în limbajul Java este că

împărţirea la zero nu mai este considerată o exceptie, ci este o operaţie permisă. Rezultatul

împărţirii la zero depinde de valoarea deîmpărţitului şi de semnele celor doi operanzi.

Rezultatul împărţirii 0/0 este NaN (Not a Number, deci o valoare nedefinită). Dacă

deîmpărţitul este diferit de zero, rezultatul împărţirii este Infinity cu un semn care se

stabileşte după semnele celor doi operanzi: + (plus) dacă au acelaşi semn, sau - (minus)dacă

semnele operanzilor sunt diferite. Amintim că la numerele în virgulă mobilă în Java şi

valoarea zero are semn, deci există +0.0 si -0.0.

Exemplu

În programul din fişierul VirgulaMobila.java, pe care îl reproducem mai jos, se testează

diferite operaţii aritmetice în virgulă mobilă, inclusiv cele care au ca rezultate valori speciale.

/* Testarea operatiilor aritmetice cu numere in virgula mobila */

class VirgulaMobila { public static void main(String args[]) { double a=12.7865, b=-158.07, c=0.0, d=-0.0, inf1, inf2, n; float p=3476.15f, q=0.00237621f, r=0.0f, s=-0.0f; System.out.println("a/b="+(a/b)+" b/a="+(b/a)+" b%a="+(b%a)); System.out.println("a/c="+(a/c)+" b/c="+(b/c)); System.out.println("a/d="+(a/d)+" b/d="+(b/d));

Page 60: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

60

System.out.println("c/d="+(c/d)+" d/c="+(d/c)); System.out.println("p/q="+(p/q)+" q/p="+(q/p)+" p%q="+(p%q)); System.out.println("p/r="+(p/r)+" p/s="+(p/s)); System.out.println("a/q="+(a/q)+" p/b="+(p/b)); inf1=a/c; inf2=a/d; n=c/d; System.out.println("a/inf1="+(a/inf1)+" a/inf2="+(a/inf2)); System.out.println("inf1/inf2="+(inf1/inf2)+" inf2/inf1="+ (inf2/inf1)); System.out.println("a*inf1="+(a*inf1)+" c*inf1="+(c*inf1)); } }

La executarea acestui program se afişează următorul rezultat:

a/b=-0.08089137723793256 b/a=-12.362257068001407 b%a=-4.631999999999991 a/c=Infinity b/c=-Infinity a/d=-Infinity b/d=Infinity c/d=NaN d/c=NaN p/q=1462896.8 q/p=6.835752E-7 p%q=0.001879394 p/r=Infinity p/s=-Infinity a/q=5381.048097062204 p/b=-21.991205809728285 a/inf1=0.0 a/inf2=-0.0 inf1/inf2=NaN inf2/inf1=NaN a*inf1=Infinity c*inf1=NaN

Din aceste rezultate constatăm că:

- operaţiile cu infiniţi şi nedeterminări respectă regulile cunoscute din matematică

(împărţirea la zero dă rezultat infinit, iar 0/0, infinit impartit la infinit şi zero înmulţit cu

infinit sunt nedeterminări);

- dacă cel puţin un operand este în dublă precizie (double), rezultatul este în dublă

precizie; dacă ambii operanzi sunt în simplă precizie (float), rezultatul este float;

- se verifică egalitatea [b/a]*a+(b%a)=b, in care [b/a] este partea intreagă a câtului b/a,

iar b%a este restul împărţirii întregi a lui b la a; de exemplu, (-12)*12.7865-4.632=-

158.07.

Comparaţia

Pentru datele in virgula mobilă se aplică aceiaşi operatori de comparatie (relaţionali) ca şi

pentru numerele întregi.

Atribuirea compusă

În cazul tipurilor de date reale se aplică următorii operatori de atribuire compusă:+=, -=,

*=, /=, %=.

Page 61: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

61

Tipul char

Tipul de date char

Datele de tip char sunt caractere, adică simboluri tipografice elementare: litere, cifre, semne

de punctuaţie, simboluri matematice, etc.

În limbajul Java, reprezentarea internă a caracterelor se face pe 2 octeţi (16 biţi), în sistemul

Unicode. In acest sistem, caracterele sunt codificate în memoria internă prin numere întregi

pozitive în intervalul [0, 65535]. În fluxurile de date de intrare/ieşire şi în fişiere, caracterele

pot fi reprezentate şi în alte coduri. Codul cel mai frecvent folosit în aceste scopuri este

ASCII, în care reprezentarea caracterelor se face pe un singur octet, deci prin numere întregi

fără semn în intervalul [0, 255].

Remarcăm ca datele de tip char sunt singurul tip de date întregi fără semn din limbajul Java,

mulţimea de valori a acestui tip de date fiind intervalul de numere naturale [0, 65535].

Reprezentarea externă a caracterelor se face în una din următoarele forme:

a/ punând caracterul respectiv între apostrofuri: 'a', 'B', '+', '(', '3', etc;

b/ folosind o secvenţă escape, în care apare codul numeric hexazecimal al caracterului

respectiv, în Unicode, de ex: '\u006c' sau '\uffff'; într-o astfel de secvenţă, codul

numeric al caracterului (format din patru cifre hexazecimale) este precedat de \u;

c/ folosind o secventa escape pentru caracterele speciale din urmatorul tabel:

Caracterul Reprezentarea in Unicode Semnificatia

'\b' '\u0008' deplasare la stânga cu o poziţie (backspace)

'\t' '\u0009' tabulare orizontală (horizontal tab)

'\n' '\u000a' trecere la linie nouă (line feed, NL)

'\f' '\u000c' salt la pagina nouă (form feed)

'\r' '\u000d' întoarcerea carului (carriage return, CR)

'\"' '\u0022' ghilimele (double quote)

'\'' '\u0027' apostrof (single quote)

'\\' '\u005c' bară inversă (backslash)

Datele de tip char pot fi folosite în operaţii numerice, în care caz ele sunt interpretate drept

numere intregi fără semn, conform cu reprezentarea lor internă prin numere binare. Din acest

motiv, în limbajul Java datele de tip char sunt incluse în categoria celor de tipuri întregi.

În programele Java, secvenţele escape pot fi folosite pentru a reprezenta caracterele în orice

loc din textul sursa. Peste tot unde întâlneşte în textul sursă caracterul \ (bara inversă,

backslash), compilatorul consideră că urmeaza o secvenţă escape, pe care o înlocuieşte cu

caracterele Unicode corespunzătoare.

Exemplul 1

Şirul de caractere "abc\"def" conţine secventa escape \", care se va inlocui cu codul

Page 62: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

62

caracterului ", obţinându-se şirul abc"def. Acelasi şir de caractere putea fi scris sub forma

"abc\u0022def", în care în loc de secvenţa escape \" s-a folosit direct cea care conţine

valoarea numerica din Unicode a caracterului ", respectiv \u0022.

Exemplul 2

Ştiind că reprezentările în Unicode ale literelor e şi t sunt, respectiv, \u0065 şi

\u0074, instrucţiunea System.out.println("Exemplu"); poate fi scrisă sub forma Sys\u0074\u0065m.ou\u0074.prin\u0074ln("Ex\u0065mplu");

Desigur că o astfel de înlocuire a caracterelor prin secvenţe escape nu este justificată în

cazul caracterelor obişnuite, dar este utilă în cazul folosirii caracterelor speciale, cum sunt

caracterul de trecere la lini noua '\n' şi altele.

Operaţii şi operatori pentru date de tip char

În limbajul Java, tipul char este considerat tip de date întregi. În consecinţă, toate operaţiile

care se aplică tipurilor întregi se aplică şi asupra tipului char. Atunci când un caracter se

foloseşte ca numar întreg se operează, evident, cu reprezentarea internă a caracterului

respectiv, tratată ca numar natural.

Exemplu

În programul de mai jos, dat in fişierul TestChar.java, se testează unele operaţii cu date de tip

char.

/* Operatii cu date de tip char */

class TestChar { public static void main(String args[]) { char c1='A', c2='a', c3='b', c4='1', c5='*', c6='\n'; System.out.println(c1+" "+c2+" "+c6+" "+c4+" "+c5+" "+c3); System.out.println((int)c1+" "+(int)c2+" "+(int)c6+" "+ (int)c4+" "+(int)c5); System.out.println(c1+c2); System.out.println(c1*c2); System.out.println((char)107); System.out.println('2'+" "+(int)'2'+" "+'3'+" "+(int)'3'+ " "+('2'+'3')); } }

La executarea acestui program, rezultatele afişate pe ecran sunt cele de mai jos:

A a 1 * b 65 97 10 49 42 162 6305 k 2 50 3 51 101

Page 63: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

63

După afişarea caracterelor A şi a s-a transmis către dispozitivul de afişare caracterul '\n',

care a fost interpretat drept comanda de trecere la linie nouă. După aceasta au fost afşsate

caracterele 1, * şi b. Pe linia următoare sunt afişate caracterele deja afişate anterior, convertite

în numere întregi. Se observă că în Unicode caracterul 'A' este reprezentat prin numarul 65,

caracterul 'a' prin numarul 97, caracterul '\n' prin 10 etc.

Pe următoarele două linii sunt afişate rezultatele operaţiilor 'c1'+'c2' si 'c1'*'c2',

obţinându-se respectiv valorile numerice 162 si 6305. Se observă că, întrucât caracterele au

fost folosite ca operanzi ai unor operatori aritmetici, rezultatele obţinute sunt numerice (de tip

int).

Pe linia următoare se afişează numărul 107 convertit din int în char şi interpretat deci drept

'k';

Pe ultima linie putem observa deosebirea dintre forma externă a caracterului (literalul de tip

char) şi codificarea lui interna. Literalul de tip char '2' este caracterul 2 si nu numarul 2. În

consecinţă, acest caracter nu se reprezinta intern prin numarul întreg 2, ci prin numărul întreg

50. În mod corespunzator, caracterul '3' se reprezinta intern prin numarul 51. Suma

codurilor numerice ale celor doua caractere este, evident, numărul 101.

Întrebări

Nivel 1

1. Ce este un comentariu?

2. Ce fel de comentarii pot să apară în fişierele sursă Java?

3. Cum se reprezintă un şir în program?

4. Ce este concatenarea şi care este operatorul prin care se realizează?

5. Prin ce metode se afişează un şir de caractere pe ecran?

6. Ce sunt identificatorii şi cum se alcătuiesc ei în Java?

7. Ce sunt cuvintele cheie?

8. Ce este un literal?

9. Ce separatori se folosesc în limbajul Java?

10. Ce sunt operatorii?

11. Ce este efectul lateral al operatorului?

12. Toţi operatorii au efect lateral?

13. Ce sunt variabilele?

14. Ce este numele variabilei?

15. Ce se înţelege prin declararea variabilei?

16. Ce este o variabilă finală?

17. Ce este un tip de date?

18. Ce tipuri de date primitive există în limbajul Java?

19. Care este mulţimea de valori a tipului boolean?

20. Care este operatorul de negaţie, asupra cărui tip de date se aplică şi ce efect are?

21. Ce sunt operatorii logici & si &&?

22. Ce sunt operatorii logici | si ||?

23. Care sunt tipurile de date numerice?

24. Ce este operaţia de atribuire?

Page 64: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

64

25. Cum acţionează operatorii == şi !=?

26. Ce efect are operatorul logic ^?

27. Ce contine o declaraţie de tip?

28. Ce este conversia de tip?

29. Ce este castul şi care este forma lui sintactică?

30. Care sunt operatorii de incrementare şi decrementare?

31. Ce operatori de comparaţie se folosesc în cazul datelor de tipuri întregi?

32. Cum se reprezintă intern datele de tipuri întregi?

33. Cum se scriu literalii în sistemul octal?

34. Cum se scriu literalii in sistemul hexazecimal?

35. Pot avea semn literalii octali şi cei hexazecimali?

36. Ce sunt datele în virgulă mobilă şi ce corespondent au ele în matematică?

37. Ce tipuri de date în virgulă mobilă există în Java?

38. Ce sunt literalii în virgulă mobilă?

39. Ce valori speciale pot avea literalii în virgulă mobilă?

40. Ce operaţii aritmetice se poa efectua asupra numerelor în virgulă mobilă?

41. Ce se întâmplă dacă, la o împărţire în virgulă mobilă, împărţitorul are valoarea zero?

42. Ce fel de date conţine tipul char?

43. Cum se reprezintă literalii de tip char?

44. Ce este o secvenţă escape? daţi exemple.

45. Ce operaţii se pot face supra datelor de tip char?

46. Care sunt operatorii de atribuire compusă şi ce efect au?

Nivel 2

1. Ce proprietăţi are operatorul de concatenare?

2. Este concatenarea asociativă? Dar comutativă?

3. Se poate oare folosi metoda print() în loc de println()?

4. Cu ce fel de caracter încep în Java numele de clase?

5. Ce deosebire este între literali şi identificatori?

6. De câte feluri sunt operatorii după numărul de operanzi?

7. Cum se plasează operatorii unari în raport cu operanzii lor? Dar cei binari?

8. Există operatori ternari?

9. Daţi o definiţie conceptului de variabilă.

10. Prin ce simbol se termina o declaraţie de variabile?

11. În ce mod se iniţializează o variabilă?

12. Ce sunt tipurile de date primitive?

13. Ce se stabileşte la definirea unui tip de date primitive?

14. Ce sunt tipurile de date derivate?

15. Ce este o clasă şi în ce fel de limbaje se foloseşte?

16. Ce deosebire există între modurile în care acţionează operatorii logici & şi &&?

17. Ce deosebire există între modurile în care acţionează operatorii logici | şi ||?

18. Ce deosebiri există între operatorii = şi ==?

19. În ce situaţii este obligatorie folosirea castului la conversiile datelor de tipuri

primitive?

20. Care sunt operatorii aritmetici unari?

21. Ce deosebire este între aşezarea operatorului de incrementare sau decrementare în faţa

operandului şi după acesta?

Page 65: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

65

22. Care sunt domeniile de valori pentru date de tipuri intregi?

23. Ce avantaj prezintă folosirea literalilor hexazecimali sau octali faţă de cei zecimali?

24. Cum se stabileşte tipul rezultatului operaţiilor aritmetice cu numere intregi?

25. În ce caz rezultatul unei operaţii aplicate asura unui operand de tip byte este tot de tip

byte?

26. Ce este împărţirea întreagă?

27. Ce este excepţia de împărţire la zero şi în ce situaţii poate să apară?

28. Ce este depăşirea binară şi în ce situaţii poate să apară?

29. Cum acţionează operatorul <<?

30. Cum acţionează operatorul >>?

31. Ce deosebire este între operatorii >> şi >>>?

32. Cum acţionează operatorii ~, &, | şi ^ când operanzii sunt de tipuri întregi?

33. Cum se reprezinta intern datele în virgulă mobilă?

34. Ce sunt cifrele semnificative ale unui număr în virgulă mobilă?

35. În ce situaţii rezultatul unei operaţii în virgulă mobilă are valoarea infinit?

36. Cum se reprezintă intern datele de tip char?

Page 66: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

66

Expresii. Instrucţiuni simple şi instrucţiuni

structurate. Tratarea excepţiilor

Expresii cu date primitive; precedenţa operatorilor; 66

Expresia condiţionala 70

Instrucţiuni simple 71

Principiile programării structurate; 74

Structurile de control fundamentale; 74

Tehnica rafinărilor succesive; 78

Instrucţiuni structurate (structuri de control) 79

Blocul ca realizare a structurii secvenţiale; variabile locale şi domenii

de vizibilitate;

79

Structura alternativă (if .. else); 81

Structura de comutare (switch); 85

Structuri repetitive 86

Ciclul cu test iniţial (while); 86

Ciclul cu test final (do .. while); 89

Ciclul for 90

Instrucţiuni etichetate; 93

Terminarea abruptă a execuţiei instrucţiunilor structurate; 93

Tratarea excepţiilor în limbajul Java (try .. catch) 95

Întrebari 97

Expresii cu date primitive

În programare, expresia este o combinaţie permisă ("legală", corectă) de simboluri, care

reprezintă o valoare. Tipul expresiei este acelaşi cu tipul valorii ei. Putem avea, deci, expresii

de tip boolean, int, long, float, double etc. Fiecare limbaj de programare are regulile

sale, prin care se stabileşte ce expresii sunt permise sau nepermise.

În limbajul Java, expresia poate conţine literali, variabile, operatori, operanzi, funcţii şi

paranteze şi trebuie să poată fi evaluată (calculată), astfel încât să se obţină o valoare.

Page 67: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

67

Construirea expresiei se face pas cu pas, având în vedere că:

- un literal sau o variabilă constituie o expresie; tipul şi valoarea acestei expresii sunt cele

ale literalului sau variabilei respective;

Exemple de astfel de expresii sunt: true -176 1.358746E-12 "sir de caractere" beta

- un operator împreună cu operanzii lui constituie o expresie.

De exemplu:

alpha+3.765 (s-a folosit operatorul binar +)

alpha++ (s-a folosit operatorul unar postfix ++)

-alpha (s-a folosit operatorul unar prefix -)

- o expresie cuprinsă între paranteze constituie o nouă expresie, a cărei valoare este

identică cu cea a expresiei din interior;

De exemplu: (-176) (alpha++) (alpha+3.765)

- valoarea unei expresii poate fi folosită ca operand într-o altă expresie.

De exemplu: (alpha+3.765)*(alpha++)

Se observă că, procedând astfel, se pot construi expresii din ce în ce mai complicate.

Utilizarea funcţiilor în expresii va fi discutată ulterior. Mernţionăm însă că şi operatorii

acţionează tot ca nişte funcţii. De exemplu, evaluarea expresiei alpha+3.765 este, de fapt,

calcularea unei funcţii, care are ca argumente valorile variabilei alpha şi literalului 3.765 şi

are ca valoare suma acestora.

Page 68: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

68

Expresia poate fi reprezentată ca un arbore sintactic, care are ca frunze literali sau variabile,

iar ca rădăcină are valoarea expresiei. Fiecare nod al arborelui sintactic conţine un operator

sau o funcţie, care are ca operanzi valorile subexpresiilor din nodurile-fii. De exemplu,

expresia a*b+3*c

corespunde următorului arbore:

Precedenţa operatorilor

La evaluarea unei expresii, prezinta o importanţă deosebită ordinea în care se aplică

operatorii pe care îi conţine, deoarece de această ordine poate să depindă valoarea expresiei.

În toate limbajele de programare, în care se folosesc expresii, se stabilesc şi anumite reguli de

precedenţă şi de asociativitate, pe baza cărora se stabileşte ordinea de evaluare.

Fiecărui operator i se asociază o precedenţă, adică un nivel de prioritate în aplicarea

operatorului respectiv. De exemplu, în expresia a+b*c operatorul * se va aplica înaintea

operatorului +, deoarece are precedenţa superioară. În consecinţă, aceasta expresie se va

calcula ca şi când ar fi scrisă sub forma a+(b*c).

În limbajul Java, la stabilirea ordinii operaţiilor se aplica următoarele reguli:

- operatorii unari se aplică înaintea celor binari;

- expresiile din interiorul parantezelor se evaluează înaintea celor din exterior;

- dacă, într-o expresie, toţi operatorii au acelaşi nivel de precedenţă, ei se aplică de la

stânga la dreapta;

- operanzii unui operator se evalueaza înainte de a se aplica operatorul respectiv (deci

operatorul se aplică întotdeauna asupra valorilor operanzilor săi); dacă operaţia este binară,

operandul din partea stângă se evaluează înaintea celui din partea dreaptă;

- nivelul de precedenţă al operatorilor se stabileşte conform cu tabela de mai jos, în care:

toţi operatorii din aceeaşi celulă a tabelei au acelaşi nivel de precedenţă;

operatorii de pe un nivel superior se aplică înaintea celor de pe nivelurile inferioare.

Tabela de precedenţă a operatorilor în limbajul Java

Page 69: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

69

. [] ()

+ unar - unar ++ -- ! ~ (<tip>)

new

* / %

+ binar - binar

<< >> >>>

< <= > >=

instanceof

== !=

&

^

|

&&

||

?:

= += -= *= /= %=

<<= >>= >>>= &=

|= ^=

,

Exemplu

În programul de mai jos, a cărui sursă se găseşte în fişierul EvExpresii.java, se calculează

unele expresii cu numere întregi şi se afişează rezultatele.

/* Evaluarea expresiilor */

class EvExpresii { public static void main(String args[]) { int a=23, b=500, c=17, d; System.out.println((a+b*c)+" "+((a+b)*c)+" "+(b/a*c)+ " "+(b/(a*c))); System.out.println((-a+b*c++/3+(d=c--%4))+" "+c+" "+d); System.out.println((d<1 && c--==0)+" "+c+" "+d); System.out.println((d<1 & ++d<c)+" "+c+" "+d); } }

La executarea acestui program, se obţin pe ecran următoarele rezultate:

8523 8891 357 1 2812 17 2 false 17 2 false 17 3

Sa urmărim acum desfăşurarea calculelor care au condus la aceste rezultate.

- s-a evaluat expresia (a+b*c), efectuându-se mai întâi înmulţirea b*c, deoarece operatorul

Page 70: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

70

* are precedenţa superioară operatorului +, şi s-a obţinut ca valoare numărul întreg 8523;

- următorul operator, +, are ca operanzi numărul întreg 8523 şi şirul de caractere " ". În

consecinţă, s-a convertit numarul 8523 într-un şir (trecându-se de la forma internă a acestuia

la cea externă) şi s-a obţinut şirul "8523", care s-a concatenat cu şirul " ", obţinându-se şirul

"8523 ";

- s-a calculat expresia ((a+b)*c) obţinându-se numărul întreg 8891; de data aceasta, s-a

calculat mai întâi subexpresia a+b, deoarece este între paranteze;

- s-a convertit numărul 8891 din forma internă în cea externă şi s-a concatenat cu şirul

obtinut anterior şi cu sirul " ", rezultând şirul "8523 8891 ";

- s-a calculat expresia (b/a*c). Întrucît operatorii / şi * au acelaşi nivel de precedenţă,

calculul s-a făcut de la stânga la dreapta, astfel:

. s-a efectuat împărţirea întreagă b/a, obţinându-se valoarea 21;

. s-a efectuat înmulţirea 21*c, obţinându-se rezultatul 357.

- s-a concatenat forma externă a numărului 357 cu şirul obţinut anterior şi cu şirul " ",

obţinându-se şirul "8523 8891 357 ";

- s-a calculat expresia (b/(a*c)), efectuându-se acum mai întâi înmultirea a*c, apoi

împărţirea întreagă a valorii lui b la rezultatul înmulţirii şi s-a obţinut valoarea 1;

- s-a concatenat forma externă a acestei valori cu şirul obţinut anterior, obţinându-se şirul

"8523 8891 357 1" care a fost afişat pe ecran, după care s-a trecut la linie nouă.

Recomandăm să urmăriţi în acelaşi mod cum s-au calculat şi afisat celelalte expresii.

Menţionăm că:

- la evaluarea expresiei (-a+b*c++/3+(d=c--%4))prezinta interes cu ce valori intră în

calcul variabila c şi ce valoare are operandul din dreapta al ultimului operator +;

- avand în vedere că valoarea expresiei d<1 este false, la aplicarea operatorului && nu s-a

mai evaluat al doilea operand, deci variabila c a rămas la valoarea ei anterioară, in timp ce la

aplicarea operatorului & a fost evaluat şi al doilea operand, astfel că variabila d a fost

incrementată.

Expresia condiţională

Urmând "tradiţia" limbajului C, în limbajul Java există operatorul ternar (cu trei operanzi) ?:

numit operatorul condiţional, care este utilizat în cadrul următoarei expresii condiţionale: operand1 ? operand2 : operand3

unde:

operand1 - expresie booleană;

operand2 şioperand3 - expresii de tipuri compatibile: fie ambii operanzi de tip boolean, fie

ambii de tipuri numerice, fie ambii de tipuri referinţă.

Evaluarea expresiei decurge astfel:

- se evaluează operand1 obţinându-se o valoare booleană;

- dacă operand1 are valoarea true, atunci valoarea expresiei condiţionale este cea care se

obţine evaluând operand2; altfel, este cea care se obţine evaluând operand3.

Exemplu

În programul de mai jos, dat şi în fişierul ExprCond.java, se exemplifică mai multe cazuri de

utilizare a expresiei condiţionale.

Page 71: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

71

/* Testarea expresiei conditionale */

class ExprCond { public static void main(String args[]) { int m=17, n=-6, p=0, q=0; System.out.println(m>n ? m+1 : 2*n-2); System.out.println(m<=n ? 3*m : m-n); /* Se evalueaza numai operandul 2 */ System.out.println((m>=6 ? ++p*n : ++q-m)+" "+p+" "+q); /* Se evalueaza numai operandul 3 */ System.out.println((m<n+3 ? m-- : n++)+" "+m+" "+n); /* Un exemplu in care operanzii 2 si 3 sunt tot expresii conditionale */ System.out.println(m>p ? (n<0? m+1 : m-2) : (m>n ? m : n)); } }

Executând acest program, obţinem pe ecran urmatoarele rezultate:

18 23 -6 1 0 -6 17 -5 18

Din aceste rezultate putem constata cu uşurinţă că s-au evaluat de fiecare dată numai acei

operanzi, care erau necesari în evaluarea expresiei condiţionale. În ultima instrucţiune se

ilustrează şi un caz de utilizare drept operanzi a unor expresii condiţionale.

Instrucţiuni simple

În limbajul Java, procesul de calcul este controlat de instrucţiuni (enunţuri). Fiecare

instrucţiune indică una sau mai multe acţiuni pe care trebuie să le execute calculatorul.

Corpul oricărei metode este constituit dintr-o succesiune de instrucţiuni. Executarea metodei

constă în executarea acestor instrucţiuni într-o ordine determinată. Instrucţiunile pot fi

grupate în blocuri.

După structura lor, instrucţiunile pot fi simple sau structurate.

Instrucţiunile simple nu conţin în interiorul lor alte instrucţiuni. Există trei categorii

principale de instrucţiuni (enunţuri) simple: declaraţiile de variabile locale, instrucţiunile-

expresie şi instrucţiunea vidă. La scrierea lor se respectă următoarele reguli:

Page 72: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

72

toate instrucţiunile simple se termină cu caracterul ';' (punct şi virgulă). Instrucţiunea

vidă este formată numai din acest caracter;

declaraţiile de variabile locale servesc pentru a specifica tipul, numele şi (opţional)

valoarea iniţială a variabilelor. Forma sintactică şi utilizarea declaraţiilor au fost

prezentate anterior;

instrucţiunile-expresie sunt formate dintr-o expresie de atribuire, de

incrementare/decrementare sau de invocare de metodă, urmată de caracterul ';'.

Notă pentru programatorii în alte limbaje

În limbajul Java, declaraţiile de variabile locale sunt considerate instrucţiuni executabile,

deci ele au efect la executarea programului.

În majoritatea limbajelor compilate, declaraţiile de variabile locale sunt luate în consideraţie

numai la compilare, deci sunt considerate instrucţiuni neexecutabile. În limbajul Java

declaraţiile sunt, de asemenea, luate în consideraţie de compilator, care verifică dacă

declaraţia este corectă sintactic şi, de asemenea, verifică la fiecare apariţie a unei variabile

locale în programul sursă dacă:

- variabila respectivă a fost declarată;

- tipul variabilei corespunde contextului în care este folosită variabila respectivă;

- variabila are deja o valoare.

Efectul declaraţiilor de variabile locale din programele Java constă în faptul că în momentul

execuţiei se alocă în memorie (pe stivă) spaţiu pentru variabilele respective şi se introduc

valorile iniţiale. În consecinţă:

- declaraţiile de variabile pot fi plasate oriunde în interiorul unui bloc (pot fi puse la

începutul acestuia sau pot fi intercalate cu alte instrucţiuni);

- "executarea" declaraţiei are loc de la stânga la dreapta şi de sus în jos, astfel că la

evaluarea expresiilor prin care se calculează valoarea iniţială a unei variabile, se consideră

cunoscute valorile iniţiale ale variabilelor declarate anterior.

Instrucţiunile-expresie pot fi instrucţiuni de atribuire, de incrementare/decrementare sau de

invocare de metodă.

Instrucţiunile de atribuire

sunt instrucţiuni prin care unei variabile i se atribuie o nouă valoare, modificându-se

astfel valoarea avută anterior. Instrucţiunea de atribuire este o expresie de atribuire

sau de atribuire compusă urmată de caracterul ';' (punct şi virgulă) deci are

următoarea formă sintactică: expresie_de_atribuire;

Valoarea acestei expresii se ignoră, astfel că acţiunea care se efectueaza la executarea

instrucţiunii de atribuire constă numai în efectul lateral al acesteia, adică în

modificarea valorii variabilei din partea stânga. De exemplu, dacă a şi b sunt variabile

numerice, atunci a=b+7 este o expresie de atribuire, în timp ce a=b+7; în care la sfârşitul expresiei de atribuire s-a pus terminatorul punct şi virgulă, este o

instrucţiune de atribuire.

Se pot face atribuiri în lanţ, ca în exemplul următor:

a=b=c=d=3;

Page 73: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

73

Instrucţiunile de incrementare/decrementare

sunt instrucţiuni formate dintr-o expresie de incrementare sau decrementare, urmată

de caracterul ';' (punct şi virgulă). De exemplu, a++ este o expresie de

postincrementare, în timp ce a++; este o instrucţiune de postincrementare.

Instrucţiunile de invocare de metodă

sunt instrucţiuni prin care se cere executarea unei metode, transmiţându-i-se acesteia

valorile parametrilor. Instrucţiunea constă din numele metodei, urmat de o pereche de

paranteze care conţine valorile parametrilor şi se termină prin caracterul ';' (punct şi

virgulă). Acţiunea cerută de instrucţiune constă în executarea metodei respective.

Daca metoda este o funcţie, valoarea funcţiei se ignoră, menţinându-se numai efectele

laterale ale metodei respective. De exemplu: System.out.println("şir de caractere");

este o instrucţiune prin care se invocă metoda println a câmpului out din clasa

System, transmiţându-i-se parametrul "şir de caractere". Acţiunea care se

realizează astfel constă din afişarea pe ecran a şirului primit ca parametru.

Exemplu

În fişierul Instructiuni.java se dă un exemplu simplu de program care conţine o secvenţa de

instrucţiuni simple: o declaraţie de variabile, două instrucţiuni de atribuire, o instrucţiune de

incrementare şi o invocare de metodă.

/* Exemple de instructiuni simple */

class Instructiuni { public static void main(String args[]) { double a=3.76, b=-15, c=2*a-b, d, e; // declaratie de variabile d=3*a-7; // instructiune de atribuire b++; // instructiune de incrementare e=b-17; // instructiune de atribuire /* invocare de metoda */ System.out.println("a="+a+" b="+b+" c="+c+" d="+d+" e="+e); } }

Pentru mai multa claritate, fiecare instrucţiune a fost scrisa pe o linie de program separată şi a

fost însoţită de un comentariu. Se permite, însă, scrierea mai multor instrucţiuni pe o singură

linie sau, invers, o instrucţiune se poate extinde pe mai multe linii. Singura restricţie este ca

trecerea de la o linie la alta să se facă la nivelul unui operator sau separator (să nu se rupă in

doua un simbol format din mai multe caractere, un identificator sau un literal). Remarcăm că

la declararea variabilei c s-a luat în consideratie faptul că variabilele a şi b au deja valori

iniţializate anterior.

Page 74: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

74

Principiile programării structurate

Programarea structurată este o orientare în conceperea şi alcătuirea programelor, având ca

obiectiv o mai bună gestionare a complexităţii acestora, ţinând cont de particularităţile

gândirii umane.

Conform metodei programării structurate, la conceperea unui program, este recomandabil să

se respecte următoarele principii:

1. Teorema de structură: orice program poate fi întocmit folosind numai trei structuri de

control fundamentale: structura secvenţială, structura alternativă şi structura repetitivă.

2. La conceperea programelor se recomandă să se aplice tehnica de elaborare descendentă

(în engleză Top-Down), numită şi tehnica rafinărilor succesive.

3. Domeniile de valabilitate (de vizibilitate) ale variabilelor şi structurilor de date trebuie să

fie limitate.

În limbajul Java, pentru rezolvarea problemei realizării creşterii eficienţei muncii

programatorilor s-a adoptat concepţia modernă a programării orientate pe obiecte. In

consecinţă, modulele de program sunt mici şi rolul programării structurate este sensibil redus.

Totuşi, fiecare metodă din limbajul Java este un mic program, la elaborarea căruia se aplică

principiile programării structurate, ceeace s-a avut în vedere şi la adoptarea instrucţiunilor

de bază oferite de acest limbaj. Este deci util ca şi programatorii în Java sa cunoască

principiile fundamentale ale programării structurate.

Structurile de control fundamentale

Aceste structuri se referă la modalităţile în care se pot înlănţui instrucţiunile dintr-un

program, deci în care se transmite "controlul" de la o instrucţiune la alta în timpul executării

programului. Conform "teoremei de structură", sunt suficiente trei astfel de "structuri de

control":

1. Structura secvenţială

În mod "natural", se consideră că instrucţiunile se execută în ordinea în care

acestea figurează în program. Înlănţuirea instrucţiunilor (transmiterea

"controlului" de la o instrucţiune la alta) se face, în acest caz, conform

schemei logice din figura 1.

Page 75: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

75

În pseudocod, aceeaşi secvenţă de program se scrie astfel:

<instrucţiunea_1> <instrucţiunea_2>

.... <instrucţiunea_n>

Există, deci, un număr oarecare (n) de instrucţiuni, care se execută una dupa alta, în ordinea

în care sunt scrise în program.

Toate exemplele de programe date în capitolele şi secţiunile anterioare au structura

secvenţială.

2. Structura alternativă (condiţională, de decizie)

Un fragment de program are structura alternativă (numită şi structură condiţională sau de

decizie), atunci când se alege una din două căi posibile, în funcţie de modul în care este

satisfăcută sau nu o anumită condiţie. Schema logică a structurii de control alternative este

dată în figura 2.

În această schemă logică, Condiţie este o expresie booleană. Executarea acestui fragment de

program decurge astfel: se verifică mai întâi dacă este satisfăcută condiţia. Dacă ea este

satisfăcută, deci expresia Condiţie are valoarea true, se execută Instrucţiunea 1, iar în caz

contrar se execută Instrucţiunea 2.

In pseudocod, acest fragment de program se scrie astfel:

Dacă <condiţie> atunci <instrucţiunea_1>

Page 76: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

76

altfel <instrucţiunea_2> Sfarşit_dacă

În unele convenţii de pseudocod, în loc de Instrucţiunea_1 şi Instructiunea_2 pot fi puse

secvenţe de instrucţiuni.

Se observă că există o asemănare între instrucţiunea alternativă şi expresia condiţională. În

ambele cazuri se verifică dacă este satisfacută o condiţie şi - în funcţie de rezultatul obtinut -

se alege una din două variante posibile. Deosebirea este următoarea:

- în cazul expresiei condiţionale se alege una din cele două expresii conţinute în aceasta,

iar rezultatul obţinut este valoarea expresiei astfel alese;

- în cazul structurii de control alternative se alege una din cele doua instrucţiuni conţinute

în această structură; instrucţiunea astfel aleasă este executată, iar rezultatul obţinut este

efectul (lateral) produs de executarea acestei instrucţiuni.

3. Structura repetitivă (ciclu, buclă)

În cazul structurii de control repetitive, o instrucţiune sau o secvenţă de instrucţiuni se repetă

cât timp este satisfacută o anumită condiţie. Structura repetitivă fundamentală, acceptată în

teoria programării structurate, este cea de ciclu cu test iniţial. Schema logică a acestei

structuri de control este dată în figura 3.

Executarea acestei structuri are loc astfel:

1. se evaluează expresia booleană care reprezintă Condiţia;

2. dacă valoarea acestei expresii este true, deci condiţia este satisfacută, se merge pe

ramura DA şi se executaă instrucţiunea din corpul ciclului, după care se trece la punctul 1;

3. altfel (deci dacă condiţia nu este satisfacută) se merge pe ramura NU şi se iese din ciclu.

Se observă, deci, că se va executa instrucţiunea în mod repetat, cât timp este satisfăcută

condiţia. În pseudocod, această structură de control se programează astfel:

cât_timp <condiţie> execută <instrucţiune> sfârşit_ciclu

Page 77: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

77

În unele versiuni de pseudocod, în loc de o singură <instrucţiune> se poate pune o

secvenţă de instrucţiuni.

Deşi, din punct de vedere al teoriei programării structurate, ciclul cu test iniţial este suficient

ca structură repetitivă, în multe limbaje de programare (inclusiv Java), din motive de

comoditate a programării se admite şi o a doua formă de astfel de structură, numită ciclu cu

test final. Schema logică a acestui ciclu este dată în figura 4.

Se observă că, în această schemă logică, executarea instrucţiunii se repetă, ca şi în cazul

ciclului precedent, cât timp este satisfacută condiţia.

Deosebirea dintre cele două forme de cicluri este că, în ciclul cu test iniţial, condiţia este

evaluată înainte de a se executa instrucţiunea din corpul ciclului, în timp ce în ciclul cu test

final evaluarea condiţiei se face după ce instrucţiunea a fost deja executată. Aceasta este o

deosebire importantă, deoarece, în cazul ciclului cu test initial, este posibil ca instrucţiunea să

nu se execute niciodată (dacă chiar de la prima evaluare condiţia nu este satisfacută), în timp

ce la ciclul cu test final instrucţiunea din corpul ciclului va fi executată cel puţin o dată. Aşa

dar, ciclul cu test final poate fi înlocuit prin unul echivalent cu test iniţial, dar nu şi invers.

Iată dece, în teoria programării structurate, ciclul cu test iniţial este considerat ca structură de

control fundamentală, în timp ce cel cu test final este o structură de control admisă, dar nu

fundamentală.

În pseudocod, ciclul cu test final reprezentat prin schema logică din figura 4 se scrie sub

forma generală:

execută <instrucţiune> cât_timp <condiţie>

În unele limbaje (de exemplu în Pascal) pentru ciclul cu test final se adoptă o schemă logică

în care singura deosebire faţă de cea din figura 4 este doar prin faptul că cele două ramuri DA

şi NU işi schimbă locurile între ele, ceeace în pseudocod se scrie sub forma:

execută <instrucţiune> până_când <condiţie>

Page 78: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

78

În acest caz, instrucţiunea din corpul ciclului se va repeta cât timp NU este satisfacuta

condiţia, deci până când se va constata pentru prima oară că ea este satisfăcută.

În ambele cazuri, în unele variante de pseudocod instrucţiunea din corpul ciclului poate fi

înlocuită printr-o secvenţa de instrucţiuni. Dacă se are în vedere utilizarea limbajului Java,

utilizarea unei secvenţe nu este necesară, deoarece ea se poate înlocui printr-o singură

instrucţiune compusă, aşa cum se va arăta ulterior.

Din examinarea structurilor de control prezentate în acest capitol, putem constata o

proprietate importantă: schemele logice ale tuturor structurilor de control admise de metoda

progrămarii structurate au fiecare un singur punct de intrare şi un singur punct de ieşire.

Datorită acestei proprietăţi, ele pot fi folosite la elaborarea unor programe complexe prin

tehnica rafinărilor succesive, aşa cum se va arăta în secţiunea următoare.

Tehnica rafinărilor succesive

Adoptarea metodei programării structurate a făcut posibilă elaborarea programelor prin

tehnica rafinărilor succesive (engl.: stepwise refinement), cunoscută şi sub numele de tehnica

descendentă (engl.:top-down), care va fi prezentată succint în cele ce urmează.

La elaborarea unui program se porneşte de la specificaţia acestuia, în care se precizează CE

trebuie sa facă programul respectiv (CE problemă trebuie rezolvată, CE rezultate trebuie

obţinute) şi se ajunge în final la programul propriu-zis, care arată CUM trebuie acţionat

pentru a se obţine aceste rezultate. De cele mai multe ori, programul elaborat conţine un

număr mare de instrucţiuni, cu numeroase ramificaţii şi cicluri. Scrierea unui astfel de

program poate fi o sarcină extrem de dificilă şi greu de îndeplinit, dacă nu se procedează

sistematic. În plus, dacă programul nu este suficient de clar şi de bine documentat, va fi

extrem de greu sau chiar imposibil să fie depanat (să se corecteze eventualele erori de

programare) şi să fie modificat ulterior, dacă se modifică specificaţia.

Tehnica rafinărilor succesive oferă o cale de a parcurge acest drum de la CE la CUM în mai

mulţi paşi, astfel încât să se pornească de la un număr mic de enunţuri (pseudoinstrucţiuni) de

nivel de abstractizare ridicat, după care - la fiecare pas de rafinare - fiecare din aceste

instrucţiuni se descompune în mai multe instrucţiuni de nivel de abstractizare mai coborât

(mai "concrete"), până când se ajunge la instrucţiuni scrise direct în limbajul de programare

folosit (de exemplu în Java). Se pune deci un accent deosebit pe abstractizarea datelor si a

instrucţiunilor. Dupa cum arăta E.W.Dijkstra, abstractizarea este calea prin care omul

stapâneşte complexitatea.

Dacă privim schemele logice ale structurilor de control fundamentale, permise de metoda

programării structurate, constatăm cu uşurinţă că atât blocurile care conţin instrucţiuni, cât şi

structurile de control admise de metoda programarii structurate au fiecare un singur punct de

intrare şi un singur punct de ieşire. Aceasta înseamnă că orice bloc care conţine o

instrucţiune poate fi înlocuit în schema respectivă printr-o structură de control. Ca urmare, se

poate aplica următoarea cale de elaborare a programului, specifică tehnicii rafinărilor

succesive:

- iniţial se consideră că programul este alcatuit dintr-o singură pseudoinstrucţiune, de înalt

Page 79: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

79

nivel de abstractizare, care constă chiar din specificaţia problemei pe care o va "rezolva"

programul respectiv;

- la pasul de rafinare următor, această "problemă" se descompune în două sau mai multe

"subprobleme"; aceasta înseamnă că unica pseudoinstrucţiune existentă iniţial se înlocuieşte

prin una din structurile admise de metoda programării structurate (structura secvenţială,

alternativă sau repetitivă); această structură conţine în ea una sau mai multe instrucţiuni sau

pseudoinstrucţiuni;

- la paşii de rafinare următori, fiecare pseudoinstrucţiune, care nu are corespondenta directă

în limbajul de programare utilizat, se inlocuieşte, de asemenea, prin una din structurile de

control admise; textul pseudoinstrucţiunii înlocuite poate fi, totusi, menţinut sub formă de

comentariu, astfel încât să se înţeleagă mai uşor programul;

- se continuă acest proces de rafinări succesive, până când toate instrucţiunile astfel

obţinute au corespondent în limbajul de programare utilizat.

Instrucţiuni structurate

Limbajul Java a fost alcătuit astfel, încât programatorul este obligat sa respecte principiile

programării structurate. Aceasta se datoreşte faptului ca instrucţiunile structurate ale

limbajului sunt cele prevăzute de această metodă de programare.

Există următoarele instrucţiuni structurate:

blocul - prin care se realizează structura secvenţială;

instrucţiunile if si if .. else - prin care se realizează structura alternativă;

instrucţiunea switch - prin care se realizează structura de comutare (de selecţie);

instrucţiunile while, do .. while şi for - prin care se realizează structurile

repetitive.

În plus, în limbajul Java există o structură de control dedicată tratării excepţiilor care apar în

timpul executării programului, realizată prin instrucţiunile try .. catch

Blocuri

Blocul este o secvenţă de instrucţiuni cuprinsă între acolade. Forma sintactică a blocului este,

deci, următoarea: { secvenţă_de_instrucţiuni }

unde secvenţă_de_instrucţiuniconstă dintr-un număr oarecare de instrucţiuni succesive,

putând fi şi vidă. Instrucţiunile din această secvenţă pot fi atât simple, cât şi structurate,

inclusiv alte blocuri.

Din punct de vedere al programării structurate, blocul este realizarea structurii de control

secvenţiale. Aceasta inseamnă că instrucţiunile dintr-un bloc se execută una dupa alta, în

ordinea în care ele sunt scrise în program. Tocmai de aceea se şi foloseşte termenul secvenţă

Page 80: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

80

de instrucţiuni pentru a indica ce conţine blocul.

Exemplu

În programul de mai jos, conţinut în fişierul Blocuri.java, se exemplifică folosirea unor

blocuri imbricate (cuprinse unul în altul). Prin comentarii s-a semnalat începutul şi sfârşitul

fiecărui bloc, deşi aceasta nu se face în mod curent. Remarcăm că însuşi corpul metodei main

(şi al oricărei alte metode) este tot un bloc. Fiecare bloc conţine atât declaraţii de variabile,

cât şi instrucţiuni-expresie

/* Exemplu de program care contine blocuri imbricate */

class Blocuri { // aici incepe corpul clasei Blocuri public static void main(String args[]) { // aici incepe blocul A int m=8, n=-3; double u=m*3.5+32, v=2, w; w=m*u+v; System.out.println("m="+m+" n="+n+" u="+u+" v="+v+" w="+w); m++; { // aici incepe blocul B, continut in A int a=5; double p=m*w-3.5, q; q=n*p-a; // s-a folosit n din blocul exterior { // aici incepe blocul C continut in B System.out.println("m="+m+" a="+a+" p="+p+" q="+q); } // aici se termina blocul C } // aici se termina blocul B } // aici se termina blocul A (corpul metodei main) } // aici se incheie corpul clasei Blocuri

La executarea acestui program se afişează următoarele rezultate:

m=8 n=-3 u=60.0 v=2.0 w=482.0 m=9 a=5 p=4334.5 q=-13008.5

Remarcăm că:

- în expresiile prin care se calculează valoarea iniţială a variabilei u s-a luat în consideraţie

valoarea variabilei m determinată anterior;

- în blocul B, la calcularea valorii iniţiale a variabilei p s-au folosit valorile variabilelor m

si w calculate la executarea unor instrucţiuni-expresie anterioare; se confirmă astfel că

iniţializarea variabilelor nu se face la compilare, când aceste valori nu sunt cunoscute, ci la

executarea declaraţiei.

Variabile locale şi domenii de vizibilitate

Variabilele declarate într-un bloc sunt variabile locale ale blocului respectiv. Domeniul de

vizibilitate al unei variabile locale începe în locul din program în care aceasta a fost declarată

şi se încheie la sfârşitul blocului care conţine declaraţia respectivă. Variabila este deci

"vizibilă" (poate fi utilizată) în propriul său bloc şi în toate blocurile interioare acestuia, în

domeniul de vizibilitate.

Page 81: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

81

Exemplu:

În programul din fişierul Blocuri.java, dat ca exemplu mai sus, variabilele m, n, u, v şi w

sunt declarate în blocul A (în însuşi corpul metodei main) şi sunt vizibile (pot fi utilizate) atât

în acest bloc, cât şi în blocurile interioare B şi C. În schimb variabilele a, p şi q pot fi

utilizate numai în blocul B, în care sunt declarate, şi în blocul C situat în interiorul acestuia.

În memoria maşinii virtuale Java, variabilele locale sunt plasate pe stiva procesului curent. La

executarea unei instrucţiuni-declaraţie, variabilele conţinute în aceasta sunt puse pe stivă, în

ordinea în care ele apar în declaraţia respectivă. Când se ajunge la sfârşitul blocului în care au

fost declarate, variabilele sunt scoase de pe stivă. Cât timp se află pe stivă, variabilele sunt

vizibile şi deci pot fi utilizate.

Structuri alternative

Instrucţiunea if

Instrucţiunea if serveşte pentru realizarea structurii alternative din programarea structurată.

Sub forma ei cea mai simplă, această instrucţiune se scrie astfel: if(expresie_booleană) instrucţiune

unde instrucţiunepoate fi orice instrucţiune valabilă în limbajul Java: instrucţiune simplă

sau structurată, inclusiv un bloc sau un alt if. Remarcăm că în forma generală de mai sus nu

am pus la sfârşit caracterul ';' (punct şi virgulă). Dacă instrucţiune este o instrucţiune

simplă, ea include şi acest simbol.

Semnificaţia instrucţiunii if este următoarea: dacă valoarea expresiei booleene din paranteză

este true, atunci se execută instrucţiune, iar altfel nu se execută nimic, continuându-se

programul.

Exemple

1. Fie instrucţiunea if(alpha<beta) x=2*alpha+beta;

În acest caz, instrucţiune este instrucţiunea-expresie x=2*alpha+beta;

care se termină ea însăşi prin punct şi virgulă. Înstrucţiunea if se interpretează astfel: dacă

expresia booleană alpha<beta are valoarea true, atuncivariabileix i se atribuie valoarea

expresiei aritmetice 2*alpha+beta. Altfel (dacă expresia booleana are valoarea false)

variabila x rămâne la valoarea pe care a avut-o anterior.

2. Fie instrucţiunea if(alpha<beta) { int gamma=alpha-3*beta; x=2*gamma; y=gamma-3; }

În acest caz, instrucţiune este un bloc, care se execută numai dacă expresia booleană

alpha<betaare valoarea true. Remarcăm ca după acolada prin care se închide blocul nu s-a

mai pus punct şi virgulă.

Page 82: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

82

3. Fie instrucţiunea if(alpha<beta) if(beta>0) System.out.println(alpha+" "+beta);

În acest caz, instrucţiune este un alt if.

Deşi cuvântul then nu apare explicit, în specificaţia limbajului Java această forma a lui if este

cunoscută sub denumirea "instrucţiunea if-then" (if-then statement), care se traduce prin dacă

.. atunci.

Remarcăm că această instrucţiune realizează un caz particular al structurii alternative, unde

pe ramura altfel nu se efectuează nici o acţiune.

Instrucţiunea if .. else

Instrucţiunea if .. else realizează ambele ramuri ale structurii alternative şi are forma if(expresie_booleană) instrucţiune_1 else instrucţiune_2

în care instrucţiune_1 şi instrucţiune_2 pot fi instrucţiuni simple sau structurate.

Interpretarea acestui if..else este următoarea: dacă expresie_logică are valoarea

true,atunci se execută instrucţiune_1, iar altfel se execută instrucţiune_2.

Deşi cuvântul then nu apare explicit, în specificaţia limbajului Java această instrucţiune se

numeşte if-then-else.

Exemple

1. Fie instucţiunea if(a<b) x=2*a-b; else x=a+b;

În acest caz, atât instrucţiune_1, cât şi instrucţiune_2 sunt instrucţiuni-expresii şi se

termină prin punct şi virgulă.

2. Fie instrucţiunea if(a<b) { x=2*a-b; y=a+1; } else { x=a+b; y=b; }

În acest caz, instrucţiune_1 şi instrucţiune_2 sunt blocuri. Remarcăm că după acolada

închisă a blocului nu s-a mai pus punct şi virgulă.

Page 83: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

83

Instrucţiuni if .. else imbricate

Atât instrucţiunea if, cât şi if..else, pot conţine alte instrucţiuni if sau if..else. În acest caz se

pune problema cărui if îi aparţine un anumit else. O programare neatentă poate conduce la

greşeli, în sensul că interpretarea dată de compilatorul Java poate fi diferită de cea avută în

vedere de programator. Pentru a nu se produce astfel de confuzii, cel mai bine este să se

grupeze instrucţiunile în blocuri.

Exemplu

Fie instrucţiunea if(a<b) if(b<c) System.out.println("A"); else System.out.println("B"); else System.out.println("C");

Interpretarea corectă este, în acest caz, că primul else aparţine celui de al doilea if, iar

ultimul else aparţine primului if. Această structură se poate întări scriind instrucţiunea

astfel: if(a<b) { if(b<c) System.out.println("A"); else System.out.println("B"); } else System.out.println("C");

Întrucât s-au folosit acoladele pentru a pune instrucţiunea if..else interioară sub formă de

bloc, a devenit clar pentru oricine cărui if îi apartine fiecare din cei doi else.

Instrucţiunea switch

Deşi în teoria programării structurate se demonstrează că, pentru a realiza programe cu

structură ramificată, este suficient să se folosească structura de control alternativă, realizată în

limbajul Java prin instrucţiunea if..else, în practica programării se admit şi structuri de

comutare sau de selecţie, care sunt prezente in diferite limbaje de programare. Aceste

structuri permit să se aleagă una din mai multe ramuri paralele,alegerea depinzând de

valoarea unei expresii numită comutator sau selector. În acelaşi timp, ele respectă principiul

de bază al programării structurate, conform căruia fiecare structură de control trebuie să aibă

un singur punct de intrare şi un singur punct de ieşire, astfel că se încadrează în această

metodă de elaborare a programelor.

În limbajul Java, structura de comutare se realizează prin instrucţiunea switch, care are

următoarea formă generală:

switch (expresie) { case valoare_1: secvenţă_1 [break;] case valoare_2: secvenţă_2 [break;] .......................... case valoare_N: secvenţă_N [default: secvenţă ] }

Page 84: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

84

în care:

- switch, case si default sunt cuvinte cheie ale limbajului Java;

- expresie este o expresie de tip byte, short, int sau char;

- valoare este fie un literal de tip byte, short, int sau char, fie o expresie constantă

de tip int, adică o expresie care conţine numai literali sau variabile finale din tipurile

menţionate;

- secvenţaeste o secvenţă de instrucţiuni simple sau structurate;

- parantezele drepte roşii []nu apar în program, ci indică faptul că conţinutul lor este

opţional (poate sa lipsească).

În limba engleză, switch înseamnă comutator. Conform acestei forme generale, după cuvantul

cheie switch, există o expresie de tip int sau compatibilă cu aceasta (deci poate fi şi de tip

char, byte sau short, dar nu de tip long), a cărei valoare serveşte drept "comutator". Se

deschide apoi acolada corpului instrucţiunii, în care există mai multe "cazuri". Fiecare "caz"

începe prin cuvantul cheie case, urmat de o valoare de tip întreg, după care apar una sau mai

multe instrucţiuni (simple sau compuse) şi opţional intrucţiunea break. După ce s-au

epuizat toate cazurile, opţional se poate scrie cuvântul cheie default urmat de una sau mai

multe instrucţiuni. La sfârşit, se închide acolada corpului instrucţiunii switch.

Executarea instrucţiunii switch decurge astfel: se evaluează mai întâi expresie şi se obţine

o valoare de tip întreg, care serveşte drept comutator. Această valoare se compară, pe rând de

sus în jos, cu fiecare din valorile indicate după cuvintele cheie case, până când se găseşte

prima valoare care coincide cu cea a comutatorului. Dacă s-a găsit o astfel de valoare, se

execută toate instrucţiunile care încep de la cazul respectiv, până la prima instrucţiune break

întalnită sau, în lipsa acesteia, până la acolada de închidere a corpului instrucţiunii switch.

Dacă însă nici unul din cazuri nu conţine valoarea potrivită a comutatorului, atunci se execută

instrucţiunile care urmează după cuvântul cheie default sau, în lipsa acestuia, nu se execută

nimic.

Exemplu

În fişierul TestSwitch.java se dă programul de mai jos, în care se testează instrucţiunea switch

în două situaţii: în primul caz nu este utilizată instrucţiunea break, iar în al doilea caz este

pusă această instrucţiune la sfârşitul secvenţei de instrucţiuni corespunzătoare fiecărui caz.

Remarcăm, de asemenea, că în al doilea caz, întrucât comutatorul este de tip char, valorile

numerice corespunzătoare fiecărui caz au trebuit să se încadreze în acest tip, adică să fie

caractere sau numere întregi pozitive în intervalul [0, 65535].

/* Testarea instructiunii switch */

class TestSwitch { public static void main(String args[]) { int a=7; char c='@'; double u=15.3782; System.out.println("Switch fara break si cu cazuri vide"); switch(a) { case 143: u++; System.out.println("A "+u); case 2: u+=a; System.out.println("B "+u);

Page 85: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

85

case 7: u--; System.out.println("C "+u); case '@': case 148: case 15: case -87: u-=a; System.out.println("D "+u); case -12: u*=a; System.out.println("E "+u); case 'F': u%=a; System.out.println("F "+u); default: u=15.3782; System.out.println("G "+u); } System.out.println("Switch cu break dupa fiecare caz

nevid"); switch(c) { case 143: u++; System.out.println("A "+u); break; case 2: u+=a; System.out.println("B "+u); break; case 7: u--; System.out.println("C "+u); break; case '@': case 148: case 15: case 87: u-=a; System.out.println("D "+u); break; case 12: u*=a; System.out.println("E "+u); break; case 'F': u%=a; System.out.println("F "+u); break; default: u=15.3782; System.out.println("G "+u); }

} }

Rezultatul rulării acestui program este următorul:

Switch fara break si cu cazuri vide C 14.3782 D 7.3782 E 51.6474 F 2.6473999999999975 G 15.3782 Switch cu break dupa fiecare caz nevid D 8.3782

Page 86: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

86

Se observă cu uşurinţă că, în primul caz (fără instrucţiuni break), s-a început executarea

secvenţei de instrucţiuni în punctul "case 7" şi s-a continuat până la sfârşitul blocului

instrucţiunii switch (inclusiv cazul default). Când s-a folosit instrucţiunea break, ieşirea

s-a făcut la întalnirea acestei instrucţiuni.

Instrucţiuni pentru structuri de control repetitive

În limbajul Java, structurile de control repetitive se realizează prin trei instrucţiuni:

- instrucţiunea while, prin care se programează ciclul cu test iniţial;

- instrucţiunea do..while, prin care se programează ciclul cu test final;

- instrucţiunea for, care este o varianta modificată a ciclului cu test iniţial, astfel încât să

poată fi folosită şi la realizarea ciclului cu contor.

În cele ce urmează se vor prezenta instrucţiunile menţionate mai sus.

Instrucţiunea while (ciclul cu test iniţial)

Această instrucţiune are forma generală

while (condiţie) instrucţiune

în care

condiţie - este o expresie de tip boolean;

instrucţiune- poate fi orice instrucţiune (simplă sau structurată) a limbajului Java,

inclusiv altă instrucţiune while.

Executarea acestei instrucţiuni se face astfel: se evaluează expresia booleană condiţie şi -

dacă valoarea acesteia este true, deci condiţia este satisfacută - se execută

instrucţiune,după care se revine la evaluarea condiţiei. acest ciclu se repetă cât timp este

satisfacută condiţia.

Exemplul 1. Se va calcula în mod repetat valoarea expresiei 2e-0.25k

sin(0.1k-0.08) pentru

valori întregi ale variabilei k de la 0 la n, unde n este dat.

În pseudocod, programul corespunzător se poate scrie astfel:

<#1. Se introduce valoarea lui n, de tip intreg> <#2. Se calculează şi se afişează valoarea expresiei 2e-0.35ksin(0.17k-

0.08) pentru valori ale lui k de la 0 la n >

Rafinarea pseudoinstrucţiunii #1 se poate face direct în program. La rafinarea

pseudoinstrucţiunii #2 luăm în consideraţie caracterul repetitiv al acţiunii solicitate, astfel că

putem folosi structura de ciclu cu test iniţial, iar programul devine:

<#1. Se introduce valoarea lui n, de tip intreg> /* #2. Se calculează şi se afisează valoarea expresiei */ k=0; // Se iniţializează k la prima sa valoare

Page 87: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

87

cât_timp k<=n afişează_valoarea_expresiei 2e-0.35ksin(0.17k-0.08); k=k+1; // se trece la valoarea următoare a lui k sfârşit_ciclu

Programul corespunzător în limbajul Java se găseşte în fişierul Repetare1.java.

Exemplul 2. Calcularea unei sume cu număr finit de termeni.

Considerăm că se cere să se calculeze suma

în care sunt date valorile variabilelor a şi b, de tip real şi n de tip întreg.

Aplicând tehnica rafinărilor succesive, vom da pentru început programului următoarea

structură secvenţială:

<#1. Se introduc datele de intrare n de tip întreg şi a,b de tip real> <#2. Se calculează suma S> <#3. Se afişează valoarea lui S>

Rafinarea pseudoinstrucţiunilor #1 şi #3 se poate face direct în program. Pentru rafinarea

pseudoinstrucţiunii #2, remarcăm că suma S se poate calcula în modul următor: se porneşte

de la valoarea iniţiala S=0 şi se adaugă la aceasta succesiv toţi termenii sumei, pentru valori

ale lui k de la 0 la n. Acţiunea are un caracter repetitiv, deci se poate folosi în acest scop un

ciclu cu test iniţial. Se obţine astfel programul următor în pseudocod:

<#1. Se introduc datele de intrare n de tip întreg şi a,b de tip real> /* #2. Se calculează S */ S=0; // Se atribuie lui S valoarea iniţială k=0; // Se atribuie lui k valoarea iniţială cât_timp k<=n <#2.1. Se calculează termenul curent al sumei şi se adaugă la valoarea precedentă a lui S > k=k+1; // Se trece la valoarea următoare a lui k sfârşit_ciclu afisează S;

Programul corespunzător în limbajul Java se găseste în fişierul Suma1.java.

Exemplul 3. Calcularea sumei unei serii convergente.

Fie S suma seriei convergente

S=1+x+x2/(2!)+x

3/(3!)+...+x

k/(k!)+...

în care k! este factorialul lui k. Demonstrarea existentei acestei sume (deci a convergenţei

seriei) este de domeniul analizei matematice. Întrucât, însă, noi ştim că această serie este

Page 88: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

88

convergentă, putem să scriem un program pentru calcularea sumei S. Seria are un număr

infinit de termeni, deci valoarea ei exactă nu poate fi calculată direct, prin adunarea lor.

Totuşi, valoarea aproximativă a sumei S se poate obţine prin "trunchiere", adică luând în

consideraţie numai un număr finit de termeni. Vom calcula deci, de fapt, suma parţială:

Sn=1+x+x2/(2!)+x

3/(3!)+...+x

n/(n!)

cu observaţia că numărul de termeni n nu este dinainte cunoscut.

Se ştie (si se observă cu uşurinţă) că termenii seriei sunt descrescători ca modul. Ne putem

deci opri din evaluarea sumei, în momentul în care constatăm că valoarea termenului curent

este mult mai mică decât suma parţială deja calculata. Putem deci adopta, pentru calcularea

sumei, următorul program în pseudocod:

<#1. Se introduce valoarea lui x, de tip real> S=0; // Se iniţializează suma S la valoarea 0 k=0; // Se iniţializează indicele termenului curent la valoarea 0 t=1; // Se iniţializează termenul curent la valoarea 1 (cea a primului

termen) /* Se calculează suma S a seriei */ cât_timp (<#2.termenul curent t este semnificativ>) S=S+t; // Se adaugă la suma precedentă S valoarea termenului curent // şi se obţine noua valoare a sumei S k=k+1; // Se trece la indicele termenului următor; <#3.se calculează noua valoare t a termenului următor> sfârşit_ciclu afişează S.

Pentru a rafina pseudocondiţia #2 avem în vedere că, în memoria calculatorului, numerele

reale au lungime finită. În consecinţă, dacă adunăm două numere foarte diferite ca ordin de

mărime, "suma" lor va fi egală cu cel mai mare dintre ele. De exemplu, dacă reprezentarea

numerelor reale s-ar face în sistemul zecimal cu 6 cifre semnificative, atunci suma

32.7628+0.00006924 ar fi egala cu numarul cel mai mare, adica 32.7628, deoarece cifrele de

la rezultat situate după cea de a 6-a cifra semnificativă se pierd. În cazul seriei noastre, la un

moment dat termenul curent t va deveni atât de mic ca modul, încât adunat la suma deja

calculata S nu o va mai modifica. Vom considera deci că termenul t este semnificativ, cât

timp se îndeplineşte condiţia (S+t este_diferit_de S).

Pentru a rafina #3, observăm că între valorile termenului t la doi paşi succesivi k şi k-1 exista

relaţia:

tk=tk-1*x/k.

Întrucât în program nu este necesar să folosim indicii paşilor, vom scrie această relaţie sub

forma t=t*x/k, adică se atribuie ca nouă valoare a termenului curent t valoarea precedentă a

acestui termen, înmulţită cu raportul x/k.

Cu observaţiile de mai sus, programul de calculare a sumei seriei devine:

<#1. Se introduce valoarea lui x, de tip real> S=0; // Se iniţializează suma S la valoarea 0 k=0; // Se iniţializează indicele termenului curent la valoarea 0

Page 89: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

89

t=1; // Se iniţializează termenul curent la valoarea 1 (cea a primului

termen) /* Se calculează suma S a seriei */ cât_timp (S+t este_diferit_de S) S=S+t; // Se adaugă la suma precedentă S valoarea termenului curent // şi se obţine noua valoare a sumei S k=k+1; // Se trece la indicele termenului următor; t=t*x/k; // se calculează noua valoare t a termenului următor sfârşit_ciclu afişează S.

Programul corespunzător în limbajul Java este dat în fişierul Serie1.java. Pentru a înţelege

mai bine acest program, recomandăm să calculaţi 3-4 termeni manual pentru a urmări cum se

înlănţuie aceştia.

Instrucţiunea do..while (ciclul cu test final)

Forma generală a instrucţiunii de control, prin care se realizează în limbajul Java ciclul cu test

final este următoarea:

do instrucţiune while (condiţie);

unde, la fel ca în cazul instrucţiunii while,condiţie este o expresie de tip boolean, iar

instrucţiune este orice instrucţiune (simplă sau structurată) din limbajul Java. Remarcăm

că la sfârşitul acestei instrucţiuni (după condiţie) se pune obligatoriu ';' (punct şi virgulă).

Principala deosebire faţă de instrucţiunea while pentru ciclul cu test iniţial este că

testarea condiţiei se face după ce a fost executată instrucţiunea din corpul ciclului. În

consecinţă, corpul ciclului va fi executat cel puţin o dată.

În programul din fişierul DeosCicluri.java se face o comparaţie între funcţionarea ciclurilor

cu test iniţial şi cu test final în condiţii similare.

În programele din fişierele Repetare2.java,Suma2.java şi Serie2.java se reiau exemplele din

secţiunea precedentă (şi realizate în fişierele Repetare1.java, Suma1.java şi Serie1.java), dar

folosind de data aceasta ciclul cu test final.

Page 90: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

90

Instrucţiunea for (ciclul cu contor generalizat)

În unele limbaje de programare, pentru realizarea ciclurilor la care numărul de paşi este

dinainte cunoscut, se foloseşte o instrucţiune de control specială, numită "ciclu cu contor". În

pseudocod, această instrucţiune poate fi scrisă în modul următor:

pentru variabila de_la val_init la val_fin [cu_pasul pas] execută <instrucţiune sau secvenţă de instrucţiuni> sfârşit_ciclu

în care, de regulă, variabila este o variabilă (de regulă de tip întreg), numită şi contorul

ciclului,val_init şi val_fin sunt respectiv valorile iniţială şi finală ale acestei variabile,

iar pas este pasul de variaţie la fiecare parcurgere a ciclului. Pasul implicit este 1.

De exemplu, pentru a calcula produsul P=(a+5)*(a+6)*(a+7)*...*(a+n) se vor scrie

următoarele pseudoinstrucţiuni:

P=1; pentru k de_la 5 la n execută P=P*(a+k); sfârşit_ciclu

Remarcăm că, în acest exemplu, instrucţiunea P=1 nu face parte din ciclu, dar ea a fost

necesară pentru a da valoarea iniţială a variabilei P.

În mod similar, pentru a calcula suma S=7+10+13+16+...+31 se pot folosi instrucţiunile

S=0; pentru j de_la 7 la 31 cu_pasul 3 execută S=S+j; sfârşit_ciclu

Remarcăm că, pentru aceleaşi calcule, se pot folosi şi ciclurile cu test iniţial sau cu test final.

Astfel, primul din aceste exemple, poate fi rescris folosind ciclul cu test iniţial astfel:

P=1; k=5; cât_timp k<=n execută P=P*(a+k); k=k+1; sfârşit_ciclu

Remarcăm că, la trecerea de la ciclul cu contor la ciclul cu test iniţial, s-au introdus

următoarele instrucţiuni suplimentare:

- înainte de intrarea în ciclu, s-a pus instrucţiunea k=5, prin care se atribuie variabilei-

contor valoarea iniţială;

- la sfârşitul corpului ciclului s-a introdus instrucţiunea k=k+1, prin care se trece la

Page 91: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

91

valoarea următoare a variabilei-contor;

- in instrucţiunea while s-a pus drept condiţie compararea variabilei-contor cu valoarea ei

finală.

Lăsăm cititorului ca exerciţiu să scrie acelaşi program, folosind ciclul cu test final.

În limbajul Java, urmând tradiţia limbajului C de la care acesta a preluat o bună parte a

regulilor de sintaxă, se foloseşte o instructiune generalizată, prin care se realizează atât ciclul

cu contor, cât şi ciclul cu test iniţial. Această instrucţiune are forma:

for ([iniţializare]; [condiţie] ; [trecere_la_pasul_următor] ) [<instrucţiune_corp_ciclu>]

în care:

iniţializare ::= instructiune[,instructiune]*- este formată din una sau mai

multe instrucţiuni, separate prin virgule, care se execută înainte de intrarea în ciclu, astfel că

sunt folosite, de regulă, pentru iniţializarea acestuia;

condiţie - este o expresie de tip boolean folosită drept condiţie de continuare a

ciclului cu test iniţial (condiţia este testata înainte de a se executa corpul ciclului;

trecere_la_pasul_următor := instrucţiune[,instrucţiune]* - una sau mai

multe instrucţiuni, separate prin virgule, care se execută după ce a fost executat corpul

ciclului. astfel că sunt, în general, folosite pentru pregătirea trecerii la următoarea parcurgere

a ciclului;

<instrucţiune_corp_ciclu>- o instrucţiune (simpla sau structurată) care constituie

corpul ciclului.

Respectând aceasta formă generală, calcularea produsului dat ca exemplu mai sus în

pseudocod, se programează în limbajul Java în modul urmator:

for(P=1,k=5; k<=n; k++) P*=a+k;

Se observă ca se iniţializează P la valoarea 1 şi k la valoarea 5, apoi cât timp este satisfacută

condiţia k<=n se execută instrucţiunea P*=a+k, după care se execută instrucţiunea k++ (se

trece la următoarea valoare a lui k).

După cum se vede în forma generală, diferitele componente ale acesteia sunt opţionale; în

consecinţă, instrucţiunea for poate fi scrisă sub diferite forme echivalente, de exemplu:

a) P=1; k=5; for(;k<=n;){ P*=a+k; k++; }

Observăm că, de data aceasta, instrucţiunea for(;k<=n;) are exact acelaşi efect, pe care l-

ar fi avut instrucţiunea while(k<=n). Remarcăm, de asemenea, că cei doi separatori ';' din

interiorul parantezei au fost mentinuţi, chiar dacă lipsesc zonele de iniţializare şi de

Page 92: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

92

incrementare.

b) for(P=1,k=5;k<=n;P*=a+k,k++);

În ultimul caz, corpul ciclului este constituit numai dintr-o instrucţiune vidă, reprezentată prin

carecterul ';' pus dupa paranteza închisă. Aceste exemple sunt date şi în programul din

fişierul TestFor.java. Tot acolo se arată că variabila care serveşte drept contor al ciclului

poate fi, în limbajul Java, şi de tip real, iar creşterea acesteia de la o parcurgere la alta a

ciclului poate fi de asemenea de tip real şi nu este obligatoriu să fie constantă. Considerăm că

exemplele din acest program sunt suficiente pentru a arăta ca instrucţiunea for permite

programatorului posibilităţi de utilizare foarte diverse, cu condiţia ca acesta să înţeleaga

corect modul ei de funcţionare.

Declararea unor variabile în zona de iniţializare a ciclului for

Este permis ca în zona iniţializare a ciclului for să fie incluse şi unele declaraţii de

variabile. Aceste variabile sunt tratate drept variabile locale ale ciclului for respectiv şi deci

nu sunt vizibile (disponibile) după ieşirea din ciclu, putând fi redefinite. Iată un astfel de

exemplu:

x=0; for(int k=0; k<n; k++) S+=a*k;

În acest caz, variabila k a fost atât declarată, cât şi iniţializată, în zona de iniţializare a

instrucţiunii for. În consecinţă această variabilă este disponibilă în interiorul acestei

instrucţiuni, inclusiv în corpul ciclului, dar îşi pierde valabilitatea la ieşirea din acest ciclu.

Daca în zona de iniţializare apare o declaraţie, ea trebuie să fie singura instrucţiune din

această zonă. Astfel, în exemplul precedent nu ar fi fost permis, de exemplu, să se scrie for(x=0, int k=0; k<n; k++) S+=a*k; Este însă permis să se declare în zona de iniţializare mai multe variabile de acelaşi tip. Astfel,

exemplul anterior poate fi modificat după cum urmează:

x=0; for(int k=0,i=9; k<n; k++, i--) S+=(a+i)*k;

Aceste exemple şi altele similare se găsesc în programul din fişierul TestFor1.java.

Exemple de programe în care se foloseşte ciclul for

În fişierele Repetare3.java, Suma3.java şi Serie3.java se reiau exemplele date in fisierele

Repetare1.java, Suma1.java şi Serie1.java), dar folosind instrucţiunea for în loc de

while. Vă recomandăm să comparaţi în mod special programele din fişierele Serie1.java si

Serie3.java si să explicaţi deosebirile constatate.

Page 93: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

93

Instrucţiuni etichetate

În principiu, orice instrucţiune în limbajul Java poate purta o etichetă. Instrucţiunile etichetate

au forma etichetă : instrucţiune

unde

etichetă este un identificator;

instrucţiuneeste o instrucţiune simplă sau structurată.

Exemplu alpha: x=2*a+b;

Se permite să se folosească drept etichete chiar şi identificatori care mai sunt folosiţi în

acelasi program ca nume de variabile, clase, metode etc., fară a se crea prin aceasta confuzii,

deoarece compilatorul face distincţie între etichete şi nume în funcţie de contextul în care

acestea sunt utilizate.

Terminarea abruptă a execuţiei instrucţiunilor structurate

În secţiunile anterioare, s-a arătat că limbajul Java respectă principiile programării

structurate. În consecinţă, instrucţiunile de control au fost concepute în conformitate cu

aceste principii, iar instrucţiunea goto nu există. Chiar dacă, din precauţie, cuvântul cheie

gotoa fost menţinut în limbaj, el nu este încă efectiv folosit. Cu toate acestea, având în

vedere experienţa practică şi pentru a veni în ajutorul programatorilor, autorii limbajului Java

au admis şi anumite abateri de la structurile de control fundamentale acceptate de teoria

programării structurate, fără a încălca însă principiul de bază al acesteia, conform căruia

fiecare asemenea structură trebuie sa aibă un singur punct de intrare şi un singur punct de

ieşire. Am arătat deja, că astfel de excepţii sunt instructiunile switch,do..while şi for. Ne

vom ocupa acum de o alta abatere de la programarea structurată pură, care constă în folosirea

instrucţiunilor break şi continue şi a instrucţiunilor etichetate.

Folosirea instrucţiunilor break şi continue

Instructiunile break şi continue au forma generală următoare:

break [etichetă]; continue [etichetă];

unde etichetăeste eticheta unei instrucţiuni şi este un identificator. Eticheta este opţională

(de aceea a fost scrisă de noi între paranteze drepte).

Instructiunea break se poate folosi în corpul unei instrucţiuni switch, while,

do..while sau for şi are ca efect ieşirea forţată (abruptă) din structura de control în care

se găseşte instrucţiunea respectivă.

S-a arătat deja cum se foloseşte instrucţiunea break în corpul unei instrucţiuni switch. Iată

acum un exemplu de folosire într-un ciclu cu test iniţial:

k=1; S=0; while(S+t!=S) {

Page 94: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

94

t*=a/k; S+=t; if(t<1.0e-10*S) break; k++; }

În acest caz, în momentul în care este satisfacută condiţia (t<1.0e-10*S) din instructiunea

if se iese forţat din ciclu, chiar dacă condiţia principală de continuare a ciclului (S+t!=S)

este încă satisfacută.

Iată şi un exemplu similar, în care se iese forţat din instrucţiunea for:

k=1; S=0; for(;;) { t*=a/k; if(S+t==S) break; S+=t; k++; }

Întrucât iniţializarea ciclului s-a făcut înainte de instructiunea for, iar condiţia de ieşire din

ciclu şi pregatirea continuarii ciclului se găsesc în corpul acestuia, în paranteza lui for toate

cele trei zone au ramas vide.

Instrucţiunea continue se poate folosi numai în corpul ciclurilor (while, do..while,

for). Dacă instrucţiunea continue nu are etichetă, efectul este că se trece peste restul

instrucţiunilor din corpul ciclului, începând din punctul în care se găseşte instrucţiunea

continue până la sfârşitul acestuia, dar se continuă executarea ciclului, adică se reia

executarea corpului acestuia cât timp este satisfacută condiţia de continuare.

Să considerăm, de exemplu, următorul fragment de program:

s=0; for(k=0; k<20; k++) { x*=a; s+=x; if(k<16) continue; System.out.println("k="+k+" x="+x+" s="+s); }

În acest caz, corpul ciclului se va repeta pentru valori ale lui k de la 0 la 19, dar instrucţiunea

System.out.println(...) va fi "sărită" pentru valori ale lui k mai mici decât 16, trecându-se

direct la acolada de închidere a corpului ciclului, astfel că afişările se vor face numai

începand cu k=16.

Folosirea etichetei în instrucţiunea break

Necesitatea utilizării unei etichete apare atunci când există două astfel de structuri imbricate

una în alta, iar noi dorim ca prin break să se iasa forţat din cea exterioară, ca în exemplul

urmator:

ciclu1: while(w>0.05){ w/=a;

Page 95: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

95

for(int k=0; k<n; k++) { s+=w; if(s>b) break ciclu1; y+=w*s } }

Instrucţiunea break se găseşte, în acest exemplu, în corpul ciclului interior. Dacă nu ar fi

conţinut eticheta ciclu1,această instrucţiune ar fi provocat numai ieşirea dim ciclul interior

(for), dar s-ar fi reluat execuţia ciclului exterior (while), implicand, desigur, şi reluarea

ciclului interior continut de acesta. Dacă însă este prezenta eticheta din break, se va ieşi forţat

din instrucţiunea de control care poartă această etichetă, în cazul de faţă din ciclul exterior.

Remarcam, deci, că eticheta conţinută în instrucţiunea break indică faptul ca se va ieşi forţat

din structura de control care poartă aceeaşi etichetă. Aceasta înseamnă că instrucţiunea

break cu etichetă constituie o abatere locală de la principiul de bază al programării

structurate, conform căruia fiecare structură de control trebuie sa aibă un singur punct de

intrare şi un singur punct de ieşire. În ultimul exemplu, ciclul interior are două puncte de

ieşire: unul este ieşirea normală din ciclul for, iar celalalt este ieşirea prin break. Daca luam

însă în consideraţie ciclul exterior, constatăm ca acesta respectă principiul menţionat. Desigur

că pot să existe mai multe instrucţiuni de control cuprinse una în alta şi fiecare dintre ele

poate avea o etichetă, care poate fi utilizată într-o instrucţiune break.

Testarea a diferite situaţii de utilizare a instructiunii breakse face în programul din fişierul

TestBreak.java.

Folosirea etichetei în instrucţiunea continue

Să considerăm acum următorul fragment de program:

ciclu1: for (int i=0; i<6; i++) { System.out.println("Control 1: i="+i); for(int j=3; j>0; j--) { System.out.println("Control 2: i="+i+" j="+j); if(i>1 && i<5) continue ciclu1; System.out.println("Control 3: i="+i+" j="+j); } // Sfarsitul ciclului interior System.out.println("Control 4: i="+i); } // Sfarsitul ciclului exterior

Instrucţiunea conţinue eticheta ciclu1, care aparţine ciclului exterior. În consecinţă,

pentru valori ale variabilei i cuprinse între 1 şi 5, se va trece forţat la sfârşitul corpului

ciclului exterior, deci nu se vor mai executa instrucţiunile de afişare "Control 3" şi "Control

4".

Programul de testare pentru instrucţiunea continue se găseşte în fişierul TestCont.java.

Tratarea excepţiilor

În timpul executării programului, pot apare anumite situaţii care altereaza desfăşurarea

normală a acestuia. Când apare o astfel de situaţie, de regulă, se generează o excepţie sau o

eroare prin care se semnalează incidentul care a avut loc. Excepţiile şi erorile pot fi generate

atât de echipamente (excepţii sau erori hardware), cât şi de programe (excepţii software).

Page 96: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

96

Exemple de excepţii hardware pot fi întreruperile, excepţia de împărţire la zero, unele

incidente din subsistemele de intrare/ieşire etc. Excepţiile software sunt mult mai diverse,

depinzând de specificul programelor care le generează. Deosebirea dintre excepţii şi erori

este că excepţiile sunt considerate că pot fi tratate prin program, în timp ce erorile sunt

considerate mai curând nerecuperabile.

În programul din fişierul TestExcept1.java se testează apariţia unei excepţii de împărţire la

zero. Întrucât variabila b are valoarea zero, la executarea împărţirii a/b procesorul

calculatorului generează o excepţie aritmetică. Întrucât în programul nostru nu există

instrucţiuni prin care să se trateze această excepţie, programul se întrerupe, trecându-se

controlul asupra sistemului de operare al calculatorului, iar acesta afişeaza excepţia survenită

şi opreşte executarea programului.

În limbajul Java, există posibilitatea de a se trata prin program diferitele excepţii care apar în

timpul execuţiei. În acest fel, programatorul poate să prevadă căi alternative de continuare a

executării programului, fără a mai fi necesară oprirea executării lui. În mediul de lucru Java,

la apariţia unei excepţii se generează un obiect special numit excepţie, care conţine informaţia

despre excepţia respectivă. Acest obiect poate fi captat prin program, iar informaţia conţinută

în el poate fi utilizată pentru a decide calea pe care se va merge în continuare în derularea

programului. Toate obiectele de excepţie care se referă la acelaşi tip de incident formează o

clasă de excepţii.

Tratarea prin program a excepţiilor se face, în limbajul Java, folosind instrucţiunea try

urmată de una sau mai multe clauze catch şi, opţional, de o clauză finally sub forma

urmatoare: try { secventa } catch (ClasaExceptie1variabila1) { secventa1 } catch (ClasaExceptie2 variabila2) { secventa2 } ............... catch (ClasaExceptieN variabilaN) { secventaN } [finally { secventa_finalizatoare }]

În engleza, try înseamnă încearcă, iar catch înseamnă prinde. În corpul instrucţiunii try se

pune secvenţa de instrucţiuni în care este posibil ca, la executarea programului, să apară

excepţii. Dacă excepţia a apărut într-un punct situat în corpul unei instrucţiuni try, aceasta

instrucţiune se termină în mod abrupt, astfel că restul instrucţiunilor nu se mai execută,

trecându-se direct la acolada de închidere a blocului. Se parcurg apoi, una după alta, clauzele

catch, până se ajunge la cea care are între paranteze numele clasei excepţiei care s-a produs şi

se execută secvenţa din corpul acestei clauze.

Clauza finally este opţională şi conţine o secvenţă de instructiuni care se vor executa în final,

adică după ce a fost tratată excepţia prin una din clauzele catch, sau dacă nu a fost tratată prin

Page 97: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

97

nici una dintre acestea.

Exemplul 1: În fişierul TestExcept2.java este dată o modificare a programului din fişierul

TestExcept1.java, în care excepţia este tratată prin instrucţiunea try. Întrucât se ştia că este

posibilă apariţia unei excepţii aritmetice, s-a încercat să se capteze mai întai această excepţie.

Ca rezervă, s-a prevăzut şi o clauza catch pentru clasa Exception, care va capta orice alta

excepţie. Comparând rezultatele executării celor două programe menţionate, constatăm că,

atunci când s-au tratat excepţiile prin instrucţiunea try, programul nu a mai fost oprit

anormal, ci s-a executat blocul clauzei catch(ArithmeticException e1), după care s-a

continuat executarea normală a programului. În schimb, instrucţiunile existente în blocul try,

după cea care a generat excepţia, nu au mai fost executate.

Exemplul 2: În fişierul TestExcept3.java se reia programul din exemplul anterior, dar a fost

suprimată prima din clauzele catch. Executând acest program, se poate observa că şi de data

aceasta excepţia aritmetică a fost captata, însa de clauza catch(Exception e).

Exemplul 3: În fişierul TestExcept4.java se reia programul din Exemplul 1, dar după captarea

excepţiei s-a introdus si clauza finally. Se observă ca secvenţa din aceasta clauză este

executată chiar daca excepţia a fost captată prin catch. Mai mult, în fişierul

TestExcept5.java s-a reluat acelaşi program, dar s-a modificat valoarea numitorului fracţiei,

astfel că nu mai are loc o împărţire la zero. Se observă ca secvenţa din clauza finallyeste

executată şi în acest caz.

Întrebări

Nivel 1

1. Ce este o expresie?

2. Cum se stabileşte tipul unei expresii?

3. Fie a si b variabile de tip byte, c de tip int, u de tip float şi v de tip double.

Care sunt tipurile următoarelor expresii: a+b, a*c, a*c+u, u-2*v.

4. Ce este precedenţa operatorilor?

5. În ce ordine se aplică operatorii cu acelaşi nivel de precedenţă?

6. În ce ordine se evaluează operanzii unui operator binar?

7. Ce forma sintactică are expresia condiţională şi care este semnificaţia acestei

expresii?

8. Ce este o instrucţiune?

9. Ce deosebire este între instrucţiunile simple şi cele structurate?

10. Ce este instrucţiunea vidă şi cum se scrie?

11. Ce este o instrucţiune-expresie?

12. Ce deosebiri există între o expresie şi o instrucţiune-expresie?

13. În ce constă teorema de structură din metoda programării structurate?

14. Care sunt categoriile de instrucţiuni de control admise de metoda programarii

structurate?

Page 98: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

98

15. Ce fel de structură de control este un bloc şi care este forma lui sintactică?

16. Ce sunt variabilele locale şi care este domeniul lor de vizibilitate?

17. Prin ce instrucţiuni se realizează structura de control alternativă şi care este forma lor

sintactică?

18. Ce sunt excepţiile?

19. Ce deosebire este între excepţii şi erori?

20. Care este forma sintactică a instrucţiunii de tratare a exceptiilor şi cum trebuie ea

interpretată?

Nivel 2

1. Construiţi arborele sintactic al următoarei expresii: (a+2*b/c)*(2*d-3)+3*e+5

2. Construiţi arborele sintactic al următoarei expresii: a=(b+=2*a)-c++*(d-=c+1)

3. Construiţi arborii sintactici ai tuturor expresiilor din fişierul EvExpresii.java.

4. Explicaţi rezultatele obţinute la executarea programului din fişierul ExprCond.java.

5. Ce este o instrucţiune de atribuire şi care este efectul ei?

6. Care este deosebirea dintre valorile expresiilor de preincrementare şi

postincrementare? Dar între efectele instrucţiunilor de preincrementare şi

postincrementare?

7. Ce este o instructiune de invocare de metodă şi care este efectul ei?

8. Care este schema logică a structurii de control secvenţiale şi cum trebuie interpretată?

9. Care este schema logică a structurii de control alternative şi cum trebuie interpretată?

10. Care este schema logică a ciclului cu test iniţial şi cum trebuie interpretată?

11. Care este schema logică a ciclului cu test final şi cum trebuie interpretată?

12. Unde sunt plasate variabilele locale în memoria maşinii virtuale Java?

13. Când sunt eliminate din memorie variabilele locale?

14. Cum se stabileşte cărui if îi aparţine clauza else în cazul instructiunilor if

imbricate?

15. Care este forma sintactică a instrucţiunii switch şi cum este ea interpretată?

16. Ce rol are instrucţiunea break în cadrul unui bloc switch?

17. Ce este o etichetă şi ce formă sintactică are o instrucţiune etichetată?

18. Poate o etichetă să aibă acelaşi identificator cu cel al unui nume de variabilă sau de

metodă?

19. Cum acţionează o instrucţiune break fără etichetă în corpul unui ciclu?

20. Cum acţionează o instrucţiune continue fără etichetă în corpul unui ciclu?

21. În ce situaţie se foloseşte o instrucţiune break cu etichetă?

22. În ce situaţie se foloseşte o instrucţiune continue cu etichetă?

23. La ce serveşte clauza catch şi unde se plasează?

24. La ce serveşte clauza finally şi unde se plasează?

Page 99: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

99

Tipul referinţă. Utilizarea claselor din

pachetul java.lang. Tablouri. Utilizarea

parametrilor din linia de comandă

Tipul referinţă; declararea variabilelor referinţă; 99

Clase, câmpuri, metode; 101

Constructori; crearea obiectelor prin operatorul new; 102

Moştenirea şi polimorfismul; ierarhia de clase Java; 102

Atribuirea de valori variabilelor-referinţă; 103

Pachetele de clase din Java API; declaratia import; 104

Utilizarea claselor din pachetul java.lang 105

Clasa Object; 105

Clasele de excepţii; 107

Clasele String şi StringBuffer; 108

Clasa Class; 111

Clasele acoperitoare de tip; 112

Clasa Math; 119

Clasa System; 120

Tablouri 121

Tablouri unidimensionale; 122

Tablouri multidimensionale; 126

Utilizarea parametrilor din linia de comandă 133

Întrebări. 134

Tipul referinţă

În limbajul Java există două categorii de tipuri de date: tipuri primitive şi clase.

Tipurile primitive sunt predefinite în limbaj, în sensul că numele, mulţimea de date,

mulţimea de operaţii şi reprezentarea datelor în memoria internă a maşinii virtuale Java

pentru fiecare tip sunt definite în insăşi specificaţia limbajului Java şi nu mai pot fi

modificate de programatori. În program, datele de tipuri primitive apar sub forma de

variabile.

Fiecare variabilă are un nume, un tip şi o valoare şi este plasată într-o anumita locaţie de

memorie. În locaţia de memorie respectivă se găseşte chiar valoarea variabilei. Pe

programator nu il interesează insă adresa de memorie la care se găseşte variabila, ci doar

numele, tipul şi valoarea acesteia.

Page 100: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

100

Clasele sunt tipuri de date structurate specifice programării orientate pe obiecte. Clasele se

definesc de programatori şi se grupează în pachete de clase. La crearea unui program nou,

programatorul poate utiliza clasele din pachetele deja existente, sau poate creea propriile sale

clase. În program, fiecare clasă poate avea mai multe instanţe, numite obiecte.

Comparând clasele cu tipurile primitive, constatăm că clasa este o extensie a conceptului de

tip, iar obiectul este o extensie a conceptului de variabila. Deosebirea este că o variabilă

simplă este o locaţie de memorie care conţine o valoare primitivă, în timp ce obiectul este tot

o zonă de memorie, care conţine însă o structură de date.

În memoria maşinii virtuale Java, obiectele sunt plasate într-o zonă de memorie specială,

numită memorie dinamică (în engleză: heap, adică "gramadă"). Localizarea în memorie a

obiectelor se face cu ajutorul unor variabile speciale, numite variabile referinţă. Valoarea

unei variabile referinţă nu este obiectul însuşi, ci o referinţă la acest obiect. Din această

cauză, se consideră că variabilele referintă aparţin unui tip de date numit tip referinţă.

Mulţimea de valori a acestui tip este mulţimea referinţelor, adică mulţimea locaţiilor

(adreselor) din memoria dinamică. Operaţiile permise asupra datelor de tip referinţa sunt cele

date de operatorii de atribuire (=), egalitate (==) şi inegalitate (!=) care au aceleaşi

semnificaţii şi mod de utilizare ca pentru toate celelalte tipuri de date.

Referinţele din Java sunt similare pointerilor din unele limbaje de programare tradiţionale,

cum sunt Pascal şi C. Există, totuşi, deosebiri importante:

- valorile variabilelor-pointer sunt adrese din memorie care pot fi cunoscute de programator

(de exemplu pot fi afişate) De asemenea, unei variabile-pointer i se poate atribui ca valoare o

adresa dată explicit. În schimb, adresele la care se găsesc în memorie obiectele indicate de

referinţele din Java nu pot fi cunoscute de utilizator;

- în limbajele tradiţionale, pointerii pot indica nu numai adresele în memorie ale unor

structuri de date, ci şi pe cele ale unor variabile simple. În java, referinţele pot fi folosite

numai pentru obiecte;

- în limbajele traditionale (de exemplu în C/C++) se pot face asupra pointerilor operatii

aritmetice, ceeace nu este permis asupra referinţelor în Java.

Declararea variabilelor referinţă

Declararea variabilelor referinţă se poate face la fel cu declararea variabilelor de tipuri

primitive. Singura deosebire constă în faptul că, în locul tipului primitiv, se foloseşte un

nume de clasa. De exemplu, declaraţia String s1, s2, s3;

arată că s1, s2 si s3 sunt variabile referinţă către obiecte din clasa String, adică din

clasa şirurilor de caractere.

Atentie: s1, s2 si s3 nu sunt şiruri de caractere (adică obiecte din clasa String) ci sunt doar

referinţe către şiruri de caractere. Aceasta înseamnă că valoarea fiecăreia deintre ele nu este

un obiect, ci o referinţă la obiect. Obiectul propriu-zis nu se găseşte în memorie în acelaşi loc

Page 101: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

101

cu variabila, ci undeva în memoria dinamică.

Prin contrast, în cazul declararii unor variabile primitive, de exemplu int i1,i2,i3;

variabilele i1, i2 si i3 sunt numere de tip int, adică au ca valori astfel de numere.

Vom arăta ulterior şi modul în care pot fi iniţializate variabilele referinţă.

Clase, câmpuri, metode

Clasa este o structură de date, asociată cu o colecţie de proceduri sau funcţii, metode, care

utilizează datele din această structură.

Datele unei clase se numesc câmpuri, sau variabile membre. Câmpurile pot fi statice (ale

clasei) sau nestatice (ale instanţei). Când clasa este instanţiată, în memoria maşinii virtuale

Java se construieşte un obiect (o instanţă a clasei respective). Obiectul conţine numai câmpuri

nestatice. Câmpurile statice se păstreaza în memorie într-un singur loc, care este rezervat

clasei respective.

Metoda este o funcţie, care întoarce o valoare şi poate avea, de asemenea, efect lateral. Ca şi

câmpurile, metodele pot fi statice(ale clasei) şi nestatice (ale instanţei). Metodele statice pot

invocă numai câmpurile statice ale clasei respective, în timp ce metodele nestatice pot invoca

atât câmpurile statice, cât şi pe cele nestatice (ale unei instanţe a clasei respective). Dacă

valoarea întoarsă de metodă este void, metoda respectivă este o procedură şi trebuie să aibă

obligatoriu efect lateral.

Invocarea unei metode statice (a clasei) se face printr-o expresie de forma nume_clasa.nume_metoda(parametri_efectivi)

a cărei valoare este valoarea întoarsă de funcţia respectivă. O astfel de invocare de funcţie

poate fi deci folosită ca o componentă într-o altă expresie. De exemplu, expresia

Math.sqrt(a) serveste pentru a calcula rădăcina patrată a lui a, în care scop este invocată

funcţia sqrt, care este o metodă statică a clasei Math (clasa funcţiilor matematice uzuale).

Putem folosi această invocare de metodă într-o expresie mai complicată, de exemplu x=2*Math.sin(a)+3;

Invocarea unei metode nestatice (a instanţei) se face sub forma referinţa_la_obiect.nume_metodă(parametri_efectivi) deci numele metodei nu mai este calificat prin (însoţit de) numele clasei, ci prin cel al

variabilei referinţă la obiectul respectiv, sau prin o expresie care are ca valoare o astfel de

referinţă. De exemplu, daca r1 este o variabilă referinţă care indică un anumit obiect din

memorie, iar met(a)este o metodă nestatică a clasei căreia îi aparţine acest obiect, atunci

r1.met(a) are ca efect invocarea metodei met pentru obiectul indicat de r1. În acest fel,

metoda met(a) va folosi atât câmpurile (nestatice ale) obiectului indicat de referinţa r1, cât şi

câmpurile (statice ale) clasei căreia îi aparţine acest obiect.

Dacă o metoda are efect lateral, ea poate fi invocată şi sub forma de instrucţiune. Această

instrucţiune constă numai din expresia de invocare a metodei, urmată de punct_şi_virgulă. În

acest caz, valoarea întoarsă de metodă (valoarea expresiei) este ignorată, folosindu-se numai

Page 102: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

102

efectul lateral al metodei respective. Un exemplu cunoscut deja este instrucţiunea System.out.println(sir);

Este evident că metodele care întorc void (procedurile) pot fi invocate numai sub formă de

instrucţiuni, fiind folosite pentru efectul lor lateral.

Constructori

Constructorul este o procedură specială, prin care se construiesc obiecte dintr-o anumită

clasă. Constructorul are întotdeauna acelaşi nume cu clasa. În schimb, o clasă poate avea

mai mulţi constructori, care pot să difere între ei prin numărul şi/sau tipul argumentelor.

Constructorul alocă în memoria dinamică spaţiul necesar pentru un obiect din clasa căreia îi

aparţine şi iniţializează câmpurile acestui obiect cu valori care depind de argumentele sale.

Crearea obiectelor prin operatorul new

Invocarea unui constructor se face prin operatorul new, urmat de numele constructorului

respectiv şi de lista de argumente a acestuia. Operatorul new este unar, iar operandul lui este

un constructor, deci forma generala a expresiei de invocare a unui constructor este new nume_constructor(parametri_efectivi)

Valoarea acestei expresii este o referinţă la obiectul nou construit.

Efectul lateral al acestei expresii este construirea în memorie a unui obiect din clasa căreia îi

aparţine constructorul, iar valoarea acestei expresii este referinţa la obiectul nou construit.

De exemplu, expresia new String("acesta este un sir")

are ca efect (lateral) construirea în memorie a şirului de caractere "acesta este un sir", iar

valoarea expresiei este referinţa către acest şir. Să considerăm acum următoarele două

instrucţiuni: String s1=new String("abcd_1234"), s2; s2=new String("alpha");

Prima dintre ele este o declaraţie, prin care se specifică faptul că s1 şi s2 sunt variabile

referinţă, ale căror valori sunt referinţe la obiecte din clasa String. Totodată, se alocă în

memorie şirul "abcd_1234" şi se atribuie ca valoare iniţială a variabilei s1 referinţa la acest

şir.

A doua dintre instrucţiunile de mai sus, este o instrucţiune de atribuire, în care variabilei s2 i

se atribuie valoarea expresiei new String("alpha"). La executarea acestei expresii, se

obţine ca efect lateral alocarea în memorie a şirului "alpha", iar referinţa la acest şir se

atribuie ca valoare a variabilei s2

Moştenirea şi polimorfismul

Moştenirea este una din proprietăţile fundamentale ale claselor în programarea orientată pe

obiecte. Ea constă în faptul că dintr-o clasă se pot deriva alte clase. Clasa de baza se mai

numeste şi superclasă, iar clasele derivate se numesc şi subclase.

Page 103: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

103

Fiecare clasă derivata moşteneşte câmpurile şi metodele superclasei. Aceasta înseamnă că

toate câmpurile şi metodele existente în superclasă sunt utilizabile şi în subclasă, dar în

aceasta din urmă pot exista, de asemenea, câmpuri şi/sau metode suplimentare.

Polimorfismul este o alta proprietate fundamentală a claselor. În limbajul Java este posibil ca

o metodă a superclasei să fie redefinită în subclasă. Aceasta înseamnă că ea va avea în

subclasă acelaşi nume şi aceeasi lista de parametri şi acelaşi tip de valoare întoarsă ca în

superclasă, dar va avea un comportament diferit.

Să considerăm, de exemplu, că exista clasa Poligon, în care există metoda double arie().

Aceasta metodă este o funcţie, a cărei valoare este aria poligonului. Sa considerăm acum că

Triunghi şi Patrat sunt doua clase derivate din clasa Poligon. În ambele clase derivate va

exista metoda double arie(), dar este evident că modul de calcul al ariei triunghiului diferă

de cel al calculării ariei patratului şi, cu atât mai mult, de modul de calcul al ariei unui

poligon oarecare.

Ierarhia de clase Java

În general, în programarea orientată pe obiecte este permisă moştenirea multiplă, adică o

clasă poate avea mai multe superclase. În limbajul Java este permisă numai moştenirea

simplă, deci fiecare clasă poate avea numai o singură superclasă. Această ierarhie de clase

este unică, adică orice clasă are obligatoriu o superclasă şi numai una. Singura excepţie o

constituie clasa Object, care este rădăcina ierarhiei de clase Java şi nu are superclasă.

Vom arata ulterior că lipsa moştenirii multiple este compensată în Java prin faptul că fiecare

clasa poate avea mai multe interfeţe.

Atribuirea de valori variabilelor-referinţă

Unei variabile referinţă i se pot atribui ca valori referinţă la obiecte din clasa variabilei

respective sau din clasele derivate.

De exemplu, având în vedere că clasa String este derivată din clasa Object, urmatoarele

instrucţiuni sunt corecte:

Object ob; String s=new String("abcd"); ob=s;

În primele două instrucţiuni, s-au declarat variabilele-referinţă ob din clasa Object şi s din

clasa String, ultima fiind iniţializată cu o referinţă către şirul "abcd", care a fost creat

folosind operatorul new. În a treia instrucţiune, variabilei-referinţă ob i se atribuie valoarea

variabilei-referinţă s. În consecinţă, acum variabila ob din clasa Object are ca valoare o

referinţa către obiectul "abcd" din clasa String.

Page 104: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

104

Pachetele de clase din Java API

Clasele sunt grupate în pachete (engleză: package). Pachetul este o colecţie de clase

reutilizabile destinate unui anumit domeniu de utilizare, care sunt puse la dispoziţia

programatorului sub formă compilată (bytecode). Ar putea fi numit şi "bibliotecă de clase",

dar autorii platformei Java au preferat denumirea de pachet.

Pachetul poate avea subpachete. Daca pachetul p are subpachetul q, atunci p.q este numele

complet (numele calificat) al subpachetului q. Acest subpachet poate avea, la rândul sau, alte

subpachete.

Java API (Application Programming Interface - interfaţa de programare de aplicaţii) este

descrierea unui set standard de pachete necesare programării în Java. Pentru pachetele

conţinute în Platforma Java 2 Standard Edition (J2SE) această documentaţie poate fi gasită pe

Internet la urmatoarea adresă:

java.sun.com/products/j2se/1.3/docs/api/index.html - la firma Sun Microsystems;

Principalele pachete de clase sunt:

java.lang - conţine clasele de bază necesare programării în limbajul Java;

java.io - conţine clasele necesare pentru programarea operaţiilor de intrare/ieşire;

java.util - conţine clase pentru anumite structuri de date tipice (listă, stivă etc) şi alte clase

utile;

java.awt si javax.swing - conţin clase necesare pentru realizarea interfeţelor grafice;

java.applet - pentru programarea appleturilor.

Există însă şi multe alte pachete, necesare în diferite domenii de aplicaţie.

Declaraţia import

Pentru a putea utiliza într-un fişier-sursa Java un anumit pachet (subpachet) de clase, la

începutul fişierului respectiv trebuie pusă declaraţia import nume_pachet.*;

în care nume_pachet este numele calificat al pachetului respectiv. De exemplu, pentru a

utiliza orice clase din pachetul java.io se pune declaraţia import java.io.*;

Pentru clasele din pachetul java.lang nu este necesară o declaraţie de import, acestea fiind

importate implicit.

Pentru a importa numai o anumita clasă dintr-un pachet, se foloseste declaraţia import nume_pachet.NumeClasa;

De exemplu, pentru a importa clasa File din pachetul java.io se foloseşte declaraţia import java.io.File;

Declaraţia import nume_pachet.*;

se numeşte declaraţie de import la cerere. Ea nu are semnificaţia că se importă toate clasele

din pachetul (subpachetul) respectiv, ci numai acele clase care sunt utilizate efectiv în

program.

Page 105: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

105

Utilizarea claselor din pachetul java.lang

Pachetul java.lang conţine clasele fundamentale şi există pe orice platformă Java. Pentru

acest pachet nu este necesară declaraţia import, clasele sale fiind importate implicit. Lista

completă a claselor din pachetul java.lang şi descrierea lor se găsesc în documentaţia Java

API de pe Internet. Noi vom prezenta aici câteva clase mai frecvent utilizate.

Clasa Object

Clasa Object este rădăcina ierarhiei de clase a platformei Java. Este singura clasă care nu

are o superclasă. Orice altă clasa este derivată direct sau indirect din clasa Object.

Conceptual, instanţele clasei Object sunt obiecte oarecare, fără atribute precizate. Variabilele

referinţă la Object se folosesc atunci când, la elaborarea programului, se consideră că lor li

se pot da ca valori referinţe la orice fel de obiecte, indiferent de clasa căreia îi aparţin.

În clasa Object sunt declarate, de asemenea, metode care se consideră ca trebuie să existe în

toate celelalte clase. Unele din aceste metode vor trebui redefinite în clasele derivate, pentru a

efectua acţiuni specifice acestor clase.

Metodele clasei Object

Clasa Object nu are date membre. În consecinţă, obiectele acestei clase nu au stare (cu

excepţia faptului ce ele există sau nu).

Clasa are un singur constructor, Object(), care nu are parametri. Obiectele acestei clase nu

conţin date. În schimb, clasa dispune de un set de metode. Conform cu principiul moştenirii,

toate celelalte clase posedă metodele clasei Object.

Metodele clasei Object sunt descrise în Java API. Noi vom prezenta aici numai o parte dintre

ele, care vor fi utilizate în cele ce urmează.

Metoda equals() este declarată sub forma:

public boolean equals(Object obj)

ceeace înseamnă că nivelul de acces este public, valoarea întoarsă (valoarea obţinută la

evaluarea acestei funcţii) este de tip boolean, iar unicul argument aparţine clasei Object.

Expresia a.equals(b) în care a şi b sunt două obiecte, întoarce valoarea true dacă a

este identic cu b şi valoarea false în caz contrar.

Aşa cum este ea definită în clasa Object, metoda equals() întoarce valoarea true numai

dacă cele doua obiecte comparate sunt cu adevărat identice, adică au aceeaşi adresă în

memorie, ceeace se poate scrie şi sub forma expresiei a==b. În clasele derivate, această

metoda poate fi redefinită, respectând principiul polimorfismului, astfel încât să compare cele

două obiecte după conţinut, chiar dacă ele nu au aceeaşi referinţă.

Page 106: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

106

Metoda hashCode() este declarată sub forma

public int hashCode()

şi întoarce codul de dispersie al obiectului căruia i se aplică. Codul de dispersie (engleză:

hash code) este un număr întreg (de tip int) care are următoarele proprietăţi:

- dacă se aplică de mai multe ori aceluiaşi obiect, metoda hashCode() întoarce de fiecare

dată acelaşi cod de dispersie;

- dacă două obiecte sunt egale între ele în sensul definit prin metoda equals(), atunci

codurile de dispersie obţinute aplicând metoda hashCode() fiecăruia în parte trebuie să fie,

de asemenea, egale;

- este posibil ca, aplicând metoda hashCode() la doua obiecte diferite, să se obţină coduri

de dispersie egale, însa este preferabil ca această situaţie să se întâlnească cât mai rar cu

putinţă.

Metoda hashCode() este utilă atunci când obiectele trebuie plasate în tabele de dispersie,

cum sunt cele care fac parte din clasa java.util.Hashtable şi java.util.HashMap.

Metoda toString() este declarată sub forma

public String toString()

şi întoarce reprezentarea sub forma de şir de caractere (de obiect din clasa String) a

obiectului căruia i se aplică. Asa dar, expresia a.toString(), în care a este un obiect,

întoarce reprezentarea sub forma de şir a obiectului a. În cazul obiectelor aparţinând clasei

Object, aceasta metodă întoarce un şir de forma java.lang.Object@<cod_dispersie> în

care <cod_dispersie> este codul de dispersie al obiectului respectiv, exprimat în

hexazecimal. În clasele derivate aceasta metodă este redefinită, astfel încât să se obţină o

reprezentare sub formă de şir a conţinutului obiectului respectiv.

Metoda clone() este declarată sub forma:

protected Object clone()

şi are rolul de a întoarce o clonă a obiectului căruia i se aplică, deci întoarce un obiect identic

cu acesta, dar situat la o altă adresă de memorie şi deci având o altă referinţă. În consecinţă,

după ce se execută instrucţiunea

b=a.clone();

în care a şi b sunt referinţe la obiecte, expresia a==b va avea valoarea false, deoarece

valorile variabilelor referinţă a şi b sunt diferite, în timp ce expresia a.equals(b) va

întoarce în mod normal valoarea true, deoarece cele două obiecte comparate au conţinuturi

identice.

Page 107: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

107

În schimb, după ce se execută instrucţiunea

b=a;

variabila b va avea ca valoare aceeaşi referinţă ca şi variabila a, adica a şi b vor indica

acelaşi obiect din memorie, astfel că expresia a==b întoarce valoarea true.

Întrucât metoda clone() este protejată (are nivelul de acces protected) ea nu poate fi

utilizată decât pentru obiectele din clasa Object. În schimb, ea poate fi redefinită la clasele

descendente, astfel încât sa devină publică.

Metodele prezentate aici (exceptând, desigur, metoda clone()) sunt testate în programul din

fişierul TestObject.java.

Metoda getClass() este declarată sub forma

public final Class getClass()

O expresie de forma a.getClass(), în care a este o referinta la un obiect, întoarce ca

valoare un obiect din clasa Class, care conţine informaţii despre clasa obiectului indicat de

variabila a. Deocamdată vom folosi această metoda numai pentru a afişa numele clasei, ca în

ultimele trei instrucţiuni ale programului din fişierul TestObject.java.

Clase de excepţii

În pachetul java.lang există şi numeroase clase de excepţii. Instanţele acestor clase sunt

creeate de către maşina virtuală Java atunci când se produce o excepţie, adică o situaţie

anormală în procesul de calcul. Toate aceste clase sunt descrise în documentatia Java API.

Vom menţiona aici numai două dintre ele, celelalte urmând să fie indicate la descrierea

claselor care conţin metode care pot genera excepţii.

În limbajul Java se face distincţie între excepţie şi eroare. Se consideră ca excepţiile sunt

incidente care pot fi captate prin mecanismul try .. catch şi pot fi deci tratate prin

program, în timp ce erorile sunt incidente grave, care - de regulă - nu pot fi tratate prin

program ci produc oprirea executării acestuia.

Clasa Exception

Această clasă este rădăcina ierarhiei claselor de excepţii. În consecinţă, atunci când dorim ca

in clauza catch sa fie captată orice fel de excepţie, scriem această clauză sub forma

catch(Exception e) { instructiuni_de_tratare_a_exceptiei e }

unde e este numele simbolic (identificatorul) dat excepţiei captate. Clasa are doi constructori:

public Exception()

creează un obiect din clasa Exception (deci "o excepţie") care nu conţine nici un mesaj.

Page 108: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

108

public Exception(String s)

creează un obiect din clasa Exception, care conţine un mesaj sub forma şirului s. Prin acest

mesaj se indică, de regulă, ce incident a condus la generarea excepţiei respective.

Vom arăta ulterior cum putem folosi aceşti constructori pentru a genera propriile noastre

excepţii.

Clasa Exception nu are propriile ei metode.Totuşi, atât pentru clasa Exception, cât şi pentru

toate celelalte clase de excepţii se pot folosi metodele superclasei Object. În particular, se

poate folosi pentru instanţele oricărei clase de excepţii metoda toString(), care pune

instanţa respectivă sub forma unui şir de caractere. Acest şir conţine, de regulă, un mesaj

privind felul exceptiei respective.

Clasa ArithmeticException

Instanţele acestei clase sunt generate de maşina virtuală Java atunci când are loc o situaţie

anormală la efectuarea unei operaţii aritmetice, cum ar fi, de exemplu, împărţirea la zero a

unui număr întreg. Instanţa respectivă conţine un mesaj care indică ce fel de excepţie s-a

produs.

Exemple de utilizare a claselor de excepţii s-au dat deja în capitolul "Tratarea excepţiilor".

Clasele String şi StringBuffer

Pentru şirurile de caractere, pe care le vom numi în viitor simplu "şiruri", există în pachetul

java.lang doua clase: String şi StringBuffer. Obiectele clasei String conţin şirurile

propriu-zise, iar cele ale clasei StringBuffer conţin zone tampon pentru şiruri.

Clasa String

Toate şirurile în limbajul Java, inclusiv literalii-şir, de exemplu "ABCdef123", sunt obiecte

ale clasei String. Obiectele din această clasă sunt constante, adică şirurile conţinute în ele

nu pot fi modificate. Dacă este necesar să se folosească şiruri modificabile, se recurge la clasa

StringBuffer.

În afară de metodele pe care le oferă, clasa String conţine şi suportul necesar pentru

operatorul de concatenare'+'. Prin concatenarea a două şiruri se obţine un nou şir, rezultat

din punerea celor două unul în continuarea celuilalt. De exemplu, expresia

"ABC"+"defg" are ca valoare şirul "ABCdefg".

Dăm aici o parte din constructorii şi metodele mai frecvent utilizate ale clasei String. O

prezentare mai amplă există în indexul de clase. Vă recomandăm să o consultaţi, pentru a

cunoaşte ce constructori şi metode conţine. Amintim că prezentarea completă se găseşte în

documentaţia Java API de pe Internet.

Page 109: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

109

Construirea unui obiect din clasa şir se face cel mai frecvent cu constructorul String(String

s). Acest constructor creeaza în memorie o copie a şirului s primit ca argument.

Dintre metodele foarte utile menţionăm aici următoarele:

int compareTo(String anotherString)

Compara acest şir cu şirul anotherString primit ca argument. Dacă cele două şiruri

sunt identice, întoarce 0 (zero). Dacă acest şir îl precede pe anotherString întoarce o

valoare negativă, iar daca îi succede lui anotherString întoarce o valoare pozitivă.

Compararea şirurilor se face în ordine lexicografică (în ordinea în care ar fi plasate într-un

dicţionar).

int compareToIgnoreCase(String str)

Compară lexicografic acest şir cu sirul str primit ca argument, ignorând deosebirea

dintre literele majuscule şi cele minuscule.

int length() Întoarce lungimea acestui şir (numărul de caractere conţinute).

String trim() Întoarce un nou şir, obţinut din acest şir prin eliminarea spaţiilor de la început şi de la

sfârşit.

int indexOf(int ch)

Întoarce indicele la care se găseşte în şir prima apariţie a caracterului ch. Dacă acest

caracter nu există în şir, întoarce -1.

int indexOf(int ch, int fromIndex)

Similar cu metoda precedentă, dar căutarea in sir începe de la poziţia fromIndex.

int indexOf(String str)

Întoarce indicele poziţiei de la care în acest şir apare prima dată subşirul str.

int indexOf(String str, int fromIndex)

Similar cu metoda precedentă, dar căutarea în acest şir începe de la poziţia fromIndex.

int lastIndexOf(int ch)

Întoarce indicele ultimei poziţii pe care apare caracterul ch în acest şir.

int lastIndexOf(int ch, int fromIndex) Întoarce indicele ultimei poziţii pe care se găseşte caracterul ch, dacă se face căutarea

înapoi, începând de la poziţia fromIndex.

int lastIndexOf(String str)

Întoarce indicele ultimei apariţii în acest şir a subşirului str.

int lastIndexOf(String str, int fromIndex) Similar cu metoda precedentă, dar căutarea înapoi se face de la poziţia fromIndex.

String substring(int beginIndex)

Page 110: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

110

Întoarce un nou şir, care conţine caracterele acestui şir, începând de la poziţia

beginIndex, până la sfârşit.

String substring(int beginIndex, int endIndex)

Întoarce subşirul situat între pozitiile beginIndex şi endIndex-1 inclusiv.

Exemplu

În programul din fişierul TestStr.java se exemplifică utilizarea clasei String.

Clasa StringBuffer

Obiectele clasei StringBuffer implementează şiruri care pot fi modificate atât ca lungime,

cât şi sub aspectul caracterelor pe care le conţin. În engleză buffer înseamnă zonă tampon.

Aşa dar, un "StringBuffer" este modelul unei zone tampon de memorie, în care se pot adăuga

noi caractere la şirul existent şi în care se pot înlocui total sau parţial caracterele existente cu

altele.

Principalele operaţii asupra unei astfel de "zone tampon" sunt metodele append() şi

insert(), prin care se poate adăuga un şir nou în coada celui existent, sau se înserează acest

şir nou în interiorul celui existent.

Un obiect StringBuffer (zona tampon pentru caractere) se caracterizează prin lungime şi

capacitate. Lungimea este numărul de caractere conţinut efectiv, iar capacitatea este

dimensiunea la un moment dat a tabloului de caractere conţinut în obiectul respectiv. Ambele

se pot modifica în timp, ca urmare a aplicării unor metode.

Construirea unui nou StringBuffer se poate face cu unul din constructorii StringBuffer(),

StringBuffer(int length) sau StringBuffer(String str). Primul dintre ei

construieşte o zonă tampon de caractere, având o capacitate iniţială predefinită; al doilea una

de capacitate iniţială length, iar al treilea construieşte o zonă tampon care conţine iniţial

şirul str.

Cele mai importante metode sunt:

public int length() - întoarce lungimea curentă a şirului (numărul de caractere

existente efectiv în buffer);

public int capacity() - întoarce capacitatea curentă a buffer-ului;

public StringBuffer append(char c) - adaugă la buffer caracterul c;

public StringBuffer insert(int offset, char c) - însereaza în buffer

caracterul c pe pozitia offset;

public String toString() - întoarce un şir care are acelaşi conţinut cu cel din acest

StringBuffer.

Există, de fapt, o familie de metode append(), care diferă între ele prin tipul argumentului: append(boolean b), append(byte b), append(short s), append(int i),

append(long l), append(char c), append(float f), append(double

d),append(String str), append(Object obj).

Page 111: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

111

Toate aceste metode adaugă în coada zonei tampon argumentul lor, convertit într-un şir.

Există, de asemenea, o familie de metode insert(), care diferă prin tipul celui de al doilea

argument: insert(int offset, boolean b), insert(int offset, byte b), insert(int

offset, short s), insert(int offset, int i), insert, int offset, long l),

insert(int offset, char c), insert(int offset, float f), insert(int offset,

double d), insert(int offset, String str), insert(int offset, Object obj).

Toate aceste metode înserează în zona tampon, pe poziţia offset, cel de al doilea argument

convertit în şir.

O prezentare mai amplă a clasei StringBuffer este dată în indexul de clase, iar descrierea

completă se găseşte pe Internet în documentaţia Java API.

Exemplu

În fişierul TestStrB.java este dat un exmplu de program în care se testează clasa StringBuffer.

Clasa Class

O caracteristică importantă a limbajului şi platformei Java este că clasele şi interfeţele

utilizate în program sunt prezente în memoria maşinii virtuale Java în timpul executării

programului, sub forma de instanţe ale clasei Class. În consecinţă, se pot obţine în timpul

executării unui program informaţii despre clasele cărora le aparţin obiectele din memorie.

Clasa Class nu are un constructor public. În schimb, putem obţine un obiect din această clasă

folosind metoda getClass() a clasei Object. Există şi instanţe ale clasei Class pentru

tipurile de date primitive. Acestea sunt conţinute sub forma de câmpuri statice în clasele

acoperitoare ale tipurilor primitive respective.

Iată câteva dintre metodele clasei Class:

public String getName() - întoarce numele calificat al unei entităţi (clase, interfeţe,

tip primitiv) reprezentată de un obiect din clasa Class;

public boolean isAssignableFrom(Class cls) - întoarce true dacă clasa căreia i

se aplică metoda este o superclasă a clasei cls, primită ca argument;

public boolean isInterface() - întoarce true dacă metoda este aplicată unei

instanţe a clasei Class care reprezintă o interfaţă;

public boolean isPrimitive() - întoarce true dacă metoda este aplicată unui obiect

din clasa Class care reprezintă un tip de date primitiv;

public Class getSuperclass() - întoarce o instanţă a clasei Class care reprezintă

superclasa obiectului căruia i se aplică această metodă.

În fişierul TestClass.java este dat un program de testare a obţinerii obiectelor Class şi a

aplicării unora dintre metodele acestora.

Descrierea completă a clasei Class este dată în documentaţia Java API.

Page 112: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

112

Clasele acoperitoare de tip

În pachetul java.lang, pentru fiecare din tipurile de date primitive există o clasă acoperitoare

de tip (engleză: Type Wrapper). Aceste clase pun la dispoziţia programatorului atât variabile

finale (constante), cât şi metode necesare pentru a lucra cu tipul de date respectiv. Clasele

acoperitoare de tip formează ierarhia din figura 1.

- Figura 1 -

În aceasta figură, clasele acoperitoare de tip sunt reprezentate cu negru. Clasa Number este o

clasa abstractă, din care sunt derivate toate clasele acoperitoare pentru tipuri de date

numerice. Fiecare din celelalte clase acoperă un anumit tip de date primitiv. Clasa Character

acoperă tipul char, iar clasa Integer acoperă tipul int. Toate celelalte clase acopera tipul

primitiv al carui nume îl poartă. Spre deosebire de numele tipurilor primitive, care sunt scrise

cu litere mici, numele claselor acoperitoare încep (ca la orice alte clase) cu majuscule.

Toate clasele acoperitoare sunt clase finale, deci din ele nu mai pot fi derivate alte clase.

Fiecare instanţă a unei clase acoperitoare conţine un câmp de date nestatic în care se

pastrează o valoare aparţinând tipului primitiv de date corespunzator clasei respective. De

exemplu, un obiect din clasa Boolean conţine un câmp de tip boolean care, la rândul lui,

conţine valoarea logică true sau false. În mod similar, un obiect din clasa Double conţine

un câmp de tip double în care există un număr în virgulă mobilă în dublă precizie.

În afară de câmpul de date nestatic, fiecare clasă acoperitoare conţine mai multe câmpuri de

date statice finale, în care se păstrează diferite constante (variabile finale) specifice tipului de

date corespunzător.

Unele dintre metode sunt prezente în toate clasele acoperitoare, altele sunt specifice fiecărei

clase sau unui grup de astfel de clase. Prezentăm aici succint principalele metode prezente în

toate clasele:

public boolean equals(Object obj) - este o redefinire a metodei equals()din

clasa Object ; compară obiectul propriu cu obiectul obj primit ca argument şi întoarce true

dacă acestea sunt identice, sau false în caz contrar;

public String toString() - este o redefinire a metodei toString() din clasa

Object ; întoarce valoarea primitivă conţinută în obiectul respectiv, convertită într-un şir de

Page 113: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

113

caractere, reprezentând forma externă a valorii respective;

public int hashCode() - este o redefinire a metodei hashCode() din clasa Object;

intoarce codul de dispersie al obiectului propriu.

Clasele acoperitoare oferă, de asemenea, metode prin care se pot converti datele din tipurile

respective din forma externă (de şiruri de caractere) în cea interna şi invers.

Clasa Boolean

Clasa Boolean acoperă tipul primitiv boolean. Clasa are doi constructori publici:

Boolean(boolean value) şi Boolean(String s). Primul primeşte ca argument o

expresie cu valoare de tip boolean, iar al doilea primeşte un şir de caractere, care conţine

forma externă a unei valori de tip boolean.

În afara de metodele equals(), toString() şi hashCode(), care au fost deja

menţionate, clasa Boolean mai oferă următoarele metode specifice:

public boolean booleanValue() - întoarce valoarea primitivă de tip boolean

conţinută în obiectul propriu;

public static Boolean valueOf(String s) - întoarce o noua instanţă a clasei

boolean, corespunzătoare şirului s: dacă şirul s este "True" întoarce TRUE, altfel întoarce

FALSE. Are, practic, acelaşi efect cu aplicarea operatorului new cu constructorul

Boolean(String s).

Clasa Boolean moşteneşte, de asemenea, metodele clasei Object.

În programul din fişierul TestBoolean.java este testată clasa Boolean.

Clase acoperitoare pentru tipurile de date numerice

Clasa abstractă Number

Este superclasa tuturor tipurilor de date numerice, cu excepţia tipului char.Contine

următoarele metode:

public abstract byte byteValue() - întoarce numărul convertit la tipul primitiv

byte, ceeace poate avea ca efect rotunjirea sau trunchierea;

public abstract short shortValue() - întoarce numărul convertit la tipul primitiv

short, ceeace poate avea ca efect rotunjirea sau trunchierea;

public abstract int intValue() - întoarce numărul convertit în tipul primitiv int,

ceeace poate avea ca efect rotunjirea;

public abstract long longValue() - întoarce numărul convertit la tipul primitiv

long, ceeace poate avea ca efect rotunjirea;

public abstract float floatValue() - întoarce numarul convertit la tipul primitiv

float;

public abstract double doubleValue() - întoarce numarul convertit la tipul

primitiv double.

Page 114: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

114

Remarcăm că aceste metode se aplica tuturor claselor acoperitoare pentru numere, realizând

conversia numărului conţinut într-o instanţă a unei clase acoperitoare numerice către tipul

primitiv dorit de utilizator.

Clasele Byte, Short, Integer şi Long

Instanţele acestor clase acoperă valori din tipurile primitive byte, short, int şi long.

Între aceste clase există o mare asemănare în ce priveăte câmpurile de date statice şi

metodele. Vom prezenta aci principalele facilităţi oferite de clasa Integer. Pentru o

prezentare completă a acestei clase, cât şi pentru informaţii privind celelalte clase,

recomandăm consultarea documentaţiei originale Java API. Menţionăm că majoritatea

metodelor statice din clasa Integer nu există în celelalte clase acoperitoare pentru tipuri de

date intregi, dar nici nu este necesar, deoarece se pot folosi aceste metode şi cu argumente

efective de tip byte sau short.

Clasa Integer este clasa acoperitoare pentru tipul primitiv int. Clasa conţine următoarele

câmpuri de date statice:

public static final int MAX_VALUE - conţine valoarea maximă pentru tipul de

date int, adică valoarea 2147483647;

public static final int MIN_VALUE - conţine valoarea minimă pentru tipul de date

int, adică -2147483648;

public static final Class TYPE - conţine un obiect din clasa Class cu informaţii

despre tipul primitiv int.

Clasa are doi constructori:

public Integer(int value) - construieşte instanţa clasei Integer care conţine

valoarea primitivă value;

public Integer(String s) - converteşte şirul s, primit ca argument, într-un număr de

tip int şi construieşte obiectul Integer care conţine acest număr; dacă şirul s nu reprezintă

forma externă a unui număr întreg, se obţine excepţia NumberFormatException. Remarcăm

deci că se face analiza sintactică a şirului s pentru a se verifica dacă acesta este cu adevărat un

număr întreg.

Clasa oferă un numeroase metode, atât de instanţă, cât şi statice, care sunt utile când se

lucrează cu numere întregi. Dintre acestea menţionăm:

a/ metodele equals(), toString() şi hashCode() existente în toate clasele

acoperitoare;

b/ metodele byteValue(), shortValue(), intValue(), longValue(),

floatValue()si doubleValue() existente în toate subclasele clasei Number;

c/ metode statice, utile în diverse operaţii cu numere întregi:

public static int parseInt(String s) - face analiza sintactică a şirului s,

considerat ca forma externă a unui număr întreg în sistemul de numeraţie zecimal, şi întoarce

valoarea de tip int corespunzatoare; dacă şirul s nu are forma corectă a unui număr întreg, se

Page 115: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

115

obţine excepţia NumberFormatException;

public static int parseInt(String s, int radix) - acţioneaza asemănător cu

metoda precedentă, cu deosebirea că se consideră că şirul s este un număr în sistemul de

numeraţie cu baza radix;

public static String toBinaryString(int i) - întoarce numărul întreg i convertit

într-un şir care îl reprezintă în sistemul de numeraţie binar;

public static String toHexString(int i) - întoarce numărul întreg i convertit

într-un şir hexazecimal;

public static String toOctalString(int i) - întoarce numărul întreg i convertit

într-un şir în sistemul de numeraţie octal;

public static String toString(int i) - întoarce numărul întreg i convertit într-un

şir în sistemul de numeraţie zecimal (se deosebeşte de metoda toString(), moştenită de la

clasa Object, prin faptul ca nu este o metodă a instanţei, ci una statică);

public static String toString(int i, int radix) - întoarce un şir care conţine

numărul intreg i convertit în sistemul de numeraţie cu baza radix;

public static Integer valueOf(String s) - acţionează asemănător cu metoda

parseInt(String s), dar întoarce un obiect din clasa Integer;

public static Integer valueOf(String s, int radix) - similara cu metoda

precedentă, dar se consideră că şirul s este un număr întreg în baza de numeraţie radix;

public static Integer decode(String s) - analizează şirul s şi îl decodifică; dacă

acesta respectă unul din formatele admise pentru numere întregi, adică este forma externă a

unui număr întreg în unul din sistemele zecimal, hexazecimal (incepe cu 0x) sau octal (incepe

cu 0), atunci il converteşte în valoare internă de tip int şi întoarce obiectul de clasa Integer

care contine aceasta valoare; altfel, întoarce excepţia NumberFormatException.

d/ metode ale instanţei (în plus, faţă de cele menţionate la punctele a/ şi b/):

public int compareTo(Integer anotherInteger) - compară propriul obiect din

clasa Integer cu obiectul anotherInteger primit ca argument. Dacă ele sunt egale, întoarce

zero; daca întregul propriu este mai mic decât argumentul, întoarce o valoare negativă, iar

dacă este mai mare întoarce o valoare pozitivă;

public int compareTo(Object obj) - dacă obiectul-argument obj este tot un

Integer, atunci această metodă acţionează la fel cu cea precedentă; altfel, se obţine excepţia

ClassCastException.

Exemplu:

Programul din fişierul TestInt.java testează utilizarea unora dintre metodele clasei Integer.

Executând acest program se poate constata că analiza sintactică a şirului primit ca argument

decurge în acelaşi mod la metodele parseInt(String), valueOf(String) şi la constructorul

Integer(String). Se acceptă numai şirurile care reprezintă cu adevărat numere întregi cuprinse

în domeniul de valori al tipului int. Se admite ca numărul să fie precedat de semnul - (minus),

dar nu de semnul +. Se observă, de asemenea, că la conversia de la Integer către byte sau

short este posibil să se piardă cifrele cele mai semnificative prin trunchiere.

Clasele Float şi Double

Instanţele claselor Float şi Double "acoperă" valori ale tipurilor primitive corespunzătoare,

respectiv float şi double. Ele oferă, de asemenea, metode de conversie a şirurilor în

Page 116: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

116

numere reale (cu analiza sintactică corespunzătoare) şi a numerelor reale în şiruri. Vom

prezenta aici clasa Double, dar aceleaşi facilităţi există şi în clasa Float.

Câmpuri de date statice:

Clasa Double (şi similar clasa Float) oferă următoarele câmpuri de date statice:

public static final double MAX_VALUE - cea mai mare valoare pozitivă de tip

double;

public static final double MIN_VALUE - cea mai mică valoare pozitivă de tip

double;

public static final double NaN - valoarea NaN (Not a Number) pentru tipul

double;

public static final double POSITIVE_INFINITY - valoarea Infinitypentru tipul

double;

public static final double NEGATIVE_INFINITY - valoarea -Infinity pentru

tipul double;

public static final Class TYPE - un obiect din clasa Class cu informaţii despre

tipul primitiv double.

Constructori:

Clasa Double are doi constructori:

Double(double value) - construieşte o instanţă a clasei Double care conţine valoarea

primitivă value;

Double(String s) - construieşte o instanţă a clasei Double care conţine valoarea

primitivă de tip double a cărei formă externă este şirul s primit ca argument; dacă acest şir

nu este corect sintactic, se obtine excepţia NumberFormatException.

Metode:

Clasa Double oferă numeroase metode utile în lucrul cu date de tip double, dintre care

mentionăm:

a/ metodele equals(), toString() si hashCode() existente în toate clasele

acoperitoare;

b/ metodele byteValue(), shortValue(), intValue(), longValue(),

floatValue() si doubleValue() existente în toate subclasele clasei Number;

c/ metode statice, utile în diverse operaţii cu numere reale:

public static double parseDouble(String s) - analizează sintactic şirul s primit

ca argument şi - dacă este corect - întoarce valoarea primitivă double corespunzatoare; altfel

generează excepţia NumberFormatException;

public static String toString(double d) - converteşte în sir numărul primitiv

primit ca argument;

public static Double valueOf(String s) - acţioneaza asemănător cu metodă

parseDouble(String), dar intoarce un obiect din clasa Double;

Page 117: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

117

public static long doubleToLongBits(double value) - întoarce o valoare de tip

long care este reprezentarea pe 64 biţi, conform standardului IEEE 754, a numărului de tip

double primit ca argument;

public static double longBitsToDouble(long bits) - întoarce o valoare de tip

double, a cărei reprezentare ca long (întreg pe 64 biţi) conform standardului IEEE 754 este

cea primită ca argument;

public static boolean isInfinite(double v) - întoarce true dacă argumentul v

este infinit;

public static boolean isNaN(double v) - întoarce true dacă argumentul v este

NaN;

d/ metode ale instanţei (în plus, faţă de cele menţionate la punctele a/ şi b/):

public int compareTo(Double anotherDouble) - compară propriul obiect din clasa

Double cu obiectul anotherDouble primit ca argument; dacă ele sunt egale, întoarce zero;

dacă numărul propriu este mai mic decât argumentul întoarce o valoare negativă, iar dacă este

mai mare întoarce o valoare pozitivă;

public int compareTo(Object obj) - dacă obiectul-argument obj este tot un

Double, atunci această metodă acţionează la fel cu cea precedentă; altfel, se obţine excepţia

ClassCastException.

public boolean isInfinite() - întoarce true dacă valoarea conţinută în obiectul

propriu este infinită;

public boolean isNaN() - întoarce true dacă valoarea conţinuta în obiectul propriu

este NaN;

Exemplu:

Programul din fişierul TestDouble.java testează principalele metode ale clasei Double.

Remarcăm că, în acest caz, a fost considerat corect şi un sir care reprezintă un număr real

precedat de semnul +. Pentru reprezentarea formatului intern al numărului s-a folosit metoda

doubleToLongBits(), combinată cu metodele toBynaryString() şi toHexString()din

clasa Long.

Clasa Character

Fiecare obiect al clasei Character "acoperă" o valoare primitiva de tip char. În plus, clasa

Character oferă metode utile în lucrul cu caractere. Reamintim că, în limbajul Java,

caracterele sunt reprezentate pe 16 biţi, în sistemul Unicode.

Câmpuri statice:

Clasa Character conţine numeroase câmpuri de date statice, prezentate în documentaţia Java

API. Cele mai multe dintre ele sunt coduri numerice ale diferitelor categorii de caractere

(litere majuscule, litere minuscule, cifre zecimale, simboluri matematice etc), folosite în

metodele care verifică dacă un anumit caracter corespunde categoriei respective. Printre ele

există însă şi câmpul public static final Class TYPE

care conţine un obiect din clasa Class cu informaţii despre tipul primitiv char.

Page 118: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

118

Constructori:

Clasa Character are un singur constructor

public Character(char value) - construieşte un obiect al clasei Character care

conţine caracterul primit ca argument.

Metode statice:

Clasa Character oferă numeroase metode statice utile în lucrul cu caractere, dintre care

menţionăm:

public static boolean isDigit(char ch) - întoarce true dacă argumentul ch

este cifră;

public static boolean isLetter(char ch) - întoarce true dacă argumentul este

literă;

public static boolean isLowerCase(char ch) - întoarce true dacă ch este literă

mică;

public static boolean isUpperCase(char ch) - întoarce true daca ch este literă

majusculă;

public static boolean isLetterOrDigit(char ch) - verifică dacă ch este literă

sau cifră;

public static boolean isWhitespace(char ch) - verifică dacă ch este un spaţiu

liber sau un alt caracter asimilabil acestuia, de exemplu caracter de trecere la linie nouă, de

întoarcere a carului, de tabulare orizontală sau verticală, de separare a fişierelor sau

înregistrărilor etc (vezi documentaţia).

public static boolean isSpaceChar(char ch) - verifică dacă ch este caracterul

spaţiu;

public static char toLowerCase(char ch) - întoarce caracterul ch convertit în

litera mică; dacă nu este literă, îl lasă neschimbat;

public static char toUpperCase(char ch) - întoarce caracterul ch convertit în

litera majusculă; dacă nu este literă, îl lasă neschimbat;

public static int getNumericValue(char ch) - întoarce valoarea numerica

Unicode a caracterului ch ca un întreg nenegativ;

public static int digit(char ch, int radix) - întoarce valoarea numerică a

caracterului ch considerat ca cifra a sistemului de numeraţie cu baza radix; dacă în sistemul

respectiv nu există o astfel de cifră, întoarce -1;

public static char forDigit(int digit, int radix) - întoarce caracterul prin

care este reprezentată cifra de valoare digit în sistemul de numeraţie cu baza radix; daca în

sistemul respectiv nu exista o asemenea cifră, întoarce caracterul nul ('\u0000');

Metode nestatice:

În afara de metodele generale equals(), toString() şi hashCode(), clasa Character

oferă, de asemenea, următoarele metode:

public char charValue() - întoarce caracterul primitiv conţinut în obiectul propriu

din clasa Character;

public int compareTo(Character anotherCharacter) - compară caracterul din

propriul obiect cu cel primit ca argument şi întoarce valoare nulă dacă sunt egale, negativă

daca primul este mai mic decât al doilea şi valoare pozitivă dacă este mai mare;

Page 119: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

119

public int compareTo(Object obj) - dacă argumentul obj este un obiect din clasa

Character, actionează similar cu metoda precedentă; altfel generează excepţia

ClassCastException;

Exemplu:

În fişierul TestChar.java este dat un program de testare a metodelor oferite de clasa

Character.

Clasa Void

Clasa Void nu este instanţiabilă (nu poate avea obiecte) şi "acoperă" tipul primitiv void. Ea

conţine numai un singur câmp static public static final Class TYPE care conţine un obiect din clasa Class cu informaţii despre tipul primitiv void.

Clasa Math

Clasa Math este foarte utilă în calcule ştiinţifice şi inginereşti. Ea conţine un număr mare de

funcţii matematice (funcţii trigonometrice, logaritmice, exponenţiale etc) şi două constante

matematice: numărul e şi numărul pi.

Constantele sunt reprezentate sub forma următoarelor două câmpuri statice finale ale clasei:

public static final double E - numărul e (baza logaritmilor naturali);

public static final double PI - numarul pi (raportul dintre perimetrul şi

diametrul cercului).

Aceste constante se folosesc în expresiile din program sub forma Math.E şi Math.PI.

Funcţiile matematice se prezintă în această clasă sub forma de metode statice. Menţionăm

aici numai câteva din aceste funcţii, cu precizarea că arcele (unghiurile) se exprimă în radiani:

public static double sin(double a) - sinusul trigonometric sin a.

public static double cos(double a) - cosinusul trigonometric cos a.

public static double tan(double a) - tangenta trigonometrică tg a.

public static double asin(double a) - arcsin a.

public static double acos(double a) - arccos a.

public static double atan(double a) - arctg a.

public static double exp(double a) - funcţia exponentială ea.

public static double log(double a) - logaritmul natural ln a.

public static double sqrt(double a) - radacina patrată a lui a.

Lista completă a funcţiilor este dată în indexul claselor.

Page 120: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

120

Utilizarea în expresiile din program a acestor funcţii se face, ca la toate metodele statice,

calificând numele funcţiei prin numele clasei. De exemplu, sin(2*u+3) se va scrie

Math.sin(2*u+3).

Clasa System

Clasa System conţine câmpuri şi metode utile pentru realizarea legăturii dintre aplicaţie şi

sistemul de execuţie Java (cel care implementează maşina virtuală Java). Această clasă nu

poate fi instanţiată.

Câmpuri statice:

Clasa System are trei câmpuri statice care reprezintă unităţile standard de intrare/ieşire ale

sistemului:

public static final InputStream in - este intrarea standard a sistemului. De

regulă, aceasta este tastatura, dar poate fi şi alt dispozitiv indicat de utilizator.

public static final PrintStream out - este ieşirea standard a sistemului. De

regulă este unitatea de afişare standard (ecranul) dar poate fi şi alt dispozitiv indicat de

utilizator. Afişarea datelor pe ecran se face, de regulă folosind metoda

System.out.println(sir) sau System.out.print(sir).

public static final PrintStream err - unitatea standard de ieşire pentru erori. De

regulă este aceeaşi ca pentru obiectul out, dar poate fi şi alt dispozitiv indicat de utilizator.

Metode: Dăm aici numai metodele care sunt utilizate de noi în acest curs. Descrierea completă a

tuturor metodelor clasei System poate fi gasită în documentaţia Java API.

public static void exit(int status)- provoaca incheierea executării

programului. Argumentul acestei metode este un cod de stare care se transmite maşinii

virtuale Java. Prin convenţie, 0 înseamnă încheiere normală a executării aplicaţiei, iar un cod

diferit de zero indică încheiere anormală (cu cod de eroare). Metoda se foloseşte în program

sub forma instructiunii System.exit(stare);.

public static void setIn(InputStream in)- schimbă unitatea de intrare standard.

Noua unitate de intrare standard va fi obiectul din clasa InputStream dat prin argumentul in.

public static void setOut(PrintStream out)- schimba unitatea de ieşire standard

pentru date. Noua unitate de ieşire va fi obiectul din clasa OutputStream dat prin argumentul

out.

public static void setErr(PrintStream err)- schimbă unitatea de ieşire standard

pentru erori. Noua unitate de iesire va fi obiectul din clasa OutputStream dat prin argumentul

err.

public static long currentTimeMillis()- întoarce timpul curent în milisecunde.

Acesta este un număr de tip long, care exprimă timpul în milisecunde măsurat cu începere de

Page 121: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

121

la data de 1 ianuarie 1970 ora 0.

Tablouri

Conceptul de tablou

Tabloul (în engleză Array) este o structură de date de acelasi tip, numite componente ale

tabloului, care sunt specificate prin indici. În programare, tabloul poate fi privit ca o colecţie

indexată de variabile de acelaşi tip.

Exemple tipice de tablouri sunt vectorul şi matricea din matematică. Un vector este o colecţie

indexată de componente cu un singur indice. De exemplu x=[x0, x1, ... , xn-1] este un

vector cu n componente. Componentele au acelaşi "nume" cu vectorul, dar se disting prin

indici, care specifică poziţia componentei respective în cadrul tabloului. În limbajul Java, la

fel ca în limbajele C/C++, indicii încep de la 0. Întrucât componentele vectorului sunt dispuse

pe o singură direcţie în spaţiu, spunem că este un tablou unidimensional. La nivel conceptual,

se consideră că tabloul ocupă o zonă compactă de memorie, în care componentele sale sunt

aşezate în ordinea crescătoare a indicilor, din care cauză mai este numit şi masiv.

Matricea este un tablou bidimensional. Componentele matricei sunt ordonate pe două direcţii

în spaţiu, iar poziţia fiecărei componente este indicată prin doi indici: primul specifică linia,

iar al doilea coloana în care se găseşte componenta respectivă. Iată un exemplu de matrice cu

4 linii şi 5 coloane:

a00 a01 a02 a03 a04

a10 a11 a12 a13 a14

a20 a21 a22 a23 a24

a30 a31 a32 a33 a34

În acest exemplu, numele matricei, ca şi numele fiecărui element al ei, este a. Poziţia

componentei în cadrul matricei este specificată prin cei doi indici. Conform convenţiei de

indexare din limbajul Java, indicii incep de la zero.

Pot exista şi tablouri cu mai mult de două dimensiuni. Astfel, un tablou tridimensional poate

fi imaginat ca un volum (o carte), având mai multe pagini, fiecare pagină fiind un tablou

bidimensional (o matrice). În acest caz, primul indice specifică linia, al doilea - coloana, iar al

treilea - pagina în care se găseşte componenta respectivă. În mod similar, un tablou cu patru

dimensiuni poate fi privit ca o serie de volume; fiecare componentă, în acest caz, are patru

indici, cel de al patrulea fiind numărul volumului în cadrul seriei. Putem, desigur, continua

raţionamentul şi pentru tablouri cu mai mulţi indici.

Page 122: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

122

Tablourile în limbajul Java

În limbajul Java, tablourile (engl.: Arrays) sunt considerate obiecte care aparţin unor clase

descendente din clasa Object. În consecinţă, variabilele care au ca valori tablouri sunt

variabile referinţă, iar alocarea tablourilor în memorie se face dinamic, prin operatorul new,

la fel ca în cazul celorlalte obiecte. Mai mult, unor variabile referinţă la Object li se pot da

ca valori referinţe la tablouri, deoarece clasa Object este superclasa oricărei alte clase, deci

şi a oricarui tip de tablou.

Tipul tabloului coincide cu tipul componentelor sale. Componentele pot aparţine unor tipuri

de date primitive, sau unor clase.

Tablouri cu un singur indice (unidimensionale)

Aceste tablouri corespund conceptului matematic de vector. Nu le vom numi totuşi astfel,

pentru a nu face confuzie cu obiectele clasei Vector din pachetul java.util.

Tabloul unidimensional este constituit dintr-un ansamblu de componente indexate (cu un

singur indice), căruia i se asociază şi o variabila de tip int numita length, care reprezintă

lungimea tabloului (numărul de componente). Indicii elementelor de tablou sunt cuprinşi în

intervalul [0, length-1]. Utilizarea unui indice situat în afara acestui interval generează o

excepţie.

Întrucât tablourile sunt obiecte, pentru indicarea lor în program se folosesc variabile

referinţă.

Declararea şi iniţializarea tablourilor cu un singur indice

Variabilele referinţă la tablouri cu un singur indice pot fi declarate în două moduri:

a/ într-o declaraţie de variabile se pune simbolul [] (o pereche de paranteze drepte) după

numele variabilei referinţă la tablou. Ca exemplu, să considerăm declaraţiile următoare: int a, b, c[], d, e[]; String s1, ts1[], s2;

În aceste declaraţii, a, b, şi d sunt variabile simple de tip double, deci ele pot primi valori

simple de acest tip, iar s1 şi s2 sunt variabile referinţă la obiecte din clasa String (la şiruri

de caractere). În schimb, c[] şi e[] sunt variabile referinţă la tablouri de tip int (tablouri

la care toate componentele sunt de tip int), iar ts1[] este o variabilă referinţă la un tablou

cu componente din clasa String.

b/ Parantezele se pun după numele tipului de date sau al clasei, în care caz toate variabilele

din declaraţia respectiva sunt considerate drept referinţe la tablouri. De exemplu, în

declaraţiile int[] i, j; long [] k, m; float []u, v; String[] ww;

variabilele i, j, k, m, u, v, ww sunt referinţe la tablouri cu componente de tipuri

corespunzătoare fiecarei declaraţii. Remarcăm că nu are importanţă dacă parantezele sunt

puse imediat după numele tipului sau clasei (fară spaţiu liber) sau între acestea există unul

sau mai multe spaţii.

Iniţializarea tablourilor unidimensionale se poate face, de asemenea, în două moduri:

a/ indicând valorile componentelor tabloului, separate prin virgule şi cuprinse între

acolade, ca în exemplele următoare:

Page 123: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

123

int a=27, b=-15, c[]={-3,72,-21},d=-5,e[]={231,-98}; String s1="un sir", ts1[]={"sirul 0", "sirul 1", "sirul 2"}, s2="alt

sir"; float[] u={-1.24076f, 0.03254f, 27.16f}, v={2.7698E-12f, -3.876e7f};

Remarcăm că în ultima declaraţie nu s-au mai pus paranteze după numele variabilelor,

deoarece ele apar după numele tipului.

b/ folosind operatorul new, urmat de numele tipului sau al clasei, însoţit de dimensiunea

tabloului (numărul de elemente din tablou) scrisă între paranteze drepte, ca în exemplele

următoare: double aa[]=new double[3]; String str[]=new String[2];

În primul caz, se alocă în memorie spaţiu pentru un tablou cu 3 componente de tip double,

iar variabilei aa i se dă ca valoare referinţa la acest tablou. În al doilea caz, se alocă în

memorie un tablou de variabile referinţă la obiecte din clasa String, iar variabilei str i se

dă ca valoare referinţa la acest tablou.

Iniţializarea unei variabile referinţă la tablou cu componente aparţinând unei anumite clase se

poate face atât cu tablouri din clasa respectivă, cât şi din clase descendente ale acesteia. De

exemplu, în declaraţia Object tab1[]=new Object[2], tab2[]=new String[3],

tab3[]={"aaa","bbb","ccc"};

variabila tab1 este initializata cu o referinţă la un tablou de componente din clasa Object,

în timp ce variabilele tab2 şi tab3 sunt iniţializate cu referinţe la tablouri de şiruri, clasa

String(ca orice alta clasă) fiind descendentă a clasei Object.

În programul din fişierul InitTab1.java se testează declaraţiile şi iniţializările de mai sus şi

altele similare şi se afişează valorile componentelor tablourilor iniţializate. Se observă că, în

cazul folosirii operatorului new pentru alocarea de tablouri, componentele acestora se

iniţializează la valorile lor implicite: 0 pentru date numerice şi null pentru obiecte.

Atribuirea de valori variabilelor referinţă la tablou

Unei variabile referinţă la tablou i se poate atribui ca valoare o referinţă la un tablou de

acelasi tip, sau dintr-o clasă descendentă a acestuia. Această referinţă poate fi obţinută prin

operatorul new (în care caz se alocă în memorie un nou tablou), fie printr-o expresie care are

ca valoare o referinţă la un tablou de tip corespunzator deja existent în memorie. În

programul din fişierul Tab1.java se dau astfel de exemple.

Page 124: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

124

Utilizarea tablourilor

Componentele tablourilor pot fi utilizate ca orice variabile simple. Referinţa la o componentă

de tablou se face prin numele tabloului, insoţit de indicele componentei pus între paranteze

drepte. De exemplu, u[3] este componenta de indice 3 a tabloului u, iar aa[i] este

componenta de indice i a tabloului aa. Indicele poate fi orice expresie de tip întreg, cu

condiţia ca valoarea acesteia să nu iasa din cadrul domeniului de indici admis pentru tabloul

respectiv.

Un exemplu de utilizare a variabilelor indexate s-a dat deja în programul din fişierul

InitTab1.java , când au fost afişate valorile componentelor tablourilor. Alte exemple se dau în

programul din fişierul Tab1.java. Este instructiv să urmărim în figurile următoare cum

evoluează datele din memorie în timpul executării acestui program.

- Fig. 1 -

În figura 1 sunt reprezentate datele din memorie după executarea instrucţiunilor double a[]={3.276, -5.83, 12.8}, b[]; String ts1[]={"aa","bb"}, ts2[]; b=a; ts2=ts1;

Prin prima declaraţie s-au creat în memorie variabilele referinţă la tablouri de tip double a[]

şi b[], s-a creat, de asemenea, un tablou cu trei componente de tip double şi s-a dat ca

valoare variabilei a referinţa la acest tablou. Prin a doua declaratie, s-au creat variabilele

referinţă la tablouri de tip String ts1[] si ts2[] şi un tablou de tip String cu două

componente, iar variabilei ts1 i s-a dat ca valoare o referinţă la acest tablou. Prin

instrucţiunea b=a i s-a atribuit variabilei b[] aceeaşi valoare-referinţă ca cea din a[], iar

prin ultima instrucţiune s-a atribuit variabilei ts2[] acceaşi valoare-referinţă ca a lui ts1[].

Remarcăm deosebirea importantă dintre tabloul de tip double şi cel de tip String. Primul

dintre ele are drept componente date de tip primitiv. În consecinţă, "celulele" tabloului conţin

chiar valorile de tip double ale componentelor corespunzătoare. În schimb, cel de al doilea

este un tablou de obiecte din clasa String, deci componentele lui sunt, de fapt, variabile

referinţă la obiecte String, iar aceste obiecte sunt reprezentate în memorie separat. În

ambele cazuri, componentele tabloului sunt tratate ca nişte variabile al căror tip este

corespunzător declaraţiei. Ştim însă că variabilele de tipuri primitive au ca valori chiar date

primitive, în timp ce pentru obiecte se folosesc variabile referinţă.

În figura 2 este reprezentată situaţia creeată după ce s-au executat instrucţiunile de atribuire

Page 125: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

125

b[0]=-12.7; b[1]=283.6;

- Fig. 2 -

Întrucât variabilele referinţă a[] şi b[] indică acelaşi tablou, este normal ca valorile

componentelor a[i] sunt şi acum aceleaşi cu ale componentelor b[i], ceeace se constată şi din

afişarea prin program a datelor respective.

În figura 3 este reprezentată situaţia creată după executarea instrucţiunii b=new double[4].

- Fig. 3 -

Prin operatorul new s-a alocat în memorie un nou tablou cu 4 componente double, iar lui

b[] i s-a dat ca valoare referinţa la acest tablou. Imediat după iniţializare componentele

noului tablou au valoarea zero, deoarece aceasta este valoarea implicită pentru tipurile de

date numerice. În schimb, valoarea variabilei referinţă a[] a ramas aceeaşi, pe care a avut-o

anterior. Acestor componente putem sa le dăm acum valori prin program.

În acelaşi program se testează şi situaţia în care se încearcă accesul la tabloul b[] cu un

indice care iese din domeniul admis [0 ... b.lenght-1]. Se constată că se produce

excepţia java.lang.ArrayIndexOutOfBoundsException.

Conversii de tip pentru referinţe la tablouri

Tablourile cu componente aparţinând unor tipuri de date primitive sunt considerate că sunt

obiecte ale unor clase cu numele tip[]

De exemplu, un tablou cu componente double (deci care a fost declarat ca double[]),

aparţine clasei double[], care este descendentă a clasei Object (nu a clasei Object[],

care conţine tablourile de obiecte). În mod asemanător, un tablou cu componente dintr-o

anumită Clasa este considerat ca aparţinând clasei Clasa[] care, de asemenea, este

Page 126: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

126

descendenta a clasei Object. De exemplu, daca s-au făcut declaraţiile int a[]={54, 23, -17}, b[]; String str1[]={"abc","def"}, str2[], str3[]; Object ob1, ob3, tob1[];

sunt permise fara conversie explicită atribuiri de forma: tob1=str1; ob1=a; ob3=str1;

În primul caz, tob1 este o referinţă la un tablou cu componente din clasa Object, iar

str1 este referinţă la un tablou cu componente din clasa String, care este descendenta a

clasei Object. În următoarele două cazuri, ob1 si ob3 sunt referinţe la Object, iar tablourile

a[] şi str1[] aparţin claselor int[] şi, respectiv, String[], care sunt şi ele descendente ale

clasei Object.

În schimb, atribuirile următoare necesită conversie explicită (prin cast), deoarece se fac de la

superclasă la clasă: str2=(String[])tob1; b=(int[])ob1; str3=(String[])ob3;

Pentru a face referinţă la componente din tablourile referite de variabilele ob1 sau ob3 este

necesară, de asemenea, conversie explicită, deoarece ob1 siob3 nu au fost declarate ca

tablouri. Se va scrie deci: ((int[])ob1).length, ((int[])ob1)[k],

((String[])ob3).length, ((String[])ob3)[j].

Nu trebuie, insa, facuta conversie explicită în cazul componentelor tabloului referit prin

tob1[], deoarece vsrisbila tob1 a fost declarată ca referinţă la tablou, iar clasa Object este

superclasă a clasei String. Este, deci permisă referinţa tob1[k].

Exemplele de mai sus, si altele, sunt testate în programul din fişierul ConvTip1.java. În

acelaşi program, se testează şi numele claselor-tablouri întoarse de metoda getName() a

clasei Class. Explicarea codificărilor respective este dată în documentaţia java API, la

descrierea acestei metode.

Tablouri cu doi sau mai mulţi indici

(multidimensionale)

Tabloul cu N indici este considerat în limbajul Java drept un tablou de referinţe la tablouri cu

N-1 indici. Vom exemplifica aceasta pentru cazul tabloului cu doi indici (bidimensional) şi

vom extinde apoi conceptul la tablouri cu mai mult de două dimensiuni.

Tablouri cu doi indici

Tablourile bidimensionale din limbajul Java sunt o generalizare a conceptului de matrice, În

matematică, toate liniile unei matrice au acelaşi număr de componente, în timp ce în Java

Page 127: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

127

numărul de componente poate fi diferit de la o linie la alta (deci liniile "matricei" pot avea

lungimi diferite). Tabloul cu doi indici este privit ca un tablou ale cărui componente sunt

referinţe la tablouri cu câte un singur indice. Putem, deci, să ne imaginăm un "tablou

coloană" care conţine în fiecare componentă o referinţă către un "tablou linie". Fiecare din

aceste "tablouri linie" are propria sa variabilă length şi deci propria sa lungime. În schimb,

variabila length a "tabloului coloană" reprezintă lungimea acestui tablou, adică numărul de

linii. "Tipul tabloului" este, de fapt, tipul componentelor "liniilor" acestuia.

Page 128: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

128

Declararea şi iniţializarea tablourilor cu doi indici

Tabloul bidimensional poate fi declarat în mod asemănător celui unidimensional, dar punând

după numele variabilei două perechi de paranteze drepte. Rămâne valabilă şi regula că, dacă

perechea de paranteze drepte se pune după numele tipului sau al clasei, ea se aplică tuturor

variabilelor din declaraţia respectivă. Fie, de exemplu, următoarele declaraţii: double u, v[], w[][]; int[] a, b[]; char[][] h1, h2; String ts[][]; Conform acestor declaraţii:

- u este o variabilă simplă de tip double;

- v este un tablou unidimensional, iar w un tablou bidimensional, ambele cu componente

de tip double;

- a este un tablou unidimensional, iar b un tablou bidimensional, ambele cu componente

de tip int;

- h1 şi h2 sunt tablouri bidimensionale cu componente de tip char;

- ts este un tablou bidimensional, având drept componente referinţe la String.

Iniţializarea tablourilor bidimensionale se face, de asemenea, asemănător cu a celor

unidimensionale, având însă şi unele trăsături specifice. Iată cum putem introduce în

declaraţiile de mai sus iniţializări folosind forma cu acolade sau operatorul new: double u=5.3127, v[]={1,25, -3.12, 2,6}, w[][]={{2.31,-4.15},{0.35,-12.6,-573.2},{10.9}}; int[] a={3,2,7}, b[]={{43,28,92,-6},{},{-1,17,29}}; char[][] h1={{'a','*'},{'+','$'}}, h2=new char[2][3], h3=new char[4][]; String ts[][]={{"abc","defg"},{"AB","CD","EF","GH"}};

Remarcam ca, la forma de iniţializare cu acolade, tabloul bidimensional este tratat ca un

tablou (acoladele exterioare) care are drept componente alte tablouri (acoladele interioare).

Acestea din urmă reprezintă "liniile" tabloului bidimensional şi pot avea lungimi diferite,

unele din ele putând avea chiar lungimea zero (în acest caz acoladele respective nu conţin

nimic), ca în cazul liniei a doua a tabloului b.

La folosirea operatorului new există urmatoarele posibilităţi de iniţializare:

a/ se indică atât numărul de linii, cât şi numărul de coloane, de ex. new int[7][4]; în

acest caz, se iniţializează o matrice, în care toate liniile au acelaşi număr de componente. În

exemplul nostru, matricea are 7 linii şi 4 coloane, toate cele 7x4=28 componente fiind

iniţializate cu valorile implicite ale tipului respectiv (în cazul de faţă zero);

b/ se indică numai numărul de linii, de exemplu: new int[7][]. În acest caz se

iniţializeaza, de fapt, numai "vectorul coloană" care contine referinţe (deocamdata nule) către

linii care, deocamdată, nu există, urmând sa fie atribuite ulterior.

În figura 1 este reprezentată matricea w dupa iniţializare.

Page 129: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

129

- Figura 1 -

Se observă că variabila w conţine numai o referinţă către un tablou cu trei componente care,

la rândul lor, conţin referinţe către trei tablouri care conţin cele trei linii ale tabloului

bidimensional indicat de variabila w. In aceasta situaţie, cele trei "linii" ale tabloului

bidimensional pot să fie situate în locuri diferite din memorie, fără a mai forma o zonă

compactă. În schimb, fiecare "linie" este, în acest caz, un tablou compact, ale cărui

componente sunt valori primitive de tip double.

Să considerăm acum tabloul String ts[][]={{"abc","defg"},{"AB","CD","EF","GH"}}; Acest tablou este reprezentat in figura 2.

- Figura 2 -

Componentele tabloului sunt aici, de fapt, referinţe la obiecte din clasa String. La nivel

conceptual însă, noi privim acest tablou ca şi când ar avea drept componente însăşi aceste

obiecte. Pentru a le distinge mai uşor, în figura 2 obiectele din clasa String au fost trasate cu

culoare albastră.

Iniţializările de mai sus sunt testate în programul din fişierul Tab2.java.

Operaţii cu tablouri bidimensionale

Numărul de componente

Ştim că fiecărui tablou unidimensional îi este asociată o variabilă length, care are ca valoare

"lungimea" tabloului, adică numărul de componente ale acestuia. Ce reprezintă variabila

length în cazul unui tablou bidimensional? Sa privim din nou figura 1. Întrucat w.length

este numărul de componente din tabloul unidimensional referit de variabila w, înseamnă că el

este egal cu numărul de linii al tabloului bidimensional. În schimb, numărul de componente

Page 130: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

130

din linia referită de componenta w[i] a tabloului w este dat de variabila w[i].length. De

exemplu, numărul de componente din linia de indice 0 este w[0].length. În programul din

fisierul Tab2.java se determină astfel numărul de linii şi numărul de componente din fiecare

linie pentru fiecare din tablourile bidimensionale iniţializate în programul respectiv.

Referirea la componentele tabloului

Pentru a indica o anumită componentă a unui tablou bidimensional, se foloseşte variabila

referinţă la tablou, însoţită de indicii componentei respective. De exemplu, w[i][j] este

componenta situata în linia i şi coloana j a tabloului referit de variabila w. Indicii pot fi literali

întregi, variabile sau expresii de tip întreg, de exemplu w[2*k-1][j-3]. Referirile la

componentele de tablou au fost folosite, de exemplu, în programul din fişierul Tab2.java la

afişarea tablourilor. În acelaşi program se poate urmări şi cum sunt afişate componentele

tablourilor, în situaţia când liniile acestor tablouri au lungimi diferite.

Componentele de tablou astfel referite pot fi folosite în orice expresii din program, la fel ca

variabilele simple. Iată doua exemple de instrucţiuni, în care se folosesc componentele

tabloului bidimensional w: t=2*w[1][0]*Math.cos(3.5*w[1][1]-0.23); w[j][k+1]=2*w[j-1][k]-w[j][k-1]; Bineînţeles, trebuie avut grijă ca indicii să nu iasă din domeniile admise pentru fiecare din ei

deoarece, în caz contrar, vor apare excepţii la executarea programului.

Referirea la tablou şi la liniile tabloului

Variabila referinţă la tablou, neînsoţită de indici, este o referire la întregul tablou. Dacă

folosim însa variabila referinţă la un tablou bidimensional însoţită de un singur indice,

aceasta este o referinţă la o linie a tabloului respectiv. De exemplu, în cazul tabloului

bidimensional w, w[i] este o referinţă la linia i a tabloului indicat de variabila w. Variabilele

w şi w[i] pot fi folosite şi ele în diferite expresii. Astfel s-a procedat mai sus, în expresiile

w.length si w[i].length. Să urmărim acum un exemplu, în care se ilustrează folosirea

acestor referinţe în instrucţiuni de atribuire.

Să urmarim programul din fişierul Tab2a.java, făcând şi schemele tablourilor din memorie in

diferite etape de execuţie a acestuia. Se fac mai intâi următoarele declaraţii cu iniţializări de

tablouri: int a[][]={{-5,12,52},{8,-4},{},{105}}, b[]={31,-3,17,24}

Rezultatul aceztor initializari este reprezentat in figura 3.

Page 131: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

131

- Figura 3-

Se fac apoi urmatoarele atribuiri: a[0][2]=2*b[1]-a[1][1]; a[2]=new int[3]; a[2][0]=b[3]; a[2][2]=a[3][0]; a[3]=b; b=a[1]; b[1]=88;

Situatia creată în memorie după această secvenţă de atribuiri este reprezentată in figura 4.

- Figura 4 -

În aceasta figură, pentru a fi urmărite mai uşor, modificarile au fost făcute cu culoare roşie. A

fost creat, prin operatorul new, un nou tablou cu trei elemente, care a devenit noua linie a[2].

S-au atribuit valori pentru a[2][0] si a[2][2], iar componenta a[2][1] a rămas la valoarea

implicită 0 cu care a fost iniţializată. Fosta linie a[3], formată numai dintr-o singură

componentă cu valoarea 105, a rămas fără referinţă şi va fi eliminată de către colectorul de

reziduuri de memorie. Noua linie a[3] este acum fostul tablou b, iar tabloul unidimensional

indicat de variabila referinta b este acum acelasi cu linia a[1]. Toate aceste modificari pot fi

verificate executând programul din fişierul Tab2a.java .

Conversii de tip la tablouri cu doi indici

Regulile aplicate pentru conversii la tablourile bidimensionale sunt aceleaşi cu cele pentru

tablouri unidimensionale. Să urmărim următorul exemplu, care este testat în programul din

fişierul Tab2b.java. Fie declaraţiile: Object ob1, ob2, tob2[][]; int ti1[][]={{0,1},{10,11,12,13},{20,21,22}},ti2[][]; String ts[][]={{"aa","ab"},{"ba","bb","bc"},{"ca","cb"}},ts1[][];

Page 132: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

132

Cu aceste declaraţii, următoarele atribuiri ob1=ti1; ob2=ts;

sunt corecte, deoarece clasele ti1[][] şi ts[][] sunt descendente ale clasei Object. În

schimb, atribuirile ti2=ob1; ts1=ob2;

nu sunt corecte, deoarece se fac în sens "descendent". Ştiind, totusi, că variabilele ob1 şi

ob2 conţin efectiv referinţe către obiecte din clasele int[][] şi respectiv String[][],

putem face conversii explicite sub forma: ti2=(int[][])ob1; ts1=(String[][])ob2;

Numărul de linii al tabloului indicat de variabila referinţă ob1 este

((int[][])ob1).length, iar numarul de componente din linia i a aceluiasi tablou este

((int[][])ob1)[i].length. De asemenea, componenta situată în linia i şi coloana j

este((int[][])ob1)[i][j].

Să încercăm acum atribuirea ti2=(int[][])ob2; În acest caz, compilatorul nu poate

sesiza eroarea, deoarece în momentul compilării nu are informaţie despre adevarata clasa

căreia îi aparţine obiectul indicat de variabila ob2. În schimb, la execuţie se constată că

obiectul indicat de ob2 aparţine clasei String[][], în timp ce variabila ti1 apartine

clasei int[][], aşa că se va genera excepţia ClassCastException.

Tablouri cu mai mulţi indici

Modul de tratare al tablourilor cu doi indici poate fi extins şi la tablouri cu mai mulţi indici

(tablouri multidimensionale). Se are în vedere ca tabloul cu N indici conţine referinţe la

tablouri cu N-1 indici. De exemplu un tablou cu trei indici (tridimensional) poate fi

considerat că conţine mai multe "pagini", iar fiecare "pagină" este un tablou cu doi indici

(bidimensional). În acest caz, primii doi indici specifica linia şi, respeectiv, coloana, iar al

treilea indice specifica "pagina" în care se găseşte o anumită componentă. Un tablou cu patru

indici poate fi asemănat cu un set de "volume", în care fiecare "volum" este un tablou cu trei

indici, iar cel de al patrulea indice specifica numarul "volumului" din acest set. Putem sa ne

imaginam astfel si semnificaţii ale unor tablouri cu mai mult de patru indici. Totuşi, în

practică, cele mai frecvent folosite tablouri au cel mult trei indici.

Tablouri eterogene

Prin definiţie, componentele unui tablou trebuie să fie toate de acelaşi tip. În programarea

orientată pe obiecte, această restricţie a fost "relaxată", în sensul că un tablou poate avea drept

componente şi obiecte aparţinând claselor descendente din clasa de bază. Faptul că clasa

Object este superclasă a oricărei alte clase din limbajul Java, inclusiv a claselor de tablouri,

permite să se creeze tablouri eterogene, adică tablouri cu componente care aparţin unor clase

foarte diferite. Acestea pot fi structuri complicate de date, realizate pornind de la structura de

"tablou de obiecte". Să consideram, de exemplu, structura de date din figura 5.

Page 133: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

133

- Figura 5 -

În programul din fişierul TabEterogen.javase construieşte această structură de date eterogenă

şi se afişează unele dintre componentele ei.

Utilizarea parametrilor din linia de

comandă

A venit timpul să ne ocupăm de argumentul args[] al metodei public static main(String args[])

Remarcăm ca argumentul formal args[] al acestei metode este un tablou unidimensional,

ale cărui componente sunt din clasa String, deci sunt şiruri de caractere. La lansarea în

execuţie a aplicaţiei, acest argument preia drept componente de tablou parametrii din linia de

comandă prin care s-a făcut lansarea. Aceşti parametri pot fi, astfel, folosiţi în program după

necesităţi.

Exemplu: să considerăm următorul program din fişierul Parametri.java:

class Parametri { public static void main(String args[]) { if(args.length==0) System.out.println("Nu ati introdus parametri in linia de

comanda"); else { System.out.println("Aplicatia are urmatorii parametri:); for(int i=0; i<args.length; i++) System.out.println(args[i]); } } }

Lungimea tabloului args (numărul de componente) este, după cun ştim, args.length. În

acest program, dacă numărul de parametri este nul, se afişează mesajul "Nu aţi introdus

Page 134: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

134

parametri în linia de comandă". În caz contrar, se afişează toţi parametrii. Să considerăm că

lansarea acestui program s-a făcut prin următoarea linie de comandă:

java Parametri abcd EFG-HIjk 1376 7.3086 -15

La executarea programului se afişează:

Aplicatia are urmatorii parametri: abcd EFG-HIjk 1376 7.3086 -15

Constatăm, deci, că unicul separator între parametri este spaţiul liber, iar numerele sunt

preluate tot sub forma de şiruri de caractere. Putem rula acum acest program în mod repetat

cu diferite seturi de parametri, pentru a urmări cum se comportă. Putem constata de asemenea

că, dacă între doi parametri există mai multe spaţii libere succesive, ele sunt tratate ca şi un

singur spaţiu.

Întrebări

Nivel 1

1. Ce deosebire este între tipul referinţă şi tipurile primitive?

2. Unde sunt plasate în memorie obiectele?

3. Care sunt operaţiile permise asupra variabilelor-referinţă?

4. Cum se declara variabilele referinţă?

5. Ce este un câmp?

6. Ce deosebire este între câmpurile statice şi cele nestatice?

7. Ce este o metodă?

8. Ce deosebire este între metodele statice şi nestatice?

9. Cum este invocată o metoda statică?

10. Cum este invocată o metoda a instanţei?

11. Ce este un constructor?

12. Cum este invocat un constructor?

13. Ce este moştenirea?

14. Ce este o superclasă?

15. Ce legatură este între o clasă şi clasele derivate din aceasta?

16. Ce este polimorfismul?

17. Ce fel de moştenire este permisă în Java?

18. Care este rădăcina ierarhiei de clase în Java?

19. Ce este un pachet?

20. Ce este Java API?

21. Ce conţine pachetul java.lang?

Page 135: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

135

22. La ce serveste declaratia import si ce forma are?

23. Cum este importat pachetul java.lang?

24. Fie a şi b două obiecte. Ce deosebire este între a.equals(b) şi a==b?

25. Ce rol are metoda toString()?

26. Ce este o excepţie?

27. Ce este clasa Exception?

28. Care este clasa şirurilor de caractere?

29. Ce este concatenarea şirurilor şi prin ce operator se realizează?

30. Cum se compară două şiruri?

31. Ce este ordinea lexicografică?

32. Cum se determina lungimea unui şir?

33. La ce foloseşte metoda trim()?

34. Ce fel de obiecte aparţin clasei StringBuffer?

35. Ce deosebire este între lungimea şi capacitatea unui StringBuffer?

36. Care sunt principalele metode ale clasei StringBuffer?

37. Ce este o clasă acoperitoare de tip?

38. Poate fi instanţiată clasa Number? Justificaţi răspunsul.

39. Care sunt subclasele clasei Number?

40. Cum se poate determina cea mai mare valoare pe care poate să o aibă un număr de tip

int?

41. Cum se poate converti un numar întreg din forma externă în cea internă?

42. Ce câmpuri statice conţine clasa Double?

43. Cum se poate converti un număr în virgulă mobilă din forma externă în cea internă?

44. În ce cod sunt reprezentate caracterele în Java?

45. Ce este clasa Character?

46. Ce este clasa Math?

47. Cum se poate calcula sinusul trigonometric al unui număr?

48. Cum se poate calcula rădăcina patrată a unui număr?

49. Cum se poate calcula logaritmul natural al unui număr?

50. Scrieţi în limbajul Java expresia prin care se calculeaza rădăcina patrată din 2u2+e

u.

51. Ce câmpuri statice conţine clasa System?

52. Ce efect are metoda exit() din clasa System?

53. Ce este un tablou?

54. Cum se declară în Java un tablou unidimensional?

55. Ce semnificaţie are declaraţia int a, b[], c;? ce sunt a, b şi c?

56. Ce semnificatie are declaratia int[] a, b, c;? ce sunt a, b şi c?

57. Cum se iniţializează în Java un tablou unidimensional?

58. Prin ce instrucţiune se crează în Java un tablou cu 7 componente de tip double?

59. Cum se poate determina numărul de elemente dintr-un tablou unidimensional?

60. Cum sunt preluaţi parametrii din linia de comandă?

61. Cum pot fi determinate valorile numerice ale parametrilor din linia de comandă?

Nivel 2

1. Ce se găseşte în zona de memorie afectată unei variabile care aparţine unui tip

primitiv?

2. Ce se găseşte în zona de memorie afectată unei variabile referinţă?

Page 136: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

136

3. Ce deosebire există între o valoare primitivă şi un obiect?

4. Fie declaraţia Integer i1, i2; Ce sunt i1 şi i2?

5. Fie declaratia int i1, i2; Ce sunt i1 şi i2?

6. Care este efectul lateral al invocării unui constructor?

7. Care este valoarea intoarsă de aplicarea operatorului new?

8. Ce este o declaratie de import la cerere şi cum acţionează?

9. Ce este codul de dispersie şi prin ce metodă se obţine?

10. Ce rol are metoda clone()?

11. Ce deosebire este în Java între excepţie şi eroare?

12. Cum se determină poziţia unui caracter într-un şir?

13. Cum se determină poziţia unui subşir într-un şir?

14. Prin ce metode se poate face adăugarea de valori la un StringBuffer?

15. Prin ce metode se poate face înserarea de valori într-un StringBuffer?

16. Ce sunt instanţele clasei Class?

17. Cum se poate determina numele clasei căreia îi aparţine un obiect?

18. Cum se poate determina în timpul execuţiei programului superclasa clasei unui

obiect?

19. Prin ce metoda poate fi convertit din forma externă în cea internă un numar scris într-

o bază oarecare?

20. Prin ce metoda se poate obţine reprezentarea externă în sistemul binar a unui întreg?

21. Prin ce metodă poate fi obţinută forma externă hexazecimală a unui întreg?

22. Prin ce metodă poate fi obţinută forma externă octală a unui întreg?

23. Cum se poate verifica dacă un numar în virgula mobilă are valoarea infinită?

24. Cum se poate verifica dacă valoarea unei variabile în virgulă mobilă este un număr?

25. Cum se poate verifica dacă un caracter este literă?

26. Cum se poate verifica dacă un caracter este cifră?

27. Cum se poate face conversia literelor dintr-un şir din minuscule în majuscule?

28. Cum se poate face conversia literelor dintr-un şir din majuscule în minuscule?

29. Ce este clasa Void?

30. Scrieţi în limbajul Java expresia: e-|u|

sin(2u+3)cos4u+ln(|u|+1).

31. Prin ce metodă se poate determina timpul curent şi în ce unităţi se exprimă acesta?

32. Prin ce metoda se poate schimba dispozitivul de intrare standard?

33. Prin ce metoda se poate schimba dispozitivul de ieşire standard?

34. Cărui concept matematic îi corespunde conceptul de tablou unidimensional?

35. Cărui concept matematic îi corespunde conceptul de tablou bidimensional?

36. Ce legatură există între conceptul de clasă şi cel de obiect?

37. Cărei clase îi aparţine un tablou?

38. Cum se construieşte o matrice cu 7 linii şi 3 coloane cu elemente de tip double?

39. Este obligstoriu ca toate liniile unui tablou bidimensional să aibă aceeaşi lungime?

40. Cum se poate determina lungimea unei linii dintr-un tablou bidimensional?

41. Cum se poate modifica în timpul execuţiei lungimea unei linii dintr-un tablou

bidimensional?

Page 137: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

137

Declararea claselor

Declararea claselor;

Declararea câmpurilor. Câmpuri statice şi câmpuri ale

instanţei. Iniţializarea câmpurilor. Valori iniţiale implicite;

Declararea metodelor. Metode statice şi metode ale

instanţei;

Metode cu acelaşi nume; signatura metodei;

Transferul parametrilor către metode la invocarea

metodelor;

Metode care întorc o referinţă la un obiect construit în

corpul lor;

Metode care au ca argumente şi/sau ca valori întoarse

referinţe la tablouri;

Metode recursive; comparaţie între iteraţie şi recursie;

Metode care generează excepţii; instrucţiunea throw şi

clauza throws;

Clase publice

Un exemplu: clasa complex

Declararea clasei complex

Utilizarea clasei complex

Distrugerea obiectelor de către colectorul de reziduuri;

Metoda finalize

Întrebări.

Declararea claselor

Până în prezent, s-a arătat modul în care putem utiliza în programul nostru clase existente în

biblioteci (în pachetele de clase). Vom studia în continuare cum putem crea propriile noastre

clase.

Cea mai simplă formă a unei declaraţii de clasă este următoarea:

class NumeClasa { declaratii_de_membri }

Observăm că declaraţia începe cu cuvântul-cheie class, urmat de numele clasei şi de corpul

clasei, cuprins între acolade.

Page 138: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

138

Numele clasei este un identificator. Se obisnuieşte ca numele clasei sa înceapă cu literă

majusculă. Dacă numele este compus din mai multe cuvinte, fiecare din acestea începe cu

majusculă.

Corpul clasei cuprinde declaraţii de membri ai clasei respective. Acestea pot fi:

- declaraţii de câmpuri;

- declaraţii de constructori;

- declaraţii de metode.

Nu este obligatoriu ca într-o clasă să existe toate aceste categorii de declaraţii. Pot exista, de

exemplu, clase în care apar numai declaraţii de metode. În principiu, pot exista şi clase care

conţin numai câmpuri şi nu conţin metode, deşi astfel de situaţii apar foarte rar în practică.

Declararea câmpurilor

Declaraţiile de câmpuri servesc pentru a descrie structura de date specifică clasei respective.

Câmpurile se mai numesc şi variabile membre şi pot fi ale clasei sau ale instanţei (ale

obiectului). Se preferă denumirea de câmpuri, pentru a le deosebi de variabilele locale ale

metodelor.

Câmpurile instanţei se declară la fel ca variabilele locale ale metodelor, numai că declaraţia

respectivă nu apare în blocul unei metode, ci în corpul clasei. De exemplu: int m=172, n=2*m-4, r; Aceste câmpuri pot avea valori diferite pentru fiecare instanţă a clasei respective. În

consecinţă, câmpurile instanţei sunt plasate în zona de memorie rezervată instanţei

respective, astfel că ele sunt distincte pentru fiecare instanţă.

Câmpurile clasei se numesc şi câmpuri statice. Declararea unor astfel de câmpuri se face

asemănător cu cea a câmpurilor de instanţă, dar declaraţia are în faţă, în acest caz,

modificatorul static.De exemplu: static double u=3.65, v=2.87*u-3.1, x;

La iniţializarea câmpurilor de instanţă se pot folosi atât valori ale câmpurilor statice, cât şi ale

altor câmpuri de instanţă. În schimb, la iniţializarea câmpurilor statice se pot folosi numai

valori ale altor câmpuri statice.

Câmpurile statice (ale clasei) sunt plasate în memorie în zona rezervată clasei căreia îi aparţin

şi nu în cea rezervata instanţelor. În consecinţă, câmpurile clasei există în memorie într-un

singur exemplar, care este accesibil fiecărei instanţe.

Valorile iniţiale implicite ale câmpurilor: dacă nu sunt iniţializate explicit, câmpurile

statice şi cele nestatice primesc valori implicite astfel:

- câmpurile booleene primesc valoarea false;

- câmpurile numerice primesc valoarea 0 (chiar şi cele de tip char, care este tot tip

numeric!);

- câmpurile referinţa primesc valoarea null.

Remarcăm, deci, că există o deosebire între crearea câmpurilor (variabilelor membre) şi

crearea variabilelor locale. La crearea câmpurilor, acestora li se atribuie implicit o valoare

iniţială, în timp ce la crearea variabilelor locale acestora trebuie sa li se atribuie valori în mod

Page 139: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

139

explicit. Dacă o variabilă locală apare într-o expresie fără să aibă o valoare atribuită anterior,

compilatorul Java semnaleaza această situaţie ca o eroare de programare.

Exemplu de clasă care nu conţine constructori expliciţi sau metode:

Acest exemplu este dat în scop didactic, pentru a ilustra declararea, iniţializarea şi utilizarea

câmpurilor. Crearea unei clase fără metode nu corespunde principiului de baza al

programării orientate pe obiecte, conform căruia o clasă conţine atât date, cât şi metodele

prin care acestea sunt tratate. În consecinţă, declararea unor clase fără metode se evită în

practica programării orientate pe obiecte, chiar dacă o astfel de declaraţie este permisă. De

altfel, chiar daca declaraţia de clasă nu conţine constructori sau metode, ea are un

constructor implicit (fără parametri) şi moşteneşte metodele superclasei, în particular

metodele clasei Object.

În exemplul din fişierul TestClasa1.java se declară şi se utilizează o clasă care nu conţine

constructori si metode, ci numai câmpuri de date. O astfel de clasă este folosită, deci, ca o

structură din limbajele neorientate pe obiecte (cum este struct în C sau record în Pascal).

În acest fişier sunt declarate două clase: clasa Proba1, care este o simplă structură de date

fără metode proprii, şi clasa TestClasa1, care conţine metoda main si serveşte ca aplicaţie în

care se testează clasa Proba1.

Clasa Proba1 este declarată astfel:

/* Declararea clasei Proba1 Clasa contine numai campuri de date */

class Proba1 { static int m=9, n=m-3; int a=7, b=m*a+1, c, d; char c1='@', c2; String s1="un sir", s2=s1+" extins", s3; }

În această clasă, s-au definit câmpurile statice (ale clasei) m şi n şi câmpurile nestatice (de

instanţă) a, b, c şi d - toate de tip int. S-au declarat, de asemenea, câmpurile c1 şi c2 de

tip char şi câmpurile s1, s2 şi s3 care contin referinţe la instanţe ale clasei String. Unele

din aceste câmpuri sunt iniţializate, altele au valori iniţiale implicite. La iniţializarea

câmpului de instanţă b s-a folosit şi valoarea câmpului static a. Câmpurile c şi d sunt

iniţializate implicit cu valoarea 0.

Amintim o deosebire importantă între modul cum sunt plasate în memorie valorile primitive

şi obiectele (instanţele claselor): valorile primitive sunt plasate chiar în zona de memorie

rezervată variabilelor respective, în timp ce instanţele claselor sunt plasate în memoria

Page 140: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

140

dinamică. În consecinţă:

- valorile câmpurilor primitive statice m şi n sunt plasate în memorie o singură dată, în

spaţiul rezervat clasei Proba1;

- valorile câmpurilor primitive nestatice a, b, c, d, c1 şi c2 sunt plasate în câmpurile

corespunzătoare ale instanţelor clasei Proba1, deci acestea vor avea câte o valoare pentru

fiecare instanţă;

- în campurile s1, s2 si s3 (care, în cazul nostru, sunt tot nestatice, deci se plaseaza în

fiecare instanţă), ca valori se pun numai referinţe la instanţe ale clasei String. În consecinţă,

şirurile "un şir" şi "un şir extins" se vor creea în memoria dinamică, sub forma de

obiecte ale clasei String, iar în câmpurile s1 şi s2 ale fiecărei instanţe a clasei Proba1 se vor

pune numai referinţe la aceste şiruri. Câmpul s3 va fi iniţializat cu referinţa null.

Clasa Proba1 poate fi utilizată în alte clase Java la fel ca o structură de date (înregistrare)

"tradiţională" cum ar fi struct în limbajul C, sau record în limbajul Pascal. Un exemplu de

aplicaţie, în care se utilizează clasa Proba1, este clasa TestClasa1 din fişierul

TestClasa1.java, pe care o reproducem în continuare.

/* Programul in care se utilizeaza clasa Proba1 ca o structura obisnuita */

class TestClasa1 { public static void main(String args[]) { /* Se declara doua referinte catre instante ale clasei Proba1, iar prima din ele se si initializeaza */ Proba1 p1=new Proba1(), p2; /* Se mai creaza o instanta si se atribuie lui p2 */ p2=new Proba1(); /* Se afiseaza unele campuri ale instantelor p1 si p2; */ System.out.println("Campuri din p1: n="+p1.n+" m="+p1.m+" a="+ p1.a+" b="+p1.b+" c="+p1.c+" c1="+p1.c1+" c2="+p1.c2+ " (int)p1.c2="+(int)p1.c2); System.out.println("Campuri din p2: n="+p2.n+" m="+p2.m+" a="+ p2.a+" b="+p2.b+" c="+p2.c+"\n s1="+p2.s1+" s2="+p2.s2+ " s3="+p2.s3); /* Afisarea campurilor statice calificandu-le cu numele clasei */ System.out.println("Afisarea campurilor statice: m="+Proba1.m+ " n="+Proba1.n); /* Modificam atribuim p1.a si p2.a valori diferite, apoi reafisam toate campurile */ p1.a=12; p2.a=-9; System.out.println("Dupa modificarea valorilor campurilor a:"); System.out.println("Campuri din p1: n="+p1.n+" m="+p1.m+" a="+ p1.a+" b="+p1.b+" c="+p1.c); System.out.println("Campuri din p2: n="+p2.n+" m="+p2.m+" a="+ p2.a+" b="+p2.b+" c="+p2.c); /* Modificam campul static p1.m si reafisam p1.m, p2.m si Proba1.m */ p1.m=-12; System.out.println("Dupa modificare: p1.m="+p1.m+" p2.m="+p2.m+ " Proba1.m="+Proba1.m);

Page 141: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

141

/* Modificam campul static n folosind expresia Proba1.n si afisam */ Proba1.n=-25; System.out.println("Dupa modificare: p1.n="+p1.n+" p2.n="+p2.n+ " Proba1.n="+Proba1.n); /* Atribuim o valoare campului de instanta p1.c */ p1.c=1234; System.out.println("Dupa atribuire: p1.c="+p1.c+" p2.c="+p2.c); } }

La compilarea fişierului sursă TestClasa1.java, vor fi create două fişiere bytecode, câte unul

pentru fiecare clasă, numite în mod corespunzător Proba1.class şi TestClasa1.class. Pentru

executarea aplicaţiei se va folosi comanda java TestClasa1

Clasa Proba1 nu poate fi pusă în execuţie în acest mod, deoarece ea nu conţine metoda main.

Această clasă poate fi folosită numai în cadrul altei clase.

Rezultatele afişate pe ecran la executarea acestei aplicaţii sunt următoarele:

Campuri din p1: n=6 m=9 a=7 b=64 c=0 c1=@ c2= (int)p1.c2=0 Campuri din p2: n=6 m=9 a=7 b=64 c=0 s1=un sir s2=un sir extins s3=null Afisarea campurilor statice: m=9 n=6 Dupa modificarea valorilor campurilor a: Campuri din p1: n=6 m=9 a=12 b=64 c=0 Campuri din p2: n=6 m=9 a=-9 b=64 c=0 Dupa modificare: p1.m=-12 p2.m=-12 Proba1.m=-12 Dupa modificare: p1.n=-25 p2.n=-25 Proba1.n=-25 Dupa atribuire: p1.c=1234 p2.c=0

Urmărind aceste rezultate, putem constata că:

- câmpurile numerice neiniţializate explicit (inclusiv cele de tip char) sunt iniţializate

implicit la valoarea zero;

- valorile câmpurilor statice pot fi utilizate calificând numele câmpului respectiv, atât cu

numele unei instanţe (de exemplu, p1.m), cât şi calificandu-le cu numele clasei (de exemplu,

Proba1.m);

- valorile câmpurilor nestatice pot fi utilizate numai calificând numele câmpului respectiv cu

numele unei instanţe (de exemplu, p2.a);

- dacă se atribuie o nouă valoare unui câmp nestatic al unei instanţe, valorile câmpurilor cu

acelaşi nume ale celorlalte instanţe rămân nemodificate;

- dacă se atribuie o nouă valoare unui câmp static, această modificare se constată în toate

înstanţele, deoarece câmpul respectiv este unic (există numai în cadrul clasei).

Declararea metodelor

În programarea orientată pe obiecte, clasa conţine, în mod normal, nu numai câmpuri de date,

ci şi metodele prin care se tratează aceste câmpuri.

Page 142: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

142

Sub aspect conceptual, metoda este o funcţie sau o procedură, care foloseşte drept date atât

valorile argumentelor sale, cât şi câmpurile clasei căreia îi aparţine metoda respectivă.

În principiu, deosebirea dintre funcţie şi procedură este că funcţia "întoarce" o valoare, în

timp ce metoda nu întoarce o valoare, ci are numai efect lateral. O funcţie fără efect lateral

este realizarea în program a conceptului matematic de funcţie şi este folosită în expresiile de

calcul numai pentru valoarea ei. În limbajele C/C++ şi Java, procedurile se scriu, din punct

de vedere sintactic, la fel ca funcţiile, dar se consideră că ele intorc o valoare specială numită

void. Acesta este un artificiu pentru a indica faptul că o asemenea "funcţie" nu întoarce o

valoare.

În limbajele de programare tradiţionale, o funcţie (sau procedura) foloseşte ca date

argumentele sale şi variabilele globale. În limbajul Java nu există variabile globale şi nici

funcţii independente (care să nu fie metode ale unor clase). În schimb, fiecare metodă poate

folosi ca date atât argumentele saleşi variabilele locale, cât şi câmpurile clasei căreia îi

aparţine metoda respectivă.

Cea mai simplă formă sintactică a declaraţiei de metodă este următoarea: tip_valoare_intoarsa nume_metoda(declaratii_de_argumente) { corpul_metodei } în care:

tip_valoare_intoarsa - este tipul valorii primitive sau clasa valorii-referinţă întoarsă de

aceasta metodă;

nume_metoda- este un identificator care, în mod uzual, începe cu literă mică şi constituie

numele metodei;

declaratii_de argumente - este o listă de declaraţii de argument separate prin virgulă,

deci ea poate avea forma: declaratie_argument1, declaratie_argument2, ... declaratie_argumentN dar poate fi şi vidă. Lista declaraţiilor de argument este cuprinsă între paranteze rotunde.

Fiecare declaraţie de argument are forma tip_argument nume_argument

în care

tip_argument - este tipul sau clasa argumentului respectiv;

nume_argument- este un identificator care, în mod uzual, începe cu literă mică.

După această listă de argumente se deschide acolada unui bloc, care conţine corpul metodei,

adică secvenţa de instrucţiuni prin care se calculează valoarea funcţiei respective şi/sau -

dacă este cazul - se efectuează acţiunile care constituie efectele laterale ale acesteia.

Instrucţiunea return

Dacă funcţia întoarce o valoare (diferită de void), aceasta se indică prin instrucţiunea return expresie;

Efectul acestei instrucţiuni este următorul: se evalueaza expresia expresie şi se încheie

executarea funcţiei respective, întorcând valoarea astfel obţinută. În consecinţă, chiar dacă

după instrucţiunea return mai apar în corpul funcţiei respective şi alte instrucţiuni, acestea

nu vor mai fi executate.

Dacă metoda nu întoarce o valoare (întoarce void), folosirea instrucţiunii return nu este

absolut necesară, încheierea execuţiei făcându-se când se ajunge la acolada prin care se

Page 143: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

143

sfârseşte blocul funcţiei. Totuşi, dacă este necesar să se încheie în mod abrupt executarea

corpului funcţiei, se poate folosi instrucţiunea return fără expresie.

Metode statice

La declararea metodelor statice, în faţa tipului valorii întoarse se pune modificatorul static.

Metodele care conţin în declaraţie acest modificator se numesc statice sau ale clasei, spre

deosebire de metodele obişnuite care sunt ale instanţei. În corpul metodelor statice se pot

folosi numai câmpurile statice ale clasei respective şi se pot invoca numai alte metode statice

ale acestei clase.

Exemplu

În fişierul Cercuri.java se declară două clase pentru cercuri: clasa Cerc1, în care aria şi

circumferinţa se calculeaza prin metode ale instanţei, şi clasa Cerc2, care conţine metode

statice.

/* Declararea clasei Cerc1 cu metode ale instantei */

class Cerc1 { static final double PI=3.141592653589793; double r;

double arie() { return PI*r*r; }

double circumferinta() { return 2*PI*r; } }

/* Declararea clasei Cerc2 cu metode ale clasei (statice) */

class Cerc2 { static final double PI=3.141592653589793;

static double arie(double r) { return PI*r*r; }

static double circumferinta(double r) { return 2*PI*r; } }

Clasa Cerc1 conţine câmpul static final PI şi câmpul de instanţă r (raza cercului). Aceasta

întrucat numărul PI este o constantă valabilă pentru orice cerc, în timp ce raza cercului diferă

de la o instanţă la alta. Cele doua metode de instanţă, arie() şi circumferinta(), nu au

argumente, dar folosesc ca date câmpurile statice şi de instanţă declarate în clasa respectivă.

Page 144: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

144

Invocarea acestor metode se face calificându-le cu numele instanţei.

Clasa Cerc2 conţine, de asemenea, câmpul static final PI, dar nu conţine câmpul de instanţă r.

În schimb, metodele sale sunt statice şi primesc raza cercului ca argument. Invocarea acestor

metode se face calificându-le cu numele clasei.

În fişierul Cercuri.java există şi clasa Cercuri, în care se folosesc clasele Cerc1 şi Cerc2

declarate anterior. Iată această aplicaţie:

/* Aplicatia in care se utilizeaza cele doua clase de cercuri declarate mai sus */

class Cercuri { public static void main(String args[]) { double r1=1, r2=7.32; Cerc1 c1=new Cerc1(), c2=new Cerc1(); c1.r=r1; c2.r=r2; System.out.println("Folosind metodele de instanta din clasa Cerc1:"); System.out.println("Pentru cercul c1: aria="+c1.arie()+ " circumferinta="+c1.circumferinta()); System.out.println("Pentru cercul c2: aria="+c2.arie()+ " circumferinta="+c2.circumferinta()); System.out.println("Folosind metodele statice din clasa Cerc2:"); System.out.println("Pentru raza r1: aria="+Cerc2.arie(r1)+ " circumferinta="+Cerc2.circumferinta(r1)); System.out.println("Pentru raza r2: aria="+Cerc2.arie(r2)+ " circumferinta="+Cerc2.circumferinta(r2)); } }

Remarcăm că:

- instanţierea clasei Cerc1 s-a făcut folosind constructorul implicit Cerc1(); vom explica

aceasta la capitolul "declararea constructorilor";

- atribuirea de valoare razei r a instanţelor din clasa Cerc1 s-a făcut calificând numele

câmpului cu numele referinţei la instanţă, de exemplu în instrucţiunea de atribuire c1.r=r1;

- invocarea metodelor de instanţă s-a făcut calificând numele metodei cu referinţa la instanţa

respectivă: de exemplu c1.arie() calculează aria cercului cu referinţa c1 si, deci, va folosi

implicit raza c1.r1;

- invocarea metodelor statice ale clasei Cerc2 s-a făcut calificându-le cu numele clasei şi

transmiţându-le valoarea razei cercului ca argument, de exemplu Cerc2.arie(r1);

- la compilarea fişierului sursă Cercuri.java se obţin trei fişiere de bytecode: Cerc1.class,

Cerc2.class si Cercuri.class, corespunzătoare celor trei clase declarate.

Metode cu acelaşi nume. Signatura metodei

În aceeaşi clasă pot exista mai multe metode cu acelaşi nume, cu condiţia ca ele să difere prin

numărul şi/sau tipul argumentelor. Pentru a deosebi între ele astfel de metode, s-a introdus

conceptul de signatură.

Page 145: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

145

Signatura metodei constă din numele acesteia, însoţit de lista de argumente. În consecinţă,

două metode pot avea acelaşi nume, dacă diferă între ele prin signatură. Putem da exemple

din clasele existente în pachetele deja studiate.

Să considerăm, de exemplu, următoarele metode ale clasei String: int indexOf(int ch) int indexOf(int ch, int fromIndex) int indexOf(String str) int indexOf(String str, int fromIndex) Se observă imediat că prima şi a doua diferă prin numărul argumentelor, prima şi a treia

diferă prin tipul unicului argument, iar a doua şi a patra diferă prin tipul unuia din cele două

argumente.

Transferul de parametri către metode

La invocarea unei metode, este necesar să se transmită de la metoda care invocă la metoda

invocată parametrii (argumentele) acesteia. De exemplu, la executarea invocării

Math.sin(a), este necesar să se transmită către metoda sin argumentul acesteia, a.

În teoria şi practica programării se cunosc diferite moduri în car se poate face transmiterea

argumentelor către o funcţie sau procedură:

- transmitere prin valoare: de la programul apelant către funcţie (procedură) se transmit

valorile argumentelor;

- transmitere prin adresa: de la programul apelant către funcţie (procedură) se transmit

adresele la care se găsesc în memorie valorile argumentelor;

- transmitere prin nume: de la programul apelant către funcţie (procedură) se transmit

numele argumentelor;

- transmitere prin referinţă: de la programul apelant la funcţie (procedură) se transmit

referinţe către argumente.

În limbajul Java, transmiterea parametrilor (argumentelor) metodelor se face prin valoare.

Aceasta înseamnă că:

- dacă argumentul aparţine unui tip de date primitiv, se transmite chiar valoarea primitivă a

argumentului respectiv;

- dacă argumentul aparţine unui tip-referinţă (este instanţă a unei clase), se transmite - de

fapt - o referinţă către un obiect din clasa respectiva sau dintr-o clasa derivată din aceasta.

Exemplu

Să considerăm metoda int indexOf(String str, int fromIndex) din clasa String.

Primul argument al acestei metode este o referinţă la un obiect din clasa String, iar al doilea

argument este o valoare primitivă de tip int. În limbajul Java, cei doi parametri str si

fromIndex sunt consideraţi variabile locale ale metodei indexOf, iar transmiterea

parametrilor este echivalentă cu operaţia de atribuire. În consecinţă, dacă se invocă această

metodă sub forma indexOf("abc", 3), variabilei-referinţă str i se atribuie ca valoare

referinţa la sirul "abc" (şi nu insuşi şirul "abc", care rămâne la locul lui în memoria

Page 146: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

146

dinamică), în timp ce variabilei fromIndex de tip int i se atribuie valoarea primitivă 3.

Să considerăm acum că într-un program există instrucţiunile: int k=7, j; String s1="un exemplu de sir", s2="exem"; j=s1.indexOf(s2,k);

Evaluarea metodei indexOf va decurge astfel: se transmit de la programul apelant către

metoda indexOf valorile argumentelor s2 si k. Numai că s2 este o variabila-referinţă, deci

valoarea ei este referinţa la şirul "exem" şi nu însuşi acest şir. În schimb, valoarea variabilei

k este chiar valoarea primitivă 7. În consecinţă, în şirul indicat de s1, se va căuta subşirul a

cărui referinţă este s2, începand căutarea de la poziţia de indice 7.

În teoria programării, argumentele (parametrii) care apar în declaraţia unei metode (funcţii,

proceduri) se numesc parametri formali, iar valorile prin care se substituie aceşti parametri

formali la invocarea metodei respective se numesc parametri efectivi. Astfel, în exemplul de

mai sus, str şi fromIndex sunt parametri formali ai metodei indexOf, in timp ce "abc", 3,

valoarea lui s2, şi valoarea lui k sunt parametri efectivi.

Consecinţa faptului că parametrii metodelor se transmit prin valoare este următoarea:

chiar dacă în corpul unei metode se atribuie unui argument formal al acesteia o nouă valoare,

această atribuire nu modifică valoarea argumentului efectiv corespunzător din programul

apelant. Daca însă, în cazul unui argument-referinţă, nu se modifica referinţa însăşi, ci

valorile câmpurilor obiectului indicat de către aceasta, modificarea respectivă se va

transmite şi la programul apelant, constituind efectul lateral al metodei respective.

Exemplu

În fişierul TestParam.java este dat următorul program, în care se testează un caz de metodă

care îşi modifică parametrii:

/* Testarea modului de transmitere a parametrilor catre metode */

/* O clasa oarecare, continand un camp a */ class Proba2 { int a; }

class TestParam { /* O metoda in care se modifica valorile propriilor parametri formali */ static void modParam(int k, Proba2 p1, Proba2 p2) { System.out.println("La intrarea in modParam k="+k+" p1.a="+p1.a+ " p2.a="+p2.a); k=-111; // S-a modificat valoarea parametrului k de tip int p1.a=-222; // S-a modificat valoarea unui camp al obiectului cu // referinta p1, dar nu insasi referinta p1 p2=new Proba2(); // S-a modificat insasi referinta p2, catre // o noua instanta a clasei Proba2 p2.a=-333; // S-a atribuit valoare campului a al noii // instante referite prin p2 System.out.println("In modParam dupa modificarile de parametri:\n"+ "k="+k+" p1.a="+p1.a+" p2.a="+p2.a); }

Page 147: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

147

/* Metoda principala */ public static void main(String args[]) { // Se declara si se initializeaza variabilele int m=123; Proba2 pr1=new Proba2(), pr2=new Proba2(); pr1.a=333; pr2.a=444; System.out.println("In main inainte de a invoca modParam:\n"+ "m="+m+" pr1.a="+pr1.a+" pr2.a="+pr2.a); // Se invoca metoda modParam modParam(m, pr1, pr2); // Se afiseaza valorile parametrilor dupa revenirea din modParam System.out.println("In main dupa ce s-a invocat modParam:\n"+ "m="+m+" pr1.a="+pr1.a+" pr2.a="+pr2.a); } }

Executând acest program, obţinem afişate pe ecran următoarele rezultate:

In main inainte de a invoca modParam: m=123 pr1.a=333 pr2.a=444 La intrarea in modparam k=123 p1.a=333 p2.a=444 In modParam dupa modificarile de parametri k=-111 p1.a=-222 p2.a=-333 In main dupa ce s-a invocat modParam: m=123 pr1.a=-222 pr2.a=444

Remarcăm că, deşi în metoda modParam s-au modificat valorile lui k, p1.a si p2.a, la

revenirea din modParam în main valorile lui m şi pr2.a (care corespund respectiv lui k şi

p2.a din modParam) au rămas cele anterioare invocării acestei metode, în timp ce pr1.a

(corespunzătoare lui p1.a) s-a modificat. Iată cum se explică cele constatate:

1/ Parametrul formal k este de tipul primitiv int. În consecinţă, la invocarea metodei

modParam, parametrul efectiv corespunzator se transmite prin valoare, adică se poate

considera că variabilei locale k din modParam i s-a atribuit valoarea lui m, respectiv 123. În

schimb, valoarea variabilei m din main a rămas nemodificată.

2/ Parametrul formal p1 este de tip referinţă la o instanţă a clasei Proba2. La invocarea

metodei modParam, acestui parametru i s-a atribuit valoarea variabilei referinţa pr1 din

main, adică o referinţă către obiectul din clasa Proba2 care a fost creat în main şi are

câmpul a=333. În modParam se modifică valoarea câmpului a din acest obiect. Este deci

normal să constatăm că, la revenirea din modParam, valoarea câmpului pr1.a s-a modificat,

deoarece pr1.a==pr2.a.

3/ Parametrul formal p2, la fel ca p1, este o referinţă la o instanţă a clasei Proba2. La

intrarea în modParam, lui p2 i se atribuie valoarea parametrului efectiv pr1 din main, adică o

referinţă la obiectul în care campul pr1.a are valoarea 444. În metoda modParam se

modifică valoarea parametrului p2, adică se creeaza o nouă instanţă a clasei Proba2 şi se

atibuie lui p2 ca valoare o referinţă la aceasta nouă instanţă. Când se face apoi atribuirea

p2.a=-333, se modifică valoarea câmpului a din această nouă instanţă, fără a se modifica

valoarea câmpului pr2.a al obiectului referit iniţial. În consecinţă, la revenirea în main

constatăm că pr2.a a rămas la valoarea anterioară invocarii metodei modParam.

Page 148: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

148

Metode care întorc o referinţă la un obiect construit în corpul lor

În limbajul Java este posibil ca o metodă să întoarcă o referinţă la un obiect construit în

interiorul ei. Un astfel de exemplu este dat în fişierul TestRef.java, care conţine următorul

program:

/* Testarea unei metode care intoarce un sir */

class TestRef {

static String metoda1() { String str=new String("un sir"); System.out.println("In metoda1 str="+str); return str; }

static void metoda2(String s) { String s1=new String("alt sir"); s=s1; System.out.println("In metoda2 s="+s); }

public static void main(String args[]) { String sir1=null, sir2=null; sir1=metoda1(); metoda2(sir2); System.out.println("In main sir1="+sir1+"\nsir2="+sir2); } }

În metoda1 se creează prin operatorul new un nou şir, iar referinţa str la acesta este

"întoarsă" de această metodă la executarea instrucţiunii return. În metoda2 se creează de

asemenea un nou şir, dar referinţa la acesta se atribuie argumentului s al metodei. La

executarea acestui program se obţin următoarele rezultate:

In metoda1 str=un sir In metoda2 s=alt sir In main sir1=un sir sir2=null

Se observă că metoda1 a întors corect referinţa către şirul "un sir" care a fost creat în

interiorul ei. În schimb, metoda2 nu a avut ca efect lateral transmiterea catre variabila-

referinţă sir2 din main a referinţei către obiectul "alt sir" creat în această metodă

deoarece, după cum s-a arătat anterior, transmiterea parametrilor se face prin valoare şi deci

modificarea în corpul metodei a valorii parametrului formal s nu afectează valoarea

parametrului efectiv str2 prin care aces

ta a fost substituit la invocarea metodei respective.

Page 149: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

149

Metode care au ca argumente şi/sau ca valori întoarse referinţe la tablouri

În limbajul Java, tablourile sunt obiecte. În consecinţă, dacă parametrii formali ai unei

metode sunt tablouri, numele lor sunt, de fapt, variabile-referinţă. De exemplu, în signatura

metodei main main(String args[])

parametrul formal args[] este o referinţă la un tablou, ale cărui elemente aparţin clasei

String (sunt şiruri de caractere). În consecinţă, tot ce s-a prezentat în secţiunea anterioară cu

privire la folosirea ca parametri formali a variabilelor- referinţă este valabil şi pentru tablouri.

Pentru exemplificare, considerăm programul următor, din fişierul TestTab.java.

/* Metode care au ca parametri si ca valori intoarse referinte la tablouri */

class TestTab {

static int[] alpha(int a[], double b[]) { System.out.print("La intrarea in metoda alpha\n Tabloul a: "); for(int i=0; i<a.length; i++) System.out.print(a[i]+" "); System.out.print("\nTabloul b: "); for(int i=0; i<b.length; i++) System.out.print(b[i]+" "); /* Se creaza tabloul c si se dau valori elementelor lui */ int c[]=new int[4]; for(int i=0; i<c.length; i++) c[i]=2*i+1; System.out.println("\nTabloul c alocat si initializat in aceasta "+ "metoda:"); for(int i=0; i<c.length; i++) System.out.print(c[i]+" "); /* Se modifica valorile primelor doua elemente ale tabloului b */ b[0]=-777.77; b[1]=-999.99; /* Se creaza un nou tablou, iar referinta catre el se atribuie parametrului formal a: */ a=new int[3]; a[0]=1000; a[1]=1001; a[2]=1002; System.out.println("Inainte de iesirea din metoda alpha:"); System.out.print("Tabloul a: "); for(int i=0; i<a.length; i++) System.out.print(a[i]+" "); System.out.print("\nTabloul b: "); for(int i=0; i<b.length; i++) System.out.print(b[i]+" "); System.out.println(); return c; }

public static void main(String args[]) { int p[]={10, 11, 12, 13, 14}, q[]; double w[]={1.1, 1.2, 1.3, 1.4, 1.5, 1.6}; q=alpha(p,w); System.out.println("In main dupa revenirea din alpha:"); System.out.print("Tabloul p: "); for(int i=0; i<p.length; i++) System.out.print(p[i]+" "); System.out.print("\nTabloul q: "); for(int i=0; i<q.length; i++) System.out.print(q[i]+" "); System.out.print("\nTabloul w: ");

Page 150: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

150

for(int i=0; i<w.length; i++) System.out.print(w[i]+" "); System.out.println(); } }

Rezultatele afişate la executarea acestui program sunt următoarele:

La intrarea in metoda alpha Tabloul a: 10 11 12 13 14 Tabloul b: 1.1 1.2 1.3 1.4 1.5 1.6 Tabloul c alocat si initializat in aceasta metoda: 1 3 5 7 Inainte de iesirea din metoda alpha: Tabloul a: 1000 1001 1002 Tabloul b: -777.77 -999.99 1.3 1.4 1.5 1.6 In main dupa revenirea din alpha: Tabloul p: 10 11 12 13 14 Tabloul q: 1 3 5 7 Tabloul w: -777.77 -999.99 1.3 1.4 1.5 1.6

Urmărind executarea programului, constatăm că:

- deşi parametrului formal a i s-a atribuit în interiorul metodei alpha o referinţă la alt

tablou, nou construit, aceasta nu a afectat tabloul referit în metoda main prin parametrul

efectiv corespunzător p;

- întrucât în metoda alpha s-au modificat valorile elementelor tabloului referit prin

parametrul formal b, aceste modificări apar şi în metoda main în tabloul referit de parametrul

efectiv corespunzatorw (deoarece b şi w sunt, de fapt, referinţe la acelaşi tablou);

- referinţa la tabloul c, creat în corpul metodei alpha, a fost intoarsă de această metodă şi a

fost atribuită în metoda main variabilei referinţă q; în consecinţă, c şi q sunt referinţe la

acelaşi tablou.

Remarcăm că, la ieşirea din metoda alpha, variabila locală c este eliminată de pe stiva

sistemului. Cu toate acestea, tabloul creat în metoda alpha şi referit de această variabilă locală

nu este eliminat din memorie, deoarece către el indică în continuare variabila-referinţă q din

metoda main.

Metode recursive. Comparaţie între iteraţie şi recursie

O metodă (funcţie sau procedură) care se invocă pe sine însăşi se numeşte metodă recursivă.

Două sau mai multe metode care se invocă una pe alta (metoda A invocă metoda B şi

reciproc) se numesc mutual recursive. Limbajul Java permite utilizarea metodelor recursive

şi mutual recursive. Vom ilustra aceasta prin exemple. Vom arăta, de asemenea că, de regulă,

aceleaşi funcţii pot fi calculate atât recursiv, cât şi iterativ (folosind cicluri). În general, în

limbajele funcţionale se utilizează predominant funcţiile recursive, în timp ce în limbajele

procedurale se prefera iteraţia, deşi în unele dintre ele (cum este şi limbajul Java) se pot folosi

atât iteraţia, cât şi recursia.

Page 151: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

151

Remarcam că, la fel ca în cazul ciclurilor iterative, în metodele recursive trebuie să existe o

condiţie de oprire a repetării. În caz contrar recursia ar continua până la depăşirea spaţiului de

memorie alocat pentru memorarea datelor intermediare (numit stivă).

Comparând metodele recursive cu cele iterative se constată că:

- metodele recursive sunt "mai elegante", fiind şi mai uşor de inţeles de către om decât cele

iterative;

- din punct de vedere computaţional, metodele iterative sunt mai eficiente, deoarece

solicită mai puţină memorie şi sunt mai rapide decât cele recursive. Deosebirea este cu atât

mai mare, cu cât numărul de invocari succesive, respectiv de repetări, este mai mare.

Exemplul 1:

Un exemplu tipic de funcţie recursivă este calcularea factorialului. Din punct de vedere

matematic, factorialul este o funcţie

factorial(n) = 1*2*3*...*n

care poate fi definită recursiv astfel:

factorial(0)=1;

factorial(n)=n*factorial(n-1) pentru n>0;

Pentru n<0 funcţia factorial nu este definită. Calcularea acestei funcţii poate fi facută prin

metoda următoare:

public static long factorial(int n) throws Exception { if(n<0) throw Exception("factorial(n): n<0"); if(n==0) return 1; return n*factorial(n-1); }

În corpul metodei se verifică, mai întâi dacă argumentul n se încadrează în domeniul admis,

iar în caz contrar se generează o excepţie. Dacă argumentul este valabil, se aplică formulele

de calcul recursiv al factorialului date mai sus. Recursia se încheie când se ajunge la n==0.

Atunci când o metodă invoca alta metodă (fie ea recursivă sau nu), datele metodei care

invocă, inclusiv adresa instrucţiunii care urmeaza celei care a făcut invocarea, sunt puse într-

o structură de memorie numita stivă, după care se transmit către metoda invocată argumentele

şi i se dă acesteia controlul. Stiva (engleza: stack) este o structura de memorie în care ultima

dată introdusă este prima extrasă (în engleză: LIFO - Last In First Out). La revenirea din

metoda invocată se obţine valoarea întoarsă de aceasta şi se extrag din stivă datele puse acolo

înainte de invocare, continuându-se calculul.

Să urmarim acest proces în cazul invocării metodei factorial(n) pentru n=4:

factorial(4)=4*factorial(3); se pune 4 în stivă şi se invocă factorial(3); stiva conţine

numărul 4;

factorial(3)=3*factorial(2); se pune 3 în stivă şi se invocă factorial(2); stiva conţine

numerele 3 4;

factorial(2)=2*factorial(1); se pune 2 în stivă şi se invocă factorial(1); stiva conţine

numerele 2 3 4;

Page 152: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

152

factorial(1)=1*factorial(0); se pune 1 în stivă şi se invocă factorial(0); stiva conţine

numerele 1 2 3 4;

factorial(0)=1; recursia s-a incheiat, deoarece funcţia nu se mai invocă pe ea însăşi. Se

continuă calculul fucţiei factorial(1)care a invocat-o pe factorial(0). În acest scop se scoate

din stivă 1 şi se calculează

factorial(1)=1*1=1; stiva conţine 2 3 4.

S-a încheiat calculul lui factorial(1) şi se revine în factorial(2)cu valoarea intoarsa 1; se

continuă factorial(2), extrăgând din stivă pe 2:

factorial(2)=2*1=2; stiva conţine 3 4;

factorial(3)=3*2=6; stiva conţine 4;

factorial(4)=4*6=24; stiva este vidă, deci calculul funcţiei recursive s-a incheiat,

intorcându-se valoarea 24.

Se observa că, cu cât recursia este mai "profundă" (funcţia recursivă se invocă de mai multe

ori pe sine însăşi), cu atât este necesară o stivă de capacitate mai mare. Daca recursia este

prea "profundă", este posibil ca stiva să nu aibă capacitate suficientă. În acest caz se obţine

eroarea de depăşire de stivă StackOverflowError (atenţie: este o eroare, nu o excepţie).

Calcularea factorialului se poate face şi iterativ, folosind următoarea funcţie, în care

factorialul se calculează printr-un ciclu for:

public static long factorial(int n) throws Exception { long fact; if(n<0) throw new Exception("factorial(n): n<0"); fact=1; for(int i=2; i<=n; i++) fact*=i; return fact; }

Ambele metode de calculare a factorialului sunt testate în aplicaţia din fişierul

TestRecursii.java. În acest fişier se declară două clase: clasa Recursii, care conţine metode

statice recursive şi mutual-recursive şi clasa Iteraţii, care conţine metode iterative. În acelaşi

fişier există şi clasa-aplicaţie TestRecursii, care testează metodele din celelalte două clase.

Pentru a se compara metodele din punctul de vedere al timpului de calcul, în aplicaţia

TestRecursii s-a procedat astfel: înainte şi după invocarea fiecărei metode s-a determinat

timpul sistemului în milisecunde, folosind metoda System.currentTimeMillis(), apoi s-a făcut

diferenţa. Se constata astfel că timpul de calcul al factorialului pe cale recursivă este mai

mare decat pe cale iterativă.

Exemplul 2:

Un alt exemplu tipic de funcţie recursivă este funcţia lui Fibonacci definită astfel:

fibonacci(0)=0;

fibonacci(1)=1;

fibonacci(n)=fibonacci(n-1)+fibonacci(n-2) pentru n>1.

În fişierul TestRecursii.java sunt declarate două metode statice pentru funcţia Fibonacci: una

recursiva, în clasa Recursii, şi alta iterativă, în clasa Iteratii. Cele două metode sunt apoi

testate şi comparate în clasa TestRecursii. Se poate constata că, la valori mici ale

Page 153: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

153

argumentului n, metoda recursivă este chiar mai rapidă decât cea iterativă. În schimb, la

valori mari ale lui n, timpul de calcul al metodei recursive creşte foarte rapid, devenind

sensibil mai mare decât al celei iterative.

Exemplul 3:

În clasa Recursii din fisierul TestRecursii.java sunt declarate şi două funcţii mutual-

recursive:

fct1(n,x)=2*fct2(n, 0.4*x+0.3)+x pentru n>=0

fct2(0,y)=y

fct2(n,y)=y*fct1(n-1, 1.27*y-0.89)-1 pentru n>0

Se observă că funcţia fct1() invocă funcţia fct2() şi reciproc.

Metode care generează excepţii

Instrucţiunea throw

Cunoaştem deja că, la apariţia anumitor anomalii în executarea programului, maşina virtuală

Java generează excepţii. Excepţiile sunt obiecte din clasa Exception s-au dintr-o subclasă a

acesteia. Este posibil ca programatorul să prevadă, în anumite puncte ale programului,

generarea unor excepţii, folosind în acest scop instrucţiunea throw, care are forma următoare:

throw new ConstructorExceptie(lista_argumente);

În limba engleză, throw este imperativul de la "a arunca". În această instrucţiune, se

foloseşte operatorul new pentru a genera un obiect al clasei de excepţii căreia îi aparţine

constructorul invocat, după care acest obiect este "aruncat", fie pentru a fi "prins" (captat)

printr-o structura try .. catch şi tratat prin program, fie pentru a fi preluat de maşina

virtuală Java care, în acest caz, opreşte execuţia programului.

Exemplu

Instrucţiunea

if(a>1000) throw new Exception("Exceptie 102: a="+a);

"aruncă" o excepţie din clasa Exception, care contine un mesaj sub forma argumentului

furnizat constructorului.

Clauza throws

În mod normal, excepţiile generate într-o metodă sunt tratate prin structuri try .. catch. chiar

în metoda în care au fost generate. Este însă posibil ca metoda respectivă să "arunce" mai

departe excepţiile generate în corpul ei. Pentru a indica această proprietate, la declararea

metodei, după paranteza care conţine lista declaraţiilor argumentelor formale se pune clauza

Page 154: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

154

throws ClasaDeExceptii, în care se indică numele clasei excepţiei care este "aruncată"

către metoda invocatoare (Cuvantul throws este persoana a treia singular a verbului to throw,

"a arunca").

Exemplu

În programul din fişierul TestExceptie.java există metoda static int factorial(int n),

care calculează factorialul argumentului n. În această metodă este folosită instrucţiunea

throw de doua ori: pentru cazul în care argumentul este negativ şi pentru cel în care

argumentul este prea mare (rezultatul depăşeşte valoarea maximă pentru tipul int al valorii

întoarse). În ambele cazuri, în instrucţiunea throw se foloseşte constructorul clasei

Exception, furnizându-i ca argument un mesaj care arată ce eroare s-a produs. Întrucat

aceste excepţii nu sunt tratate în metoda factorial, în declaraţia metodei factorial s-a

folosit clauza throws. În metoda main se captează şi se afişează atât aceste excepţii, cât şi

excepţia NumberFormatException generată de metoda int Integer.parseInt(String s)

atunci când argumentul acesteia nu este forma externă a unui număr întreg.

/* Testarea unei metode care genereaza exceptii.

Lansarea in executie a aplicatiei se face prin comanda: java TestExceptie <numar_intreg> Daca <numar_intreg> este un numar intreg cuprins intre 0 si 12 se afiseaza factorialul acestui numar. Altfel, se afiseaza un mesaj de eroare */

class TestExceptie {

/* O metoda in care se genereaza exceptii prin clauza throw */

static int factorial(int n) throws Exception { if(n<0) throw new Exception("factorial: argument negativ n="+n); if(n>12) throw new Exception("factorial: argument prea mare: "+n); int fact=1; for(int k=1; k<=n; k++) fact*=k; return fact; }

/* In metoda main se capteaza si trateaza exceptiile generate de metodele factorial si parseInt */ public static void main(String args[]) { if(args.length==0) { System.out.println("Lipsa argument in linia de comanda"); System.exit(1); } try { int n=Integer.parseInt(args[0]); int m=factorial(n); System.out.println("Factorialul lui "+n+" este "+m); } catch(Exception e) { System.out.println(e); }

Page 155: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

155

} }

Clase publice

Clasele publice sunt clase care pot fi utilizate şi în alte pachete, decât cel din care fac parte.

Fiecare clasă publică se declară într-un fişier separat, care are obligatoriu acelaşi nume cu

cel al clasei şi extensia java. În declaraţia de clasă, în faţa numelui clasei se pune

modificatorul public. Dăm în continuare ca exemplu clasa Complex.

Page 156: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

156

Declararea clasei Complex

Clasa Complex este un exemplu de clasă prin care se modelează conceptul matematic de

număr complex. După cum este cunoscut, numărul complex a+b.ieste compus din două

numere reale a şi b, numite respectiv partea reală şi partea imaginară. Simbolul i este numit

unitatea imaginară şi are proprietatea i2= -1. În fişierul Complex.java este dat un exemplu de

declaraţie a clasei Complex. Iată această declaraţie:

/* Clasa numerelor complexe */

public class Complex { private double re; // partea reala private double im; // partea imaginara

/* Constructori */

public Complex() { re=0; im=0; }

public Complex(double parteaReala) { re=parteaReala; im=0; }

public Complex(double parteaReala, double parteaImaginara) { re=parteaReala; im=parteaImaginara; }

public Complex(Complex z) { re=z.re; im=z.im; }

/* Metode */

public double real() { // intoarce partea reala return re; }

public double imag() { // intoarce partea imaginara return im; }

public double modul() { // intoarce modulul numarului complex return Math.sqrt(re*re+im*im); }

public double arg() { // intoarce argumentul numarului complex return Math.atan2(im,re); }

public static Complex complex(double modul, double argument) throws Exception { if(modul<0) throw new Exception("Complex: modul negativ: "+modul); Complex z=new Complex();

Page 157: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

157

z.re=modul*Math.cos(argument); z.im=modul*Math.sin(argument); return z; }

public Complex plus(Complex a) { Complex z=new Complex(); z.re=re+a.re; z.im=im+a.im; return z; }

public Complex plus(double d) { return new Complex(re+d, im); }

public static Complex plus(double d, Complex z) { return new Complex(d+z.re, z.im); }

public Complex minus(Complex a) { Complex z=new Complex(); z.re=re-a.re; z.im=im-a.im; return z; }

public Complex minus(double d) { return new Complex(re-d, im); }

public static Complex minus(double d, Complex z) { return new Complex(d-z.re, -z.im); }

public Complex inmultitCu(Complex a) { Complex z=new Complex(); z.re=re*a.re-im*a.im; z.im=re*a.im+im*a.re; return z; }

public Complex inmultitCu(double d) { return new Complex(re*d, im*d); }

public static Complex inmultitCu(double d, Complex z) { return new Complex(d*z.re, d*z.im); }

public Complex impartitLa(Complex a) throws Exception { Complex z=new Complex(); double w=a.re*a.re+a.im*a.im; // patratul modulului numitorului if(w==0) throw new Exception("Complex impartitLa: impartire la zero");

Page 158: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

158

z.re=(re*a.re+im*a.im)/w; z.im=(im*a.re-re*a.im)/w; return z; }

public Complex impartitLa(double d) throws Exception { if(d==0) throw new Exception("Complex impartitLa: impartire la zero"); return new Complex(re/d, im/d); }

public static Complex impartitLa(double d, Complex z) throws Exception { double w=z.re*z.re+z.im*z.im; if(w==0) throw new Exception("Complex impartitLa: impartire la zero"); return new Complex(d*z.re/w, -d*z.im/w); }

public String toString() { StringBuffer b=new StringBuffer("("+re); if(im>=0) b.append('+'); b.append(im+"*i)"); return b.toString(); }

public boolean equals(Object obj) { if(this==obj) return true; if(getClass()!=obj.getClass()) return false; if(re==(((Complex)obj).re)&&(im==(((Complex)obj).im))) return true; return false; }

public int hashCode() { return (int)(100000*modul()+100*arg()); } }

Declaraţia clasei incepe prin public class Complex, deci este o clasa publică. Clasa

conţine două câmpuri de tip double, reprezentând respectiv partea reală şi partea imaginară a

numărului complex. S-au prevăzut mai mulţi constructori. Primul dintre aceştia nu are

argumente şi creează un număr complex la care, atât partea reală, cât şi cea imaginară sunt

nule.

Având în vedere că s-a declarat un constructor cu două argumente de tip double, reprezentând

partea reală şi cea imaginară a numărului complex nou creat, nu a mai fost posibil să se

creeze încă un constructor, care să aibă ca argumente modulul şi argumentul noului număr

complex (acestea fiind tot numere reale). Din această cauză, el a fost înlocuit prin metoda

statică public static Complex complex(double modul double argument) al cărei nume începe cu literă mică.

Au fost redefinite metodele toString, equals şi hashCode ale superclasei Object, pentru a

ţine seama de specificul clasei Complex. Au fost declarate, de asemenea, metode pentru

Page 159: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

159

efectuarea de calcule între două numere complexe, între un număr complex şi unul real şi

intre unul real şi unul complex. Ultimele au fost declarate ca metode statice, deoarece

operandul din stânga nu aparţine clasei complex.

În toate metodele, în care pot să apară situaţii anormale, s-a prevazut generarea de excepţii.

Utilizarea clasei complex

Testarea diferitelor situaţii de utilizare a clasei complex este exemplificată în fişierul

TestComplex.java.

Colectorul de reziduuri

Dacă un obiect nu mai este necesar, el poate fi distrus, adică eliminat din memorie. În maşina

virtuală Java, există un colector de reziduuri de memorie (engleză: garbage collector) care

eliberează automat spaţiul de memorie ocupat de obiectele către care nu mai există nici o

referinţă. în consecinţă, programatorul nu mai este pus în situaţia să prevadă explicit în

program distrugerea obiectelor şi, deci clasele nu mai conţin destructori, ca în alte limbaje de

POO.

În programul din fişierul Referinte.java se dă un exemplu de situaţie în care unele obiecte

rămân fără referinţe. Dacă, după ce s-a ajuns în situaţia din Figura 2, se execută

instrucţiunile: e=b; a="Sir nou"; c=new String(a); se ajunge în situaţia din Figura 3.

- Figura 3 -

S-au făcut, faţă de situaţia din Figura 2, următoarele transformări:

- referinţei e i s-a atribuit aceeaşi valoare ca referinţei b;

- s-a construit un obiect cu conţinutul "Şir nou", iar variabila aa primit ca valoare referinţa

la acest obiect;

- s-a construit un obiect cu acelaşi continut ca cel indicat de a, iar variabila c indică acum

Page 160: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

160

acest nou obiect.

În consecinţă, două din obiectele "un şir" construite initial au rămas fără referinţe. Nu mai

există nici o cale în program de a folosi aceste obiecte, deci ele trebuie să fie eliminate. Acest

rol este îndeplinit de colectorul de reziduuri. Programatorul nu are însă posibilitatea de a

decide în ce moment se va produce eliminarea efectivă a acestor obiecte, decizia aparţinand

numai colectorului de reziduuri.

Metoda finalize

În clasa Object exista metoda

protected void finalize() throws Throwable

Aceasta metodă este invocată de colectorul de reziduuri, atunci când acesta determină că nu

mai există referinţe către obiectul respectiv. În clasa Object, această metodă nu efectuează

nimic.

Metoda finalize poate fi redefinită în orice altă clasă, pentru a elibera resurse sau a efectua

orice alte acţiuni necesare înainte de distrugerea obiectului respectiv. De exemplu, dacă

obiectul respectiv a deschis anumite fişiere sau conexiuni externe, în metoda finalize se poate

efectua închiderea lor.

Metoda finalize nu este apelată explicit în programul de aplicaţie. Apelarea metodei finalize

se face numai de către colectorul de reziduuri (garbage collector), dar nu imdeiat ce un obiect

a rămas fără referinţă, ci abia atinci când acest obiect a "intrat în atenţia" colectorului. Este

posibil ca executarea aplicaţiei să se incheie înainte ca "finalizarea" unor obiecte să aibă loc.

Exemplu

În aplicaţia din fişierul Finalizari.java este declarată clasa ProbaFinaliz, în care este

redefinită metoda finalize() din clasa Object. În clasa Finalizari din acelaşi fisier se

construiesc două obiecte din clasa ProbaFinaliz, după care se elimină referinţele către

aceste obiecte. Având în vedere că imediat după aceea se încheie executarea aplicaţiei, cel

mai probabil este că nu va avea loc invocarea de către colectorul de reziduuri a metodei

finalize().

Întrebări

Nivel 1

1. Care este cea mai simplă formă a unei declaraţii de clasă?

2. Ce sunt membrii unei clase?

3. Ce este numele clasei din punct de vedere sintactic?

4. Cu ce începe numele unei clase?

Page 161: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

161

5. Ce conţine corpul clasei?

6. Ce asemănare este între câmpuri şi variabilele locale?

7. Ce deosebire este între câmpuri şi variabille locale?

8. Ce sunt câmpurile statice şi prin ce se deosebesc de cele nestatice?

9. Pot exista clase care nu conţin metode?

10. Care este cea mai simplă formă a unei declaraţii de metodă?

11. Ce este numele metodei din punct de vedere sintactic?

12. Ce este corpul metodei şi ce conţine el?

13. Cum se declară argumentele metodei?

14. Cum se declară tipul valorii întoarse?

15. Ce formă şi ce semnificaţie are instrucţiunea return?

16. Ce este o metodă statică?

17. Ce restricţii trebuie respectate la declararea unei metode statice?

18. Ce este signatura metodei?

19. Pot exista în aceeaşi clasă mai multe metode cu acelaşi nume?

20. Cum se face transferul argumentelor (parametrilor) de la metoda invocatoare la cea

invocată?

21. Cum pot fi generate excepţii în corpul unei metode?

22. Ce formă are instrucţiunea throw şi la ce serveşte?

23. La ce serveste clauza throws?

24. Ce deosebire este între throw şi throws?

25. Ce sunt clasele publice?

26. Cum se declara o clasă publică?

27. Ce este colectorul de reziduuri?

Nivel 2

1. Care sunt valorile iniţiale implicite ale câmpurilor?

2. Ce deosebire este între iniţializarea câmpurilor şi iniţializarea variabilelor locale?

3. Ce deosebire este intre o funcţie şi o procedură?

4. Prin ce se deosebeşte o metodă prin care se realizează o procedură de una care

realizează o funcţie?

5. În ce mod se invocă, în mod normal, o metodă prin care se realizează o funcţie

propriu-zisă (a carei valoare întoarsă nu este void)?

6. În ce mod poate fi invocata o metoda care întoarce void?

7. Există în limbajul Java variabile globale?

8. Ce deosebire este între parametrii formali ai unei metode şi cei efectivi?

9. Ce se întâmplă dacă în corpul unei metode se modifică valoarea unui argument

formal?

10. Ce se întâmplă dacă în corpul unei metode se modifică conţinutul unui obiect referit

de către un parametru formal al metodei respective?

11. Ce se întâmplă dacă în corpul unei metode se modifică valoarea unui parametru

formal de tip referinţă (în sensul că i se dă ca valoare o referinţă la alt obiect)?

12. În ce situaţie, la revenirea dintr-o metodă, poate să aibă loc un efect lateral?

13. Este posibil ca o metodă să întoarcă o referinţă la un obiect construit în corpul

acesteia?

14. Ce se întâmplă dacă, în corpul unei metode care are ca argument formal un tablou, se

modifică elementele acestui tablou?

15. Ce se întâmplă dacă, în corpul unei metode care are ca argument formal un tablou, i se

Page 162: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

162

dă acestui argument ca valoare o referinţa la alt tablou?

16. Poate o metodă să întoarcă drept valoare o referinţă la un tablou creat în interiorul ei?

17. Ce este o metodă recursivă?

18. Ce deosebiri există între iteraţie şi recursie?

19. În ce scop se redefineşte într-o clasă metoda toString() a clasei Object?

20. În ce scop se redefineşte într-o clasă metoda equals(Object ob) a clasei Object?

21. Poate fi declarată o metodă care creează un obiect nou al clasei căreia îi apartine

metoda respectivă? Prin ce se deosebeşte ea de un constructor?

22. Ce este metoda finalize()?

23. În ce scop este redefinită metoda finalize()?

24. În ce situaţii este invocată metoda finalize()?

Page 163: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

163

Caracteristicile obiectelor şi claselor şi

reflectarea lor în declararea claselor.

Interfeţe. Clase imbricate

Caracteristici ale obiectelor şi claselor şi reflectarea lor în declararea

claselor:

163

Încapsularea; câmpuri şi metode publice şi private; 166

Modificatori de acces pentru câmpuri şi metode; 167

Declararea constructorilor; 167

Agregarea; 170

Moştenirea; 171

Membrii protejati ai clasei; 171

Referinţele this şi super; 171

Declararea clasei derivate; clauza extends; 171

Declararea constructorului clasei derivate; 172

Redefinirea metodelor; 172

Ascunderea (acoperirea) câmpurilor; 175

Ascunderea metodelor statice; 175

Metode finale; 177

Declararea propriilor clase de excepţii; 177

Clase finale; 177

Polimorfismul; 177

Un exemplu: clasa Persoana şi subclasa Student; 180

Declararea clasei Persoana; 180

Declararea clasei Student; 181

Utilizarea celor două clase; 183

Instanţierea clasei care conţine metoda main; 184

Clase abstracte; 186

Interfeţe; 186

Clase imbricate şi clase interioare 190

Întrebări 195

Caracteristicile obiectelor şi claselor

În majoritatea surselor bibliografice asupra POO, se consideră drept principale caracteristici

ale obiectelor încapsularea, moştenirea şipolimorfismul. La acestea se mai pot adaugă şi alte

caracteristici importante, cum sunt identitatea, agregarea şi clasificarea.

Identitatea (engleză: Identity) se referă la faptul că datele sunt grupate în entităţi discrete,

numite obiecte. Fiecare obiect din POO modelează starea şi comportamentul unui anumit

Page 164: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

164

obiect din lumea reală, care poate fi un obiect fizic (de exemplu automobil, calculator, furnal,

om, animal etc.) sau unul conceptual (de exemplu figură geometrică, orar etc.). Fiecare obiect

are propria lui identitate, astfel că două obiecte sunt considerate distincte, chiar daca

atributele lor (cum ar fi numele, culoarea etc.), sunt identice. Pentru a face aceasta distincţie,

obiectul este indicat printr-o referinţă unică. Modul în care este reprezentata această referinţă

poate sa difere în diverse limbaje de programare (de ex. adresă de memorie, nume etc.),

important însă este că fiecare obiect are o singură referinţă şi nu există două obiecte distincte

cu aceeaşi referinţă.

Încapsularea (engleză: encapsulation) este proprietatea obiectelor de a-şi ascunde o parte din

date şi metode. Din exteriorul obiectului sunt accesibile ("vizibile") numai datele şi metodele

publice. Putem deci sa ne imaginăm obiectul ca fiind format din două straturi, ca în Figura 1.

- Figura 1 -

Obiectul se comportă ca şi când ar avea doua "învelişuri": unul "transparent", care permite

accesul la datele şi metodele publice ale obiectului, şi un al doilea inveliş "opac", care

cuprinde datele şi metodele invizibile (inaccesibile) din exterior. Starea obiectului depinde

atât de datele publice, cât şi de cele încapsulate. Metodele publice ale obiectului au acces la

datele şi metodele încapsulate (ascunse) ale acestuia. In consecinţă, starea obiectului poate fi

modificata atât prin modificarea directă, din exterior, a valorilor variabilelor publice, fie prin

utilizarea unor metode publice care modifica valorile variabilelor încapsulate. În mod similar,

valorile variabilelor încapsulate pot fi obţinute numai utilizand metode publice ale obiectului

respectiv.

Încapsularea obiectelor prezintă avantaje importante în programare, deoarece măreşte

siguranţa şi fiabilitatea programelor, prin eliminarea posibilităţii modificării accidentale a

valorilor acestora, ca urmare a accesului neautorizat din exterior. Din această cauză,

programatorii evită în general să prevadă într-un obiect date publice, preferand ca accesul la

date să se facă numai prin metode.

Partea vizibilă (publică) a obiectului constituie interfaţa acestuia cu "lumea exterioară". Este

posibil ca două obiecte diferite să aibă interfeţe identice, adică să prezinte în exterior aceleaşi

date şi metode. Datorită faptului că partea încapsulată diferă, astfel de obiecte pot avea

comportament diferit.

Agregarea (engleză: aggregation) este proprietatea obiectelor de a putea încorpora alte

obiecte. Aşa dar, "datele" conţinute într-un obiect pot fi nu numai date primitive, ci şi obiecte.

Se pot astfel crea obiecte cu structuri din ce în ce mai complexe.

Page 165: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

165

Clasificarea (engleză: classification) este proprietatea obiectelor care au aceeaşi structură de

date şi acelaşi comportament (aceleaşi metode) de a putea fi grupate într-o clasă. Clasa este o

abstractizare, care conţine acele proprietăţi ale obiectelor, care sunt importante într-o

aplicaţie sau într-o categorie de aplicaţii, şi le ignoră pe celelalte. De exemplu, în aplicaţii

privind situaţia profesională a studenţilor, clasa Student conţine astfel de atribute ca numele şi

prenumele studentului, facultatea, anul de studii, examenele promovate şi notele obţinute, dar

ignoră atribute ca înălţimea, culoarea ochilor sau a părului, greutatea etc., care nu sunt

necesare în aplicaţia respectivă. Spre deosebire de agregare, care este o relaţie între obiecte,

clasificarea este o relaţie între concepte reprezentate prin clase.

În functie de nivelul de abstractizare, clasele pot forma o structura ierarhică. De exemplu,

clasa mijloacelor de transport cuprinde subclasele mijloacelor de transport terestre, navale şi

aeriene. Clasa mijloacelor de transport terestre le cuprinde pe cele rutiere şi feroviare. Clasa

mijloacelor de transport rutiere cuprinde clasele automobilelor şi autocamioanelor etc.

Fiecare subclasă a unei clase este ea însăşi o clasă. O astfel de ierarhie de clase este

reprezentată în Figura 2.

- Figura 2 -

Cu cat o clasă se afla în această ierarhie pe un nivel mai înalt, cu atât ea este mai abstractă,

deci descrie un număr mai mic de atribute ale obiectelor care îi aparţin. Clasa A este rădăcina

acestei ierarhii, fiind situată pe cel mai înalt nivel de abstractizare. Clasele B, C şi D sunt

subclase ale lui A, iar clasele E si F sunt subclase ale clasei B. În acelaşi timp, clasa

Aestesuperclasă a clasei B, iar aceasta este superclasă a clasei F. În programarea orientată pe

obiecte se spune, de asemenea, că clasa B este derivată din clasa A, iar clasa F este derivată

din clasa B sau, în general, o subclasă este derivată din superclasa sa.

Un obiect care aparţine unei clase se numeşte şi instanţă a clasei (este o instanţiere, o

realizare particulara a clasei respective). De exemplu, clasa Barbat şi clasa Femeie sunt

subclase ale clasei Om. În schimb, Ion_Popescu este o instanţăa clasei Barbat (un obiect care

aparţine acestei clase), iar Maria_Preda este o instanţă a clasei Femeie.

În principiu, o clasă poate avea o infinitate de instanţe. Practic, desigur, numărul lor este finit.

Toate instanţele unei clase au aceleaşi atribute (aceleaşi "câmpuri"), dar valorile acestora pot

să difere de la o instanţă la alta.

Page 166: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

166

Moştenirea (engleză: inheritance) este proprietatea unei clase de a conţine toate atributele

(câmpurile) şi metodele superclasei sale. În consecinţă, trecerea de la clasă la subclasă se face

prin adăugarea de atribute şi/sau de metode. De exemplu, clasa Barbat şi clasa Femeie au

ambele toate atributele clasei Om, dar fiecare din acestea are şi atribute specifice.

În general, în programarea orientată pe obiecte, moştentirea poate fi simplă sau multiplă. În

cazul moştenirii simple fiecare clasă are cel mult o superclasă, ca în Figura 2. În cazul

moştenirii multiple o clasă poate avea mai multe superclase, ca în Figura 3.

- Figura 3 -

În această figură se observă că clasa D moşteneşte clasele A şi B, iar clasa H moşteneşte

clasele D, E siF. Aceasta corespunde situaţiei din lumea reală în care, de exemplu, un

student_sportiveste în acelaşi timp şi student, şi sportiv, deci deţine atributele ambelor clase.

Deşi există limbaje de programare, ca limbajul C++, care admit moştenirea multiplă, aceasta

creează unele dificultăţi. Astfel, în exemplul din Figura 3, metodele şi datele clasei B sunt

moştenite de clasa H pe două căi: pe traseul BDH şi pe traseul BEH. Pentru a se evita astfel

de situaţii, în limbajul Java se admite numai moştenirea simplă. Lipsa moştenirii multiple

este compensată în limbajul Java prin introducerea conceptului de interfaţă care va fi

prezentat ulterior.

Polimorfismul (engleză: polymorphism) permite ca aceeaşi operaţie să se realizeze în mod

diferit în clase diferite. Să considerăm, de exemplu, că în clasa Figura_geometrica există

metoda arie(), care calculeaza aria figurii respective. Clasele Cerc, Triunghi, Patrat sunt

subclase ale clasei Figura_geometrica si vor moşteni, deci, de la aceasta metoda arie(). Este

însă evident că aria cercului se calculează în alt mod decât aria patratului sau cea a

triunghiului. Pentru fiecare din instanţele acestor clase, la calcularea ariei se va aplica metoda

specifică clasei respective.

Încapsularea

Încapsularea este una din proprietăţile fundamentale ale claselor în programarea orientată pe

obiecte.

Câmpurile, constructorii şi metodele dintr-o clasă pot fi încapsulate, astfel încât să nu fie

vizibile din exteriorul clasei sau instanţei în care se află. Aceasta se realizează folosind la

declararea câmpului, constructorului sau metodei respective modificatorul private.

Page 167: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

167

De exemplu, prin declaraţia de câmpuri private double a, b, c;

se creează câmpurile private a, b, c care nu sunt vizibile din exteriorul instanţei în care se

afla. În mod similar, prin declaraţia de metodă private int ex1(int k) { return 2*k+1); }

se declară metoda privată ex1.

Câmpurile şi metodele declarate astfel se numesc private. În opoziţie cu acestea, sunt

câmpurile şi metodele publice, care sunt declarate folosind modificatorul public şi sunt

vizibile din orice altă clasă.

Modificatori de acces pentru câmpuri şi metode

În limbajul Java există trei modificatori de acces pentru câmpuri şi metode:

- private - pentru a specifica câmpuri sau metode private;

- public - pentru a specifica câmpuri sau metode publice;

- protected - pentru a specifica câmpuri sau metode protejate (care vor fi prezentate în

secţiunea despre moştenire).

Membrii privati ai claselor (câmpuri sau metode) sunt accesibili numai din clasa respectivă.

Membrii publici sunt accesibili din orice clasă. Membrii protejati sunt accesibili numai din

clasa în care se află sau din subclasele acesteia.

Dacă la declararea câmpurilor sau metodelor nu se folosesc modificatori de acces, acestea

sunt considerate vizibile numai din clasele care sunt situate în acelaşi pachet cu clasa căreia îi

aparţin. În particular, pentru clasele declarate de către noi, aceste câmpuri şi metode sunt

vizibile numai din clasele situate pe disc în acelaşi director. Se spune, în astfel de cazuri, că

modul de acces este prietenos (engleză: friendly) sau de pachet (engleză: package).

Declararea constructorilor

Constructorii sunt utilizati impreuna cu operatorul new pentru a creea instanţe ale claselor.

Constructorii pot fi impliciţi sau expliciţi.

Constructorii, ca şi metodele, sunt niste subprograme. Faţă de metode, constructorii prezintă

următoarele trăsături specifice:

- numele constructorului este întotdeauna acelaşi cu al clasei căreia îi aparţine;

- constructorul nu întoarce o valoare. În consecinţă, la declararea constructorului nu se

specifică tipul valorii întoarse, ca la metode;

- constructorii nu pot fi statici;

- invocarea constructorilor se face numai prin operatorul new.

Ca şi în cazul metodelor, o clasă poate avea mai multi constructori, care sa difere între ei prin

signatură.

Constructorul implicit

Dacă într-o clasă nu este declarat explicit nici un constructor, ea are un constructor implicit.

Acest constructor nu are argumente, iar efectul lui constă în iniţializarea tuturor câmpurilor

instanţei care se creează cu valorile implicite corespunzătoare tipurilor câmpurilor respective.

Page 168: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

168

ATENŢIE: dacă clasa are unul sau mai multi constructori declaraţi explicit, ea nu mai are

constructor implicit.

Exemplu: în aplicaţia Cercuri din fişierul Cercuri.java, la crearea instanţelor clasei Cerc1 s-a

folosit constructorul implicit al acestei clase.

Constructori expliciţi

Declararea constructorului se face sub forma modificator_acces nume_clasa(declaratii_de_argumente) { corpul_constructorului } Se observă imediat că declararea constructorului se face la fel cu a unei metode, cu

deosebirea că lipseşte tipul valorii întoarse, iar numele constructorului este cel al clasei.

Modificatorul de acces al constructorului este, cel mai frecvent, public. El poate, totuşi, sa

lipsească dacă se consideră că instanţierea clasei se va face numai în metode ale claselor din

acelaşi pachet.

În corpul constructorului pot fi programate orice fel de acţiuni care trebuie executate imediat

după ce se alocă în memorie spaţiu pentru o instanţă a clasei respective. Cel mai frecvent, în

corpul constructorilor se iniţializează valorile câmpurilor instanţei nou create.

Exemplu

În fişierul Cercuri1.java este declarată clasa Cerc în modul următor:

class Cerc { public static final double PI=3.141592653589793; private double r;

public Cerc(double raza) { r=raza; }

public double raza() { return r; }

public double arie() { return PI*r*r; }

public double circumferinta() { return 2*PI*r; }

public static double arie(double r) { return PI*r*r; }

public static double circumferinta(double r) { return 2*PI*r;

Page 169: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

169

} }

Clasa Cerc are atât metodele de instanţă, cât şi metodele statice pentru calcularea ariei şi

circumferinţei, care existau în clasele Cerc1 şi Cerc2 din exemplul dat în fişierul Cercuri.java.

În plus, remarcăm următoarele:

- câmpul r1 (raza cercului) a fost declarat privat, deci el nu este accesibil din exteriorul

clasei;

- s-a declarat un constructor care, la crearea unui obiect din clasa Cerc, iniţializează câmpul

r1. Întrucât clasa Cerc nu conţine nici o metodă prin care să se modifice valoarea acestui

câmp, raza cercului nu mai poate fi modificată după ce acesta a fost creat, aşa cum era posibil

în cazul instanţelor clasei Cerc1.

În acelaşi fişier sursă, este declarata şi clasa Cercuri1, în care se utilizeaza clasa Cerc.

Aplicaţia menţionată este declarată astfel:

/* Aplicatia in care se utilizeaza cele doua clase de cercuri declarate mai sus */

class Cercuri1 { public static void main(String args[]) { double r1=1, r2=7.32; /* Instantierea a doua cercuri */ Cerc c1=new Cerc(r1), c2=new Cerc(r2); /* Utilizarea metodelor de instanta */ System.out.println("Utilizand metodele de instanta:"); System.out.println("Pentru cercul c1:\n aria="+c1.arie()+ " circumferinta="+c1.circumferinta()+" raza="+c1.raza()); System.out.println("Pentru cercul c2:\n aria="+c2.arie()+ " circumferinta="+c2.circumferinta()+" raza="+c2.raza()); /* Utilizarea metodelor statice */ System.out.println("Folosind metodele statice ale clasei Cerc:"); System.out.println("Pentru raza r1: aria="+Cerc.arie(r1)+ " circumferinta="+Cerc2.circumferinta(r1)); System.out.println("Pentru raza r2: aria="+Cerc.arie(r2)+ " circumferinta="+Cerc2.circumferinta(r2)); System.out.println("Pentru raza r=9.23 aria="+Cerc.arie(9.23)+ " circumferinta="+Cerc.circumferinta(9.23)); /* Acelasi calcul, facut calificand numele metodelor statice prin

referinte la instante ale clasei Cerc */ System.out.println("Aria cercului cu raza 9.23: "+ c1.arie(9.23)+" "+c2.arie(9.23)); } }

Se observă că iniţializarea celor două cercuri (instanţe ale clasei Cerc) c1 şi c2 s-a făcut

folosind constructorul Cerc(double raza). După ce a fost construit cercul, raza lui nu mai

poate fi modificată. Calculara ariei cercului c1 se face invocând metoda c1.arie(), care

aparţine instanţei c1. În acest caz, metoda nu are argumente, deoarece se va folsi raza

cercului c1.

Aria unui cerc oarecare poate fi calculată însă şi invocând metoda staticăCerc.arie(raza),

Page 170: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

170

căreia însă i se dă ca argument raza cercului. Chiar dacă această metodă statică este

invocată prin intermediul referinţei la o instanţă sub forma c1.arie(raza), nu se va folosi

în calcul raza instanţei c1, ci raza primită ca argument. Compilatorul face distincţie intre

metodele arie() şi arie(double raza) întrucât au semnături diferite.

Agregarea

Agregarea este o caracteristică fundamentală a programării orientate pe obiecte, conform

căreia un obiect poate conţine alte obiecte.

În limbajul Java, la declararea claselor, este permis ca atât câmpurile clasei, cât şi ale

instanţei să aibă ca valori obiecte din alte clase. Se poate porni astfel de la clase simple, care

au drept câmpuri date din tipuri primitive, şi construi pas cu pas clase cu structuri din ce in ce

mai complicate, realizate prin agregarea claselor cu structuri mai simple.

Un exemplu de agregare este clasa Pers din fisierul Pers.java, pe care îl reproducem aici.

class Pers { private String numePers, prenumePers; private int anNasterePers;

Pers(String nume, String prenume, int anNastere) { numePers=nume; prenumePers=prenume; anNasterePers=anNastere; }

String nume() { return numePers; }

String prenume() { return prenumePers; }

int anNastere() { return anNasterePers; } }

Instanţele clasei Pers conţin datele unei persoane. Se observă că obiectele din clasa Pers

conţin câmpurile nume şi prenume, care sunt referinţe la obiecte ale clasei String. Remarcăm

de asemenea că, întrucât câmpurile de date sunt private, iniţializarea lor se face folosind un

constructor. După crearea obiectului, aceste câmpuri nu mai pot fi modificate. Testarea clasei

Pers se face în aplicaţia din fişierul TestPers.java.

Moştenirea

Conceptul de moştenire

Page 171: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

171

Moştenirea este o trăsătură fundamentală a programării orientate pe obiecte, conform căreia:

- dintr-o clasă se pot deriva alte clase. Dacă din clasa A este derivată clasa B, atunci A se

numeşte clasă de bază, sau superclasă, iar B se numeşte clasă derivată, sau subclasă;

- subclasa mosteneste câmpurile şi metodele superclasei;

- metodele superclasei pot fi redefinite în subclasă prin alte metode cu aceeaşi signatură;

- metodele statice ale superclasei pot fi ascunse în subclasă;

- câmpurile superclasei pot fi ascunse în subclasă prin câmpuri cu acelaşi nume dar care

pot avea, eventual, alt tip.

- câmpurile unei clase pot fi ascunse chiar şi în metodele clasei respective, dacă aceste

metode au argumente sau variabile locale cu acelaşi nume.

Membrii protejaţi ai clasei

Există trei moduri de acces la membrii claselor (atât la câmpuri, cât şi la metode): public,

privat si protejat. Până în prezent am folosit numai modificatorii de acces public şi private,

deoarece nu am declarat clase derivate. Introducem acum şi modificatorul de acces

protected. Câmpurile sau metodele declarate cu acest modificator de acces sunt vizibile

(accesibile) în propria clasă şi în clasele derivate din aceasta. Iată, deci, care sunt cei trei

modificatori de acces la membrii unei clase folositi în declaraţiile de clase:

- public - pentru câmpuri şi metode care sunt accesibile din orice clasă (inclusiv din clase

aparţinând altor pachete);

- protected - pentru câmpuri şi metode care sunt accesibile în propria clasă şi în

subclasele acesteia, dar nu sunt vizibile din alte clase;

- private - pentru câmpurile şi metodele care sunt accesibile numai din propria clasă.

Acestea nu sunt accesibile din nici o alta clasă (nici chiar din subclasele propriei lor clase).

Amintim că, în lipsa modificatorului de acces, câmpurile şi metodele respective sunt

accesibile din clasele aceluiaşi pachet. Acest mod de acces este cunoscut sub numele de

prietenos (engleză: friendly) sau de pachet (engleză: package).

Referinţele this şi super

În orice clasă pot fi utilizate două referinţe predefinite:

this - este o referinţă la "această" instanţă, adică la instanţa (obiectul) din care se face

referinţa respectivă;

super - este o referinţă la superclasă.

Declararea clasei derivate. Clauza extends

În declaraţia clasei derivate (subclasei), numele clasei care se declară este urmat de clauza

extends, în care se indică numele superclasei. În consecinţă, clasa derivată poate fi declarată

astfel:

class NumeClasa extends NumeSuperclasa { declaratii_de_membri }

Page 172: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

172

Amintim că în limbajul Java orice clasă are o superclasă şi numai una. Excepţie face clasa

Object, care este rădăcina ierarhiei de clase. Daca lipseşte clauza extends, superclasa

implicită este Object.

Declararea constructorului clasei derivate

Pentru a se da valori iniţiale câmpurilor superclasei, în declaraţia constructorului subclasei

poate fi invocat constructorul superclasei prin instrucţiunea super(lista_parametri_efectivi); unde lista parametrilor efectivi este cea a constructorului superclasei. Aceasta instrucţiune,

dacă există, trebuie să fie prima instrucţiune din corpul constructorului clasei derivate. În

lipsa ei, va fi invocat constructorul fără parametri al superclasei.

Este posibil, de asemenea, ca într-un constructor să se invoce alt constructor al aceleeaşi

clase, sub forma this(lista_parametri_efectivi);

Redefinirea metodelor

Metodele de instanţă (nestatice) ale unei clase pot fi redefinite în subclasele acesteia.

Redefinirea unei metode se face declarând în subclasă o metodă având aceeaşi signatură cu

una din superclasă. Atunci când se redefineşte o metoda protejată, modificatorul de acces al

acesteia poate fi menţinut, sau poate fi transformat în public.

În subclasă pot fi folosite, totuşi, şi metodele superclasei care au fost redefinite, dacă la

invocarea acestor metode se foloseste referinţa super.

Exemplu:

În fişierul S1.java este declarata clasa S1, iar in fişierul CD1.java este declarata clasa CD1,

care extinde clasa S1 (este, deci, derivată din aceasta). Reproducem aici declaraţiile celor

două clase:

/* Clasa S1 din care vor fi derivate alte clase */

public class S1 { public int a; protected double b; private int c; public final static int alpha=12;

public S1(int a, double b, int c) { // constructorul clasei S1 this.a=a; this.b=b; this.c=c; }

private double f1() { // o metoda privata return a*c+b; }

Page 173: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

173

protected int f2() { // o metoda protejata return a+2*c; }

public double f3() { // o metoda publica in care se folosesc f1 si f2 return 2*f1()+f2(); }

public String toString() { // redefinirea metodei Object.toString() return "(S1: "+a+" "+b+" "+c+")"; }

public static int f4(int k) { return 2*k+alpha; } }

/* O clasa derivata din S1, in care se redefinesc unele metode */

class CD1 extends S1 { public CD1(int a, double b, int c) { super(a,b,c); }

public int f2() { // redefinirea metodei f2() din superclasa return 2*a; } public double f3() { // redefinirea metodei f3() din superclasa return f2()+super.f3(); } }

Remarcăm următoarele:

- în metodele clasei S1 pot fi folosite toate câmpurile declarate în această clasă, fie ele

publice, protejate sau private; de asemenea, pot fi invocate toate metodele din această clasă;

- în clasa S1 a fost redefinită metoda toString din clasa Object, astfel incât să se întoarca un

şir care conţine valorile câmpurilor a, b şi c;

- metoda statică f4() din clasa S1 utilizează numai câmpul static alpha al acestei clase;

- în constructorul clasei CD1 a fost invocat constructorul clasei S1 sub forma

super(a,b,c). În acest mod au fost iniţializate toate câmpurile din superclasa S1, inclusiv

câmpul privat c, care nu este direct accesibil din clasa CD1;

- în clasa CD1 au fost redefinite metodele f2 şi f3 din superclasa S1 şi a fost iarăşi redefinită

metoda toString;

- în mod normal, în clasa CD1 se folosesc metodele f2 şi f3 redefinite în această clasă. Este

totuşi posibil ca în clasa CD1 să se apeleze metodele superclasei, dacă în expresia de invocare

se foloseşte referinta super. Astfel, în metoda f3 din clasa CD1 există expresia super.f3(),

prin care se invoca metoda f3 din superclasa S1;

- la redefinirea metodei f2, modul de acces a fost modificat din protected in public;

- în metodele clasei CD1 nu au putut fi folosite câmpurile şi metodele private ale superclasei

S1.

Testarea claselor S1 si CD1 se face în clasa TestCD1, care se găseşte în fişierul TestD1.java.

Iată aceasta clasă:

Page 174: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

174

/* Testarea claselor S1 si CD1 */

class TestCD1 { public static void main(String args[]) { S1 s=new S1(1, 1.1, 2); CD1 cd=new CD1(10, 10.2, 20); System.out.println("s="+s+" cd="+cd); System.out.println("s.f2()="+s.f2()+" s.f3()="+s.f3()); System.out.println("cd.f2()="+cd.f2()+" cd.f3()="+cd.f3()); System.out.println("CD2.f4(3)="+CD2.f4(3)+" S1.f4(3)="+S1.f4(3)); System.out.println("cd.f4(3)="+cd.f4(3)+" s.f4(3)="+s.f4(3)); } }

Executând aplicaţia TestCD1 se obţin urmatoarele rezultate:

s=(S1: 1 1.1 2) cd=(S1: 10 10.2 20) s.f2()=5 s.f3()=11.2 cd.f2()=20 cd.f3()=460.4 CD2.f4(3)=18 cd.f4(3)=18

Remarcăm că:

- crearea instanţelor claselor S1 şi CD1 s-a făcut aplicând operatorul new asupra

constructorilor claselor respective;

- în instrucţiunea System.out.println("s="+s+" cd="+cd); este de două ori invocată implicit metoda toString, pentru a converti în şiruri afişabile

obiectele s şi cd;

prima dată este invocată metoda s.toString() din clasa S1. A doua oară ar trebui sa fie

invocată metoda cd.toString() din clasa CD1 dar, intrucât metoda nu a fost redefinită în

aceasta clasă, a fost aplicată efectiv metoda toString() din superclasa S1;

- în expresiile s.f2() si s.f3() sunt invocate metodele din clasa S1, careia îi aparţine s, iar

in expresiile cd.f2() şi cd.f3() sunt invocate metodele corespunzătoare din clasa CD1;

- metoda statică f4() din clasa S1 a fost invocată în patru moduri: calificând numele

metodei f1 cu numele clasei S1 (căreia îi aparţine de fapt această metodă), cu numele

subclasei CD1 (care moşteneşte această metodă) şi cu numele instanţelor s şi cd ale acestor

clase. Cum era de aşteptat, în toate cele patru cazuri s-a obţinut acelaşi rezultat.

Puteti compila cele trei fişiere menţionate şi pune în executie aplicaţia TestCD1 pentru a

verifica respectarea afirmaţiilor de mai sus. Puteţi, de asemenea, face modificări în metodele

celor trei clase menţionate, astfel încât să verificaţi:

- ce se întâmplă dacă într-o metoda a clasei CD1 se încearcă folosirea câmpurilor sau

metodelor private ale superclasei S1;

- ce se întâmplă dacă în clasa TestDC1 se încearcă folosirea câmpurilor sau metodelor

private sau protejate din clasele S1 şi CD1.

Ascunderea câmpurilor

Page 175: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

175

Câmpurile declarate într-o clasă pot fi ascunse prin câmpuri cu acelaşi nume declarate în

subclasă, chiar dacă acestea au tipuri diferite. Aceasta înseamna că, în mod normal, în

metodele clasei se folosesc câmpurile declarate în clasa respectivă, şi nu cele cu acelaşi nume

ale superclasei. În subclasă pot fi, totuşi, folosite şi câmpurile superclasei, dacă sunt calificate

cu referinţa super.

Ascunderea metodelor statice

Metodele statice nu aparţin instanţelor, ci clasei. Din această cauză, dacă într-o subclasă se

declara o metoda statică cu aceeaşi signatură ca o metodă a superclasei, atunci se spune că

metoda din subclasă o ascunde pe cea din superclasă (nu o redefineşte). Modul de lucru cu

metodele ascunse este similar cu cel în care se lucrează cu câmpurile ascunse. Vom înţelege

mai bine deosebirea dintre redefinire şi ascundere când vom studia polimorfismul.

Exemplu

În fişierul CD2.java este declarată clasa CD2, care extinde clasa S1 din exemplul precedent.

În clasa CD2 există declaraţia public double a, b, m; prin care se creează câmpuri ale

instanţelor acestei clase, dintre care a şi b ascund câmpurile cu aceleaşi nume ale superclasei.

De asemenea, în clasa CD2 este declarată metoda statică f4(int h), care ascunde metoda

statică cu aceeaşi signatura din superclasa S1.

/* O clasa in care se ascund unele din campurile superclasei */

class CD2 extends S1 { public double a, b, m; // campurile a, b le ascund pe cele cu // aceleasi nume din superclasa

public CD2(int a1, double b1, int c1, double a2, double b2, double m2) { super(a1,b1,c1); // initializarea campurilor din superclasa a=a2; b=b2; m=m2; // initializarea campurilor proprii }

public void afisare() { System.out.println("Campuri din CD2: a="+a+" b="+b+" m="+m); System.out.println("Campuri din S1: a="+super.a+" b="+super.b); }

public static int f4(int h) { // ascunde metoda statica f4() din // superclasa return h+alpha; }

public String toString() { return "(CD2: "+super.toString()+" "+a+" "+b+" "+m+")"; } }

Remarcăm că:

- în constructorul clasei CD2 este mai întâi invocat constructorul superclasei, prin care se

iniţializează câmpurile din S1, după care se iniţializează şi câmpurile din CD2;

- întrucât metoda afisare() este declarată în clasa CD2, ea operează cu câmpurile a, b şi m

Page 176: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

176

declarate în CD2. Totuşi, în acesastă metodă se poate lucra şi cu câmpurile a şi b din S1,

folosindu-se în mod corespunzător expresiile super.a şi super.b;

- în redefinirea metodei toString() s-a folosit expresia super.toString() pentru a

invoca metoda cu aceeasi signatură din superclasa S1. Observăm că pentru a utiliza în

aceasta metodă în mod direct câmpurile a şi b din S1 (care sunt ascunse în clasa CD2), ar fi

trebuit utilizate expresiile super.a şi super.b;

Testarea clasei CD2 se face în aplicaţia din fişierul TestCd2.java, care are conţinutul următor:

/* Testarea clasei CD2 */

class TestCD2 { public static void main(String args[]) { CD2 cd=new CD2(1, 2.45, 3, 10.23, 12.5, 17.08); System.out.println("Imediat dupa ce s-a creat instanta clasei CD2:"); cd.afisare(); System.out.println("cd.toString(): "+cd.toString()); cd.a=-17.83; cd.b=28.16; cd.m=127.9; System.out.println("dupa ce s-au schimbat valorile "+ "campurilor din CD2:"); cd.afisare(); System.out.println("cd.toString(): "+cd.toString()); System.out.println("S1.f4(3)="+S1.f4(3)+" CD2.f4(3)="+CD2.f4(3)+"

CD1.f4(3)=cd1.f4(3)); } }

Executând aplicaţia TestCD2 obţinem următoarele rezultate:

Imediat dupa ce s-a creat instanta clasei CD2: Campuri din CD2: a=10.23 b=12.5 m=17.08 Campuri din S1: a=1 b=2.45 cd.toString()=(CD2: (S1: 1 2.45 3) 10.23 12.5 17.08) dupa ce s-au schimbat valorile campurilor din CD2: Campuri din CD2: a=-17.83 b=28.16 m=127.9 Campuri din S1: a=1 b=2.45 cd.toString()=(CD2: (S1: 1 2.45 3) -17.83 28.16 127.9) S1.f4(3)=18 CD2.f4(3)=15 CD1.f4(3)=18

Remarcăm că:

- în metoda afişare() din clasa CD2 se operează corect atât cu câmpurile a şi b din clasa

CD2, cât şi cu cele ascunse de acestea din clasa S1;

- în metoda toString() din CD2 se operează direct cu câmpurile a şi b declarate în această

clasă şi cu metodele declarate în CD2 şi se opereaza indirect (folosind referinţa super) cu

câmpurile şi metodele din superclasa S1 care sunt ascunse sau redefinite în CD2;

- în expresiile S1.f4(3) şi CD1.f4(3) este invocată metoda statică a clasei S1, în timp ce în

expresia CD2.f4(3) este invocată metoda cu aceeaşi signatură a clasei CD2, care o ascunde

pe cea din clasa S1.

Page 177: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

177

Metode finale

Metodele finale sunt metode care nu mai pot fi redefinite în clasele derivate. Astfel de

metode se declară cu modificatorul final. De exemplu, în clasa Object, metoda getClass

este o metoda finală, fiind declarată sub forma public final Class getClass(). Aceasta

inseamnă că în nici o altă clasă nu este posibil ca aceasta metodă să fie redefinită. Când

declarăm propriile noastre clase, avem şi noi posibilitatea să declarăm că unele din metodele

lor sunt finale.

Declararea propriilor clase de excepţii

Deşi Java API oferă o varietate destul de mare de clase de excepţii, uneori programatorul

poate simţi nevoia să işi creeze propriile sale clase de exceptii. Aceasta se poate realiza

derivând clasele respective din clasa Exception, existentă în pachetul java.lang. Corpul

declaraţiei clasei de excepţii conţine numai declaraţii de constructori, în care se apelează

constructorul corespunzător al superclasei.

Exemplu:

În fişierul TestExceptie.java se dă ca exemplu declararea şi utilizarea clasei

ExceptieDomeniuFactorial, care este generată la calcularea funcţiei factorial(n), dacă

argumentul acesteia n este negativ. S-au creat doi constructori: unul fără argument, altul

având un argument din clasa String. Dintre aceştia a fost folosit unul singur. Puteţi modifica

programul pentru a-l utiliza şi pe al doilea.

Clase finale

Dacă se doreşte ca o clasă să nu poată avea subclase, la declararea acesteia se foloseşte

modificatorul final. De exemplu, dacă se dorea ca clasa CD1, dată ca exemplu mai sus, să

fie finala, ea trebuia declarata sub forma public final class CD1 extends S1 sau, dacă nu se dorea sa fie publica, sub forma final class CD1 extends S1

Polimorfismul

Polimorfismul se manifestă atunci când unei variabile-referinţă pentru superclasă i se

atribuie ca valoare o referinţă către o instanţă a unei subclase a acesteia, în care una sau mai

multe metode ale superclasei au fost redefinite. În limbajul Java se consideră că metodele

sunt legate dinamic (engleză: dynamic method binding). Aceasta înseamnă că stabilirea

metodei care va fi invocată se face în momentul execuţiei, fiind invocată metoda din clasa

căreia îi aparţine efectiv obiectul indicat de referinţa respectivă.

Fie A o clasă, iar B o subclasă a clasei A şi fie declaraţiile A a1, a2, a3; B b1; Object ob1, ob2, ob3;

Unei variabile referinţă dintr-o clasă, i se pot atribui ca valori referinţe la instanţe ale

Page 178: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

178

subclaselor sale. În consecinţă, pot exista instrucţiuni de atribuire de forma a1=new A(); a2=new B(); b1=new B(); a3=b1; ob1=new B(); ob2=a1; ob3=b1;

Ultimele două atribuiri sunt posibile deoarece, în limbajul Java, toate clasele sunt subclase ale

clasei Object.

Se pune întrebarea: dacă o metodă din clasa A, fie aceasta metoda1(), a fost redefinită în

clasa B, care din ele va fi executata în expresia a2.metoda1()? Observăm că, în această

expresie, variabila a2 aparţine clasei A, în timp ce obiectul indicat de această variabilă

aparţine efectiv clasei B. Conform principiului polimorfismului, va fi executata metoda1()

din clasa B.

Atenţie: polimorfismul se aplică numai metodelor de instanţă. În cazul câmpurilor statice şi

metodelor statice, care sunt redeclarate în subclasa, nu are loc o redefinire, ci o ascundere. În

consecinţă, legarea acestora este statică (la compilare), iar la execuţie se vor folosi câmpurile

şi metodele statice din clasa căreia ii aparţine variabila-referinţa, nu din clasa căreia îi

aparţine instanţa indicată de aceasta.

În atentia programatorilor de C++

În limbajul C++ polimorfismul se manifestă numai pentru metodele virtuale. Metodele care

nu au fost declarate cu modificatorul virtual sunt legate static (la compilare), deci la

execuţie se invocă în astfel de cazuri metoda clasei căreia îi aparţine variabila-referinţa (sau

pointerul) şi nu cea căreia îi aparţine obiectul indicat. Folosind conceptele din C++, se poate

considera că în limbajul Java toate metodele de instanţă sunt implicit virtuale (sunt legate

dinamic), în timp ce metodele statice nu sunt virtuale (sunt legate static).

Conversia unei referinţe la clasă într-o referinţă la subclasă

Am arătat mai sus că atribuiri de forma ob1=new B() sau ob2=a1 (unde ob1 şi ob2 sunt

variabile-referinţă la Object, iar a1 este variabila-referinţă la A) sunt permise, deoarece unei

variabile referinţă dintr-o clasa i se pot da ca valori referinţe la instanţe ale unor subclase. În

schimb, dacă încercăm să utilizăm expresia ob1.metoda1() sau ob2.metoda1() obţinem

erori de compilare, deoarece metoda1() nu există în clasa Object. Pentru a evita astfel de

erori, este necesar să convertim explicit (prin cast) referinţa la Object în referinţă la clasa A

sau B, în care există metoda1(). În acest scop, vom folosi expresiile ((B)ob1).metoda1()

sau, respectiv, ((A)ob2).metoda1().

Având în vedere că B este subclasă a lui A, iar variabila ob1 indică efectiv un obiect din clasa

B, atât în expresia ((B)ob1).metoda1(), cât şi în expresia ((A)ob1).metoda1() se va

invoca metoda1() din clasa B, adică din clasa căreia îi aparţine efectiv obiectul indicat de

variabila-referinţă ob1.

Exemplu

În fişierul Polimorf1.java se da următorul exemplu de aplicaţie în care se testează

polimorfismul, folosind clasa S1 şi subclasele ei CD1 şi CD2 definite anterior:

class Polimorf1 { public static void main(String args[]) {

Page 179: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

179

Object ob1, ob2, ob3, ob4; S1 s1a, s1b, s1c; CD1 cd1a; CD2 cd2a; String s1="sirul1"; s1a=new S1(1, 2.5, 3); cd1a=new CD1(-1, -2.5, -3); cd2a=new CD2(10, 20.5, 30, 100, 200.5, 300); s1b=cd1a; s1c=cd2a; ob1=s1; ob2=s1a; ob3=cd1a; ob4=cd2a; System.out.println("s1a="+s1a+" s1b="+s1b); System.out.println("s1c="+s1c); System.out.println("s1a.f2()="+s1a.f2()+" s1a.f3()="+s1a.f3()); System.out.println("s1b.f2()="+s1b.f2()+" s1b.f3()="+s1b.f3()); System.out.println("s1c.f2()="+s1c.f2()+" s1c.f3()="+s1c.f3()); System.out.println("ob1="+ob1+" ob2="+ob2+" ob3="+ob3); System.out.println("ob4="+ob4);

System.out.println("cd1a.f2()="+cd1a.f2()+" cd1a.f3()="+cd1a.f3()); System.out.println("cd2a.f2()="+cd2a.f2()+" cd2a.f3()="+cd2a.f3()); System.out.println("((S1)ob2).f2()="+((S1)ob2).f2()+ " ((S1)ob2).f3()="+((S1)ob2).f3()); System.out.println("((S1)ob3).f2()="+((S1)ob3).f2()+ " ((S1)ob3).f3()="+((S1)ob3).f3()); System.out.println("((CD1)ob3).f2()="+((CD1)ob3).f2()+ " ((CD1)ob3).f3()="+((CD1)ob3).f3()); System.out.println("((S1)ob4).f2()="+((S1)ob4).f2()+ " ((S1)ob4).f3()="+((S1)ob4).f3()); System.out.println("((CD2)ob4).f2()="+((CD2)ob4).f2()+ " ((CD2)ob4).f3()="+((CD2)ob4).f3()); } }

La executarea acestei aplicaţii se obţin pe ecran următoarele rezultate:

s1a=(S1: 1 2.5 3) s1b=(S1: -1 -2.5 -3) s1c=(CD2: (S1 10 20.5 30) 100.0 200.5 300.0) s1a.f2()=7 s1a.f3()=18.0 s1b.f2()=-2 s1b.f3()=-3.0 s1c.f2()=70 s1c.f3()=711.0 ob1=sirul1 ob2=(S1: 1 2.5 3) ob3=(S1: -1 -2.5 -3) ob4=(CD2: (S1 10 20.5 30) 100.0 200.5 300.0) cd1a.f2()=-2 cd1a.f3()=-3.0 cd2a.f2()=70 cd2a.f3()=711.0 ((S1)ob2).f2()=7 ((S1)ob2).f3()=18.0 ((S1)ob3).f2()=-2 ((S1)ob3)f3()=-3.0 ((CD1)ob3.f2()=-2 ((CD1)ob3).f3()=-3.0 ((S1)ob4).f2()=70 ((S1)ob4).f3()=711.0 ((CD2)ob4).f2()=70 ((CD2)ob4).f3()=711.0

Remarcăm următoarele:

- atribuiri de forma s1b=cd1a sau ob1=s1 sunt corecte, întrucât unei variabile-referinţă dintr-

o clasă i se pot da ca valori referinţe la instanţe ale subclaselor acesteia;

- expresiile s1a.f2() şi ((S1)ob2).f2() au aceeaşi valoare (7), intrucat in ambele cazuri

este invocata metoda f2() din clasa S1;

Page 180: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

180

- în expresia ((S1)ob2).f2() s-a folosit castul pentru a converti referinţa la Object intr-o

referinţă la S1, întrucat în clasa Object nu există o metoda f2();

- expresiile s1b.f2(), cd1a.f2(), ((S1)ob3).f2() şi ((CD1)ob3).f2()au aceeasi

valoare (-2), deoarece în toate cele trei cazuri metoda f2() se aplică asupra aceluiaşi obiect;

- în expresia s1b.f2() nu a fost necesar să se folosească o conversie explicită (cast) de

forma ((CD1)s1b).f2(), deoarece o metoda cu signatura f2() există şi în clasa S1, căreia îi

aparţine variabila s1b. Totuşi, în momentul execuţiei, se aplică efectiv metoda f2() din clasa

CD2, căreia îi aparţine obiectul indicat de s1b;

- în mod similar, expresiile s1c.f2(), cd2a.f2(), ((S1)ob4).f2() si

((CD2)ob4).f2() au aceeaşi valoare (70);

- în instrucţiunea System.out.println("s1a="+s1a+" s1b="+s1b); se foloseşte implicit

metoda toString()pentru a se converti obiectele indicate de variabilele-referinţă s1a şi s1b

în şiruri. Se foloseşte în ambele cazuri metoda toString() din clasa S1, deoarece în clasa

CD1 nu a fost redefinită o astfel de metodă;

- în instrucţiunea System.out.println("s1c="+s1c); se foloseşte implicit metoda

toString() din clasa CD2, căreia îi aparţine efectiv obiectul indicat de variabila s1c;

Un exemplu: clasa Persoana si subclasa Student

Studentul are toate atributele unei persoane, dar are şi atribute şi metode specifice. În

consecinţă, clasa Student poate fi derivată din clasa Persoana. În continuare dăm exemple de

declarare şi de testare a celor două clase.

Declararea clasei Persoana

În fişierul Persoana.java, reprodus aici, este declarată clasa Persoana.

public class Persoana { private String nume, prenume; private int anNastere;

public Persoana(String nume, String prenume, int anNastere) { this.nume=nume; this.prenume=prenume; this.anNastere=anNastere; }

public Persoana(Persoana pers) { nume=pers.nume; prenume=pers.prenume; anNastere=pers.anNastere; }

public String nume() { return nume; }

public String prenume() { return prenume; }

Page 181: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

181

public int anNastere() { return anNastere; }

public int varsta(int anCurent) { return anCurent-anNastere; }

public String toString() { return nume+" "+prenume+" "+anNastere; }

public int hashCode() { return nume.hashCode()+prenume.hashCode()/1000+anNastere%100; } }

Clasa contine trei câmpuri private: două referinţe la String (nume şi prenume) şi un câmp de

tip int (anNaştere). Întrucât câmpurile sunt private, ele nu sunt vizibile din alte clase (nici

chiar din subclasele clasei Persoana).

Clasa Persoana are doi constructori. Primul constructor primeşte ca argumente valorile celor

trei câmpuri: nume, prenume, anNaştere. Întrucât argumentele au aceleaşi nume cu câmpurile

corespunzătoare, în corpul constructorului numele de câmpuri sunt calificate cu referinţa

this. Aceasta se putea evita schimband numele argumentelor. Al doilea constructor are ca

argument o instanţă a clasei Persoana, fiind ceeace se numeşte un "constructor de copiere".

Vom vedea utilitatea lui in continuare, la declararea clasei Student.

Metodele nume(), prenume() şi anNastere() au rolul de a întoarce fiecare valoarea

câmpului corespunzator. Fiind publice, ele pot fi utilizate în alte clase. Aşa dar, este posibil să

obţinem în altă clasă valorile câmpurilor unui obiect Persoana, dar nu putem modifica aceste

valori. Remarcăm că este posibil ca numele unei metode să coincidă cu cel al unui câmp.

Nu are loc nici o confuzie, întrucât numele metodei este insoţit întotdeauna de paranteze, ca

în expresia p1.nume(), care are ca valoare numele persoanei p1.

Metoda varsta(int anCurent) întoarce vârsta persoanei, fiind dat ca argument anul pentru

care se calculează. Este un exemplu de metodă care întoarce un atribut al persoanei (vârsta),

care nu este memorat într-un câmp, ci se obţine prin calcul.

Metodele toString() şi hashCode() redefinesc metodele corespunzătoare ale superclasei

Object.

Declararea clasei Student

Clasa publică Student este declarată în fişierul Student.java şi este reprodusă aici.

public class Student extends Persoana { private String fac, gr; private int anStudii;

public Student(String nume, String prenume, int anNastere, String facultate, int an, String grupa) { super(nume, prenume, anNastere); fac=facultate; anStudii=an; gr=grupa;

Page 182: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

182

}

public Student(Persoana pers, String facultate, int an, String grupa) { super(pers); fac=facultate; anStudii=an; gr=grupa; }

public Student(Student stud) { super(stud.nume(), stud.prenume(), stud.anNastere()); fac=stud.fac; anStudii=stud.anStudii; gr=stud.gr; }

public String facultate() { return fac; }

public int an() { return anStudii; }

public String grupa() { return gr; }

public String toString() { return super.toString()+" fac: "+fac+" an: "+anStudii+ " grupa: "+gr; } }

Clasa Student moşteneşte câmpurile şi metodele superclasei Persoana. În plus, conţine

următoarele câmpuri private: două referinţe la String (fac - facultatea şi gr - grupa) şi un int

(anStudii).

Au fost declaraţi trei constructori. Primul are ca argumente valorile tuturor câmpurilor, atât

ale celor moştenite de la superclasă, cât şi ale celor proprii. Întrucât câmpurile superclasei

sunt private, nu a fost posibilă iniţializarea lor directă, prin operaţii de atribuire, ci prin

apelarea constructorului superclasei sub forma super(nume, prenume, anNastere);

Al doilea constructor are ca prim argument o referinţă la persoană, iar ultimele trei argumente

sunt aceleaşi ca la constructorul precedent. Pentru iniţializarea câmpurilor superclasei a fost

invocat constructorul acesteia sub forma super(pers);

în care pers este referinţa la o Persoana. S-a utilizat aici constructorul de copiere

Persoana(Persoana pers). Remarcăm că nu am fi putut utiliza instrucţiunea super(pers.nume, pers.prenume, pers.anNastere); deoarece câmpurile clasei Persoana sunt private şi nu sunt, deci, accesibile din clasa Student.

În lipsa constructorului de copiere, am fi putut utiliza in schimb instructiunea super(pers.nume(), pers.prenume(), pers.anNastere());

deoarece metodele nume(), prenume() şi anNastere() sunt publice.

Metodele publice facultate(), an() şi grupa() întorc valorile câmpurilor specifice

clasei Student, respectiv fac, anStudii şi gr.

Metoda toString() redefineşte metoda cu aceeaşi signatură a superclasei.

Page 183: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

183

Utilizarea claselor Persoana şi Student

Aplicaţia din fişierul TestStud.java are ca obiectiv testarea claselor Persoana şi Student.

class TestStud { public static void main(String args[]) { Persoana p1=new Persoana("Vasiliu","George",1981), p2; Student s1=new Student(p1, "NIE",2,"2221a"), s2=new Student("Ionescu","Maria", 1980, "NIE", 2, "2322b"), s3; Object ob1, ob2, ob3; Persoana tabPers[]=new Persoana[3]; ob1=s1; ob2=p2=s2; ob3=p1; System.out.println("p1="+p1); System.out.println("s1="+s1); System.out.println("s2="+s2); System.out.println("ob1="+ob1); System.out.println("p2="+p2); System.out.println("ob2="+ob2); System.out.println("ob3="+ob3); System.out.println("Numele lui p1: "+p1.nume()); System.out.println("Numele lui s1: "+s1.nume()); System.out.println("Numele lui ob1: "+((Persoana)ob1).nume()); s3=(Student)ob2; System.out.println("s3="+s3); System.out.println("In anul 2000, s3 are "+s3.varsta(2000)+" ani"); System.out.println("p2.hashCode()="+p2.hashCode()); System.out.println("s1.hashCode()="+s1.hashCode()); tabPers[0]=p1; tabPers[1]=s1; tabPers[2]=s2; System.out.println("Tabloul de persoane tabPers contine:"); System.out.println("Clasa lui p1: "+p1.getClass().getName()); System.out.println("Clasa lui ob2: "+ob2.getClass().getName()); for(int i=0; i<tabPers.length; i++) System.out.println(tabPers[i]); } }

Se testează funcţionarea metodelor polimorfe toString() din clasele Persoană şi Student,

funcţionarea castului de la Object la Student si funcţionarea metodei hashCode(), redefinită

în clasa Persoana şi mostenită de clasa Student. Se testează, de asemenea, metoda

getClass(), moştenita de la clasa Object. Se construieşte şi se utilizează un tablou de

referinţe la Persoana.

O variantă în care se utilizează câmpuri protejate

În fişierele Persoana1.java, Student1.java si Test1.java sunt date variante ale fişierelor

comentate mai sus, în care sunt făcute următoarele modificări:

- în clasa Persoana1 câmpurile nu mai sunt private, ci protejate;

- în clasa Persoana1 s-a introdus în plus un constructor fără argumente. Acest constructor

este necesar pentru a fi invocat implicit de constructorul clasei Student1, aşa cum vom arăta

mai jos;

- în primul constructor al clasei Student1 nu a mai fost invocat explicit constructorul clasei

Page 184: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

184

Persoana. Aceasta înseamnă că, la construirea instanţei Student1, a fost invocat implicit

constructorul fără argumente Persoana1() al superclasei. Atribuirea de valori câmpurilor

protejate ale superclasei se face, apoi, direct în corpul constructorului clasei Persoana1. S-au

folosit, în acest scop, instrucţiuni de forma this.nume=nume, întrucât numele câmpului

coincide cu cel al argumentului. Referinţa this este utilizată corect, intrucât câmpul

superclasei Persoana1 a fost moştenit de clasa Student1, ne fiind acoperit în aceasta. Se putea

folosi, însă, şi referinţa super sub forma super.nume=nume, deoarece câmpul nume aparţine,

de fapt, superclasei;

- în al doilea constructor al clasei Student1 nu a fost invocat explicit, de asemenea,

constructorul superclasei. Atribuirea de valori câmpurilor protejate ale superclasei Persoana1

s-a făcut direct în corpul clasei Student1, prin instrucţiuni de forma nume=pers.nume, unde

Pers este argumentul din clasa Persoana1;

- s-au înlocuit peste tot, în cele trei fişiere, numele de clase Persoana şi Student prin

Persoana1 şi Student1.

Complilând fişierul TestStud1.java şi executând aplicaţia TestStud1 constatăm că se obţin

aceleaşi rezultate ca în cazul aplicaţiei TestStud. Întrucât clasele Persoana1 şi Student1 sunt

publice, compilarea explicită a fişierelor respective nu este necesară, deoarece ea se face

automat când se compilează fişierul TestStud1.java.

Instanţierea clasei care conţine metoda main

Clasa care conţine metoda main este clasa principală a unei aplicaţii, deci este prima clasă

care se încarcă în maşina virtuală Java la punerea în execuţie a aplicaţiei respective. În acelaşi

timp, ea este o clasă ca oricare alta, care poate avea şi instanţe. Metoda main(), fiind statică,

nu poate utiliza direct decât câmpurile statice şi metodele statice ale acestei clase. Totuşi, în

metoda main() sau în alte metode, pot fi create instanţe ale acestei clase, putându-se astfel

utiliza şi câmpurile şi metodele de instanţă ale acestora.

Exemplu

În fişierul Aplic.java este dat un exemplu de aplicaţie, în care clasa Aplic, care conţine

metoda main(), are câmpuri şi metode statice şi de instanţă şi constructor.

/* O clasa care contine metoda main() si poate fi instantiata */

class Aplic { static int a=10; // un camp static (al clasei) double b; // camp al instantei String s; // camp al instantei

Aplic(double b, String s) { // constructorul clasei Aplic this.b=b; this.s=s; }

double f1(double x) { // o metoda (functie) de instanta return a*b+1; // se utilizeaza campul static si cel de instanta }

static int f2(int m) { // o metoda (functie) statica return m+a; // se utilizeaza numai campul static

Page 185: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

185

}

public static void main(String args[]) { String s0="sir implicit 0", s1="sir implicit 1"; Aplic a0, a1; // Doua referinte la instante ale clasei Aplic if(args.length>=1) s0=args[0]; if(args.length>=2) s1=args[1]; /* Se creaza doua instante ale clasei Aplic */ a0=new Aplic(12.47, s0); a1=new Aplic(-15.28, s1); /* Campul static a si metoda statica f2 pot fi utilizate direct, sau calificandu-le cu numele clasei sau cu referinta la o instanta */ System.out.println("a="+a+" Aplic.a="+Aplic.a+" a0.a="+a0.a+ " a1.a="+a1.a); System.out.println("f2(2)="+f2(2)+" Aplic.f2(2)="+Aplic.f2(2)+ " a0.f2(2)="+a0.f2(2)+" a1.f2(2)="+a1.f2(2)); /* Campurile si metodele de instanta se folosesc prin intermediul referintelor la instantele respective */ System.out.println("a0.b="+a0.b+" a0.s="+a0.s); System.out.println("a1.b="+a1.b+" a1.s="+a1.s); System.out.println("a0.f1(1.5)="+a0.f1(1.5)+ " a1.f1(1.5)="+a1.f1(1.5)); /* Modificam campul static a si il afisam in diferite moduri */ a=20; System.out.println("Dupa modificari:"); System.out.println("a="+a+" Aplic.a="+Aplic.a+" a0.a="+a0.a+ " a1.a="+a1.a); /* Modificam campul b din fiecare instanta si afisam */ a0.b=32.5; a1.b=-121.8; System.out.println("a0.b="+a0.b+" a1.b="+a1.b); } }

Remarcăm urmatoarele:

- clasa Aplic are câmpuri statice şi de instanţă şi alte metode statice şi de instanţă, pe lângă

metoda main();

- clasa Aplic are şi un constructor (putea avea chiar mai mulţi, sau numai pe cel implicit);

- în metoda main() se creează două instanţe ale clasei Aplic, cu referinţele a0 şi a1;

- în metodele statice main()şi f2(), câmpul static a şi metoda statica f2() pot fi utilizate

direct, sau calificându-le cu numele clasei sau cu o referinţă la o instanţă a acesteia. În toate

cazurile se obtine acelaşi rezultat;

- câmpurile şi metodele de instanţă nu pot fi utilizate direct în metoda statică main(), dar

pot fi utilizate cele ale instanţelor, calificandu-le cu referinţele la aceste instanţe, de exemplu

a0.b sau a0.f1(1.5);

- în metodele de instanţă pot fi utilizate direct atât câmpurile clasei, cât şi ale instanţei.

Astfel, în metoda de instanţă f1() se foloseşte expresia a*b+1, în care apar câmpul static a şi

câmpul de instanţă b.

Page 186: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

186

Clase abstracte

Clasele abstracte conţin în declaraţia lor modificatorul abstract. Clasele abstracte nu pot fi

instanţiate. Remarcăm însa că pot exista clase care nu pot fi instanţiate deşi nu sunt abstracte,

cum sunt, de exemplu, clasele care nu au decât constructori privaţi.

Cu toate că clasa abstractă nu poate fi instanţiată, se pot declara variabile aparţinând unor

clase abstracte. Acestor variabile li se pot da însa ca valori numai referinţe către instanţe ale

unor subclase concrete. De exemplu, daca A este o clasă abstracta, iar B este o subclasă

concreta a clasei A, atunci este corectă declaraţia A a1=new B();

Din punct de vedere conceptual, clasa abstractă modelează un concept general, care trebuie

apoi dezvoltat prin subclase. Subclasele unei clase abstracte pot fi, la rândul lor, abstracte sau

concrete. De exemplu, clasa abstractă FiguraPlana poate avea ca subclase clasele Cerc,

Elipsa, Poligon etc.

Din punct de vedere al progrămarii, clasa abstractă conţine cel puţin o metodă abstractă, adică

o metodă pentru care s-a declarat numai antetul, fără să i se definească şi corpul. O clasă

poate să conţină o metodă abstractă în mai multe moduri:

a/ în corpul clasei este declarată explicit o metodă abstractă;

b/ clasa mosteneşte de la superclasa ei o metodă abstractă, care nu este definita nici în

corpul clasei curente;

c/ clasa implementeaza o interfaţă, dar nu defineşte una sau mai multe din metodele

acesteia.

Dacă apare o astfel de situaţie, iar clasa nu este declarată în mod explicit abstractă, se

genereaza o eroare la compilare.

Declararea unei metode abstracte:

- antetul metodei trebuie sa conţina modificatorul abstract;

- corpul metodei se înlocuieşte prin caracterul ';' (punct şi virgulă).

Exemplu:

În fişierul FiguriPlane.java sunt declarate clasa abstractă FiguraPlana şi clasele instanţiabile

Cerc şi Patrat. Este declarată, de asemenea clasa-aplicaţie în care se testează aceste clase.

Page 187: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

187

Interfeţe

Conceptul de interfaţă

Conform principiului încapsulării, fiecare clasă are "interfaţa" sa intrinsecă, prin care poate fi

accesata din exterior. Aceasta "interfaţă" conţine toate datele şi metodele publice ale clasei

respective.

Pentru a compensa lipsa moştenirii multiple, în limbajul Java s-a admis că o clasă poate avea

mai multe interfeţe şi că mai multe clase pot implementa aceeaşi interfaţă. S-a introdus astfel

o nouă categorie de componente, numite interfeţe, care se declară în mod asemănător cu nişte

clase abstracte, dar nu sunt înglobate, aşa cum sunt clasele abstracte, în ierarhia unică de

clase .

Interfaţa este o specificaţie care descrie metodele publice şi variabilele finale publice pe care

trebuie sa le aibă o clasă care implementeaza interfaţa respectivă. Dacă o clasă

implementează mai multe interfeţe, ea conţine toate metodele publice şi variabilele finale

publice ale acestora.

Interfaţa nu este o clasă, dar poate fi utilizată de programator ca şi când ar fi o clasă

abstractă. Se pot declara variabile referinţă la o interfaţă în mod asemănător cu declararea

variabilelor referinţa la obiecte aparţinând unei clase, adică sub forma:

interfaţa nume_variabila1[=initializare1], ...,

nume_variabilaN[=initializareN];

în care interfaţa este numele unei interfeţe, iar celelalte elemente ale declaraţiei sunt

aceleaşi ca în cazul declarării de referinţe la obiecte. Interfeţele pot fi şi ele organizate

ierarhic, aplicându-se principiul moştenirii. În schimb, pentru interfeţe, ierarhia nu mai este

unică, aşa cum este în cazul claselor, şi se admite moştenirea multiplă.

Remarcam că, la fel ca şi clasele abstracte, interfeţele nu pot fi instanţiate. În schimb, unei

variabile referinţă la o interfaţă i se pot da ca valori referinţe către obiecte din orice clasă care

implementează acea interfaţă sau este descendentă a unei astfel de clase.

Pentru a le distinge mai uşor, în documentaţia Java API numele interfeţelor sunt scrise cu

litere cursive (stil italic), în timp ce numele claselor sunt scrise cu litere normale (drepte). De

exemplu, în pachetul java.lang există interfaţa Cloneable care este implementată de toate

clasele din SDK care implementează metoda clone(), deci ale căror obiecte pot fi clonate.

Sa considerăm acum exemplul din Figura 1, în care clasele B şi C implementeaza interfeţele

I1 şi I2, iar clasele C si D implementează interfeţele I2 şi I3.

Page 188: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

188

- Figura 1 -

În acest exemplu, interfetele I1 şi I2 sunt derivate din interfata I0 deci moştenesc variabilele

finale şi metodele acesteia, putând avea fiecare, de asemenea, date finale, câmpuri şi metode

proprii. Clasa B implementează interfaţa I1, deci conţine variabilele finale şi metodele

interfeţei I1 şi pe cele mostenite de aceasta de la interfaţa I0. Clasa C implementează

interfeţele I1 şi I2, deci conţine variabilele finale şi metodele interfeţelor I1 şi I2, inclusiv pe

cele moştenite de acestea de la interfaţa I0. Totodată, clasele A, B şi C moştenesc datele şi

metodele clasei A. Faptul că variabilele finale şi metodele interfeţei I0 se propagă la clasa C

atât pe traseul I0-I1-C, cât şi pe traseul I0-I2-C nu mai produce dificultăţi, ca în cazul

moştenirii multiple a claselor, deoarece implementarea efectivă a acestor variabile şi metode

se face în clasa C şi nu in interfeţe.

Pentru exemplul din Figura 1, să considerăm acum următoarele declaraţii şi instrucţiuni de

atribuire valabile, în care A(), B(),C() si D() sunt constructori ai claselor respective:

A v1=new A(), v2; B v3=new B(), v4; C v5=new C(), v6; I0 w1=new B(),w2; I1 w3=new C(), w4; I2 w5, w6; v2=v5; w2=new D(); v4=v3; w4=v3; v6=new C(); w5=v6; w2=w4;

Constatăm că variabilele referinţă la interfeţe (w1, w2, w3 etc.) sunt utilizate la fel ca şi

variabilele referinta la obiecte ale claselor. Dacă, insă, ştiind că variabila w1 are ca valoare o

referinţă la un obiect din clasa B, vom dori sa folosim instrucţiunea v4=w1; vom constata că apare o eroare de compilare, deoarece v4 este referinţă la un obiect al unei

clase, în timp ce w1 este o referinţă la interfaţă. În această situaţie este necesară o conversie

explicită (cast), astfel că vom folosi instrucţiunea v4=(B)w1;

Page 189: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

189

Declararea interfeţelor

O declaraţie de interfaţă introduce un nou tip referinţă, ai cărui membri sunt câmpuri statice

finale şi metode abstracte. În consecinţă, interfaţa se aseamănă cu o clasa abstractă pură,

care nu conţine decât metode abstracte şi câmpuri statice finale şi nu se încadrează în ierarhia

unică de clase descendente din Object (amintim ca o clasa abstractă, în afară de una sau mai

multe metode abstracte, poate conţine şi câmpuri de date şi metode concrete şi este

descendentă a clasei Object).

Deşi nu se încadrează în ierarhia claselor, interfeţele se pot constitui in diverse ierarhii de

interfeţe, aplicându-li-se principiul mostenirii. O clasă poate implementa mai multe interfeţe.

Cel mai important avantaj al folosirii interfeţelor este că mai multe clase, de pe diferite

ramuri ale arborelui ierarhic al claselor, pot fi "văzute" printr-o singură interfaţă. Se pot

declara variabile referinţă la interfaţă la fel cum se pot declara variabile referinţă la clasă.

Interfaţa este abstractă şi deci nu poate fi instanţiată. În schimb, unei variabile referinţă la

interfaţă i se pot atribui ca valori referinţe la obiecte din orice clasă care implementează

interfaţa respectivă.

Declaraţia de interfaţă are forma generală următoare:

[public] interface NumeInterfata [extends lista_superinterfete] { declaratii_de_membri_ai_interfetei }

În afară de modificatorul public, se poate folosi şi modificatorul abstract, numai că

acesta este implicit, deci folosirea lui este de prisos.

Spre deosebire de clase, la care moştenirea multiplă este interzisă (o clasă poate avea numai o

singura superclasă), în cazul interfeţelor moştenirea multiplă este permisă. În consecinţă,

clauza extends poate conţine o listă de nume de interfeţe separate prin virgule.

Corpul interfeţei conţine una sau mai multe declaraţii de membru al interfeţei.

Declaraţiile de membri ai interfeţei pot fi:

a/ Declaraţia de câmpuri statice finale, numită şi declaraţie de constante, sub forma:

tip NUME_CAMP1=valoare1,NUME_CAMP2=valoare2,... , NUME_CAMP_N=valoareN;

în care tip este un tip primitiv. Modificatorii public, static şi final pentru câmpurile

interfeţei sunt impliciţi, deci folosirea lor este de prisos. Aceasta înseamnă că toate

câmpurile unei interfeţe sunt publice, statice şi finale, deci ele trebuie să fie iniţializate la

declarare şi nu mai pot fi modificate ulterior. Se obisnuieşte ca numele de câmp ale

interfeţelor să fie scrise numai cu majuscule.

Exemplu: interface CuloareDeBaza { int ROSU=1, VERDE=2, ALBASTRU=4; }

Page 190: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

190

interface Culoare extends CuloareDeBaza { int GALBEN=3, ORANGE=5, INDIGO=6, VIOLET=7; }

b/ Declaraţia de metodă abstractă, care constă din antetul metodei urmat de simbolul ';'

(punct şi virgulă). Ea este deci la fel ca o declaraţie de metodă abstractă din corpul unei clase,

cu următoarele observaţii:

- modificatorii public şi abstract sunt impliciti, deci folosirea lor este de prisos (dar

este permisă);

- modificatorul final nu poate fi folosit, deoarece se declară o metodă abstractă;

- corpul metodei este înlocuit prin simbolul punct şi virgulă, ca la orice metodă abstractă.

Exemplu: interface Interf1 { double metoda1(); int metoda2(int a, int b, double c); }

Ambele metode din exemplul de mai sus sunt implicit publice şi abstracte. Orice clasă, care

implementează aceasta interfaţă, trebuie sa conţină declaraţii de metode cu aceeaşi semnătură

cu cele din interfaţă. La definirea acestor metode îm cadrul claselor, folosirea

identificatorului public este obligatorie.

Clase imbricate şi clase interioare

În limbajul Java se permite ca o clasă să aibă ca membri alte clase. Acestea se numesc clase

imbricate sau clase încuibate (engleza: nested classes). Ca şi ceilalţi membri, clasele

imbricate pot fi statice sau nestatice şi se declară în corpul clasei care le încorporează. Clasele

imbricate nestatice se numesc clase interioare (engleză: inner classes). O clasă care

încorporează (imbrică) alte clase se declară astfel:

[public] class NumeClasa { declaratii_de_membri_ai_clasei [modificatori_de_camp] class NumeClasaImbricata { declaratii_de_membri_ai_clasei_imbricate } declaratii_de_membri_ai_clasei }

Se recurge la aceasta tehnică atunci când utilizarea unei clase are sens numai în cadrul altei

clase. Aşadar, prin imbricare se creează o legatură strânsa între două clase. Este posibil,

desigur, ca o clasa să conţină mai multe clase imbricate. Remarcăm că declaraţia clasei

imbricate este tratata ca oricare alta declaraţie de membru al clasei, putând avea şi

modificatori de câmp (de exemplu static).

Fiind membru al clasei, clasa imbricată are acces la toţi membrii clasei care o conţine, chiar şi

la cei privaţi. Dacă clasa imbricată este statică, ea nu poate referi direct decât membrii statici

Page 191: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

191

ai clasei care o conţine. Clasa imbricată statică există, la fel ca şi câmpurile sau metodele

statice, numai în cadrul clasei care o conţine, nu şi în instanţele acesteia. În consecinţă, pentru

a referi membrii acestei clase, se foloseşte pentru calificare numele clasei.

Clasa interioară (clasa imbricată nestatică) are câte o instanţă în interiorul fiecărei instanţe a

clasei care o conţine. În consecinţă, accesul la membrii ei se poate face folosind drept

calificator referinţa la o instanţă. Clasa interioară are acces la toţi membrii clasei care o

conţine, atât la cei statici, cât şi la cei de instanţă (nestatici).

Exemplu:

În secţiunea Interfeţe a acestui curs, a fost dat un exemplu de aplicaţie (din fişierul

Integrare.java), în care se face integrarea funcţiilor prin metoda trapezelor. În fişierul

Integrare.java, toate clasele sunt declarate în mod obişnuit, ca nişte clase autonome. În

consecinţă, după compilare se obţin urmatoarele fişiere cu extensia class: Functie1.class,

FunctieReala.class, Integrare.class, Integrator.class, IntegrareTrapeze.class.

Clasa IntegrareTrapeze poate fi folosită în diferite aplicaţii, deci are sens să fie declarată ca o

clasa separată. În schimb, clasa Funcţie1 este specifica numai unei singure aplicaţii. Este deci

preferabil să fie declarata ca o clasă interioară a acestei aplicaţii, aşa cum se face în fisierul

Integrare1.java.

Clasa Functie1, din acest exemplu, a fost declarată ca o clasa interioară (clasă imbricată

nestatică) a clasei-aplicaţie Integrare1. În consecinţă, accesul la membrii ei se poate face

numai printr-o instanţă a clasei Integrare1. În acest scop, s-a procedat astfel:

a/ s-a creat în metoda main() o instanţă a clasei Integrare1 prin instrucţiunea Integrare1 int1=new Integrare1(); b/ s-a creat o instanţă a clasei Functie1 prin instrucţiunea Functie1 f1=int1.new Functie1(arg1,arg2,arg3,arg4);

c/ Referinţa f1 la o instanţă a clasei interioare f1 a fost apoi utilizată în mod obişnuit, ca

argument al metodei integrare();

Atragem atenţia asupra modului cum s-a făcut instanţierea clasei interioare Functie1:

operatorul new a fost calificat cu referinta int1 la o instanţă a clasei Integrare1, care o

conţine. Procedeul de mai sus a fost necesar, întrucat metoda main() este statică, astfel că nu

poate accesa direct un membru nestatic al clasei, ci numai prin crearea unei instanţe a

acesteia.

Pentru comparaţie, în acelaşi fişier s-a declarat (tot în clasa-aplicaţie Integrare1) şi o clasa

imbricată statică numită Functie2. Remarcăm că instanţierea acesteia s-a făcut în mod

"obişnuit" prin instrucţiunea Functie2= func2=new Functie2(arg1,arg2,arg3);

iar utilizarea funcţiei statice f2() conţinute în aceasta s-a facut sub forma "obişnuită"

Functie2.f2(arg1,arg2) . De asemenea, utilizarea funcţiei nestatice f() a acestei clase s-a

făcut "obişnuit", sub forma func2.f(arg), iar instanţa func2 a fost transmisă şi ca argument

al metodei de integrare.

După compilarea fişierului Integrare1.java, constatăm că au fost creeate următoarele fişiere

cu extensia class: FunctieReala.class, Integrare1.class, Integrare1$Functie1.class,

Page 192: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

192

Integrare1$Functie2.class, IntegrareTrapeze.class, Integrator.class. Remarcam ca numele

fişieror de bytecode care conţin clase imbricate sau interioare încep prin numele clasei care

le conţine, urmat de caracterul $ şi de numele clasei imbricate (interioare) respective. În acest

fel, devine posibil ca în două aplicaţii distincte să existe clase imbricate sau interioare cu

acelaşi nume, fără să se creeze confuzii.

Page 193: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

193

Exemplu de declarare, implementare şi utilizare a unor interfeţe

Considerăm că dorim să realizăm diferite clase de integratoare numerice, care calculează prin

diferite metode valoarea integralei pe intervalul [inf, sup] a funcţiei reale f(x). Dorim ca,

în oricare din aceste integratoare, să existe metoda de calculare a integralei: double integrala(double inf, double sup, FunctieReala func)

în care inf şi sup sunt, respectiv, marginea inferioara şi cea superioara a intervalului de

integrare, iar func este o referinţă la un obiect care contine funcţia de integrat f(x). Având în

vedere că nu avem, deocamdată, în vedere o metoda de integrare numerică particulară, vom

declara interfaţa

interface Integrator { double integrala(double inf, double sup, FunctieReala func); }

în care metoda de integrare apare ca o metoda abstractă.

Cu aceasta ocazie remarcam că, spre deosebire de limbajele de programare tradiţionale, cum

sunt Pascal sau C/C++, în limbajul Java nu există posibilitatea ca o funcţie (metodă) să aibă

ca argument o referinţa la altă funcţie (metodă). În schimb, putem să-i oferim ca argument o

referinţa la un obiect care conţine funcţia respectivă. Astfel, în cazul nostru, func este

referinţă la un obiect care conţine funcţia de integrat f(x). Având în vedere că dorim ca

integratoarele noastre să fie valabile pentru orice funcţie reală f(x), vom declara o interfaţă:

interface FunctieReala { double f(double x); }

care conţine metoda abstractă f(x) pe care trebuie să o conţină orice obiect pe care îl oferim

ca argument metodei de integrare din interfaţa Integrator.

Să realizăm acum un integrator concret, pentru o anumita metodă particulară de integrare.

Pentru simplitate, vom implementa integrarea prin metoda trapezelor. Ştiind că integrala

poate fi interpretată geometric ca aria suprafeţei cuprinse între graficul funcţiei respective şi

axa ox, putem împărţi intervalul de integrare [inf, sup] în n subintervale de lungime egala

h=(sup-inf)/n, ca în Figura 1.

Page 194: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

194

- Figura 1 -

Înlocuind pe fiecare din aceste subintervale curba f(x) prin coarda ei, obtinem n trapeze.

Considerand că ariile cuprinse între curbă şi coarda curbei în fiecare din subintervale sunt

mici, aproximăm aria de sub curbă prin suma ariilor celor n trapeze. Se obţine astfel pentru

calcularea integralei I cunoscuta formulă a integrării numerice prin metoda trapezelor dată în

Figura 2.

- Figura 2 -

Pentru calcularea integralei este necesar să se impună şi numărul de paşi n, pe care îl vom

nota în continuare cu nrPasi. Putem astfel declara clasa IntegrareTrapeze, care

implementeaza interfaţa Integrator, în modul următor:

class IntegrareTrapeze implements Integrator { int nrPasi; // Numarul de pasi de integrare /* Constructorul initializeaza numarul de pasi de integrare */ public IntegrareTrapeze(int nrPasi) throws Exception { if(nrPasi<=0) throw new Exception("IntegrareTrapeze:

nrPasi<=0"); this.nrPasi=nrPasi; } /* Metoda de modificare a numarului de pasi de integrare */ public void puneNrPasi(int nrPasi) throws Exception { if(nrPasi<=0) throw new Exception("IntegrareTrapeze:

nrPasi<=0"); this.nrPasi=nrPasi; } /* Implementarea metodei abstracte din interfata Integrator */ public double integrala(double inf, double sup, FunctieReala func)

{ double h, s; h=(sup-inf)/nrPasi; // h este pasul de integrare /* Calcularea sumei ordonatelor s */ s=0; for(int i=1; i<nrPasi; i++) s+=func.f(inf+i*h);

Page 195: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

195

/* Calcularea valorii integralei si intoarcerea rezultatului */ return ((func.f(inf)+func.f(sup))/2+s)*h; } }

La calcularea integralei s-a aplicat formula din Figura 2, luând în consideraţie că

xi=inf+i*h. Remarcăm că funcţia f(x) nu a fost încă precizată. S-a indicat numai sub forma

func.f(inf+i*h) că se foloseşte funcţia (metoda) f(x) a obiectului func, care

implementează interfaţa FunctieReala. Integratorul nostru are deci o utilizare foarte largă,

putând integra funcţia f(x) din orice obiect care implementează această interfaţă. Remarcăm,

de asemenea, că putem aplica şi alte metode de integrare numerică, dacă creem pentru fiecare

din aceste metode o clasa care implementează interfaţa Integrator.

Să considerăm acum că dorim să integrăm funcţia f(x)=a*sin(b*x+c)+d*cos(b*x) în careparametrii a, b, c şi d sunt numere reale. Pentru aceasta vom creea o clasă care

implementează interfaţa FunctieReala şi, totodată, conţine drept câmpuri parametrii funcţiei:

class Functie1 implements FunctieReala { private double a, b, c, d; // parametrii functiei /* Constructorul clasei introduce valorile parametrilor functiei */ public Functie1(double a, double b, double c, double d) { this.a=a; this.b=b; this.c=c; this.d=d; } /* implementarea metodei abstracte din interfata */ public double f(double x) { return a*Math.sin(b*x+c)+d*Math.cos(b*x); } }

Putem acum să scriem o aplicaţie în care se calculează integrala acestei funcţii. În fişierul

Integrare.javasunt date atât declaraţiile de interfeţe şi clase prezentate mai sus, cât şi cea a

clasei-aplicaţie în care se folosesc acestea.

Întrebări

Nivel 1

1. Ce este încapsularea?

2. Care sunt modificatorii de acces pentru câmpuri şi metode?

3. Ce sunt constructorii?

4. Ce particularităţi prezintă declaraţiile de constructori?

5. Poate avea o clasă mai multi constructori? cum se disting aceştia?

6. Ce este constructorul implicit?

7. Ce este agregarea?

8. Ce este moştenirea?

Page 196: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

196

9. Ce relaţie există între o clasă şi superclasa ei?

10. Câte superclase poate avea o clasă în limbajul Java?

11. Ce sunt membrii protejaţi ai clasei?

12. Ce sunt this si super?

13. Ce particularităţi prezintă constructorul unei clase derivate?

14. Ce se înţelege prin redefinirea metodelor?

15. Ce fel de metode pot fi redefinite?

16. Ce este o metodă finală?

17. Ce se înţelege prin ascunderea câmpurilor?

18. În ce situaţie o metoda poate fi ascunsă?

19. Este posibilă declararea unei clase de excepţii proprie?

20. Ce este o clasă finală?

21. Ce este polimorfismul?

22. În ce situaţii se manifestă polimorfismul?

23. Cum se face conversia unei referinţe dintr-o clasa în referinţă dintr-o subclasă?

24. Poate fi instanţiata clasa care conţine metoda main()?

25. Ce este o clasă abstractă?

26. Ce este o metodă abstractă?

27. Cum se declară o clasă abstractă?

28. Ce este o interfaţă?

29. Ce efect are faptul că o clasă implementează o interfaţă?

30. Ce este o clasa imbricată?

31. Ce este o clasa interioară?

Nivel 2

1. Enumeraţi caracteristicile obiectelor şi claselor

2. Ce se înţelege prin identitatea obiectelor?

3. Ce se înţelege prin clasificare, ca proprietate a obiectelor?

4. Ce este moştenirea?

5. Ce fel de moştenire este permisă în limbajul Java în cazul claselor?

6. Ce se înţelege prin ascunderea câmpurilor?

7. Cum poate fi accesat dintr-o clasă un câmp ascuns al superclasei?

8. Este posibil să utilizăm într-o clasă un membru privat al superclasei?

9. Este posibil să declarăm într-o clasă o metodă cu aceeaşi signatură ca o metodă

privată din superclasă?

10. Ce se întâmplă dacă un argument sau o altă variabilă locală a unei metode are acelaşi

nume cu un câmp al clasei respective?

11. Cum putem utiliza într-o metodă a unei clase un câmp ascuns al propriei clase?

12. Sa considerăm că în subclasa B a clasei A a fost redefinită metoda met(); cum putem

utiliza în B metoda met() din A?

13. Ce este o metoda statică?

14. Ce se întâmplă dacă într-o clasă se declară o metodă statică cu aceeaşi signatura ca a

unei metode statice din superclasă?

15. Cum poate fi invocată o metodă statică?

16. Cum poate fi invocată o metodă de instanţă?

17. Daţi un exemplu de declarare a unei clase de excepţii.

18. Ce metode, în limbajul Java, nu sunt supuse polimorfismului?

Page 197: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

197

19. Daţi un exemplu de situaţie în care trebuie folosit castul pentru a converti o referinţă.

20. În ce scop au fost definite în clasa Object metodele equals() şi toString()?

21. Să considerăm că clasa A conţine atât metoda main(), cât şi un câmp nestatic a şi o

metodă nestatica met(). Cum putem utiliza în main câmpul a şi metoda met()?

22. Ce asemănări şi deosebiri există între interfeţe şi clasele abstracte?

23. Poate exista moştenire multiplă în cazul interfeţelor?

24. Care sunt proprietăţile implicite ale câmpurilor unei interfeţe?

25. Care sunt proprietăţile implicite ale metodelor unei interfeţe?

26. Poate fi declarată ca finală o metodă a unei interfeţe? Justificati răspunsul.

27. Ce avantaj prezintă declatrarea interfeţei Integrator ca o interfaţă şi nu ca o clasă?

28. Ce avantaj prezintă folosirea unei interfeţe ca argument al unei metode?

29. Ce deosebire există între clasa imbricată şi clasa interioară?

Page 198: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

198

Interfeţe utilizator grafice şi programarea

orientată pe evenimente

Interfeţe utilizator grafice; 198

Interfaţa utilizator grafică a unei aplicaţii 200

Clasa Component 200

Un exemplu introductiv de interfaţă utilizator grafică 201

Programarea orientată pe evenimente 203

Modelul de evenimente de pe platforma Java 2 204

Clase de evenimente 205

Interfeţe şi clase adaptoare pentru ascultători de evenimente 206

Evenimentele generate de o fereastră 206

Terminarea aplicatiei la inchiderea ferestrei; utilizarea clasei

WindowAdapter

208

Evenimente de mouse 209

Evenimente de tastă 213

Adăugarea unei componente la fereastra principală a aplicaţiei 216

Gestionarea poziţionării componentelor 219

Clasa BorderLayout 220

Clasa FlowLayout 222

Clasa GridLayout 226

Clasa BoxLayout 228

Poziţionarea absolută a componentelor (fără gestionar de

poziţionare)

231

Gruparea componentelor prin utilizarea containerelor auxiliare 233

Clasele Panel si JPanel 234

Clasa Box 235

Întrebări. 237

Interfeţe utilizator grafice

Interfaţa utilizator, numită şi interfaţa om-maşină, este mijlocul de comunicare între un

sistem informatic şi utilizator.

În programare, conceptul de interfaţă utilizator a apărut în legătură cu utilizarea programelor

în regim interactiv. Un asemenea regim permite utilizatorului să comunice cu procesul de

calcul în timpul desfăşurării acestuia.

În prezent, se cunosc două tipuri principale de interfeţe utilizator:

- interfaţa prin linie de comandă;

Page 199: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

199

- interfaţa grafică.

În modul de comunicare prin linie de comandă, operatorul uman transmite calculatorului

comenzi, pe care le introduce de la tastatură sub forma unor linii de text, folosind un anumit

limbaj de comandă. Exemplele cele mai cunoscute sunt limbajele de comandă ale sistemelor

de operare MS-DOS şi Unix.

Interfaţa utilizator grafică (engleză: GUI - graphical user interface) este o interfaţă om-

maşină care permite operatorului să dea comenzi şi să introducă date prin acţionarea asupra

unor obiecte grafice vizualizate pe ecran: butoane, pictograme, meniuri etc.

Interfaţa utilizator grafică a fost introdusă pentru prima dată la Palo Research Center al

firmei Xerox în anii 1970 şi a fost apoi aplicată de firma Apple pe calculatoarele Macintosh

în 1984. În prezent, cele mai răspândite interfeţe utilizator grafice sunt sistemul Windows al

firmei Microsoft şi cele de tip X-Window folosite în sistemele de operare din categoria Unix.

Un avantaj important al platformei Java 2 este că oferă pachete de clase, care permit

programatorului realizarea comodă şi eficientă a interfeţelor grafice. În prezent, există două

grupuri de pachete de clase pentru interfeţe grafice, care corespund la două principii diferite

de realizare a interfeţei:

1. AWT (engleză: Abstract Windowing Toolkit - setul de dezvoltare de ferestre abstracte) -

este un set de clase care permit realizarea de interfeţe grafice în care se folosesc obiectele

grafice specifice platformei pe care se execută programul. Aceasta înseamnă că, dacă

programul se execută - de exemplu - sub Windows, diferitele obiecte grafice (butoane,

meniuri, bare de defilare etc.) vor avea aspectul specific sistemului Windows, în timp ce dacă

se executa sub X-Window vor avea aspectul specific acestui sistem.

Principalele pachete utilizate în acest set sunt: java.awt,java.applet,java.awt.color si

java.awt.event. Acestea se completează şi cu alte subpachete ale pachetului java.awt, care

sunt descrise în documentaţia Java API.

2. JFC (engleză: Java Foundation Classes - clase de bază Java), este un set de pachete de

clase, care extind posibilităţile oferite de AWT, pentru realizarea de interfeţe utilizator de

calitate superioară. Dintre acestea, cele mai larg folosite constituie setul cunoscut sub numele

de cod Swing (sau JFC/Swing), care oferă posibilitatea de a realiza interfeţe grafice al căror

aspect nu depinde de platforma pe care se execută programul.

Principalele pachete din JFC/Swing sunt javax.swing şi javax.swing.event, la care se adaugă

multe alte subpachete ale pachetului javax.swing descrise în documentaţia Java API.

Este important să menţionăm că pachetele din JFC/Swing nu se substituie, ci le completează

pe cele din AWT. Modul de realizare al interfeţei grafice folosind AWT este prezentat destul

de amplu in lucrarea "Interfaţa grafica utilizator în limbajul Java". În cursul de faţă ne vom

referi în special realizarea interfeţei grafice utilizator folosind JFC/Swing şi vom folosi

Page 200: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

200

clasele din AWT numai acolo unde va fi absolut necesar.

Se ştie că autorii limbajului Java şi-au propus ca programele scrise în acest limbaj să poată fi

executate pe orice platformă. Sub acest aspect, realizarea interfeţei grafice a ridicat probleme

dificile deoarece, pe diferite platforme, atât setul de obiecte grafice utilizate, cât şi aspectul

acestora, pot fi diferite.

La realizarea setului de dezvoltare AWT s-a acceptat ideea că în program se lucrează cu nişte

obiecte grafice abstracte, care sa fie comune tuturor platformelor. Obiectul grafic abstract, aşa

cum este el luat în consideraţie în AWT, se caracterizează prin anumite atribute şi un anumit

comportament, dar aspectul său pe ecran poate sa difere de la o platformă la alta.

Avantajul utilizării AWT este că utilizatorul vede pe ecran obiectele care compun interfaţa

grafică sub forma cu care el este obişnuit pe platforma pe care lucrează. La aceasta se adaugă

şi faptul că AWT se înţelege şi se utilizează relativ usor. Dezavantajul este că o astfel de

interfaţă nu poate folosi decât obiectele grafice existente pe toate platformele (mulţimea de

clase de obiecte grafice din AWT este "intersecţia" mulţimilor de clase grafice de pe diferite

platforme), ceeace restrânge posibilitatea programatorilor de a realiza interfeţe utilizator

diversificate şi originale.

Autorii setului de dezvoltare JFC/Swing au decis să realizeze un set de clase de interfaţă care

sunt complet independente de platformă. În acest scop, s-a renunţat la metodele native,

clasele Swing fiind programate total în Java. Unele din aceste clase le extind sau le dublează

pe cele din AWT, iar altele sunt complet noi. Mai mult, se dă posibilitatea programatorului să

dezvolte propriile sale clase de obiecte grafice prin extinderea celor existente. Este drept insă

că aceasta se plăteşte prin creşterea complexităţii interfeţei grafice şi a nivelului de

competenţă cerut de la programator.

Interfaţa utilizator grafică a unei aplicaţii

Orice interfaţă utilizator grafică este un obiect grafic structurat, în alcătuirea căruia intră

componente grafice. În sistemele AWT şi JFC/Swing, toate componentele grafice fac parte

din clase care constituie un arbore, a cărui rădăcină este clasa Component. Deosebim

componente atomice şi containere. Containerele sunt componente grafice care conţin alte

componente. Containerele aparţin unor clase care formează o ierarhie, a cărei rădăcină este

clasa Container. Clasa Container este derivată din clasa Component. Aceasta înseamnă ca

orice container este o el însuşi componentă, deci un container poate să conţină alte

containere.

Clasa Component

Având în vedere că întreaga ierarhie de clase de obiecte de interfaţă utilizator grafică folosite

în Java (atât cele din AWT, cât şi din JFC/Swing) are ca rădăcină clasa Component, este util

să începem studiul cu această clasă.

Componenta este un obiect grafic care este afişabil pe ecran şi poate interacţiona cu

utilizatorul.

Page 201: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

201

Clasa Component este o clasă abstractă, derivată direct din clasa Object.

Dintre numeroasele metode ale acestei clase, prezentăm aici numai câteva mai frecvent

folosite:

public boolean isVisible() - testează dacă această componentă este vizibilă, atunci

când este vizibil şi containerul în care se găseşte;

public void setVisible(boolean visible) - face componenta sa fie vizibilă sau

nu, după cum argumentul este true sau false;

public boolean isShowing() - determină dacă componenta este efectiv afişată pe

ecran;

public Point getLocation() - întoarce locaţia componentei (poziţia colţului din

stânga sus în containerul-părinte) sub forma unei instanţe a clasei Point;

public void setLocation(Point location) - setează noua poziţie a componentei

în cadrul containerului părinte;

public Dimension getSize() - întoarce dimensiunea componentei;

public void setSize(int latime, int inaltime) - setează noile dimensiuni ale

componentei.

În aceste metode se utilizează şi clasele auxiliare Point şi Dimension din pachetul java.awt.

Instanţele clasei Point conţin coordonatele unui punct. Se consideră că originea sistemului de

coordonate se află în colţul din stânga sus, axa Ox este orientată către dreapta, iar axa Oy este

orientata în jos. Instanţele clasei Dimension conţin dimensiunile componentei: lăţimea şi

înălţimea.

O prezentare mai amplă a metodelor acestei clase este dată în indexul de clase. Descrierea

completă este dată în documentaţia Java API.

Un exemplu introductiv de interfaţă utilizator grafică

Întrucât interfaţa grafică conţine componente, ea este un container. Vom studia ulterior

diferite clase de containere dar, deocamdată, ne vom opri asupra clasei JFrame, care se

foloseşte în aplicaţiile Java.

În sistemul JFC/Swing, interfaţa utilizator grafică a unei aplicaţii este o instanţă a clasei

JFrame din pachetul javax.swing, sau este o subclasă a acesteia. În mod obişnuit, instanţele

clasei JFrame sunt ferestre care au la partea superioara o bară de titlu. În partea stângă a barei

de titlu există un buton, la apăsarea căruia se desfaşoară un menu cu urmatoarele opţiuni:

Restore, Move,Size, Minimize, Maximize, Close. Cînd meniul este desfăşurat, acste opţiuni

pot fi selectate cu mouse-ul sau acţionând tasta corespunzătoare literei subliniate. La partea

dreaptă a barei de titlu exista trei butoane, care au acelasi efect ca opţiunile Minimize,

Maximize şi Close din meniul menţionat.

Selecţionarea opţiunilor sau acţionarea butoanelor din bara de titlu produce asupra ferestrei

efectul corespunzător. Fereastra poate fi deplasată pe ecran dacă punem cursorul mouse-lui

Page 202: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

202

pe bara de titlu şi o tragem, ţinând butonul de mouse apăsat. Dimensiunile ferestrei pot fi

modificate trăgând cu mouse-ul oricare din laturile sau din colţurile ei.

Modul cel mai simplu de a realiza o aplicaţie cu interfaţă grafică este să folosim direct o

instanţă a clasei javax.swing.JFrame, care extinde clasa Frame din AWT. Clasa are o

structură destul de complicată şi este descrisă complet în documentaţia Java.API. Pentru a nu

intra de la început în detalii, vom da, deocamdată, numai cateva informaţii strict necesare

pentru folosirea acestei clase, urmând să revenim ulterior cu indicaţii suplimentare.

Principalul constructor este: JFrame(String titlu)

unde titlu este titlul ferestrei.

Clasa JFrame are numeroase metode, atât proprii, cât şi moştenite de la superclasele ei. În

afară de metodele moştenite de la clasa Component, deocamdată, vom mai menţiona aici

numai două, care sunt moştenite de la clasa Frame:

public String getTitle() - întoarce titlul ferestrei;

public void setTitle(String titlu) - pune ferestrei un titlu (în locul celui

existent).

La crearea ei, instanţa clasei JFrame nu este vizibilă. Pentru a o face vizibilă se foloseşte

metoda public void setVisible(boolean visible) a clasei Component.

Constructorii şi metodele clasei Frame se gasesc în indexul de clase. Descrierea completă se

găseşte în documentaţia Java API.

Exemplu: introducerea unui JFrame într-o aplicaţie

În fişierul TestJFrame1.java este dat un exemplu de aplicaţie care are o interfaţă utilizator din

clasa JFrame. Iată conţinutul acestui fişier:

import java.awt.*; import javax.swing.*;

class TestJFrame1 { static JFrame iug;

public static void main(String args[]) throws Exception { iug=new JFrame("Exemplu de JFrame"); iug.setSize(300,100); iug.setLocation(new Point(100,50)); iug.setVisible(true); System.out.println("Titlul ferestrei este: "+iug.getTitle()); System.out.println("Coltul din stanga sus este in punctul: "+ iug.getLocation()); System.out.println("Dimensiunile ferestrei: "+iug.getSize()); } }

Page 203: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

203

În prima linie este importat pachetul javax.swing, care conţine principalele clase ale

JFC/Swing, inclusiv clasa JFrame.

În clasa TestJFrame1 (care este aplicaţia noastră), s-a declarat câmpul static iug, care este o

referinţă la JFrame. În prima instrucţiune din metoda main se creeaza o instanţă a clasei

JFrame şi se dă câmpului iug ca valoare referinţa la instanţa nou creată. Se folosesc apoi

metodele setSize(), setLocation() şi setVisible() din clasa Component, pentru a

stabili dimensiunile ferestrei şi pozitia ei pe ecran şi a o face vizibilă. Se afişeaza apoi în

fereastra terminalului de la care s-a lansat aplicaţia (la ieşirea standard a sistemului) titlul,

coordonatele şi dimensiunile ferestrei, folosind metodele adecvate din clasele JFrame şi

Component.

La lansarea în execuţie a acestei aplicaţii, în colţul din stânga sus al ecranului apare o

fereastră de dimensiuni 300x100 pixeli, cu titlul "Exemplu de JFrame", iar la ieşirea standard

apar toate mesajele afişate prin instrucţiunile System.out.println(...) din metoda main.

Putem acum să acţionăm asupra ferestrei cu mouse-ul, având grijă să nu dam comanda Close

(nici din menu, nici acţionând butonul din dreapta sus marcat cu X): putem să deplasăm

fereastra tragând cu mouse-ul de bara de titlu, să o iconificăm (minimizăm), deiconificăm,

maximizam, restaurăm. Putem, de asemenea, să modificăm dimensiunile ferestrei, trăgând cu

mouse-ul de marginile acesteia.

La sfârşit, putem da comanda Close (din meniul ferestrei sau apasând butonul marcat cu X) şi

fereastra se închide. Constatăm însă că închiderea ferestrei nu are drept consecinţa şi

încheierea executării aplicaţiei: în fereastra terminalului din care am lansat aplicaţia nu a

apărut promptul sistemului de operare. Pentru a încheia executarea aplicaţiei, trebuie să dăm

de la terminal comanda <Control>-C.

Pentru a avea o interfaţă grafică functională, este necesar:

- să adaugăm la interfaţă componente grafice;

- să asigurăm interacţiunea utilizatorului cu aceste componente şi cu însăşi fereastra

aplicaţiei.

Ne vom ocupa de aceste aspecte în secţiunile următoare.

Programarea orientată pe evenimente

Când se lucrează cu o interfaţă grafică, pe ecranul staţiei de lucru apar diferite obiecte

grafice: ferestre, meniuri, butoane, bare de defilare etc. Operatorul poate utiliza tastatura

staţiei de lucru, la fel ca în cazul progrămarii tradiţionale, dar, în plus, utilizează un dispozitiv

de selecţie numit mouse, cu ajutorul căruia poate alege diferite obiecte grafice de pe ecran şi

poate da anumite comenzi prin apăsarea unuia din butoanele acestui dispozitiv.

Se numeste eveniment orice modificare care are loc, fie în starea dispozitivelor de intrare, fie

în cea a obiectelor grafice de pe ecran: apăsarea sau eliberarea unei taste, deplasarea mouse-

ului, apăsarea sau eliberarea unui buton al mouse-ului, deschiderea sau închiderea unei

ferestre, efectuarea unui clic de mouse pe un obiect de control (buton, caseta de validare, bara

de defilare etc.), intrarea cursorului de mouse în câmpul activ al unui obiect grafic sau

Page 204: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

204

părăsirea acestuia etc. Pot exista, desigur, şi alte tipuri de evenimente, dar aici ne interesează

numai cele legate de interfaţa grafică a aplicaţiei.

Interacţiunea dintre operator şi aplicaţie într-un sistem bazat pe evenimente decurge astfel:

operatorul provoacă generarea unui eveniment, acţionând asupra tastaturii, mouse-ului sau a

altui dispozitiv de intrare, iar programul "răspunde" la acest eveniment prin executarea unei

anumite acţiuni. Acest mod de lucru impune o nouă concepţie în proiectarea programelor,

numită programarea orientată pe evenimente.

În programarea procedurală tradiţională, procesul de calcul este în întregime ghidat de

instrucţiunile programului. Imediat ce s-a încheiat executarea unei instrucţiuni, se trece la

instrucţiunea următoare, respectând fluxul de instrucţiuni al programului respectiv. Aceasta

se referă şi la interacţiunea dintre program şi utilizator. Chiar dacă programul este interactiv,

initiaţiva privind ce date trebuie introduse şi în ce moment se introduc acestea aparţine

programului. Operatorului uman nu îi rămâne decât să se conformeze solicitărilor

programului şi să introducă date atunci când ele sunt cerute de acesta. Este evident că un

asemenea rol nu este deloc convenabil pentru om, care doreşte să aibă el iniţiativa acţiunilor.

Apariţia interfeţelor grafice a permis introducerea unei noi concepţii în interacţiunea dintre

operator şi aplicatie, astfel ca iniţiativa să îi revină operatorului uman, iar programul să

execute comenzile acestuia. S-a trecut, astfel, de la programarea procedurală tradiţională la

programarea orientată pe evenimente (engleză: Event-Oriented Programming), cunoscuta şi

sub numele de programare ghidată de evenimente (engleză: Event Driven Programming).

Există diferite modele de generare, captare şi tratare a evenimentelor. În lucrarea de faţă va fi

prezentat modelul de evenimente specific platformei Java 2.

Modelul de evenimente de pe Platforma Java 2

In JDK 1.0 s-a folosit un model de evenimente bazat pe moştenire, reprezentat prin clasa

Event. Această clasă este menţinuta în continuare, din motive de compatibilitate a

programelor din JDK 1.0 cu cele din versiunile ulterioare, dar nu mai este recomandată.

Începând cu JDK 1.1 s-a introdus un nou model de evenimente, bazat pe delegare (engleză:

Delegation Event Model). Conform acestui model, distingem trei catedorii de obiecte care au

relaţii cu evenimentele:

- obiecte care generează evenimente, numite surse de evenimente (engleza: Event Source);

- obiecte care captează şi tratează evenimentele, numite ascultători de evenimente

(engleză: Event Listener);

- evenimentele propriu-zise (engleză: Event), care sunt tot obiecte, generate de surse şi

captate de ascultători.

Un eveniment generat de o sursă poate fi interceptat de mai mulţi ascultători. Este posibil ca

un obiect să se "asculte" pe sine însuşi, deci să îşi trateze propriile evenimemte. Tocmai

această legatură strânsa între sursele şi ascultătorii de evenimente este caracteristica esenţiala

a "modelului delegării": ea constă în faptul că sursa transmite evenimentele generate de ea

Page 205: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

205

numai către ascultătorii care au fost ataşaţi la sursa respectivă, iar ascultătorul primeşte

evenimente numai de la sursele la care a fost ataşat.

În modelul de evenimente din JDK 1.0 sursa transmitea evenimentele fără o destinaţie

anume, iar consumatorii de evenimente trebuiau sa depisteze singuri ce fel de evenimente

sunt acestea şi de la ce sursă provin şi, în funcţie de aceasta, să decidă dacă interceptează sau

nu evenimentul respectiv.

Remarcăm, deci, că se aplică cu consecvenţă principiul programării orientate pe obiecte, în

sensul că aplicaţia este constituită dintr-un ansamblu de obiecte care interacţionează. Putem

spune că evenimentul este o nouă forma de mesaj, care se transmite între obiectele-sursă şi

obiectele-ascultători. Fiecare ascultator trebuie "adăugat" la sursă. În acest fel, sursa "ştie"

căror ascultători să le transmită evenimentele pe care le generează.

Este important sa reţinem faptul că, în acest model de evenimente, sursele sunt întotdeauna

componente ale interfeţei grafice. Când cursorul mouse-ului intră în interiorul unei

componente sau iese din aceasta, sau când facem click de mouse pe o componenta,

evenimentul nu este generat direct de către mouse, ci de către componenta respectivă a

interfeţei. În mod similar, când apăsăm sau eliberăm o tastă, evenimentul nu este generat

direct de către tastă, ci de către acea componentă a interfeţei grafice, care este activă în

momentul respectiv. Evenimentele pot fi generate de o componentă şi atunci când au loc

modificari ale stării acesteia ca urmare a executării unor instrucţiuni din program (de

exemplu când se deschide sau se închide o fereastră, etc.).

Clase de evenimente

Clasele de evenimente se găsesc în pachetele java.awt.event şi javax.swing.event şi formează

o ierarhie de clase, care are ca radacină clasa abstractă java.awt.AWTEvent. Aceasta, la

rândul ei, extinde clasa java.util.EventObject din pachetul java.util.

Orice eveniment conţine următoarele metodele declarate în clasa java.util.EventObject:

public Object getSource() - care întoarce o referinţă către obiectul care a generat

evenimentul respectiv;

public String toString() - care întoarce o reprezentare sub forma de şir a

obiectului.

Orice eveniment AWT (generat de componente AWT sau JFC/Swing) conţine un câmp

protejat de tip int numit id, a cărui valoare indică tipul evenimentului. Toate clasele de

evenimente conţin câmpuri statice finale de tip int, al căror nume indică tipul de eveniment şi

a căror valoare este valoarea corespunzătoare a câmpului id. Valoarea acestui câmp se poate

obţine prin metoda public int getId()

Evenimentele pot fi de nivel coborât (low level event) sau semantice. Numele claselor de

evenimente de nivel coborât indică fie componenta, fie dispozitivul de intrare care le-a

generat, de exemplu: ComponentEvent, WindowEvent, MouseEvent, KeyEvent. Numele

claselor de evenimente semantice indică mai curând tipul de eveniment, decât sursa acestuia,

Page 206: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

206

de exemplu: ActionEvent, TextEvent. Descrierea claselor de evenimente este dată complet în

documentaţia Java API.

Interfeţe şi clase adaptoare pentru ascultători de evenimente

Evenimentele generate de surse, sunt captate şi tratate de ascultători. Sursele sunt

componente ale interfeţei grafice care, de regulă, sunt preluate din pachetele de clase ale

platformei Java 2, deci nu sunt programate de către programatorul de aplicaţie, ci doar

utilizate de acesta. În schimb, programatorul de aplicaţie trebuie să creeze clasele de

ascultători de evenimente specifice aplicaţiei pe care o dezvoltă. Metodele acestor clase

trebuie sa reacţioneze la apariţia evenimentelor şi să execute acţiunile corespunzătoare,

conform cu obiectivele aplicaţiei. În consecinţă, platforma Java 2 nu pune la dispoziţie clase

ascultătoare predefinite, ci doar interfeţele pe care trebuie să le implementeze aceste clase,

pentru a putea trata evenimentele pe care le recepţionează.

Există câte o interfaţă de ascultător pentru fiecare clasă de eveniment. De exemplu, pentru

ComponentEvent există interfaţa ComponentListener, pentru WindowEvent exista intefaţa

WindowListener etc.

Pentru a se uşura munca programatorilor, pentru unele interfeţe care conţin mai multe

metode, se oferă şi prototipuri de clase care implementează interfaţa respectivă, numite

adaptoare. De exemplu, clasa WindowAdapter implementează interfaţa WindowListener,

clasa MouseAdapter implementează interfaţa MouseListener etc.

Adăugarea ascultătoarelor la sursele de evenimente se face prin metode de adăugare

corespunzătoare, existente în clasele de surse. De exemplu, pentru a se adăuga la o instanţă a

clasei Window sau a subclaselor acesteia (de exemplu JFrame) un ascultător de evenimente

de fereastră, în clasa Window există metoda public void addWindowListener(WindowListener l)

Descrierea completă a interfeţelor şi adaptoarelor pentru clasele de ascultători de evenimente

este dată în documentaţia Java API.

Evenimentele generate de o fereastră

Pentru a ne familiariza cu modelul de evenimente al platformei Java 2, vom urmări acum

evenimentele generate de o fereastră şi modul cum acestea pot fi tratate. Vom folosi în acest

scop o interfaţă din clasa javax.swing.JFrame. Aceasta este derivată din clasa

java.awt.Frame care, la rândul ei, este derivată din clasa java.awt.Window. Evenimentele

prezentate în această secţiune sunt generate de orice instanţă a clasei Window şi ale

subclaselor sale.

Evenimentele generate de fereastră sunt instanţe ale clasei WindowEvent şi sunt ascultate de

instanţe ale unor clase care implementează interfaţa WindowListener sau extind clasa

WindowAdapter. Toate aceste clase şi interfeţe se găsesc în pachetul java.awt.event.

Metodele interfeţei WindowListener sunt următoarele:

public void windowOpened(WindowEvent e)- fereastra a fost deschisă

public void windowClosing(WindowEvent e)- fereastra se închide

Page 207: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

207

public void windowClosed(WindowEvent e)- fereastra a fost inchisă

public void windowIconified(WindowEvent e)- fereastra a fost iconificată

public void windowDeiconified(WindowEvent e)- fereastra a fost deiconificată

public void windowActivated(WindowEvent e)- fereastra a fost activată

public void windowDeactivated(WindowEvent e)- fereastra a fost dezactivată

Pentru a se trata evenimentele generate de fereastră, este necesar să se declare o clasă care

implementează interfaţa WindowListener. În această clasă se definesc toate metodele

interfeţei, astfel încât acestea să execute acţiunile adecvate evenimentelor corespunzătoare.

Exemplu

În fişierul Evenim1.java este dat ca exemplu următorul program, în care se urmăresc

evenimentele generate de o fereastră din clasa JFrame.

import java.awt.*; import java.awt.event.*; import javax.swing.*;

class Evenim1 { static JFrame iug; // referinta la interfata grafica static AscultFereastra af; // referinta la ascultator

/* Clasa imbricata pentru ascultatorul de fereastra */ static class AscultFereastra implements WindowListener { public void windowOpened(WindowEvent e) { System.out.println("Fereastra a fost deschisa: "+e); } public void windowClosing(WindowEvent e) { System.out.println("Fereastra se inchide: "+e); } public void windowClosed(WindowEvent e) { System.out.println("Fereastra a fost inchisa: "+e); } public void windowIconified(WindowEvent e) { System.out.println("Fereastra a fost iconificata: "+e); } public void windowDeiconified(WindowEvent e) { System.out.println("Fereastra a fost deiconificata: "+e); } public void windowActivated(WindowEvent e) { System.out.println("Fereastra a fost activata: "+e); } public void windowDeactivated(WindowEvent e) { System.out.println("Fereastra a fost dezactivata: "+e); } } // se incheie clasa ascultatorului de fereastra

/* Metoda principala */ public static void main(String args[]) throws Exception { af=new AscultFereastra(); // instantierea ascultatorului iug=new JFrame("Urmarire evenimente fereastra"); iug.setSize(300,100); iug.setLocation(new Point(100,50)); iug.setVisible(true);

Page 208: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

208

iug.addWindowListener(af); // adaugarea ascultatorului System.out.println("Titlul ferestrei este: "+iug.getTitle()); System.out.println("Coltul din stanga sus este in punctul: "+ iug.getLocation()); System.out.println("Dimensiunile ferestrei: "+iug.getSize()); } }

Pentru ascultătorul de fereastră a fost creată clasa imbricată statică AscultFereastra, în care

sunt implementate toate metodele interfeţei WindowListener. În cazul de faţă, aceste metode

nu fac altceva, decât că afişează pe terminal un mesaj privind evenimentul care s-a produs.

Acest mesaj conţine şi evenimentul interceptat e, convertit în şir. În metoda main(), se

construiesc instanţele claselor JFrame şi AscultFereastra, după care se adaugă ascultătorul af

la fereastra iug prin metoda addWindowListener(). Se stabilesc, de asemenea, dimensiunea

şi poziţia ferestrei şi se face fereastra vizibilă.

După ce a fost pusă aplicaţia în execuţie, pe ecran apare o fereastră cu titlul "Urmarire

evenimente fereastra". La terminal putem urmări succesiunea evenimentelor care se produc.

Ca şi în exemplul precedent, ieşirea din aplicaţie se face de la tastatura, prin comanda

<Control>-C.

Remarcăm că, în exemplul de mai sus, a fost necesar ca, în clasa care implementează interfata

WindowListener, să se definească toate metodele acesteia. Dacă ne sunt necesare numai

unele din aceste metode, este preferabil sa obţinem clasa AscultFereastra prin extinderea

clasei WindowAdapter. Această ultimă clasă conţine toate metodele interfeţei

WindowListener, dar corpurile lor sunt vide, deci metodele nu fac nimic. În acest fel, în clasa

derivată este suficient să redefinim numai metodele care ne sunt necesare, ca în exemplul din

secţiunea următoare.

Terminarea aplicaţiei la închiderea ferestrei

Pentru ca la acţionarea butonului de închidere din colţul din dreapta-sus al ferestrei să se

închidă nu numai fereastra respectivă, ci si aplicaţia, este necesar ca metoda

windowClosing() a ascultătorului de fereastră să conţină invocarea metodei

System.exit(0) din clasa System. Dacă nu dorim să utilizam şi alte metode de tratare a

evenimentelor generate de fereastră, vom deriva clasa de ascultare a ferestrei AF din clasa

WindowAdapter.

Exemplu

În fişierul Inchidere.java se dă o modificare a clasei Evenim1 din exemplul precedent.

import java.awt.*; import java.awt.event.*; import javax.swing.*;

class Inchidere { static JFrame iug; // referinta la fereastra static AF af; // referinta la ascultator

/* Clasa imbricata pentru ascultatorul de fereastra */ static class AF extends WindowAdapter {

Page 209: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

209

public void windowActivated(WindowEvent e) { System.out.println("Fereastra a fost activata"); } public void windowDeactivated(WindowEvent e) { System.out.println("Fereastra a fost dezactivata"); } public void windowClosing(WindowEvent e) { System.out.println("Fereastra se inchide"); System.exit(0); // incheierea executarii aplicatiei } }

/* Metoda principala */ public static void main(String args[]) throws Exception { af=new AF(); // instantierea ascultatorului iug=new JFrame("Urmarire evenimente fereastra"); iug.setSize(300,100); iug.setLocation(new Point(100,50)); iug.setVisible(true); iug.addWindowListener(af); // adaugarea ascultatorului System.out.println("Titlul ferestrei este: "+iug.getTitle()); System.out.println("Coltul din stanga sus este in punctul: "+ iug.getLocation()); System.out.println("Dimensiunile ferestrei: "+iug.getSize()); } }

În acest program, în afară de modificarea numelor claselor, s-au mai făcut următoarele

modificări:

- clasa de ascultare a evenimentelor AF extinde clasa WindowAdapter, deci implementează

in mod indirect interfaţa WindowListener, prin intermediul acesteia;

- s-au definit numai trei din cele şapte metode ale intefeţei WindowListener; celelalte

metode sunt moştenite de la clasa WindowAdapter, deci nu fac nimic;

- în metoda windowClosing()s-a introdus instrucţiunea System.exit(0); În consecinţă,

când acţionăm butonul de închidere al ferestrei, sau selectăm optiunea Close din meniu, se

încheie executarea aplicaţiei.

Evenimente de mouse

Evenimentele de mouse sunt instanţe ale clasei java.awt.event.MouseEvent şi sunt generate

de către orice componentă a interfeţei grafice, atunci când asupra ei se acţioneaza cu mouse-

ul. Clasa MouseEvent este derivată din clasa java.awt.event.InputEvent. Evenimentele de

mouse sunt intrarea cursorului de mouse într-o componentă sau ieşirea din aceasta, apăsarea

unui buton de mouse sau eliberarea lui, efectuarea unui click de mouse (simplu sau multiplu)

pe suprafaţa componentei, mişcarea mouse-ului.

Pentru ascultarea evenimentelor de mouse se folosesc interfeţele

java.awt.event.MouseListener,java.awt.event.MouseMotionListener şi

javax.swing.event.MouseInputListener. Ascultătoarele de mouse se pot obţine, de

asemenea, prin extinderea claselor

java.awt.event.MouseAdapter,java.awt.event.MouseMotionAdapter şi

Page 210: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

210

javax.swing.event.MouseInputAdapter.

În AWT se face distincţie între evenimentele de mouse discrete şi evenimentele care

caracterizează mişcarea continuă a mouse-lui.

a/ Evenimente de mouse

- a fost apăsat un buton al mouse-ului (MOUSE_PRESSED);

- a fost eliberat un buton al mouse-ului (MOUSE_RELEASED);

- s-a făcut click de mouse, adică un buton al acestuia a fost apăsat şi eliberat imediat

(MOUSE_CLICKED);

- cursorul mouse-ului a intrat într-o componentă (MOUSE_ENTERED);

- cursorul mouse-ului a ieşit din componentă (MOUSE_EXITED).

Ascultarea acestor evenimente se face cu instanţe ale claselor care implementeaza interfaţa

java.awt.event.MouseListener.

b/ Evenimente de mişcare a mouse-ului

- mouse-ul s-a mişcat pe suprafaţa componentei (MOUSE_MOVED);

- mouse-ul a fost "tras" pe suprafaţa componentei, adică a fost mişcat ţinând un buton

apăsat (MOUSE_DRAGGED).

Aceste evenimente sunt ascultate cu instanţe ale claselor care implementează interfaţa

java.awt.event.MouseMotionListener.

În JFC/Swing s-a introdus în plus interfaţa javax.swing.event.MouseInputListener, care

ascultă ambele categorii de evenimente de mouse, moştenind cele două interfeţe menţionate

mai sus.

Exemplu

În fişierul EvMouse.java este dat un exemplu de aplicaţie în care se ascultă evenimentele de

mouse generate de o instanţă a clasei JFrame şi se afişează la terminal conţinutul acestor

evenimente. În acest scop, în clasa imbricată AMouse au fost implementate toate metodele

interfeţei MouseListener, dar aceste metode nu fac altceva, decât să afişeze la terminal

evenimentul recepţionat.

import java.awt.*; import java.awt.event.*; import javax.swing.*;

class EvMouse { static JFrame iug; // referinta la fereastra static AF af; // referinta la ascultator de fereastra static AMouse am; // referinta la ascultator de mouse

/* Clasa imbricata pentru ascultatorul de fereastra */ static class AF extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); // incheierea executarii aplicatiei } }

Page 211: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

211

/* Clasa imbricata pentru ascultatorul de mouse */ static class AMouse implements MouseListener { public void mouseClicked(MouseEvent e) { System.out.println(e); } public void mousePressed(MouseEvent e) { System.out.println(e); } public void mouseReleased(MouseEvent e) { System.out.println(e); } public void mouseEntered(MouseEvent e) { System.out.println(e); } public void mouseExited(MouseEvent e) { System.out.println(e); } }

/* Metoda principala */ public static void main(String args[]) throws Exception { af=new AF(); // instantierea ascultatorului am=new AMouse(); // instantierea ascultatorului de mouse iug=new JFrame("Urmarire evenimente de mouse"); iug.setSize(300,100); iug.setLocation(new Point(100,50)); iug.setVisible(true); iug.addWindowListener(af); // adaugarea ascultatorului de fereastra iug.addMouseListener(am); // adaugarea ascultatorului de mouse } }

Executând acest program, putem urmări pe ecran succesiunea de evenimente care se produc

atunci când acţionăm cu mouse-ul asupra ferestrei aplicaţiei.

Evenimentul de mouse conţine următoarele informaţii:

- tipul evenimentului (câmpul id);

- coordonatele punctului în care s-a produs evenimentul;

- modul în care s-a produs evenimentul, caracterizat printr-un numar întreg, în care fiecare

bit are o anumită semnificaţie. Acest număr poate fi decodificat cu ajutorul măştilor

existente în clasa java.awt.event.InputEvent;

- contorul de click-uri (util când au loc mai multe clickuri succesive);

- numărul de ordine al ferestrei (în ordinea în care ferestrele au fost creeate).

Aceste informaţii pot fi obţinute folosind metodele şi măştile din clasele

java.awt.event.MouseEvent şi java.awt.event.InputEvent.

Exemplu

În fişierul EvMouse1.java este dat un exemplu de aplicaţie, în care se urmăresc situaţiile în

care este apăsat unul dintre butoanele mouse-ului, atunci când cursorul acestuia se găseşte

pe suprafaţa ferestrei aplicaţiei. Întrucât nu se folosesc toate metodele interfeţei

MouseListener, clasa ascultătorului de mouse AMouse s-a creat prin extinderea clasei

java.awt.event.MouseAdapter.

Page 212: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

212

import java.awt.*; import java.awt.event.*; import javax.swing.*;

class EvMouse1 { static JFrame iug; // referinta la fereastra static AF af; // referinta la ascultator de fereastra static AMouse am; // referinta la ascultator de mouse

/* Clasa imbricata pentru ascultatorul de fereastra */ static class AF extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); // incheierea executarii aplicatiei } }

/* Clasa imbricata pentru ascultatorul de mouse */ static class AMouse extends MouseAdapter { public void mousePressed(MouseEvent e) { int x=e.getX(), y=e.getY(), n=e.getClickCount(), mod=e.getModifiers(), buton=0; String mesaj="S-a apasat butonul "; if((InputEvent.BUTTON1_MASK & mod) != 0) buton=1; else if((InputEvent.BUTTON2_MASK & mod) !=0) buton=2; else if((InputEvent.BUTTON3_MASK & mod) !=0) buton=3; mesaj+=buton+" x="+x+" y="+y+" contor="+n+" mod="+mod; if(e.isControlDown()) mesaj+=" Ctrl"; if(e.isAltDown()) mesaj+=" Alt"; if(e.isShiftDown()) mesaj+=" Shift"; System.out.println(mesaj); } }

/* Metoda principala */ public static void main(String args[]) throws Exception { af=new AF(); // instantierea ascultatorului am=new AMouse(); // instantierea ascultatorului de mouse iug=new JFrame("Urmarire evenimente de mouse"); iug.setSize(300,100); iug.setLocation(new Point(100,50)); iug.setVisible(true); iug.addWindowListener(af); // adaugarea ascultatorului de fereastra iug.addMouseListener(am); // adaugarea ascultatorului de mouse } }

În metoda mousePressed() a clasei AMouse se determină coordonatele punctului în care

s-e găseşte cursorul la apăsarea butonului, invocând metodele getX() şi getY() ale clasei

MouseEvent. Se determină numărul de apăsări succesive rapide, invocând metoda

getClickCount() a aceleeaşi clase.

Pentru a afla ce buton a fost apăsat, se procedează astfel:

- se determină codul modificatorilor, invocând metoda getModifiers() din clasa

InputEvent;

- se aplică asupra acestui cod măştile butoanelor, folosind operatorul de intersecţie pe biţi

Page 213: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

213

&. Butonul de mouse a cărui mască, intersectată cu codul mod, dă rezultat nenul este cel

apăsat.

Codul modificatorilor mod poate fi folosit şi pentru a determina daca, în timp ce s-a apăsat

butonul de mouse, era apăsată şi una din tastele auxiliare Ctrl, Alt sau Shift, folosind

măştile corespunzătoare acestor taste. Totuşi, aici s-a preferat utilizarea metodelor

isControlDown(), isAltDown() şi isShiftDown() ale clasei InputEvent.

Toate măştile folosite în această aplicaţie sunt definite în clasa java.awt.event.InputEvent.

Evenimente de tastă

De câte ori se apasă sau se eliberează o tastă, componenta activă a interfeţei grafice

generează un eveniment de tastă din clasa java.awt.event.KeyEvent. Acesta poate fi tratat cu

un "ascultător de taste" care implementează interfaţa java.awt.event.KeyListener sau care

extinde clasa java.awt.event.KeyAdapter.

Se disting următoarele evenimente generate la acţionarea tastelor:

- a fost apasată o tastă (KEY_PRESSED);

- a fost eliberată o tastă (KEY_RELEASED);

- a fost "tipărit" un caracter, adică a fost apasată şi eliberată o tastă care transmite un

caracter tipăribil (KEY_TYPED).

Aceste situaţii pot fi detectate cu metodele corespunzătoare ale interfeţei KeyListener.

Evenimentul generat de tastă conţine, în afară de codul tastei acţionate, şi informaţii privind

starea tastelor auxiliare Ctrl, Alt şi Shift în momentul producerii evenimentului respectiv.

Aceste stări pot fi detectate cu metodele corespunzătoare ale interfeţei superclasei

java.awt.event.InputEvent.

Exemplu

În fişierul EvTaste.java se dă un exemplu de aplicaţie, în care se urmăreşte apariţia unor

evenimente de tastă, care sunt generate de fereastra aplicaţiei, atunci când ea este activă şi

se actionează o tastă.

import java.awt.*; import java.awt.event.*; import javax.swing.*;

class EvTaste { static AF af=new AF(); // ascultatorul de fereastra static ATaste at=new ATaste(); // ascultatorul de taste static IUG iug=new IUG("Urmarirea evenimentelor de tasta");

/* Clasa imbricata pentru interfata utilizator */ static class IUG extends JFrame { /* Constructorul interfetei utilizator */

Page 214: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

214

IUG(String titlu) { super(titlu); setSize(300,100); setLocation(new Point(100,50)); setVisible(true); addWindowListener(af); // adaugarea ascultatorului de fereastra addKeyListener(at); // adaugarea ascultatorului de taste } }

/* Clasa imbricata pentru ascultatorul de fereastra */ static class AF extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); // incheierea executarii aplicatiei } }

/* Clasa imbricata pentru ascultatorul de taste */ static class ATaste implements KeyListener { public void keyTyped(KeyEvent e) { System.out.println(e); } public void keyPressed(KeyEvent e) { System.out.println(e); } public void keyReleased(KeyEvent e) { System.out.println(e); } }

/* Metoda principala */ public static void main(String args[]) { } }

Ascultătorul de taste este realizat prin clasa imbricată ATaste, care implementează interfaţa

KeyListener. Aşa cum sunt ele redefinite aici, metodele ascultătorului de taste afişează

evenimentul respectiv la terminal.

Punând în execuţie această aplicaţie, putem urmări la terminal succesiunea evenimentelor

care sunt generate atunci când acţionam tastele. Remarcăm, de asemenea, că aceste

evenimente sunt generate numai atunci când fereastra aplicaţiei este activă.

Pentru a detecta în ce condiţii a fost generat evenimentul (codul tastei care a fost apasată,

inscripţia de pe tastă, ce taste auxiliare erau apăsate), putem utiliza metodele claselor

KeyEvent şi superclasei acesteia InputEvent.

Exemplu

În fişierul EvTaste1.java este dat un exemplu de aplicaţie în care se folosesc metodele din

clasele KeyEvent şi InputEvent pentru a detecta situaţiile în care au apărut evenimentele

captate de către ascultătorul de taste. Acesta a fost realizat prin extinderea clasei

Page 215: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

215

KeyAdapter.

import java.awt.*; import java.awt.event.*; import javax.swing.*;

class EvTaste1 { static AF af=new AF(); // ascultatorul de fereastra static ATaste at=new ATaste(); // ascultatorul de taste static IUG iug=new IUG("Urmarirea evenimentelor de tasta");

/* Clasa imbricata pentru interfata utilizator */ static class IUG extends JFrame { /* Constructorul interfetei utilizator */ IUG(String titlu) { super(titlu); setSize(300,100); setLocation(new Point(100,50)); setVisible(true); addWindowListener(af); // adaugarea ascultatorului de fereastra addKeyListener(at); // adaugarea ascultatorului de taste } }

/* Clasa imbricata pentru ascultatorul de fereastra */ static class AF extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); // incheierea executarii aplicatiei } }

/* Clasa imbricata pentru ascultatorul de taste */ static class ATaste extends KeyAdapter { public void keyPressed(KeyEvent e) { int cod=e.getKeyCode(), mod=e.getModifiers(); String mesaj="S-a apasat tasta de cod "+cod+" "+e.getKeyText(cod); if(mod!=0) mesaj+=" cu modificatorii: "+e.getKeyModifiersText(mod); System.out.println(mesaj); } public void keyTyped(KeyEvent e) { System.out.println("S-a introdus caracterul "+e.getKeyChar()); } }

/* Metoda principala */ public static void main(String args[]) { } }

Punând în execuţie această aplicaţie, putem urmări la terminal evenimentele de apăsare a

unei taste (KEY_PRESSED) şi de introducere a unui caracter (KEY_TYPED) afişate sub

formă decodificată.

Pentru detalii privind metodele disponibile în clasele KeyAdapter, KeyEvent şi InputEvent

se poate consulta documentaţia Java API.

Page 216: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

216

Adăugarea unei componente la fereastra

principală a aplicaţiei

Până în prezent, am arătat că, atunci când folosim JFC/Swing, fereastra principală a aplicaţiei

este o instanţă a clasei javax.swing.JFrame sau a unei subclase a acesteia. Pentru a construi

o interfaţă utilizator grafică este necesar ca în fereastra principală să introducem diverse

componente. Acestea pot fi componente simple, ca etichete, butoane, casete de validare,

câmpuri de text etc., sau pot fi containere, care conţin - la rândul lor - alte componente.

Pentru realizarea acestor componente simple şi containere se folosesc clasele din pachetele

java.awt şi javax.swing, care sunt descrise în documentaţia Java API.

Adăugarea de componente nu se face direct la instanţele clasei JFrame. În JFrame există un

Container (un obiect dintr-o subclasă a clasei Container) numit contentPane, la care se pot

adăuga componente. O referinţă la acest Container se obţine prin metoda public Container

getContentPane(), existentă în clasa JFrame. Adăugarea de componente se face prin una

din metodele add() ale clasei Container. Dacă, de exemplu, comp este referinţă la o

componentă, atunci expresia getContentPane().add(comp), folosită într-o metodă a clasei

JFrame sau a subclaselor ei, adaugă componenta comp la containerul contentPane conţinut

în JFrame.

O prezentare succintă a clasei JFrame este dată în Indexul de clase, iar cea completă se

găseşte în Java API, completată cu cea din Tutorialul Java.

Exemplul 1

În fişierul AdComp.java este un exemplu de aplicaţie, în care se testează adăugarea la

fereastra principală a unui buton şi se face contorizarea numărului de apăsări pe butonul

respectiv. În acest exemplu se arată:

- cum se adaugă la fereastra aplicaţiei un buton (o instanţă a clasei JButton);

- cum se tratează evenimentele de acţiune generate la apasarea butonului.

În locul unui buton se putea folosi orice altă componentă.

import java.awt.*; import java.awt.event.*; import javax.swing.*;

class AdComp { static String textButon="Numar de actionari: "; static int contorActionari=0; static AF af=new AF(); static AB ab=new AB(); static JButton buton=new JButton(textButon+contorActionari); static IUG iug=new IUG("Un buton de contorizare a apasarilor");

/* clasa imbricata pentru interfata utilizator grafica */

Page 217: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

217

static class IUG extends JFrame {

IUG(String titlu) { // constructorul clasei IUG super(titlu); setSize(300, 80); setLocation(200, 150); getContentPane().add(buton); // adaugarea butonului addWindowListener(af); // adaugarea ascultatorului de fereastra buton.addActionListener(ab); // adaugarea ascult. de actiune setVisible(true); } }

/* Clasa ascultatoare de fereastra */ static class AF extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); // incheierea executarii aplicatiei } }

/* Clasa ascultatoare de actiuni asupra butonului */ static class AB implements ActionListener { public void actionPerformed(ActionEvent e) { contorActionari++; buton.setText(textButon+contorActionari); } }

/* Metoda principala a aplicatiei */ public static void main(String args[]) { } }

Remarcăm următoarele:

- S-au declarat trei clase imbricate:

. clasa IUG, care este interfaţa utilizator grafică;

. clasa AF, care este ascultătorul evenimentelor de fereastră, necesar pentru închiderea

aplicaţiei;

. clasa AB, care asculta şi tratează evenimentele de acţiune generate de buton.

- În constructorul clasei IUG se adaugă la containerul de conţinut al ferestrei principale

(contentPane) butonul button, din clasa JButton. În acest scop, se foloseşte instrucţiunea getContentPane().add(buton);

- În acelaşi constructor, se adaugă la buton ascultătorul de evenimente de fereastră af şi

ascultătorul de evenimente de acţiune ab. Obiectele indicate de referinţele buton af şi ab au

fost construite înainte de a se construi interfaţa grafică.

- Metoda actionPerformed(Event e) din clasa imbricată AB este invocată atunci când se

produce un "eveniment de acţiune". Întrucat în programul nostru sursa evenimentelor de

acţiune (la care a fost inregistrată instanţa ab a clasei AB) este butonul buton, evenimentele

de acţiune vor fi generate atunci când se apasă pe buton (se face click de mouse pe suprafaţa

butonului). În această metodă se incrementează variabila contorAcţionări şi se pune în buton

un nou text, care indică valoarea contorului. În acest scop se foloseşte instrucţiunea

buton.setText(text).

Când punem în execuţie această aplicaţie, pe ecran apare o fereastră cu titlul "Un buton de

Page 218: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

218

contorizare a apăsărilor", în interiorul căreia se găseşte un buton pe care apare inscripţia

"Număr de acţionări: 0". De fiecare dată, când facem click de mouse pe acest buton,

constatăm că s-a modificat textul continut, indicand noua valoare a contorului de acţionări.

Exemplul 2 Folosirea unei clase de buton de contorizare proprie, derivată din clasa JButton

Având în vedere ca butonul de contorizare a apăsărilor poate fi, în principiu, folosit şi în mai

multe aplicaţii, putem să îl declarăm ca o clasa publică într-un fişier separat, ca în fişierul

ButonContor.java, reprodus aici:

/* Buton care contorizeaza numarul de apasari si afiseaza acest numar pe suprafata sa, dupa numele butonului. In acest scop, butonul isi asculta propriile evenimente de actiune. */

import java.awt.event.*; import javax.swing.*;

public class ButonContor extends JButton implements ActionListener { private int contor; // contorul de apasari private String nume; // numele butonului

public ButonContor(String nume) { // constructorul butonului contor=0; this.nume=nume+" #"; setText(this.nume+contor); addActionListener(this); // butonul se asculta pe sine }

public void actionPerformed(ActionEvent e) { contor++; setText(nume+contor); }

public int numarApasari() { // se intoarce numarul de apasari return contor; }

public void reset() { // se pune contorul la zero contor=0; setText(nume+contor); } }

În fişierul AdComp1.java se dă o modificare a aplicaţiei din exemplul precedent, în care, în

locul unei instanţe a clasei JButton, se foloseşte o instanţă a clasei ButonContor. În acest caz

nu a mai fost necesar să se creeze o clasă de ascultare a butonului, întrucât butonul din clasa

ButonContor se ascultă pe el însuşi.

import java.awt.event.*; import javax.swing.*;

Page 219: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

219

class AdComp1 { static AF af=new AF(); static ButonContor buton=new ButonContor("Contor apasari"); static IUG iug=new IUG("Un buton de contorizare a apasarilor");

/* clasa imbricata pentru interfata utilizator grafica */ static class IUG extends JFrame {

IUG(String titlu) { // constructorul clasei IUG super(titlu); setSize(300, 80); setLocation(200, 150); getContentPane().add(buton); // adaugarea butonului addWindowListener(af); // adaugarea ascultatorului de fereastra setVisible(true); } }

/* Clasa ascultatoare de fereastra */ static class AF extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); // incheierea executarii aplicatiei } }

/* Metoda principala a aplicatiei */ public static void main(String args[]) { } }

Gestionarea poziţionării componentelor

Am arătat în secţiunea precedentă cum se poate plasa într-un container (în particular într-un

contentPane) o singură componentă. În mod normal însă, într-un comtainer se plasează mai

multe componente. În acest caz, este foarte important să se stabilească modul în care aceste

componente sunt poziţionate pe suprafaţa containerului. În acest scop, a fost introdus

conceptul de gestionar de poziţionare (în engleză: Layout Manager).

Gestionarul de poziţionare este o clasă care asigură poziţionarea şi redimensionarea automată

a componentelor situate într-un container, atât la crearea containerului, cât şi la modificarea

dimensiunilor acestuia. Orice gestionar de poziţionare implementează interfaţa

java.awt.LayoutManager sau subinterfaţa acesteia java.awt.LauoutManager2. În cele ce

urmează, vom studia cele mai larg utilizate clase de gestionare a poziţionării, existente în

pachetele java.awt şi javax.swing.

Fiecare clasă de container are un gestionar de poziţionare implicit. Acesta este BorderLayout

pentru Frame şi JFrame.contentPane şi FlowLayout pentru clasa Panel. Modificarea

gestionarului de pozitionare se face prin metoda public void setLayout(LayoutManager manager)

Page 220: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

220

din clasa java.awt.Container.

Clasa BorderLayout

Începem cu această clasă, deoarece este gestionarul de poziţionare implicit pentru conţinutul

instanţelor clasei JFrame. În acest caz, se consideră că suprafaţa containerului este imparţită

în cinci zone numite, respectiv, NORTH, SOUTH, WEST, EAST si CENTER. În fiecare din

aceste zone se poate plasa numai o singură componentă, care poate fi însă ea însăşi un

container. Adăugarea de componente la container se face, în acest caz, folosind metoda

add(componenta, BorderLayout.ZONA), unde componenta este referinţa la componenta

adaugată, iar ZONA este una din cele cinci zone menţionate mai sus. Dacă se foloseşte

metoda add(componenta), fără a indica zona, componenta respectivă este plasată implicit în

zona CENTER, aşa cum s-a procedat în secţiunea precedenta, în exemplul din fişierul

AdComp.java.

Exemplu

În fişierul Butoane.java este dat un exemplu, în care se plasează în fereastra aplicaţiei câte un

buton în fiecare din zonele NORTH,WEST, CENTER şi EAST şi o etichetă (instanţă a clasei

javax.swing.JLabel) în zona SOUTH. Pe suprafaţa fiecărui buton este afişat numărul de

apăsări succesive. În eticheta de la partea de jos se afişează numărul total de acţionări asupra

tuturor butoanelor.

import java.awt.*; import java.awt.event.*; import javax.swing.*;

class Butoane { static AF af=new AF(); // ascultatorul de fereastra static AA aa=new AA(); // ascultatorul de actiuni static IUG iug=new IUG("Adaugare de butoane"); static int totalActionari=0;

static class IUG extends JFrame { JLabel lab=new JLabel("Actionati butoanele"); ButonContor b1, b2, b3, b4;

IUG(String titlu) { super(titlu); Container cp=getContentPane(); setSize(400,300); setLocation(200,150); addWindowListener(af); b1=new ButonContor("N"); b1.addActionListener(aa); cp.add(b1, BorderLayout.NORTH); b2=new ButonContor("E"); b2.addActionListener(aa); cp.add(b2, BorderLayout.EAST); b3=new ButonContor("W"); b3.addActionListener(aa); cp.add(b3, BorderLayout.WEST); b4=new ButonContor("C");

Page 221: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

221

b4.addActionListener(aa); cp.add(b4, BorderLayout.CENTER); cp.add(lab, BorderLayout.SOUTH); setVisible(true); } }

static class AA implements ActionListener { public void actionPerformed(ActionEvent e) { totalActionari++; iug.lab.setText("Total actionari: "+totalActionari); } }

static class AF extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } }

public static void main(String args[]) { } }

Remarcăm următoarele:

- clasa ButonContor extinde clasa JButton şi implementează interfaţa ActionListener, fiind

definită de noi ca o clasa publică în fişierul ButonContor.java. În constructorul acestei clase

există instrucţiunea addActionListener(this), astfel că fiecare buton îşi ascultă propriile

evenimente de acţiune;

- în metoda actionPerformed(ActionEvent e) din clasa ButonContor se incrementează

contorul intern al butonului respectiv şi se afişează valoarea contorului pe suprafaţa

butonului;

- în constructorul clasei imbricate IUG se adaugă câte un ButonContor în fiecare din zonele

NORTH, WEST, EAST si CENTER ale ferestrei principale.

- pentru a fi totalizat numărul de apăsări al tuturor butoanelor, la fiecare buton se adaugă, de

asemenea, ascultătorul de acţiune ac, instanţă a clasei AC, care incrementează câmpul total

al clasei Butoane;

- eticheta din zona SOUTH face parte din clasa javax.swing.JLabel. Instanţele acestei clase

au ca principal rol afişarea pe suprafaţa lor a unui text şi/sau a unei pictograme. În exemplul

nostru se afişează numarul total de acţionări ale butoanelor (valoarea câmpului total al

clasei Butoane);

- adăugarea la fereastra aplicaţiei a butoanelor şi a etichetei se face în constructorul clasei

IUG.

Punând în execuţie această aplicaţie, putem vedea cum se plasează cele cinci componente pe

suprafaţa ferestrei. Putem urmări, de asemenea, cum se modifică automat dimensiunile

componentelor atunci când modificăm cu mouse-ul dimensiunile ferestrei. Dacă facem click

de mouse pe oricare din butoane, se modifică atât contorul afişat pe butonul respectiv, cât şi

numărul total de acţionari afişat pe eticheta din partea inferioară a ferestrei.

Page 222: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

222

Clasa FlowLayout

Gestionarul de poziţionare java.awt.FlowLayout plasează componentele pe suprafaţa

containerului una după alta, în ordinea în care acestea sunt adăugate, de la stânga la dreapta şi

de sus în jos. Când s-a terminat o linie, se trece la linia următoare. Numărul de componente

pe o linie depinde de lăţimea componentelor şi de lăţimea containerului în care sunt acestea

plasate.

Este posibil să se specifice modul de aliniere a componentelor: la stânga, la dreapta sau la

centru. Aceasta se face fie specificând alinierea ca argument al constructorului, fie invocând

metoda public void setAlignement(int align)

în care argumentul align poate fi FlowLayout.LEFT, FlowLayout.RIGHT sau

FlowLayout.CENTER.

Exemplul 1

În fişierul ButoaneF.java este dat un exemplu de aplicaţie, în care se testează gestionarul de

poziţionare FlowLayout. În fereastra aplicaţiei sunt plasate mai multe butoane din clasa

ButonContor şi un buton de anulare a tuturor contoarelor. Numărul de butoane de contorizare

este dat la punerea în execuţie a aplicatiei, ca parametru în linia de comanda. Modificând cu

mouse-ul dimensiunile ferestrei, putem constata cum se modifică în mod corespunzator

dimensiunile şi amplasarea butoanelor. Îtrucât la crearea gestionarului de poziţionare nu s-a

precizat alinierea componentelor, modul de aliniere este implicit CENTER.

/* Testarea gestionarului de pozitionare FlowLayout.

In fereastra aplicatiei apar mai multe butoane din clasa ButonContor si un buton de anulare, a carui apasare anulaza toate contoarele.

La lansarea in executie se da ca parametru in linia de comanda numarul de butoane de contorizare */

import java.awt.*; import java.awt.event.*; import javax.swing.*;

class ButoaneF { static AF af=new AF(); // ascultatorul de fereastra static Anulare anulare=new Anulare(); // ascultatorul // butonului de anulare static IUG iug; // fereastra aplicatiei static int numarButoane;

static class IUG extends JFrame { JLabel lab=new JLabel("Actionati butoanele"); ButonContor bc[]; JButton br=new JButton("Reset");

IUG(String titlu) { // constructorul ferestrei aplicatiei super(titlu);

Page 223: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

223

Container cp=getContentPane(); setSize(300,150); setLocation(200,150); addWindowListener(af); cp.setLayout(new FlowLayout()); // setarea gestionarului // de pozitionare bc=new ButonContor[numarButoane]; for(int i=0; i<numarButoane; i++) { bc[i]=new ButonContor("B"+(i+1)); // crearea butoanelor cp.add(bc[i]); // adaugarea butoanelor la contentPane } cp.add(br); // adaugarea butonului de anulare br.addActionListener(anulare); // adaugarea ascultatorului setVisible(true); } }

static class AF extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } }

static class Anulare implements ActionListener { public void actionPerformed(ActionEvent e) { for(int i=0; i<numarButoane; i++) iug.bc[i].reset(); } }

public static void main(String args[]) throws Exception { if(args.length!=1) { System.out.println("Utilizare: java ButoaneF <numarButoane>"); System.exit(1); } numarButoane=Integer.parseInt(args[0]); // crearea tabloului de // butoane iug=new IUG("FlowLayout cu "+numarButoane+ " butoane de contorizare"); // crearea ferestrei aplicatiei } }

Remarcăm că aplicaţia ButoaneF este o modificare a aplicaţiei Butoane din fişierul

Butoane.java şi se deosebeşte de aceasta prin următoarele:

- în metoda main se preia un argument din linia de comandă, care trebuie să fie numărul de

butoane de acţionare solicitat de utilizator, după care se construieşte fereastra aplicaţiei;

- s-a introdus tabloul bc[] care conţine referinţe la instanţele clasei ButonContor. Atât acest

tablou, cât şi butoanele respective, se creează în constructorul clasei IUG;

- după adăugarea butoanelor de contorizare, se adaugă la fereastra aplicaţiei butonul de

anulare br, din clasa JButton;

- pentru ascultarea acţionării butonului de anulare, a fost declarată clasa imbricată Anulare,

care implementează interfaţa ActionListener.

Page 224: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

224

Exemplul 2

În fişierul Aliniere.java este dată o modificare a aplicaţiei din exemplul precedent, în care s-

au introdus trei butoane suplimentare, care au ca efect modificarea alinierii butoanelor pe

suprafaţa containerului. În acest scop:

- Pentru a se afla care buton a fost acţionat, în metoda actionPerformed() a clasei

imbricate de ascultare a evenimentelor de acţiune Actiuni s-a invocat metoda

getActionCommand()a clasei ActionEvent. Această metodă întoarce un String care, în mod

obisnuit, este textul de pe butonul respectiv. Este posibil, totuşi, să se modifice acest şir

folosind metoda setActionCommand(String command), care există în toate clasele care

generează evenimente de acţiune, de exemplu în clasa AbstractButton, din care este derivată

şi clasa JButton.

- Modificarea alinierii se face invocând pentru gestionarul de poziţionare metoda

setAlignment(int align) a clasei FlowLayout. Dupa ce s-a aplicat această metodă, se

invocă pentru conţinutul ferestrei (contentPane) metoda doLayout() a clasei Container,

pentru a se aplica efectiv noua poziţionare.

/* Testarea alinierii componentelor cand se foloseste gestionarul de pozitionare FlowLayout.

In fereastra aplicatiei apar mai multe butoane din clasa ButonContor, trei butoane de aliniere si un buton de anulare.

La lansarea in executie se da ca parametru in linia de comanda numarul de butoane de contorizare

Actionarea unuia din butoanele de aliniere are ca efect modificarea corespunzatoare a alinierii componentelor pe suprafata containerului

Actionarea butonului de anulare produce anuloarea tuturor contoarelor. */

import java.awt.*; import java.awt.event.*; import javax.swing.*;

class Aliniere { static AF af=new AF(); // ascultatorul de fereastra static Actiuni actiuni=new Actiuni(); // ascultatorul // butoanelor de aliniere si de anulare static IUG iug; // fereastra aplicatiei static int numarButoane; static FlowLayout layout=new FlowLayout();

static class IUG extends JFrame { JLabel lab=new JLabel("Actionati butoanele"); ButonContor bc[]; JButton br=new JButton("Anulare"); JButton bas=new JButton("Stanga"), bac=new JButton("Centru"), bad=new JButton("Dreapta");

IUG(String titlu) { // constructorul ferestrei aplicatiei super(titlu);

Page 225: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

225

Container cp=getContentPane(); setSize(300,150); setLocation(200,150); addWindowListener(af); cp.setLayout(layout); // setarea gestionarului de pozitionare bc=new ButonContor[numarButoane]; for(int i=0; i<numarButoane; i++) { bc[i]=new ButonContor("B"+(i+1)); // crearea butoanelor cp.add(bc[i]); // adaugarea butoanelor la contentPane } cp.add(bas); cp.add(bac); cp.add(bad); // adaugare butoane // de aliniere cp.add(br); // adaugarea butonului de anulare br.addActionListener(actiuni); // adaugarea ascultatorului bas.addActionListener(actiuni); bac.addActionListener(actiuni); bad.addActionListener(actiuni); setVisible(true); } }

static class AF extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } }

static class Actiuni implements ActionListener { public void actionPerformed(ActionEvent e) { String comanda=e.getActionCommand(); if(comanda.equals("Anulare")) for(int i=0; i<numarButoane; i++) iug.bc[i].reset(); else { if(comanda.equals("Stanga")) layout.setAlignment(FlowLayout.LEFT); else if(comanda.equals("Centru")) layout.setAlignment(FlowLayout.CENTER); else if(comanda.equals("Dreapta")) layout.setAlignment(FlowLayout.RIGHT); iug.getContentPane().doLayout(); } } }

public static void main(String args[]) throws Exception { if(args.length!=1) { System.out.println("Utilizare: java Aliniere <numarButoane>"); System.exit(1); } numarButoane=Integer.parseInt(args[0]); // crearea tabloului de // butoane iug=new IUG("FlowLayout cu "+numarButoane+ " butoane de contorizare"); // crearea ferestrei aplicatiei } }

Page 226: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

226

Clasa GridLayout

Gestionarele de poziţionare din clasa java.awt.GridLayout plasează componentele în

celulele unei grile rectangulare. În consecinţă, toate componentele de pe aceeaşi coloană sunt

aliniate vertical.

Clasa are doi constructori:

public GridLayout(int rows, int cols) - are ca argumente numărul de linii şi de

coloane al grilei;

public GridLayout(int rows, int cols, int hgap, int vgap) - are în plus ca

argumente spaţiul orizontal şi, respectiv, vertical între componente.

Deşi în constructor se indică atât numărul de linii, cât şi cel de coloane ale grilei, în realitate

numai numărul de linii este respectat, în timp ce numărul de coloane este practic ignorat. La

stabilirea amplasării componentelor în container, dacă numarul lor total este mai mic sau egal

cu cel de linii, toate componentele vor fi aşezate vertical, una sub alta. Dacă numărul de

componente este mai mare decât numărul de linii, numărul de coloane se stabileşte automat,

prin împărţirea numărului de componente la cel de linii, cu rotunjire în plus. Plasarea efectivă

a componentelor în celulele grilei astfel creeate se face apoi de la stânga la dreapta şi de sus

in jos, la fel ca în cazul gestionarului FlowLayout, dar respectând alinierea verticală şi

orizontală impusă de grilă.

Exemplu

În fişierul Grila.java se dă un exemplu de aplicaţie, în care se testează gestionarul de

poziţionare GridLayout. La punerea în execuţie a aplicaţiei, se dau ca parametri în linia de

comandă numărul total de butoane de contorizare, numărul de linii al grilei şi numărul de

coloane. Se poate observa ordinea în care sunt butoanele aşezate pe grilă şi modul în care se

schimbă aspectul ferestrei, dacă se modifică cu mouse-ul dimensiunile acesteia. Se poate

verifica şi ce se întâmplă dacă numărul de coloane dat ca parametru este mai mic sau mai

mare decât cel necesar.

/* Testarea alinierii componentelor cand se foloseste gestionarul de pozitionare GridLayout.

In fereastra aplicatiei apar mai multe butoane din clasa ButonContor si un buton de anulare.

Punerea in executie a aplicatiei se face prin comanda java Grila <numarContoare> <nrLinii> <nrColoane>

Actionarea butonului de anulare produce anuloarea tuturor contoarelor. */

import java.awt.*; import java.awt.event.*; import javax.swing.*;

class Grila { static AF af=new AF(); // ascultatorul de fereastra

Page 227: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

227

static Actiuni actiuni=new Actiuni(); // ascultatorul // butonului de anulare static IUG iug; // fereastra aplicatiei static int numarButoane, nrLinii, nrColoane;

static class IUG extends JFrame { JLabel lab=new JLabel("Actionati butoanele"); ButonContor bc[]; JButton br=new JButton("Anulare");

IUG(String titlu) { // constructorul ferestrei aplicatiei super(titlu); Container cp=getContentPane(); setSize(400,250); setLocation(200,150); addWindowListener(af); cp.setLayout(new GridLayout(nrLinii, nrColoane)); // setarea // gestionarului de pozitionare bc=new ButonContor[numarButoane]; for(int i=0; i<numarButoane; i++) { bc[i]=new ButonContor("B"+(i+1)); // crearea butoanelor cp.add(bc[i]); // adaugarea butoanelor la contentPane } cp.add(br); // adaugarea butonului de anulare br.addActionListener(actiuni); // adaugarea ascultatorului setVisible(true); } }

static class AF extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } }

static class Actiuni implements ActionListener { public void actionPerformed(ActionEvent e) { String comanda=e.getActionCommand(); if(comanda.equals("Anulare")) for(int i=0; i<numarButoane; i++) iug.bc[i].reset(); } }

public static void main(String args[]) throws Exception { /* Verificarea numarului de argumente din linia de comanda */ if(args.length!=3) { System.out.println( "Utilizare: java <numarButoane> <nrLinii> <nrColoane>"); System.exit(1); } /* Preluarea argumentelor din linia de comanda */ numarButoane=Integer.parseInt(args[0]); nrLinii=Integer.parseInt(args[1]); nrColoane=Integer.parseInt(args[2]); /* Crearea ferestrei aplicatiei */ iug=new IUG("GridLayout cu "+numarButoane+ " butoane de contorizare"); } }

Page 228: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

228

Clasa BoxLayout

Gestionarul de poziţionare javax.swing.BoxLayout plasează toate componentele

containerului pe o singură direcţie, care poate fi orizontală sau verticală.

Constructorul clasei este public BoxLayout(Container target, int axis)

în care target este o referinţa la containerul ţintă (al cărui gestionar de poziţionare este

creat), iar axis poate fi BoxLayout.X_AXIS sau BoxLayout.Y_AXIS şi indică direcţia (axa)

după care vor fi plasate componentele.

Exemplul 1

În fişierul ButoaneBox.java se dă un exemplu de aplicaţie, în care se testează clasa

BoxLayout. În acest caz, gestionarul BoxLayout a fost folosit direct în containerul

contentPane al ferestrei aplicaţiei. La lansarea aplicaţiei în execuţie, se indică numărul de

butoane de contorizare şi direcţia după care acestea vor fi plasate (x sau y). Se poate urmări

efectul modificării cu mouse-ul a dimensiunilor ferestrei. Se observă că dimensiunile

componentelor rămân constante, fără a mai fi influenţate de dimensiunile ferestrei.

/* Testarea gestionarului de pozitionare BoxLayout.

In fereastra aplicatiei apar mai multe butoane din clasa ButonContor si un buton de anulare, a carui apasare anulaza toate contoarele.

La lansarea in executie se da ca parametru in linia de comanda numarul de butoane de contorizare si numele axei in lungul careia vor fi plasate componentele (X sau Y). De exemplu, comanda java ButoaneBox 5 Y are ca efecte punerea in executie a aplicatiei cu 5 butoane contor si un buton de anulare, toate plasate unul sub altul */

import java.awt.*; import java.awt.event.*; import javax.swing.*;

class ButoaneBox { static AF af=new AF(); // ascultatorul de fereastra static Anulare anulare=new Anulare(); // ascultatorul // butonului de anulare static IUG iug; // fereastra aplicatiei static int numarButoane; static int axa;

static class IUG extends JFrame { JLabel lab=new JLabel("Actionati butoanele");

Page 229: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

229

ButonContor bc[]; JButton br=new JButton("Reset");

IUG(String titlu) { // constructorul ferestrei aplicatiei super(titlu); Container cp=getContentPane(); setSize(350,350); setLocation(200,150); addWindowListener(af); cp.setLayout(new BoxLayout(getContentPane(), axa)); bc=new ButonContor[numarButoane]; for(int i=0; i<numarButoane; i++) { bc[i]=new ButonContor("B"+(i+1)); // crearea butoanelor cp.add(bc[i]); // adaugarea butoanelor la contentPane } cp.add(br); // adaugarea butonului de anulare br.addActionListener(anulare); // adaugarea ascultatorului setVisible(true); } }

static class AF extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } }

static class Anulare implements ActionListener { public void actionPerformed(ActionEvent e) { for(int i=0; i<numarButoane; i++) iug.bc[i].reset(); } }

public static void main(String args[]) throws Exception { if(args.length!=2 ) { System.out.println( "Utilizare: java ButoaneBox <numarButoane> <axa>"); System.exit(1); } String numeAxa=args[1].toUpperCase(); if(numeAxa.equals("Y")) axa=BoxLayout.Y_AXIS; else if(numeAxa.equals("X")) axa=BoxLayout.X_AXIS; else { System.out.println("Axa nu poate fi decat X sau Y"); System.exit(1); } numarButoane=Integer.parseInt(args[0]); iug=new IUG("BoxLayout cu "+numarButoane+ " butoane de contorizare"); } }

În loc de a folosi gestionarul BoxLayout într-un container oarecare, se preferă să se

foloseasca clasa javax.swing.Box, care are acest gestionar implicit.

Page 230: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

230

Exemplul 2

În fişierul TestBox.java se dă o variantă a aplicaţiei din exemplul precedent, în care se

utilizează drept container pentru butoane o instanţă a clasei Box. În constructorul ferestrei

aplicaţiei, după ce se creeaza această instanţă a clasei Box, se adaugă la ea succesiv toate

componentele, după care este ea însăşi adaugată la conţinutul ferestrei aplicaţiei (la

contentPane). În această situaţie, gestionarul de poziţionare BoxLayout este folosit prin

intermediul instanţei clasei Box, în care sunt plasate componentele.

/* Testarea clasei javax.swing.Box

In fereastra aplicatiei apar mai multe butoane din clasa ButonContor si un buton de anulare, a carui apasare anulaza toate contoarele.

La lansarea in executie se da ca parametru in linia de comanda numarul de butoane de contorizare si numele axei in lungul careia vor fi plasate componentele (X sau Y). De exemplu, comanda java TestBox 5 Y are ca efecte punerea in executie a aplicatiei cu 5 butoane contor si un buton de anulare, toate plasate unul sub altul */

import java.awt.*; import java.awt.event.*; import javax.swing.*;

class TestBox { static AF af=new AF(); // ascultatorul de fereastra static Anulare anulare=new Anulare(); // ascultatorul // butonului de anulare static IUG iug; // fereastra aplicatiei static int numarButoane; static int axa;

static class IUG extends JFrame { JLabel lab=new JLabel("Actionati butoanele"); ButonContor bc[]; JButton br=new JButton("Reset"); Box box;

IUG(String titlu) { // constructorul ferestrei aplicatiei super(titlu); setSize(350,350); setLocation(200,150); addWindowListener(af); box=new Box(axa); // se creeaza o instanta a clasei Box // orientata pe directia axa bc=new ButonContor[numarButoane]; for(int i=0; i<numarButoane; i++) { bc[i]=new ButonContor("B"+(i+1)); // crearea butoanelor box.add(bc[i]); // adaugarea butoanelor la caseta box } box.add(br); // adaugarea butonului de anulare br.addActionListener(anulare); // adaugarea ascultatorului getContentPane().add(box); // adaugarea casetei box la

Page 231: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

231

// contentPane setVisible(true); } }

static class AF extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } }

static class Anulare implements ActionListener { public void actionPerformed(ActionEvent e) { for(int i=0; i<numarButoane; i++) iug.bc[i].reset(); } }

public static void main(String args[]) throws Exception { if(args.length!=2 ) { System.out.println( "Utilizare: java Box <numarButoane> <axa>"); System.exit(1); } String numeAxa=args[1].toUpperCase(); if(numeAxa.equals("Y")) axa=BoxLayout.Y_AXIS; else if(numeAxa.equals("X")) axa=BoxLayout.X_AXIS; else { System.out.println("Axa nu poate fi decat X sau Y"); System.exit(1); } numarButoane=Integer.parseInt(args[0]); iug=new IUG("Box cu "+numarButoane+ " butoane de contorizare"); } }

Poziţionarea absolută a componentelor în container

În general, este recomandabil ca pentru amplasarea componentelor în containere să se

folosească gestionari de poziţionare. În acest fel se asigură modificarea automată a poziţiei şi

dimensiunilor componentelor, atunci când se modifică dimensiunile containerului. Există

totuşi situaţii, în care se preferă ca poziţiile şi dimensiunile componentelor să fie fixe şi să fie

indicate prin program. Din această cauză, în afară de amplasarea flexibilă a componentelor în

containere, folosind clasele de gestionare a poziţionării, este posibil să se proiecteze şi

interfeţe grafice în care poziţionarea componentelor se face folosind coordonatele şi

dimensiunile absolute ale acestora. În acest scop:

a/ pentru a se indica faptul că nu se foloseşte un gestionar de poziţionare, se recurge la

instrucţiunea:

setLayout(null);

b/ pentru stabilirea coordonatelor colţului din stânga sus şi dimensiunilor fiecărei

componente se foloseşte metoda public void setBounds(int x, int y, int width, int height);

Page 232: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

232

din clasa java.awt.Component. În acest mod, fiecare componentă este plasată în container cu

colţul stânga-sus în punctul de coordonate (x,y)şi are dimensiunile date prin lăţimea width

şi înălţimea height.

În locul metodei setBounds se pot folosi şi metodele public void setLocation(Point location) public void setSize(int latime, int inaltime)

care există, de asemenea, în clasa Component şi permit setarea separată a poziţiei şi

dimensiunilor componentelor.

Poziţia şi dimensiunile astfel stabilite ale componentelor rămân neschimbate, chiar dacă se

modifică dimensiunile containerului care le conţine.

Exemplu:

În fişierul PozAbs.java se dă un exemplu de aplicaţie, în care se recurge la poziţionarea

absolută a componentelor pe suprafaţa ferestrei principale a aplicaţiei, care este o instanţă a

clasei JFrame.

În fereastră (mai exact în containerul contentPane al ferestrei) se plasează următoarele

componente:

- o etichetă cu textul "Butoane de contorizare";

- patru butoane de contorizare ale clasei ButonContor, creată de noi anterior;

- o etichetă cu textul "Anularea tuturor contoarelor >>>";

- un buton din clasa JButton cu inscriptia "Reset", care serveşte aici pentru a comanda

punerea la zero a tuturor contoarelor.

Pentru a realiza poziţionarea absolută a acestor componente, se seteaza la null gestionarul de

poziţionare al containerului contentPane conţinut în fereastra aplicaţiei, iar pentru fiecare

componentă se indică poziţia şi dimensiunile, invocând metoda setBounds().

/* Pozitionarea absoluta a componentelor in container */

import java.awt.*; import java.awt.event.*; import javax.swing.*;

class PozAbs { static AF af=new AF(); // ascultatorul de fereastra static AA aa=new AA(); // ascultatorul de actiuni static IUG iug=new IUG("Pozitionare absoluta");

static class IUG extends JFrame { JLabel et1=new JLabel("Butoane de contorizare"); JLabel et2=new JLabel("Anularea tuturor contoarelor >>>"); JButton br=new JButton("Reset"); int numarContoare=4; ButonContor bc[]=new ButonContor[numarContoare];

/* Constructorul ferestrei aplicatiei */

Page 233: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

233

IUG(String titlu) { super(titlu); Container cp=getContentPane(); setSize(420,220); setLocation(200,150); addWindowListener(af); cp.setLayout(null); // se elimina gestionarul de pozitionare din // contentPane et1.setBounds(150, 5, 160,10); // pozitia si dimensiunile etichetei cp.add(et1); // adaugarea etichetei for(int i=0; i<numarContoare; i++) { bc[i]=new ButonContor("B"+i); // crearea butoanelor-contor bc[i].setBounds(10+100*i, 20, 90,70); // stabilirea pozitiei // si dimensiunilor butoanelor-contor cp.add(bc[i]); // adaugarea butoanelor-contor la contentPane } et2.setBounds(10, 140, 200,10); // locul si dimens. etichetei 2 cp.add(et2); // adaugarea etichetei 2 la contentPane br.setBounds(210, 120, 70, 60); // pozitia si dimensiunile // butonului de anulare br.addActionListener(aa); // ascultarea butonului de anulare cp.add(br); // adaugarea butonului de anulare la contentPane setVisible(true); } }

/* Ascultatorul actiunilor butonului de anulare. Cand este apasat acest buton, se pun la zero toate contoarele */ static class AA implements ActionListener { public void actionPerformed(ActionEvent e) { for(int i=0; i<iug.numarContoare; i++) iug.bc[i].reset(); } }

/* Ascultarea evenimentelor de fereastra */ static class AF extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } }

public static void main(String args[]) { } }

Gruparea componentelor

Pentru a poziţiona componentele în structuri mai complicate decât cele oferite de clasele de

gestionare a poziţiei existente, se poate recurge la gruparea mai multor componente în

containere auxiliare, care se plasează apoi în containerul principal. Drept containere auxiliare,

se folosesc cel mai frecvent instanţe ale claselor java.awt.Panel, javax.swing.JPanel şi

javax.swing.Box.

Page 234: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

234

Clasele Panel si Jpanel

Clasa java.awt.Panel (panou) reprezinta cel mai simplu container, care este o suprafaţă

dreptunghiulară fără bordură. Gestionarul de poziţionare implicit este FlowLayout, dar se

poate pune oricare altul. Panourile sunt frecvent folosite pentru a plasa pe ele diferite

componente, formând un grup care se plaseaza apoi într-un alt container. Clasa

javax.swing.JPanel este varianta de Panel folosită în JFC/Swing, fiind un container genreric.

Exemplu

În fişierul Panouri.java este dat un exemplu în care fereastra aplicaţiei, cu gestionar de

pozitionare GridLayout, conţine în cele patru celule ale reţelei două panouri şi două butoane

de anulare. Un panou conţine 5 butoane de contorizare amplasate cu gestionar BorderLayout,

iar alt panou conţine trei butoane de contorizare amplasate cu FlowLayout (gestionarul

implicit). Fiecare buton de anulare pune la zero contoarele de apăsări dintr-un panou.

import java.awt.*; import java.awt.event.*; import javax.swing.*;

class Panouri { static ButonContor bc[]=new ButonContor[8]; static JButton br1=new JButton("Reset 1"), br2=new JButton("Reset 2"); static Anulare anulare=new Anulare(); static IUG iug=new IUG("Gruparea componentelor pe panouri");

static class IUG extends JFrame { JPanel p1=new JPanel(); // p1 are implicit FlowLayout JPanel p2=new JPanel(new BorderLayout()); // p2 primeste BorderLayout

IUG(String titlu) { super(titlu); Container cp=getContentPane(); setSize(500,400); addWindowListener(new AF()); cp.setLayout(new GridLayout(2,2)); /* Crearea butoanelor */ for(int i=0; i<8; i++) bc[i]=new ButonContor("B"+i); /* Completarea cu butoane a panoului p2 */ p2.add(bc[0], BorderLayout.NORTH); p2.add(bc[1], BorderLayout.WEST); p2.add(bc[2], BorderLayout.CENTER); p2.add(bc[3], BorderLayout.EAST); p2.add(bc[4], BorderLayout.SOUTH); /* Completarea panoului p1 */ for(int i=5; i<8; i++) p1.add(bc[i]); /* Adaugarea de ascultatori la butoanele de anulare */ br1.addActionListener(anulare); br2.addActionListener(anulare); /* Adaugarea de panouri si butoane la controlPane */ cp.add(p2); cp.add(p1); cp.add(br1);

Page 235: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

235

cp.add(br2); setVisible(true); } }

static class AF extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } }

static class Anulare implements ActionListener { public void actionPerformed(ActionEvent e) { String actiune=e.getActionCommand(); if(actiune.equals(br1.getText())) for(int i=0; i<5; i++) bc[i].reset(); else if(actiune.equals(br2.getText())) for(int i=5; i<8; i++) bc[i].reset(); } }

public static void main(String args[]) { } }

Clasa Box

Clasa javax.swing.Box are ca instanţe containere speciale, care nu pot folosi decât

gestionarul de poziţionare javax.swing.BoxLayout. Orice incercare de a-i pune alt gestionar

produce o eroare de execuţie din clasa AWTError.

Într-un container din clasa Box, componentele pot fi amplasate numai pe o singură direcţie:

orizontală sau verticală.

Clasa dispune de metode statice pentru crearea de "casete" (instanţe ale clasei Box) orizontale

sau verticale: public static Box createHorizontalBox() public static Box createVerticalBox()

Se pot creea, de asemenea "componente invizibile" de dimensiuni fixe sau variabile, care pot

fi folosite la distanţarea componentelor vizibile. În acest scop, se folosesc metodele

public static Component createRigidArea(Dimension d) - creeaza o

"componentă ascunsă" de dimensiune fixă;

public static Component createHorizontalStrut(int width) - creeaza o

"componentă ascunsă" de lăţime fixă, dar de înălţime variabilă;

public static Component createVerticalStrut(int height) - creeaza o

"componentă ascunsă" de înalţime fixă, dar de lăţime variabilă;

public static Component createGlue() - creaza o "componentă ascunsă" cu

ambele dimensiuni variabile;

Page 236: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

236

Combinarea adecvată de containere din clasa Box şi folosirea în acestea a diferitelor

componente vizibile şi ascunse permite crearea de interfeţe grafice cu aspecte foarte

diversificate.

Exemplu

În fişierul Casete.java este dată o aplicaţie în care se folosesc trei casete din clasa Box: două

verticale şi una orizontală.

/* Exemplu de utilizare a containerelor din clasa javax.swing.Box */

import java.awt.*; import java.awt.event.*; import javax.swing.*;

class Casete { static ButonContor bc[]=new ButonContor[5]; static JButton br1=new JButton("Reset 1"), br2=new JButton("Reset 2"); static Anulare anulare=new Anulare(); static IUG iug=new IUG("Gruparea componentelor in casete");

static class IUG extends JFrame { Box c1=Box.createVerticalBox(); Box c2=Box.createVerticalBox(); Box c3=Box.createHorizontalBox();

IUG(String titlu) { super(titlu); setSize(280,160); addWindowListener(new AF()); /* Crearea butoanelor */ for(int i=0; i<5; i++) bc[i]=new ButonContor("B"+i); /* Completarea cu butoane a casetei c1 */ c1.add(Box.createVerticalStrut(18)); // deplasare in jos c1.add(bc[0]); c1.add(bc[1]); c1.add(Box.createVerticalStrut(10)); // deplasare in jos c1.add(br1); /* Completarea casetei c2 */ for(int i=2; i<5; i++) c2.add(bc[i]); c2.add(Box.createVerticalStrut(5)); // deplasare in jos c2.add(br2); /* Adaugarea de ascultatori la butoanele de anulare */ br1.addActionListener(anulare); br2.addActionListener(anulare); /* Adaugarea casetelor c1 si c2 la caseta c3 */ c3.add(Box.createGlue()); // pentru alinierea la centru c3.add(c1); c3.add(Box.createHorizontalStrut(10)); c3.add(c2); /* Adaugarea casetei c3 la contentPane */ getContentPane().add(c3); setVisible(true);

Page 237: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

237

} }

static class AF extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } }

static class Anulare implements ActionListener { public void actionPerformed(ActionEvent e) { String actiune=e.getActionCommand(); if(actiune.equals(br1.getText())) for(int i=0; i<2; i++) bc[i].reset(); else if(actiune.equals(br2.getText())) for(int i=2; i<5; i++) bc[i].reset(); } }

public static void main(String args[]) { } }

Remarcăm următoarele:

- butoanele au fost plasate în cele două casete verticale, c1 şi c2;

- întrucât numărul de butoane din cele două casete este diferit, în caseta c1 s-a introdus o

componentă ascunsă pentru alinierea la partea inferioară. De asemenea, în ambele casete

verticale s-au introdus în faţa ultimului buton componente ascunse pentru distanţare;

- cele două casete verticale au fost introduse în cea orizontală;

- componenta ascunsă cu dimensiuni variabile, introdusă în faţa primei casete din c3, a fost

pusă pentru a se obţine alinierea pe centru a casetelor c1 şi c2. În lipsa acesteia, caseta c1 ar fi

fost aliniată la stânga;

- caseta c3 a fost introdusă în contentPane.

Urmăriţi ce se întâmplă când modificaţi cu mouse-ul dimensiunile ferestrei aplicaţiei.

Întrebări

Nivel 1

1. Ce este interfaţa utilizator?

2. Ce este interfaţa utilizator grafică?

3. Ce sunt obiectele grafice?

4. Ce este AWT?

5. Ce este JFC/Swing?

6. Ce rol are clasa Component şi din ce pachet face parte?

7. Ce deosebire este între componentele atomice şi containere?

8. Care este clasa folosită în JFC/Swing pentru fereastra principală a aplicaţiei?

9. Ce conţin la partea superioară instanţele clasei JFrame?

Page 238: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

238

10. Ce sunt evenimentele în cazul interfeţei utilizator grafice?

11. Ce este programarea orientată pe evenimente?

12. Care este modelul de evenimente folosit pe platforma Java 2?

13. Cum sunt generate evenimentele?

14. Cum sunt utilizate evenimentele?

15. Ce deosebire este între evenimentele de nivel jos şi cele semantice?

16. Care este rădăcina claselor de evenimente generate de obiectele interfeţei grafice?

17. Ce clase de evenimente cunoasteţi?

18. În ce pachete se găsesc clasele de evenimente?

19. Ce sunt interfeţele pentru ascultarea de evenimente şi la ce folosesc?

20. Care este rolul unei clase ascultătoare de evenimente?

21. Ce este un adaptor pentru ascultarea de evenimente?

22. Cum poate fi comandată prin interfaţa utilizator grafică încheierea executării

aplicaţiei?

23. Care este componenta instanţei clasei JFrame la care se adaugă componentele

interfeţei grafice?

24. Ce este un gestionar de poziţionare?

25. Care sunt interfeţele gestionarilor de poziţionare?

26. Care este gestionarul de poziţionare implicit pentru contentPane?

27. Care este gestionarul de poziţionare implicit pentru Panel şi JPanel?

28. Cum sunt amplasate componentele în cazul gestionarului BorderLayout?

29. Cum sunt amplasate componentele în container în cazul gestionarului FlowLayout?

30. Cum sunt aliniate componentele în cazul gestionarului FlowLayout?

31. Ce fel de evenimente generează un buton?

32. Cum sunt amplasate componentele în cazul gestionarului GridLayout?

33. Cum se stabileste numarul de linii şi de coloane pentru gestionarul GridLayout?

34. Cum sunt plasate componentele într-un BoxLayout?

Nivel 2

1. Ce categorii de interfeţe utilizator cunoasteţi?

2. Ce este un limbaj de comandă şi ce astfel de limbaje cunoasteţi?

3. Care sunt în prezent cele mai larg folosite interfeţe utilizator grafice?

4. Prin ce pachete se realizează AWT pe platformele Java?

5. Prin ce pachete se realizează JFC/Swing pe platforma Java 2?

6. In ce constă deosebirea de abordare între AWT şi JFC/Swing?

7. Ce metode ale clasei Component cunoasteţi?

8. Ce metode ale clasei JFrame cunoasteţi?

9. Cum este ghidat procesul de calcul în programarea procedurală tradiţională?

10. Cine are iniţiativa acţiunilor în programarea orientată pe evenimente?

11. Care sunt obiectele care intervin atunci când se generează un eveniment?

12. Ce sunt evenimentele de mouse şi cum sunt ele generate?

13. Ce sunt evenimentele de tastă şi cum sunt ele generate?

14. Care sunt evenimentele generate de o fereastră şi cum sunt ele ascultate?

15. Care sunt evenimentele de mouse?

16. Cum sunt ascultate evenimentele de mouse?

17. Care sunt evenimentele de tasta?

18. Cum sunt ascultate evenimentele de tasta?

19. În ce stare trebuie sa fie fereastra pentru a genera evenimente de tastă?

Page 239: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

239

20. În ce clasă există metoda getContentPane() şi la ce foloseşte?

21. Cum se adaugă un ascultător la o sursă?

22. Poate un obiect grafic să-şi asculte propriile evenimente? Cum se programează

aceasta?

23. Care sunt zonele unui BorderLayout şi câte componente pot fi plasate în fiecare zonă?

24. Ce se întâmplă cu componentele unui container cu gestionar BorderLayout dacă se

modifică dimensiunile acestuia?

25. Dacă într-un container există mai multe butoane, cum se poate afla care din ele a fost

acţionat atunci când este receptat un eveniment de acţiune?

26. Ce se întâmplă cu componentele unui container cu gestionar FlowLayout, dacă se

modifică laţimea acestuia?

27. Ce se întâmplă în cazul gestionarului GridLayout, dacă numarul de componente

conţinute este mai mare decât numărul de celule ale grilei stabilite la crearea

containerului?

28. În ce ordine se plasează componentele adăugate la un container cu gestionar

GridLayout?

29. Ce legatură există între clasele Box şi BoxLayout?

30. Ce se înţelege prin poziţionarea absolută a componentelor?

31. Cum se setează gestionarul de poziţionare pentru a realiza poziţionarea absolută?

32. Ce metode se folosesc pentru poziţionarea absolută a componentelor?

33. Ce fel de containere auxiliare se folosesc pentru gruparea componentelor?

34. Ce este un Panel sau un JPanel?

35. Ce reprezintă clasa Box?

36. Cum pot fi create instanţele clasei Box?

37. Ce componente ascunse se pot pune într-un container din clasa Box?

Page 240: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

240

Componente grafice din JFC/Swing

Componente ale interfeţei utilizator grafice 240

Clasa JComponent 241

Componente de control 244

Butoane 244

Clasa AbstractButton 244

Butoane obişnuite (cu o singură stare stabilă) 245

Butoane cu două stări stabile 245

Casete de validare 246

Butoane radio 246

Liste 249

Liste ascunse 250

Câmpuri de text 253

Rigle cu cursor 256

Meniuri 258

Meniuri cu bară 258

Meniuri volante 260

Componente de afişare 262

Componente de afişare needitabile 262

Componente de afişare editabile 263

Întrebări. 265

Componentele din JFC/Swing

Pentru a realiza interfaţa utilizator grafică a unei aplicaţii folosind JFC/Swing, este necesar ca

la fereastra aplicaţiei (din clasa JFrame) să se adauge diferite obiecte grafice numite

componente. Deosebim:

1. Componente de control: butoane, butoane radio, casete de validare, liste, liste ascunse,

meniuri, rigle ajustabile, câmpuri de text.

2. Componente de afişare needitabile: etichete, indicatoare, etc.

3. Componente de afişare editabile: zone de text, tabele editabile, selectoare de culori,

selectoare de fişiere, arbori.

4. Containere: panouri, panouri glisante, etc.

O prezentare a acestor componente însoţită de ilustraţii sugestive şi de descrierea detaliată a

utilizării fiecăreia se găseşte în lecţia Using Swing Components din sectiunea Creating a GUI

Page 241: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

241

with JFC/Swing din Java Tutorial. Noi nu vom face aici, din lipsă de timp, decât o scurta

prezentare a unor componente mai larg folosite şi a modului lor de utilizare.

Majoritatea claselor de componente din JFC/Swing sunt derivate din clasa JComponent,

moştenind caracteristicile acestei clase.

Clasa JComponent

Clasa abstracta javax.swing.JComponent extinde clasa java.awt.Container. In consecinţă,

orice componenta Swing are şi caracteristici de container.

Iată, ca exemplu, câteva facilităţi pe care le ofera orice JComponentă:

- posibilitatea de a-i ataşa componentei o "inscripţie volanta" (engleză: ToolTip), adică o

inscripţie explicativă care apare când punem cursorul de mouse pe componenta respectivă,

fără să apăsăm butonul. O astfel de inscripţie se ataşează componentei prin metoda

public void setToolTipText(String text);

- posibilitatea de a-i pune componentei o bordură, folosind metoda public void setBorder(Border border); - posibilitatea de a modifica culoarea de fond şi culoarea de primplan ale componentei

folosind metodele: public void setBackground(Color color); public void setForeground(Color color);

Mai multe metode sunt indicate în Indexul de clase.

O specificaţie mai detaliată a clasei JComponent este dată în indexul de clase.

Specificaţia completă a clasei JComponent este dată in documentaţia Java API, iar o descriere

amplă a facilităţilor şi modului de utilizare se găseşte în capitolul The JComponent class din

tutorialul Java.

Caracteristicile componentelor JFC/Swing

Fiecare componentă a interfeţei utilizator grafice se caracterizează prin aspect, stare şi

comportament.

Aspectul este dat de figura prin care este reprezentată pe ecran componenta respectivă.

Fiecare clasă de componente oferă un aspect tipic al instanţelor sale. În JFC/Swing

programatorului i se pun însa la dispoziţie metode şi clase prin care poate modifica aspectul

componentelor.

Starea componentei este dată, ca la orice obiect, de valorile câmpurilor sale. Starea se poate

modifica fie datorită acţiunilor utilizatorului, fie datorită invocării prin program a unor

metode ale acesteia. În general, la modificarea stării componenta generează un eveniment, iar

uneori îşi schimbă şi aspectul.

Comportamentul componentei este modul în care aceasta reacţionează atunci cînd se

acţionează asupra ei de către utilizator sau când este invocată o metodă şi constă în

modificarea stării şi a aspectului şi în generarea de evenimente.

Page 242: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

242

Componentele din JFC/Swing oferă programatorului unele facilităţi importante privind

stabilirea aspectului şi comportamentului acestora. Iată unele ditre ele:

- posibilitatea de a introduce în componentă un text, o imagine, sau ambele;

- posibilitatea de a adăuga la fiecare componentă a unui text explicativ volant (engleză:

Tool Tip), care conţine indicaţii care apar când se pune cursorul mouse-ului pe componenta

respectivă, fără a apăsa butonul de mouse.

- posibilitatea de a pune în jurul componentei una sau mai multe borduri (engleză: Border),

cu diferite aspecte: chenar simplu, chenar cu titlu, bordură care dă aspect de supraînălţare,

bordură care dă aspect de scufundare;

- posibilitatea de a alege aspectul general al tuturor componentelor interfeţei grafice

(engleză: Look and Feel).

Pentru a ataşa componentei un text volant se foloseşte metoda clasei JComponent public void setToolTipText(String text);

Pentru a pune o bordură se foloseşte clasa javax.swing.BorderFactory care oferă metode

pentru crearea unor borduri standard. Clasele de borduri şi interfaţa Border se gasesc în

pachetul javax.swing.border.

Adăugarea bordurii la componentă se face prin metoda clasei JComponent public void setBorder(Border border);

Iată unele din metodele clasei BorderFactory:

public static Border createLineBorder(Color color) - creează o bordură (un

chenar) dintr-o singură linie;

public static Border createLineBorder(Color color, int thickness) -

creează o bordură formată dintr-o linie de grosime (thickness) dată;

public static Border createRaisedBevelBorder() - creeaza o bordură cu aspect

de înălţare a componentei;

public static Border createLoweredBevelBorder() - creeaza o bordura cu

aspect de scufundare a componentei; public static Border createBevelBorder(int type, Color highlight,

Color shadow) - creeaza o bordură pentru care se impun tipul şi culorile, unde:

type - tipul bordurii, care poate fi BevelBorder.RAISED sau BevelBorder.LOWERED;

highlight - culoarea marginii care creează aspectul de înălţare sau coborâre;

shadow - culoarea umbrei.

public static TitledBorder createTitledBorder(String title) - creeaza o

bordură cu titlu. public static CompoundBorder createCompoundBorder(Border

outsideBorder, Border insideBorder) - creeaza o bordură compusă, indicându-se

bordura exterioară (outsideBorder) şi cea interioara (insideBorder).

Exemplu

În fişierul TestComp.java este dat un exemplu de testare a posibilităţii de a stabili aspectul

Page 243: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

243

componentelor şi a le ataşa texte volante. Drept componente s-au folosit, deocamdată,

instanţe ale clasei JButton, care a mai fost deja utilizată în capitolul precedent. Acelaşi mod

de lucru poate fi însă folosit pentru orice alte clase care sunt derivate din JComponent.

import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.border.*;

class TestComp { static AF af=new AF(); static IUG iug=new IUG("Butoane cu diferite aspecte");

/* clasa imbricata pentru interfata utilizator grafica */ static class IUG extends JFrame { //JLabel lab1, lab2, lab3, lab4; //JPanel panel; JButton b1,b2,b3,b4,b5,b6,b7;

IUG(String titlu) { // constructorul clasei IUG super(titlu); setSize(300, 400); setLocation(200, 150); Container cp=getContentPane(); addWindowListener(af); // adaugarea ascultatorului de fereastra //panel=new JPanel(); cp.setLayout(new GridLayout(7,1)); //panel.setBackground(Color.red); b1=new JButton("Un buton obisnuit"); //b1.setBackground(Color.blue); b2=new JButton("Un buton cu bordura liniara"); b2.setBorder(BorderFactory.createLineBorder(Color.red, 4)); b2.setToolTipText("Bordura este rosie cu grosimea 4"); b3=new JButton("Un buton cu bordura cu titlu"); b3.setBorder(BorderFactory.createTitledBorder("Un titlu")); b4=new JButton("Un buton ridicat"); b4.setBorder(BorderFactory.createRaisedBevelBorder()); b5=new JButton("Un buton coborat"); b5.setBorder(BorderFactory.createLoweredBevelBorder()); b6=new JButton(new ImageIcon("buton_go.gif")); b6.setBorder(BorderFactory.createTitledBorder( "Un buton cu titlu, care contine o imagine")); b7=new JButton("Un buton cu bordura compusa"); Border bord1, bord2, bord3; bord1=BorderFactory.createBevelBorder(BevelBorder.RAISED, Color.green, Color.blue); bord2=BorderFactory.createBevelBorder(BevelBorder.LOWERED, Color.cyan, Color.yellow); bord3=BorderFactory.createCompoundBorder(bord1, bord2); b7.setBorder(bord3); cp.add(b1); cp.add(b2); cp.add(b3); cp.add(b4); cp.add(b5); cp.add(b6); cp.add(b7); setVisible(true);

Page 244: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

244

} }

/* Clasa ascultatoare de fereastra */ static class AF extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); // incheierea executarii aplicatiei } }

/* Metoda principala a aplicatiei */ public static void main(String args[]) { } }

Remarcăm următoarele:

- pentru a lucra cu borduri, a fost necesar să se importe pachetul javax.swing.border;

- s-au folosit bordurile standard din clasa BorderFactory;

- butonului al doilea (b2, cel cu bordura roşie groasă) i s-a ataşat un text explicativ volant;

dacă punem cursorul de mouse deasupra acestui buton fără să apăsăm şi aşteptăm câteva

secunde, apare textul volant;

- în penultimul buton (b6) s-a introdus imaginea care se găseşte în fişierul

buton_go.gif. Dacă doriţi sa testati programul, această imagine trebuie să existe în acelaşi

director cu clasa TestComp (deci în directorul curent al dvs). Pentru a realiza acest lucru,

puneţi cursorul mouse-ului pe această imagine, apasaţi butonul din dreapta şi va apare un

meniu din care selectaţi opţiunea "Save image as ..." sau "Save picture as ...", apoi salvaţi

imaginea în acelaşi director cu fişierul TestComp.java.

Componente de control

Componentele de control sunt dispozitive de intrare virtuale, uşor de utilizat, prin intermediul

cărora utilizatorul poate introduce anumite comenzi. Din această categorie fac parte

butoanele, riglele ajustabile, listele, listele ascunse, meniurile şi câmpurile de text.

Butoane

Butoanele sunt obiecte grafice, al căror aspect este similar celor al butoanelor folosite în

aparatura electronică şi electrică. Acţionarea butonului se face punând deasupra lui cursorul

mouse-ului şi apasând un buton al acestuia. În JFC/Swing există mai multe tipuri de butoane:

butonul simplu, caseta de validare, butonul radio şi articolul de meniu. Toate acestea sunt

subclase ale clasei abstracte javax.swing.AbstractButton.

Clasa AbstractButton

Clasa javax.swing.AbstractButton defineşte caracteristicile comune ale diferitelor tipuri de

butoane din JFC/Swing.

Iată câteva dintre acestea:

Page 245: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

245

- orice buton poate avea un text, care poate fi pus prin metoda void setText(String

text) şi poate fi aflat prin metoda String getText();

- orice buton poate avea cel puţin o pictogramă, care poate fi pusă prin metoda void

setIcon(Icon defaultIcon) şi obţinută prin metoda Icon getIcon();

- orice buton poate avea o mnemonică, adică i se poate asocia o tastă, a cărei apasare are

acelaşi efect cu apăsarea cu mouse-ul a butonului respectiv. Mnemonica se pune cu metoda

void setMnemonic(int mnemonic), al cărei argument este codul tastei care trebuie

acţionată;

- butonul generează trei tipuri de evenimente:

. ActionEvent, când se acţioneaza asupra lui;

. ChangeEvent, când îşi modifică starea;

. ItemEvent, când butonul este selectat sau deselectat.

Există metode de adăugare a ascultătoarelor pentru aceste trei tipuri de evenimente: void addActionListener(ActionListener a), void addChangeListener(ChangeListener c),

void addItemListener(ItemListener i);

- butonul are un nume al acţiunii de comandă pe care o exercită, sub forma unui şir de

caractere; implicit, acest nume este identic cu textul butonului, dar el poate fi modificat prin

metoda

void setActionCommand(String command) şi poate fi aflat prin metoda

String getActionCommand();

O prezentare mai amplă a clasei AbstractButton este dată în Indexul de clase.

În secţiunile următoare vom prezenta modul de utilizare a diferitelor tipuri de butoane,

folosind clasele corespunzătoare ale pachetului javax.swing.

Butonul obişnuit (cu o singură stare stabilă)

Butoanele obişnuite se realizează folosind clasa javax.swing.JButton, derivată din clasa

javax.swing.AbstractButton, aşa cum am arătat în exemplele date în capitolul precedent.

Butonul obişnuit are o singură stare stabilă, în care ajunge când este eliberat. Cât timp se

ţine butonul de mouse apăsat deasupra lui, butonul se află în starea "apăsat" ("acţionat"). De

fiecare dată când este acţionat, butonul generează un AcţionEvent şi un ChangeEvent. Când

este eliberat, generează numai un ChangeEvent. Butonul generează de asemenea, ca orice altă

componentă, evenimente de componentă, de mouse şi de tastă. Totuşi, în cazul butoanelor

obişnuite, cel mai frecvent se folosesc evenimentele de acţiune (ActionEvent), care sunt

ascultate de un ascultător de acţiune (ActionListener). Clasele Button şi JButton sunt

specificate mai detaliat în Indexul de clase.

Butonul cu două stări stabile

Clasa javax.swing.JToggleButton este derivata din javax.swing.AbstractButton şi

reprezintă butoane cu două stări stabile. Trecerea de la o stare la alta este impusă de utilizator

prin click de mouse sau este comandată prin program. În practică, cel mai frecvent se

folosesc caseta de validare şi butonul radio, realizate prin subclase ale clasei ToggleButton şi

prezentate în continuare. O specificare mai detaliată a clasei JToggleButton este dată în

indexul de clase.

Page 246: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

246

Caseta de validare

Caseta de validare este un obiect de control cu două stări stabile. La fiecare click de mouse

pe suprafata casetei de validare, aceasta trece dintr-o stare în cealaltă. În mod obişnuit, caseta

de validare este reprezentată grafic printr-un patrat, în care apare un simbol de bifare (de

validare), cum ar fi simbolul V sau X, când caseta se găseşte în starea "selectat". În starea

opusă (deselectat), caseta este vidă. Imaginea casetei este insoţită şi de un text explicativ.

În unele sisteme de interfaţă grafică, în locul casetei de validare se foloseste un comutator

("switch"). Acesta are aspectul unui buton, la care ambele stări ("apăsat" şi "eliberat") sunt

stabile, trecerea de la o stare la alta făcându-se la fiecare click de mouse pe suprafaţa

butonului. Din punct de vedere funcţional, astfel de comutatoare se comporta identic cu

casetele de validare, diferenţa fiind numai în aspectul grafic.

În JFC/Swing casetele de validare se realizează folosind clasa javax.swing.JCheckBox, care

este derivată din clasa javax.swing.JToggleButton.

Dintre evenimentele generate de caseta de validare, cel mai important este

java.awt.event.ItemEvent, care este ascultat de clase cu interfaţa

java.awt.event.ItemListener. Astfel de evenimente sunt generate în momentele în care

caseta a fost selectată sau deselectată. Metoda prin care se captează astfel de evenimente într-

un ItemListener este public void itemStateChanged(ItemEvent e)

Pentru a afla în ce stare se gaseşte caseta la un moment dat, se foloseşte metoda public boolean isSelected()

din superclasa javax.swing.AbstractButton.

Butonul radio

Butonul radio este un buton cu două stări stabile, care face parte dintr-un grup de butoane,

astfel că la un moment dat numai unul dintre ele poate fi "selectat". În momentul în care este

selectat ("apăsat") un buton al grupului, se deselectează automat cel care era selectat anterior.

În JFC/Swing, butoanele radio sunt realizate ca instanţe ale clasei

javax.swing.JRadioButton, care este derivată din clasa javax.swing.JToggleButton.

Gruparea butoanelor se face folosind clasa javax.swing.ButtonGroup.

Exemplu

În fişierul TestButoane.java se dă un exemplu de aplicaţie, în care se testează butoanul

simplu, caseta de validare şi butonul radio.

import java.awt.*; import java.awt.event.*;

Page 247: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

247

import javax.swing.*;

class TestButoane { static AF af=new AF(); static Ascultator ascult=new Ascultator(); static IUG iug=new IUG("Diferite tipuri de butoane");

/* clasa imbricata pentru interfata utilizator grafica */ static class IUG extends JFrame { JButton b1,b2; JCheckBox cb1, cb2; JRadioButton rb1, rb2, rb3; ButtonGroup grup; Box box1, box2, box3, box4; JLabel label;

IUG(String titlu) { // constructorul clasei IUG super(titlu); setSize(300, 150); setLocation(200, 50); Container cp=getContentPane(); addWindowListener(af); // adaugarea ascultatorului de fereastra /* Se creeaza doua butoane, b1 si b2, care se pun in caseta box1 */ b1=new JButton("B1 (F1)"); b1.addActionListener(ascult); b1.setMnemonic(KeyEvent.VK_F1); b2=new JButton("B2 (F2)"); b2.addActionListener(ascult); b2.setMnemonic(KeyEvent.VK_F2); box1=Box.createVerticalBox(); box1.add(new JLabel("Butoane simple")); box1.add(b1); box1.add(b2); /* Se creeaza doua casete de validare, care se pun in box2 */ cb1=new JCheckBox("Caseta 1 (A)"); cb1.addItemListener(ascult); cb1.setMnemonic(KeyEvent.VK_A); cb2=new JCheckBox("Caseta 2 (S)"); cb2.addItemListener(ascult); cb2.setMnemonic(KeyEvent.VK_S); box2=Box.createVerticalBox(); box2.add(new JLabel("Casete validare")); box2.add(cb1); box2.add(cb2); /* Se creeaza trei butoane radio, care se grupeaza si se pun in box3 */ rb1=new JRadioButton("BR 1 (F5)"); rb1.setMnemonic(KeyEvent.VK_F5); rb1.addActionListener(ascult); rb2=new JRadioButton("BR 2 (F6)"); rb2.setMnemonic(KeyEvent.VK_F6); rb2.addActionListener(ascult); rb3=new JRadioButton("BR 3 (F7)"); rb3.setMnemonic(KeyEvent.VK_F7); rb3.addActionListener(ascult); box3=Box.createVerticalBox(); box3.add(new JLabel("Butoane radio"));

Page 248: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

248

box3.add(rb1); box3.add(rb2); box3.add(rb3); grup=new ButtonGroup(); grup.add(rb1); grup.add(rb2); grup.add(rb3); /* box1, box2 si box3 se pun in box4 , iar aceasta se pune in controlPane */ box4=Box.createHorizontalBox(); box4.add(Box.createHorizontalGlue()); box4.add(box1); box4.add(Box.createHorizontalStrut(15)); box4.add(box2); box4.add(Box.createHorizontalStrut(15)); box4.add(box3); box4.add(Box.createHorizontalGlue()); cp.add(box4, BorderLayout.CENTER); label=new JLabel("Actionati butoanele si urmariti mesajul"); cp.add(label, BorderLayout.SOUTH); setVisible(true); } }

/* Clasa ascultatoare de fereastra */ static class AF extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); // incheierea executarii aplicatiei } }

/* Clasa ascultatoare de actiuni si de selectari */ static class Ascultator implements ActionListener, ItemListener { public void actionPerformed(ActionEvent e) { iug.label.setText("A fost apasat butonul "+e.getActionCommand()); } public void itemStateChanged(ItemEvent e) { JCheckBox cb=(JCheckBox)e.getItem(); String selectie; if(cb.isSelected()) selectie="A fost selectata "; else selectie="A fost deselectata "; iug.label.setText(selectie+cb.getText()); } }

/* Metoda principala a aplicatiei */ public static void main(String args[]) { } }

În fereastra principală a aplicaţiei apar:

- două butoane simple din clasa JButton, cu textele B1 şi B2; butoanele sunt referite prin b1

şi b2 şi sunt puse în caseta verticală box1;

- două casete de validare din clasa JCheckBox, cu textele Caseta 1 şi Caseta 2, referite prin

cb1 şi cb2 şi puse în caseta verticală box2;

- trei butoane radio din clasa JRadioButton, cu textele BR1, BR2 şi BR3, referite prin br1,

Page 249: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

249

br2 şi br3 si puse în caseta verticală box3;

- cele trei casete verticale, box1, box2 şi box3, sunt plasate în caseta orizontală box4, iar

aceasta este pusă în zona CENTER a panoului controlPane;

- în zona SOUTH a controlPane este pusă o etichetă din clasa JLabel, folosită pentru a afişa

evenimentele.

Ascultarea evenimentelor de acţiune (ActionEvent) şi de selecţie (ItemEvent) se face cu clasa

Ascultare, care implementează interfeţele ActionListener şi ItemListener.

Detectarea butonului care a fost apăsat, fie că este vorba de un buton simplu sau unul radio,

se face în metoda actionPerformed(ActionEvent action) folosind metoda String

getActionCommand() din clasa ActionEvent. Pentru a constata care caseta de validare care a

fost selectată sau deselectată, în metoda itemStateChanged(ItemEvent item) se

procedează astfel: se determină mai întâi obiectul selectabil (în cazul nostru caseta de

validare) care a generat evenimentul, folosind metoda Object getItem() din clasa

ItemEvent, după care se aplică metoda boolean isSelected() a acestui obiect.

Fiecărui buton (sau casetă de validare) i-a fost ataşată o mnemonică. Pentru comoditatea

utilizatorului, tasta corespunzătoare a fost menţionată între paranteze, în textul fiecărui buton.

Dacă se dă comanda Alt-<Tastă mnemonică> se obţine acelaşi efect ca atunci când se face

click de mouse pe butonul respectiv. De exemplu, în loc de a apăsa cu mouse-ul butonul B2,

se apasă simultan tastele Alt şi F2. Simbolurile tastelor se găsesc în clasa

java.awt.event.KeyEvent.

Pentru aprofundarea folosirii diferitelor tipuri de butoane, recomandăm capitolul How to use

Buttons, Check Boxes and Radio Buttons din Java Tutorial.

Liste

În cazul interfeţelor utilizator grafice, se numeşte listă o componentă care conţine articole

selectabile. Selectarea lor se face de către utilizator, prin click de mouse pe articolul

respectiv. Lista poate fi cu selecţie simplă sau cu selecţie multiplă, după cum pot fi selectate

simultan unul sau mai multe articole.

În JFC/Swing, listele se realizează ca instanţe ale clasei javax.swing.JList. Articolele din

listă pot fi, în principiu, orice obiecte afişabile. La crearea listei, constructorului i se dă ca

argument tabloul obiectelor pe care le va conţine lista. Ulterior este posibil să se adauge

articole la listă, sau să se elimine.

Daca lista este mai lunga decât spaţiul de afişare disponibil, ea poate fi pusă pe un panou

glisant, din clasa javax.swing.JScrollPane.

Selectarea simplă a unui articol se face prin click de mouse pe articolul respectiv.

Selectarea multiplă se face în două moduri:

- se face click de mouse pe primul articol din zona care trebuie selectată, apoi se apasă tasta

Page 250: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

250

Shift şi se face click pe ultimul articol din această zonă. În acest fel se selectează toate

articolele din zona respectivă;

- se face click de mouse pe primul articol din zonă, apoi se apasă tasta Shift şi se acţionează

tastele cu săgeţi sus/jos până când sunt selectate toate articolele din zona respectivă.

De câte ori se face o selecţie de articole din listă, se generează un eveniment din clasa

javax.swing.event.ListSelectionEvent, care este ascultat cu ajutorul unei clase care

implementează interfaţa javax.swing.event.ListSelectionListener.

Punerea articolelor în listă poate fi făcută astfel:

- la crearea listei, folosind unul din constructorii

public JList(Object[] listData) - primeşte ca argument un tablou de obiecte, care

sunt articolele din listă

public JList(Vector listData)- primeşte ca argument o instanţă a clasei

java.util.Vector, care are ca elemente articolele listei;

- în timpul utilizării listei, invocându-se una din metodele public void setListData(Object[] listData) public void setListData(Vector listData)

Pentru a afla articolele selectate dintr-o listă se pot folosi metodele:

public int[] getSelectedIndices() - întoarce tabloul indicilor articolelor selectate

public Object[] getSelectedValues() - întoarce tabloul articolelor selectate.

Clasa are numeroase alte metode. Pentru aprofundare, recomandăm capitolul How to Use

Lists din Java Tutorial.

Liste ascunse

Lista ascunsă este o listă din care se vede un singur articol (cel care este selectat), deci ocupa

pe ecran spaţiu mult mai putin decât una obişnuită. Celelalte articole ale listei sunt "ascunse"

şi devin vizibile numai dacă se face click pe articolul vizibil. Dacă acum facem click de

mouse pe un alt articol din lista devenită vizibilă, acest nou articol este selectat (rămâne

vizibil), iar celelalte dispar. Într-o listă ascunsă nu este posibilă selecţia multiplă.

În JFC/Swing, pentru realizarea listelor ascunse se foloseşte clasa javax.swing.JComboBox.

Când este selectat un nou articol din lista ascunsă, aceasta generează un eveniment de articol

din clasa java.awt.event.ItemEvent, care este ascultat cu un java.awt.event.ItemListener.

La fiecare acţionare asupra listei ascunse, se generează, de asemenea, un

java.awt.ActionEvent.

În mod implicit, instanţele clasei JComboBox nu sunt editabile. Totuşi, este posibil ca acestea

sa fie făcute editabile, în care caz ele se comportă ca o combinaţie între listă şi câmpul de

text: utilizatorul poate să introducă textul manual, sau poate să aleagă unul din listă.

Punerea articolelor în listă se poate face astfel:

- la crearea listei ascunse, folosind unul din constructorii

Page 251: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

251

public JComboBox(Object[] items) public JComboBox(Vector items) - în timpul utilizării listei, folosind metodele

public void addItem(Object anObject) - adaugă un articol la sfârşitul listei;

public void insertItemAt(Object anObject, int index) - înserează un articol

pe poziţia index.

Eliminarea unui articol din listă se face cu una din metodele

public void removeItem(Object anObject) - elimină articolul anObject;

public void removeItemAt(int anIndex) - elimină articolul de pe poziţia anIndex.

Pentru a afla articolul selectat se foloseşte metoda public Object getSelectedItem()

iar pentru a afla indicele articolului selectat se foloşeste metoda public int getSelectedIndex()

Pentru ca lista ascunsă sa devină editabilă, se foloseşte metoda

public void setEditable(boolean aFlag)- în care parametrul boolean aFlag

indică dacă lista va fi sau nu editabilă.

Pentru aprofundarea folosirii listelor ascunse recomandăm capitolul How to Use Combo

Boxes din Java Tutorial.

Exemplu

În fişierul Liste.java este dat un exemplu de aplicaţie în care se folosesc instanţe ale claselor

JList şi JComboBox.

import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*;

class Liste { static AF af=new AF(); static AAL ascult=new AAL(); static AEA ascult1=new AEA(); static IUG iug=new IUG("Diferite tipuri de liste");

/* clasa imbricata pentru interfata utilizator grafica */ static class IUG extends JFrame { JList lista1, lista2; JComboBox combo; JLabel label;

IUG(String titlu) { // constructorul clasei IUG super(titlu);

Page 252: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

252

setSize(350, 240); setLocation(200, 50); Container cp=getContentPane(); addWindowListener(af); // adaugarea ascultatorului de fereastra

/* Se creeaza o lista cu zilele saptamanii. Listei nu i se pune un model de selectie, deci se pot face implicit selectii multiple intr-o singura zona continua */ String zile[]={"Luni", "Marti", "Miercuri", "Joi", "Vineri", "Sambata", "Duminica"}; lista1=new JList(zile); lista1.setBorder(BorderFactory.createTitledBorder( "Lista")); lista1.addListSelectionListener(ascult); // ascultarea listei cp.add(lista1, BorderLayout.WEST);

/* Se creeaza o lista cu lunile anului, pusa intr-un panou glisant. Listei i se pune un model de selectie care permite numai selectarea unui singur articol */ String luni[]={"Ianuarie", "Februarie", "Martie", "Aprilie", "Mai", "Iunie", "Iulie", "August", "Septembrie", "Octombrie", "Noiembrie", "Decembrie"}; lista2=new JList(luni); lista2.setBorder(BorderFactory.createTitledBorder( "Lista glisanta")); lista2.setSelectionModel(new DefaultListSelectionModel()); lista2.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

lista2.addListSelectionListener(ascult); JScrollPane scroll=new JScrollPane(lista2); // panoul glisant // care contine lista nou creata, lista2 cp.add(scroll, BorderLayout.CENTER);

/* Se creeaza o lista ascunsa (din clasa JComboBox) */ String ordinea[]={"Primul ", "Al doilea", "Al treilea", "Al patrulea"}; combo=new JComboBox(ordinea); combo.setBorder(BorderFactory.createTitledBorder( "Lista ascunsa")); combo.addItemListener(ascult1); JPanel panel=new JPanel(); panel.add(combo); cp.add(panel, BorderLayout.EAST);

/* Se creeaza o "eticheta" pentru afisarea mesajelor */ label=new JLabel("Selectati articolele si urmariti efectul"); label.setBorder(BorderFactory.createTitledBorder( "Afisarea mesajelor privind articolele selectate")); cp.add(label, BorderLayout.SOUTH); setVisible(true); } }

/* Clasa ascultatoare de fereastra */ static class AF extends WindowAdapter { public void windowClosing(WindowEvent e) {

Page 253: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

253

System.exit(0); // incheierea executarii aplicatiei } }

/* Clasa ascultatoare de selectari ale articolelor de lista folosita pentru JList. La aparitia unui astfel de eveniment, se afiseaza toate articolele selectate din lista sursa */ static class AAL implements ListSelectionListener { public void valueChanged(ListSelectionEvent e) { JList sursa=(JList)e.getSource(); Object selectie[]=sursa.getSelectedValues(); StringBuffer buff=new StringBuffer(); for(int i=0; i<selectie.length; i++) buff.append(selectie[i].toString()+" "); iug.label.setText(buff.toString()); } }

/* Clasa ascultatoare de evenimente de articol folosita pentru JComboBox. La aparitia unui astfel de eveniment, se afiseaza articolul care l-a produs */ static class AEA implements ItemListener { public void itemStateChanged(ItemEvent e) { iug.label.setText(e.getItem().toString()); } }

/* Metoda principala a aplicatiei */ public static void main(String args[]) { } }

Câmpul de text

Câmpul de text este principalul instrument al interfeţei grafice prin care utilizatorul introduce

date de la tastatură. El se prezintă sub forma unei ferestre dreptunghiulare editabile, în care se

poate introduce o singură linie de text. De obicei, prin intermediul câmpului de text se

introduce o singură valoare numerică sau un şir de caractere.

În JFC/Swing, câmpurile de text se realizează ca instanţe ale clasei javax.swing.JTextField.

Când câmpul de text este activ şi se apasă tasta Enter, este generat un eveniment de acţiune

din clasa java.awt.ActionEvent.

Textul conţinut în câmpul de text poate fi obţinut în două moduri:

- prin metoda public String getText() a clasei JTextField;

- prin metoda public String getActionCommand() a clasei ActionEvent.

Dacă în câmpul de text se introduce o valoare numerică, ea trebuie verificata sintactic şi

Page 254: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

254

convertită din forma externă (de şir de caractere) în forma internă. În acest scop, se folosesc

metodele de analiză şi conversie din clasele acoperitoare. De exemplu, pentru un numar de tip

double se va folosi metoda public double parseDouble(String str)

din clasa acoperitoare java.lang.Double, unde str este şirul care trebuie analizat. Întrucât

aceste metode pot să genereze excepţii de format incorect (NumberFormatException), ele

trebuie utilizate în secvenţe try .. catch;

Pentru aprofundarea utilizării câmpurilor de text, recomandăm capitolul How to Use Text

Fields din Java Tutorial.

Menţionăm că, în afara clasei JTextField, există şi clasa javax.swing.JPasswordField, care

se foloseşte pentru introducerea parolelor.

Exemplu

În fişierul CâmpuriText.java este dat un exemplu de aplicaţie în care se utilizează trei

câmpuri de text, pentru a introduce, respectiv, un şir de caractere, un număr întreg şi un

număr în virgulă mobilă. În clasa imbricată Actiuni, prin care este realizat ascultătorul de

evenimente de acţiune, se poate observa cum se determină care câmp de text a generat

evenimentul de acţiune şi cum se preia şi analizează textul din câmpul respectiv, în funcţie de

tipul valorii pe care acest câmp trebuie să o conţină.

import java.awt.*; import java.awt.event.*; import javax.swing.*;

class CampuriText { static AF af=new AF(); static Actiuni act=new Actiuni(); static IUG iug=new IUG("Campuri de text");

/* clasa imbricata pentru interfata utilizator grafica */ static class IUG extends JFrame { JPanel panel; JTextField tf1, tf2, tf3; JLabel label;

IUG(String titlu) { // constructorul clasei IUG super(titlu); setSize(450, 150); setLocation(200, 50); Container cp=getContentPane(); addWindowListener(af); // adaugarea ascultatorului de fereastra

/* Crearea panoului pentru campurile de text */ panel=new JPanel(); panel.setLayout(new GridLayout(3,2));

/* Adaugarea la panou a etichetelor si campurilor de text */ panel.add(new JLabel("Un sir de caractere: "));

Page 255: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

255

tf1=new JTextField(); tf1.addActionListener(act); panel.add(tf1); panel.add(new JLabel("Un numar intreg")); tf2=new JTextField(); tf2.addActionListener(act); panel.add(tf2); panel.add(new JLabel("Un numar real: ")); tf3=new JTextField(); tf3.addActionListener(act); panel.add(tf3); /* Adaugarea la contentPane a panoului cu campuri de text */ cp.add(panel, BorderLayout.CENTER);

/* Se creeaza o "eticheta" pentru afisarea mesajelor */ label=new JLabel("Introduceti date in campuri si urmariti efectul"); label.setBorder(BorderFactory.createTitledBorder( "Afisarea mesajelor privind campurile de text")); cp.add(label, BorderLayout.SOUTH);

setVisible(true); } }

/* Clasa ascultatoare de fereastra */ static class AF extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); // incheierea executarii aplicatiei } }

/* Clasa ascultatoare a actiunilor asupra campurilor de text */ static class Actiuni implements ActionListener { public void actionPerformed(ActionEvent e) { JTextField sursa=(JTextField)e.getSource(); String text=e.getActionCommand(), text1="Ati introdus in campul "; if(sursa==iug.tf1) iug.label.setText(text1+"1 textul: "+text); else if(sursa==iug.tf2) try { int n=Integer.parseInt(text); iug.label.setText(text1+" 2 numarul intreg "+n); } catch(Exception e1) { iug.label.setText("In campul 2 nu este un numar intreg!"); } else if(sursa==iug.tf3) try { double d=Double.parseDouble(text); iug.label.setText(text1+"3 numarul real "+d); } catch(Exception e2) { iug.label.setText("In campul 3 nu este un numar real!"); } } }

/* Metoda principala a aplicatiei */

Page 256: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

256

public static void main(String args[]) { } }

Rigla cu cursor

Clasa javax.swing.JSlider oferă o componentă care are aspectul unei rigle prevăzute cu

cursor. Prin deplasarea cursorului cu ajutorul mouse-ului se modifică valoarea indicată de

riglă. Valoarea minimă şi cea maximă de pe scala riglei şi valoarea unei diviziuni se indică

prin program. Rolul riglei poate fi asemănat cu cel al unui dispozitiv de ajustare continuă,

cum este potenţiometrul din aparatura electronică.

La deplasarea cursorului, rigla generează evenimente din clasa

javax.swing.event.ChangeEvent, care sunt ascultate cu o clasă care implementează interfaţa

javax.swing.event.ChangeListener.

Crearea riglei se face folosind unul dintre constructorii ei, dintre care cel mai complet este public JSlider(int orientation, int min, int max, int value)

în care

orientation - orientarea riglei, care poate fi JSlider.HORIZONTAL sau

JSlider.VERTICAL;

min, max - valorile minimă şi maximă de pe scala riglei;

value - valoarea indicată iniţial de cursorul riglei (trebuie să fie în intervalul [min,max]).

Pentru a stabili aspectul riglei se folosesc metodele

public void setMajorTickSpacing(int n) - stabilirea valorii diviziunilor mari

public void setMinorTickSpacing(int n) - stabilirea valorii diviziunilor mici

public void setPaintTicks(boolean b) - determină dacă diviziunile vor fi vizibile

public void setPaintLabels(boolean b) - determină dacă vor fi afişate valorile

numerice ale diviziunilor.

Pentru aprofundarea utilizării riglelor cu cursor, recomandăm consultarea capitolului How to

Use Sliders din Java Tutorial.

Exemplu

În fişierul TestRigla.java este dat un exemplu de aplicaţie în care se testează o riglă cu cursor

realizată ca instanţă a clasei JSlider.

La partea superioară a ferestrei apare o riglă în poziţie orizontală. Când se modifică cu

mouse-ul poziţia cursorului, în eticheta de la partea inferioară a ferestrei aplicaţiei se afişeaza

noua valoare indicată de riglă.

import java.awt.*; import java.awt.event.*; import javax.swing.*;

Page 257: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

257

import javax.swing.event.*;

class TestRigla { static AF af=new AF(); static AscultRigla ascult=new AscultRigla(); static IUG iug=new IUG("O rigla ajustabila");

/* clasa imbricata pentru interfata utilizator grafica */ static class IUG extends JFrame { JSlider rigla; JLabel label;

IUG(String titlu) { // constructorul clasei IUG super(titlu); setSize(450, 150); setLocation(200, 50); Container cp=getContentPane(); addWindowListener(af); // adaugarea ascultatorului de fereastra

/* Se creeaza o "eticheta" pentru afisarea mesajelor */ label=new JLabel("Deplasati cursorul riglei si urmariti efectul"); label.setBorder(BorderFactory.createTitledBorder( "Afisarea mesajelor privind valoarea ajustata")); cp.add(label, BorderLayout.SOUTH);

rigla=new JSlider(JSlider.HORIZONTAL, -20, 80, 35); rigla.setBorder(BorderFactory.createTitledBorder( "Ajustarea valorii")); rigla.setMajorTickSpacing(10); rigla.setMinorTickSpacing(1); rigla.setPaintTicks(true); rigla.setPaintLabels(true); rigla.addChangeListener(ascult);

cp.add(rigla, BorderLayout.CENTER);

setVisible(true); } }

/* Clasa ascultatoare de fereastra */ static class AF extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); // incheierea executarii aplicatiei } }

/* Clasa ascultatoare a evenimentelor de ajustare a riglei */ static class AscultRigla implements ChangeListener { public void stateChanged(ChangeEvent e) { iug.label.setText("Noua valoare: "+iug.rigla.getValue()); } }

/* Metoda principala a aplicatiei */

Page 258: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

258

public static void main(String args[]) { } }

Meniuri

La fel ca listele sau butoanele radio, meniurile permit utilizatorului să aleagă una din mai

multe opţiuni posibile. În JFC/Swing se disting două categorii de meniuri:

- meniuri cu bară, care pornesc dintr-o bară situată la partea superioară a ferestrei aplicaţiei;

- meniuri derulante (pop-up), care apar în poziţia în care se găseşte cursorul de mouse.

Meniuri cu bară

Bara de meniu se poate plasa, daca este necesara, numai la partea superioara a ferstrei

aplicatiei si se realizeaza ca o instanta a clasei javax.swing.JMenuBar.

Bara de meniu poate sa conţină unul sau mai multe meniuri, care se realizează ca instanţe ale

clasei javax.swing.JMenu. La rândul său, fiecare meniu poate conţine unul sau mai multe

articole, care sunt instanţe ale claselor javax.swing.JMenuItem sau

javax.swing.JCheckBoxMenuItem. Este însă posibil ca un articol de meniu să fie el însuşi

un meniu (din clasa JMenu). Dacă utilizatorul alege cu mouse-ul un aricol de meniu, sunt

posibile deci două situaţii:

- acesta este un articol propriu-zis (un JMenuItem), în care caz opţiunea respectivă este

selectată;

- articolul ales este el însuşi un meniu (un JMenu), în care caz noul (sub)meniu se

desfăşoară şi căutarea continuă.

Barele de meniu nu pot fi adăugate la un container ca nişte componente obişnuite. Pentru a

pune bara de meniu la partea superioară a ferestrei aplicaţiei se foloseşte metoda clasei

JFrame public void setJMenuBar(JMenuBar menubar)

Adăugarea de meniuri la bara de meniu se face prin metoda clasei JMenuBar public JMenu add(JMenu c) iar adăugarea de articole sau submeniuri la un meniu se face prin metodele clasei JMenu public JMenuItem add(JMenuItem menuItem) public Component add(Component c) public JMenuItem add(String s) public JMenuItem add(Action a)

Pentru a introduce în meniu o linie orizontală de separare a două articole se foloseşte metoda public void addSeparator()

Atunci când este selectat un articol de meniu simplu (din clasa JMenuItem), acesta acţionează

ca un buton obişnuit, adică generează un eveniment de acţiune (ActionEvent). Dacă se

selectează un articol de meniu sub forma de casetă de validare (din clasa

JCheckBoxMenuItem), acesta se comporta ca o caseta de validare, adică generează un

Page 259: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

259

eveniment de articol (ItemEvent). Ascultarea acestor evenimente se face cu clase care

implementează interfeţele ActionListener, respectiv ItemListener.

Posibilităţile oferite de meniuri sunt mult mai bogate decât s-a arătat aici. Pentru aprofundare

recomandăm consultarea capitolului How to Use Menus din Java Tutorial.

Exemplu

În fişierul Meniuri.java este dat un exemplu de aplicaţie cu bară de meniu.

import java.awt.*; import java.awt.event.*; import javax.swing.*;

class Meniuri { static AF af=new AF(); static AA aa=new AA(); static IUG iug=new IUG("O fereastra cu bara de menu");

/* clasa imbricata pentru interfata utilizator grafica */ static class IUG extends JFrame { JMenuBar menuBar; JMenu menu1, menu2; JLabel label; JMenuItem mi1, mi2, mi3, mi4, mi5;

IUG(String titlu) { // constructorul clasei IUG super(titlu); setSize(350, 150); setLocation(200, 50); Container cp=getContentPane(); addWindowListener(af); // adaugarea ascultatorului de fereastra menuBar=new JMenuBar(); // se creeaza bara de menu setJMenuBar(menuBar); // bara de menu se adauga la fereastra /* Se creeaza meniurile si se adauga la bara de meniu */ menu1=new JMenu("Un menu"); menuBar.add(menu1); menu2=new JMenu("Alt menu"); menuBar.add(menu2); /* Se creaza articole de menu si se adauga la meniuri */ mi1=new JMenuItem("A"); mi1.addActionListener(aa); menu1.add(mi1); mi2=new JMenuItem("B"); mi2.addActionListener(aa); menu1.add(mi2); mi3=new JMenuItem("C"); mi3.addActionListener(aa); menu2.add(mi3); /* La menu2 se aduga un submeniu cu doua articole */ JMenu menu3=new JMenu("Un submeniu"); mi4=new JMenuItem("Alpha"); mi4.addActionListener(aa); menu3.add(mi4); mi5=new JMenuItem("Beta"); mi5.addActionListener(aa); menu3.add(mi5); menu2.add(menu3);

Page 260: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

260

/* Se creeaza o "eticheta" pentru afisarea mesajelor */ label=new JLabel("Selectati articole de meniu si urmariti efectul"); label.setBorder(BorderFactory.createTitledBorder( "Afisarea mesajelor privind selectarea articolelor de meniu")); cp.add(label, BorderLayout.SOUTH);

setVisible(true); } }

/* Clasa ascultatoare de fereastra */ static class AF extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); // incheierea executarii aplicatiei } }

/* Ascultator de actiuni pentru articolele de menu */ static class AA implements ActionListener { public void actionPerformed(ActionEvent e) { iug.label.setText("A fost selectata optiunea: "+ e.getActionCommand()); } }

/* Metoda principala a aplicatiei */ public static void main(String args[]) { } }

Meniuri volante (pop-up)

Spre deosebire de meniurile cu bară, meniurile volante sunt tratate ca nişte componente

obişnuite, care pot să fie afişate prin program, atunci când este necesar. În JFC/Swing,

meniurile volante se realizează ca instanţe ale clasei javax.swing.JPopupMenu. În rest,

meniul pop-up se comportă la fel ca un meniu cu bară.

Afişarea meniului pop-up trebuie programată, folosindu-se în acest scop metoda din clasa

JPopupMenu public void show(Component invoker, int x, int y)

în care invoker este referinţa la componenta in spaţiul căreia trebuie să apară meniul, iar x şi

y sunt coordonatele punctului în care acesta va fi afişat.

De obicei, se doreste ca afişarea meniului pop-up să se facă atunci când se efectuează o

anumită acţiune a mouse-lui asupra componentei respective. În acest scop, se creează o clasă

ascultătoare de mouse (care implementează interfaţa MouseListener sau extinde clasa

MouseAdapter) şi - în corpul metodei corespunzatoare situaţiei în care trebuie să se afişeze

meniul (mousePressed, mouseReleased sau mouseClicked) se invocă metoda show

menţionată mai sus, dacă a fost acţionat butonul de mouse care ne interesează. Se

demonstrează acest procedeu în exemplul de mai jos.

Page 261: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

261

Exemplu

În fişierul Popup.java se dă un exemplu de aplicaţie în care se testează utilizarea unui menu

pop-up. Drept componentă pe suprafaţa căreia trebuie să apară meniul s-a ales eticheta de la

partea inferioară a ferestrei aplicaţiei. Evenimentul care declanşează apariţia meniului este

apăsarea pe butonul din dreapta al mouse-ului, atunci când acesta se găseşte în spaţiul

ferestrei. Acest eveniment este urmărit de instanţa clasei AfisPopup, care este ataşata

etichetei label în calitate de ascultător de mouse.

import java.awt.*; import java.awt.event.*; import javax.swing.*;

class Popup { static AF af=new AF(); static AA aa=new AA(); static AfisPopup afisare=new AfisPopup(); static IUG iug=new IUG("Exemplu de menu pop-up");

/* clasa imbricata pentru interfata utilizator grafica */ static class IUG extends JFrame { JPopupMenu popup; JLabel label; JMenuItem mi1, mi2, mi3;

IUG(String titlu) { // constructorul clasei IUG super(titlu); setSize(350, 150); setLocation(200, 50); Container cp=getContentPane(); addWindowListener(af); // adaugarea ascultatorului de fereastra

/* Se creeaza meniul pop-up */ popup=new JPopupMenu();

/* Se creaza articole de menu si se adauga la meniuri */ mi1=new JMenuItem("A"); mi1.addActionListener(aa); popup.add(mi1); mi2=new JMenuItem("B"); mi2.addActionListener(aa); popup.add(mi2); mi3=new JMenuItem("C"); mi3.addActionListener(aa); popup.add(mi3);

/* Se creeaza o "eticheta" pentru afisarea mesajelor */ label=new JLabel(" Apasati pe aceasta eticheta butonul drept al mouse-ului"); label.setBorder(BorderFactory.createTitledBorder( "Afisarea mesajelor privind selectarea articolelor de meniu")); cp.add(label, BorderLayout.SOUTH);

/* Se adauga la eticheta label ascultatorul de mouse pentru afisarea meniului popup

Page 262: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

262

*/ label.addMouseListener(afisare); setVisible(true); } }

/* Clasa ascultatoare de fereastra */ static class AF extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); // incheierea executarii aplicatiei } }

/* Clasa ascultatoare de mouse pentru afisarea meniului pop-up */ static class AfisPopup extends MouseAdapter { public void mousePressed(MouseEvent e) { if((e.getModifiers()&InputEvent.BUTTON3_MASK)!=0) iug.popup.show(e.getComponent(), e.getX(), e.getY()); } }

/* Ascultator de actiuni pentru articolele de menu */ static class AA implements ActionListener { public void actionPerformed(ActionEvent e) { iug.label.setText("A fost selectata optiunea: "+ e.getActionCommand()); } }

/* Metoda principala a aplicatiei */ public static void main(String args[]) { } }

Componente de afişare

Componentele de afişare sunt cele care servesc pentru a afişa anumite texte sau imagini şi pot

fi needitabile sau editabile.

Componente de afişare needitabile

Componentele de afişare needitabile sunt realizate ca instanţe ale următoarelor clase:

- javax.swing.JLabel - pentru realizarea unor "etichete" în care pot fi afişate texte sau

imagini, fără a putea fi editate de utilizator;

- javax.swing.JTooltip - pentru afişarea de "inscripţii volante", când se pune cursorul de

mouse deasupra unei alte componente;

- javax.swing.JProgressBar - pentru realizarea unor "bare de progres" adică a unor bare de

lungime variabilă, care arată cum evoluează realizarea unei anumite activităţi (de la 0% la

Page 263: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

263

100%).

Utilizarea etichetelor şi a inscripţiilor volante a fost deja prezentată. Pentru aprofundarea

acestora şi pentru a studia folosirea barelor de progres recomandăm capitolele How to Use

Labels, How to Use Tool Tips şi How to Monitor Progress din Java Tutorial.

Componente de afişare editabile

Componentele de afişare editabile permit utilizatorului operaţii de editare în timpul executării

programului. În JFC/Swing există un număr important de clase pentru astfel de componente.

Astfel, pentru editare de texte există clasele javax.swing.JTextArea,

javax.swing.JTextPane şi javax.swing.JEditorPane. În aceeaşi categorie pot fi încadrate şi

clasele javax.swing.JTextField şi javax.swing.JPasswordField, care au fost prezentate

anterior.

Tot în categoria componentelor editabile intră şi clasele javax.swing.JTable (pentru

realizarea de tabele editabile), javax.swing.JFileChooser (pentru realizarea de selectoare de

fişiere), javax.swing.JTree (pentru realizarea de arbori) şi javax.swing.JColorChooser

(pentru realizarea de selectoare de culori).

Vom prezenta aici numai clasa JTextArea, iar pentru celelalte recomandăm folosirea

documentaţiei indicate.

Pentru aprofundare recomandăm folosirea capitolelor Using Text Components, How to Use

Tables, How to Use File Choosers, How to Use Trees, si How to Use Color Choosers din

Java Tutorial.

Clasa JtextArea

Instanţele clasei javax.swing.JTextArea (arie de text) sunt suprafeţe de afişare a unor texte

editabile cu mai multe linii. Componenta are comportamentul unui editor de text simplu:

permite să se introducă text de la tastatură, să se şteargă textul în întregime sau pe porţiuni, să

se adauge sau să se însereze text. Prin metode speciale se poate seta componenta astfel, încât

să se realizeze automat trecerea de la un rând la altul. Se oferă metode prin care se poate

adăuga text prin program, sau se poate obţine sub forma de String textul existent.

Iată unele dintre metodele oferite de clasa JTextArea:

public int getRows() - întoarce numărul maxim de linii din aria de text;

public void setRows(int rows) - setează numărul maxim de linii;

public int getColumns() - întoarce numărul maxim de coloane din aria de text;

public void setColumns(int columns) - setează numărul maxim de coloane;

Page 264: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

264

public void setFont(Font f) - setează fontul;

public void setLineWrap(boolean wrap) - indică dacă se face trecere automată la

linie nouă;

public void setWrapStyleWord(boolean word) - indică dacă trecerea automată la

linie nouă se face la sfârşit de cuvânt;

public int getLineCount() - întoarce numărul de linii de text conţinute efectiv;

public void insert(String str, int pos) - înserează şirul str începând de la poziţia

pos;

public void append(String str) - adaugă la sfârşit textul str;

public void replaceRange(String str, int start, int end) - înlocuieşte prin

şirul str caracterele cuprinse între poziţiile start şi end;

public String getText() - întoarce sub forma de String textul conţinut;

public String getSelectedText() - întoarce textul selectat.

Ultimele două metode sunt moştenite de la superclasa javax.swing.text.JTextComponent.

Exemplu

În fişierul ZonaText.java se dă un exemplu simplu de creare a unei instanţe a clasei

JTextArea, setând trecerea automată la linie nouă la sfârşit de cuvant (astfel încât un cuvânt

să nu se împartă pe două linii). Punând în execuţie această aplicaţie, constatăm cum aria de

text se comportă ca un mic editor de text: putem să introducem de la tastatură text nou sau să

modificăm textul existent. Dacă modificăm cu mouse-ul dimensiunile ferestrei, observăm

cum se rearanjează automat liniile de text.

import java.awt.*; import java.awt.event.*; import javax.swing.*;

class ZonaText { static AF af=new AF(); // static AA aa=new AA(); //static AfisPopup afisare=new AfisPopup(); static IUG iug=new IUG("O zona de text");

/* clasa imbricata pentru interfata utilizator grafica */ static class IUG extends JFrame { JTextArea ta; JLabel label;

IUG(String titlu) { // constructorul clasei IUG super(titlu); setSize(450, 150); setLocation(200, 50); Container cp=getContentPane(); addWindowListener(af); // adaugarea ascultatorului de fereastra ta=new JTextArea (); ta.setLineWrap(true); ta.setWrapStyleWord(true); cp.add(ta, BorderLayout.CENTER);

setVisible(true); } }

/* Clasa ascultatoare de fereastra */

Page 265: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

265

static class AF extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); // incheierea executarii aplicatiei } }

/* Metoda principala a aplicatiei */ public static void main(String args[]) { } }

Întrebări

Nivel 1

1. Ce categorii de componente grafice cunoaşteţi?

2. Care este rădăcina ierarhiei claselor de componente?

3. Care sunt caracteristicile componentelor din JFC/Swing?

4. Cum se stabileşte aspectul componentelor din JFC/Swing?

5. Prin ce se caracterizează starea componentei?

6. Prin ce se caracterizeaza comportamentul componentei?

7. Care este deosebirea dintre componentele atomice şi containere?

8. Ce poate conţine o componentă atomică din JFC/Swing?

9. Care sunt componentele de control şi ce rol au?

10. Ce reprezintă clasa AbstractButton?

11. Ce reprezintă clasa JToggleButton?

12. Ce este o casetă de validare şi prin ce clasă se realizează?

13. Ce este un buton radio şi prin ce clasă se realizează?

14. La ce serveşte clasa ButtonGroup?

15. Ce este o listă în JFC/Swing şi prin ce clasă se realizează?

16. Ce este o listă ascunsă şi prin ce clasă se realizează?

17. Prin ce clasă se realizează câmpul de text şi ce conţine el?

18. Care este principala utilizare a câmpului de text?

19. Ce evenimente generează un câmp de text şi când le generează?

20. Ce este o riglă ajustabilă şi prin ce clasă se realizează?

21. Care este dispozitivul electronic pe care îl simulează o riglă ajustabilă?

22. Ce este un meniu?

23. Ce categorii de meniuri există în JFC/Swing?

24. Unde poate fi plasat un meniu cu bara?

25. Prin ce clasă se realizează bara de meniu?

26. Ce conţine bara de meniu?

27. Prin ce clasă se realizează un meniu utilizabil într-o bară de meniu?

28. Ce conţine un meniu?

29. Prin ce clase se realizează articolele de meniu?

30. Ce este un meniu derulant şi prin ce clasă se realizează?

Page 266: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

266

31. Ce sunt componentele de afişare needitabile?

32. Ce componente de afişare needitabile cunoaşteţi?

33. Ce sunt componentele de afişare editabile?

34. Ce componente de afişare editabile cunoaşteţi?

35. Ce sunt instanţele clasei JTextArea şi cum se comportă ele?

Nivel 2

1. Care este superclasa clasei JComponent şi ce decurge din aceasta?

2. Ce este un text volant şi cum este el ataşat unei componente?

3. Cum se adaugă bordura unei componente?

4. Care este clasa prin care se realizează bordurile?

5. Cum se poate pune un text într-o componentă?

6. Cum se poate pune o imagine într-o componentă?

7. Cum se adaugă componentă la container?

8. Care sunt caracteristicile unui AbstractButton?

9. Ce este o mnemonică?

10. Ce evenimente generează un AbstractButton?

11. Cum se poate detecta momentul apăsării unui buton?

12. Cum se poate afla care buton a fost apăsat?

13. Cum se poate determina momentul schimbării stării unei casete de validare?

14. Cum se poate afla în ce stare se găseşte la un moment dat o casetă de validare?

15. Cum se face selectarea unui articol dintr-o listă?

16. Ce deosebire este între selecţia simplă şi selecţia multiplă?

17. Cum pot fi selectate mai multe articole ale listei?

18. Cum poate fi determinat momentul selectării unui articol din listă?

19. Cum se poate determina ce articole de listă sunt selectate la un moment dat?

20. Sunt oare editabile instanţele clasei JComboBox?

21. Cum se poate afla textul conţinut într-un câmp de text?

22. Cum se poate converti textul preluat din câmpul de text într-o valoare numerică?

23. Ce orientare poate avea o riglă ajustabilă?

24. Cum se pot trasa diviziunile riglei ajustabile?

25. Cum se stabileşte intervalul de valori al riglei ajustabile?

26. Cum se poate obţine valoarea indicată de riglă?

27. Prin ce metodă se pune bara de meniu în fereastra aplicaţiei şi cărei clase îi aparţine

această metodă?

28. Cum se adaugă un articol la un meniu?

29. Ce evenimente generează un articol de meniu?

30. Cum se programează afişarea pe ecran a unui meniu pop-up?

31. Ce reprezintă instanţele clasei JTable?

32. Care este clasa de componente folosite la alegerea culorii?

33. Ce clase de componente pot fi folosite pentru a realiza un selector de fişier?

34. Ce metode ale clasei JTextArea cunoasteţi?

35. Ce clase pot fi folosite la realizarea de componente cu text editabil?

Page 267: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

267

Utilizarea ferestrelor de dialog. Desenarea

In aceasta sectiune vom studia utilizarea ferestrelor de dialog si a unor clase necesare pentru

reprezentari grafice.

Utilizarea ferestrelor de dialog 267

Alegerea culorii 270

Clasa Color 272

Alegerea culorii folosind clasa JColorChooser 278

Elemente de grafică 280

Contextul grafic 280

Metodele paint şi repaint 283

Întrebări. 289

Utilizarea ferestrelor de dialog

Ferestrele de dialog sunt ferestre care se afişează pe ecran numai temporar, pentru a transmite

anumite mesaje sau a permite introducerea unor date. Principalul avantaj al folosirii

ferestrelor de dialog este că apar pe ecran numai atunci când sunt necesare şi nu încarcă

fereastra principală a aplicaţiei cu elemente care nu sunt necesare în permanenţă.

În JFC/Swing, ferestrele de dialog se realizează folosind clasa javax.swing.JDialog.

Instanţele acestei clase se comportă asemanator cu cele ale clasei JFrame, permiţând

adăugarea oricăror componente. La fel ca la JFrame, aceste componente nu se adaugă direct

la fereastră, ci la panoul contentPane conţinut în aceasta şi obţinut prin metoda public

Container getContentPane().

Fereastra de dialog poate avea ca "proprietar" (owner) o instanţă a claselor java.awt.Frame,

javax.swing.JFrame, java.awt.Dialog sau javax.swing.JDialog. Proprietarul se transmite ca

argument al constructorului ferestrei de dialog. Se permite ca, în loc de proprietar, să se pună

argumentul null, în care caz se atribuie un proprietar implicit.

Pentru afişarea pe ecran a ferestrei de dialog se invocă metoda public void show(), iar

pentru ascunderea ei se invocă metoda public void hide(). În fine, pentru a elimina

fereastra de dialog, eliberând toate resursele pe care le foloseşte, se invocă metoda public

void dispose(). Aceste trei metode sunt moştenite de JDialog de la superclasa

java.awt.Dialog. Când fereastra de dialog este deschisă, ea trece în prim plan sau în plan

secund împreună cu proprietarul ei.

Ferestrele de dialog pot fi modale sau nemodale. Când este afişată pe ecran o fereastră

modală, toate celelalte ferestre existente pe ecran sunt blocate (nu se poate acţiona asupra

lor), până când se încheie lucrul cu fereastra de dialog modală respectivă.

Page 268: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

268

Clasele Dialog şi JDialog sunt prezentate ceva mai detaliat în indexul de clase.

Clasa JDialog este folosită pentru realizarea unor ferestre de dialog configurate de

programator după dorinţa sa. În multe situaţii, este însă suficient să se folosească ferestre de

dialog standard, preconfigurate, ceeace uşurează programarea. În acest scop, în JFC/Swing a

fost creată clasa javax.swing.JOptionPane care este prezentată în indexul de clase.

Clasa JOptionPane oferă metode statice pentru a creea patru tipuri de ferestre de dialog:

- pentru dialog de mesaj (showMessageDialog) - fereastra conţine o informaţie şi un buton

OK care se apasă pentru a închide fereastra;

- pentru dialog de confirmare (showConfirmDialog) - în fereastra se afişează un mesaj (o

întrebare) şi trei butoane de confirmare: Yes/No/Cancel; la apăsarea unuia dintre ele, metoda

întoarce valoarea corespunzatoare şi fereastra de dialog dispare;

- pentru dialog de intrare (showInputDialog) - fereastra conţine un mesaj, un câmp de text

şi două butoane: OK şi Cancel. Utilizatorul introduce în câmpul de text o valoare (un şir de

caractere sau un număr) şi apasa tasta <Enter> sau actioneaza cu mouse-ul butonul OK. În

ambele cazuri fereastra de dialog dispare, iar metoda întoarce şirul introdus în câmpul de text.

Dacă se apasă butonul Cancel, fereastra de dialog dispare, iar metoda întoarce null.

- pentru dialog de opţiune (showOptionDialog), care întruneşte caracteristicile celor trei

tipuri de mai sus.

Pentru fiecare din aceste patru tipuri de ferestre de dialog există mai multe metode cu

numele corespunzător, care diferă între ele prin lista de argumente. Pentru detalii trimitem la

documentaţia Java API.

Exemplu

În fişierul Dialog1.java este dat un exemplu de aplicaţie, în care se testează diferitele tipuri de

ferestre de dialog create cu metodele statice ale clasei javax.swing.JOptionPane. Fereastra

principală a aplicaţiei conţine un buton cu inscripţia "Introducere text" şi o arie de text

(JTextArea). Când este acţionat butonul, apare o fereastră de dialog de intrare, cu mesajul

"Introduceţi un text". Dacă se acţioneaza butonul OK fără să fi introdus nimic în câmpul de

text, apare o noua fereastră de dialog, care conţine mesajul de avertisment "Nu se permite un

şir vid". Dacă se introduce un şir în câmpul de text şi se acţioneaza butonul OK sau tasta

Enter, apare o nouă fereastră de dialog, care cere confirmarea că acest text trebuie introdus în

aria de text. Dacă se răspunde prin acţionarea butonului Yes, se face adăugarea, iar dacă se

răspunde prin apăsarea butonului No sau Cancel, fereastra de dialog dispare fără să se facă

adăugarea textului.

Întrucât întregul dialog este declanşat, în cazul de faţă, prin acţionarea butonului "Introducere

text", programul prin care se realizează dialogul a fost plasat în metoda actionPerformed a

clasei IntroducereText care ascultă evenimentele de acţiune generate de butonul menţionat.

/* Alegerea culorilor folosind obiectele de culoare predefinite din clasa Color

Page 269: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

269

*/

import java.awt.*; import java.awt.event.*; import javax.swing.*; //import javax.swing.event.*;

class Dialog1 { static AF af=new AF(); static IntroducereText it=new IntroducereText(); static IUG iug=new IUG("Utilizarea unei ferestre de dialog");

/* clasa imbricata pentru interfata utilizator grafica */ static class IUG extends JFrame { JTextArea arieText;

IUG(String titlu) { // constructorul clasei IUG super(titlu); setSize(250, 200); setLocation(100, 50); Container cp=getContentPane(); addWindowListener(af); // adaugarea ascultatorului de fereastra JButton buton1=new JButton("Introducere text"); buton1.addActionListener(it); cp.add(buton1, BorderLayout.NORTH); arieText=new JTextArea(); arieText.setLineWrap(true); arieText.setWrapStyleWord(true); cp.add(arieText, BorderLayout.CENTER); setVisible(true); }

}

/* Clasa ascultatoare de fereastra */ static class AF extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); // incheierea executarii aplicatiei } }

/* Clasa pentru introducerea textului prin fereastra de dialog */ static class IntroducereText implements ActionListener { public void actionPerformed(ActionEvent e) { String sirIntrodus; boolean terminat=false; while(!terminat) { sirIntrodus=JOptionPane.showInputDialog("Introduceti un text"); if(sirIntrodus!=null) { if(sirIntrodus.trim().equals("")) JOptionPane.showMessageDialog(iug, "Nu se permite un sir vid!", "Avertisment", JOptionPane.WARNING_MESSAGE); else { int raspuns=JOptionPane.showConfirmDialog(iug, "Doriti adaugarea textului: "+sirIntrodus+"?"); if(raspuns==JOptionPane.YES_OPTION) iug.arieText.append(sirIntrodus+"\n");

Page 270: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

270

terminat=true; } } else terminat=true; } } }

/* Metoda principala a aplicatiei */ public static void main(String args[]) { } }

Cu privire la metoda actionPerformed din clasa IntroducereText remarcăm următoarele:

1) Instrucţiunea sirIntrodus=JOptionPane.showInputDialog("Introduceti un text");

are ca efect afişarea pe ecran a unei ferestre de dialog de intrare. Şirul introdus în câmpul de

text al acestei ferestre este intors şi atribuit variabilei sirIntrodus. Dacă s-a acţionat butonul

Cancel, metoda întoarce null.

2) Instrucţiunea JOptionPane.showMessageDialog(null, "Nu se permite un sir

vid!","Avertisment", JOptionPane.WARNING_MESSAGE); are ca efect afişarea unei ferestre de dialog care conţine un mesaj de avertisment.

3) Instrucţiunea int raspuns=JOptionPane.showConfirmDialog(iug, "Doriti adaugarea textului: "+sirIntrodus+"?"); are ca efect afişarea unei ferestre de dialog de confirmare, care întoarce o valoare de tip int,

care poate fi egală cu una din cosnstantele YES_OPTION, NO_OPTION sau

CANCEL_OPTION care sunt definite în clasa JOptionPane.

În rest, considerăm că procedura de dialog rezultă clar din textul metodei.

Pentru aprofundarea utilizării ferestrelor de dialog, recomandăm consultarea capitolului How

to Make Dialogs din Java Tutorial.

Alegerea culorii

În multe aplicaţii, la proiectarea interfeţei utilizator grafice este necesar să se impună culorile

de fond şi de primplan ale diferitelor componente, folosind metodele clasei Component

public void setBackground(Color color) - pentru culoarea de fond;

public void setForeground(Color color) - pentru culoarea de prim-plan (a

textului).

Pentru reprezentarea şi manipularea informaţiei despre culoare se foloseşte clasa

java.awt.Color. Cea mai simplă utilizare a acestei clase este utilizarea culorilor predefinite,

pe care le conţine sub forma de câmpuri statice.

De exemplu, culoarea albastru este reprezentată prin câmpul static Color.blue, iar culoarea

galben prin Color.yellow. În consecinţă, dacă dorim să punem componentei comp culoarea

Page 271: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

271

de fond albastru şi culoarea de primplan galben, vom folosi instrucţiunile: comp.setBackground(Color.blue); comp.setForeground(Color.yellow);

Pentru a afla toate culorile predefinite şi celelalte specificaţii privind clasa Color trimitem

cititorii la documentaţia Java API. Culorile predefinite sunt folosite şi în exemplul care

urmează.

Exemplu

În fişierul Culori.java se dă un exemplu de aplicaţie, în care se demonstrează utilizarea

culorilor predefinite din clasa java.awt.Color.

Fereastra aplicaţiei conţine o listă cu denumirile culorilor predefinite din clasa Color şi un

panou pe care se afişează culorile respective, prin setarea corespunzătoare a culorii de fond a

panoului. Când se selectează o culoare din listă, se observa imediat modificarea

corespunzătoare a culorii panoului. În acest scop, în program au fost folosite două tablouri:

numeCulori - este un tablou de şiruri (String[]) care conţin numele culorilor;

tablouCulori - este un tablou de instanţe ale clasei Color, care conţine toate culorile

predefinite din aceasta clasă.

Lista de culori listaCulori din clasa JList este construită pe baza tabloului numeCulori şi

deci conţine ca articole numele culorilor (denumirile puteau fi date în limba română, dar am

preferat ca cititorii să se familiarizeze cu cele existente în clasa Color).

Când se selectează un articol din listă, se generează un ListSelectionEvent. Pentru ascultarea

lui s-a creeat clasa AscultaLista. În metoda valueChanged a acestei clase, se determină

indicele articolului care a fost selectat şi se setează drept culoare de fond a panoului culoarea

cu acelaşi indice din tablouCulori.

/* Alegerea culorilor folosind obiectele de culoare predefinite din clasa Color */

import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*;

class Culori { static AF af=new AF(); static IUG iug=new IUG("Alegerea culorii din lista");

/* clasa imbricata pentru interfata utilizator grafica */ static class IUG extends JFrame { JPanel panouCuloare; // panoul pe care se prezinta culoarea String[] numeCulori={"black", "darkGray", "gray", "lightGray", "white", "blue", "cyan", "green", "orange", "yellow", "red", "pink", "magenta"}; Color[] tablouCulori={Color.black, Color.darkGray, Color.gray, Color.lightGray, Color.white, Color.blue, Color.cyan, Color.green, Color.orange, Color.yellow, Color.red, Color.pink, Color.magenta};

Page 272: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

272

JList listaCulori;

IUG(String titlu) { // constructorul clasei IUG super(titlu); setSize(250, 200); setLocation(100, 50); Container cp=getContentPane(); addWindowListener(af); // adaugarea ascultatorului de fereastra panouCuloare=new JPanel(); // crearea panoului pentru culoare cp.add(panouCuloare, BorderLayout.CENTER);

Color[] tablouCulori={Color.black, Color.darkGray, Color.white}; listaCulori=new JList(numeCulori); listaCulori.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); listaCulori.addListSelectionListener(new AscultLista()); JScrollPane panouCulori=new JScrollPane(listaCulori); cp.add(panouCulori, BorderLayout.WEST);

setVisible(true); }

}

/* Clasa ascultatoare de fereastra */ static class AF extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); // incheierea executarii aplicatiei } }

/* Clasa ascultatoare a listei de culori */ static class AscultLista implements ListSelectionListener { public void valueChanged(ListSelectionEvent e) { int indiceCuloare=iug.listaCulori.getSelectedIndex(); iug.panouCuloare.setBackground(iug.tablouCulori[indiceCuloare]); } }

/* Metoda principala a aplicatiei */ public static void main(String args[]) { } }

Clasa Color

Clasa Color încapsulează informaţiile despre culoare. În Java AWT se foloseşte modelul de

culori RGB (engleză: red, green, blue) în care fiecare culoare este considerată ca fiind

compusă din trei culori fundamentale: roşu, verde şi albastru. În consecinţă, culoarea este

dată prin trei numere cuprinse în intervalul [0, 255], reprezentând ponderile celor trei culori

fundamentale. În figura de mai jos este reprezentată schema de combinare a acestor trei culori

fundamentale.

Page 273: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

273

Prin modificarea ponderilor celor trei culori se pot obţine, în principiu, toate culorile posibile,

de la negru [r=0,g=0,b=0] la alb [r=255,g=255,b=255]. Dacă ponderile celor trei culori sunt

egale, se obţin diferite nuanţe de gri. Culoarea galbenă are ponderile [r=255,g=255,b=0],

culoarea cyan (azuriu) are ponderile [r=0,g=255,b=255] iar culoarea magenta are ponderile

[r=255,g=0,b=255]. Alte culori: orange: [r=255,g=200,b=0], pink (roz):

[r=255,g=175,b=175].

Clasa Color conţine şi un al patrulea câmp, numit alpha, care poate avea, de asemenea, valori

întregi în intervalul [0..255] şi exprima opacitatea culorii respective. Daca alpha=255,

culoarea este complet opaca. Aceasta înseamnă că, dacă o figură cu această culoare se

suprapune peste alta, o maschează complet. Dacă alpha=0, culoarea este complet

transparentă, deci practic invizibilă. Între aceste valori extreme putem avea diferite opacităţi

intermediare, cuprinse intre 0 si 255.

Culoarea în sistemul RGB poate fi exprimată nu numai printr-o instanţă a clasei Color, ci şi

printr-un număr întreg (de tip int), în care cei patru octeţi au, respectiv, valorile

componentelor alpha, r, g, b exprimate în intervalul [0..255]. Componentele sunt plasate

astfel: alpha în biţii 24..31, r în biţii 16..23, g în biţii 8..15 şi b în biţii 0..7.

Clasa Color conţine, de asemenea, constructori şi metode care suportă sistemele de culori

sRBG şi HSB. Standardul sRGB defineşte o variantă standardizată a sistemului RGB,

destinată monitoarelor cu tub catodic. În acest sistem, parametrii r, g, b şi alpha se exprimă

prin numere reale în intervalul [0.0...1.0].

Sistemul de culori HSB (engleză: Hue, Saturation and Brightness) ofera o descriere a

culorilor independentă de sistemul de afişare, folosind următorii trei parametri:

Nuanţa (engleză: Hue) care se exprimă în grade, în intervalul [0..360], unde 0 este rosu, 60

este galben, 120 este verde etc.

Saturaţie (engleză: Saturation) este puritatea culorii, exprimată în procente, în intervalul

[0..100]. La valoarea 0, nuanţa (Hue) nu are semnificatie, iar la valoarea 100 culoarea este

pură.

Strălucire (engleză: Brightness) este exprimată de asemenea în procente, în intervalul

[0..100]. Valoarea 0 înseamnă negru (iluminare 0%), deci parametrii Hue şi Saturation nu au

Page 274: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

274

sens. Valoarea 100 reprezintă strălucirea maximă. Diagrama de mai jos dă o reprezentare a

culorilor exprimate în sistemul HSB.

În clasa Color, parametrii Hue, Saturation şi Brightness se exprimă prin numere reale (tipul

float) în intervalul [0.0 .. 1.0].

Dacă valorile sunt în afara acestui interval, se ia în consideraţie numai partea fracţionara: de

exemplu valoarea 2.73 se consideră echivalentă cu 0.73. În aceste condiţii, dacă se consideră

saturaţia şi strălucirea egale cu 1.0 (100%), valorile parametrului Hue (nuanţă) pentru

principalele culori sunt:

red: h=0.0;

yellow: h=0.6666 (600);

green: h=0.3333 (1200);

cyan: h=0.5 (1800);

blue: h=0.6666 (2400);

magenta: h=0.8333 (3000)

Culoarea neagra (black) se obtine punând strălucirea Brightness=0, iar culoarea albă

(white) se obţine punand saturaţia Saturation=0 şi strălucirea Brightness=1. Dacă se menţine

saturaţia la valoarea 0 şi se dau strălucirii diferite valori între 0 şi 1 se obţin nuanţele de gri.

Variabile: Clasa Color conţine variabile statice finale (constante) care sunt instanţieri ale clasei pentru

diferite culori tipice: black, blue, cyan, darkGray, gray, green, lightGray, magenta, orange,

pink, red, white yellow. Acestea sunt, respectiv, culorile negru, albastru, azuriu, gri inchis, gri, verde, gri deschis,

mov, roz, rosu, alb şi galben. De exemplu, culoarea verde va fi reprezentata prin

Color.green. Toate aceste culori sunt opace, deci au componenta alpha cu valoarea 255.

Page 275: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

275

Constructori: Clasa Color are mai mulţi constructori, dintre care menţionăm aici pe cei mai frecvent

folosiţi:

public Color(int r, int g, int b) - în care argumentele r,g,b sunt numere

întregi în intervalul [0..255], reprezentând ponderile culorilor red, green, blue, iar

componenta alpha are implicit valoarea 255;

public Color(int r, int g, int b, int alpha) - similar cu cel precedent,

indicându-se în plus gradul de opacitate alpha, de asemenea în intervalul [0..255];

public Color(int rgb) - creează o culoare opacă cu parametrii r,g,b daţi ultimii trei

octeţi ai argumentului rgb;

public Color(int rgba, boolean hasalpha) - creează o culoare pornind de la

parametrii alpha,r,g,b împacetaţi în cei patru octeţi ai argumentului rgba. Daca al doilea

argument este true, parametrul alpha (bitii 24..31 ai argumentului) este luat în consideraţie;

public Color(float r, float g, float b) - creează o culoare opacă în sistemul

sRGB, în care r,g,b sunt ponderile culorilor fundamentale în intervalul [0.0...1.0], iar alpha

are valoarea implicită 1.0;

public Color(float r, float g, float b, float alpha) - creează o culoare în

sistemul sRGB, fiind daţi toti cei patru parametri.

Metode: Menţionăm aici metodele cel mai frecvent utilizate.

public int getRed() - întoarce ponderea culorii red (rosu);

public int getGreen() - întoarce ponderea culorii green(verde);

public int getBlue() - întoarce ponderea culorii blue(albastru);

public int getAlpha() - întoarce componenta alpha(opacitatea culorii);

public Color brighter() - creează o versiune mai luminoasă a acestei culori;

public Color darker() - creează o versiune mai întunecată a acestei culori;

public static Color getHSBColor(float h, float s, float b) - creează o

instanţă a clasei Color (deci în sistemul RGB) pornind de la parametrii h, s şi b ai culorii

respective, exprimaţi is sistemul HSB, în intervalul [0.0 ... 1.0];

public static int HSBtoRGB(float h, float s, float b) - transformă

parametrii h,s,b ai culorii exprimate în sistemul HSB prin numere reale în intervalul [0.0 ...

1.0] într-un număr întreg (int), în care cei patru octeţi sunt parametrii r,g,b,alpha ai aceleeaşi

culori exprimate în sistemul RGB;

O prezentare mai completă a câmpurilor, constructorilor şi metodelor clasei Color este dată în

Indexul de clase.

Exemplul 1:

În fişierul TestRGB.java este dat un exemplu de aplicaţie, în care se testează compunerea

diferitelor culori în sistemul RGB. În partea stângă a ferestrei sunt trei rigle de ajustare

(JSlider) pentru cele trei culori fundamentale (roşu, verde, albastru). În dreptul fiecărei rigle

există un câmp de text în care se afişează valoarea indicată, în întervalul [0, 255]. În partea

dreaptă a ferestrei există un panou (JPanel) a cărui culoare de fond corespunde combinaţiei de

culori date de cele trei rigle.

Page 276: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

276

Puteţi ajusta culorile şi urmări efectul produs.

Exemplul 2:

În fişierul TestHSB.java este dat un exemplu de aplicaţie în care se testează alegerea culorilor

în sistemul HSB. Fereastra se aseamană cu cea din exemplul precedent, dar cele trei rigle

servesc pentru ajustarea componentelor HSB: nuanţa, saturaţie şi strălucire. Valorile

corespunzătoare sunt indicate în câmpurile de text alăturate, ca numere reale în intervalul

[0.0, 1.0]. La partea inferioară a ferestrei sunt afişate componentele culorii în sistemul RGB.

/* Alegerea culorilor in sistemul HSB (Hue, Saturation, Brightness) */

import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*;

class TestHSB { static AF af=new AF(); static IUG iug=new IUG("Alegerea culorii in sistemul HSB"+ " (Hue, Saturation, Brightness)");

/* clasa imbricata pentru interfata utilizator grafica */ static class IUG extends JFrame { AjustCuloare hue, satur, bright; // rigle de ajustare a culorilor Box box1; // caseta riglelor de ajustare JPanel panouCuloare; // panoul pe care se prezinta culoarea Color culoare; // culoarea panoului panouCuloare JLabel culoriRGB; // pentru afisarea culorilor in sistem RGB

IUG(String titlu) { // constructorul clasei IUG super(titlu); setSize(500, 200); setLocation(100, 50); Container cp=getContentPane(); addWindowListener(af); // adaugarea ascultatorului de fereastra /* Se creeaza caseta cu dispozitive de ajustare */ box1=Box.createVerticalBox(); hue=new AjustCuloare("Nuanta "); // ajustarea nuantei box1.add(hue); satur=new AjustCuloare("Saturatie "); // ajustarea saturatiei box1.add(satur); bright=new AjustCuloare("Stralucire "); // ajustarea stralucirii bright.ajustare.setPaintLabels(true); box1.add(bright); cp.add(box1, BorderLayout.WEST); panouCuloare=new JPanel(); // crearea panoului pentru culoare cp.add(panouCuloare, BorderLayout.CENTER); culoriRGB=new JLabel(); // crearea etichetei cu valori RGB cp.add(culoriRGB, BorderLayout.SOUTH); puneCuloarea(); // se pune culoarea initiala setVisible(true); }

Page 277: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

277

/* Metoda de determinare a culorii RGB */ void puneCuloarea() { culoare=new Color(Color.HSBtoRGB(hue.fval, satur.fval, bright.fval)); // conversie din HSB in RGB panouCuloare.setBackground(culoare); culoriRGB.setText("Culori RGB -> rosu: "+ culoare.getRed()+" verde: "+culoare.getGreen()+ " albastru: "+culoare.getBlue()); } }

/* Un "dispozitiv" de ajustare a valorii unei culori */

static class AjustCuloare extends Box implements ChangeListener { JTextField valoare; // camp pentru afisarea valorii HSB JSlider ajustare; // rigla de ajustare a valorii float fval=1.0f; // valoarea HSB (in intervalul 0,..,1).

AjustCuloare(String culoare) { super(BoxLayout.X_AXIS); add(new JLabel(culoare)); add(Box.createHorizontalGlue()); ajustare=new JSlider(JSlider.HORIZONTAL, 0, 100,100); ajustare.setMajorTickSpacing(20); ajustare.setMinorTickSpacing(10); ajustare.setPaintTicks(true); ajustare.addChangeListener(this); add(ajustare); add(Box.createHorizontalStrut(5)); valoare=new JTextField("1.00",4); valoare.setHorizontalAlignment(JTextField.RIGHT); valoare.setEditable(false); valoare.setBackground(Color.white); valoare.setMaximumSize(valoare.getMinimumSize()); add(valoare); add(Box.createHorizontalStrut(5)); }

/* metoda de ascultare a deplasarii cursorului riglei */ public void stateChanged(ChangeEvent e) { fval=ajustare.getValue()/100.0f; // determinarea valorii reale // in intwervalul 0,..1 valoare.setText((fval+" ").substring(0,4)); // afisarea valorii iug.puneCuloarea(); // modificarea culorii panoului } }

/* Clasa ascultatoare de fereastra */ static class AF extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); // incheierea executarii aplicatiei } }

/* Metoda principala a aplicatiei */ public static void main(String args[]) {

Page 278: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

278

} }

Ajustând valorile prin intermediul riglelor, constatăm următoarele:

- Dacă strălucirea este 0.0, culoarea obţinută este negru, indiferent de valorile celorlalte

două componente. Cu cât valoarea strălucirii este mai mare, culoarea obţinută este mai

deschisă.

- Dacă saturaţia este 0.0, valoarea nuanţei nu are efect: în acest caz, modificând strălucirea

de la 0.0 la 1.0 se obţin diferite nuanţe de gri, de la negru la alb.

- Dacă saturaţia şi strălucirea au valori diferite de 0.0, culoarea se poate ajusta prin

modificarea nuanţei. Cu cât saturaţia este mai mare, nuanţa respectivă este mai pronunţată, iar

cu cât strălucirea este mai mare, culoarea este mai deschisă.

Alegerea culorii folosind clasa JColorChooser

Pentru a alege culoarea în mod interactiv, în JFC/Swing este prevazută clasa

javax.swing.JColorChooser. Instanţele acestei clase sunt panouri de selectare a culorii, care

pot fi folosite atât prin încorporarea lor într-o fereastră obişnuită, cât şi sub forma unei

ferestre de dialog.

Pentru a creea o fereastră de dialog, care conţine în ea un JColorChooser şi întoarce culoarea

selectată, în clasa JColorChooser există metoda public static JDialog createDialog(Component c,String title, boolean

modal, JColorChooser chooserPane, ActionListener okListener, ActionListener

cancelListener) în care:

- c este componenta beneficiară (owner) a ferestrei de dialog create;

- title este titlul ferestrei de dialog create;

- argumentul boolean modal indică dacă fereastra este modală;

- chooserPane este instanţa clasei JColorChooser care se întroduce în fereastra de dialog;

- okListener si cancelListener sunt ascultătoarele de acţiune care reacţioneaza la

apăsarea butonului OK, respectiv Cancel al selectorului de culoare.

Folosind un JColorChooser, alegerea culorii se poate face în trei moduri:

- folosind un tablou de culori, în care fiecare celulă este colorată în altă culoare;

- în sistemul RGB, folosind trei rigle de ajustare a culorilor fundamentale;

- în sistemul HSB, selectând culoarea prin alegerea cu mouse-ul a punctului de pe panou

care are culoarea potrivita (trei butoane alăturate, notate H, S, B, arată care din cele trei

componente se menţine constantă, celelalte două fiind date de coordonatele punctului ales pe

panou).

Exemplu

În fişierul SelectCulori.java se dă un exemplu de aplicaţie în care, pentru alegerea culorii unui

panou, se foloseşte o fereastră de dialog, în care se găseşte un JColorChooser.

/* Alegerea culorilor folosind un JColorChooser */

import java.awt.*; import java.awt.event.*;

Page 279: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

279

import javax.swing.*;

class SelectCulori { static AF af=new AF(); static AscultDialog ascultDialog=new AscultDialog(); static AscultButon ascultButon=new AscultButon(); static IUG iug=new IUG("Alegerea culorii folosind JColorChooser");

/* clasa imbricata pentru interfata utilizator grafica */ static class IUG extends JFrame { JPanel panouCuloare; // panoul pe care se prezinta culoarea JColorChooser selectorCuloare; JDialog dialogCuloare;

IUG(String titlu) { // constructorul clasei IUG super(titlu); setSize(350, 200); setLocation(100, 50); Container cp=getContentPane(); addWindowListener(af); // adaugarea ascultatorului de fereastra panouCuloare=new JPanel(); // crearea panoului pentru culoare cp.add(panouCuloare, BorderLayout.CENTER); selectorCuloare=new JColorChooser(); JButton butonCuloare=new JButton("Schimbarea culorii"); butonCuloare.addActionListener(ascultButon); butonCuloare.setToolTipText("Selectarea culorii panoului"); cp.add(butonCuloare, BorderLayout.SOUTH); dialogCuloare=JColorChooser.createDialog(butonCuloare, "Alegerea culorii", true, selectorCuloare, ascultDialog, ascultDialog); setVisible(true); } }

/* Clasa ascultatoare de fereastra */ static class AF extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); // incheierea executarii aplicatiei } }

/* Ascultator actiuni fereastra dialog */ static class AscultDialog implements ActionListener { public void actionPerformed(ActionEvent e) { if(e.getActionCommand().equals("OK")) iug.panouCuloare.setBackground( iug.selectorCuloare.getColor()); } }

/* Ascultarea butonului de comanda */ static class AscultButon implements ActionListener { public void actionPerformed(ActionEvent e) { iug.dialogCuloare.show(); } }

/* Metoda principala a aplicatiei */

Page 280: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

280

public static void main(String args[]) { } }

Elemente de grafică

Java API ofera programatorilor posibilităţi ample privind realizarea de desene, text stilizat şi

alte construcţii grafice. Ne vom rezuma aici numai la câteva noţiuni elementare, utile în

realizarea unor aplicaţii grafice simple.

Pentru aprofundare recomandăm lectia Working with Graphics din Java Tutorial. Studiul

poate fi apoi continuat cu secţiunea 2D Graphics a aceluiaşi tutorial.

In principiu, desenarea se poate face pe orice componentă grafică. Există însă clasa

java.awt.Canvas, ale cărei instanţe sunt simple panouri destinate desenării (în engleză

Canvas este pânza pictorului). Pentru desenare se mai folosesc frecvent şi clasele JPanel şi

JLabel.

Sistemul de coordonate folosit pentru grafică are originea în colţul din stânga sus al

componentei, axa Ox este orientată catre dreapta, iar axa Oy este orientată în jos.

Coordonatele se exprimă în numere întregi (int), având ca unitate de măsură pixelul (punctul

de pe ecran).

Contextul grafic

Modul de realizare a imaginilor şi desenelor este strâns dependent atât de echipament

(hardware) cât şi de sistemul de operare. Pentru a se asigura independenţa de platformă, în

Java API a fost introdusă clasa abstractă java.awt.Graphics. Aceasta este clasa de bază a

tuturor contextelor grafice, care permit trasarea de desene pe suprafaţa componentelor

grafice realizate pe diverse dispozitive fizice. Pe fiecare platformă, în mediul de execuţie

Java, trebuie să existe o implementare a contextului grafic, adică o extindere a clasei

Graphics, care conţine toate câmpurile şi metodele acestei clase, dar este specifică platformei

respective.

Un obiect din clasa Graphics încapsulează informaţia de stare a contextului grafic la care se

referă şi anume:

- referinţa la obiectul din clasa Component (sau dintr-o subclasa a acesteia) pe care se

desenează;

- o translaţie a originii sistemului de coordonate; toate coordonatele din desen sunt

raportate la această origine;

- decupajul curent (dreptunghiul în interiorul căruia se trasează desenul);

- culoarea curentă;

- fontul curent;

- operaţia logică pe pixeli curentă (XOR sau paint);

- alternarea curentă de culori pentru operaţia pe pixeli XOR.

Page 281: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

281

Originea sistemului de axe (punctul de coordonate 0,0) se găseşte în colţul din stânga-sus al

dreptunghiului de desenare. Axa 0x este îndreptată spre dreapta, iar axa 0y - in jos.

Practic, clasa abstractă Graphics conţine acele metode, care trebuie să existe în orice context

grafic. Conţinutul concret al acestor metode, deci modul efectiv în care se realizează funcţiile

respective, depinde de contextul grafic real, deci de dispozitivul fizic pe care se face

desenarea şi de sistemul de operare folosit. Pe programatorul de aplicaţii sau miniaplicaţii în

Java nu îl interesează însă acest lucru, deoarece el foloseşte în programele sale metodele

clasei abstracte Graphics, fără să se preocupe de modul în care acestea vor fi executate.

Principalele metode ale clasei Graphics sunt următoarele:

public abstract Graphics create() - creează şi întoarce un nou obiect din clasa

Graphics, care este o copie a obiectului pentru care se aplică această metodă;

public abstract Graphics create(int x, int y, int width, int height) -

creează şi întoarce o copie a obiectului din clasa Graphics căruia i se aplică, însă cu o noua

translaţie a originii (x,y) şi cu valori noi valori ale lăţimii şi înălţimii dreptungiului de

desenare (suprafeţei de decupare);

public abstract void translate(int x, int y) - translatează originea sistemului

de coordonate în punctul (x,y) al sistemului de coordonate curent;

public abstract Color getColor() - întoarce culoarea de desenare curentă;

public abstract void setColor(Color c) - setează culoarea de desenare curentă;

public abstract Font getFont() - întoarce fontul curent;

public abstract void setFont(Font f) - setează fontul curent;

public abstract FontMetrics getFontMetrics() - întoarce metrica fontului

curent;

public abstract void setFontMetrics(FontMetrics fm) - setează metrica

fontului curent;

public abstract Rectangle getClipBounds() - întoarce dreptunghiul de decupare

curent;

public abstract void setClip(int x, int y, int width, int height) -

setează dreptunghiul de decupare curent; public abstract void copyArea(int x, int y, int width, int height, int

dx, int dy) - copiaza suprafaţa dreptunghiulara cu originea (x,y), lăţimea width şi

înălţimea height într-o noua zonă de aceleaşi dimensiuni, având originea (x+dx, y+dy)..

public abstract void setPaintMode() - setează operaţia logică pe pixeli curentă la

modul paint, adică desenarea se face peste fondul existent, folosinduse culoarea de desenare

curentă, fără a lua în consideraţie culoarea fondului.

public abstract void setXORMode(color c1) - setează operaţiile pe pixeli la

modul XOR, adică se alternează pixelii de culoare curentă cu cei din culoarea c1; aceasta

înseamnă că, dacă un pixel nou plasat are aceeaşi culoare curentă cu cea existentă anterior în

acelaşi loc, ea va fi înlocuita cu c1; invers, dacă pixelul existent anterior avea culoarea c1, ea

va fi înlocuită cu culoarea curentă.

public abstract void drawLine(int x1, int y1, int x2, int y2) - se

traseaza o linie dreaptă din punctul de coordonate (x1,y1) până în punctul (x2,y2);

public abstract void drawRect(int x, int y, int width, int height) - se

trasează un dreptunghi cu colţul din stânga sus în punctul (x,y), având lăţimea width şi

Page 282: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

282

înălţimea height;

public abstract void fillRect(int x, int y, int width, int height) -

umple cu culoarea curentă interiorul dreptunghiului cu colţul din dreapta sus în punctul (x,y)

şi cu dimensiunile (width, height);

public abstract void clearRect(int x, int y, int width, int height) -

şterge conţinutul dreptunghiului de coordonate şi dimensiuni specificate, umplându-l cu

culoarea de fond; public abstract void drawRoundRect(int x, int y, int width, int height,

int arcWidth, int arcHeight) - trasează un dreptunghi cu colţurile rotunjite, unde

arcWidth si arcHeight sunt respectiv diametrul orizontal şi diametrul vertical al arcelor de

rotunjire; public abstract void fillRoundRect(int x, int y, int width, int height,

int arcWidth, int arcHeight) - umple cu culoarea curentă interiorul unui dreptunghi cu

colţurile rotunjite; public abstract void draw3DRect(int x, int y, int width, int height,

boolean raised) - desenează un dreptunghi astfel luminat, încât el apare că iese din

suprafaţa de baza, dacă raised=true, sau este scufundat în aceasta suprafaţă, dacă

raised=false; public abstract void fill3dRect(int x, int y, int width, int height,

boolean raised) - umple cu culoarea curentă interiorul unui dreptunghi tridimensional,

luând în consideraţie şi iluminarea;

public abstract void drawOval(int x, int y, int width, int height) - se

desenează ovalul înscris în dreptunghiul cu colţul din stânga sus în punctul (x,y) şi cu

dimensiunile (width, height);

public abstract void fillOval(int x, int y, int width, int height) - se

umple cu culoarea curentă conţinutul ovalului înscris în dreptunghiul cu colţul stânga sus în

punctul (x,y) şi de dimensiuni (width, height); public abstract void drawArc(int x, int y, int width, int height, int

startAngle, int arcAngle) - se desenează un arc circular sau eliptic, care se înscrie în

dreptunghiul specificat. Putem să ne imaginăm că din elipsa înscrisă în acest dreptunghi şi

având centrul în centrul dreptunghiului, se trasează efectiv numai arcul care începe de la

unghiul startAngle şi se extinde pe un unghi egal cu arcAngle. Unghiurile sunt măsurate în

grade. Unghiul 0 este corespunzator poziţiei de la ora 3 a acului de ceasornic, iar sensul

pozitiv al unghiurilor este cel contra acelor de ceasornic; public abstract void fillArc(int x, int y, int width, int height, int

startAngle, int arcAngle) - umple cu culoarea curentă sectorul mărginit de arcul

specificat prin parametri şi de razele de la capete; public abstract void drawPolyline(int[] xPoints, int[] yPoints, int

nPoints) - trasează o linie frântă, care trece prin punctele ale căror coordonate (x,y) sunt

date în tabelele xPoints şi yPoints; numărul de puncte este nPoints; public abstract void drawPoligon(int[] xPoints, int[] yPoints, int

nPoints) - trasează un poligon cu nPoints vârfuri, situate în punctele ale căror coordonate

(x,y) sunt date în tabelele xPoints şi yPoints;

public abstract void drawPoligon(Poligon p) - trasează poligonul specificat ca

argument; public abstract void fillPoligon(int[] xPoints, int[] yPoints, int

nPoints) - umple cu culoarea curenta un poligon cu nPoints vârfuri, situate în punctele ale

căror coordonate (x,y) sunt date în tabelele xPoints şi yPoints;

public abstract void fillPoligon(Poligon p) - umple cu culoarea curentă

poligonul specificat ca argument;

public abstract void drawString(String str, int x, int y) - trasează şirul

Page 283: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

283

de caractere str, folosind fontul şi culoarea curente; baza primului caracter al şirului este în

punctul de coordonate (x,y); public abstract void drawString(AttributedCharacterIterator iterator,

int x, int y) - trasează un şir de caractere conţinute în obiectul iterator, care specifică nu

numai caracterele propriuzise ci şi fontul fiecărui caracter; baza primului caracter este în

punctul de coordonate (x,y); public abstract void drawChars( char[] data, int offset, int length,

int x, int y) - trasează length caractere din tabloul data, începând cu caracterul cu

indicele offset; baza primului caracter se găseşte în punctul de coordonate (x,y); fontul şi

culoarea sunt cele curente;

Metodele paint si repaint

Pentru desenarea pe suprafaţa unei componente, în clasa java.awt.Component (rădăcina

ierarhiei de clase a componentelor) există metoda public void paint(Graphics g)

Această metodă traseaza efectiv desenul, folosind în acest scop contextul grafic g primit ca

argument. Contextul grafic nu este instanţiat de către programator, ci este transmis acestei

metode de către maşina virtuală Java. În schimb, metoda paint trebuie redefinită în program

pentru orice componentă pe care dorim să se traseze un desen. În aceast scop se folosesc în

metoda paint metodele de desenare ale clasei Graphics.

Metoda paint nu este invocată explicit în program. Ea este invocată implicit (de către maşina

virtuală Java) atunci când componenta respectivă este afişată pe ecran sau îşi modifică

dimensiunile şi/sau poziţia. Dacă, totuşi, programatorul doreşte să solicite explicit desenarea,

foloseşte metoda public void repaint() Aceasta metodă care există, de asemenea, în clasa java.awt.Component, nu trebuie

redefinită, singurul ei rol fiind de a apela metoda paint.

Exemplul 1:

În fişierul Desen.java este dat un exemplu de aplicaţie simplă, în care se testează diferite

metode ale clasei Graphics. În acest scop, s-a creat clasa PanouDesen ca o extensie a clasei

Canvas. În această clasă, a fost redefinită metoda paint(), astfel încât să se traseze diferite

desene: un dreptunghi gol, un dreptunghi plin, un dreptunghi gol cu colţurile rotunjite, un

dreptunghi plin cu colţurile rotunjite, un oval gol, un oval plin, o linie frântă şi un poligon. S-

au testat în acest fel metodele clasei Graphics. În fereastra aplicaţiei s-a introdus o instanţă a

clasei PanouDesen.

/* Testarea clasei Graphics In fereastra aplicatiei iug se introduce suprafata de desenare panouDesen din clasa PanouDesen, care este derivata din clasa Canvas In clasa PanouDesen, metoda paint() este redefinita, astfel incat sa traseze mai multe desene, testandu-se metodele clasei Graphics */

Page 284: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

284

import java.awt.*; import java.awt.event.*; import javax.swing.*;

class Desen { static Sfarsit sfarsit=new Sfarsit(); static IUG iug=new IUG("Exemplu de desenare");

static class IUG extends JFrame { PanouDesen panouDesen;

IUG(String titlu) { super(titlu); addWindowListener(sfarsit); panouDesen=new PanouDesen(); setLocation(200,150); getContentPane().add(panouDesen); setSize(220,200); setVisible(true); } }

static class Sfarsit extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } }

static class PanouDesen extends Canvas {

public void paint(Graphics g) { setBackground(Color.white); g.setColor(Color.black); g.drawRect(5,5,40,25); g.drawRect(50,5,40,25); g.setColor(Color.blue); g.fillRect(50,5,40,25); g.setColor(Color.red); g.drawRoundRect(100,5,40,25,10,10); g.drawRoundRect(150,5,40,25,10,10); g.setColor(Color.green); g.fillRoundRect(150,5,40,25,10,10); g.drawOval(5,40,40,25); g.drawOval(50,40,40,25); g.setColor(Color.magenta); g.fillOval(50,40,40,25); g.setColor(Color.black); g.drawArc(100,40,40,25,-5,130); g.drawArc(150,40,40,25,-5,130); g.setColor(Color.green); g.fillArc(150,40,40,25,-5,130); g.setColor(Color.black); int[] xlf={5,30,55,80,100,125}, ylf={100,70,85,75,75,80}; g.drawPolyline(xlf,ylf,6); int[] xp={15,50,75,65,55}, yp={100,90,95,120,150}; g.drawPolygon(xp,yp,5);

Page 285: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

285

g.setColor(Color.yellow); g.fillPolygon(xp,yp,5); }

}

public static void main(String args[]) { } }

Exemplul 2:

În fişierul GraficeFunctii.java este dat un exemplu de aplicaţie pentru trasarea graficelor unor

funcţii. În fereastra aplicaţiei s-au pus:

- panoul fct, care conţine o listă de selectie a funcţiei de reprezentat şi trei câmpuri de text,

în care se introduc de la tastatură marginile inferioară şi superioară a intervalului în care se

trasează funcţia (sub forma de numere reale) şi numărul de subintervale în care se împarte

acesta;

- suprafaţa de afişare gr, pe care se trasează graficul;

- eticheta mesaj, în care se afişează eventualele mesaje de eroare.

Pentru panoul fct a fost creată clasa Functii, derivată din clasa JPanel şi s-a folosit gestionarul

de poziţionare GridLayout.

Pentru suprafaţa de afişare s-a creat clasa Grafic, derivată din clasa Canvas.

Clasa Actiuni interceptează evenimentele generate de fereastra principală, câmpurile de text

şi lista de selecţie a funcţiilor. În acest scop, ea este derivată din clasa WindowAdapter şi

implementează interfeţele ActionListener şi ItemListener.

Trasarea graficului se face sub forma unei linii frânte, folosind metoda drawPoliline(int

x[],int y[],int nrPuncte), în care vectorii x şi y conţin coordonatele punctelor prin care

trece curba. Scările de reprezentare pe cele două axe se aleg automat, astfel încât graficul să

ocupe întreaga suprafaţă de desenare. În acest scop, se calculează mai întâi valorile reale ale

funcţiei de reprezentat, completându-se cu ele vectorul real valy. Se determină apoi ymax şi

ymin, iar dimensiunile suprafeţei de desenare se determină prin metodele getWidth() şi

getHeight(), iar xmin şi xmax sunt date. Folosind aceste date se calculează scările pe x şi y,

după care se calculează coordonatele pe desen ale punctelor, completându-se astfel vectorii x

şi y. Aceste calcule se fac în metoda calcul() din clasa Actiuni, iar trasarea graficului se

face în metoda paint() din clasa Grafic.

/* Aplicatie de trasare a graficelor unor functii. Se selecteaza functia de trasat si se introduc valorile marginilor intervalului de reprezentare. Trasarea functiei se face fie cand se selecteaza o noua functie, fie cand este selectat unul din campurile de text si se apasa tasta <Enter>. Daca se introduc date gresite, nu se traseaza functia, ci apare un mesaj de eroare */

Page 286: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

286

import java.awt.*; import java.awt.event.*; import javax.swing.*;

class GraficeFunctii { static Actiuni act=new Actiuni(); static Functii fct=new Functii(); static Grafic gr=new Grafic(); static Label mesaj=new Label(); static boolean trasare=false; static int nrPasi=200; // numarul de subintervale static int nrNoduri=nrPasi+1; // numarul de puncte ale graficului static int indFunc; // indicele functiei care se reprezinta grafic // Tabele de coordonate ale punctelor graficului functiei static int x[]=new int[nrNoduri], y[]=new int[nrNoduri]; // inaltimea si latimea suprafetei de desenare si pozitiile axelor static int inaltime, latime, xord, yabsc;

public static void main(String args[]) { JFrame fp=new JFrame("Grafice de functii"); Container cp=fp.getContentPane(); cp.add(fct,"North"); cp.add(gr,"Center"); gr.setBackground(Color.cyan); cp.add(mesaj,"South"); mesaj.setBackground(Color.green); fp.addWindowListener(act); fp.setSize(500,500); fp.setVisible(true); }

// Introducerea datelor si calcularea coordonatelor

static class Functii extends JPanel { // Componenta de selectare a functiei JLabel lab=new JLabel("Alegeti functia de reprezentat"); Choice f=new Choice(); // Campurile de text pentru introducerea marginilor intervalului // si numarului de subintervale JTextField inf=new JTextField("-6.28"); JTextField sup=new JTextField("6.28"); JTextField pasi=new JTextField("200");

// Constructorul clasei Functii Functii() { // Adaugarea de functii la lista de optiuni f.add("x^2"); f.add("x^3"); f.add("log(1+x^2)-1"); f.add("sin(x)"); f.add("cos(x)"); f.add("exp(-abs(0.1*x))*cos(x)"); f.add("cos(x)/sqrt(1+x*x)"); // Setarea gestionarului de pozitionare setLayout(new GridLayout(4,2)); // Adaugarea componentelor

Page 287: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

287

add(new Label("Alegeti functia de reprezentat: ")); add(f); add(new Label("Marginea inferioara a intervalului: ")); add(inf); add(new Label("Marginea superioara a intervalului: ")); add(sup); add(new Label("Numarul de subintervale pentru trasare: ")); add(pasi); // Adaugarea la componente a interceptorului de evenimente inf.addActionListener(act); sup.addActionListener(act); pasi.addActionListener(act); f.addItemListener(act); }

// Calcularea valorii functiei in punctul de abscisa x double func(double x) { switch(indFunc) { case 0: return x*x; case 1: return x*x*x; case 2: return Math.log(1+x*x)-1; case 3: return Math.sin(x); case 4: return Math.cos(x); case 5: return Math.exp(-Math.abs(0.1*x))*Math.cos(x); case 6: return Math.cos(x)/Math.sqrt(1.0+x*x); } return 0.0; }

}

// Captarea si tratarea evenimentelor static class Actiuni extends WindowAdapter implements ActionListener, ItemListener {

public void windowClosing(WindowEvent e) { System.exit(0); } public void actionPerformed(ActionEvent e) { reprezinta(); } public void itemStateChanged(ItemEvent e) { reprezinta(); } public void reprezinta() { try { calcul();//Se calculeaza coordonatele punctelor graficului gr.repaint();//Se traseaza graficul functiei } catch(Exception e) { mesaj.setText("eroare: "+e); } } // Calcularea coordonatelor tuturor punctelor graficului void calcul() throws Exception { double xmin,xmax,ymin,ymax,pas,scarax,scaray; // Initializari mesaj.setText("");

Page 288: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

288

trasare=false; gr.repaint(); // Preluarea datelor introduse in campurile de text int nrP=Integer.parseInt(fct.pasi.getText()); if(nrP<1) throw new Exception("Numar de intervale incorect"); if(nrP != nrPasi) { nrPasi=nrP; nrNoduri=nrPasi+1; x=new int[nrNoduri]; y=new int[nrNoduri]; } xmin=Double.parseDouble(fct.inf.getText()); // marginea din stanga xmax=Double.parseDouble(fct.sup.getText()); // marginea din dreapta if(xmin==xmax) throw new Exception("xmin==xmax"); pas=(xmax-xmin)/nrPasi; // Lungimea subintervalului double valy[]=new double[nrNoduri];// tabloul ordonatelor // Preluarea indicelui functiei selectate indFunc=fct.f.getSelectedIndex(); // se afla indicele functiei // Determinarea dimensiunilor suprafetei de desenare inaltime=gr.getHeight(); // inaltimea suprafetei de desenare latime=gr.getWidth(); // latimea suprafetei de desenare // Calcularea ordonatelor punctelor graficului for (int i=0; i<nrNoduri; i++) valy[i]=fct.func(xmin+i*pas); // Determinarea valorilor minima si maxima ale lui y ymin=valy[0]; ymax=valy[0]; for (int i=1; i<nrNoduri; i++) { if(valy[i]>ymax) ymax=valy[i]; if(valy[i]<ymin) ymin=valy[i]; } // Determinarea scarilor de reprezentare pe cele doua directii scarax=latime/(xmax-xmin); scaray=inaltime/(ymax-ymin); // Calcularea coordonatelor de pe desen ale punctelor graficului for(int i=0; i<nrNoduri; i++) { y[i]=inaltime-(int)Math.round((valy[i]-ymin)*scaray); x[i]=(int)Math.round(i*pas*scarax); } // Determinarea pozitiilor pe desen ale axelor de coordonate yabsc=inaltime+(int)Math.round(ymin*scaray); xord=(int)Math.round(-xmin*scarax); trasare=true; } }

// Componenta pe care se traseaza desenul static class Grafic extends Canvas { // Metoda de trasare a graficului public void paint(Graphics g) { if(!trasare) return; // Trasarea axelor de coordonate g.setColor(Color.blue); if(yabsc>=0 && yabsc<=inaltime) g.drawLine(0,yabsc,latime,yabsc); if(xord>=0 && xord<=latime) g.drawLine(xord,0,xord,inaltime); // Trasarea curbei (sub forma de linie franta) g.setColor(Color.red); g.drawPolyline(x,y,nrNoduri); }

Page 289: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

289

} }

Întrebări

Nivel 1

1. Ce sunt ferestrele de dialog?

2. Ce deosebire există între ferestrele de dialog modale şi cele nemodale?

3. Ce sunt ferestrele de dialog standard?

4. Cum se creeaza ferestrele de dialog standard?

5. Cum se stabileşte culoarea de fond a unei componente?

6. Ce este culoarea de prim plan a unei componente şi prin ce metodă se modifică?

7. Ce sunt instanţele clasei Color?

8. Care este principalul model de culori folosit în Java?

9. Prin ce tip de date se exprimă culorile în sistemul RGB şi care este intervalul în care

acestea iau valori?

10. Care este culoarea pentru care cele trei culori fundamentale RGB au valoarea 0?

11. Care este culoarea pentru care toate cele trei culori fundamentale au valoarea 255?

12. La ce foloseşte clasa JColorChooser?

13. Pe ce fel de componente se poate face desenarea?

14. Care este sistemul de coordonate pentru reprezentări grafice?

15. Care este unitatea de măsură folosită pe axele de coordonate pentru reprezentări

grafice?

16. Ce este contextul grafic?

17. Prin ce clasă abstractă este reprezentat contextul grafic în Java API?

18. În ce clasă este declarată metoda paint şi ce rol are ea?

19. Cum este invocată metoda paint?

20. În ce scop este redefinită metoda paint?

21. Ce trebuie să conţină corpul metodei paint pentru a se trasa un desen?

22. La ce foloseşte metoda repaint?

23. Se redefineste în program metoda repaint?

Nivel 2

1. Prin ce clasă se realizează ferestrele de dialog în JFC/Swing?

2. Ce relaţie există între fereastra de dialog şi proprietarul ei?

3. Prin ce metodă se afişează pe ecran o fereastră de dialog?

4. Prin ce metode se închide o fereastră de dialog?

5. Care tipuri de ferestre pot fi create folosind metodele clasei JOptionPane?

6. Ce conţine o fereastră de dialog de mesaj?

7. Ce conţine o fereastră de dialog de confirmare?

8. Ce conţine o fereastră de dialog de intrare şi cum este ea utilizată?

9. Ce este modelul HSB?

10. Prin ce tip de date se exprimă componentele modelului HSB şi în ce interval de

valori?

Page 290: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

290

11. Pentru ce fel de culori HSB saturaţia are valoarea 0.0?

12. Cum se creează o instanţă a clasei JColorChooser?

13. Cum poate fi afişat un JColorChooser sub formă de fereastră de dialog?

14. Ce modele de culori se folosesc în JColorChooser?

15. Ce câmpuri conţine un obiect al clasei Graphics?

16. Ce fel de metode conţine clasa Graphics?

17. Unde se plasează în program redefinirea metodei paint?

Page 291: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

291

Introducere în HTML. Crearea şi utilizarea

appleturilor

Introducere în HTML 291

Ce este un hipertext

Ce este WWW

Ce este HTML

Ctructura documentului HTML

Carcaje de formatare a textului folosite frecvent

Legaturi catre alte pagini

Marcajul APPLET

Utilizarea marcajelor HTML în textele introduse în

componentele JFC/Swing

Applet-uri

Clasa Applet

întrebări.

Introducere în HTML

Deşi prezentarea limbajului HTML nu constituie un obiectiv al acestui manual, vom da aici

unele noţiuni introductive asupra acestui limbaj, fiind utile pentru o mai bună înţelegere a

utilizării appleturilor.

Ce este un hipertext

Hipertextul (engleză: hypertext) este o colecţie de documente, numite şi noduri sau pagini,

unite între ele prin legăturica în Figura 1.

Page 292: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

292

- Figura 1 -

Este necesar, desigur, să se adopte o convenţie privind modul în care se însereaza în pagina

de hipertext legăturile către alte pagini. Pentru utilizatorul care vede pe ecran pagina

respectivă, această legătură apare, de regulă, sub forma unui cuvânt sau unui grup de cuvinte

puse în evidenţă prin subliniere, colorare sau prin ambele procedee. Dacă se face click cu

mouse-ul pe o astfel de "legătura", pagina curentă se schimbă cu pagina către care indică

legătura respectivă. Citirea unui asemenea hipertext nu se face cu un editor de texte obişnuit,

ci cu un program special numit navigator sau browser.

Paginile (nodurile) hipertextului sunt stocate sub forma de fişiere, situate pe un singur

calculator, sau pe mai multe calculatoare legate în reţea.

Ce este WWW

World-Wide Web (WWW) este un sistem de regăsire a informaţiei distribuite pe Internet. În

limba engleză, web înseamnă "plasa", "reţea", "pânză de păianjen", ceeace sugerează

legaturile existente între noduri într-un hipertext. Asadar, WWW este o astfel de "pânză de

păianjen" care acopera întreaga lume şi ale cărei noduri sunt documente.

Documentele sunt stocate sub formă de fişiere pe diferite calculatoare, care acţioneaza ca

servere de web. Utilizatorul poate naviga pe această reţea, folosind un program numit

browser de web (navigator). Cele mai răspândite browsere de web sunt, în prezent, Netscape

Navigator şi Internet Explorer. Putem deci considera că WWW este perceput de utilizator ca

un hipertext, ale cărui noduri sunt raspândite în întreaga lume. Transmiterea prin Internet a

paginilor WWW se face folosind un protocol special, numit HTTP (Hypertext Transfer

Protocol), iar pentru marcarea paginilor de WWW, cu scopul de a însera în ele legăturile

necesare, se foloseşte un limbaj numit HTML.

Ce este HTML

HyperText Markup Language (HTML) este un limbaj de marcare a hipertextelor. În estenţă,

o pagină HTML este un fişier de text ASCII, care conţine nişte simboluri speciale, numite

marcaje sau taguri. Prin aceste marcaje se indică legăturile către alte documente şi către

Page 293: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

293

appleturi, imagini sau secvenţe audio incluse în document, dându-se, de asemenea, informaţii

privind formatarea documentului şi altele.

Fiecare marcaj (tag) este de forma <tag> ... </tag>, deci începe printr-un nume de marcaj

(tag) cuprins între paranteze unghiulare şi se termină prin acelaşi marcaj, având în faţa

numelui simbolul / (slash). Astfel, fiecare document HTML începe cu marcajul <html> şi se

termină cu </html>. În limbajul HTML nu se face distincţie în marcaje între literele mari şi

cele mici, deci tagul <HTML> ... </HTML> este echivalent cu tagul <html> ... </html>.

Aceste marcaje pot fi cuprinse unul în altul, ca în Figura 2.a, dar nu este permis ca

domeniile lor să se intersecteze, ca în Figura 2.b.

- Figura 2 -

Pentru crearea de documente HTML se poate folosi un editor de text simplu, în mod ASCII,

dar - în acest caz - cel care creează documentul trebuie să cunoască bine sintaxa HTML şi

toate tagurile acestuia. Mult mai comoda este folosirea unor editoare speciale de pagini Web,

cum sunt Netscape Composer sau Front Page, care prezintă interfaţă utilizator grafică, iar pe

ecran se vede documentul sub forma în care acesta apare şi in browser.

Structura documentului HTML

Un document HTML are urmatoarea structură:

<HTML>

<HEAD>

Antetul documentului

</HEAD>

<BODY>

Corpul documentului

</BODY>

</HTML>

Modul de punere în pagină nu are importanţă, deoarece întreaga informaţie despre structură şi

formatare este conţinuta în marcaje (taguri). Acelaşi document poate fi pus în pagina, de

exemplu, astfel:

<HTML><HEAD>Antetul documentului </HEAD><BODY>Corpul documentului

</BODY></HTML>

Antetul documentului conţine, opţional, titlul acestuia şi informaţii despre autor, tipul de

document etc. O componentă importantă a antetului este titlul documentului, care are forma:

Page 294: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

294

<TITLE>Titlul documentului</TITLE>

Titlul este un text, care apare în bara de titlu a browserului care vizualizează documentul

respectiv.

Corpul documentului este documentul propriu-zis, care se afişează pe ecran, inclusiv

legăturile conţinute în documentul respectiv.

Marcaje de formatare a textului folosite frecvent

Marcarea paragrafelor

Fiecare paragraf este cuprins între marcajele <P> .. </P>. Totusi, folosirea marcajului de

sfârşit de paragraf </P> nu este obligatorie. Atunci când documentul este vizualizat în

browser, fiecare paragraf începe de la capăt de linie. În interiorul paragrafului, trecerea la

linie nouă se face automat, când se ajunge la marginea din dreapta a paginii. Se poate, totuşi,

forţa trecerea la linie nouă prin marcajul <br> (prescurtare de la break).

În marcajul <P> se pot introduce şi indicaţii privind culoarea de fond, culoarea caracterelor

şi forma caracterelor din paragraful respectiv. Aceste indicaţii se dau prin parametri de forma

nume=valoare.

Culoarea caracterelor se indică prin parametrul color=culoare, unde culoare poate fi:

black (negru), gray (gri), silver (argintiu), white (alb), red (rosu), green (verde), blue

(albastru), yellow (galben), lime (verde deschis), aqua (albastru deschis), fuchsia (roz),

purple (purpuriu), maroon (maron), olive (oliv), navy (bleu marin), teal (verde inchis).

Remarcăm că sunt alte nume de culori decât cele din clasa java.awt.Color.

Culoarea fondului se indică prin parametrul bgcolor=culoare, unde numele culorilor sunt

aceleaşi ca pentru caractere.

Forma caracterelor cu care este scris paragraful este indicată prin parametrul face=forma.

În funcţie de platformă, se pot folosi diferite forme de caractere. Există, totuşi, trei forme care

sunt disponibile pe orice platformă: Serif, sansSerif si Monospace. Primele două au caractere

de lăţime variabilă (de exemplu, m este mai lat decat i), iar ultimul are toate caracterele de

aceeasi lăţime (exemplu: în cuvantul lăţime, scris cu astfel de caractere, m şi i au aceeaşi

lăţime). Deosebirea între Serif şi SansSerif este prezentă, respectiv absenţa serifurilor.

Acestea sunt liniuţele mici care delimitează unele linii ale literelor, cum se poate observa

comparând caracterele din cuvintele de mai jos:

Serif SansSerif

Indicarea fontului

Se numeşte font tipul de literă folosit într-un text. Termenul este preluat din tipografie şi se

referă la reprezentarea formei şi mărimii unui caracter. S-a menţionat mai sus cum pot fi

indicate forma şi culoarea caracterelor dintr-un paragraf ca parametri în marcajul <P>. Exista

însă şi situaţii în care un anumit font se foloseşte numai într-o porţiune de paragraf, sau se

extinde pe mai multe paragrafe. În acest scop, se foloseşte marcajul <font parametri>

text</font>.

Parametrii din marcajul <font > sunt face=formă, color=culoare şi size=mărime. Forma

şi culoarea se indică în acelaşi mod ca în marcajul <P>. Mărimea este un număr întreg cu sau

Page 295: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

295

fără semn. Dacă se foloseşte un număr întreg fără semn, acesta indică mărimea absolută a

fontului. Mărimea indicată ca numar intreg cu semn în intervalul [-3, +3] arată mărimea

relativă, faţă de cea pentru care este setat browserul utilizat. Aşa dar, de exemplu, parametrii

size=3 si size=+3 indică fonturi de mărimi diferite.

Exemplu

Textul HTML următor: <font face=serif color=purple size=+1> proba de text </font>

va apare scris pe ecran sub forma

proba de text

Nu este obligatoriu să se indice toţi cei trei parametri. Se folosesc numai cei prin care noul

font diferă de cel anterior.

Indicarea stilului

În afară de forma, marimea şi culoarea fontului, textul se caracterizează şi prin stil: păstrând

forma fontului, textul poate să apară îngroşat, cursiv, subliniat etc. În HTML, stilul textului se

indică prin marcaje speciale:

<B> ... </B> pentru text aldin, îngrosat (engleză: bold);

<I> ... </I> pentru text cursiv (engleză: italic);

<U> ... </U> pentru text subliniat (engleză: underline);

<strike> ... </strike> pentru text tăiat cu o linie (engleză: strikethrough);

<sub> ... </sub> text scris mai mic şi mai jos decât textul de bază (engleză: subscript);

<sup> ... </sup> text scris mai mic şi mai sus decât cel de bază (engleză: superscript

).

Aceste stiluri pot fi şi combinate. De exemplu, textul HTML <B><I><U>text aldin, cursiv şi subliniat</U></I></B> apare pe ecran sub forma:

text aldin, cursiv şi subliniat

Marcarea titlurilor şi subtitlurilor

Titlurile diferitelor secţiuni ale textului (capitole, subcapitole etc) se pun în evidenţă prin

faptul că apar scrise cu caractere diferite de restul textului (de regulă mai mari) şi sunt

distanţate prin câte o linie atât de textul de deasupra, cât şi prin cel de dedesubt. Pentru

marcarea titlurilor se foloseşte marcajul <Hn>titlu</Hn> în care n este un număr întreg

cuprins în intervalul [1, 6]. Cu cât cifra n este mai mare, titlul respectiv se afişează scris cu

caractere mai mici. De exemplu, textul HTML <H1>Primul titlu></H1><H2>Al doilea titlu</H2><H3>Al treilea titlu</H3> apare pe ecran sub forma

Primul titlu

Al doilea titlu

Al treilea titlu

Se poate astfel continua până la marcajul <H6>.

Page 296: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

296

Text preformatat

S-a arătat mai sus că aşezarea textului în pagină se face de către browser, respectând

marcajele de formatare din textul HTML. În consecinţă, dacă se modifică dimensiunile

ferestrei, se modifica şi aşezarea în pagină a textului. Spaţiile şi caracterele speciale din textul

HTML, cum sunt caracterul de trecere la linie nouă sau de întoarcere a carului sunt ignorate

de browser şi nu au efect la afişarea pe ecran. Există, totuşi un marcaj care impune ca textul

sa fie aşezat pe ecran aşa cum este el în pagina HTML. Acest marcaj este <PRE> text

preformatat </PRE>. De exemplu, textul <PRE> un exemplu de text preformatat scris pe trei linii </PRE>

va apare pe ecran sub forma un exemplu de text

preformatat

scris pe trei linii

Legături către alte pagini

Legăturile cu alte documente sunt marcate prin ancore, care sunt taguri de forma:

<A HREF="referinţă la document">text de legătură</A>

Parametrul HREF (Hypertext Reference) reprezintă indicarea locului în care poate fi găsit

documentul către care se face trimiterea (referinţa la document). Această referinţă nu este

vizibilă în fereastra de browser în care este afişat documentul. În schimb, este vizibil textul de

legătură, sub forma unui text subliniat şi având o culoare diferită de a restului documentului.

Referinţa la document depinde de locul în care acesta se găseşte.

a/ Documentul ţintă se găseşte pe acelasi calculator. În acest caz, referinţa poate fi:

a1/ Referinţa absolută, de forma:

cale/document

unde cale (engleza: path) este succesiunea de directoare parcurse de la rădăcina

arborelui de directoare, până la directorul în care se găseşte fişierul care conţine documentul;

pentru separarea directoarelor se foloseşte bara (slash, /), conform convenţiei din sistemul de

operare Unix. De exemplu: "C:/d1/d2/d3/docum.html"

este o referinţă la documentul docum.html, care se găseşte pe discul C, urmând calea

d1/d2/d3/ unde d1, d2 si d3 sunt directoare. Dacă documentul ţintă se găseşte pe acelaşi disc

cu documentul în care apare această referinţă, discul poate fi omis, punând referinţa sub

forma "/d1/d2/d3/docum.html" dar având grijă să înceapă cu "/", ceeace înseamnă că se porneşte de la rădăcină, deci este o

referinţă absolută.

a2/ Referinţa relativă, în care calea se trasează pornind de la directorul în care se

găseşte documentul sursă.La indicarea căii, simbolul .. (doua puncte succesive) înseamnă

deplasare cu un director înapoi, iar / înseamna deplasare cu un director înainte. De exemplu,

referinţa: "../../d2/d3/docum.html" are semnificaţia următoare: pornind de la directorul în care se găseşte documentul sursă, ne

deplasăm două directoare "înapoi" către rădacină, după care parcurgem "înainte" calea d2/d3

şi ajungem la documentul docum.html.

b/ Documentul ţintă se găseşte pe un alt calculator. În acest caz, referinţa la document este

Page 297: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

297

un URL (engleză: Uniform Resource Locator), care este modul de adresare caracteristic

pentru WWW. Iată exemple de URL-uri: "http://www.w3.org/default.html" "http://java.sun.com/docs/books/jls/html/index.html" "http://lib.cs.ugal.ro/~sbumbaru/CursJava/Sapt01/poo.html" Prima parte a URL-ului (în cazul de faţă http:) reprezintă protocolul de transmisie folosit.

Cele două bare (//) indică modul de acces (în cazul de faţă - adresa pe Internet a unui

calculator, de exemplu java.sun.com). Urmeaza calea absolută parcursă pe calculatorul

respectiv (de exemplu /docs/books/jls/html/) şi numele documentului (index.html).

Modul de adresare pe Internet este, în principiu, următorul: Internetul este împărţit în

domenii, care pot fi domenii naţionale (de exemplu: ro - Romania, fr - Franta, uk - Marea

Britanie, de - Germania etc) sau domenii profesionale (com - comercial, edu - educaţional,

org - organizaţii, net - retele). Fiecare domeniu este imparţit în subdomenii (de ex.: în

domeniul ro există subdomeniul ugal - Universitatea din Galati, iar în domeniul com există

subdomeniul sun - firma Sun Microsystems). Subdomeniile pot fi împărţite în sub-

subdomenii s.a.m.d până se ajunge la calculatoare individuale. De exemplu, locaţia

atlas.stud.ugal.ro înseamnă calculatorul atlas din subreţeaua stud, din subdomeniul ugal al

domeniului ro.

Marcajul APPLET

Pentru a introduce într-un document HTML o referinţă la un applet, se foloseşte marcajul

(tagul) APPLET, care are forma următoare:

<APPLET CODE=fişier_class [CODEBASE=localizare] WIDTH=lăţime

HIGHT=înălţime[ALIGN=aliniere]>

[<PARAM NAME=nume VALUE=valoare>]* [text_de_înlocuire] </APPLET>

în care:

fişier_class - fişierul cu extensia .class, în care se află bytecode-ul appletului (indicarea

extensiei nu este obligatorie), de exemplu:

CODE=TestFlowAp.class sau CODE=TestFlowAp

localizare - referinţa la directorul în care se găseşte bytecode-ul appletului; această

referinţă poate fi absolută, relativă sau sub forma de URL, la fel ca în cazul legăturilor către

alte documente, cu observaţia că nu se mai termină prin numele documentului ţintă, acesta

fiind cel din parametrul CODE; dacă fişierul bytecode al appletului se găseşte în acelaşi

director cu fişierul HTML în care acesta este invocat, parametrul CODEBASE lipseşte;

lăţime si înălţime - numere întregi, reprezentând lăţimea şi înălţimea appletului;

aliniere - alinierea appletului în pagina de browser, poate fi una din următoarele:

left | right | top | texttop | middle | absmiddle | baseline | bottom | absbottom

unde left şi right indică aliniere la stânga sau la dreapta, top - aliniere cu elementul cel

mai înalt din linie (fie el text, imagine sau alt applet), texttop - aliniere cu cel mai înalt

element de text din linia respectivă, middle - mijlocul appletului se aliniază cu mijlocul liniei

de bază a textului, absmiddle - mijlocul appletului se aliniază cu mijlocul elementului cel mai

mare din linie, baseline sau bottom - baza appletului se aliniază cu linia de bază a textului,

absbottom - baza appletului va fi elementul cel mai de jos din linie.

text_de_înlocuire- un text care va apare în locul appletului, dacă browserul folosit pentru

vizualizarea documentului HTML nu este capabil sa utilizeze appleturi.

Page 298: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

298

Dacă este necesar, marcajul APPLET poate să conţină unul sau mai mulţi parametri, care

se vor transmite appletului la lansarea acestuia. Aceşti parametri apar în subtagul PARAM,

pentru fiecare din ei indicându-se un nume şi o valoare.

Exemplul 1: marcajul

<APPLET CODE="CBGroupAp" WIDTH=180 HEIGHT=80> Testarea clasei

CheckboxGroup </APPLET>

se foloseşte pentru a include în documentul HTML a unui applet, al cărui fişier de bytecode

este CBGroupAp.class şi se găseşte în acelasi director cu documentul HTML în care există

acest tag. Appletul va avea lăţimea 180 şi înălţimea 80. Dacă browserul folosit nu suportă

appleturi java, în locul rezervat appletului va apare textul de înlocuire "Testarea clasei

CheckboxGroup".

Exemplul 2: marcajul

<APPLET CODE=PrimApplet CODEBASE=../Sapt01/surse WIDTH=200

HEIGHT=100>Primul applet</APPLET>

se foloseşte pentru a include în documentul HTML appletul al cărui fişier bytecode este

PrimApplet.class şi care se găseşte în alt director decât fişierul HTML, dar pe acelaşi disc. În

CODEBASE s-a folosit forma relativa a căii.

Exemplul 3: marcajul

<APPLET CODE=PrimApplet CODEBASE=/CursJava/Sapt11/surse WIDTH=200

HEIGHT=100> Primul applet </APPLET>

are aceeaşi semnificaţie ca cel din exemplul anterior, dar în CODEBASE s-a folosit forma

absolută a căii.

Exemplul 4: marcajul

<APPLET CODE=PrimApplet

CODEBASE=http://lib.cs.ugal.ro/~sbumbaru/CursJava/Sapt11/surse WIDTH=200

HEIGHT=100> Primul applet </APPLET>

are aceeaşi semnificaţie ca cel din exemplul anterior, dar în CODEBASE se foloseşte un

URL la care poate fi găsit appletul respectiv.

Folosirea de parametri în appleturi

În marcajul APPLET pot fi introduşi şi unul sau mai mulţi parametri, folosind în acest scop

sub-marcajul

[<PARAM NAME=nume VALUE=valoare>]*

Atât numele, cât şi valoarea sunt şiruri. Preluarea în applet a fiecăruia din aceşti parametri se

face invocând metoda public String getParameter(String name) care primeşte ca argument numele parametrului şi întoarce valoarea acestuia sub forma de şir.

Avantajul este că valorile parametrilor pot fi modificate direct în fişierul HTML, fără să mai

Page 299: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

299

fie necesar să se modifice şi să se recompileze programul appletului.

Exemplu:

În fişierul DouaTexte.java este dat un exemplu de applet în care sunt preluaţi doi parametri,

cu numele textul1 si textul2. Aceşti parametri sunt şiruri de caractere, care se afişează

alternativ într-o etichetă. Schimbarea textului se face la apăsarea pe buton. Acest applet este

inclus în pagina HTML din fişierul DouaTexte.html prin următorul marcaj:

<APPLET CODE=DouaTexte WIDTH=250 HEIGHT=100 ALIGN=middle>

<PARAM NAME=textul1 VALUE="Acesta este primul text">

<PARAM NAME=textul2 VALUE="Acesta este al doilea text">

</APPLET>

Pentru a se afişa alte texte, este suficient să se modifice în mod corespunzător valorile

parametrilor din acest marcaj, fără a se face modificări în programul appletului.

Utilizarea marcajelor HTML în textele

pentru componentele JFC/Swing

În mod obişnuit, textul introdus în componentele AWT sau JFC/Swing prin metoda void

setText(String text) apare pe ecran pe suprafaţa componentei respective sub forma unui

text scris pe o singura linie, folosind fontul SansSherif, culoarea neagra şi o mărime implicită.

Începând cu platforma Java 2 (SDK 1.2) în textele introduse în componentele JFC/Swing

(cum ar fi cele din clasele JButton, JLabel, JPanel etc.) pot fi folosite marcaje HTML. Dacă

textul introdus prin metoda setText() începe cu marcajul <HTML>, el este interpretat ca un

text HTML şi tratat în mod corespunzător. Aceasta înseamnă că textul poate să apară pe

suprafaţa componentei respective pe mai multe linii, să aibă diferite fonturi, culori şi stiluri,

conform cu marcajele HTML utilizate. Dacă, însă, sintaxa HTML nu este respectată, metoda

generează o excepţie.

Exemplu

În fişierul TextHTML.java este dat un exemplu de aplicaţie, în care se experimentează

folosirea textelor HTML în componentele interfeţei grafice. În fereastra aplicaţiei sunt plasate

următoarele componente:

- o arie de text (JTextArea), în care se afişează un text iniţial, care poate fi apoi modificat de

utilizator;

- o etichetă (JLabel) pe suprafaţa căreia se afişează textul existent în aria de text din partea

stângă;

- un buton cu inscripţia Vizualizare text, a cărui acţionare are ca efect afişarea pe suprafaţa

etichetei a textului din aria de text;

- un al doilea buton, cu inscripţia Reset, a cărui acţionare are ca efect revenirea la textul

Page 300: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

300

afişat iniţial în aria de text.

Înscripţiile de pe cele două butoane au fost formatate folosind marcaje HTML.

În aria de text este introdus iniţial un text HTML, care poate fi vizualizat apăsând pe butonul

Vizualizare text. Acest text poate fi însă modificat în fereastra din stânga şi vizualizat în

eticheta din dreapta, apăsând pe acelaşi buton. Dacă se doreşte, apoi, revenirea la textul

iniţial, se apasă butonul Reset.

Se pot experimenta, astfel, diferite modificări ale textului iniţial sau se poate introduce

oricând un text obişnuit sau un hipertext nou.

/* Experimentarea folosirii marcajelor HTML in textele pentru componente JFC/Swing */

import java.awt.*; import java.awt.event.*; import javax.swing.*;

class TextHTML extends JFrame { JTextArea ta; JLabel label; Sfarsit sfarsit; /* Textul introdus initial in aria de text */ String textInitial="<html>\n<h2>Proba HTML</h2>Text normal<br>\n"+ "<i>Text italic <b>Text italic aldin</b></i><br>\n"+ " <font face=serif color=blue size=4>\n"+ " Text albastru cu font serif\n </font>\n<p bgcolor=aqua>"+ "Revenire la text normal<br>cu fond aqua\n</html>";

/* Constructorul clasei TextHTML construieste interfata grafica */ TextHTML() { super("Incercare de texte HTML"); Container cp=getContentPane(); sfarsit=new Sfarsit(); // incheierea executarii aplicatiei addWindowListener(sfarsit); ta=new JTextArea(15,10); // aria in care se introduce textul HTML ta.setLineWrap(true); ta.setWrapStyleWord(true); ta.append(textInitial); ta.setBorder(BorderFactory.createTitledBorder( "Introduceti aici un text HTML")); Box vb=Box.createVerticalBox(); Box hb=Box.createHorizontalBox(); vb.add(ta); String textButon="<html><font color=red size=4>"+ "<b><i>Vizualizare text</i></b></font>"; JButton buton=new JButton(textButon); // butonul de comanda a // vizualizarii textului

buton.addActionListener(new Vizualizare()); buton.setBorder(BorderFactory.createRaisedBevelBorder()); hb.add(buton); JButton reset=new JButton("<html><font color=blue size=4>"+ "<b>Reset</b></font>"); // butonul de revenire la textul initial reset.setBorder(BorderFactory.createRaisedBevelBorder()); reset.addActionListener(new Reset()); hb.add(reset); vb.add(hb);

Page 301: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

301

cp.add(vb,BorderLayout.WEST); label=new JLabel(); // eticheta pe care se vizualizeaza textul HTML label.setBorder(BorderFactory.createTitledBorder( "Vizualizarea textului HTML")); label.setOpaque(true); label.setBackground(Color.white); cp.add(label,BorderLayout.CENTER); setLocation(50,50); setSize(450,300); setVisible(true); }

/* Clasa de ascultare a inchiderii ferestrei principale*/ class Sfarsit extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } }

/* clasa de ascultare a butonului de vizualizare a textului */ class Vizualizare implements ActionListener { public void actionPerformed(ActionEvent e) { try { /* afisarea pe componenta label a textului extras din aria de text ta */ label.setText(ta.getText()); } catch(Exception ex) { // s-a constatat o eroare in textul HTML label.setText("Eroare de sintaxa HTML"); } } }

/* Clasa de ascultare a butonului de Reset */ class Reset implements ActionListener { public void actionPerformed(ActionEvent e) { ta.setText(textInitial); label.setText(""); } }

public static void main(String args[]) { TextHTML text=new TextHTML(); // instantierea aplicatiei } }

Remarcăm că, în această aplicaţie, s-au introdus următoarele abordări noi faţă de aplicaţiile

anterioare:

- s-a considerat că interfaţa grafică este însăşi clasa principala TextHTML, derivata din clasa

JFrame. În consecinţă, adăugarea componentelor la fereastra principală se face în

constructorul clasei TextHTML;

- clasele interioare şi câmpurile clasei TextHTML nu au mai fost declarate statice, în

schimb, în metoda main() s-a creat o instanţă a acestei clase.

Desigur că acest mod de construire a aplicaţiei nu are legătura cu tema acesteia, fiind doar o

ilustrare a unui alt mod de lucru posibil în Java.

Page 302: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

302

Applet-uri

Miniaplicaţia (engleză: applet) este un mic program cu interfaţă utilizator grafică, care nu

poate rula în mod independent, ci este înglobat într-o altă aplicaţie, numită context de applet.

Pentru executarea unui applet trebuie să existe deci două entităţi: applet-ul propriu-zis şi

contextul în care acesta se execută (engleză: applet context). În mod normal, contextul de

executare a unui applet este un navigator de Web (engleză: web browser), cum sunt Netscape

Navigator, Internet Explorer sau HotJava. Pentru testare, appletul poate fi executat, de

asemenea, folosind drept context un program de vizualizare special, existent in SDK, numit

appletviewer.

Orice applet este realizat ca o clasă, derivată din clasa Applet, existentă în pachetul

java.applet, sau derivată din clasa JApplet, care extinde clasa Applet şi există în pachetul

javax.swing.

Întrucât utilizarea clasei JApplet este mai complicată, ne vom rezuma aici la descrierea şi

exemplificarea utilizării clasei Applet.

Clasa Applet

Clasa Applet se găseşte în pachetul java.applet şi este o subclasă a clasei Panel din

pachetul java.awt. În consecinţă, applet-ul este, de fapt, un caz special de container.

Clasa Applet este superclasa tuturor miniaplicaţiilor care sunt încorporate în pagini Web sau

pot fi vizualizate cu un Java Applet Viewer.

Clasa Applet moşteneşte metodele superclaselor sale Component, Container şi Panel, oferind

şi metode specifice. Dintre acestea, cele mai importante sunt : init(), start(), stop() şi

destroy(). Aceste metode sunt apelate de către browser în momentele importante ale

ciclului de viaţă al unui applet, respectiv în momentul încărcării acestuia în memorie, în

momentul începerii sau întreruperii execuţiei şi înainte ca appletul să fie distrus. Aşa cum

sunt ele oferite de clasa Applet, aceste metode nu fac nimic. Ele pot fi însă redefinite de

programatori în subclasele clasei Applet, astfel încât să execute anumite acţiuni specifice

momentelor în care sunt invocate. Metoda init() este utilizată pentru a crea partea "statică"

a applet-ului: adăugarea de componente la applet, înregistrarea ascultătorilor de evenimente

etc. Ea este redefinită în marea majoritate a applet-urilor. Metodele start() şi stop() se

folosesc numai pentru lansarea şi oprirea proceselor dinamice (de exemplu animaţie şi/sau

sunete) care nu trebuie să continuie când appletul nu este vizibil pe ecran. În fine, metoda

destroy() se foloseşte în special pentru a distruge firele de execuţie paralele care au fost

create de către applet, sau a elibera anumite resurse ocupate de acesta.

Principalele metode ale clasei Applet:

Vom prezenta aici metodele mai frecvent utilizate. Pentru celelalte recomandăm consultarea

documentaţiei originale.

public void init() - metoda este invocată de către browser sau appletviewer atunci

Page 303: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

303

când appletul este încărcat în memorie, deci înainte de prima invocare a metodei start();

public void start() - metoda este invocată de către browser atunci când appletul

trebuie să îşi înceapă execuţia, adică atunci când este vizitată sau revizitată pagina Web în

care acesta este inclus;

public void stop() - metoda este invocată de către browser atunci când pagina de

Web, în care se găseşte appletul, este înlocuită de alta, fără a fi însă eliminată din memorie.

Întrucât appletul nu mai este vizibil pe ecran, acesta poate sa îşi înceteze temporar execuţia;

metoda este invocată, de asemenea, înaintea invocării metodei destroy();

public void destroy() - metoda este invocată de către browser înainte de

distrugerea appletului;

public boolean isActive() - determină dacă appletul este activ;

public String getAppletInfo() - dacă este redefinită în subclase, metoda poate

intoarce informaţii despre applet: autorul, versiunea, drepturi de autor etc. În clasa Applet

metoda întoarce null;

public AppletContext getAppletContext() - întoarce o referinţă către contextul

appletului;

public URL getCodeBase() - întoarce URL-ul (locaţia pe Internet) la care se găseşte

bytecode-ul appletului;

public URL getDocumentBase() - întoarce URL-ul la care se găseşte documentul

care conţine appletul;

public String getParameter(String name) - întoarce valoarea parametrului cu

numele dat ca argument, conţinut în tagul APPLET al documentului HTML.

Dăm în continuare trei exemple de applet-uri, împreună cu fişierele HTML în care se afişeaza

acestea. Pentru compatibilitate, s-au utilizat numai componente din pachetele java.applet şi

java.awt.

Exemplul 1:

În introducere a fost deja dat un exemplu de applet simplu, în care nu se redefineşte nici o

metodă a clasei Applet, folosindu-se numai o invocare de metodă prin care se scrie un text pe

suprafaţa appletului. Programul acestui applet se găseşte în fişierul PrimApplet.java, iar

fişierul HTML în care este folosit acest applet este PrimApplet.html.

Exemplul 2:

În fişierul CBGroupAp.java este dat un applet de testare a unui grup de casete de validare

(butoane radio) din fişierul TestCheckboxGroup.java. Remarcăm următoarele deosebiri faţă

de o aplicaţie similară:

- nu mai există o fereastră principală sub formă de cadru (Frame sau JFrame) ca în cazul

aplicaţiei, acest rol fiind îndeplinit chiar de către applet;

- în consecinţă, nu mai este necesară o clasă care sa intercepteze evenimentele generate de

fereastra principală;

- adăugarea componentelor la applet, setarea culorilor şi înregistrarea interceptorului de

evenimente, care în cazul aplicaţiei se fac în metoda main() sau în constructorul interfeţei

utilizator grafice, acum se fac în metoda init();

- având în vedere că, pentru clasa Applet, gestionarul de poziţionare implicit este

Page 304: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

304

FlowLayout, pentru a utiliza gestionarul BorderLayout acesta a trebuit adăugat în mod

explicit.

Pentru vizualizarea appletului se foloseste fişierul CBGroupAp.html.

Exemplul 3:

În fişierul TestFlowAp.java se prezintă un applet de testare a gestionarului de poziţionare

FlowLayout. Vizualizarea din browser a acestui applet se face folosind fişierul

TestFlow.html. Pe suprafaţa appletului apar două butoane de comandă ("Pune" şi "Elimina")

pentru adaugarea sau eliminarea de etichete şi trei butoane radio, prin care se selectează

modul de aliniere a etichetelor pe suprafaţa containerului ("Stânga", "Centru", "Dreapta").

Acţionand aceste butoane se poate testa modul de aranjare al etichetelor pentru diferite tipuri

de aliniere.

Oricare din aceste applet-uri poate fi vizionat şi într-un appletviewer, dacă (din fereastra X-

window sau MS-DOS) se dă comanda: appletviewer fisierHTML

De exemplu, pentru a vizualiza applet-ul TestFlowAp, se dă comanda appletviewer TestFlow.html unde TestFlow.html este fişierul HTML în care este invocat acest applet.

Întrebări

Nivel 1

1. Ce este un hipertext?

2. Ce sunt nodurile hipertextului?

3. Ce este WWW?

4. Ce este un browser de Web?

5. Ce este HTTP?

6. Ce este HTML?

7. Ce formă au marcajele HTML?

8. Care este marcajul cu care începe şi se termină un document HTML?

9. Care este structura unui document HTML?

10. În ce zonă a documentului HTML se specifică titlul acestuia?

11. Cum se specifică titlul unui document HTML?

12. Prin ce se marchează, într-un document HTML, legăturile către alte pagini ale

hipertextului?

13. La ce serveşte marcajul APPLET şi ce conţine el?

14. Cum sunt folosite marcajele HTML în componentele JFC/Swing?

15. Ce este un applet?

16. Ce clase se folosesc pentru realizarea applet-urilor?

17. Ce este un context de applet?

18. Ce contexte de applet cunoaşteţi?

19. Din ce clasă este derivată clasa Applet? dar clasa JApplet?

20. Care sunt principalele metode ale unui applet şi de către ce program sunt invocate ele?

21. La ce serveşte metoda init() în cazul unui applet?

22. Când sunt invocate metodele start() şi stop() ale unui applet?

23. În ce scop se foloseşte metoda destroy() a unui applet?

Page 305: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

305

24. Cum este utilizat un appletviewer?

Nivel 2

1. Cum se marchează paragrafele într-un document HTML?

2. Este absolut necesar ca un paragraf să se încheie cu marcajul </P>?

3. Cum se marchează într-un document HTML trecerea forţată la linie nouă?

4. Cum se specifică, într-un document HTML, culoarea fondului unui paragraf?

5. Cum se specifică culoarea caracterelor într-un document HTML?

6. Cum se specifică forma caracterelor într-un document HTML?

7. Care sunt principalele tipuri (forme) de caractere folosite în documentele HTML?

8. Ce conţine marcajul <font> şi ce semnificaţie are?

9. Ce este stilul textului?

10. Cum se marchează stilul textului într-un document HTML?

11. Cum se marcheaza titlurile şi subtitlurile de capitole într-un document HTML?

12. Ce este un text preformatat şi cum se marchează el într-un document HTML?

13. Cum se reprezinta, într-o legatură HTML, o referinţă absoluta la altă pagină de pe

acelaşi calculator?

14. Cum se reprezintă, într-o legatură HTML, o referinţă relativă la altă pagina de pe

acelaşi calculator?

15. Cum se reprezintă, într-o legatură HTML, o referinţă la o pagină situată pe alt

calculator de pe Internet?

16. Cum pot fi introduşi parametri în marcajul APPLET şi la ce folosesc?

17. Ce componente ale interfeţei grafice permit folosirea textelor HTML?

18. Prin ce metodă se introduce un text HTML într-o componentă JFC/Swing?

19. Ce se întamplă dacă, într-un text care se pune într-o componentă JFC/Swing, există o

eroare de sintaxa HTML?

20. Ce efect au metodele init(), start() şi stop() ale unui applet, aşa cum sunt ele

conţinute în clasa Applet?

21. Este obligatoriu ca, la crearea unei noi clase de applet, să fie redefinite toate cele patru

metode principale init(), start(), stop() şi destroy()?

Page 306: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

306

Fluxuri de intrare/ieşire şi fişiere

Fluxuri de intrare/ieşire 306

Introducere 306

Pachetul java.io 307

Clasele de bază ale ierarhiilor de fluxuri de

intrare/ieşire

310

Clasa Reader 310

Clasa Writer 311

Clasa InputStream 312

Clasa OutputStream 312

Consideraţii generale privind utilizarea

fluxurilor

313

Clasele PrintStream şi PrintWriter 313

Fişiere 315

Clasa File 316

Citirea fişierelor 319

Citirea fişierelor de octeţi: clasa

FileIntputStream

319

Citirea fişierelor de caractere: clasa FileReader 310

Scrierea în fişiere 322

Scrierea în fişiere de octeţi: clasa

FileOutputStream

322

Scrierea în fişiere de caractere: clasa FileWriter 323

Fişiere cu acces direct 324

Fluxuri de prelucrare 327

Fluxuri de date 327

Fluxuri de obiecte 329

Întrebări. 331

Fluxuri de intrare/ieşire şi fişiere

Introducere

În majoritatea aplicaţiilor, este necesar să se transmită date între diferite componente cum

sunt: memoria internă, tastatura, ecranul, fişierele de pe disc, reţeaua de calculatoare etc.

Poate fi necesar, de asemenea, să se transmită date între două aplicaţii sau între două fire de

execuţie ale aceleeaşi aplicaţii. În limbajul Java, fluxul (engleză: stream) este o cale de

comunicaţie între o sursă de date şi o destinaţie (Figura 1).

Page 307: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

307

- Figura 1 -

Fluxul este un concept situat pe un nivel înalt de abstractizare, fiind privit ca o simplă

succesiune de octeţi sau de caractere care se transmite între sursă şi destinaţie. Nu prezintă

importanţă nici natura sursei sau a destinaţiei, nici modul în care trebuie interpretată secvenţa

de octeti sau de caractere respectivă. De exemplu, un grup de 32 de octeţi transmişi între

sursă şi destinaţie poate să reprezinte 32 de caractere ASCII sau 16 caractere Unicode sau 8

numere de tip int sau 4 numere de tip double etc. Această abstractizare permite să se trateze

în mod unitar toate tipurile de transmisii de date.

Se disting doua feluri de fluxuri: de ieşire şi de intrare. Pentru un proces dat, toate fluxurile

transmise de acesta către exterior se numesc fluxuri de ieşire, iar cele primite din exterior se

numesc fluxuri de intrare. În consecinţă, acelaşi flux este de ieşire în raport cu sursa şi de

intrare în raport cu destinaţia.

Principalele operaţii care au loc asupra unui flux sunt:

La sursă (flux de ieşire) La destinaţie (flux de intrare)

- Deschiderea fluxului

- cât timp (există date de transmis)

scriere în flux

-Închiderea fluxului

-Deschiderea fluxului

- cât timp (există date de citit)

citire din flux

-Închiderea fluxului

Programatorului procesului sursă îi revine obligaţia de a pregăti, sub forma unei succesiuni de

caractere sau de octeţi, datele care urmează a fi transmise pe fluxul de ieşire. Interpretarea şi

tratarea datelor conţinute în flux se face de către procesul de destinaţie, deci întreaga

responsabilitate îi revine celui care programează acest proces. Desigur că este necesar ca

interpretarea datelor din flux la destinaţie să corespundă cu cea de la sursă. Programarea

operaţiilor de intrare/ieşire poate fi destul de complicată, dar în limbajul Java ea este totuşi

uşurată de existenţa unui număr destul de mare de clase cu această destinaţie, grupate în

pachetul java.io.

Pachetul java.io

În Java 2 SDK se consideră că fluxurile pot fi de caractere saude octeţi. În primul caz, de la

sursă la destinaţie se transmite o succesiune de caractere Unicode (de câte 16 biţi), iar în al

doilea caz - o succesiune de octeţi (de 8 biţi). În mod corespunzător, pentru fiecare din cele

două categorii de fluxuri există câte o ierarhie de clase de fluxuri de intrare şi o ierarhie de

clase de fluxuri de iesire. Pentru fluxurile de caractere, rădăcinile ierarhiilor de clase sunt

clasele abstracte Reader şi Writer.Pentru fluxurile de octeţi, rădăcinile acestor ierarhii sunt

clasele abstracte InputStream şi OutputStream. Aceste ierarhii de clase sunt reprezentate

în figurile 2, 3, 4 şi 5. În afară de cele patru ierarhii menţionate, în pachetul java.io există şi

clase auxiliare şi interfete. Distingem trei tipuri de clase, care sunt reprezentate în aceste

figuri prin culori diferite:

- clase abstracte (culoare albastră);

- clase care efectuează operaţiile de intrare sau de ieşire propriu-zise (culoare verde) şi

modelează sursele sau destinaţiile fluxurilor (engleză: Data Sink Streams);

Page 308: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

308

- clase care efectuează unele operaţii de transformare a datelor de pe flux (culoare violet) şi

reprezinta "fluxuri de prelucrare" (engleză: Processing Streams).

- Figura 2 - Ierarhia claselor pentru fluxuri de intrare de caractere

- Figura 3 - Ierarhia claselor pentru fluxuri de ieşire de caractere

Page 309: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

309

- Figura 4 - Ierarhia claselor pentru fluxuri de intrare de octeţi

- Figura 5 - Ierarhia claselor pentru fluxuri de ieşire de octeti

Se observă corespondenţa între clasele de fluxuri de intrare şi de ieşire în cadrul aceleeaşi

categorii de fluxuri. De exemplu, în cazul fluxurilor de caractere, unui BufferedReader îi

corespunde un BufferedWriter, unui CharArrayReader îi corespunde un CharArrayWriter etc.

În mod similar, în cazul fluxurilor de octeţi, unui FileInputStream îi corespunde un

FileOutputStream, unui PipedInputStream îi corespunde un PipedOutputStream etc. Aceasta

reflectă "simetria" operaţiilor de intrare şi de ieşire. Există totuşi şi clase de intrare fără

corespondent la ieşire (de exemplu StringBufferInputStream sau PushbackInputStream) sau

clase de ieşire fără corespondent la intrare (de exemplu PrintStream).

În JDK 1.0 existau numai clasele de fluxuri de octeţi. Fluxurile de caractere au fost introduse

începand cu JDK 1.1. În prezent se folosesc ambele categorii de fluxuri. Pentru transmiterea

textelor sau a datelor reprezentate în format extern şi codificate în Unicode este preferabil,

evident, să se folosească fluxuri de caractere. Pentru transmiterea datelor codificate binar sau

a textelor în care caracterele sunt codificate pe un octet (de exemplu în codul ASCII) este

preferabilă folosirea fluxurilor de octeţi.

Page 310: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

310

Fluxurile pot fi înlănţuite, astfel încât ieşirea unui flux poate fi intrare a altui flux. Astfel, în

Figura 6 este dată schema unei înlănţuiri de fluxuri de intrare: ieşirea fluxului InputStream

(sub forma de fluxului de octeţi flux1) este dată la intrarea fluxului InputStreamReader, care o

converteşte în fluxul de caracrtere flux2, iar acesta - la rândul lui - este preluat fe fluxul de

intrare de caractere cu zonă tampon BufferedReader.

- Figura 6- Înlănţuire de fluxuri de intrare

În Figura 7 este reprezentată o înlănţuire similară de fluxuri de ieşire: ieşirea fluxului de

caractere BufferedWriter este aplicată la intrarea fluxului OutputStreamWriter, iar acesta face

conversia într-un flux de octeţi, pe care îl transmite la un OutputStream (de exemplu la un

PrintStream sau la un FileOutputStream).

- Figura 7 - Înlănţuire de fluxuri de ieşire

Având în vedere complexitatea programării operaţiilor de intrare/ieşire, în cele ce urmează

vom căuta să facem o prezentare graduală, de la simplu la complex. Vom începe însă cu

prezentarea comparativă a claselor abstracte care constituie rădăcinile celor patru ierarhii de

clase de fluxuri. Aceasta ne va permite să ne formăm o vedere de ansamblu asupra

principalelor metode folosite în lucrul cu fluxuri.

Clasele de bază ale ierarhiilor de fluxuri de

intrare/ieşire

Clasa Reader

Clasa abstractă java.io.Reader este rădăcina ierarhiei de clase de fluxuri de intrare de

caractere.

Metode:

public int read() throws IOException - citeşte din fluxul de intrare un singur

caracter; întoarce caracterul citit (în domeniul 0 .. 16383) sau -1 dacă s-a ajuns la sfârşit de

fişier; metoda produce blocarea procesului în care este invocată, până când apare un caracter

în fluxul de intrare;

public int read(char[] cbuf) throws IOException - citeşte din flux o secvenţă

de caractere şi le depune într-o zonă tampon (buffer) constituită din tabloul de caractere cbuf;

întoarce numărul de caractere citite sau -1 dacă s-a atins sfârşitul de fişier; metoda produce

blocarea procesului până când apar caractere în fluxul de intrare, sau se ajunge la sfârşit de

fişier;

Page 311: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

311

public abstract int read(char[] cbuf, int off, int len) throws

IOException - acţionează asemănător cu metoda precedentă, dar depunerea caracterelor

citite în zona tampon de destinaţie se face începând de la poziţia off (offset), iar numărul

maxim de caractere citite este len;

public long skip(long n) throws IOException - se sare peste n caractere din

fluxul de intrare, care nu vor fi citite; procesul apelant este blocat pană când apare cel puţin

un caracter în fluxul de intrare; dacă se întâlneşte sfârşitul de fişier, se generează o excepţie

de intrare/ieşire; întoarce numărul de caractere sărite efectiv;

public boolean ready() - întoarce true dacă fluxul de intrare este gata pentru a

putea fi citit;

public void mark(int readAheadLimit) throws IOException - marchează

poziţia curentă în fluxul de intrare, pentru a se putea reveni la ea ulterior; argumentul

readAheadLimit indică numărul de caractere care vor putea fi ulterior citite din flux,fără ca

acest marcaj să se piardă; excepţia de intrare/ieşire apare dacă fluxul nu suportă marcarea sau

dacă se produce altă eroare de intrare/ieşire;

public boolean markSupported() - indică dacă fluxul suportă marcarea;

public void reset() throws IOException - dacă fluxul a fost marcat, este readus

la poziţia corespunzătoare ultimului marcaj; dacă fluxul nu a fost marcat sau nu suportă

resetarea, se generează o excepţie de intrare/ieşire;

public abstract void close() throws IOException - închide fluxul; din acest

moment, invocarea metodelor read(), ready(), mark() sau reset pentru acest flux va genera o

excepţie de intrare/ieşire.

Clasa Writer

Clasa abstractă java.io.Writer este rădăcina ierarhiei de clase pentru fluxuri de ieşire de

caractere.

Metode:

public void write(int c) throws IOException - scrie în fluxul de ieşire

caracterul c;

public void write(char[] cbuf) throws IOException - scrie în fluxul de ieşire

caracterele conţinute în tabloul cbuf; public abstract void(char[] cbuf, int off, int len) throws IOException

- scrie în fluxul de ieşire len caractere din tabloul cbuf, începând de la poziţia off (offset);

public void write(String str) throws IOException - scrie în flux caracterele

existente în şirul str; public void write(String str, int off, int len) throws IOException -

scrie în flux len caractere din şirul str, începând de la poziţia off (offset);

public abstract void flush() throws IOException - "descarcă" fluxul de

ieşire; dacă fluxul a salvat într-o zonă tampon anumite caractere scrise cu metodele write(),

aceste caractere sunt scrise efectiv în fluxul de destinaţie; dacă această destinaţie este tot un

flux, invocă şi metoda flush() a acestuia, astfel că se "descarcă" întregul lanţ de fluxuri;

public abstract void close() throws IOException - se închide fluxul de ieşire;

invocarea ulterioară a metodelor write() sau flush() pentru acest flux va produce o excepţie de

intrare/ieşire.

Page 312: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

312

Clasa InputStream

Clasa java.io.InputStream este rădăcina ierarhiei de clase pentru fluxuri de intrare

organizate pe octeţi.

Metode:

public int read() throws IOException - citeşte din fluxul de intrare un singur

octet; întoarce octetul citit (in domeniul 0 .. 255) sau -1 dacă s-a ajuns la sfârşit de fişier;

metoda produce blocarea procesului în care este invocată, până când apare un octet în fluxul

de intrare;

public int read(byte[] buf) throws IOException - citeşte din flux o secvenţă

de octeţi şi îi depune într-o zonă tampon (buffer) constituită din tabloul de octeţi buf; întoarce

numărul de octeţi citiţi sau -1 dacă s-a atins sfârşitul de fişier; metoda produce blocarea

procesului până când apar octeţi în fluxul de intrare, sau se ajunge la sfârşit de fişier; public abstract int read(byte[] buf, int off, int len) throws

IOException - acţionează asemănător cu metoda precedentă, dar depunerea octeţilor citiţi

în tabloul de destinaţie byte[] se face începând de la poziţia off (offset), iar numărul maxim

de octeţi citiţi este len;

public long skip(long n) throws IOException - se sare peste n octeţi din fluxul

de intrare, care nu vor fi citiţi; procesul apelant este blocat până când apare cel puţin un octet

în fluxul de intrare; dacă se întâlneşte sfârşitul de fişier se generează o eroare de intrare/ieşire;

întoarce numărul de octeţi săriţi efectiv;

public int available() throws IOException - întoarce numărul de octeţi

disponibili pentru citire în fluxul de intrare;

public void mark(int readAheadLimit) throws IOException - marchează

poziţia curenta în fluxul de intrare, pentru a se putea reveni la ea ulterior; argumentul

readAheadLimit indică numărul de octeţi care vor putea fi ulterior citiţi din flux, fără ca acest

marcaj să se piardă; excepţia de intrare/ieşire apare dacă fluxul nu suportă marcarea sau dacă

se produce altă eroare de intrare/ieşire;

public boolean markSupported() - indică dacă fluxul suportă marcarea;

public void reset() throws IOException - dacă fluxul a fost marcat, este readus

la poziţia corespunzătoare ultimului marcaj; dacă fluxul nu a fost marcat sau nu suporta

resetarea, se generează o excepţie de intrare/ieşire;

public abstract void close() throws IOException - închide fluxul; din acest

moment, invocarea metodelor read(), ready(), mark() sau reset() pentru acest flux va genera o

excepţie de intrare/ieşire.

Clasa OutputStream

Clasa java.io.OutputStream este rădăcina ierarhiei de clase pentru fluxuri de iesire de octeţi.

Metode:

public void write(int c) throws IOException - scrie în fluxul de ieşire ultimul

octet al numărului c;

public void write(byte[] buf) throws IOException - scrie în fluxul de ieşire

octeţii conţinuti în tabloul buf; public abstract void(byte[] buf, int off, int len) throws IOException -

scrie în fluxul de ieşire len octeţi din tabloul buf, începând de la poziţia off (offset);

public abstract void flush() throws IOException - "descarcă" fluxul de

Page 313: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

313

ieşire; dacă fluxul a salvat într-o zonă tampon anumiţi octeţi scrişi cu metodele write(), aceşti

octeţi sunt scrişi efectiv în fluxul de destinaţie; dacă această destinaţie este tot un flux, invocă

şi metoda flush() a acestuia, astfel că se "descarcă" întregul lanţ de fluxuri;

public abstract void close() throws IOException - se închide fluxul de ieşire;

invocarea ulterioară a metodelor write() sau flush() pentru acest flux va produce o excepţie de

intrare/ieşire.

Consideraţii privind utilizarea fluxurilor

Se remarcă cu uşurinţă faptul că metodele claselor Reader şi InputStream sunt similare atât ca

seigatură (şi deci ca mod de invocare), cât şi ca funcţionalitate. Metodele read(), skip(),

mark(), markSupported(), reset() şi close() există în ambele clase. Deosebirea este

ca în clasa Reader metoda read() citeşte din fluxul de intrare un caracter, iar în clasa

InputStream citeşte un octet. Metodele read() pentru citirea de secvenţe de caractere,

respectiv de octeţi, se deosebesc numai prin aceea ca în clasa Reader se folosesc ca destinaţie

tablouri de caractere, iar în clasa InputStream se folosesc tablouri de octeţi.

Metodele claselor Writer şi OutputStream sunt, de asemenea, similare ca signatură şi

funcţionalitate. Metodele write(), flush() şi close() există în ambele clase, însă în

clasa Writer metoda write() scrie în fluxul de ieşire un caracter, iar în clasa OutputStream

scrie un octet. În cazul că în metodele write() se scrie în flux conţinutul unui tablou, în clasa

Writer acesta este un tablou de caractere, iar in clasa OutputStream este un tablou de octeţi.

Remarcăm că ierarhiile de clase Reader şi Writer, introduse începând cu JDK 1.1, nu

înlocuiesc pe cele anterioare, având ca rădăcini clasele InputStream şi OutputStream, ci le

completează. Se vor putea deci folosi, după necesităţi, atât clasele de fluxuri de caractere, cât

şi cele de fluxuri de octeţi.

Clasele PrintStream şi PrintWriter

Clasele java.io.PrintStream şi java.io.PrintWriter se folosesc pentru a transmite către un

flux se ieşire date formatate pentru tipărire (afişare). Se ştie că forma internă a datelor diferă

de forma externă. De exemplu, numerele întregi sunt reprezentate intern sub formă binară, în

timp ce pe ecranul calculatorului sau la imprimantă apar sub forma unor şiruri de cifre

zecimale, precedate eventual de semn. Metodele claselor PrintStream şi PrintWriter fac

această conversie din forma internă în cea externă a diferitelor tipuri de date, generând

reprezentările datelor respective sub forma de şiruri de octeţi (caractere în codul ASCII) sau,

respectiv, de caractere Unicode. Aceste clase nu se folosesc în mod independent, ci adaugă

altui flux de ieşire (de octeţi sau, respectiv, de caractere) capacitatea de formatare a datelor în

vederea tipăririi.

Clasa PrintStream

Clasa PrintStream conţine doua feluri de metode de scriere a datelor: metodele cu numele

write() scriu întotdeauna octeţi (fără formatare), în timp ce cele cu numele print() sau

println() formatează datele, respectând convenţia de codificare (pe octeti sau pe caractere)

specifică platformei pe care ruleaza aplicaţia respectivă. Totuşi, se recomandă ca pentru a

obţine fluxuri de caractere să se folosească clasa PrintWriter.

Deosebirea dintre print() şi println() este că metodele cu numele println() adaugă, la

sfârşitul şirului de octeţi generat, un caracter de sfârşit de linie ('\n'). În consecinţă, dacă se

Page 314: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

314

foloseşte metoda print(), afişarea se face fără a se trece la o linie nouă, în timp ce dacă se

foloseşte metoda println(), după afişare se trece la linie nouă. Dacă fluxul este cu

descărcare automată, metoda println() provoacă, de asemenea, descărcarea acestuia (flush).

Constructori:

public PrintStream(OutputStream out) - creează un nou flux de formatare pentru

tipărire, conectat la fluxul de ieşire out; acest flux nu se descarcă automat;

public PrintStream(OutputStream out, boolean autoFlush) - creeaza un nou

flux de formatare a datelor pentru tipărire, conectat la fluxul de ieşire out; al doilea argument

indică dacă fluxul se descarcă automat atunci când se întâlneste în flux caracterul '\n' (linie

nouă) sau se execută metoda println() sau se tipăreşte un tablou de octeţi.

Metode:

public void flush() - descarcă fluxul (goleşte zonele tampon, transmiţând

conţinutul lor la ieşire);

public void close() - închide fluxul;

public void write(int b) - scrie în fluxul de ieşire un singur octet (ultimul octet al

argumentului);

public void write(byte[] buf, int off, int len) - se scriu în fluxul de ieşire

len octeţi din tabloul de octeti buf (buffer), începând de la poziţia off (offset);

public void print(boolean b) - transmite în fluxul de ieşire forma externă a

valorii variabilei booleene b, respectiv cuvântul true sau false;

public void print(char c) - se afişează caracterul c (pe unul sau doi octeţi,

depinzând de platformă);

public void print(int i) - se afişează numărul întreg i;

public void print(long l) - se afişează numărul întreg lung l;

public void print(float f) - se afişează numărul real în simplă precizie f;

public void print(double d) - se afişează numărul real în dublă precizie d;

public void print(char[] s) - se afişează conţinutul tabloului de caractere s;

public void print(String s) - se afişează şirul de caractere s;

public void print(Object obj) - se afişeaza obiectul obj convertit în şir de

caractere prin aplicarea metodei String.valueOf(obj) care, la rândul ei, apeleaza metoda

obj.toString() din clasa căreia îi aparţine obiectul;

public void print() - introduce în fluxul de ieşire codul caracterului '\n' (linie

nouă);

public void println(boolean b) - transmit în fluxul de ieşire forma externă a

valorii variabilei booleene b, respectiv cuvântul true sau false;

public void println(char c) - se afişează caracterul c (pe unul sau doi octeţi,

depinzând de platformă);

public void println(int i) - se afişează numărul întreg i;

public void println(long l) - se afişează numărul întreg lung l;

public void println(float f) - se afişează numărul real în simplă precizie f;

public void println(double d) - se afişează numărul real în dublă precizie d;

public void println(char[] s) - se afişează conţinutul tabloului de caractere s;

public void println(String s) - se afişează şirul de caractere s;

public void println(Object obj) - se afişează obiectul obj convertit în şir de

caractere prin aplicarea metodei String.valueOf(obj);

Page 315: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

315

Clasa PrintWriter

Constructori:

public PrintWriter(Writer out) - creează un nou flux de formatare pentru afişare,

fără descărcare automată, conectându-l la fluxul de ieşire pe caractere out;

public PrintWriter(Writer out, boolean autoFlush) - la fel ca şi constructorul

precedent, dar al doilea argument specifică dacă are loc descărcarea automată a fluxului;

public PrintWriter(OutputStream out) - creează un nou flux de formatare pe

caractere, fără descărcare automată, conectându-l la fluxul de ieşire pe octeţi out; el creează şi

un OutputStreamWriter intermediar, care face conversia caracterelor pe unul sau doi octeţi,

dependent de platformă;

public PrintWriter(OutputStream out, boolean autoFlush) - la fel ca şi

constructorul precedent, dar al doilea argument indică dacă se face descărcare automată a

fluxului.

Metode: Această clasa implementează aceleaşi metode ca şi clasa PrintStream, cu excepţia celor care

scriu octeţi bruti (write()).

Fişiere

În memoria externă a calculatorului, datele se păstrează sub forma de fişiere. Fişierul

(engleză: File) este o colecţie de înregistrări situată, de regulă, pe un suport extern şi

identificată printr-un nume. Fiecare înregistrare (engleză: Record) este o grupare de

informaţii sau de date care poate fi tratată în mod unitar.

Fişierele pot fi clasificate după diferite criterii.

După formatul înregistrărilor, distingem fişiere de text şi fişiere de date.

În fişierele de text, fiecare înregistrare este o linie de text, adică un şir de caractere care se

termină cu un marcaj de trecere la linie nouă. Acest marcaj depinde de platformă. De

exemplu, în fişierele MS-DOS marcajul de sfârşit de linie este format din secvenţa de

caractere "\r\n", adică din caracterul de întoarcere la cap de linie (Carriage Return, '\r' ) şi

caracterul de linie nouă (New Line, '\n'), care au codurile ASCII 0x0D şi respectiv 0x0A. Pe

platforme Unix, marcajul de sfârşit de linie este constituit numai din caracterul '\n' (New

Line, 0x0A). Liniile textului pot avea lungimi diferite. Codificarea caracterelor în fişier

depinde, de asemenea, de platformă. În prezent, pentru fişierele de text se foloseşte cel mai

frecvent codul ASCII, dar pot exista şi platforme pe care se foloseşte Unicode sau o altă

convenţie de codificare.

În fişierele de date, înregistrările au, de regulă, lungime predefinită, iar fiecare înregistrare

este constituită din mai multe câmpuri de date. În principiu, toate înregistrările unui fişier de

date au acelaşi format. Prin formatul înregistrării se înţelege descrierea structurii acesteia,

care constă din specificarea câmpurilor de date pe care le conţine, a lungimii fiecărui câmp, a

tipului de date conţinut în fiecare câmp şi a modului de reprezentare a datelor. Datele din

câmpuri pot fi reprezentate fie sub forma lor externă, fie sub formă binară, iar formatul

înregistrărilor diferă de la un fişier la altul.

Page 316: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

316

După modul de exploatare, fişierele pot fi de intrare, de ieşire sau de intrare/ieşire (de

manevră). În cazul fişierelor de intrare, din momentul deschiderii fişierului şi până în

momentul închiderii acestuia se pot efectua numai operaţii de citire. În cazul fişierelor de

ieşire, între momentele de deschidere şi de închidere a fişierului respectiv se pot face numai

operaţii de scrieire. Desigur însă că, după ce s-a încheiat scrierea într-un anumit fişier de

ieşire şi acesta a fost închis, el poate fi deschis ca fişier de intrare. Acelaşi fişier poate fi citit

de mai multe ori. Fişierele de intrare/ieşire permit ca, după ce au fost deschise, să se

efectueze atât operaţii de scriere, cât şi de citire.

După modul de acces fişierele pot fi cu acces secvenţial sau cu acces direct. Fişierele cu

acces secvenţial se caracterizează prin faptul că înregistrările lor pot fi parcurse într-un singur

sens, în ordinea în care acestea sunt plasate în fişier. În cazul fişierelor cu acces direct,

numite şi fişiere cu acces aleator (engleză: random access file) ordinea de parcurgere a

înregistrărilor din fişier este arbitrară, în sensul că la fiecare operaţie de intrare/ieşire făcută

asupra fisierului respectiv se poate indica adresa sau numărul de ordine al înregistrării care va

fi citită sau scrisă.

În limbajul Java, fişierul este privit ca sursa sau destinaţia unui flux. În cazul citirii din

fişier, datele se transmit de la acesta către memoria internă sub forma unui flux de intrare. În

cazul operaţiei de scriere, datele se transmit de la memoria internă la fişier sub forma unui

flux de ieşire.

În principiu, comunicarea între memoria internă şi un fişier de text se face sub forma unui

flux de caractere. Totuşi, pe platformele pe care reprezentarea caracterelor se face pe un octet

(de exemplu în cod ASCII), acesta poate fi tratat şi ca un flux de octeţi.

În cazul fişierelor de date, comunicarea dintre memoria internă şi fişier se poate face prin

fluxuri de caractere numai dacă datele din fişier sunt reprezentate exclusiv în format extern

(deci sub forma de şiruri de caractere). Dacă însă există şi câmpuri de date în format binar,

legatura dintre memoria internă şi fişierul de date se face, de regula, prin fluxuri de octeţi.

Operaţiile cu fişierul se fac în ordinea următoare:

1/ se deschide fişierul, în care scop trebuie să se comunice sistemului de operare numele

fişierului, locul în care se găseşte (de exemplu unitatea de disc şi calea către directorul care îl

conţine) şi modul în care va fi utilizat (pentru citire, pentru scriere sau în ambele moduri);

2/ se exploatează fişierul, efectuând o succesiune de operaţii de citire/scriere;

3/ se închide fişierul.

În limbajul Java, se consideră că, în operaţiile de intrare/ieşire, între fişier şi memorie se

transmit numai fluxuri de caractere sau de octeţi, fară să se ia în consideraţie informaţia pe

care o conţin aceste fluxuri. Întreaga responsabilitate privind interpretareaacestor fluxuri

revine programelor care le prelucrează.

Clasa File

Instanţele clasei java.io.File conţin informaţii privind numele fişierului şi calea pe care se

găseste acesta (engleza: Path). Clasa File oferă, de asemenea, metode prin care se pot face

unele operaţii legate de prezenţa fişierului respectiv: se poate afla dacă fişierul există, dacă el

poate fi citit sau scris, se poate crea un fişier nou, se poate şterge un fişier existent etc.

Page 317: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

317

Calea indică modul în care poate fi localizat fişierul de pe disc. Calea poate fi absolută sau

relativă. Calea absolută constă în indicarea unităţii de disc şi a succesiunii de directoare prin

care se ajunge de la rădacină la fişierul care ne interesează. Calea relativă, arată cum se

poate ajunge de la directorul curent la fişierul căutat.

Se ştie că, pe diferite platforme, calea se reprezintă în moduri diferite. De exemplu, în

sistemul Unix, calea relativa "../../alpha/beta/fisier1.txt" indică faptul că, pornind

de la directorul curent, se face o deplasare către rădăcină cu doua directoare, după care se

merge înainte (către frunzele arborelui director) trecând la subdirectorul alpha şi de aici la

subdirectorul beta, în care se găseşte fişierul căutat cu numele fişier1.txt. Remarcăm că

separarea directoarelor se face prin caracterul '/' (slash). Pe platformele firmei Microsoft

(MS-DOS, Windows), ca separator se foloseşte caracterul '\' (backslash), care în limbajele

C şi Java se reprezintă sub forma '\\'. În consecinţă, aceeaşi cale relativă se va scrie pe o

astfel de platforma sub forma "..\\..\\alpha\\beta\\fisier1.txt".

În clasa File, reprezentarea căii se face sub o formă independentă de platformă. În acest scop,

în instanţele clasei File, calea se păstrează sub forma unui tablou de şiruri de caractere, în

care se memoreaza numele fiecărui director conţinut în cale. Separatorul se păstrează într-un

câmp separat şi este setat automat în funcţie de sistemul de operare al calculatorului pe care

se execută programul. În acest fel, portabilitatea programului creşte, întrucât nu trebuie

modificate căile fişierelor folosite în program atunci când se trece de pe o platformă pe alta.

ATENŢIE: pentru asigurarea portabilităţii programelor sursă, este recomandabil ca, în căile

date ca argumente ale metodelor clasei File, să se folosească numai varianta Unix de

separatori. Compilatorul javac de pe platformele Microsoft înlocuieşte automat separatorul '/'

prin ' \\' in timp ce pe platformele Unix (Linux) nu se face înlocuirea inversă.

Remarcăm că numele clasei File poate să ne inducă în eroare, lăsându-ne să credem că

instanţele acestei clase sunt fişiere. În realitate, instanţele ei conţin căile şi numele fişierelor.

Page 318: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

318

Clasa File prezentată în detaliu

Câmpuri:

public static final char separatorChar - conţine caracterul prin care se separă

directoarele dintr-o cale; acest carecter este dependent de platforma, fiind '/' (slash) pe

platforme Unix şi '\' (backslash) pe platforme Microsoft;

public static final String separator - conţine caracterul de separare

(separatorChar) sub forma de String;

public static final char pathSeparatorChar - conţine caracterul de separare a

căilor; acest caracter este dependent de platformă, fiind ':' (două puncte) sub Unix şi ';' (punct

şi virgulă) pe platforme Microsoft;

public static final String pathSeparator - caracterul de separare a căilor

(pathSeparatorChar) sub formă de String.

NOTĂ: aceste câmpuri se completează automat, în funcţie de platforma pe care rulează

programul.

Constructori:

public File(String pathname) - creează o instanţă a clasei File, care conţine calea

dată ca argument;

public File(String parent, String child) - creează o instanţă a clasei File, în

care calea este compusă dintr-o cale "părinte" (formată numai din directoare) şi o cale "copil"

(care poate fi director sau fişier);

public File(File parent, String child) - se deosebeşte de constructorul

precedent numai prin faptul că "părintele" este o instanţă a clasei File.

Metode: Specificăm aici principalele metode ale clasei File.

public String getName() - întoarce numele fişierului (ultimul nume din cale); dacă

această cale este vidă, întoarce un şir vid;

public String getParent() - întoarce calea părinte;

public File getParentFile() - întoarce calea părinte sub forma de instanţă a

clasei File;

public String getPath() - întoarce calea conţinută în această instanţă; calea va

conţine separatorii impliciţi de pe platforma curentă;

public boolean isAbsolute() - intoarce true dacă această cale este absolută (dacă

este prefixată cu '/' pe platformele Unix sau cu '\\' pe platformele Microsoft);

public String getAbsolutePath() - întoarce calea absolută corespunzătoare căii

conţinute în această instanţă;

public File getAbsoluteFile() - întoarce o instanţă a clasei File care conţine

calea absolută corespunzatoare celei din instanţa curentă;

public URL toURL() - întoarce un URL (Uniform Resource Locator) corespunzător

căii din această instanţă; forma acestui URL este dependentă de sistem (Nota: URL-ul se

foloseşte pentru a localiza un fişier cu ajutorul unui browser de Web);

public boolean canRead() - testează dacă aplicaţia poate citi fişierul indicat de

această instanţă a clasei File;

public boolean canWrite() - testează dacă aplicaţia poate scrie în fişierul indicat;

public boolean exists() - testează dacă fişierul indicat există;

public boolean isDirectory() - testează dacă ultimul nume din această cale este

al unui director;

Page 319: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

319

public boolean isFile() - testează dacă ultimul nume din această cale este al unui

fişier;

public long lastModified() - întoarce timpul la care s-a făcut ultima modificare

în fişierul indicat de această cale (exprimat în milisecunde de la 1 ianuarie 1970 ora 00:00:00

GMT);

public long length() - întoarce lungimea fişierului indicat de această instanţă (în

octeţi);

public boolean createNewFile() throws IOException - dacă fişierul indicat în

această cale nu există, creează un fişier nou vid;

public boolean delete() - şterge fişierul; întoarce truedacă ştergerea a avut loc;

public void deleteOnExit() - cere ca fişierul să fie şters când se încheie

funcţionarea maşinii virtuale Java (are efect numai dacă funcţionarea se încheie normal);

public String[] list() - întoarce un tablou de şiruri, care conţine numele de

directoare şi de fişier din această cale;

public File[] listFile() - dacă această cale nu se încheie cu un nume de director,

întoarce null; altfel întoarce un tablou de instanţe ale clasei File, câte una pentru fiecare nume

de fişier din directorul indicat de această cale.

Exemplu: În fişierul TestFile.java este dat un exemplu de aplicaţie, în care se testează utilizarea

metodelor clasei File. Metodele se aplică pentru un fişier situat în directorul curent, pentru un

director şi pentru un fişier situat în alt director.

Citirea fişierelor

Citirea fluxurilor de octeţi: clasa FileInputStream

Clasa java.io.FileInputStream permite citirea datelor din fişiere sub forma de fluxuri de

octeţi. Orice instanţă a acestei clase este un flux de intrare, care are ca sursă un fişier. La

crearea acestei instanţe se caută şi se deschide fişierul indicat ca argument al constructorului.

Dacă fişierul nu există, sau nu poate fi deschis pentru citire, se generează o excepţie.

Page 320: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

320

Constructorii şi metodele clasei FileInputStream

Metodele acestei clase permit să se citească din fişierul de intrare octeţi sau secvenţe de

octeţi, fără a le da nici o interpretare.

Constructori:

public FileInputStream(String name) throws FileNotFoundException - se

creează un flux de intrare de octeţi având ca sursă fişierul name; (name este numele fişierului;

dacă acesta nu se află în directorul curent, atunci şirul name conţine şi calea);

public FileInputStream(File file) throws FileNotFoundException - se

creează un flux de intrare de octeţi având ca sursă fişierul indicat de instanţa file a clasei File;

public FileInputStream(FileDescriptor fdObj) - se creează un nou flux de

intrare de octeţi, care este conectat la fluxul de intrare fdObj deja existent.

Metode:

public int read() throws IOException - citeşte din fişier un singur octet; dacă

octetul nu este înca disponibil în fluxul de intrare, programul intră în aşteptare;

public int read(byte[] b) throws IOException - se citesc din fişier cel mult

b.length octeţi, care se pun în tabloul b; întoarce numărul de octeţi citit efectiv, sau zero dacă

s-a intâlnit sfârşitul de fisier fără să se citească nici un octet; dacă în fluxul de intrare nu mai

sunt octeţi de citit, dar nu s-a întâlnit sfârşitul de fişier, programul intră în aşteptare;

public int read(byte[] b, int off, int len) throws IOException - se

citesc din fluxul de intrare cel mult len octeţi, care se pun în tabloul b începând de la poziţia

off (offset); întoarce numărul de octeţi citit efectiv; dacă s-a întâlnit sfârşitul de fişier fără să

se citească nici un octet, intoarce -1; dacă nu s-a întâlnit sfârşitul de fişier şi nu sunt octeţi

disponibili pentru citire în fluxul de intrare, programul intră în aşteptare;

public long skip(long n) throws IOException - se sare peste n octeţi din

fişierul de intrare; se întoarce numărul de octeţi săriţi efectiv;

public int available() throws IOException - întoarce numărul de octeţi

disponibili pentru citire din fluxul de intrare;

public void close() throws IOException - închide fişierul;

public final FileDescriptor getFD() throws IOException - întoarce un

descriptor al acestui fişier.

NOTA: descriptorii de fişiere sunt obiecte care aparţin clasei java.io.FileDescriptor şi pot fi

folosiţi ca argument al constructorului pentru a crea un nou flux conectat la un fişier deja

deschis. Clasa FileDescriptor conţine, de asemenea, câmpurile statice in, out şi err, care sunt

descriptori ai fluxurilor de intrare/ieşire standard. În consecinţă, dacă se foloseşte ca

argument al constructorului clasei FileInputStream obiectul FileDescriptor.in, se creaza un

flux care citeşte datele de la tastatura.

Exemplu: În fişierul TestFileInput.java este un exemplu de aplicaţie, în care se testeaza metodele clasei

FileInputStream. În aplicaţie se deschide fişierul f1, prin care se citesc octeţi dintr-un fişier de

text, al cărui nume se dă ca parametru în linia de comandă, după care octeţii respectivi se

afişează. Întrucât se ştie că f1 este un fişier de text, octeţii sunt afişati convertiţi în caractere.

Se deschide apoi un al doilea flux, f2, care este echivalent cu f1, deoarece au acelaşi

descriptor. În consecinţă, în continuare fluxurile f1 şi f2 citesc date din acelaşi fişier. În final,

se creează un nou flux (cu referinţa f1), care citeşte datele de la tastatura, deoarece la creare s-

Page 321: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

321

a folosit descriptorul FileDescriptor.in. Acesta este câmpul in din clasa

java.io.FileDescriptor şi este o referinţă la fluxul de intrare standard, deci tratează fluxul de

la tastatură ca pe un fişier folosit pentru citire.

Citirea din fişiere de caractere: Clasa FileReader

Citirea unui fişier de text se poate face nu numai folosind o instanţă a clasei FileInputStream,

ci şi o instanţă a clasei FileReader. Deosebirea este că această ultimă clasă creează un flux de

caractere, în loc de un flux de octeţi. Chiar dacă fişierul nu este codificat în Unicode, ci în alt

cod de caractere (de cele mai multe ori ASCII), se face automat conversia în Unicode. Clasa

java.io.FileReader este derivată din clasa java.io.InputStreamReader şi foloseşte metodele

acesteia.

Constructori: public FileReader(String fileName) throws FileNotFoundException -

deschide ca flux de caractere de intrare fişierul cu numele fileName (eventual acest şir

cuprinde şi calea);

public FileReader(File file) - throws FileNotFoundException - deschide

ca flux de intrare de caractere fişierul cu calea file;

public FileReader(FileDescriptor fd) - deschide un nou flux de intrare de

caractere şi îl conectează la fluxul deja existent, al cărui descriptor este fd.

Metode: Clasa FileReader nu are metode proprii, dar moşteneşte următoarele metode ale clasei

InputStreamReader:

public int read() throws IOException - citeşte din fluxul de intrare un singur

caracter şi-l întoarce convertit în int; public int read(char[] buf, int off, int len) throws IOException -

citeşte din fluxul de intrare cel mult len caractere, pe care le pune în tabloul buf începând de

la poziţia off (offset);

public boolean ready() throws IOException - verifică dacă fluxul de intrare

este gata pentru citire (dacă conţine caractere care pot fi citite);

public void close() throws IOException - închide fluxul de intrare;

public String getEncoding() - întoarce numele canonic al codului folosit pentru

caractere.

Exemplu: În fişierul TestFileReader.java este dat un exemplu de aplicaţie în care se testează metodele

clasei FileReader. Fişierul care se citeşte poate fi acelaşi ca şi în cazul citirii cu un flux de

octeţi (din clasa FileInputStream). În această aplicaţie, citirea fişierului se face de trei ori,

folosind diverse metode.

Page 322: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

322

Scrierea în fişiere

Clasa FileOutputStream

Fiecare instanţă a clasei java.io.FileOutputStream este un flux de octeţi de ieşire conectat la

un fişier, în care se sriu octeţii primiţi din flux. Fluxul se poate conecta şi la un flux de octeti

de ieşire deja existent.

Constructorii şi metodele clasei FileOutputStream

Constructori: public FileOutputStream(String name) throws FileNotFoundException -

Deschide pentru scriere fişierul cu numele (şi, eventual, calea) name şi creează un flux de

octeţi către acest fişier; dacă fişierul nu există, se va crea pe disc un fişier nou, cu numele dat

ca argument; excepţia se generează dacă fişierul nu există şi nici nu poate fi creat; scrierea în

fişier se va face de la începutul acestuia ("peste" ceeace, eventual, exista deja scris); public FileOutputStream(String name, boolean append) throws

FileNotFoundException - acţionează la fel ca în cazul constructorului precedent, dar dacă

al doilea parametru este true, scrierea se va face în coada fişierului deja existent (scrierea

începe după ultima înregistrare deja existentă);

public FileOutputStream(File file) throws IOException - se deschide pentru

scriere fişierul indicat de calea file şi se creează un flux de octeţi către acesta; dacă fişierul nu

există, se creează unul nou; scrierea se face de la începutul fişierului;

public FileOutputStream(FileDescriptor fd) - creeaza un nou flux de octeţi de

ieşire, care se conectează la fluxul deja existent cu descriptorul fd.

Metode:

public void write(int b) throws IOException - scrie în fişier un singur octet,

conţinut în argumentul b;

public void write(byte[] b) throws IOException - scrie în fişier toti octeţii

conţinuti în tabloul b;

public void write(byte[] b, int off, int len) throws IOException - scrie

în fişier len octeţi din tabloul b începând de la poziţia off (offset);

public void close() throws IOException - închide fişierul;

public final FileDescriptor getFD() throws IOException - întoarce un

descriptor al acestui fişier;

Exemplu: În fişierul TestFileOutput.java se dă un exemplu de aplicaţie, în care se testează metodele

clasei FileOutputStream. Se deschide un fişier cu numele "ProbaScriere.txt" (dacă nu există,

se creează unul nou). În fişier se scrie textul dat în linia de comandă. În acest scop, lansarea

în execuţie se face sub forma

java TestFileOutput text_de_scris_în_fişier

După ce s-a scris textul, fişierul este închis, apoi este redeschis pentru citire şi conţinutul este

afişat pe ecran. Se închide şi se redeschide iarăşi, dar de data aceasta pentru scriere "în coada"

conţinutului existent. Se scriu cuvintele "Text adăugat", după care se închide, se redeschide

pentru citire şi se afişează. Metoda de scriere în fişier folosită de fiecare dată este cea în care

Page 323: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

323

se scrie un tablou de octeţi. Pentru afişare pe ecran, a doua oară s-a folosit tot un flux creat ca

instanţă a clasei FileOutputStream, dar care a fost conectat la fluxul standard de iesire

java.ioFileDescriptor.out, fiind astfel tratat acest flux ca un fişier.

Clasa FileWriter

Scrierea într-un fişier de text se poate face, de asemenea, folosind clasa FileWriter. Instanţele

acestei clase sunt fluxuri de ieşire de caractere, prin care se face scrierea într-un fişier. Clasa

FileWriter este derivată din java.io.OutputStreamWriter şi foloseşte metodele acesteia.

Constructori:

public FileWriter(String fileName) throws IOException - deschide fişierul

fileName pentru scriere şi creează un flux de caractere de ieşire conectat la acest fişier; dacă

fişierul nu există, îl creează; public FileWriter(String fileName, boolean append) throws IOException

- la fel ca în cazul constructorului precedent, dar, dacă al doilea parametru este true,

scrierea în fişier se va face în coada celui deja existent;

public FileWriter(File file) throws IOException - deschide pentru scriere

fişierul indicat prin calea file şi creează un flux de caractere de ieşire conectat la acest fişier;

public FileWriter(FileDescriptor fd) - creează un flux de caractere de ieşire

şi îl conectează la fluxul deja existent, cu descriptorul fd;

Metode: Metodele clasei FileWriter sunt moştenite de la clasa OutputStreamWriter.

public void write(int c) throws IOException - scrie în fişier un singur

caracter; public void write(char[] cbuf, int off, int len) throws IOException -

scrie în fişierul de ieşire len caractere din tabloul de caractere cbuf, începând de la poziţia

off (offset); public void write(String str, int off, int len) throws IOException -

scrie în fişier len caractere din şirul str începând de la poziţia off;

public void flush() throws IOException - goleşte conţinutul zonei tampon,

descărcându-l în fişierul de ieşire;

public void close() throws IOException - închide fişierul de ieşire;

public String getEncoding() - întoarce numele canonic al codului de caractere

utilizat de acest flux.

Exemplu: În fişierul TestFileWriter.java este dat un exemplu similar cu cel din fişierul

TestFileOutput.java, în care în locul claselor FileInputStream şi FileOutputStream s-au folosit

clasele FileReader şi, respectiv, FileWriter.

Page 324: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

324

Fişiere cu acces direct

Fişierele cu acces direct, numite şi fisiere cu acces aleator (engl.: Random Access File), sunt

fişiere la care programatorul poate indica prin program locul (adresa) din fişier de la care

începe operaţia de citire sau de scriere. De regulă, astfel de fişiere pot fi utilizate atât pentru

citire, cât şi pentru scriere. Pentru ca înregistrările sale să poată fi parcurse într-o ordine

arbitrară, fişierul cu acces direct trebuie să fie stocat pe un suport adresabil, cum ar fi discul

magnetic, discul optic, memoria RAM sau ROM. În JDK, fişierele cu acces direct sunt

instanţe ale clasei RandomAccessFile.

Clasa RandomAccessFile

Clasa java.io.RandomAccessFile este derivată direct din clasa Object, deci nu face parte

din niciuna din cele patru ierarhii de fluxuri de intrare/ieşire prezentate anterior, deşi face

parte, ca şi acestea, din pachetul java.io.

Fişierul cu acces direct este privit aici ca un tablou de octeţi memorat într-un sistem de fişiere

(de regulă în memoria externă). Există un cursor al fişierului (numit în engleză File Pointer),

care se comportă ca un indice al acestui tablou. Valoarea acestui indice (poziţia cursorului de

fişier relativ la începutul acestuia) poate fi "citită" cu metoda getFilePointer() şi poate fi

modificată cu metoda seek(). Orice citire sau scriere se face începând de la poziţia pe care

se găseşte acest cursor. La sfârşitul operaţiei, cursorul se deplasează pe o distanţă

corespunzatoare cu numarul de octeţi care au fost citiţi sau scrişi efectiv.

Fişierul cu acces direct poate fi deschis în modul read (numai pentru citire), write (numai

pentru scriere) sau read/write. În ultimul caz, este posibil să se efectueze atât citiri , cât şi

scrieri.

Scrierea în fişierele cu acces direct se poate face atât în mod text (succesiunea de octeţi

fiind privită ca o succesiune de caractere), cât şi în mod binar, la fel ca în fişierele de date, în

care scrierea s-a făcut folosind un DataOutputStream. În consecinţă, clasa RandomAccessFile

oferă atât metode de scriere şi de citire de octeţi, cât şi metode de scriere şi de citire pentru

toate tipurile de date primitive şi pentru şiruri de caractere, la fel ca în cazul claselor

DataOutputStream şi DataInputStream. Este evident că, la citirea din fişier, trebuie să se

respecte modul în care acesta a fost scris.

Dacă la citire se întâlneşte sfârşitul de fişier, se generează o excepţie de sfârşit de fişier din

clasa EOFException (End of File Exception), care este derivată din IOException. În toate

celelalte cazuri când nu se poate efectua o operaţie de citire sau de scriere se genereaza o

IOException (Input-Output Exception).

Constructori public RandomAccessFile(String file, String mode) throws

FileNotFoundException - deschide fişierul cu acces direct cu numele file în modul de

exploatare mode. Modul poate fi "r" (numai citire) sau "rw" (citire si scriere); dacă este "rw"

Page 325: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

325

şi fişierul nu există, se creează un fişier nou; public RandomAccessFile(File file, String mode) throws IOException -

acţionează asemănător cu constructorul precedent, dar calea şi numele fişierului care se

deschide sunt date de instanţa file a clasei File.

Metode

public final FileDescriptor getFD() throws IOException - întoarce

descriptorul de fişier;

public int read() throws IOException - citeşte din fişier un singur octet (sau

întoarce -1 dacă s-a atins sfârşitul fişierului); dacă în fluxul de intrare nu este disponibil nici

un octet, se intră în aşteptare;

public int read(byte[] b) throws IOException - citeşte maximum b.length

octeţi pe care îi pune în tabloul b; întoarce numărul de octeţi citit efectiv; public int read(byte[] b, int offset, int length)throws IOException -

citeşte cel mult length octeţi pe care îi pune în tabloul b începând de la poziţia offset; întoarce

numărul de octeţi cititi efectiv sau -1;

public final void readFully(byte[] b) throws IOException - citeşte exact

b.length octeţi, pe care îi pune în tabloul b; se blochează dacă nu are sufucienţi octeţi, iar la

întâlnirea sfârşitului de fişier generează o EOFException; public final void readFully(byte[] b, int offset, int length) throws

IOException - citeşte exact length octeţi, pe care îi depune în tabloul b începând de la

poziţia offset;

public int skipBytes(int n) - throws IOException - încearca să sară peste n

octeţi; întoarce numărul de octeţi săriţi efectiv;

public void write(int n) throws IOException - scrie în fişier un singur octet;

public void write(byte[] b) throws IOException - scrie în fişier conţinutul

tabloului b; public void write(byte[] b, int offset, int length)throws IOException -

scrie length octeţi din tabloul b începând cu cel de pe poziţia offset;

public long getFilePointer() throws IOException - întoarce poziţia

cursorului de fişier;

public void seek(long pos) throws IOException - deplasează cursorul de fişier

pe poziţia pos;

public long length() throws IOException - întoarce lungimea fişierului

(exprimată în octeti);

public void setLength(long newLength) throws IOException - setează noua

lungime a fişierului;

public void close() throws IOException - închide fişierul;

public final boolean readBoolean() throws IOException - citeşte o valoare

booleană (un octet);

public final byte readByte() throws IOException - citeşte o valoare primitivă

de tip byte;

public final int readUnsignedByte() throws IOException - citeşte un singur

octet, pe care îl interpretează ca număr întreg fără semn (în intervalul 0 .. 255);

public final short readShort() throws IOException - citeşte un întreg scurt

(pe doi octeţi);

public final int readUnsignedShort() throws IOException - citeşte doi

octeţi, pe care îi interpretează ca un numar întreg scurt fără semn;

public final char readChar() throws IOException - citeşte doi octeţi, pe care

îi interpretează ca un caracter Unicode;

Page 326: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

326

public final int readInt() throws IOException - citeşte un int (pe patru

octeţi);

public final long readLong() throws IOException - citeşte un long (pe opt

octeţi);

public final float readFloat() throws IOException - citeşte un float (pe

patru octeţi);

public final double readDouble()throws IOException - citeşte un double (pe

opt octeţi);

public final String readLine() throws IOException - citeşte din fişier o linie

de text, adică un şir de caractere încheiat prin marcajul de sfârşit de linie ('\n' pe platforme

Unix sau '\r' '\n' pe platforme Microsoft);

public final String readUTF() throws IOException - citeşte un şir de caractere

în format UTF-8;

public final void writeBoolean(boolean b) throws IOException - scrie o

valoare booleană (pe un octet);

public final void writeByte(byte v) throws IOException - scrie o valoare de

tip byte;

public final void writeShort(short v) throws IOException - scrie un short

(pe doi octeţi);

public final void writeChar(char v) throws IOException - scrie un caracter

Unicode (pe doi octeţi);

public final void writeInt(int v) throws IOException - scrie un int (pe

patru octeţi);

public final void writeLong(long v) throws IOException - scrie un long (pe

opt octeţi);

public final void writeFloat(float v) throws IOException - scrie un float

(pe patru octeţi);

public final void writeDouble(double v) throws IOException - scrie un

double (pe opt octeţi);

public final void writeBytes(String s) throws IOException - scrie un şir de

caractere convertit în secvenţă de octeţi (fiecare caracter este reprezentat pe un octet,

eliminându-se octetul superior al codului caracterului);

public final void writeChars(String s) throws IOException - scrie un şir de

caractere Unicode;

public final void writeUTF(String s) throws IOException - scrie un şir de

caractere în format UTF-8.

Exemplu În fişierul AccesDirect.java este dat un exemplu de aplicaţie, în care se creează şi se

utilizează un fişier cu acces direct, cu numele "Proba.fad". Prima dată fişierul este deschis în

mod "rw" (read/write). Se fac două serii de scrieri de date, care apoi sunt citite şi afişate.

Înainte de fiecare citire a unei serii de date se poziţionează cursorul de fişier la începutul

seriei respective, iar datele se citesc respectând modul în care acestea au fost scrise. Fişierul

este apoi închis şi redeschis în mod "r" ("read"), după care se poziţionează cursorul la

începutul celei de a doua serii de date, care este citită şi afişată.

Page 327: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

327

Fluxuri de prelucrare

Fluxurile de prelucrare se conectează la alte fluxuri de intrare/ieşire pentru a face anumite

transformări asupra datelor din fluxul respectiv. Clasele de fluxuri de prelucrare din Java API

au fost prezentate pe scurt la descrierea pachetului java.io. În această secţiune ne vom ocupa

de două categorii de fluxuri de prelucrare: fluxurile de date şi fluxurile de obiecte.

Fluxuri de date

În unele aplicaţii se doreşte să se transmită într-un flux de ieşire sau să se recepţioneze dintr-

un flux de intrare date primitive reprezentate binar (de tip boolean, char, byte, short, int, long,

float sau double) şi şiruri de caractere. În acest scop, pot fi folosite clasele

java.io.DataOutputStream şi java.io.DataInputStream.Se pot citi cu un

DataInputStream numai date care au fost scrise cu un DataOutputStream.

Instanţele acestor clase nu sunt fluxuri de intrare/ieşire propriu-zise, ci fluxuri de prelucrare.

În consecinţă, ele nu se conectează direct la sursă sau la destinaţie, ci la alte fluxuri. Astfel,

ieşirea unui DataOutputStream se poate conecta la intrarea unui FileOutputStream,

ByteArrayOutputStream sau PipedOutputStream. Se poate conecta, de asemenea la intrarea

unui BufferedOutputStream care, la rândul lui, este conectat la oricare din cele trei

menţionate anterior. În mod similar, intrarea unui DataInputStream poate fi conectată la

ieşirea unui FileInputStream, ByteArrayInputStream sau PipedInputStream.

Clasa DataOutputStream

Clasa java.io.DataOutputStream este derivată din clasa java.io.FilterOutputStream şi

implementează interfaţa java.io.DataOutput. Ea permite să se transmită date primitive către

un flux de ieşire într-o formă portabilă (independentă de platformă), cu condiţia ca aceste

date să fie citite ulterior printr-un DataInputStream.

Constructor:

public DataOutputStream(OutputStream out) - creează un nou flux de ieşire de

date, conectat la ieşire la un OutputStream (adică la o instanţă a unei clase derivate din clasa

OutputStream).

Metode: Aceasta clasă conţine metodele clasei java.io.OutputStream, la care se adaugă următoarele

metode specifice, destinate scrierii în fluxul de ieşire a datelor primitive sau a unor şiruri de

caractere:

public final void writeBoolean(boolean v) throws IOException - scrie o

valoare booleană;

public final void writeChar(char v) throws IOException - scrie o valoare de

tip char, în format Unicode;

public final void writeByte(byte v) throws IOException - scrie o valoare de

tip byte pe un octet;

public final void writeShort(short v) throws IOException - scrie o valoare

de tip short pe doi octeţi;

public final void writeInt(int v) throws IOException - scrie o valoare de tip

Page 328: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

328

int pe 4 octeţi;

public final void writeLong(long v) throws IOException - scrie o valoare de

tip long pe 8 octeţi;

public final void writeFloat(float v) throws IOException - scrie o valoare

de tip float pe 4 octeţi;

public final void writeDouble(double v) throws IOException - scrie o

valoare de tip double pe opt octeţi;

public final void writeBytes(String v) throws IOException - scrie un şir de

caractere, convertit într-un şir de octeţi prin suprimarea octetului superior al fiecărui caracter;

public final void writeChars(String v) throws IOException - scrie în flux un

şir de caractere (în Unicode);

public final void writeUTF(String v) throws IOException - scrie un şir de

caractere codificat în formatul UTF-8 într-o formă independentă de maşină (se scrie mai întâi

lungimea şirului pe doi octeţi, apoi fiecare caracter din şir pe câte un singur octet);

public final int size() - întoarce numărul de octeţi scrişi în acest flux de ieşire.

Clasa DataInputStream

Un DataInputStream este un flux de intrare de octeţi care este conectat la intrare la un alt

InputStream şi citeste din acesta date primitive într-o formă independentă de platformă. Se

pot citi cu DataInputStream numai date care au fost scrise cu DataOutputStream.

Clasa java.io.DataInputStream este derivată din clasa java.io.FilterInputStream şi

implementează interfaţa java.io.DataInput.

Constructor:

public DataInputStream(InputStream in) - creează un flux de date de intrare, care

citeşte date din fluxul de intrare in, primit ca argument.

Metode: Aceasta clasă conţine toate metodele clasei java.io.InputStream, la care se adaugă

următoarele metode specifice, prin care se implementează interfaţa java.io.DataInput:

public final void readFully(byte[] b) throws IOException - citeşte din

fluxul de intrare un număr de octeţi egal cu lungimea tabloului b, primit ca argument, şi îi

pune în acest tablou. Dacă în fluxul de intrare nu sunt înca suficienţi octeţi, dar nu s-a atins

sfârşitul de fişier, procesul este pus în aşteptare până apar noi octeţi. Dacă se întâlneşte

sfârşitul de fişier (EOF - End of File), se generează o EOFException; public final void readFully(byte[] b, int off, int len) throws

IOException - acţionează similar cu metoda precedentă, dar se citesc len octeţi, care sunt

depuşi în tabloul b, începand de la poziţia off;

public final void skipBytes(int n) throws IOException - sare peste n octeţi

din fluxul de intrare; întoarce numărul de octeţi săriţi efectiv (este posibil să nu reuşească să

sară n octeti, de exemplu dacă a întalnit sfârşitul fluxului);

public final boolean readBoolean() throws IOException - citeşte un octet din

fluxul de intrare şi îl converteşte în valoare booleană;

public final byte readByte() throws IOException - citeşte din fluxul de intrare

Page 329: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

329

un singur octet, pe care îl tratează ca un număr întreg cu semn în intervalul [-128, 127]; se

consideră că a fost scris cu writeByte(byte v);

public final int readUnsignedByte() throws IOException - citeşte din fluxul

de intrare un singur octet, pe care îl tratează ca număr întreg fără semn în intervalul [0, 255]

şi îl întoarce sub formă de int;

public final short readShort() throws IOException - citeşte doi octeţi din

fluxul de intrare şi îi interpretează ca un număr de tip short, scris anterior cu writeShort(short

v);

public final int readUnsignedShort() throws IOException - citeşte din fluxul

de intrare doi octeţi, pe care îi interpretează ca număr întreg fără semn şi-l întoarce sub formă

de int;

public final char readChar() throws IOException - citeşte din fluxul de intrare

un char (doi octeţi, format Unicode);

public final int readInt() throws IOException - citeşte patru octeţi si îi

interpretează ca un număr de tip int scris cu writeInt(int v);

public final long readLong() throws IOException - citeste opt octeţi si îi

interpretează ca un număr de tip long, scris cu writeLong(long v);

public final float readFloat() throws IOException - citeşte patru octeţi si îi

interpretează ca un număr de tip float, scris cu writeFloat(float v);

public final double readDouble() throws IOException - citeşte opt octeţi si îi

interpretează ca un număr de tip double, scris cu writeDouble(double v);

public final String readUTF() throws IOException - citeşte un şir de caractere

în format UTF (care a fost scris cu writeUTF(String str));

Exemplu

În fişierul FisierDate.java se dă un exemplu de aplicaţie, în care se creează un fişier de date şi

se scriu date în acest fişier folosind un DataOutputStream legat la un FileOutpusStream.

După ce au fost scrise datele, se închide fişierul pentru scriere şi se redeschide pentru citire,

după care se citesc datele în aceeaşi ordine în care au fost scrise. Datele scrise în fişier şi cele

citite sunt afişate pe ecran pe perechi, pentru comparaţie.

Fluxuri de obiecte

Fluxurile de obiecte sunt fluxuri de prelucrare care permit să se transmită obiecte. În acest

scop, obiectele transmise trebuie să fie serializate, înainte de a fi transmise, adică să fie puse

sub forma unei serii de octeti, într-un format care să permită la destinaţie reconstituirea în

memorie a obiectului respectiv. Astfel de obiecte se numesc serializabile.

Pe platforma Java 2, fluxurile de obiecte se realizează prin clasele

java.io.ObjectOutputStream şi java.io.ObjectInputStream. Obiectele transmise de aceste

fluxuri trebuie sa implementeze interfaţa java.io.Serializable.

Interfaţa Serializable

Orice obiect care se transmite pe un flux trebuie să aparţină unei clase care implementează

interfaţa java.io.Serializable. Aceasta inseamnă că trebuie îndeplinite următoarele condiţii:

Page 330: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

330

- la declararea clasei respective, se pune clauza implements Serializable;

- clasa trebuie să conţină un constructor fără argumente;

- toate câmpurile obiectului trebuie să fie serializabile, adică fie să aparţina unor tipuri de

date, primitive, fie unor clase care implementează interfaţa Serializable.

Interfaţa Serializable nu conţine câmpuri sau metode. Clauza implements Serializable

constituie doar o indicaţie pentru compilatorul Java să o pună sub forma serializabilă.

Dacă, la transmiterea obiectelor pe flux, se constată că unul din acestea nu este serializabil, se

generează excepţia NotSerializableException.

Clasele care necesită o manipulare specială la serializare sau deserializare trebuie să conţina

metode cu signaturile următoare: private void writeObject(java.io.ObjectOutputStream out) throws IOException private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException;

O prezentare mai amplă a acestei interfeţe se găseşte în documentaţia Java API.

Clasa ObjectOutputStream

Clasa java.io.ObjectOutputStream este clasa fluxurilor de prelucrare pentru obiecte, având

rolul de a serializa obiectele care urmează să fie puse într-un flux de ieşire. Fluxurile de

obiecte se conectează la ieşire la un alt flux, de preferinţă la un FileOutputStream,

ByteArrayOutputStream sau PipedOutputStream, iar utilizarea lor este asemănătoare cu cea a

fluxurilor de date (DataOutputStream). Într-un flux de obiecte se pot scrie atât obiecte

serializate, cât şi date primitive sau şiruri.

Clasa ObjectOutputStream conţine toate metodele de scriere a datelor primitive şi a şirurilor,

care există şi în clasele DataOutputStream şi RandomAccessFile. În plus, ea conţine metode

necesare pentru scrierea în flux a obiectelor, cea mai frecvent folosită fiind următoarea:

public final void writeObject(Object obj)throws IOException - scrie în fluxul

de ieşire obiectul obj sub formă serializată;

Informaţii mult mai ample despre această clasă pot fi găsite în documentaţia Java API.

Clasa ObjectInputStream

Clasa java.io.ObjectInputStream serveşte pentru citirea (deserializarea) fluxurilor de

obiecte care au fost scrise folosind clasa java.io.ObjectOutputStream. Intrarea unui

ObjectInputStream este conectată la ieşirea unui alt flux de intrare, de preferinţă

FileInputStream, ByteArrayInputStream sau PipedInputStream.

Clasa ObjectInputStream conţine toate metodele de citire a datelor primitive şi a şirurilor

existente în clasa DataInputStream. În plus, ea conţine metode necesare pentru citirea

Page 331: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

331

obiectelor serializate, dintre care cea mai frecvent folosită este public final Object readObject() throws OptionalDataException,

ClassNotFoundException, IOException Informaţii mai ample despre această clasă se găsesc în documentaţia Java API.

Exemplu

În fişierul FisierObiecte.java este dat un exemplu de aplicaţie, în care se testează clasele

ObjectOutputStream şi ObjectInputStream.

În prima parte a metodei main(), se creează un fişier (Proba1.dat) în care se scriu atât

obiecte (din clasele Persoana şi Student), cât şi date primitive, şiruri şi tablouri. Pentru

scrierea obiectelor şi a tablourilor se foloseşte metoda void writeObject(Object obj), iar

pentru datele primitive şi pentru şiruri se folosesc metodele specifice pentru scrierea tipurilor

respective. După ce s-a încheiat scrierea datelor, se închide fişierul Proba1.dat.

În partea a doua a metodei main() se deschide fişierul Proba1.dat pentru citire şi se citesc din

el toate datele scrise anterior, în ordinea în care au fost scrise. Întrucât metoda Object

readObject() întoarce un Object, acesta este convertit prin cast într-un obiect din clasa

căruia îi aparţine în realitate.

În ultima parte a metodei main() se afişează pe ecran datele citite, putându-se astfel verifica

faptul că serializarea şi deserializarea s-au făcut corect.

Remarcăm că, în afară de date primitive şi obiecte, au fost scrise în fişier (prin metoda

writeObject) şi tablouri unidimensionale şi bidimensionale, care au fost apoi citite corect

(prin metoda readObject).

Din acest exemplu se poate constata că clasele ObjectOutputStream şi ObjectInputStream

constituie un instrument foarte puternic de salvare şi restaurare a datelor din memorie la

nivelul obiectelor (al structurilor de date), care îl scutesc pe programator de munca laborioasă

şi dificilă se a programa aceste operaţii la nivelul inferior al fluxurilor de octeţi sau la nivelul

fluxurilor de date primitive.

Întrebări

Nivel 1

1. Ce este un stream?

2. Ce deosebire este între fluxurile de ieşire şi cele de intrare?

3. Care sunt etapele de utilizare a unui flux de iesire?

4. Care sunt etapele de utilizare a unui flux de intrare?

5. Ce conţine pachetul java.io?

6. Ce deosebire este între fluxurile de caractere şi cele de octeţi?

7. Care sunt rădăcinile ierarhiilor de clase pentru fluxuri de caractere?

8. Care sunt rădăcinile ierarhiilor de clase pentru fluxuri de octeţi?

9. Ce sunt fluxurile de prelucrare?

10. Ce este un fişier?

11. Care sunt clasele folosite pentru citirea fişierelor?

12. Care sunt clasele folosite pentru scrierea fişierelor?

13. Cum se deschide un fişier?

14. Cum se închide un fişier?

15. Ce clase se folosesc pentru a scrie date într-un fişier de octeţi şi pentru a citi date

Page 332: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

332

dintr-un astfel de fişier?

16. Ce sunt fişierele cu acces direct?

17. Cărei clase îi aparţin fişierele cu acces direct?

18. Ce fel de operaţii se pot face asupra unui fişier cu acces direct?

19. Ce este cursorul (pointerul) fişierului cu acces direct?

20. Care sunt modurile în care poate fi deschis un fişier cu acces direct?

21. Ce sunt fluxurile de prelucrare?

22. Ce sunt fluxurile de date?

23. Prin ce clase se realizează fluxurile de date?

24. Ce este un flux de obiecte?

25. Prin ce clase se realizează fluxurile de obiecte?

26. Ce proprietate trebuie sa aibă obiectele pentru a putea fi transmise într-un flux de

obiecte?

27. Ce reprezintă interfaţa Serializable?

28. Cum este folosită interfaţa Serializable?

29. Ce condiţii trebuie să îndeplinească o clasă pentru a fi serializabilă?

30. Ce metode conţine interfaţa Serializable?

Nivel 2

1. Dece fluxul este un obiect abstract?

2. Clasele Reader şi Writer sunt abstracte sau instanţiabile?

3. Ce se înţelege prin marcarea unui flux şi prin ce metodă se realizează?

4. Cum se poate reveni într-un flux la marcajul făcut anterior?

5. Clasele InputStream şi OutputStream sunt sau nu instanţiabile?

6. În ce situaţii este obligatorie folosirea fluxurilor de octeţi?

7. Ce clasă se foloseşte pentru a scrie date într-un fişier de caractere?

8. Ce clasă se foloseşte pentru a citi date dintr-un fişier de caractere?

9. Prin ce metode se scriu datele primitive într-un fişier cu acces direct?

10. Prin ce metode se citesc datele primitive dintr-un fişier cu acces direct?

11. Prin ce metode se scriu şirurile de caractere într-un fişier cu acces direct?

12. Ce este UTF?

13. Pot fi fluxurile de date conectate direct la un fişier?

14. La ce fluxuri se conectează fluxurile de date?

15. Ce se întamplă dacă se încearcă introducerea într-un flux de obiecte a unui obiect

neserializabil? Când se constată anomalia: la compilare sau la execuţie?

16. Un flux de obiecte poate conţine şi date primitive? dece?

17. Pot fi puse tablourile într-un flux de obiecte?

Page 333: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

333

Fire de execuţie

Conceptul de proces. Procese paralele şi

concurente

333

Fire de execuţie 335

Clasa Thread 335

Interfaţa Runnable 346

Sincronizarea firelor de execuţie 348

Întrebări. 354

Conceptul de proces. Procese paralele şi

concurente

În general, se numeşte proces o succesiune de transformări sau de operaţii care conduce la

realizarea unui anumit rezultat.

Esenţial pentru un proces este caracterul său temporal: fiecare transformare elementară

necesită un anumit timp, iar procesul în ansamblu este o succesiune de astfel de transformări

elementare. Termenul este folosit în domenii diferite: procese fizice, procese chimice,

procese tehnologice, procese biologice, procese economice, procese sociale, procese juridice

etc.

În informatică, procesul este un program în execuţie. În consecinţă, fiecărui proces i se

asociază un program, şi un ansamblu de resurse necesare executării acestui program: o

anumită zonă din memoria internă în care se păstrează datele programului, acces la

procesorul sistemului, acces la anumite dispozitive de intrare/ieşire etc. Procesul constă

tocmai în efectuarea în timp a succesiunii de operaţii prevăzută în program, folosind în acest

scop resursele alocate.

În mod tradiţional, programul este executat de către un singur procesor (dispozitiv de

prelucrare), care poate efectua, la un moment de timp dat, numai o singură operaţie. În

consecinţă, operaţiile prevăzute în program trebuie executate secvenţial, astfel încât operaţia

următoare nu poate începe decât după încheierea celei precedente. Toate programele

prezentate de noi în capitolele precedente se încadrează în această categorie.

Este posibil ca mai multe procese să se desfăşoare simultan, adică intervalele de timp

corespunzătoare acestor procese să se suprapună total sau parţial. Astfel de procese pot fi

paralele sau concurente.

Page 334: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

334

Dacă procesele de calcul care au loc simultan folosesc resurse diferite (sunt executate de

procesoare diferite, folosesc zone de memorie internă şi externă diferite etc.), ele se numesc

procese paralele.

Dacă procesele care se desfăşoară în acelaşi interval de timp folosesc anumite resurse

comune, ele se numesc procese concurente. Cel mai frecvent se întâlneşte situaţia, în care

mai multe procese folosesc în comun acelaşi procesor. Întrucât, la un moment dat, procesorul

nu poate efectua decât o singură operaţie, înseamnă că este necesar să se adopte o anumită

strategie, conform căreia timpul de funcţionare al procesorului este partajat între diferitele

procese concurente. În principiu, aceste strategii se împart în două categorii:

1. Se acordă fiecăruia dintre procesele concurente un anumit nivel de prioritate. Dacă mai

multe procese solicită simultan aceeaşi resursă, ea este alocată procesului cu prioritate

superioară.

Conform acestei strategii, dacă, în timpul derularii unui proces A, procesorul este solicitat

de un alt proces B de prioritate superioară, procesul A este întrerupt, trecându-se la

executarea procesului B. După încheierea executării procesului prioritar B, se revine la

procesul A, care este continuat din starea în care a fost întrerupt. Este însa posibil ca, în timp

ce se deruleaza procesul B, procesorul sa fie solicitat de un alt proces C, de prioritate şi mai

înalta. În acest caz, şi procesul B va fi întrerupt, trecându-se la executarea procesului C şi

aşa mai departe.

2. Timpul total de funcţionare a procesorului este porţionatsau divizat (împărţit în intervale

de durate egale sau diferite), acordându-se succesiv câte un astfel de înterval de timp fiecăruia

dintre procesele concurente. La expirarea intervalului de timp alocat, numit şi felie sau tranşă

de timp (engleză: time slice), procesul în curs este întrerupt şi se trece la executarea

procesului următor, prin rotaţie. O astfel de utilizare a procesorului se numeşte "partajare a

timpului" (engleză: time sharing sau time slicing).

Cele două strategii menţionate aici pot fi aplicate în diferite variante şi pot fi combinate în

diferite moduri. Cel mai frecvent, partajarea timpului este aplicată numai pentru procesele cu

acelaşi nivel de prioritate.

Majoritatea sistemelor de operare ale calculatoarelor moderne permit executarea în acelaşi

timp a mai multor programe, deci permit concurenţa proceselor la nivel de program (de

aplicaţie). De exemplu, în timp ce edităm un text, putem tipări alt text la imprimantă, putem

aştepta sosirea de pe reţea a unei pagini de Web etc. Studierea acestui mod de funcţionare a

calculatorului, cunoscut sub numele de multitasking, se face la cursul de "Sisteme de

operare".

Pentru a pune în evidenţă distincţia între program şi proces, putem menţiona că acelaşi

program poate da naştere la procese diferite: dacă programul conţine ramificaţii şi/sau cicluri,

parcurgerea efectivă a acestora (ce ramuri vor fi executate efectiv şi de câte ori se vor

parcurge ciclurile) depinde de datele de intrare. În cadrul multitaskingului, este chiar posibil

ca doi utilizatori să utilizeze simultan acelaşi program folosind date diferite, astfel încât se

generează procese diferite.

Page 335: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

335

Fire de execuţie

Firul de execuţie (în engleză: Thread) este, în esenţă, un subproces strict secvenţial.

Menţinând definiţia procesului ca un program în curs de execuţie, putem considera acum că

procesul este format din mai multe fire de execuţie care se derulează în paralel, concurând la

utilizarea resurselor alocate procesului respectiv.

În limbajul Java, există posibilitatea de a se crea programe care conţin mai multe fire de

execuţie. Aceasta înseamnă că, la executarea lor, se vor crea mai multe subprocese care se

vor desfăşura simultan, folosind acelaşi procesor şi aceeaşi zonă de memorie. Acest mod de

funcţionare se numeşte în engleză multithreading.

Chiar şi în cazul programelor Java în care nu sunt prevăzute explicit mai multe fire de

execuţie, în timpul executării lor coexistă cel puţin două astfel de fire: cel al aplicaţiei

propriu-zise şi cel al colectorului de reziduuri (garbage collector). Colectorul de reziduuri

este un fir de execuţie cu nivel de prioritate coborât, care funcţionează atunci când apar

întreruperi în desfăşurarea aplicaţiei propriu-zise (de exemplu, când se aşteaptă efectuarea

unor operaţii de intrare/ieşire). În consecinţă, maşina virtuală Java are intrinsec o funcţionare

de tip multithreading.

Există două moduri de a programa un fir de execuţie:

- prin extinderea clasei Thread;

- prin implementarea interfeţei Runnable.

Clasa Thread

Clasa java.lang.Thread realizează un fir de execuţie. Acesta poate fi un fir de execuţie

obişnuit, sau un demon.

Demonul (engleză: daemon thread) este un fir de execuţie de prioritate coborâtă, care nu este

invocat în mod explicit. El stă "adormit" şi intră automat în execuţie atunci când sunt

îndeplinite anumite condiţii.

Un exemplu tipic de demon este colectorul de reziduuri. După cum ştim deja, acesta este un

fir de execuţie de prioritate coborâtă, care intră în funcţiune atunci când în memorie apar

obiecte către care nu mai există referinţe.

Crearea unui fir de execuţie se face invocând unul dintre constructorii clasei Thread. Dintre

aceştia, îi menţionâm aici pe următorii:

public Thread() - creează un nou fir de execuţie cu numele implicit Thread-n, unde n

este un număr de ordine;

public Thread(String name) - creează un nou fir de execuţie cu numele name;

public Thread(Runnable target) - creează un nou fir de execuţie, care conţine

obiectul target cu interfaţa Runnable, iar numele firului este cel implicit;

Page 336: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

336

public Thread(Runnable target, String name) - creează un nou fir de execuţie,

care conţine obiectul target cu interfaţa Runnable şi are numele name.

Cele mai frecvent utilizate metode ale clasei Thread sunt run(), start() şi sleep(). Iată o

listă a principalelor metode ale acestei clase:

public void run() - conţine programul care trebuie executat de firul respectiv; Aşa

cum este ea în clasa Thread, metoda nu face nimic (are corpul vid). Această metodă trebuie

redefinită fie prin crearea unei subclase a clasei Thread, fie prin crearea unei obiect cu

interfaţa Runnable, care să fie înglobat în acest Thread (folosind constructorul

Thread(Runnable target));

public void start() - pune firul nou creat în starea "gata pentru execuţie";

public static void sleep(long millis) throws InterruptedException -

opreşte temporar execuţia acestui fir, pentru o durata de millis milisecunde;

public static void yield() - opreşte temporar execuţia acestui fir, permiţând

monitorului să dea controlul altui fir de aceeaşi prioritate;

public static Thread currentThread() - întoarce o referinţă la firul care este

executat în momentul curent;

public final void setPriority(int newPriority) - seteaza prioritatea firului de

execuţie; prioritatea trebuie sa fie cuprinsă în intervalul [Thread.MIN_PRIORITY,

Thread.MAX_PRIORITY] (valorile lor fiind, respectiv, 1 şi 10). Nerespectarea acestui

interval genereaza o IllegalArgumentException. Daca nu este stabilită explicit, prioritatea

este Thread.NORM_PRIORITY (are valoarea 5).

public final int getPriority() - întoarce prioritatea curentă a firului de execuţie.

public final void setName(String name) - pune firului de execuţie un nou nume;

public final String getName() - întoarce numele firului de execuţie;

public final void setDaemon(boolean on) - dă firului de execuţie calitatea de

demon (dacă argumentul este true) sau de fir obişnuit (dacă argumentul este false); Metoda

poate fi invocată numai dacă firul nu este activ, altfel se generează o

IllegalThreadStateException.

public final boolean isDaemon() - testează dacă firul de execuţie este demon.

La programarea unui fir de execuţie, principala atenţie se acordă metodei run(),

deoarece ea conţine programul propriu-zis, care trebuie executat de acest fir. Totuşi,

metoda run()nu este invocată explicit. Ea este invocată de maşina virtuală Java, atunci

când firul respectiv este pus în mod efectiv în execuţie.

Pentru redefinirea metodei Run este necesar sa creem o subclasă a clasei Thread sau sa

creem o clasă cu interfaţa Runnable, şi să dăm o instanţă a acestei clase ca argument

constructorului clasei Thread.

După ce firul de execuţie a fost creat (de exemplu prin expresia new Thread()), el există în

memorie, dar înca nu poate fi executat. Se găseşte, deci, în starea "nou creat" (engleza:

born). Pentru a-l face gata de execuţie, pentru firul respectiv este invocată metoda start().

După invocarea metodei start(), firul este executabil, dar aceasta nu înseamnă că el este

Page 337: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

337

pus în execuţie imediat: noul fir devine concurent cu cele deja existente (în primul rând cu cel

care l-a creat), şi va fi pus în execuţie în mod efectiv (i se va acorda acces la procesor) atunci

când îi vine rândul, conform cu strategia de alocare a resurselor adoptată.

Un fir în curs de execuţie poate fi oprit temporar ("adormit") invocând metoda statică

sleep(long millis). Argumentul acestei metode este intervalul de timp cât procesul se va

găsi în stare de "somn", exprimat în milisecunde.

Referitor la utilizarea acestei metode, remarcăm două aspecte:

- întrucât ea poate "arunca" o InterruptedException, este necesar să fie prinsă într-un

bloc try..catch;

- întrucat metoda este statică şi nu are ca argument un fir de execuţie, ea nu poate fi invocată

decât în metodele firului de execuţie căruia i se aplică.

Fiecărui fir de execuţie i se asociază o anumită prioritate. Aceasta este un numar întreg,

cuprins între valorile Thread.MIN_PRIORITY şi Thread.MAX_PRIORITY (având valorile 1 şi

respectiv 10). Dacă metoda setPriority(int newPriority) nu este invocată explicit, firului i se

dă prioritatea implicita Thread.NORM_PRIORITY, respectiv 5.

Daca firul de execuţie solicită o operaţie de intrare/ieşire, el rămîne blocat pe întreaga durată

a executării operaţiei respective.

În timpul în care firul de execuţie "doarme" (ca urmare a invocării metodei sleep()) sau este

blocat (deoarece asteapta terminarea unei operatii de intrare/iesire), se pot executa alte fire, de

prioritate egală sau inferioară. În schimb, firele de prioritate superioară pot întrerupe în orice

moment executarea celor de prioritate inferioară.

Un proces poate fi pus, de asemenea, în aşteptare prin invocarea metodei wait(). În acest

caz, firul aşteaptă confirmarea efectuării unei anumite acţiuni, prin invocarea metodei

notify() sau notifyAll(). Aceste trei metode există în clasa Object şi servesc la

sincronizarea firelor de execuţie.

Având în vedere cele de mai sus, punem în evidenţă urmatoarele stări în care se poate găsi un

fir de execuţie pe durata ciclului său de viaţă:

- nou creat (engleză: born) - este starea în care se găseşte imediat ce a fost creat prin

operatorul new; în această stare, firul nu poate fi executat;

- gata de execuţie (engleză: ready) - este starea în care firul poate fi pus în execuţie;

punerea efectivă în execuţie se face de către maşina virtuala Java atunci când procesorul este

liber şi nu sunt gata de execuţie fire de prioritate superioară;

- în execuţie (engleză: running) - este starea în care procesul se execută efectiv (ocupă

procesorul);

- adormit (engleză: sleeping) - este starea de oprire temporară, ca urmare a invocării

metodei sleep();

- blocat (engleză: blocked) - este starea în care aşteaptă incheierea unei operaţii de

intrare/ieşire;

- în aşteptare (engleză: waiting) - este starea în care firul se găseşte din momentul în care

Page 338: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

338

se invocă metoda wait(), până când primeşte o confirmare dată prin invocarea metodei

notify();

- mort (engleză: dead) - este starea în care intră firul de execuţie dupa ce s-a încheiat

executarea metodei run().

Relaţiile dintre aceste stări sunt reprezentate grafic în figura de mai jos.

Denumirile stărilor firului de execuţie au fost date în limba engleză, pentru a putea fi urmarită

mai uşor documentaţia originală din Java API.

Trecerea de la starea Born la starea Ready (gata) se face prin invocarea metodei start().

Trecerea de la starea Ready la starea Running (în execuţie) se face de către maşina virtuală

Java (de către dispecerul firelor) atunci când sunt create condiţiile necesare: procesorul este

liber şi nici un fir de execuţie de prioritate superioară nu se găseşte în starea Ready.

Trecerea de la starea Running la starea Ready se face la executarea metodei yield(), sau

atunci când a expirat tranşa de timp alocată procesului (în cazul sistemelor cu diviziune a

timpului).

Trecerea de la starea Running la starea Sleeping se face la executarea metodei sleep().

Trecerea de la starea Sleeping la starea Ready se face când a expirat intervalul de timp de

Page 339: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

339

"adormire" (intervalul dat ca argument în metoda sleep(long millis)).

Trecerea de la starea Running la starea Blocked are loc atunci când firul de execuţie

respectiv solicită efectuarea unei operaţii de intrare ieşire.

Trecerea de la starea Blocked la starea Ready are loc când s-a încheiat operaţia de

intrare/ieşire solicitată de acest fir.

Trecerea de la starea Running la starea Waiting se face la invocarea metodei wait().

Trecerea de la starea Waiting la starea Ready se face când se primeşte o confirmare prin

invocarea metodei notify() sau notifyAll().

Trecerea de la starea Running la starea Dead are loc atunci când se încheie executarea

metodei run() a firului de execuţie respectiv.

Se observă că orice fir de execuţie îşi începe ciclul de viaţă în starea Born şi îl încheie în

starea Dead. Punerea firului în execuţie efectivă (trecerea de la Ready la Running) se face

numai de către dispecerul firelor. În toate cazurile în care se încheie o stare de oprire

temporară a execuţiei (Sleeping, Waiting sau Blocked), firul de execuţie respectiv trece în

starea Ready, aşteptând ca dispecerul să-l pună efectiv în execuţie (să-l treacă în starea

Running). În timpul cât firul de execuţie se găseşte în orice altă stare decât Running,

procesorul calculatorului este liber, putând fi utilizat de alte fire de execuţie sau de alte

procese.

Exemplul 1

Fişierul DouaFireA.java conţine un exemplu de aplicaţie, în care se creează fire de execuţie

folosind o clasă care extinde clasa Thread.

/* Crearea si utilizarea unei clase de fire de executie care extinde clasa Thread dar nu foloseste metodele sleep sau yield. Se creeaza doua fire de aceeasi prioritate (Thread.NORM_PRIORITY). */

class DouaFireA {

/* Clasa firelor de executie */ static class Fir extends Thread {

Fir(String numeFir) { super(numeFir); System.out.println("S-a creat firul "+getName()); }

/* Redefinirea metodei run() din clasa Thread */ public void run() { System.out.println("Incepe executarea firului "+getName()); for(int i=0; i<6; i++) {

Page 340: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

340

System.out.println("Firul "+getName()+" ciclul i="+i); } } } /* incheierea clasei Fir */

public static void main(String args[]) throws Exception { Fir fir1, fir2; System.out.println("Se creeaza firul Alpha"); fir1=new Fir("Alpha"); System.out.println("Se creeaza firul Beta"); fir2=new Fir("Beta"); System.out.println("Se pune in executie firul Alpha"); fir1.start(); System.out.println("Se pune in executie firul Beta"); fir2.start(); System.out.println("Sfarsitul metodei main()"); } /* Sfarsitul metodei main() */ }

Clasa Fir din această aplicaţie extinde clasa Thread, deci instanţele ei sunt fire de execuţie. În

clasa Fir s-a redefinit metoda run(), astfel încât să conţină programul firului respectiv. În

cazul nostru, firul execută un ciclu, în care afişează la terminal un mesaj, conţinând numele

firului şi indicele ciclului executat.

În metoda main() a aplicaţiei se creează două instanţe ale clasei Fir, dându-le, respectiv,

numele Alpha şi Beta, apoi se lansează în execuţie aceste fire. Iată un exemplu de rezultat al

executării acestei aplicaţii:

Se creeaza firul Alpha S-a creat firul Alpha Se creeaza firul Beta S-a creat firul Beta Sfarsitul metodei main() Incepe executarea firului Alpha Firul Alpha ciclul i=0 Firul Alpha ciclul i=1 Firul Alpha ciclul i=2 Firul Alpha ciclul i=3 Firul Alpha ciclul i=4 Firul Alpha ciclul i=5 Incepe executarea firului Beta Firul Beta ciclul i=0 Firul Beta ciclul i=1 Firul Beta ciclul i=2 Firul Beta ciclul i=3 Firul Beta ciclul i=4 Firul Beta ciclul i=5

Remarcăm cele ce urmează.

- În realitate, în afară de firele de execuţie Alpha şi Beta create explicit de către noi, mai

exista incă două fire de execuţie: cel al aplicaţiei propriu-zise (executarea metodei main()) şi

cel al colectorului de reziduuri. Întrucât nu s-au setat explicit priorităţile, firele Alpha, Beta şi

main() au toate prioritatea Thread.NORM_PRIORITY.

Page 341: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

341

- Întrucât toate firele au aceeaşi prioritate, durata executării fiecărui fir este mică şi nu s-au

folosit metode de suspendare a execuţiei (yield(), sleep(), wait()), în momentul în

care începe executarea unui fir acesta se execută până la capăt, după care procesorul

sistemului este preluat de firul următor. În consecinţă s-a executat mai întâi metoda main()

până la incheierea ei (confirmată prin mesajul "Sfârşitul metodei main()"), după care se

execută complet firul Alpha şi apoi firul Beta (în ordinea lansării).

- Aplicaţia se încheie în momentul în care s-a încheiat ultimul fir de execuţie.

Exemplul 2

În fişierul DouaFireA1.java se reia aplicaţia din exemplul precedent, dar la sfârşitul fiecărui

ciclu de indice i se invocă metoda yield() care suspendă firul în curs şi permite astfel să se

transmită controlul următorului fir de aceeaşi prioritate.

/* Crearea si utilizarea unei clase de fire de executie care extinde clasa Thread. Se foloseste metoda yield() pentru a ceda controlul altui fir de aceeasi prioritate. Se creeaza doua fire de aceeasi prioritate (Thread.NORM_PRIORITY). */

class DouaFireA1 {

/* Clasa firelor de executie */ static class Fir extends Thread {

Fir(String numeFir) { super(numeFir); System.out.println("S-a creat firul "+getName()); }

/* Redefinirea metodei run() din clasa Thread */ public void run() { System.out.println("Incepe executarea firului "+getName()); for(int i=0; i<6; i++) { System.out.println("Firul "+getName()+" ciclul i="+i); yield(); // cedarea controlului procesorului } } } /* incheierea clasei Fir */

public static void main(String args[]) throws Exception { Fir fir1, fir2; System.out.println("Se creeaza firul Alpha"); fir1=new Fir("Alpha"); System.out.println("Se creeaza firul Beta"); fir2=new Fir("Beta"); System.out.println("Se pune in executie firul Alpha"); fir1.start(); System.out.println("Se pune in executie firul Beta"); fir2.start(); System.out.println("Sfarsitul metodei main()");

Page 342: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

342

} /* Sfarsitul metodei main() */ }

Rezultatul executarii acestei aplicatii este urmatorul:

Se creeaza firul Alpha S-a creat firul Alpha Se creeaza firul Beta S-a creat firul Beta Sfarsitul metodei main() Incepe executarea firului Alpha Firul Alpha ciclul i=0 Incepe executarea firului Beta Firul Beta ciclul i=0 Firul Alpha ciclul i=1 Firul Beta ciclul i=1 Firul Alpha ciclul i=2 Firul Beta ciclul i=2 Firul Alpha ciclul i=3 Firul Beta ciclul i=3 Firul Alpha ciclul i=4 Firul Beta ciclul i=4 Firul Alpha ciclul i=5 Firul Beta ciclul i=5

Se observă cu uşurinţă că, în acest caz, executarea celor două fire, Alpha şi Beta, are loc

intercalat, deoarece, după fiecare parcurgere a unui ciclu într-un fir, se invocă metoda

yield() , cedându-se procesorul sistemului în favoarea celuilalt fir. Aceasta nu s-ar fi

întâmplat, dacă cele doua fire ar fi avut priorităţi diferite.

Exemplul 3

În fişierul DouaFireB.java s-a reluat aplicaţia din Exemplul 1, aducându-i-se următoarele

modificări:

- în ciclul cu contorul i din metoda run() a clasei Fir s-a mai introdus un ciclu interior (cu

contorul j) care se parcurge de 100000000 ori, pentru a mări în mod artificial durata de

execuţie; în locul acestuia se putea pune, evident, orice alta secvenţa de instrucţiuni cu durata

de execuţie comparabilă;

- cele două cicluri (pe i şi pe j) au fost introduse şi în metoda main(), pentru a putea urmări

executarea acesteia după lansarea firelor Alpha şi Beta.

Fragmentele de program nou adăugate sunt puse în evidenţă în textul de mai jos cu caractere

aldine (îngroşate).

/* Crearea si utilizarea unei clase de fire de executie. In metoda run a firului nu se folosesc metodele sleep() sau yield(), dar se parcurge un ciclu de contorizare (pe j) de 100000000 ori pentru a mari durata de executie a ciclului exterior (pe indicele i). Se creeaza doua fire de aceeasi prioritate (Thread.NORM_PRIORITY). */

Page 343: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

343

class DouaFireB {

/* Clasa firelor de executie */ static class Fir extends Thread {

Fir(String numeFir) { super(numeFir); System.out.println("S-a creat firul "+getName()); }

/* Redefinirea metodei run() din clasa Thread */ public void run() { System.out.println("Incepe executarea firului "+getName()); for(int i=0; i<5; i++) { for(int j=0; j<100000000; j++); System.out.println("Firul "+getName()+" ciclul i="+i); } } } /* incheierea clasei Fir */

public static void main(String args[]) throws Exception { Fir fir1, fir2, fir3; System.out.println("Se creeaza firele Alpha si Beta"); fir1=new Fir("Alpha"); fir2=new Fir("Beta"); System.out.println("Se pun in executie cele doua fire"); fir1.start(); fir2.start(); for (int i=0; i<5; i++) { for(int j=0; j<100000000; j++); System.out.println("main() ciclul i="+i); } System.out.println("Sfarsitul metodei main()"); } /* Sfarsitul metodei main() */ }

Iată un exemplu de rezultat obţinut prin executarea acestei aplicaţii:

Se creeaza firele Alpha si Beta S-a creat firul Alpha S-a creat firul Beta Incepe executarea firului Alpha Incepe executarea firului Beta Firul Alpha ciclul i=0 Firul Beta ciclul i=0 main() ciclul i=0 main() ciclul i=1 Firul Alpha ciclul i=1 Firul Beta ciclul i=1 main() ciclul i=2 Firul Alpha ciclul i=2 Firul Beta ciclul i=2 main() ciclul i=3 Firul Alpha ciclul i=3 Firul Beta ciclul i=3

Page 344: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

344

main() ciclul i=4 Sfarsitul metodei main() Firul Alpha ciclul i=4 Firul Beta ciclul i=4

Constatăm că, întrucat durata de execuţie a fiecărui fir a devenit mult mai mare decât în

exemplul precedent şi toate cele trei fire (Alpha, Beta si main()) au aceeaşi prioritate

(Thread.NORM_PRIORITY), se aplică o strategie de partajare a timpului, astfel încât timpul

de funcţionare al procesorului este alocat sub forma de tranşe succesive fiecăruia dintre

procese. În consecinţă, se creeaza impresia că cele trei procese se desfăşoară în paralel,

simultan în timp.

Exemplul 4

În fişierul DouaFireC.java se reia aplicaţia din exemplul precedent, dar s-a renunţat la

ciclurile interioare (cu contorul j), în schimb după parcurgerea fiecărui ciclu de indice i se

pune firul respectiv in aşteptare timp de 1000 milisecunde prin invocarea metodei sleep.

Această metodă aruncă excepţia InterruptedException care trebuie captată.

În mod similar s-a procedat şi în ciclul din metoda main. Având însă în vedere că metoda

main() nu se găseşte într-o clasa derivata din Thread, la invocarea metodei statice sleep a fost

necesar să se indice clasa căreia îi aparţine, deci invocarea s-a făcut sub forma

Thread.sleep(1000).

/* Crearea şi utilizarea unei clase de fire de execuţie. În metoda run a firului se foloseste metoda sleep(1000) pentru a pune firul in asteptare pe o durata de 1000 milisecunde. Similar se procedeaza in metoda main() */

class DouaFireC {

/* Clasa firelor de executie */ static class Fir extends Thread {

Fir(String numeFir) { super(numeFir); System.out.println("S-a creat firul "+getName()); }

/* Redefinirea metodei run() din clasa Thread */ public void run() { System.out.println("Incepe executarea firului "+getName()); for(int i=0; i<5; i++) { System.out.println("Firul "+getName()+" ciclul i="+i); try { sleep(1000); } catch(InterruptedException e) {}

Page 345: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

345

} } } /* incheierea clasei Fir */

public static void main(String args[]) throws Exception { Fir fir1, fir2, fir3; System.out.println("Se creeaza firele Alpha si Beta"); fir1=new Fir("Alpha"); fir2=new Fir("Beta"); System.out.println("Se pun in executie cele doua fire"); fir1.start(); fir2.start(); for (int i=0; i<5; i++) { System.out.println("main() ciclul i="+i); try { Thread.sleep(1000); } catch(InterruptedException e) {} } System.out.println("Sfarsitul metodei main()"); } /* Sfarsitul metodei main() */ }

Iată rezultatul executării acestei aplicaţii:

Se creeaza firele Alpha si Beta S-a creat firul Alpha S-a creat firul Beta Se pun in executie cele doua fire main() ciclul i=0 Incepe executarea firului Alpha Firul Alpha ciclul i=0 Incepe executarea firului Beta Firul Beta ciclul i=0 main() ciclul i=1 Firul Alpha ciclul i=1 Firul Beta ciclul i=1 main() ciclul i=2 Firul Alpha ciclul i=2 Firul Beta ciclul i=2 main() ciclul i=3 Firul Alpha ciclul i=3 Firul Beta ciclul i=3 main() ciclul i=4 Firul Alpha ciclul i=4 Firul Beta ciclul i=4 Sfarsitul metodei main()

În timp ce un fir "doarme", se pot executa alte fire, chiar dacă ele sunt de prioritate

inferioară!

Page 346: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

346

Interfaţa Runnable

Interfaţa java.lang.Runnable trebuie implementată de orice clasă care nu este descendentă a

clasei java.lang.Thread, dar ale cărei instanţe trebuie tratate ca nişte fire de execuţie.

Singura metodă a acestei interfeţe este public void run() care are acelaşi rol cu cea din clasa Thread.

Necesitatea implementării interfeţei Runnable apare atunci când dorim să creem o clasa de

fire de execuţie care nu extinde clasa Thread. Motivul ar putea fi, de exemplu, cel că clasa

nou creată, B, trebuie sa extindă o alta clasă, A, care nu este descendentă a clasei Thread Se

ştie că în Java nu există moştenire multiplă, deci clasa B nu poate avea ca superclase atât

clasa A, cât şi clasa Thread. În acest caz, vom crea o clasă B care extinde clasa A şi

implementeaza interfaţa Runnable, care conţine metoda run().

Utilizarea instanţelor claselor cu interfaţa Runnable se face, punându-le ca argumente ale

următorilor constructori ai clasei Thread: public Thread(Runnable target) public Thread(Runnable target, String name)

O instanţă a clasei Thread creată cu un astfel de constructor, se comportă ca şi cum ar fi

instanţa unei extensii a clasei Thread care ar conţine metoda run() a obiectului target cu

interfaţa Runnable.

Exemplul 1

În fişierul DouaFireAR.java se dă un exemplu de aplicaţie similară cu cea din fişierul

DouaFireA1.java, cu deosebirea că clasa Fir nu extinde clasa Thread, ci implementează

interfaţa Runnable. Fragmentele de program modificate sunt puse în evidenţa în textul sursă

de mai jos prin caractere aldine (ingroşate).

/* Crearea si utilizarea unei clase cu interfata Runnable. Se foloseste metoda yield() pentru a ceda controlul altui fir de aceeasi prioritate. Se creeaza doua fire de aceeasi prioritate (Thread.NORM_PRIORITY), utilizand ca argument al constructorului instante ale clasei Fir cu interfata Runnable. */

class DouaFireAR {

/* Clasa cu interfata Runnable */ static class Fir implements Runnable {

/* Definirea metodei run() din interfata Runnable */ public void run() { System.out.println("Incepe executarea firului "+ Thread.currentThread().getName()); for(int i=0; i<6; i++) { System.out.println("Firul "+

Page 347: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

347

Thread.currentThread().getName()+" ciclul i="+i); Thread.yield(); // cedarea controlului procesorului } } } /* incheierea clasei Fir */

public static void main(String args[]) throws Exception { Thread fir1, fir2; System.out.println("Se creeaza firul Alpha"); fir1=new Thread(new Fir(), "Alpha"); System.out.println("Se creeaza firul Beta"); fir2=new Thread(new Fir(), "Beta"); System.out.println("Se pune in executie firul Alpha"); fir1.start(); System.out.println("Se pune in executie firul Beta"); fir2.start(); System.out.println("Sfarsitul metodei main()"); } /* Sfarsitul metodei main() */ }

Comparând cu Exemplul 2 din sectiunea Clasa Thread, constatăm cele ce urmează.

- Clasa Fir nu mai extinde clasa Thread, ci implementeaza interfaţa Runnable.

- În metoda run() a clasei Fir s-a avut în vedere că aceasta nu extinde clasa Thread şi deci

nu moşteneşte metodele ecesteia. În consecinţă:

. metoda statică yield() a clasei Thread a fost invocată sub forma Thread.yield();

. pentru a obţine o referinţă la instanţa curentă a clasei Thread, necesară invocării metodei

getName(), s-a folosit metoda statică Thread.getCurrentThread().

- Crearea celor două fire de execuţie în metoda main() s-a făcut folosind un constructor al

clasei Thread, căruia i s-au dat ca parametri o instanţă a clasei Fir şi numele firului respectiv,

de exemplu: fir1=new Thread(new Fir(), "Alpha");

Dacă se compilează şi se execută această aplicaţie, se obţin exact aceleaţi rezultate ca în cazul

când s-a recurs la extinderea clasei Thread.

Exemplul 2

În fişierul Bondari.java este dat un exemplu de aplicaţie, în care se pot crea mai multe fire de

execuţie, fiecare având propria sa interfaţă grafică. Fiecare fir de execuţie este o instanţa a

clasei Bondar, care extinde clasa JFrame şi implementează interfaţa Runnable. Aplicaţia

propriu-zisă (care conţine metoda main()) este clasa Bondari, care extinde şi ea clasa

JFrame.

Fereastra principală a aplicaţiei (interfaţa clasei Bondari) conţine numai un buton cu

inscripţia "Creare nou bondar". De câte ori se apasă acest buton, se creeaza o noua instanţă a

clasei Bondar.

Clasa Bondar are propria ei interfaţă grafică, în care există două rigle pentru ajustarea

perioadei şi amplitudinii şi o fereastră în care evoluează "bondarul". Acesta este un mic

Page 348: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

348

dreptunghi roşu, a cărui mişcare o simuleaza pe cea a unei insecte în zbor. Amplitudinea, cât

şi perioada deplasărilor "bondaruliui" sunt ajustate cu cele două rigle. Dacă se acţioneaza

butonul de închidere a ferestrei "bondarului" (cel marcat cu X din colţul dreapta-sus), se

încheie ciclul de viaţă al firului de execuţie respectiv. Aceasta are loc, întrucat ciclul din

metoda run() a firului continuă cât timp variabila booleana esteViu are valoarea true.

Când se acţioneaza butonul de închidere a ferestrei "bondarului", evenimentul este captat de

metoda windowClosing() a clasei SfarsitBondar, care pune variabila esteViu a

"bondarului" respectiv la valoarea false.

Dacă se acţionează butonul de închidere a ferestrei principale (cea care conţine butonul

"Creare nou bondar"), evenimentul este captat de metoda windowClosing() a clasei Iesire,

astfel că se execută metoda exit(0). Efectul este încheierea execuţiei tuturor firelor şi

oprirea maşinii virtuale Java.

Sincronizarea firelor de execuţie

Pană în prezent, am considerat că fiecare fir (Thread) se execută independent, fără legătura cu

celelalte fire ale aceleeaşi aplicaţii. Există însă situaţii, în care este necesar să se stabilească

anumite interdependenţe între fire. Aceasta se întâmplă, în special, atunci când un fir trebuie

să folosească datele produse de alt fir: este evident că nu le poate folosi înainte ca ele să fie

produse.

În limbajul Java, sincronizarea firelor de execuţie se face prin intermediul monitoarelor. Se

numeşte monitor instanţa unei clase care conţine cel puţin o metodă sincronizată, sau o

metodă care conţine un bloc sincronizat. Se numeşte metodă sincronizată orice metodă care

conţine în antetul său modificatorul synchronized, deci este declarată sub forma

[modif]synchronized tip nume_metoda(declaratii_argumente) {corpul_metodei}

unde modif reprezinta alţi eventuali modificatori (public, static etc.).

Când un fir începe executarea uni metode sincronizate a unui monitor, el devine

"proprietarul" monitorului căruia îi aparţine această metodă (engleză: owner) şi deţine această

calitate până la încheierea executării metodei sincronizate respective, sau până când se

autosuspendă invocând metoda wait(), aşa cum vom explica ulterior. Pe toata durata cât un

fir de execuţie este proprietarul unui monitor, nici un alt fir nu poate invoca o metodă

sincronizată a monitorului respectiv. Aşa dar, orice fir care, în acest interval de timp, ar

încerca să invoce o metodă sincronizată a unui monitor al cărui proprietar este alt fir, trebuie

să aştepte până când monitorul respectiv este eliberat de proprietarul existent.

În acest fel, se evită situaţiile în care un fir de execuţie ar interveni să facă modificări asupra

unui obiect, în timp ce acesta se găseşte deja în curs de prelucrare de către un alt fir. De

exemplu, dacă un fir de execuţie efectuează ordonarea datelor dintr-un tablou, nu este corect

ca un alt fir, în acest timp, să modifice datele din acest tablou.

Page 349: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

349

Relaţia producător/consumator şi utilizarea metodelor wait(), notify() şi notifyAll()

În aplicaţiile limbajului Java, pentru sincronizarea firelor se foloseşte frecvent modelul

producător/consumator. Considerăm că un fir de execuţie "produce" anumite date, pe care le

"consumă" alt fir. Pentru efectuarea acestor operaţii folosim un monitor, care conţine atât

datele transmise, cât şi o variabilă booleană, numită variabila de condiţie a monitorului, care

indică dacă sunt disponibile date noi, puse de producator şi neutilizate de consumator. Atât

punerea de date noi, cât şi preluarea acestora se fac numai folosind metode sincronizate ale

monitorului. În corpul acestor metode sincronizate, se pot folosi metodele wait(),

notify() şi notifyAll() ale clasei Object.

Metoda public final void wait() throws InterruptedException şi variantele ei public final void wait(long timeout) throws InterruptedException public final void wait(long timeout, int nanos) throws InterruptedException

au ca efect trecerea firului de execuţie activ din starea Running în starea Waiting (vezi

schema). Metoda wait() fără argumente face această trecere pentru un timp nedefinit, în

timp ce celelalte două metode primesc ca argument intervalul de timp maxim pentru care se

face suspendarea execuţiei firului.

Metodele public final void notify() public final void notifyAll() au ca efect trecerea firului de execuţie din starea Waiting în starea Ready, astfel încât el

poate fi activat de către dispecer în momentul în care procesorul sistemului devine disponibil.

Deosebirea dintre ele este ca metoda notify() trece în starea Readyun singur fir de

execuţie dintre cele care se gasesc în momentul respectiv în starea Waiting provocată de

acest monitor (care din ele depinde de implementare), în timp ce notifyAll() le trece în

starea Ready pe toate.

Clasa monitor concepută pentru asigurarea relaţiei producător/consumator are următoarea

formă:

class NumeClasaMonitor { // declaraţii câmpuri de date ale monitorului boolean variabilaConditie=false;

[public] synchronized void puneDate(declaraţii_argumente) { if(variabila_condiţie) { try { wait(); // se asteapta folosirea datelor puse anterior } catch(InterruptedException e) { /* instrucţiuni de executat dacă a apărut o excepţie de întrerupere

*/ } } /* punerea de date noi în câmpurile de date ale monitorului */ variabilaConditie=true; // s-au pus date noi

Page 350: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

350

notify(); // se notifica punerea de noi date } // sfarsit puneDate

[public] synchronized tip preiaDate(declaratii_argumente) { if(!variabilaConditie) { try { wait(); // se aşteaptă să se pună date noi } catch(InterruptedException e) { /* Instrucţiuni de executat dacă a apărut o excepţie de întrerupere

*/ } } /* instrucţiuni prin care se folosesc datele din monitor şi se

formează valoarea_întoarsă */ variabilaConditie=false; // datele sunt deja folosite notify(); // se notifică folosirea datelor return valoarea_intoarsa; } // sfarsit preiaDate

/* Alte metode ale monitorului (sincronizate sau nesincronizate) */ } // sfarsit clasa monitor

Iniţial, variabila variabilaConditie a monitorului are valoarea false, întrucat -

deocamdată - nu există date noi.

Dacă firul de execuţie producător a ajuns în starea, în care trebuie să pună în monitor date

noi, el invocă metoda sincronizată puneDate, devenind astfel proprietar (owner) al

monitorului. În această metodă, se verifică, în primul rând, valoarea variabilei

variabilaConditie. Dacă această variabilă are valoarea true, înseamnă că în monitor

există deja date noi, înca nefolosite de consumator. În consecinţă, se invocă metoda wait() şi

firul de execuţie monitor este suspendat, trecând în starea Waiting, astfel că el încetează să

mai fie proprietar (owner) al monitorului. Dacă un alt fir (în cazul de faţă consumatorul)

invocă o metodă sincronizată a aceluiaşi monitor care, la rândul ei, invocă metoda notify()

sau notifyAll(), firul pus în aşteptare anterior trece din starea Waiting în starea Ready şi,

deci, poate fi reactivat de către dispecer. Dacă variabila variabilaConditie are valoarea

false, firul producător nu mai intră în aşteptare, ci execută instrucţiunile prin care modifică

datele monitorului, după care pune variabilaConditie la valoarea true şi se invocă

metoda notify() pentru a notifica consumatorul că exista date noi, după care se încheie

executarea metodei puneDate.

Funcţionarea firului de execuţie consumator este asemănătoare, dar acesta invocă metoda

preiaDate. Executând această metodă, se verifică mai întâi dacă variabilaConditie are

valoarea false, ceeace înseamnă că nu există date noi. În această situaţie, firul consumator

intră în aşteptare, până va primi notificarea că s-au pus date noi. Dacă, însă,

variabilaConditie are valoarea true, se folosesc datele monitorului, după care se pune

variabilaConditie la valoarea false, pentru a permite producătorului să modifice datele şi

se invocă metoda notify() pentru a scoate producătorul din starea de aşteptare.

Este foarte important să avem în vedere că metoda puneDate este concepută pentru a fi

invocată de firul producător, în timp ce metoda preiaDate este concepută pentru a fi

invocată de către firul consumator. Numele folosite aici atât pentru clasa monitor, cât şi

pentru metodele acesteia şi variabila de condiţie sunt convenţionale şi se aleg de către

Page 351: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

351

programator, din care cauză au fost scrise în cele de mai sus cu roşu cursiv.

Exemplul 1

În fişierul Sincro.java se dă un exemplu de aplicaţie în care se sincronizeaza două fire de

execuţie folosind modelul producător/consumator. Pentru a uşura citirea programului, clasele

au fost denumite chiar Producator, Consumator şi Monitor, dar se puteau alege, evident, orice

alte nume. Firul de execuţie prod, care este instanţa clasei Producator, parcurge un număr de

cicluri impus (nrCicluri), iar la fiecare parcurgere genereaza un tablou de numere aleatoare,

pe care îl depune în monitor. Firul de execuţie cons, care este instanţă a clasei Consumator,

parcurge acelaşi număr de cicluri, în care foloseşte tablourile generate de firul prod.

Transmiterea datelor se face prin intermediul monitorului monit, care este instanţă a clasei

Monitor. Această clasă conţine tabloul de numere întregi tab şi variabila de condiţie

valoriNoi, care are iniţial valoarea false, dar primeşte valoarea true atunci când

producătorul a pus în monitor date noi şi primeşte valoarea false, atunci când aceste date au

fost folosite de consumator. Pentru punerea de date noi în monitor, producătorul invocă

metoda sincronizată puneTablou. Pentru a folosi datele din monitor, consumatorul invocă

metoda sincronizată preiaTablou. Fiecare din aceste metode testează valoarea variabilei de

condiţie valoriNoi şi pune firul de execuţie curent în aşteptare, dacă valoarea acestei

variabile nu este corespunzătoare. După ce s-a efectuat operaţia de punere/utilizare a datelor,

metoda sincronizată prin care s-a făcut această operaţie invocă metoda notify(). Dacă ar fi

putut exista mai multe fire în starea Waiting, era preferabil sa se invoce metoda

notifyAll().

class Sincro { Producator prod; Consumator cons; Monitor monit; int nrCicluri;

/* Clasa Producator. Producatorul genereaza un tablou de date si il pune in monitor pentru a fi transmis consumatorului */ class Producator extends Thread { public void run() { System.out.println("Incepe executarea firului producator"); for (int i=0; i<nrCicluri; i++) { int n=((int)(5*Math.random()))+2; int tab[]=new int[n]; for(int j=0; j<n; j++) tab[j]=(int)(1000*Math.random()); monit.puneTablou(tab); System.out.print("Ciclul i="+i+" S-a pus tabloul: "); for(int j=0; j<n; j++) System.out.print(tab[j]+" "); System.out.println(); } System.out.println("Sfarsitul executiei firului Producator"); } } /* Sfarsitul clasei Producator */

/* Clasa Consumator. Consumatorul foloseste (in cazul de fata doar afiseaza) datele preluate din monitor

Page 352: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

352

*/ class Consumator extends Thread { public void run() { System.out.println("Incepe executarea firului Consumator"); int tab[]; for(int i=0; i<nrCicluri; i++) { tab=monit.preiaTablou(); System.out.print("Ciclul i="+i+ " s-a preluat tabloul "); for(int j=0; j<tab.length; j++) System.out.print(tab[j]+" "); System.out.println(); } System.out.println("Sfarsitul executiei firului Consumator"); } } /* Sfarsitul clasei Consumator */

/* Clasa Monitor. Monitorul contine date si metode folosite in comun de Producator si Consumator. In acest scop, producatorul si consumatorul folosesc metodele sincronizate ale monitorului */ class Monitor { int tab[]; // tabloul de date care se transmit boolean valoriNoi=false; // variabila de conditie a monitorului

/* Metoda prin care producatorul pune date in monitor */ public synchronized void puneTablou(int tab[]) { if(valoriNoi) { try { wait(); // se asteapta sa fie folosite datele puse anterior } catch(InterruptedException e) {} } this.tab=tab; // se modifica tabloul tab din monitor valoriNoi=true; // monitorul contine date noi notify(); // se notifica consumatorul ca s-au pus date noi }

/* Metoda prin care consumatorul preia datele din monitor */ public synchronized int[] preiaTablou() { if(!valoriNoi) { try { wait(); // se asteapta sa se puna date noi } catch(InterruptedException e) {} } valoriNoi=false; // datele puse anterior au fost folosite notify(); // se notifica producatorul ca datele au fost preluate return tab; } } /* Sfarsitul clasei Monitor */

public Sincro(int numarCicluri) { nrCicluri=numarCicluri; prod=new Producator(); cons=new Consumator(); monit=new Monitor(); prod.start(); cons.start();

Page 353: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

353

}

public static void main(String args[]) { int numarCicluri=8; System.out.println("Incepe executarea metodei main()"); Sincro sinc=new Sincro(numarCicluri); System.out.println("Sfarsitul metodei main()"); } }

Referitor la acest program, remarcăm urmatoarele:

- instrucţiunile care constituie subiectul acestei lecţii au fost puse în evidenţă prin îngrosare;

- metodele run() din clasele Producător şi Consumator sunt scrise ca şi când ele s-ar

executa în mod independent, însă sincronizarea firelor se face prin invocarea metodelor

sincronizate puneTablou şi preiaTablou ale clasei Monitor; în aceste metode, sincronizarea

se face folosind variabila de condiţie booleană dateNoi şi invocând în mod corespunzător

metodele wait() şi notify().

Iată un exemplu de executare a acestei aplicaţii:

Incepe executarea metodei main() Sfarsitul metodei main() Incepe executarea firului producator Ciclul i=0 S-a pus tabloul: 827 789 Incepe executarea firului Consumator Ciclul i=1 S-a pus tabloul: 464 312 Ciclul i=0 s-a preluat tabloul 827 789 Ciclul i=2 S-a pus tabloul: 455 995 271 40 583 Ciclul i=1 s-a preluat tabloul 464 312 Ciclul i=3 S-a pus tabloul: 581 193 9 635 Ciclul i=2 s-a preluat tabloul 455 995 271 40 583 Ciclul i=4 S-a pus tabloul: 621 164 215 Ciclul i=3 s-a preluat tabloul 581 193 9 635 Ciclul i=5 S-a pus tabloul: 554 626 791 444 Ciclul i=4 s-a preluat tabloul 621 164 215 Ciclul i=6 S-a pus tabloul: 204 961 Ciclul i=5 s-a preluat tabloul 554 626 791 444 Ciclul i=7 S-a pus tabloul: 476 692 Sfarsitul executiei firului producator Ciclul i=6 s-a preluat tabloul 204 961 Ciclul i=7 s-a preluat tabloul 476 692 Sfarsitul executiei firului Consumator

Se observă că, deşi cele două fire se derulează în mod autonom, exista între ele o sincronizare

corectă, în sensul că datele puse de producător la un ciclu cu un anumit indice, sunt preluate

de consumator la ciclul cu acelaşi indice (de exemplu datele puse de producator în ciclul 3

sunt luate de consumator tot în ciclul 3). Aşa dar, nu există date pierdute sau preluate de două

ori.

Page 354: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

354

Exemplul 2

În fişierul Bondari1.java se dă un exemplu de aplicaţie cu interfaţă grafică, în care există trei

fire de execuţie (în afară de cel al metodei main()): două fire din clasa Bondar, care

calculeaza fiecare mişcările unui "bondar", şi un fir de executie din clasa Fereastră, care

reprezintă grafic mişcările celor doi bondari. În acest caz, ambii "bondari" se mişca în aceeaşi

fereastră. Pentru că fiecare din acestea extinde câte o clasa de interfaţă grafică (respectiv

clasele JPanel şi Canvas), pentru realizarea firelor de execuţie s-a folosit interfaţa Runnable.

Cele două fire "bondar" (respectiv fir1 şi fir2) au rolul de producător, iar firul care conţine

fereastra de afişare (respectiv fir3) are rolul de consumator. Rolul monitorului este îndeplinit

de instanţa clasei CutiePoştală, care nu conţine decât variabila de condiţie a monitorului

valoareNoua şi două metode sincronizate amPus şi amLuat. Având în vedere că există

posibilitatea ca, la un moment dat, să existe în starea Waiting mai multe fire de aşteptare care

trebuie reactivate, în aceste metode s-a folosit invocarea notifyAll() în loc de notify().

Dacă se execută această aplicaţie se poate vedea cum cei doi "bondari" evoluează în mod

independent în aceeaşi fereastră, putându-se ajusta în mod independent perioada şi

amplitudinea fiecăruia.

Întrebări

Nivel 1

1. Ce este un proces (în general)?

2. Cum se defineşte procesul în informatică?

3. Ce se înţelege prin multitasking?

4. Ce sunt firele de execuţie?

5. Ce se înţelege prin multithreading?

6. În ce moduri se poate programa o clasă de fire de execuţie?

7. Ce este clasa Thread?

8. Care sunt principalele metode ale clasei Thread?

9. La ce serveşte metoda run() a clasei Thread?

10. În ce mod este invocată metoda run() a clasei Thread?

11. Ce este interfaţa Runnable şi la ce foloseşte?

12. În ce stare se găseşte firul de execuţie imediat după ce el a fost creat?

13. În ce clasă există metodele wait(), notify() şi notifyAll() şi la ce folosesc ele?

14. Ce metode conţine interfaţa Runnable?

15. Cum se creeaza un fir de execuţie folosind un obiect cu interfaţa Runnable?

Nivel 2

1. Ce sunt procesele paralele?

2. Ce sunt procesele concurente?

3. În ce situaţii şi cum se iau în consideraţie priorităţile proceselor?

Page 355: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

355

4. Ce se înţelege prin partajarea timpului?

5. Ce fire de execuţie există obligatoriu în timpul funcţionării maşinii virtuale Java?

6. Ce este un demon?

7. În ce stare trece firul de execuţie după invocarea metodei start()?

8. La ce serveşte metoda sleep() şi în ce stare trece firul de execuţie la invocarea ei?

9. Prin ce metodă se modifică prioritatea unui fir de execuţie?

10. Care este prioritatea implicită a unui fir de execuţie?

11. În ce stare trece firul de execuţie în timpul executării unei operaţii de intrare/ieşire?

12. În ce stare trece firul de execuţie după ce a invocat metoda wait()?

13. În ce stare trece firul de execuţie după ce a expirat intervalul de "somn" dat prin

metoda sleep()?

14. În ce stare trece un fir de execuţie blocat după ce s-a încheiat operaţia de intrare/ieşire

solicitată?

15. Când se încheie executarea unui fir de execuţie şi în ce stare trece el în acest caz?

16. Dece este necesară sincronizarea firelor de execuţie?

17. Cum se sincronizează firele de execuţie în Java?

18. Ce este un monitor?

19. Ce este o metodă sincronizată şi la ce foloseşte?

20. În ce situaţie firul de execuţie devine proprietarul unui monitor?

21. Ce se întamplă în timpul cât un fir de execuţie este proprietarul unui monitor?

22. Cum se realizează sincronizarea între un fir de execuţie producător şi unul

consumator?

23. La ce serveşte variabila de condiţie a monitorului?

24. În ce fel de metode se pot invoca metodele wait(), notify() şi notifyAll()?

25. Care este efectul invocării metodei notify()?

26. Care este efectul invocării metodei notifyAll()?

Page 356: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

356

Index de clase şi de interfeţe

În acest index sunt cuprinse rezumate ale descrierilor de clase şi interfete din Java API care

sunt folosite în acest curs practic. În Java API există mult mai multe pachete, clase şi interfeţe

decât se prezintă aici. Descrierile complete ale tuturor claselor şi interfetelor pot fi găsite în

documentaţia Java API la următoarele adrese:

java.sun.com/j2se/1.4/docs/api/ - la firma Sun Microsystems;

http://lib.cs.ugal.ro/java/jdk140/api/index.html - pe intranetul Catedrei de Calculatoare si

Informatica Aplicata al Universităţii "Dunărea de Jos" din Galaţi

Pachetul java.lang

Clase

Byte - clasă acoperitoare pentru tipul byte - v.cap.4

Boolean - clasă acoperitoare pentru tipul boolean – v. cap.4

Character - clasă acoperitoare pentru tipul char – v.cap.4

Class - clasa claselor – v.cap.4

Double - clasă acoperitoare pentru tipul double – v.cap.4

Float - clasă acoperitoare pentru tipul float – v. cap.4

Integer - clasă acoperitoare pentru tipul int – v. cap.4

Long - clasă acoperitoare pentru tipul long – v. cap.4

Math - clasă care oferă metode pentru calcularea funcţiilor matematice uzuale – v.cap.4 şi

completarea din acest index, pag. 361

Number - clasă abstractă, rădăcina claselor acoperitoare numerice – v. cap.4

Object - rădăcina ierarhiei de clase Java (un obiect oarecare) – v.cap.4 şi completarea din

acest index pag. 363

Short - clasa acoperitoare pentru tipul short – v.cap.4

String - clasa şirurilor de caractere nemodificabile - v.cap.4 şi completarea din acest index

pag. 364 StringBuffer - clasa şirurilor de caractere modificabile (instanţa este o zonă tampon care

conţine un şir modificabil) – v. cap.4 şi completarea din acest index pag. 369

System - clasa sistemului de execuţie – v. cap.4

Thread - clasa firelor de execuţie – v.cap.12

Void - clasă acoperitoare pentru tipul void – v.cap.4

Interfeţe

Cloneable - implementată de clasele pentru care se poate folosi metoda clone() din clasa

Object. Nu contine metode.

Comparable - implementată de clasele ale căror instanţe sunt comparabile între ele

(formează o mulţime ordonată). – v. specificatia de la pag. 372

Runnable - implementată de clasele, ale căror instanţe pot fi rulate ca fire de execuţie. –

v.cap.12.

Pachetul java.io

Conţine clase şi interfeţe necesare pentru operaţiile de intrare/ieşire (input/output - io).

Page 357: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

357

Clase

(ierarhiile de clase de intrare/ieşire sunt prezentate în cap.11, secţiunea pachetul java.io din

acest manual)

BufferedInputStream - clasa fluxurilor de intrare de octeţi, cu zonă tampon – v. cap.11 si

completarea de la pag.373

BufferedOutputStream - clasa fluxurilor de ieşire de octeţi, cu zonă tampon – v.cap.11 şi

completarea de la pag. 373.

BufferedReader - clasa fluxurilor de intrare de caractere, cu zonă tampon – v.cap.11 şi

completarea de la pag. 374.

BufferedWriter - clasa fluxurilor de ieşire de caractere, cu zonă tampon – v.cap.11 şi

completarea de la pag. 374.

ByteArrayInputStream - clasa fluxurilor care citesc dintr-un tablou de octeţi situat în

memoria internă + v.cap.11 şi completarea de la pag. 374.

ByteArrayOutputStream - clasa fluxurilor care scriu într-un tablou de octeţi situat în

memoria internă + v.cap.11 şi completarea de la pag. 374.

CharArrayReader - clasa fluxurilor care citesc dintr-un tablou de caractere situat în

memoria internă – v. cap.11 şi pag. 376.

CharArrayWriter - clasa fluxurilor care scriu într-un tablou de caractere situat în memoria

internă – v. cap.11 şi pag.376

DataInputStream - clasa fluxurilor de octeţi de intrare pentru date - v. cap.11

DataOutputStream - clasa fluxurilor de octeţi de ieşire de date – v. cap.11

File - clasă ale cărei instanţe conţin informaţii despre fişiere – v. cap.11

FileDescriptor - clasa descriptorilor de fişiere – v. cap.11 şi pag.377

FileInputStream - clasa fluxurilor de octeţi de intrare din fişiere (clasa fişierelor deschise

pentru intrare) – v. cap.11

FileOutputStream - clasa fluxurilor de octeţi de ieşire în fişiere (clasa fişierelor deschise

pentru ieşire) – v. cap.11.

FileReader - clasa fluxurilor de caractere de citire din fişiere – v. cap.11

FileWriter - clasa fluxurilor de caractere de scriere în fişiere – v. cap.11

FilterInputStream - clasa fluxurilor de intrare de octeţi cu filtru – v. cap.11 şi pag. 377.

FilterOutputStream - clasa fluxurilor de ieşire de octeţi cu filtru – v.cap.11 şi pag. 378.

FilterReader - clasa flucurilor de intrare de caractere cu filtru – v. cap.11 şi pag. 378.

FilterWriter - clasa flucurilor de ieşire de caractere cu filtru – v. cap.11 şi pag.378.

InputStream - clasa fluxurilor de intrare de octeţi – v. cap.11

ObjectInputStream - clasa fluxurilor de intrare de obiecte – v. cap.11

ObjectOutputStream - clasa fluxurilor de ieşire de obiecte – v. cap.11

OutputStream - clasa fluxurilor de ieşire de octeţi – v. cap.11

PrintStream - clasa fluxurilor de imprimare de octeţi – v. cap.11

PrintWriter - clasa fluxurilor de imprimare de caractere – v. cap.11

RandomAccessFile - clasa fişierelor cu acces direct (acces aleator). – v. cap.11

Reader - clasa fluxurilor de intrare de caractere – v. cap.11

Writer - clasa fluxurilor de ieşire de caractere – v. cap.11

Interfeţe

Serializable - interfaţă pe care trebuie să o aibă obiectele serializabile (care pot fi scrise cu

ObjectOutputStream şi citite cu ObjectInputStream) – v. cap.11

Page 358: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

358

Pachetul java.util

Clase

EventObject - clasa obiectelor care conţin informaţii despre evenimente – v. cap. 7 şi pag.

379

Interfeţe

EventListener - interfaţă generică pentru ascultătoarele de evenimente. – v. cap.7 şi pag. 379

Pachetul java.awt

Clase

AWTEvent - superclasa ascultătoarelor de evenimente generate de componentele interfeţei

grafice – v. cap.7 şi pag. 380.

BorderLayout - gestionar de poziţionare – v. cap.7 şi pag. 381.

Button - clasa butoanelor simple – v. cap.8 şi pag. 382.

Canvas - clasă specială de componente pe care se trasează desene - v. cap.9 şi pag. 383

CardLayout - gestionar de poziţionare – v. cap. 7 şi pag. 383

Color - clasa culorilor – v. cap.9 şi pag. 384

Component - superclasa tuturor claselor de componente ale interfeţei grafice. – v. cap.7 şi

pag. 387 Container - clasa containerelor (componente care conţin alte componente) – v. cap.7 şi pag.

393.

Dialog - clasa ferestrelor de dialog + v. cap.9 şi pag. 394.

Dimension - dimensiunile unei componente – v. cap.9 şi pag. 396.

Event - clasa evenimentelor din JDK1.0 (înlocuită acum prin clasa AWTEvent) – v. cap.7 şi

pag. 396.

FlowLayout - gestionar de poziţionare – v. cap.7 şi pag. 397.

Font - clasa fonturilor – v. cap.9 şi pag. 398.

Frame - clasa ferestrelor principale ale aplicaţiilor. – v. cap.7 şi pag. 399.

Graphics - clasa contextelor grafice simple – v. cap.9

Graphics2D - clasa contextelor grafice 2D – v. cap.9 şi pag. 401.

GridBagLayout - gestionar de poziţionare – v. cap.7 şi pag. 401.

GridLayout - gestionar de poziţionare – v. cap.7 şi pag. 401.

Insets - clasa inserţiilor (marginilor libere ale containerelor) + v. pag. 402.

Panel - clasa panourilor – v. cap.7 şi pag. 402.

Point - clasa punctelor – v. pag. 403.

Rectangle - clasa dreptunghiurilor – v. pag. 404.

Window - clasa ferestrelor. + v. cap.7 şi pag. 405.

Interfeţe

LayoutManager - interfaţă pentru clsasele de gestionare a poziţionării – v. cap.7 şi pag. 406

LayoutManager2 - interfaţă pentru clasele de gestionare a poziţionării cu restricţii – v. cap.7

şi pag. 407.

Page 359: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

359

Pachetul java.awt.event

Clase

ActionEvent - eveniment de acţiune – v. cap.8 şi pag. 408.

AdjustementEvent - eveniment de ajustare – v. cap.8 şi pag. 408.

ComponentAdapter - adaptor pentru ascultătoarele de evenimente de componentă.- v.cap.8

şi pag. 409.

ComponentEvent - eveniment de componentă – v.cap.8 şi pag. 409.

InputEvent - clasă abstractă. Rădăcina ierarhiei claselor de evenimente de intrare – v.cap.7 şi

pag.410.

ItemEvent - eveniment de articol (selectare sau deselectare) – v.cap.8 şi pag.411.

KeyAdapter - adaptor pentru ascultarea evenimentelor de tastă – v.cap.7 şi pag.411.

KeyEvent - eveniment de tastă – v.cap.7 şi pag.412.

MouseAdapter - adaptor pentru ascultarea evenimentelor de mouse – v.cap.7 şi pag.416.

MouseEvent - eveniment de mouse – v.cap.7 şi pag.416.

MouseMotionAdapter - adaptor pentru ascultarea evenimentelor de mişcare a mouse-ului –

v.cap.7 şi pag.417.

TextEvent - eveniment de text - v.cap.8 şi pag.417.

WindowAdapter - adaptor pentru ascultarea evenimentelor de fereastră – v.cap.7 şi pag.418.

WindowEvent - eveniment de fereastră - v. cap.7 şi pag.418.

Interfeţe

ActionListener - interfaţă pentru ascultătoarele de evenimente de acţiune – v.cap.8 şi

pag.419 AdjustmentListener - interfaţă pentru ascultătoarele de evenimente de ajustare – v.cap.8 şi

pag.420.

ComponentListener - interfaţă pentru ascultătoarele de evenimente de componentă – v.cap.8

şi pag.420.

ItemListener - interfaţă pentru ascultătoarele de evenimente de articol – v.cap.8 şi pag.421.

KeyListener - interfaţă pentru ascultătoare de evenimente de tastă – v.cap.7 şi pag.421.

MouseListener - interfaţă pentru ascultătoare de evenimente de mouse v.cap.7 şi pag.421.

MouseMotionListener - interfaţă penteru ascultătoare de evenimente de mişcare a mouse-

ului – v.cap.7 şi pag.422.

TextListener - interfaţă pentru ascultătoare de evenimente de text – v.cap.8 şi pag.422.

WindowListener - interfaţă pentru ascultătoare de evenimente de fereastră – v.cap.7 şi

pag.423

Pachetul javax.swing

Clase

AbstractButton - clasă abstractă. Superclasa claselor de butoane – v.cap.8 şi pag. 423.

BorderFactory - clasă care permite producerea de borduri pentru componentele Swing – v.

cap.8.

Box - container sub formă de casetă – v. cap.8.

Box.Filler - clasa componentelor invizibile, folosite pentru distanţare în instanţele clasei

Box + v. cap.8 şi pag.425.

BoxLayout - gestionar de poziţionare în casetă – v. cap.7.

Page 360: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

360

ButtonGroup - clasa grupurilor de butoane – v.cap.8 şi pag.426.

JApplet - clasa applet-urilor din Swing – v.cap.10 şi pag. 426.

JButton - clasa butoanelor – cap.8 şi pag.427.

JCheckBox - clasa casetelor de validare – v. cap.8.

JCheckBoxMenuItem - clasa articolelor de meniu cu casetă de validare – v. cap.8 şi

pag.427. JColorChooser - clasa selectorului de culori + v.cap.9.

JComboBox - clasa listelor ascunse – v. cap.8.

JComponent - rădăcina ierarhiei de clase de componente Swing – v.cap.8 şi pag.428.

JDialog - clasa ferestrelor de dialog – v.cap.9 şi pag.430.

JEditorPane - clasă pentru editoare de text formatat – v.cap.8 şi pag.432.

JFileChooser - clasa selectoarelor de fişiere – v.cap.8 şi pag.432.

JFrame - clasă folosită în special pentru ferestrele principale ale aplicaţiilor – v.cap.7 şi

pag.433.

JLabel - clasa etichetelor (componente de afişare needitabile) + v.cap.8 şi pag.435.

JList - clasa listelor afişabile în interfaţa grafică – v. cap.8.

JMenu - clasa meniurilor – v. cap.8 şi pag.436.

JMenuBar - clasa barelor de menu – v. cap.8 şi pag.437.

JMenuItem - clasa articolelor de meniu – v. cap.8 şi pag.438.

JOptionPane - clasă cu metode pentru realizarea unor ferestre de dialog standard – v. cap.9

şi pag.439.

JPanel - clasa panourilor (containere simple) – v.cap.7 şi pag.441.

JPasswordField - clasa câmpurilor pentru introducerea parolei – v. cap.8 şi pag.441.

JPopupMenu - clasa meniurilor volante (meniuri pop-up) – v. cap.8.

JProgressBar - clasa barelor de progres – v. cap.8 şi pag.442.

JRadioButton - clasa butoanelor radio – v. cap.8.

JRadioButtonMenuItem - clasa articolelor de meniu cu buton radio – v. cap.8 şi pag.443.

JScrollBar - clasa barelor de defilare – v. cap.8 şi pag. 444.

JScrollPane - clasa panourilor cu bare de defilare – v. cap.7 şi pag.445.

JSeparator - clasa separatoarelor de meniu v. cap.8 şi pag.446.

JSlider - clasa riglelor cu cursor – v. cap.8.

JSplitPane - clasa panourilor care pot fi scindate - v. cap.7 şi pag.447.

JTabbedPane - clasa panourilor tabulate – v. cap.8 şi pag.448.

JTable - clasa tabelelor – v. cap.8 şi pag. 450.

JTextArea - clasa ariilor de text – v. cap.8.

JTextField - clasa câmpurilor de text – v. cap.8.

JTextPane - clasă pentru editoare de text stilizat – v. cap.8 şi pag.450.

JToggleButton - superclasa butoanelor cu două stări stabile – v. cap.8 şi pag.451

JWindow - clasa ferestrelor – v. cap.7 şi pag. 451.

Pachetul javax.swing.event

Clase

ChangeEvent - eveniment de schimbare a stării sursei – v. cap.7 şi pag.452.

ListDataEvent - eveniment de modificare a datelor dintr-o listă – v.cap.8 şi pag.452.

ListSelectionEvent - clasa evenimentelor de selectare a articolelor de listă v.cap.8 şi pag.453

MenuEvent - clasa evenimentelor de meniu – v. cap.8 şi pag.453.

MouseInputAdapter - adaptor pentru ascultătoarele de evenimente de mouse – v. cap.7 şi

Page 361: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

361

pag.454.

PopupMenuEvent - clasa evenimentelor generate de meniuri pop-up – v.cap.8 şi pag.454.

Interfeţe

ChangeListener - ascultător de evenimente de schimbare a stării – v.cap.7 şi pag.454.

ListDataListener - ascultător de evenimente de modificare a conţinutului unei liste – v.cap.8

şi pag.455.

ListSelectionListener - ascultător de evenimente de modificare a articolelor selectate dintr-o

listă – v. cap.8 şi pag.455.

MenuListener - ascultător al evenimentelor de meniu – v. cap.8 şi pag.455.

MouseInputListener - ascultător de mouse - v. cap.7 şi pag.456.

PopupMenuListener - ascultător al evenimentelor de meniu pop-up v. cap.8 şi pag.456.

Page 362: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

362

Completări la descrierea claselor şi interfeţelor

Clasa Math

public final class Math extends Object

Clasa Math contine metode statice pentru calcularea unor functii matematice uzuale, cum

sunt functiile trigonometrice, radacina patrata si altele.

Campuri:

public static final double E - numarul e (baza logaritmilor naturali);

public static final double PI - numarul pi (raportul dintre circumferinta cercului si

diametru).

Metode:

public static double sin(double a)- intoarce sinusul trigonometric sin a, unde unghiul

a este in radiani.

public static double cos(double a)- intoarce cosinusul trigonometric cos a, unde

unghiul a este in radiani;

public static double tan(double a)- intoarce tangenta trigonometrica tg a, unde

unghiul a este in radiani;

public static double asin(double a)- intoarce arcsin a in intervalul [-pi/2, pi/2];

public static double acos(double a)- intoarce arccos a in intervalul [0.0, pi];

public static double atan(double a)- intoarce arctg a in intervalul [-pi/2, pi/2];

public static double toRadians(double angdeg)- converteste argumentul angDeg din

grade in radiani;

public static double toDegrees(double angrad)- converteste argumentul angrad din

radiani in grade;

public static double exp(double a)- calculeaza functia exponentiala ea;

public static double log(double a)- calculeaza logaritmul natural ln a;

public static double sqrt(double a)- calculeaza radacina patrata a argumentului a.

Daca argumentul este negativ sau NaN, rezultatul este NaN.

public static double IEEEremainder(double f1, double f2)- calculeaza restul

impartirii f1/f2 conform prescriptiilor standardului IEEE 754. Restul este egal matematic cu

Page 363: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

363

valoarea expresiei f1-f2*n, unde n este numarul intreg cel mai apropiat de valoarea exacta a

raportului f1/f2. Daca restul este zero, el are semnul primului argument.

public static double ceil(double a)- intoarce, sub forma de valoare double, cel mai

mic numar intreg care nu este mai mic decat argumentul (rotunjire prin adaos);

public static double floor(double a)- intoarce, sub forma de valoare double, cel

mai mare numar intreg care nu este mai mare decat argumentul (rotunjire prin micsorare);

public static double rint(double a)- intoarce, sub forma de valoare double, numarul

intreg cel mai apropiat de argument;

public static double atan2(double a, double b)- calculeaza arctg(a/b) in intervalul

[-pi, pi] tinand seama de semnele argumentelor a si b (se considera ca se calculeaza

argumentul theta la conversia din coordonate carteziene (b, a) in coordonate polare (r,

theta)).

public static double pow(double a, double b)- calculeaza ab. Daca (a==0 si b<=0)

sau daca (a<=0 si b nu este un numar intreg) se genereaza o exceptie aritmetica.

public static int round(float a)- se intoarce numarul intreg cel mai apropiat de

argument. Daca acest intreg este mai mic decat marginea inferioara pentru tipul int, rezultatul

este Integer.MIN_VALUE. Daca acest intreg este mai mare decat marginea superioara pentru

tipul int, se obtine rezultatul Integer.MAX_VALUE.

public static long round(double a)- intoarce numarul intreg cel mai apropiat de

argument (cu aceleasi observatii ca la metoda precedenta).

public static double random()- intoarce un numar pseudoaleator in intervalul [0.0, 1.0],

avand o lege de repartitie (aproximativ) uniforma in acest interval.

public static int abs(int a)- intoarce modului argumentului a (valoarea absoluta);

public static long abs(long a)- intoarce modului argumentului a (valoarea absoluta);

public static float abs(float a)- intoarce modulul argumentului a (valoarea

absoluta);

public static double abs(double a)- intoarce modulul argumentului a (valoarea

absoluta);

public static int max(int a, int b)- intoarce cel mai mare din cele doua argumente;

public static long max(long a, long b)- intoarce cel mai mare din cele doua

argumente;

public static float max(float a, float b)- intoarce cel mai mare din cele doua

argumente;

Page 364: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

364

public static double max(double a, double b)- intoarce cel mai mare din cele doua

argumente;

public static int min(int a, int b)- intoarce cel mai mic din cele doua argumente;

public static float min(float a, float b)intoarce cel mai mic din cele doua

argumente;

public static double min(double a, double b)intoarce cel mai mic din cele doua

argumente;

Class Object

java.lang.Object

--------------------------------------------------------------------------------

public class Object

Clasa Object este radacina ierarhiei de clase Java. Orice alta clasa ore clasa Object ca

superclasa. Toate celelalte clase, inclusiv tablourile, implementeaza metodele acestei clase ---

-----------------------------------------------------------------------------

Constructor:

public Object()

Metode:

protected Object clone()

Creaza si intoarce o copie a acestui obiect.

public boolean equals(Object obj)

Indica daca acest obiect este sau nu "egal cu" obiectul obj primit ca argument.

protected void finalize() Este apelata de colectorul de reziduuri atunci cand acesta constata ca nu mai exista

referinte la obiectul respectiv.

public Class getClass() Intoarce clasa caruia ii apartine obiectul.

public int hashCode() Intoarce codul de dispersie al obiectului

public void notify() Notifica un singur fir de executie dintre cele care asteapta acest obiect.

Page 365: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

365

public void notifyAll() Notifica toate firele de executie care asteapta acest obiect

public String toString()

Intoarce reprezentarea sub forma de String a acestui obiect.

public void wait() Pune firul de executie curent in asteptare, pana cand alt fir de executie invoca metoda

notify sau notifyAll() pentru acest obiect.

public void wait(long timeout) Pune firul de executie curent in asteptare, pana cand alt fir de executie invoca metoda

notify sau notifyAll() pentru acest obiect, sau pana cand exprira intervalul de timp dat

timeout dat ca argument. Timpul este exprimat in milisecunde.

public void wait(long timeout, int nanos) Pune firul de executie curent in asteptare, pana cand alt fir de executie invoca metoda

notify sau notifyAll() pentru acest obiect, sau pana cand exprira intervalul de timp dat

timeout dat ca argument, sau pana cand alt fir de asteptare il intrerupe pe cel curent. Timpul

de asteptare, exprimat in nanosecunde, este in acest caz 1000000*timeout+nanos, unde

nanos este un intreg in intervalul 0..999999.

Clasa String

public final class String extends Object implements Serializable, Comparable

Instantele clasei String sunt siruri de caractere. Orice literal sir in limbajul Java, de exemplu

"abc", este un astfel de obiect. Sirurile sunt constante, deci continutul lor nu poate fi

modificat. Pentru a obtine siruri modificabile se va folosi clasa StringBuffer.

Nota: amintim ca in limbajul Java reprezentarea interna a caracterelor se face pe 16 biti, in

Unicode.

Campuri: public static Comparator CASE_INSENSITIVE_ORDER

Campul contine un Comparator care ordoneaza obiectele-sir cand ele sunt comparate

cu metoda comparetoIgnoreCase().

Constructori:

public String()

Creeaza un sir vid.

public String(byte[] bytes) Creeaza un obiect al clasei String care contine caracterele din tabloul de octeti primit ca

argument. Se considera ca in acest tablou caracterele sunt reprezentate pe 8 biti, in codul

local valabil pe calculatorul pe care se executa programul. Daca referinta la tablou este nula

se genereaza o NullPointerException.

Page 366: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

366

public String(byte[] bytes, int offset, int length) Actioneaza similar cu constructorul precedent, cu observatia ca se preiau din tabloul

bytes numai length octetii de pe pozitiile care incep de la indicele offset. Pot fi generate

NullPointerException daca referinta la tablou este nula, sau o

IndexOutOfBoundsException daca indicii sunt gresiti.

public String(byte[] bytes, int offset, int length, String enc)

Actioneaza similar cu constructorul precedent, dar la conversia din octet in Unicode se

foloseste sistemul de codificare a caracterelor enc. Pot fi generate NullPointerException

daca referinta la tablou este nula, sau o IndexOutOfBoundsException daca indicii sunt

gresiti,sau UnsupportedEncodingException daca argumentul enc este gresit.

public String(byte[] bytes, String enc)

Construieste un sir care contine caracterele din tabloul de octeti bytes. Se considera ca

in acest tablou caracterele sunt reprezentate in codul enc. Se genereaza

NullPointerException daca referinta la tablou este nula, sau

UnsupportedEncodingException daca argumentul enc este gresit..

public String(char[] value)

Construieste un sir care contine caracterele din tabloul de caractere value. Se

genereaza NullPointerException daca referinta la tablou este nula.Pot fi generate

NullPointerException daca referinta la tablou este nula, sau o

IndexOutOfBoundsException daca indicii sunt gresiti.

public String(char[] value, int offset, int count)

Actioneaza similar cu constructorul precedent, dar preia din tabloul value numai

count caractere, incepand cu cel de pe pozitia offset. Pot fi generate

NullPointerException daca referinta la tablou este nula, sau o

IndexOutOfBoundsException daca indicii sunt gresiti.

public String(String value)

Creeaza un nou sir, in care il copiaza pe cel dat ca argument.

public String(StringBuffer buffer)

Creeaza un nou sir, care contine aceleasi caractere ca cele din argumentul buffer, care

apartine clasei StringBuffer (deci este o zona-tampon pentru siruri).

Metode:

public char charAt(int index) Intoarce caracterul situat in sir pe pozitia index. Se genereaza

IndexOutOfBoundsException daca indicele este gresit.

public int compareTo(Object o)

Compara acest sir cu obiectul o primit ca argument. Daca acest obiect nu este un sir, se

genereaza o exceptie de incompatibilitate de clase (ClassCastException). Daca o este un

sir, atunci compararea se face la fel ca in metoda urmatoare.

public int compareTo(String anotherString)

Compara acest sir cu sirul anotherString primit ca argument. Daca cele doua siruri

sunt identice, intoarce 0 (zero). Daca acest sir il precede pe o intoarce o valoare negativa, iar

Page 367: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

367

daca ii succede lui o intoarce o valoare pozitiva. Compararea sirurilor se face in ordine

lexicografica (in ordinea in care ar fi plasate intr-un dictionar).

public int compareToIgnoreCase(String str)

Compara lexicografic acest sir cu sirul str primit ca argument, ignorand deosebirea

dintre literele majuscule si cele minuscule.

public String concat(String str)

Concateneaza acest sir cu sirul str primit ca argument.

public static String copyValueOf(char[] data)

Intoarce un sir care contine aceleasi caractere cu cele din tabloul data. Se poate genera

NullPointerException daca referinta la tablou este nula.

public static String copyValueOf(char[] data, int offset, int count)

Similar cu metoda precedenta, dar se preiau din tabloul data numai count caractere

incepand cu pozitia offset. Se poate genera NullPointerException daca referinta la tablou

este nula

public boolean endsWith(String suffix)

Testeaza daca acest sir se termina cu subsirul suffix.

public boolean equals(Object anObject)

Testeaza daca acest sir este "egal" cu obiectul anObject.

public boolean equalsIgnoreCase(String anotherString)

Testeaza daca acest sir contine aceleasi caractere ca argumentul anotherString,

ignorand deosebirea dintre literele mici si cele mari.

public byte[] getBytes()

Converteste acest sir intr-un tablou de octeti, luind in consideratie codificarea locala de

pe calculatorul pe care ruleaza programul.

public byte[] getBytes(String enc)

Similara cu metoda precedenta, dar conversia se face folosind codificarea enc. Se

genereaza UnsupportedEncodingException daca argumentul enc este gresit.

public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)

Copiaza caracterele din acest sir in tabloul de caractere de destinatie char[]. Copierea

incepe de la caracterul de pe pozitia srcBegin si se termina la caracterul de pe pozitia

srcEnd-1. Plasarea in tabloul de destinatie incepe cu pozitia dstBegin. Se poate genera

NullPointerException daca referinta la tablou este nula sau IndexOutOfBoundsException

daca indicii sunt gresiti..

public int hashCode() Intoarce codul de dispersie pentru acest sir.

public int indexOf(int ch)

Intoarce indicele la care se gaseste in sir prima aparitie a caracterului ch. Daca acest

caracter nu exista in sir, intoarce -1.

Page 368: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

368

public int indexOf(int ch, int fromIndex)

Similar cu metoda precedenta, dar cautarea in sir incepe de la pozitia fromIndex.

public int indexOf(String str)

Intoarce indicele pozitiei de pe care in acest sir apare prima data subsirul str.

public int indexOf(String str, int fromIndex)

Similar cu metoda precedenta, dar cautarea in acest sir incepe de la pozitia fromIndex.

public String intern()

Intoarce o reprezentare canonica a acestui obiect-sir.

public int lastIndexOf(int ch)

Intoarce indicele ultimei pozitii pe care apare caracterul ch in acest sir.

public int lastIndexOf(int ch, int fromIndex) Intoarce indicele ultimei pozitii pe care se gaseste caracterul ch daca se face cautarea

inapoi incepand de la pozitia fromIndex.

public int lastIndexOf(String str)

Intoarce indicele ultimei aparitii in acest sir a subsirului str.

public int lastIndexOf(String str, int fromIndex) Similar cu metoda precedenta, dar cautarea inapoi se face de la pozitia fromIndex.

publicint length() Intoarce lungimea acestui sir (numarul de caractere continute).

public boolean regionMatches(boolean ignoreCase, int toffset, String other,

int ooffset, int len)

Testeaza daca o regiune din acest sir este egala cu o regiune din sirul other primit ca

argument. Daca primul argument (ignoreCase) are valoarea true, comparatia se face

ignorand deosebirea dintre caracterele mari si cele mici. Argumentele tooffset si ooffset

reprezinta indicii pozitiilor de la care incep regiunile comparate in acest sir si, respectiv, in

sirul-argument other. Argumentul len este lungimea celor doua zone comparate.

public boolean regionMatches(int toffset, String other, int ooffset, int

len)

Similar cu metoda precedenta, dar se ia in consideratie deosebirea intre literele mici si

cele mari.

public String replace(char oldChar, char newChar)

Intoarce un nou sir, care are acelasi continut cu acest sir, dar in care toate aparitiile

caracterului oldChar sunt inlocuite prin caracterul newChar.

public boolean startsWith(String prefix)

Testeaza daca acest sir incepe cu subsirul prefix.

public boolean startsWith(String prefix, int toffset)

Testeaza daca subsirul prefix incepe in acest sir de pe pozitia index.

Page 369: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

369

public String substring(int beginIndex) Intoarce un nou sir, care contine caracterele acestui sir incepand de la pozitia

beginIndex, pana la sfarsit.

public String substring(int beginIndex, int endIndex)

Intoarce subsirul situat intre pozitiile beginIndex si endIndex-1.

public char[] toCharArray() Converteste acest sir intr-un tablou de caractere.

public String toLowerCase() Intoarce un nou sir, in care literele mari ale acestui sir sunt inlocuite cu litere mici.

public String toLowerCase(Locale locale) Similar cu metoda precedenta, dar inlocuirea literelor mari cu cele mici se face

respectand conventia locale.

public String toString()

Intoarce chiar acest sir.

public String toUpperCase() Intoarce un nou sir, provenit din acest sir, in care toate literele mici au fost inlocuite cu

litere mari.

public String toUpperCase(Locale locale)

Similar cu metoda precedenta, dar conversia se face respectand conventia locale.

public String trim() Intoarce un nou sir, obtinut din acest sir prin eliminarea spatiilor de la inceput si de la

sfarsit.

public static String valueOf(boolean b)

Intoarce reprezentarea sub forma de sir a unui argument de tip boolean.

public static String valueOf(char c)

Intoarce un sir care contine numai caracterul c.

public static String valueOf(char[] data)

Intoarce reprezentarea sub forma de sir a tabloului de caractere data. Se genereaza

NullPointerException daca referinta la tablou este nula.

public static String valueOf(char[] data, int offset, int count)

Intoarce reprezentarea sub forma de sir a subtabloului de lungime count cuprins in

tabloul data incepand de la indicele offset. Se genereaza NullPointerException daca

referinta la tablou este nula.

public static String valueOf(double d)

Intoarce reprezentarea sub forma de sir a unui argument de tip double.

public static String valueOf(float f)

Intoarce reprezentarea ca sir a unui argument de tip float.

Page 370: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

370

public static String valueOf(int i)

Intoarce reprezentarea ca sir a unui argument de tip int.

public static String valueOf(long l)

Intoarce reprezentarea ca sir a unui argument de tip long.

public static String valueOf(Object obj)

Intoarce reprezentarea ca sir a obiectului obj.

Metode mostenite de la clasa java.lang.Object: clone, finalize, getClass, notify, notifyAll, wait

Clasa StringBuffer

public final class StringBuffer extends Object implements Serializable

Un StringBuffer implementeaza un sir de caractere care poate fi modificat. El reprezinta o

zona tampon din memorie, in care se ppoate plasa un sir de caractere.

Operatiile principale asupra unui StringBuffer sunt metodele append si insert. Fiecare

din ele converteste o data intr-un String, pe care apoi il adauga la sirul din StringBuffer

sau il insereaza in acesta pe o pozitie data.

Fiecare StringBuffer are o capacitate si o lungime. Lungimea este numarul efectiv de

caractere continute, iar capacitatea este numarul maxim de caractere care incap in zona

tampon rezervata in memorie. Daca, printr-o noua adaugare de caractere, lungimea depaseste

capacitatea, atunci capacitatea se mareste in mod automat.

Constructori:

public StringBuffer() - construieste un StringBuffer vid cu capacitatea 16 caractere.

public StringBuffer(int length)- construieste un StringBuffer vid de lungime length.

Daca length este negativ, se genereaza o NegativeArraySizeException.

public StringBuffer(String str)- construieste un StringBuffer care contine sirul str,

iar capacitatea este lungimea lui str plus 16.

Metode:

public int length()- intoarce lungimea sirului continut in StringBuffer (numarul de

caractere).

public int capacity()- intoarce capacitatea curenta a zonei tampon.

Page 371: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

371

public void ensureCapacity(int minimumCapacity)- asigura capacitatea minima a

zonei tampon. Daca capacitatea curenta este mai mica decat minimumCapacity, se aloca in

memorie o noua zona tampon si se transfera in ea sirul curent. Capacitatea noului

StringBuffer este cea mai mare dintre valoarea argumentului minimumCapacity si dublul

vechii capacitati.

public void setLength(int newLength)- seteaza noua lungime a acestui StringBuffer.

Daca noua lungime newLength este mai mica decat cea existenta, sirul este trunchiat. Daca

newLength este mai mare decat cea curenta, se adauga un numar suficient de caractere nule

(\0000) pentru a se obtine noua lungime. Daca argumentul newLength este negativ se

genereaza o exceptie IndexOutOfBoundsException.

public char charAt(int index)- intoarce caracterul de pe pozitia de indice index. Daca

indicele nu se incadreaza in lungimea sirului curent, se genereaza o

IndexOutOfBoundsException.

public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)

Caracterele situate in StringBuffer intre pozitiile srcBegin si srcEnd-1 sunt copiate in

tabloul de caractere dst incepand de la pozitia dstBegin. Daca dst este null se genereaza o

NullPointerException. Daca srcBegin, srcEnd sau dstBegin nu sunt corecte, se genereaza

o IndexOutOfBondsException.

public void setCharAt(int index, char ch)- se pune caracterul ch pe pozitia index.

Daca index este incorect, se genereaza o IndexOutOfBoundsException.

public StringBuffer append(Object obj)- se adauga obiectul obj convertit in sir.

public StringBuffer append(String str)- se adauga sirul str.

public StringBuffer append(char[] str)- se adauga toate caracterele continute in

tabloul str.

public StringBuffer append(char[] str, int offset, int len)- se adauga la acest

StringBuffer len caractere din tabloul str, incepand de la pozitia offset din acest tablou.

public StringBuffer append(boolean b)- se adauga valoarea booleana b convertita in

sir.

public StringBuffer append(char c)- se adauga caracterul c.

public StringBuffer append(int i)- se adauga intregul i convertit in sir.

public StringBuffer append(long l)- se adauga numarul intreg llung l convertit in sir.

public StringBuffer append(float f)- se adauga numarul real f convertit in sir.

public StringBuffer append(double d)- se adauga numarul real d convertit in sir.

Page 372: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

372

public StringBuffer delete(int start, int end)- se elimina caracterele de pe

pozitiile de la indicele start pana la end-1. Daca start este negativ, mai mare ca lungimea

sau mai mare ca end se genereaza o StringIndexOutOfBoundsException.

public StringBuffer deleteCharAt(int index)- se elimina caracterul de pe pozitia

index sau se genereaza o StringIndexOutOfBoundsException.

public StringBuffer replace(int start, int end, String str)- caracterele situate

in StringBuffer pe pozitiile de la start la end-1 se inlocuiesc prin subsirul str. Daca indicii

start sau end nu sunt corecti se genereaza o StringIndexOutOfBoundsException.

public String substring(int start)- intoarce subsirul care incepe de la pozitia start

sau genereaza o StringIndexOutOfBoundsException.

public String substring(int start, int end)- intoarce subsirul de la pozitia start la

pozitia end-1 sau genereaza o StringIndexOutOfBoundsException.

public StringBuffer insert(int index, char[] str, int offset, int len)

Incepand de la pozitia index insereaza in StringBuffer len caractere situate in tabloul str de

la pozitia offset sau se genereaza o StringIndexOutOfBoundsException.

public StringBuffer insert(int offset, Object obj)- insereaza incepand de la

pozitia offset obiectul obj reprezentat ca sir. Daca offset nu este corect se genereaza o

StringingIndexOutOfBoundsException.

public StringBuffer insert(int offset, String str)- se insereaza incepand de la

pozitia offset sirul str. Daca offset este incorect se genereaza o

StringIndexOutOfBoundsException.

public StringBuffer insert(int offset, char[] str)- incepand de la pozitia offset

se insereaza caracterele din tabloul str. Daca offset este incorect se genereaza o

StringIndexOutOfBoundsException.

public StringBuffer insert(int offset, boolean b)- se insereaza incepand de la

pozitia offset valoarea booleana b convertita in sir, sau se genereaza o

StringIndexOutOfBoundsException.

public StringBuffer insert(int offset, char c)- pe pozitia offset se insereaza

caracterul c sau se genereaza o StringIndexOutOfBoundsException.

public StringBuffer insert(int offset, int i)- incepand de la pozitia offset se

insereaza numarul intreg i convertit in sir sau se genereaza o

StringIndexOutOfBoundsException.

public StringBuffer insert(int offset, long l)- incepand de la pozitia offset se

insereaza numarul intreg lung l convertit in sir, sau se genereaza o

StringIndexOutOfBoundsException.

Page 373: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

373

public StringBuffer insert(int offset, float f)- incepand de la pozitia offset se

insereaza numarul real f convertit in sir sau se genereaza o

StringIndexOutOfBoundsException.

public StringBuffer insert(int offset, double d)- incepand de la pozitia offset se

insereaza numarul real f convertit in sir sau se genereaza o

StringIndexOutOfBoundsException.

public StringBuffer reverse()- se pun caracterele din StringBuffer in ordine inversa

celei actuale.

public String toString()- intoarce un String care are acelasi continut cu acest

StringBuffer.

--------------------------------------------------------------------------------

Metode mostenite de la clasa Object:

clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait

Interfaţa Comparable

java.lang.Comparable

Interfaţa este implementată de clasele ale căror instanţe pot fi comparate între ele, deci fac

parte dintr-o mulţime ordonată.

Interfaţa conţine o singură metodă:

public int compareTo(Object obj) - compară obiectul de care aparţine cu obiectul obj

primit ca argument. Valoarea întoarsă este:

0 (zero) - dacă cele două obiecte sunt egale;

valoare negativă, dacă obiectul propriu îl precede pe obj;

valoare pozitivă, dacă obiectul propriu este succesor al lui obj.

Fie a şi b două obiecte, aparţinând unei clase cu interfaţa Comparable. În acest caz:

a.compareTo(b)<0 dacă a<b (a precede lui b);

a.compareTo(b)==0 dacă a==b;

a.compareTo(b)>0 dacă a>b (a succede lui b).

Clasa BufferedInputStream

Face parte din pachetul java.IO şi extinde clasa FilterInputStream.

Instanţele acestei clase sunt fluxuri de intrare de octeţi, care conţin o zonă tampon (buffer).

Octeţii sunt citiţi unul câte unul din această zonă tampon. Când zona tampon se goleşte, ea se

Page 374: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

374

umple din nou, în mod automat, prin citirea din fluxul de intrare căruia acest

BufferedInputStream îi este ataşat.

Constructori

public BufferedInputStream(InputStream in) - se creează un BufferedInputStream

ataşat fluxului de intrare in.

public BufferedInputStream(InputStream in, int size) - se creează un

BufferedInputStream ataşat fluxului de intrare in, lungimea zonei tampon fiind de size

octeţi.

Metode

Aceleaşi ca în clasa InputStream.

Clasa BufferedOutputStream

Face parte din pachetul java.io şi extinde clasa FilterOutputStream

Constructori

public BufferedOutputStream(OutputStream out) - creează o instanţa a clasei

BufferedOutputStream conectată la ieşire la fluxul out şi conţinând o zonă tampon cu

lungimea implicită de 512 octeţi;

public BufferedOutputStream(OutputStream out, int size) - creează o instanţa a

clasei BufferedOutputStream conectată la ieşire la fluxul out şi conţinând o zonă tampon cu

lungimea de size octeţi;

Metode

Aceleaşi ca în clasa OutputStream.

Clasa BufferedReader

Face parte din pachetul java.io şi extinde clasa Reader.

Constructori

public BufferedReader(Reader in) - creează un flux de intrare de caractere, cu zonă

tampon de lungime implicită, conectat la ieşirea fluxului de intrare de caractere in.

Page 375: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

375

public BufferedReader(Reader in, int sz) - creează un flux de intrare de caractere,

cu zonă tampon de lungime sz, conectat la ieşirea fluxului de intrare de caractere in.

Metode

Aceleaşi ca în clasa Reader.

Clasa BufferedWriter

Face parte din pachetul java.io şi extinde clasa Writer. Caracterele primite sunt acumulate

într-o zonă tampon şi sunt transmise la ieşire numai când această zonă tampon s-a umplut,

sau când se execută metoda flush().

Constructori

public BufferedWriter(Writer out) - creează un flux de ieşire de caractere, cu zonă

tampon de lungime implicită, conectat la ieşire la fluxul de caractere out.

public BufferedWriter(Writer out, int sz) - creează un flux de ieşire de caractere, cu

zonă tampon de lungime sz, conectat la ieşire la fluxul de caractere out.

Metode

Aceleaşi ca în clasa Writer.

Clasa ByteArrayInputStream

Face parte din pachetul java.io şi extinde clasa InputStream.

Acest flux conţine o zonă tampon (buffer) din care se citesc datele, situată în memoria

internă.

Câmpuri

protected byte[] buf - tabloul de octeţi din care se face citirea, situat în memoria internă.

protected int pos - indicele următorului octet care va fi citit din tabloul de octeţi de

intrare buf[].

protected int mark - poziţia marcată din flux (este iniţializată implicit la zero şi poate fi

modificată prin metoda mark()).

protected int count - numărul de octeţi existenţi efectiv în tabloul buf (este cel puţin 0 şi

cel mult egal cu lungimea tabloului)

Constructori

public ByteArrayInputStream(byte[] buf) - creează un flux de intrare de octeţi, care

citeşte din tabloul buf[] situat în memoria internă.

Page 376: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

376

public ByteArrayInputStream(byte[] buf, int offset, int length) - creează un

flux de intrare de octeţi, care citeşte dintr-o zonă a tabloului de octeţi buf[] care începe de la

poziţia de indice offset a acestui tablou şi are lungimea length.

Metode

Aceleaşi ca la clasa InputStream.

Clasa ByteArrayOutputStream

Face parte din pachetul java.io şi extinde clasa OutputStream.

Flux de ieşire de octeţi, care scrie într-un tablou de octeţi situat în memoria internă. Zona

tampon (tabloul) în care se scrie are capacitate variabilă: capacitatea lui se mareşte automat

dacă prin o nouă scriere se depăşeşte capacitatea existentă. Referinţa la zona tampon pentru

scriere se obţine prin metoda toByteArray().

Câmpuri

protected byte[] buf - tabloul de octeţi în care se face scrierea, situat în memoria internă.

protected int count - numărul de octeţi valizi existenţi în tabloul buf[].

Constructori

public ByteArrayOutputStream() - creează un flux de ieşire de octeţi care scrie într-o

zonă tampon (tablou) care are iniţial capacitatea de 32 octeţi, dar capacitatea creşte automat,

dacă este necesar.

public ByteArrayOutputStream(int size) - creează un flux de ieşire de octeţi care scrie

într-o zonă tampon (tablou) care are iniţial capacitatea de size octeţi, dar capacitatea creşte

automat, dacă este necesar.

Metode

Metodele sunt cele din clasa OutputStream, la care se adaugă:

public void writeTo(OutputStream out) throws IOException - scrie în fluxul de

ieşire out întregul conţinut al tabloului (yonei tampon) buf, ca şi când s-ar fi fi făcut

invocarea de metodă out.write(buf, 0, cont).

public byte[] toByteArray() - întoarce un nou tablou de octeţi, în care este copiat

conţinutul valid al yonei tampon buf.

public int size() - întoarce dimensiunea curentă a zonei tampon (valoarea câmpului count).

Clasa CharArrayReader

Page 377: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

377

Face parte din pachetul java.io şi extinde clasa Reader. Instanţele acestei clase sunt fluxuri de

intrare de carractere, care citesc dintr-un tablou de caractere situat in memoria internă.

Constructori

public CharArrayReader(char[] buf) - creează un flux de intrare de caractere, care

citeşte din tabloul de caractere buf[], situat ]n memoria internă.

public CharArrayReader(char[] buf, int offset, int length) - creează un flux de

intrare de caractere, care citeşte din tabloul de caractere buf[], situat ]n memoria internă.

Citirea începe de la poziţia de indice offset, iar yona de citire are lungimea length.

Metode

Aceleaşi ca în clasa Reader.

Clasa CharArrayWriter

Face parte din pachetul java.io şi extinde clasa Writer. Instanţele sunt fluxuri de ieşire de

caractere, care scriu într-o zonă tampon sub formă de tablou de caractere extensibil, situat în

memoria internă. Datele din zona tampon de ieşire pot fi obţinute prin metodele

toCharArray() şi toString().

Constructori

public CharArrayWriter() - creează un flux de ieşire de caractere, care scrie într-o zonă

tampon situată în memoria internă, a cărei lungime este dată implicit.

public CharArrayWriter(int initialSize) - creează un flux de ieşire de caractere, care

scrie într-o zonă tampon situată în memoria internă, a cărei lungime este initialSize.

Metode

Aceleaşi ca în clasa Writer, la care se adaugă:

public void writeTo(Writer out) throws IOException - scrie datele din zona tampon

în fluxul de ieşire de caractere out.

public char[] toCharArray() - întoarce un tablou de caractere, având acelaşi conţinut cu zona

tampon de ieşire.

public int size() - întoarce lungimea curentă a zonei tampon.

public String toString() - întoarce un şir, care are acelaşi conţinut cu zona tampon.

Clasa FileDescriptor

Page 378: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

378

Face parte din pachetul java.io. Instanţele clasei FileDescriptor servesc ca manipulatori ai

unor fişiere sau socluri deja deschise. Principala utilizare este la crearea unor fluxuri din

clasele FileInputStream sau FileOutputStream, conectate la fişiere deja deschise.

Câmpuri

public static final FileDescriptor in - descriptorul fişierului de intrare standard a

sistemului, System.in.

public static final FileDescriptor out - descriptorul fişierului de ieşire standard a

sistemului, System.out

public static final FileDescriptor err - descriptorul fişierului de ieşire pentru erori

a sistemului, System.err

Constructori

public FileDescriptor() - creează o instanţă a clasei Filedescriptor, care nu este validă

(nu indică nici un fişier)

Observaţie: pentru a obţine un descriptor de fişier valid se foloseşte metoda

public final FileDescriptor getFD()throws IOException - existentă în clasele

FileInputStream şi FileOutputStream. Această metodă întoarce descriptorul fişierului

respectiv.

Metode

public boolean valid() - indică dacă acest descriptor de fişier este valid (se referă la un

fişier sau soclu deschis).

public void sync() throws SyncFailedException - forţează sincroniăarea zonelor

tampon ale sistemului pentru dispozitivul corespunzător.

Clasa FilterInputStream

Face parte din pachetul java.io. Este superclasa claselor de fluxuri de intrare de octeţi, care

realizează anumite operaţii de filtrare (prelucrare) a datelor de intrare. De fapt, metodele

acestei clase sunt cele moştenite de la superclasa InputStream, deci nu fac nici o prelucrare.

Aceste metode pot fi însă redefinite în subclase, pentru a realiza astfel de prelucrări. În

pachetul java.io există subclasele DataInputStream, BufferedInputStream şi

PushbackInputStream. Putem crea şi propriile noastre subclase.

Constructor

protected FilterInputStream(InputStream in) - creează un flux de intrare de octeţi cu

filtru, care preia fluxul de intrare in.

Metode

Aceleaşi ca în clasa InputStream.

Page 379: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

379

Clasa FilterOutputStream

Face parte din pachetul java.io. Este superclasa claselor de fluxuri de ieşire de octeţi, care

realizează anumite operaţii de filtrare (prelucrare) a datelor de ieşire. De fapt, metodele

acestei clase sunt cele moştenite de la superclasa OutputStream, deci nu fac nici o prelucrare.

Aceste metode pot fi însă redefinite în subclase, pentru a realiza astfel de prelucrări. În

pachetul java.io există subclasele DataOutputStream, BufferedOutputStream, PrintStream şi

altele. Putem crea şi propriile noastre subclase.

Constructor

public FilterOutputStream(OutputStream out) - creează un flux de ieşire de octeţi cu

filtru, care transmite datele la fluxul de ieşire de octeţi out.

Metode

Metodele sunt aceleaşi ca în clasa OutputStream.

Clasa FilterReader

Face parte din pachetul java.io. Este superclasa claselor de fluxuri de intrare de caractere,

care realizează anumite operaţii de filtrare (prelucrare) a datelor de intrare. De fapt, metodele

acestei clase sunt cele moştenite de la superclasa Reader, deci nu fac nici o prelucrare. Aceste

metode pot fi însă redefinite în subclase, pentru a realiza astfel de prelucrări. În pachetul

java.io există subclasa PushbackReader. Putem crea şi propriile noastre subclase.

Constructor

protected FilterReader(Reader in) - creează un flux de intrare de caractere cu filtru,

care preia fluxul de intrare in.

Metode

metodele sunt la fel cele din superclasa Reader.

Clasa FilterWriter

Face parte din pachetul java.io. Este superclasa claselor de fluxuri de ieşire de caractere, care

realizează anumite operaţii de filtrare (prelucrare) a datelor de ieşire. De fapt, metodele

acestei clase sunt cele moştenite de la superclasa Writer, deci nu fac nici o prelucrare. Aceste

metode pot fi însă redefinite în subclase, pentru a realiza astfel de prelucrări.

Page 380: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

380

Constructor

protected FilterWriter(Writer out) - creează un flux de ieşire de caractere cu filtru, care

transmite datele la fluxul de ieşire de caractere out.

Metode

Aceleaşi ca în superclasa Writer.

Clasa EventObject

public class EventObject extends Object implements Serializable

Face parte din pachetul java.util. Este rădăcina ierarhiei de clase de evenimente. Fiecare

eveniment este generat de o sursă (source). Fiecare instanţă a clasei EventObject conţine o

referinţă la această sursă şi o metodă prin care ea este obţinută.

Constructor

public EventObject(Object source) - se generează un eveniment, indicându-se sursa.

Metode

public Object getSource() - întoarce sursa evenimentului.

public String toString() - întoarce reprezentarea sub formă de String a evenimentului.

Interfaţa EventListener

public interface EventListener

Face parte din pachetul java.util. Este o interfaţă generică, pe care trebuie să o extindă -

direct sau indirect - orice interfaţă de ascultătoare de evenimente.

Interfaţa nu conţine nici o metodă.

Clasa AWTEvent

public abstract class AWTEvent extends EventObject

Face parte din pachetul java.awt. Este superclasa tuturor claselor de evenimente AWT. Orice

eveniment AWT are un identificator, reprezentat prin câmpul id. Clasa conţine câmpuri

Page 381: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

381

statice, care au ca valori măşti pentru selectarea după id a diferitelor tipuri de evenimente.

Clasele de evenimente create în afara pachetelor din Java API trebuie să aibă valoarea

câmpului id superioară valorii maxime din câmpul RESERVED_ID_MAX.

Clasa AWTEvent înlocuieşte clasa Event din JDK 1.0, care a fost menţinută în pachet numai

pentru compatibilitate. Subclasele directe ale clasei AWTEvent sunt: ActionEvent,

AdjustmentEvent, AncestorEvent, ComponentEvent, HierarchyEvent, InputMethodEvent,

InternalFrameEvent, InvocationEvent, ItemEvent, TextEvent. Ele se găsesc în pachetul

java.awt.event, cu excepţia clasei InternalFrameEvent, care se găseşte în pachetul

javax.swing.event.

Câmpuri

protected int id - identificatorul tipului de eveniment.

public static final long COMPONENT_EVENT_MASK - masca pentru selectarea

evenimentelor de componentă.

public static final long CONTAINER_EVENT_MASK - masca pentru selectarea

evenimentelor de container.

public static final long FOCUS_EVENT_MASK - masca pentru selectarea evenimentelor

de focalizare

public static final long KEY_EVENT_MASK - masca pentru selectarea evenimentelor de

tastă.

public static final long MOUSE_EVENT_MASK - masca pentru selectarea evenimentelor

de mouse.

public static final long MOUSE_MOTION_EVENT_MASK - masca pentru selectarea

evenimentelor de mişcare a mouse-ului.

public static final long WINDOW_EVENT_MASK - masca pentru selectarea evenimentelor

de fereastră.

public static final long ACTION_EVENT_MASK - masca pentru selectarea evenimentelor

de acţiune.

public static final long ADJUSTMENT_EVENT_MASK - masca pentru selectarea

evenimentelor de ajustare.

public static final long ITEM_EVENT_MASK - masca pentru selectarea evenimentelor de

articol.

public static final long TEXT_EVENT_MASK - masca pentru selectarea evenimentelor de

text.

public static final long INPUT_METHOD_EVENT_MASK - masca pentru selectarea

evenimentelor de metodă de intrare.

Page 382: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

382

public static final long PAINT_EVENT_MASK - masca pentru selectarea evenimentelor

de desenare.

public static final long INVOCATION_EVENT_MASK - masca pentru selectarea

evenimentelor de invocare.

public static final long HIERARCHY_EVENT_MASK - masca pentru selectarea

evenimentelor de ierarhie.

public static final long HIERARCHY_BOUNDS_EVENT_MASK - masca pentru selectarea

evenimentelor de margini ale ierarhiei.

public static final int RESERVED_ID_MAX - valoarea maximă rezervată pentru id.

Constructori

public AWTEvent(Event event) - construieşte un obiect din clasa AWTEvent, folosind

paramerii unei instanţe a clasei Event.

public AWTEvent(Object source, int id) - construieşte o nouă instanţă a clasei

AWTEvent, specificându-se sursa şi tipul de eveniment.

Metode principale

Metodele clasei EventObject, la care se adaugă:

public int getID() - întoarce tipul de eveniment.

public String toString() - întoarce reprezentarea sub formă de String a evenimentului.

public String paramString() - întoarce un şir care conţine parametrii evenimentului. Se

foloseşte în special la depanarea programului.

Clasa BorderLayout

public class BorderLayout extends Object implements LayoutManager2, Serializable

Suprafaţa containerului prevăzut cu acest gestionar de poziţionare se împarte în cinci zone:

NORTH, SOUTH, WEST, EAST şi CENTER. În fiecare din aceste zone poate fi pusă câte o

singură componentă.

Dăm aici un exemplu de utilizare a unui gestionar de poziţionare din clasa BorderLayout: p.setLayout(new BorderLayout()); p.add(new Button("OK"), BorderLayout.SOUTH); În prima instrucţiune, pentru containerul p se setează gestionarul de poziţionare

BorderLayout. În a doua instrucţiune, se pune butonul cu inscripţia "OK" în zona SOUTH a

aceluiaşi container. Dacă se omite zona, se consideră implicit că adăugarea componentei se

face în zona CENTER.

Page 383: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

383

Constructori

public BorderLayout() - se creează un gestionar de poziţionare BorderLayout, fără

distanţare între componente.

public BorderLayout(int hgap, int vgap) - se creează un gestionar de poziţionare

BorderLayout, având distanţări între componente hgap pe orizontală şi vgap pe verticală.

Metode

Metodele din interfeţele LayoutManager şi LayoutManager2, la care se adaugă următoarele:

public int getHgap() - întoarce distanţarea pe orizontală între componente.

public void setHgap(int hgap) - setează distanţarea pe orizontală între componente.

public int getVgap() - întoarce distanţarea pe verticală între componente.

public void setVgap(int vgap) - setează distanţarea pe verticală între componente.

Clasa Button

public class Button extends Component implements Accessible

Instanţele acestei clase sunt butoane care conţin un text numit "etichetă" (engl: label). Când

este apăsat, butonul generează un eveniment de acţiune, care poate fi ascultat cu un

ActionListener.

Constructori

public Button() - construieşte un buton care nu conţine text.

public Button(String label) - construieşte un buton care conţine eticheta specificată.

Metode

Metodele sunt cele ale clasei Component la care se adaugă următoarele:

public String getLabel() - întoarce eticheta butonului.

public void setLabel(String label) - setează eticheta butonului.

public void setActionCommand(String command) - setează numele acţiunii de comandă

generată de buton. Dacă nu se foloseşte această comandă, implicit acest nume este identic cu

eticheta butonului.

public String getActionCommand() - întoarce numele acţiunii de comandă generată de

buton.

Page 384: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

384

public void addActionListener(ActionListener l) - adaugă la buton un ascultător de

evenimente de acţiune.

public void removeActionListener(ActionListener l) - elimină ascultătorul de

evenimente de acţiune specificat.

Clasa Canvas

public class Canvas extends Component implements Accessible

Instanţele acestei clase sunt suprafeţe rectangulare albe, pe care se pot trasa desene (în

engleză, canvas este pânza pe care se pictează). Pentru a realiza un desen, se creează o

subclasă a clasei Canvas, pentru care se redefineşte metoda paint.

Constructori

public Canvas() - creează o nouă instanţă a clasei Canvas.

public Canvas(GraphicsConfiguration config) - creează o nouă instanţă a clasei

Canvas, folosind configuraţia grafică config.

Medtode

Metodele clasei Component, dintre care cea mai utilizată este metoda:

public void paint(Graphics g) - desenează pe suprafaţa acestei componente (Canvas),

folosind contextul grafic g.

Clasa CardLayout

public class CardLayout extends Object implements LayoutManager2, Serializable

Instanţele acestei clase sunt gestionari de poziţionare, care plasează componentele în

container una peste alta, ca într-un pachet de cărţi de vizită.La un moment dat este vizibilă

numai componenta de deasupra, însă componentele îşi pot schimba locurile între ele prin

rotaţie.

Constructori

public CardLayout() - construieşte un CardLayout fără spaţiu liber în jurul componentelor.

public CardLayout(int hgap, int vgap) - construieşte un cardLayout care are pe

margini spaţiile libere hgap pe orizontală şi vgap pe verticală.

Page 385: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

385

Metode

Metodele interfeţelor LayoutManager şi LayoutManager2, la care se adaugă următoarele:

public int getHgap() - întoarce spaţiul liber pe orizontală.

public void setHgap(int hgap) - setează spaţiul liber pe orizontală.

public int getVgap() - întoarce spaţiul liber pe verticală.

public void setVgap(int vgap) - setează spaţiul liber pe verticală.

public void first(Container parent) - pune deasupra prima componentă din

containerul părinte specificat.

public void next(Container parent) - pune deasupra următoarea componentă a

containerului specificat.

public void previous(Container parent) - pune deasupra componenta precedentă a

containerului specificat.componenta cu numele name din containerul specificat.

public void show(Container parent, String name) - pune deasupra

public void last(Container parent) - pune deasupra ultima componentă din

containerul specificat.

Clasa Color

Clasa Color încapsulează culorile din spaţiul de culori implicit sRGB, sau culori dintrun

spqaţiu de culori arbitrar, identificat prin ColorSpace. Fiecare culoare conţine, în afară de

componentele de culoare fundamentale, şi o componentă numită alpha, care semnifică

opacitatea şi are valori reale în intervalul 0.0 ... 1.0 sau valori întregi în intervalul 0 .. 255.

Valoarea alpha=0 înseamnă opacitate nulă (culoare total transparentă), iar valoarea maximă a

lui alpha înseamnă opacitate maximă (culoare total netransparentă). În mod implicit se

admite opacitatea maximă.

Culorile fundamentale din sistemul sRGB (standard RGB) sunt următoarele: red (roşu),

green (verde) şi blue (albastru). Acestea pot fi date prin numere întregi în intervalul 0 .. 255

sau prin numere reale în intervalul 0.0 .. 1.0. Aceste valori reprezintă intensitatea culorii

fundamentale respective în culoarea dată. Orice culoare se obţine prin combinarea acestor trei

componente fundamentale, cu intensităţi diferite. Explicaţii suplimentare sunt date şi în

secţiunea "Clasa Color" din acest manual.

Valorile componentelor fundamentale ale culorii pot fi date şi împachetate într-un singur

număr de tip int, în care fiecare octet conţine una din componente (în intervalul 0 .. 255)

astfel: blue - biţii 0 ..7; green: biţii 8 .. 15; red: biţii 16 .. 23; alpha: biţii 24 .. 31.

Clasa Color conţine şi câmpuri finale pentru culorile tipice.

Page 386: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

386

Câmpuri

public static final Color white - culoarea albă.

public static final Color lightGray - culoarea gri deschis.

public static final Color gray - culoarea gri.

public static final Color darkGray - culoarea gri închis.

public static final Color black - culoarea neagră.

public static final Color red - culoarea roşie.

public static final Color pink - culoarea roz.

public static final Color orange - culoarea portocalie (orange).

public static final Color yellow - culoarea galbenă.

public static final Color green - culoarea verde.

public static final Color magenta - culoarea violet.

public static final Color cyan - culoarea azuriu (albastru deschis)

public static final Color blue - culoarea albastră.

Constructori

public Color(int r, int g, int b) - creează o instanţă a clasei Color pentru cu

culoarea cu componentele RGB specificate prin numere întregi cuprinse între 0 şi 255.

public Color(int r, int g, int b, int a) - creează o instanţă a clasei Color pentru

cu culoarea cu componentele RGB şi componenta a (alpha) specificate prin numere întregi

cuprinse între 0 şi 255.

public Color(int rgb) - creează o instanţă a clasei Color, dându-i ca argument un număr

de tip int (pe 4 octeţi), care în primii trei octeţi conţine cele trei componente fundamentale.

public Color(int rgba, boolean hasalpha) - creează o instanţă a clasei Color, dându-i ca

argument un număr de tip int (pe 4 octeţi), care în primii trei octeţi conţine cele trei

componente fundamentale, iar în ultimul octet componenta alpha. Al doilea argument indică

dacă există sau nu componenta alpha.

public Color(float r, float g, float b) - creează o instanţă a clasei Color pentru cu culoarea cu

componentele RGB specificate prin numere reale cuprinse între 0.0 şi 1.0.

public Color(float r, float g, float b, float a) - public Color(int r, int g, int b, int

a) - creează o instanţă a clasei Color pentru cu culoarea cu componentele RGB şi

componenta a (alpha) specificate prin numere reale cuprinse între 0.0 şi 1.0.

Page 387: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

387

public Color(ColorSpace cspace, float[] components, float alpha) - creează o

instanţă a clasei Color, dându-se spaţiul de culori cspace (instanţă a clasei ColorSpace),

tabloul de componente components şi opacitatea alpha.

Metode

public int getRed() - întoarce componenta roşie.

public int getGreen() - întoarce componenta verde.

public int getBlue() - întoarce componenta albastră.

public int getAlpha() - întoarce componenta alpha.

public int getRGB() - întoarce un int, care conţine sub formă împachetată cele patru

componente (r, g, b, alpha).

public Color brighter() - întoarce o variantă mai deschisă a acestei culori.

public Color darker() - întoarce o variantă mai închisă a acestei culori.

public static Color decode(String nm) throws NumberFormatException -

converteşte un şir de caractere, care reprezintă culoarea codificată în octal sau hexazecimal, şi

întoarce instanţa corespunzătoare a clasei Color.

public static Color getColor(String nm) - caută o culoare în proprietăţile sistemului:

caută proprietatea cu numele nm şi decodifică valoarea acestei proprietăţi (care este

interpretat ca un şir care conţine număr întreg), generând instanţa corespunzătoare a clasei

Color.

public static Color getColor(String nm, Color v) - similar cu metoda precedentă,

dar se indică şi culoarea implicită v care va fi folosită dacă proprietatea de sistem cu numele

nm.

public static Color getColor(String nm, int v) - similar cu metoda precedentă, dar

culoarea implicită este dată printr-un număr întreg.

public static int HSBtoRGB(float hue, float saturation, float brightness) -

converteşte culoarea din sistemul HSB (dată prin parametrii hue: nuanţă, saturation: saturaţie

şi brightness: strălucire) într-o culoare din sistemul RGB, reprezentată sub forma unui număr

de tip int.

public static float[] RGBtoHSB(int r, int g, int b, float[] hsbvals) - face

conversia culorii din RGB în HSB. Întoarce un tablou, care conţine cele trei componente

fundamentale HSB, corespunzătoare componentelor de culoare RGB date ca parametri.

Ultimul argument poate fi null, sau poate conţine un tablou în care se vor întoarce

componwentele HSB rezultate.

Page 388: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

388

public static Color getHSBColor(float h, float s, float b) - întoarce o instanţă

a clasei Color, care conţine culoarea pentru care s-au dat ca argumente valorile

componentelor sale în sistemul HSB.

public float[] getRGBComponents(float[] compArray) - întoarce un tablou de tip

float care conţine cele trei componente RGB şi componenta alpha pentru această culoare.

Parametrul compArray poate fi null, sau este un tablou cu cel puţin 4 componente de tip float,

în care se vor pune valorile întoarse.

public float[] getRGBColorComponents(float[] compArray) - similar cu metoda

precedentă, dar întoarce un tablou cu trei componente, care conţine numai cele trei

componente RGB (fără componenta alpha).

public ColorSpace getColorSpace() - întoarce spaţiul culorilor pentru această culoare (o

instanţă a clasei ColorSpace).

public PaintContext createContext(ColorModel cm, Rectangle r, Rectangle2D

r2d, AffineTransform xform, RenderingHints hints) - întoarce un context de

desenare, care este necesar ca argument în metodele claselor cu interfaţa Paint.

public int getTransparency() - întoarce transparenţa acestei culori (necesară pentru

implementarea interfeţei Paint).

Clasa Component

public abstract class Component extends Object implements ImageObserver, MenuContainer,

Serializable

Face parte din pachetul java.awt. Este rădăcina ierarhiei tuturor claselor de componente ale

interfeţelor grafice AWT şi JFC/Swing.

Metode

public String getName() - întoarce numele componentei.

public void setName(String name) - setează numele componentei.

public Container getParent() - întoarce o referinţă către containerul care conţine

această componentă.

public void setDropTarget(DropTarget dt) - setează un obiect DropTarget pentru

această componentă. Componenta va putea fi ţinta unei operaţii de "drag and drop" (tragere şi

lăsare cu mausul), atunci când este activă.

public DropTarget getDropTarget() - întoarce obiectul DropTarget asociat acestei

componente.

Page 389: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

389

public GraphicsConfiguration getGraphicsConfiguration() - întoarce configuraţia

grafică a acestei componente sau a containerului în care se găseşte, sau null.

public final Object getTreeLock() - întoarce obiectul de închidere al arborelui de

componente AWT şi de gestionare a poziţionării (obiectul proprietar al monitorului de

sincronizare a firului de execuţie).

public Toolkit getToolkit() - întoarce Toolkit-ul pentru această componentă.

public boolean isValid() - indică dacă această componentă este validă (este corect

dimensionată şi poziţionată în containerul său părinte).

public boolean isDisplayable() - indică dacă această componentă este afişabilă (este

conectată la o resursă de ecran de afişare nativă).

public boolean isVisible() - indică dacă această componentă este vizibilă. Toate

componentele sunt iniţial vizibile, cu excepţia celor de cel mai înalt nivel, cum sunt cele din

clasele Frame şi JFrame.

public boolean isShowing() - indică dacă această componentă apare efectiv pe ecran.

public boolean isEnabled() - arată dacă această componentă este activă (poate răspunde

la intrările date de utilizator şi să genereze evenimente).

public void setEnabled(boolean b) - face ca această componentă să fie activă sau

inactivă, după cum valoarea argumentului este true sau false.

public void setVisible(boolean b) - setează proprietatea de vizibilitate a componentei.

public Color getForeground() - întoarce culoarea de prim-plan a componentei (culoarea

textului).

public void setForeground(Color c) - setează culoarea de prim-plan a componentei.

public Color getBackground() - întoarce culoarea de fond a componentei.

public void setBackground(Color c) - setează culoarea de fond a componentei.

public Font getFont() - întoarce fontul componentei.

public void setFont(Font f) - setează fontul componentei.

public ColorModel getColorModel() - întoarce modelul de culori al componentei.

public Point getLocation() - întoarce locaţia componentei (coordonatele colţului din

stânga sus), în sistemul de coordonate al containerului părinte.

public Point getLocationOnScreen() - întoarce locaţia componentei (coordonatele

colţului din stânga sus) în sistemul de coordonate al ecranului.

Page 390: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

390

public void setLocation(int x, int y) - setează locaţia componentei (coordonatele

colţului din stânga sus) în sistemul de coordonate al containerului părinte.

public void setLocation(Point p) - setează locaţia componentei (coordonatele colţului

din stânga sus) în sistemul de coordonate al containerului părinte.

public Dimension getSize() - întoarce dimensiunile componentei.

public void setSize(int width, int height) - setează dimensiunile componentei.

public void setSize(Dimension d) - setează dimensiunile componentei.

public Rectangle getBounds() - întoarce o instanţă a clasei Rectangle (dreptunghi) care

conţine lăţimea, înălţimea şi locaţia componentei.

public void setBounds(int x, int y, int width, int height) - setează

coordonatele colţului din stânga sus, lăţimea şi înălţimea componentei.

public void setBounds(Rectangle r) - setează locaţia şi dimensiunile componentei.

public int getX() - întoarce coordonata x a colţului din stânga-sus (în sistemul de

coordonate al containerului părinte).

public int getY() - întoarce coordonata y a colţului din stânga-sus (în sistemul de

coordonate al containerului părinte).

public int getWidth() - întoarce lăţimea componentei.

public int getHeight() - întoarce înălţimea componentei.

public boolean isOpaque() - indică dacă această componentă este opacă (implicit, toate

componentele sunt opace).

public boolean isLightweight() - întoarce true dacă această componentă nu are un

suport nativ. Toate componentele Swing şi unele din componentele AWT sunt "Lightweight",

adică sunt desenate în Java şi deci nu folosesc componentele grafice de pe platforma locală.

public Dimension getPreferredSize() - întoarce dimensiunile preferabile ale

componentei.

public Dimension getMinimumSize() - întoarce dimensiunile minime ale componentei.

public Dimension getMaximumSize() - întoarce dimensiunile maxime ale componentei.

public void doLayout() - transmite gestionarului de poziţionare indicaţia de a poziţiona

componenta.

public void validate() - asigură că această componentă are un gestionar de poziţionare

valid.

Page 391: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

391

public void invalidate() - invalidează componenta. Această componentă şi părinţii săi

sunt marcaţi că necesită poziţionare.

public Graphics getGraphics() - creează un context grafic pentru această

componentă.Intoarce null dacă această componentă nu este afişabilă.

public void setCursor(Cursor cursor) - setează cursorul pentru această componentă.

public Cursor getCursor() - întoarce cursorul setet pentru această componentă sau

pentru părintele ei.

public void paint(Graphics g) - desenează componenta. Această metodă este apelată automat

când trebuie desenată componenta.

public void update(Graphics g) - actualizează desenul componentei, ca răspuns la

invocarea metodelor repaintupdate sau repaint. Aceasta înseamnă că: (1) se şterge vechiul

conţinut, umplând componenta cu culoarea de fond; (2) se setează culoarea de primplan în

contextul grafic pentru această componentă; (3) se apelează metoda paint pentru a desena

complet componenta.

public void paintAll(Graphics g) - desenează această componentă şi toate

subcomponentele sale.

public void repaint() - redesenează componentă (face ca metoda update pentru această

componentă să fie invocată cât mai rapid posibil).

public void repaint(long tm) - apelează metoda update în tm milisecunde.

public void repaint(int x, int y, int width, int height) - redesenează

dreptunghiul specificat al componentei.

public void repaint(long tm, int x, int y, int width, int height) -

redesenează dreptunghiul specificat al componentei după tm milisecunde.

public void print(Graphics g) - tipăreşte componenta.

public void printAll(Graphics g) - tipăreşte componenta şi toate subcomponentele ei.

public boolean imageUpdate(Image img, int infoflags, int x, int y, int w,

int h) - redesenează componenta când s-a modificat imaginea pe care o conţine.

public Image createImage(ImageProducer producer) - creează o imagine din

producătorul de imagine specificat.

public boolean contains(int x, int y) - verifică dacă această componentă conţine

punctul de coordonate (x, y), în sistemul de coordonate propriu al componentei.

public boolean contains(Point p) - verifică dacă această componentă conţine punctul

p, în sistemul de coordonate propriu al componentei.

Page 392: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

392

public Component getComponentAt(int x, int y) - întoarce subcomponenta care

conţine punctul de coordonate (x, y).

public Component getComponentAt(Point p) - întoarce subcomponenta care conţine

punctul p.

public void addComponentListener(ComponentListener l) - adaugă acestei

componente un ascultător de evenimente generate de către ea.

public void removeComponentListener(ComponentListener l) - elimină ascultătorul

de evenimente de componentă specificat.

public void addFocusListener(FocusListener l) - adaugă un ascultător de evenimente

de focalizare.

public void removeFocusListener(FocusListener l) - elimină ascultătorul de

evenimente de focalizare.

public void addHierarchyListener(HierarchyListener l) - adaugă un ascultător de

evenimente de ierarhie.

public void removeHierarchyListener(HierarchyListener l) - elimină ascultătorul

de evenimente de ierarhie.

public void addKeyListener(KeyListener l) - adaugă un ascultător de evenimente de

tastă.

public void removeKeyListener(KeyListener l) - elimină ascultătorul de evenimente

de tastă.

public void addMouseListener(MouseListener l) - adaugă un ascultător de evenimente

de mouse.

public void removeMouseListener(MouseListener l) - elimină ascultătorul de

evenimente de mouse.

public void addMouseMotionListener(MouseMotionListener l) - adaugă un ascultător

de evenimente de mişcare a mouse-ului.

public void removeMouseMotionListener(MouseMotionListener l) - elimină

ascultătorul de evenimente de mişcare a mouse-ului.

public void addInputMethodListener(InputMethodListener l) - adaugă un ascultător

de evenimente de metodă de intrare.

public void removeInputMethodListener(InputMethodListener l) - elimină

ascultătorul de evenimente de metodă de intrare.

Page 393: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

393

public EventListener[] getListeners(Class listenerType) - întoarce un tablou de

ascultătoare de evenimente ataşate acestei componente şi având tipul dat ca argument. De

exemplu, pentru a obţine tabloul ascultătoarelor de evenimente de mouse adăugate

componentei c se pune instrucţiunea:

MouseListener[] mls = (MouseListener[])(c.getListeners(MouseListener.class))

public void add(PopupMenu popup) - adauga la componentă meniul popup specificat.

public void remove(MenuComponent popup) - elimină meniul popup specificat.

protected String paramString() - întoarce un şir de caractere care reprezintă starea

componentei. Se foloseşte numai pentru depanarea programului.

public String toString() - întoarce reprezentarea sub formă de şir a acestei componente.

public void list() - afişează listingul acestei componente pe System.out.

public void list(PrintStream out) - scrie listingul acestei componente în fluxul out.

public void list(PrintStream out, int indent) - scrie listingul acestei componente

în fluxul out, indentat cu indent.

public void list(PrintWriter out) - scrie listingul acestei componente în fluxul out.

public void list(PrintWriter out, int indent) - scrie listingul acestei componente în fluxul out,

indentat cu indent.

public void addPropertyChangeListener(PropertyChangeListener listener) -

adaugă un ascultător de evenimente de schimbare a proprietăţilor.

public void removePropertyChangeListener(PropertyChangeListener listener) -

elimină ascultătorul de evenimente de schimbare a proprietăţilor.

public void addPropertyChangeListener(String propertyName,

PropertyChangeListener listener) - adaugă un ascultător de evenimente de schimbare a

proprietăţilor, pentru proprietatea specificată prin primul argument.

public void removePropertyChangeListener(String propertyName,

PropertyChangeListener listener) - elimină ascultătorul de evenimente de schimbare a

proprietăţilor, pentru proprietatea specificată prin primul argument.

protected void firePropertyChange(String propertyName, Object oldValue,

Object newValue) - suport pentru raportarea modificărilor de proprietăţi. Metoda poate fi

apelată când s-a modificat o proprietate şi ea va transmite un PropertyChangeEvent către toţi

acsultătorii de evenimente de proprietate înregistraţi la această componentă.

public void setComponentOrientation(ComponentOrientation o) - setează orientarea

componentei.

Page 394: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

394

public ComponentOrientation getComponentOrientation() - întoarce orientarea

componentei.

public AccessibleContext getAccessibleContext() - întoarce contextul accesibil.

Clasa Container

public class Container extends Component

Containerele sunt componente care pot conţine alte componente (inclusiv alte containere,

deoarece şi acestea sunt sunt tot componente).

Componentele adăugate în container sunt păstrate într-o listă. Ordinea din această listă este

cea în care componentele sunt luate în consideraţie de către gestionarul de poziţionare.

Constructor

public Container() - construieşte un nou container.

Metode

Metodele clasei Component, la care se adaugă următoarele:

public int getComponentCount() - întoarce numărul de componente conţinute în acest

container.

public Component getComponent(int n) - întoarce componenta care are indicele i în

lista de componente a containerului.

public Component[] getComponents() - întoarce un tablou cu toate componentele

conţinute în container.

public Insets getInsets() - întoarce lăţimea bordurii containerului (sub forma unui

obiect din clasa Insets).

public Component add(Component comp) - adaugă componenta comp la sfârşitul listei de

componente a containerului.

public Component add(Component comp, int index) - se adaugă componenta comp pe

poziţia din lista de componente cu indicele index.

public void add(Component comp, Object constraints) - se adaugă componenta

comp cu restricţiile date de obiectul constraints. Adăugarea se face la sfârşitul listei de

componente.

public void add(Component comp, Object constraints, int index) - se adaugă

componenta comp cu restricţiile date de obiectul constraints. Adăugarea se face pe poziţia

de indice index a listei de componente.

Page 395: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

395

public void remove(int index) - elimină componenta de indice index.

public void removeAll() - elimină toate componentele conţinute în container.

public LayoutManager getLayout() - întoarce gestionarul de poziţionare al containerului.

public void setLayout(LayoutManager mgr) - setează gestionarul de poziţionare al

containerului.

public void doLayout() - pune în acţiune gestionarul de poziţionare al containerului.

public void paintComponents(Graphics g) - desenează fiecare componentă din acest

container.

public void printComponents(Graphics g) - tipăreşte toate componentele din acest

container.

public void addContainerListener(ContainerListener l) - adaugă un ascultător de

evenimente de container.

public void removeContainerListener(ContainerListener l) - elimină ascultătorul

de evenimente de container specificat.

public Component findComponentAt(int x, int y) - întoarce componenta care conţine

punctul de coordonate (x,y).

public Component findComponentAt(Point p) - întoarce componenta care conţine

punctul p.

Clasa Dialog

public class Dialog extends Window

Fereastra de dialog este o fereastră de cel mai înalt nivel (care poate fi plasată direct pe

ecranul nativ). Ea are bordură şi este folosită în special pentru dialogul (schimbul de

informaţii interactiv) cu utilizatorul. Managerul de poziţionare implicit este BorderLayout.

Generează următoarele evenimente de fereastră: WindowOpened, WindowClosing,

WindowClosed, WindowActivated, WindowDeactivated.

Fereastra de dialog are ca proprietar o altă fereastră din clasa Frame sau Dialog. Când

proprietarul este ascuns sau minimizat, fereastra de dialog este de asemenea ascunsă.

Fereastra de dialog poate fi modală sau nemodală (implicit este nemodală). O fereastră

modală blochează toate intrările către orice altă fereastră de cel mai înalt nuvel şi

descendentele lor, cu excepţia celor care au ca proprietar chiar această fereastră de dialog.

Page 396: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

396

Constructori

public Dialog(Frame owner) - construieşte o fereastră de dialog fără titlu, având ca

proprietar cadrul owner.

public Dialog(Frame owner, boolean modal) - construieşte o fereastră de dialog fără

titlu, cu proprietarul owner, specificându-se dacă ea este sau nu modală.

public Dialog(Frame owner, String title) - construieşte o ferestră de dialog,

indicându-se proprietarul şi titlul ferestrei.

public Dialog(Frame owner, String title, boolean modal) - construieşte o fereastră

de dialog, indicându-se proprietarul, titlul şi dacă este sau nu modală.

public Dialog(Dialog owner) - construieşte o fereastră de dialog fără titlu, având ca

proprietar altă fereastră de dialog.

public Dialog(Dialog owner, String title) - construieşte o fereastră de dialog cu

titlu, având ca proprietar altă fereastră de dialog.

public Dialog(Dialog owner, String title, boolean modal) - construieşte o

fereastră de dialog cu titlu, având ca proprietar altă fereastră de dialog şi indicându-se dacă

este sau nu modală.

Metode

Metodele clasei Window, la care se adaugă următoarele:

public boolean isModal() - indică dacă fereastra de dialog este sau nu modală.

public void setModal(boolean b) - specifică dacă fereastra de dialog va fi sau nu

modală.

public String getTitle() - întoarce titlul ferestrei de dialog (poate fi şi null).

public void setTitle(String title) - setează titlul ferestrei de dialog.

public boolean isResizable() - îndică dacă fereastra de dialog este sau nu

redimensionabilă.

public void setResizable(boolean resizable) - specifică dacă această fereastră de dialog va fi

sau nu redimensionabilă.

Clasa Dimension

public class Dimension extends Dimension2D implements Serializable

Page 397: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

397

Instanţele acestei clase conţin dimensiunile orizontală şi vericală ale unei componente,

exprimate ca numere întregi.

Câmpuri

public int width - lăţimea.

public int height - înălţimea.

Constructori

public Dimension() - construieşte o instanţă a clasei Dimension, conţinând dimensiuni

nule.

public Dimension(Dimension d) - construieşte o copie a lui d.

public Dimension(int width, int height) - construieşte o instanţă a clasei Dimension,

conţinând lăţimea width şi înălţimea height.

Metode

public double getWidth() - întoarce lăţimea.

public double getHeight() - întoarce înălţimea.

public void setSize(double width, double height) - setează lăţimea şi înălţimea,

argumentele fiind de tip double.

public void setSize(int width, int height) - setează lăţimea şi înălţimea,

argumentele fiind de tip int.

public boolean equals(Object obj) - redefineşte metoda equals din clasa Object.

Clasa Event

public class Event extends Object implements Serializable

Clasa Event este clasa evenimentelor generate de interfaţa utilizator grafică utilizată în JDK

1.0 (în prima versiune a Java API) şi menţinută în continuare pentru compatibilitate, deşi

începând cu JDK 1.1 ea a fost înlocuită prin clasa AWTEvent.

Clasa FlowLayout

Page 398: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

398

Gestionarul de poziţionare FlowLayout plasează componentele pe suprafaţa containerului pe

linii succesive, de la stânga la dreapta şi de sus în jos, ca literele dintr-un text. Fiecare

componentă are deimensiunile ei preferate. Alinierea componentelor poate fi făcută la stânga,

la dreapta sau pe centru (alinierea implicită este pe centru). Dacă se modifică dimensiunile

containerului, componentele se rearanjează, menţinându-şi ordinea şi dimensiunile, dar

putând trece de pe o linie pe alta.

Clasa conţine câmpuri statice finale, cu denumirile modurilor de aliniere a componentelor.

Câmpuri

public static final int LEFT - aliniere la stânga.

public static final int CENTER - aliniere la centru.

public static final int RIGHT - aliniere la dreapta

public static final int LEADING - aliniere la muchia frontală pentru orientarea dată a

containerului (adică aliniere la stânga, în cazul când ordinea de plasare este de la stânga la

dreapta).

public static final int TRAILING - aliniere la muchia terminală, ţinând cont de

orientarea dată a containerului (deci aliniere la dreapta, dacă ordinea de plasare a

componentelor este de la stânga la dreapta).

Constructori

public FlowLayout() - construieşte un FlowLayout cu aliniere implicită a componentelor

(la centru) şi cu spaţii libere între componente de 5 unităţi.

public FlowLayout(int align) - construieşte un nou FlowLayout, cu alinierea

componentelor specificată. Parametrul align poate fi unul din câmpurile: FlowLayout.LEFT,

FlowLayout.CENTER, FlowLayout.RIGHT.

public FlowLayout(int align, int hgap, int vgap) - construieşte un nou

FlowLayout, fiind specificate alinierea şi spaţiile libere între componente pe orizontală şi pe

verticală.

Metode

metodele din interfaţa LayoutManager, la care se adaugă următoarele:

public int getAlignment() - întoarce alinierea.

public void setAlignment(int align) - setează alinierea. Parametrul align poate fi unul

din câmpurile: FlowLayout.LEFT, FlowLayout.CENTER, FlowLayout.RIGHT.

public int getHgap() - întoarce spaţiul liber între componente pe orizontală.

public void setHgap(int hgap) - setează spaţiul liber între componente pe orizontală.

Page 399: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

399

public int getVgap() - întoarce spaţiul liber între componente pe verticală.

public void setVgap(int vgap) - setează spaţiul liber între componente pe verticală.

Clasa Font

public class Font extends Object implements Serializable

Instanţele clasei Font reprezintă fonturi şi încorporează fiecare informaţii privind forma,

mărimea şi stilul unui caracter. Caracterele sunt simbolurile tipografice folosite în texte.

Stilurile sunt: plain (normal), bold, italic, bold+italic. Mărimea fontului (înălţimea literei

majuscule) se exprimă în puncte tipografice.

Cele mai răspândite fonturi folosite în programele Java sunt:

Serif - toate caracterele au serifuri, adică mici liniuţe prin care se termină liniile

principale care formează caracterul respectiv; lăţimea caracterelor este variabilă, de exemplu

W este mai lat decât I).

SansSerif - caracterele nu au serifuri, dar au lăţimea variabilă.

Monospaced - toate caracterele au aceeaşi lăţime, ca cele de la maşina de scris.

Aceste fonturi există pe toate maşinile virtuale Java, dar pot fi instalate şi alte fonturi.

Câmpuri statice finale pentru stiluri

public static final int PLAIN - stilul PLAIN (normal).

public static final int BOLD - stilul BOLD (caractere îngroşate, aldine).

public static final int ITALIC - stilul italic (cursiv).

Constructori

public Font(String name, int style, int size) - se construieşte un nou font, fiind

specificate numele fontului, stilul şi mărimea. Numele fontului poate fi "Serif", "SansSerif",

"Monospaced" sau alt stil existent pe maşina virtuală Java respectivă. Stiluol poate fi

Font.PLAIN, Font.BOLD, Font.ITALIC sau Font.BOLD|Font.ITALIC.

public Font(Map attributes) - construieşte un nou font, folosind atributele specificate

prin argument. La alcătuirea mapării atributelor se folosesc numai cheile definite în clasa

TextAttribute (pentru detalii se va consulta Java API).

Metode principale

public static Font getFont(Map attributes) - întoarce fontul care corespunde cel mai

bine setului de atribute specificat ca argument.

public AffineTransform getTransform() - întoarce transformarea asociată acestui font.

Page 400: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

400

public String getFamily() - întoarce numele familiei de fonturi din care face parte acest

font.

public String getPSName() - întoarce numele PostScript al acestui font.

public String getName() - întoarce numele logic al acestui font. Se va folosi

getFontName() pentru a afla numele fontului.

public String getFontName() - întoarce numele fontului.

public int getStyle() - întoarce stilul fontului.

public int getSize() - întoarce mărimea fontului, exprimată în puncte tipografice.

public boolean isPlain() - indică dacă stilul caracterului este PLAIN (normal).

public boolean isBold() - indică dacă stilul caracterului este BOLD (aldin, îngroşat).

public boolean isItalic() - indică dacă stilul caracterului este ITALIC (cursiv).

public static Font getFont(String nm) - întoarce fontul din lista de proprietăţi a

sistemului. Ca parametru se dă numele proprietăţii.

public static Font decode(String str) - întoarce fontul pe care îl descrie argumentul

str. Dacă argumentul este null, se întoarce un font implicit.

public Font deriveFont(int style, float size) - întoarce un nou font, care să aibă

aceeaşi formă cu acesta, dar să aibă stilul şi mărimea specificate.

public Font deriveFont(float size) - întoarce un nou font, similar acestuia, dar cu

mărimea specificată.

public Font deriveFont(int style) - întoarce un nou font, similar acestuia, dar cu stilul

specificat.

Clasa Frame

public class Frame extends Window implements MenuContainer

Face parte din pachetul java.awt. Instanţele acestei clase sau ale subclaselor ei sunt folosite ca

ferestre pr4incipale ale aplicaţiilor. Un Frame este o fereastră care are chenar şi bară de titlu.

Este o fereastră de cel mai înalt nivel (top-level window), deci poate fi plasată direct pe

ecranul fizic. Generează evenimente de fereastră (din clasa WindowEvent), care pot fi

ascultate cu un WindowListener sau WindowAdapter. La partea superioară i se poate pune o

bară de meniu (MenuBar). Iniţial, cadrul este invizibil, dar poate fi făcut vizibil invocând

setVisible(true), iar dimensiunile se stabilesc prin setSize(int, int), ambele fiind

metode ale clasei Component.

Page 401: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

401

Constructori

public Frame() - construieşte un cadru (Frame) fără titlu.

public Frame(GraphicsConfiguration gc) - construieşte un cadru (Frame) folosind

configuraţia grafică gc (poate fi folosită pentru a afişa cadrul pe alt ecran decât cel principal,

într-un sistem multiecran).

public Frame(String title) - construieşte un cadru (Frame) cu titlul title.

public Frame(String title, GraphicsConfiguration gc) - construieşte un cadru

(Frame) cu titlul title şi cu configuraţia grafică gc.

Metode

public String getTitle() - întoarce titlul cadrului (cel din bara de titlu).

public void setTitle(String title) - pune titlul title în bara de titlu.

public Image getIconImage() - întoarce imaginea care trebuie afişată ca pictogramă la

minimizarea acestui cadru.

public void setIconImage(Image image) - setează imaginea care trebuie afişată ca

pictogramă la minimizarea acestui cadru.

public MenuBar getMenuBar() - îmtoarce bara de meniu a acestui cadru, sau null, dacă ea

nu există.

public void setMenuBar(MenuBar mb) - setează pentru acest cadru bara de meniu mb.

public boolean isResizable() - indică dacă acest cadru poate fi redimensionat de către

utilizator (prin tragere cu mouse-ul). Implicit, toate instanţele clasei Frame sunt

redimensionabile.

public void setResizable(boolean resizable) - setează dacă acest cadru poate sau nu

să fie redimensionat de către utilizator.

public void setState(int state) - setează starea acestui cadru.

public int getState() - întoarce starea acestui cadru.

public void remove(MenuComponent m) - elimină bara de meniu specificată.

public static Frame[] getFrames() - întoarce tabloul tuturor cadrelor (Frame) deschise

de o aplicaţie sau accesibile unui applet.

Clasa Frame moşteneşte şi toate metodele clasei Window, deci şi pe cele ale claselor

Container şi Component.

Page 402: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

402

Clasa Graphics2D

public abstract class Graphics2D extends Graphics

Este noul context grafic, care extinde clasa Graphics, pentru a putea realiza desene mult mai

complexe. Pentru utilizarea acestei clase şi, deci, a aplica în Java tehnicile de grafică 2D,

recomandăm să se consulte documentaţia originală Java API şi capitolul 2D Graphics din

Tutorialul Java.

Clasa GridBagLayout

public class GridBagLayout extends Object implements LayoutManager2, Serializable

Este un gestionar de poziţionare flexibil, care permite să se alinieze orizontal şi vertical

componente de dimensiuni diferite. Pentru folosirea acestei clase recomandăm să se consulte

Tutorialul Java şi să se folosească documentaţia Java API originală.

Clasa GridLayout

public class GridLayout extends Object implements LayoutManager, Serializable

Gestionarii de poziţionare din clasa GridLayout aranjează componentele în container sub

forma unei grile rectangulare. Fiecare celulă a grilei conţine o singură componentă.

Constructori

public GridLayout() - construieşte un GridLayout cu o singură linie de componente.

public GridLayout(int rows, int cols) - construieşte un GridLayout cu rows linii şi

cols coloane. Unul din cele două argumente (dar nu ambele) poate fi 0 (zero).

public GridLayout(int rows, int cols, int hgap, int vgap) - construieşte un nou

GridLayout, specificându-se numărul de linii şi de coloane şi spaţiile libere între componente

pe orizontală şi pe verticală.

Metode

Metodele interfeţei LayoutManager, la care se adaugă următoarele:

public int getRows() - întoarce numărul de linii al grilei.

public void setRows(int rows) - setează numărul de linii al grilei.

public int getColumns() - întoarce numărul de coloane al grilei.

Page 403: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

403

public void setColumns(int cols) - setează numărul de coloane al grilei.

public int getHgap() - întoarce distanţarea pe orizontală a componentelor.

public void setHgap(int hgap) - setează distanţarea pe orizontală a componentelor.

public int getVgap() - întoarce distanţarea pe verticală a componentelor.

public void setVgap(int vgap) - setează distanţarea pe verticală a componentelor.

Clasa Insets

public class Insets extends Object implements Cloneable, Serializable

Instanţele acestei clase conţin lăţimile marginilor libere ale containerelor (care nu conţin

componente). Marginea respectivă poate fi complet liberă, sau poate conţine o bordură sau un

titlu.

Câmpuri

public int top - marginea de sus

public int left - marginea din stânga

public int bottom - marginea de jos

public int right - marginea din dreapta.

Constructor

public Insets(int top, int left, int bottom, int right) - construieşte o instanţă

a clasei Insetws, fiind specificate marginile de sus, stânga, jos şi dreapta.

Metode

Cele moştenite de la clasa Object.

Class Panel

public class Panel extends Container implements Accessible

Panoul este cea mai simplă clasă de containere. Un panou este un dreptunghi fără bordură pe

suprafaţa căruia se pot plasa diferite componente ale interfeţei grafice, inclusiv alte panouri.

Page 404: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

404

Constructori

public Panel() - construieşte un nou panou, având gestionarul de poziţionare implicit

FlowLayout.

public Panel(LayoutManager layout) - construieşte un nou panou, cu gestionarul de

poziţionare specificat.

Metode

Metodele clasei Container şi superclaselor acesteia.

Clasa Point

public class Point extends Point2D implements Serializable

Fiecare instanţă a acestei clase conţine coordonatele (x, y) ale unui punct, exprimate prin

numere întregi.

Constructori

public Point() - construieşte un punct de coordonate (0, 0).

public Point(Point p) - construieşte o copie a punctului p.

public Point(int x, int y) - construieşte un punct de coordonate (x, y).

Metode principale

public double getX() - întoarce coordonata x.

public double getY() - întoarce coordonata y.

public void setLocation(int x, int y) - setează noile valori ale coordonatelor

punctului.

public void translate(int dx, int dy) - efectuează o translaţie a acestui punct, astfel

că noile coordonate vor fi x+dx, y+dy.

Clasa Rectangle

Instanţele acestei clase sunt suprafeţe de formă dreptunghiulară, cu laturile dispuse orizontal

şi vertical, pentru care se dau următoarele elemente:

x, y - coordonatele colţului din stânga sus;

width - lăţimea dreptunghiului;

height - înălţimea dreptunghiului.

Valorile acestor elemente sunt exprimate prin numere întregi.

Page 405: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

405

Constructori

public Rectangle() - construieşte un dreptunghi cu coordonatele (0, 0) şi dimensiunile

nule.

public Rectangle(Rectangle r) - construieşte o copie a dreptunghiului r.

public Rectangle(int x, int y, int width, int height) - construieşte un

dreptunghi, pentru care sunt specificate coordonatele originii (x, y), lăţimea şi înălţimea.

public Rectangle(int width, int height) - construieşte un dreptunghi cu originea în

punctul de coordonate (0 0) şi având specificate lăţimea şi înălţimea.

public Rectangle(Point p, Dimension d) - construieşte un dreptunghi cu originea în

punctul p şi dimensiunile d.

public Rectangle(Point p) - construieşte un dreptunghi cu originea în punctul p şi

dimensiuni nule.

public Rectangle(Dimension d) - construieşte un dreptunghi cu originea în punctul (0, 0)

şi dimensiunile d.

Metode mai frecvent utilizate

public double getX() - întoarce coordonata x a colţului stânga-sus.

public double getY() - întoarce coordonata y a colţului stânga-sus.

public double getWidth() - întoarce lăţimea.

public double getHeight() - întoarce înălţimea.

public void setBounds(int x, int y, int width, int height) - setează toate

elementele date ca parametri.

public void setBounds(Rectangle r) - setează elementele acestui dreptunghi la fel ca la

dreptunghiul r.

public Point getLocation() - întoarce punctul de origine (colţul stânga-sus).

public void setLocation(Point p) - setează punctul de origine (colţul stânga-sus).

public void setLocation(int x, int y) - setează coordonatele punctului de origine

(colţul stânga-sus).

public void translate(int dx, int dy) - translatează dreptunghiul, astfel că noile

coordonate devin (x+dx, y+dy).

public Dimension getSize() - întoarce dimensiunile dreptunghiului.

public void setSize(Dimension d) - setează dimensiunile dreptunghiului.

Page 406: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

406

public void setSize(int width, int height) - setează dimensiunile dreptunghiului.

public boolean contains(Point p) - indică dacă acest dreptunghi conţine punctul p.

public boolean contains(int x, int y) - indică dacă acest dreptunghi conţine punctul

de coordonate (x, y).

public boolean contains(Rectangle r) - indică dacă acest dreptunghi conţine

dreptunghiul r.

public boolean contains(int x, int y, int width, int height) - indică dacă acest

dreptunghi conţine dreptunghiul ale cărui elemente sunt specificate.

public boolean intersects(Rectangle r) - indică dacă acest dreptunghi intersectează

dreptunghiul r.

public Rectangle intersection(Rectangle r) - întoarce intersecţia acestui dreptunghi

cu dreptunghiul r.

public Rectangle union(Rectangle r) - întoarce dreptunghiul cel mai mic care conţine

în întregime acest dreptunghi şi dreptunghiul r.

Clasa Window

public class Window extends Container implements Accessible

Instanţele acestei clase sunt ferestre de cel mai înalt nivel (pot fi plasate direct pe eranul

nativ), fără bordură şi fără bară de meniu. Trebuie să aibă drept proprietar un cadru, o

fereastră de dialog sau o altă instanţă a clasei Window.

Constructori

public Window(Frame owner) - se construieşte o nouă fereastră, având ca proprietar o

instanţă a clasei Frame.

public Window(Window owner) - se construieşte o nouă fereastră, având ca proprietar altă

fereastră din clasa Window.

public Window(Window owner, GraphicsConfiguration gc) - se construieşte o nouă fereastă,

având proprietarul owner şi configuraţia grafică gc (poate fi afişată şi pe un alt ecran fizic, în

sistemele cu mai multe ecrane).

Metode

Metodele clasei Container, la care se adaugă următoarele:

Page 407: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

407

public void pack() - face ca fereastra să fie dimensionată la dimensiunea preferată şi

componentele ei să fie aranjate de către gestionarul de poziţionare, după care fereastra este

făcută afişabilă şi este validată.

public void show() - face fereastra vizibilă pe ecran.

public void hide() - ascunde fereastra (o face invizibilă).

public void toFront() - plasează fereastra deasupra celorlalte de pe ecran.

public void toBack() - plasează fereastra în spatele celorlalte de pe ecran.

public final String getWarningString() - întoarce textul de avertizare, care însoţeşte

această fereastră dacă ea nu este sigură.

public Window getOwner() - întoarce proprietarul ferestrei.

public Window[] getOwnedWindows() - întoarce tabloul ferestrelor, pe care această

fereastră le deţine ca proprietar.

public void addWindowListener(WindowListener l) - adaugă un ascultător de

evenimente de fereastră.

public void removeWindowListener(WindowListener l) - elimină ascultătorul de

evenimente de fereastră specificat.

public EventListener[] getListeners(Class listenerType) - întoarce un tablou al

tuturor ascultătoarelor de evenimente adăugate la această fereastră.

public Component getFocusOwner() - dacă fereastra este activă, întoarce fereastra copil

care este deţine focalizarea.

Interfaţa LayoutManager

Defineşte interfaţa pentru clasele care gestionează poziţionarea componentelor în container.

Clase care implementează această interfaţă: GridLayout, FlowLayout, ViewportLayout,

ScrollPaneLayout, BasicOptionPaneUI.ButtonAreaLayout,

BasicTabbedPaneUI.TabbedPaneLayout, BasicInternalFrameTitlePane.TitlePaneLayout,

BasicScrollBarUI,

BasicInternalFrameUI.InternalFrameLayout,

BasicComboBoxUI.ComboBoxLayoutManager,

BasicSplitPaneDivider.DividerLayout

Page 408: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

408

Metode

public void addLayoutComponent(String name, Component comp) - adaugă la

container componenta comp cu numele name.

public void removeLayoutComponent(Component comp) - elimină din container

componenta specificată.

public Dimension preferredLayoutSize(Container parent) - întoarce dimensiunile

preferate ţinând seama de componentele din containerul părinte specificat.

public Dimension minimumLayoutSize(Container parent) - întoarce dimensiunile

minime ţinând cont de componentele din containerul părinte specificat.

public void layoutContainer(Container parent) - se face redimensionarea şi

poziţionarea componentelor din containerul specificat.

Interfaţa LayoutManager2

public interface LayoutManager2 extends LayoutManager

Clase care implementează această interfaţă: CardLayout, BorderLayout, GridBagLayout,

BoxLayout, OverlayLayout, JRootPane.RootLayout,

BasicSplitPaneUI.BasicHorizontalLayoutManager

Interfaţă pentru clasele de gestionare a poziţionării care folosesc un obiect de restricţii (care

stabileşte restricţiile pe care trebuie să le satisfacă poziţionarea).

Metode

Are toate metodele interfeţei LayoutManager la care se adaugă următoarele metode:

public void addLayoutComponent(Component comp, Object constraints) - adaugă

componenta comp respectând restricţiile constraints.

public Dimension maximumLayoutSize(Container target) - întoarce dimensiunea

maximă a containerului.

public float getLayoutAlignmentX(Container target) - întoarce un număr în

intervalul 0.0 .. 1.0, care indică modul în care se face alinierea componentelor pe axa oX: 0.0

- la origine, 0.5 - la centru, 1.0 - la extremitatea dreaptă.

public float getLayoutAlignmentY(Container target) - întoarce un număr în

intervalul 0.0 .. 1.0, care indică modul în care se face alinierea componentelor pe axa oY: 0.0

- la origine, 0.5 - la centru, 1.0 - la extremitatea de jos.

public void invalidateLayout(Container target) - se invalidează gestionarul de

poziţionare, descărcându-se informaţia pe care o conţine.

Page 409: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

409

Clasa ActionEvent

public class ActionEvent extends AWTEvent

Eveniment semantic, care indică faptul că asupra unei componente a fost exercitată o acţiune

specifică acelei componente (de exemplu, un buton a fost apăsat). Cu ajutorul măştilor date

drept câmpuri statice finale se pot determina anumite caracteristici ale evenimentului produs.

De exemplu, câmpul ALT_MASK permite sa se determine dacă, în momentul generării

evenimentului, era apăsată tasta alt. Aceasta se obţine intersectănd masca cu valoarea

întoarsă de metoda getModifiers().

Câmpuri

public static final int SHIFT_MASK - mască pentru a detecta dacă tasta shift era

apăsată.

public static final int CTRL_MASK - mască pentru a detecta dacă tasta ctrl era apăsată

public static final int META_MASK - mască pentru a detecta dacă tasta meta era apăsată

public static final int ALT_MASK - mască pentru a detecta dacă tasta alt era apăsată.

Metode

Metodele clasei AWTEvent, la care se adaugă următoarele:

public String getActionCommand() - întoarce un şir, care identifică acţiunea de comandă

indicată de acest eveniment.

public int getModifiers() - întoarce modificatorii evenimentului (ce taste de control

erau apasate când s-a produs evenimentul).

public String paramString() - întoarce un şir, care conţine parametrii evenimentului şi

este util în special la depanare.

Clasa AdjustmentEvent

public class AdjustmentEvent extends AWTEvent

Instanţele acestei clase sunt evenimente, generate atunci când este ajustată o mărime specifică

sursei de eveniment respective.

Metode

public Adjustable getAdjustable() - întoarce obiectul ajustabil care a generat acest

eveniment.

public int getValue() - întoarce valoarea curentă a mărimii ajustate.

Page 410: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

410

public int getAdjustmentType() - întoarce tipul de ajustare, care poate fi unul din

următoarele: UNIT_INCREMENT, UNIT_DECREMENT, BLOCK_INCREMENT,

BLOCK_DECREMENT, TRACK.

public String paramString() - întoarce un şir, care conţine parametri necesari, în special,

la depanare.

Clasa ComponentAdapter

public abstract class ComponentAdapter extends Object implements ComponentListener

Clasă abstractă, servind drept prototip pentru realizarea claselor ascultătoare de evenimente

de componentă. Clasa conţine toate metodele interfeţei ComponentListener, dar aceste

metode nu fac nimic (au corpul vid). Penteru a crea un ascultător de evenimente de

componentă, se crează o subclasă a clasei ComponentAdapter, în care se redefinesc numai

metodele efectiv necesare.

Constructor

public ComponentAdapter()

Metode

Toate metodele interfeţei ComponentListener.

Clasa ComponentEvent

public class ComponentEvent extends AWTEvent

Clasa evenimentelor generate la modificarea stării unei componente: deplasare, modificare a

stării, modificare a vizibilităţii. Este, de asemenea, superclasă pentru alte evenimente de

componentă, cum sunt ContainerEvent, FocusEvent, InputEvent, PaintEvent, WindowEvent.

Evenimentele de componentă sunt date numai pentru scopuri de notificare (în mod obişnuit

nu sunt folosite explicit în programul de aplicaţie, ci numai în mod implicit, pentru

redimensionarea şi repoziţionarea componentelor).

Metode

public Component getComponent() - întoarce componenta care a generat evenimentul.

public String paramString() - întoarce un şir de parametri, utili pentru depanare.

Page 411: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

411

Clasa InputEvent

public abstract class InputEvent extends ComponentEvent

Clasă abstractă, care constituie rădăcina ierarhiei de clase pentru evenimente de intrare. Are

ca subclase directe KeyEvent şi MouseEvent.

Conţine câmpuri statice finale, ale căror valori sunt măşti pentru recunoaşterea tipului de

eveniment. Conţine, de asemenea, metode pentru recunoaşterea diferitelor situaţii existente la

generarea evenimentelor de intrare.

Câmpuri statice finale

public static final int SHIFT_MASK - mască pentru tasta SHIFT.

public static final int CTRL_MASK - mască pentru tasta CTRL.

public static final int META_MASK - mască pentru tasta META.

public static final int ALT_MASK - mască pentru tasta ALT.

public static final int ALT_GRAPH_MASK - mască pentru tasta ALT_GRAPH.

public static final int BUTTON1_MASK - mască pentru butonul 1 de mouse.

public static final int BUTTON2_MASK - mască pentru butonul 2 de mouse.

public static final int BUTTON3_MASK - mască pentru butonul 3 de mouse.

Metode

public boolean isShiftDown() - la generarea evenimentului, tasta SHIFT era apăsată.

public boolean isControlDown() - la generarea evenimentului, tasta CTRL era apăsată.

public boolean isMetaDown() - la generarea evenimentului, tasta META era apăsată.

public boolean isAltDown() - la generarea evenimentului, tasta ALT era apăsată.

public boolean isAltGraphDown() - la generarea evenimentului, tasta ALT_GRAPH era

apăsată.

public long getWhen() - întoarce momentul de timp când a avut loc evenimentul (dat de

ceasul sistemului).

public int getModifiers() - întoarce modificatorii (din care, folosind măştile) se pot

obţine caracteristicile evenimentului.

Page 412: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

412

Clasa ItemEvent

public class ItemEvent extends AWTEvent

Eveniment semantic, care arată că un articol a fost selectat sau deselectat. Este generat de

către obiecte selectabile (de exemplu articolele de listă).

Metode

public ItemSelectable getItemSelectable() - întoarce articolul care a generat acest

eveniment.

public Object getItem() - întoarce articolul afectat de către acest eveniment.

public int getStateChange() - întoarce schimbarea de stare care a provocat generarea

evenimentului (poate fi ItemEvent.SELECTED sau ItemEvent.DESELECTED)

public String paramString() - întoarce un şir, care conţine parametrii evenimentului

(poate fi util la depanare).

Clasa KeyAdapter

public abstract class KeyAdapter extends Object implements KeyListener

Adaptor pentru ascultătoarele de evenimente de tastă. Clasa conţine toate metodele din

interfaţa KeyListener, dar aceste metode nu fac nimic (au corpul vid). Pentru a obţine un

ascultător de evenimente de tastă, se face o subclasă în care se redefinesc numai metodele

necesare în aplicaţia respectivă.

Constructor

public KeyAdapter()

Metode

public void keyTyped(KeyEvent e) - a avut loc apăsarea şi eliberarea imediată a unei

taste.

public void keyPressed(KeyEvent e) - a fost apăsată o tastă.

public void keyReleased(KeyEvent e) - a fost eliberată o tastă.

Page 413: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

413

Clasa KeyEvent

public class KeyEvent extends InputEvent

Eveniment care indică faptul că a fost acţionată o tastă. Evenimentul este generat de

componenta care este activă în momentul acţionării tastei.

Clasa conţine câmpuri statice finale, care permit identificarea tastei care a fost apăsate şi a

modificatorilor corespunzători (a tastelor auxiliare care erau apăsate în momentul când s-a

acţionar tasta generatoare de eveniment).

Principalele câmpuri statice finale

public static final int KEY_TYPED - tasta a fost apăsată şi eliberată imediat.

public static final int KEY_PRESSED - tasta a fost apăsată.

public static final int KEY_RELEASED - tasta a fost eliberată.

public static final int VK_ENTER - a fost acţionată tasta ENTER.

public static final int VK_BACK_SPACE - tasta BackSpace

public static final int VK_TAB - tasta Tab

public static final int VK_SHIFT - tasta Shift

public static final int VK_CONTROL - tasta Ctrl

public static final int VK_ALT - tasta Alt

public static final int VK_PAUSE - tasta Pause

public static final int VK_CAPS_LOCK - tasta CapsLock (blocare pe litere majuscule)

public static final int VK_ESCAPE - tasta Esc (Escape)

public static final int VK_SPACE - tasta de spaţiu liber

public static final int VK_PAGE_UP - tasta PageUp (o pagină în sus)

public static final int VK_PAGE_DOWN - tasta PageDown (o pagină în jos)

public static final int VK_END - tasta End

public static final int VK_HOME - tasta Home

public static final int VK_LEFT - tasta cu săgeată spre stânga

public static final int VK_UP - tasta cu săgeata în sus

Page 414: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

414

public static final int VK_RIGHT - tasta cu săgeata la dreapta

public static final int VK_DOWN - tasta cu săgeata în jos

public static final int VK_COMMA - tasta cu virgula (caracterul ",").

public static final int VK_MINUS - tasta cu minus (caracterul "-").

public static final int VK_PERIOD - tasta cu punctul (caracterul ".").

public static final int VK_SLASH - tasta cu linia de fracţie (caracterul "-").

public static final int VK_0 - tasta cu cifra zero

public static final int VK_1 - tasta cu cifra 1

. . . . . . . . . . . . . similar VK_2, VK_3, VK_4, VK_5, VK_6, VK_7, VK_8, VK_9 respectiv pentru cifrele 2, 3, 4, 5, 6, 7, 8, 9

public static final int VK_SEMICOLON - tasta punct şi virgulă (caracterul

";")

public static final int VK_EQUALS - tasta egal (caracterul "=").

public static final int VK_A - tasta cu litera A

public static final int VK_B - tasta cu litera B

. . . . . . . . . . . . . similar pentru literele C, D, E, F, G, K, I, J, K, L, M, N, O, P, Q, R, S, T, U,

V, W, X, Y, Z

public static final int VK_OPEN_BRACKET - tasta paranteză dreaptă deschisă (caracterul

"[" )

public static final int VK_BACK_SLASH - caracterul bară inversă (caracterul "\" )

public static final int VK_CLOSE_BRACKET - caracterul paranteză dreaptă închisă

(caracterul "]" )

public static final int VK_NUMPAD0 - tasta 0 (zero) de pe tastatura numerică.

public static final int VK_NUMPAD1 - tasta 1 de pe tastatura numerică.

. . . . . . . . . . . . similar pentru tastele 2, 3, 4, 5, 6, 7, 8, 9 de pe tastatura numerică

public static final int VK_MULTIPLY - caracterul "*" de pe tastatura numerică

public static final int VK_ADD - caracterul "+" de pe tastatura numerică

public static final int VK_SEPARATER - caracterul separator

Page 415: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

415

public static final int VK_SUBTRACT - caracterul scădere de pe tastatura numerică

public static final int VK_DIVIDE - caracterul împărţire de pe tastatura numerică

public static final int VK_DELETE - tasta Delete (ştergere)

public static final int VK_NUM_LOCK - tasta NumLock (trecerea pe tastatura numerică)

public static final int VK_SCROLL_LOCK - tasta ScrollLock (blocarea defilării)

public static final int VK_F1 - tasta specială F1

. . . . . . . . . . . . . similar pentru tastele speciale F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12,

F13, F14, F15, F16, F17, F18, F19, F20, F21, F22, F23, F24

public static final int VK_PRINTSCREEN - tasta PrintScreen (tipărirea ecranului)

public static final int VK_INSERT - tasta Insert

public static final int VK_HELP - tasta Help

public static final int VK_META - tasta Meta

public static final int VK_BACK_QUOTE - tasta apostrof invers (caracterul ` )

public static final int VK_QUOTE - tasta apostrof (caracterul ' )

public static final int VK_KP_UP - tasta funcţională săgeată în sus

public static final int VK_KP_DOWN - tasta funcţională săgeată în jos

public static final int VK_KP_LEFT - tasta funcţională săgeată spre stânga

public static final int VK_KP_RIGHT - tasta funcţională săgeată la dreapta

public static final int VK_AMPERSAND - tasta ampersand (caracterul "&" )

public static final int VK_ASTERISK - tasta asterisc (caracterul "*" )

public static final int VK_QUOTEDBL - tasta ghilimele (caracterul " )

public static final int VK_LESS - tasta "mai mic" (caracterul "<" )

public static final int VK_GREATER - tasta "mai mare" (caracterul ">" )

public static final int VK_BRACELEFT - tasta "acolada stanga" (caracterul "{" )

public static final int VK_BRACERIGHT - tasta "acolada dreapta" (caracterul "}" )

Page 416: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

416

public static final int VK_AT - tasta cu caracterul at (caracterul "@" )

public static final int VK_COLON - tasta "doua puncte" (caracterul ":" )

public static final int VK_CIRCUMFLEX - tasta circumflex (caracterul "^" )

public static final int VK_DOLLAR - tasta cu simbolul valutar dolar (caracterul "$" )

public static final int VK_EURO_SIGN - tasta cu simbolul valutar Euro.

public static final int VK_EXCLAMATION_MARK - tasta cu semnul de exclamatie

(caracterul "!" )

public static final int VK_LEFT_PARENTHESIS - paranteză stânga (caracterul "(" )

public static final int VK_NUMBER_SIGN - tasta cu simbolul numeric (caracterul "#" )

public static final int VK_PLUS - tasta plus (caracterul "+" )

public static final int VK_RIGHT_PARENTHESIS - tasta paranteza dreapta (caracterul

")" )

public static final int VK_UNDERSCORE - tasta underscore (caracterul "_" )

public static final int VK_ALT_GRAPH - Tasta AltGraph

Metode principale

public int getKeyCode() - întoarce codul tastei asociat cu acest eveniment de intrare (cel

care poate fi comparat cu unul din câmpurile statice finale de mai sus)

public char getKeyChar() - întoarce caracterul logic al tastei (caracterul generat la

apăsarea tastei respective: de exemplu, dacă s-au apăsat tastele Shift A, se întoarce caracterul

"A", în timp ce dacă s-a apăsat simplu tasta A, se întoarce caracterul "a")

public static String getKeyText(int keyCode) - întoarce un şir, care conţine textul

de pe tasta al cărui cod este dat ca argument (un text cum ar fi "HOME", "F1" sau "A").

public static String getKeyModifiersText(int modifiers) - întoarce un şir, care

conţine modificatorii, adică tastele auxiliare apasate la generarea evenimentului respectiv, de

exemplu: "Shift" sau "Ctrl+Shift". (Observaţie: parametrul modifiers poate fi obţinut

aplicând metoda getModifiers() a superclasei InputEvent).

public boolean isActionKey() - indică dacă aceasta este o tastă de acţiune, adică o tastă

prin care utilizatorul cere o acţiune, cum ar fi tastele PageUp, PageDown, F1, F2 etc.

Page 417: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

417

Clasa MouseAdapter

public abstract class MouseAdapter extends Object implements MouseListener

Clasă abstractă, care poate fi extinsă pentru realizarea de ascultătoare de evenimente care

implementează interfaţa MouseListener. Clasa conţine toate metodele interfeţei

MouseListener, dar acestea nu fac nimic (au corpul vid). Extinzând această clasă,

programatorul poate redefini numai acele metode, de care are nevoie.

Constructor public MouseAdapter()

Metode

Cele ale interfeţei MouseListener.

Clasa MouseEvent

public class MouseEvent extends InputEvent

Clasa evenimentelor generate de o componentă, atunci când este acţionat mouse-ul, iar

cursorul de mouse se găseşte pe componenta respectivă. Există două categorii de astfel de

evenimente:

- evenimente de mouse propriu-zise: apăsarea sau eliberarea unui buton de mouse, click de

mouse, intrarea cursorului de mouse pe suprafaţa componentei sau ieşirea de pe aceasta.

- evenimente de mişcare a mouse-ului: tragerea mouse-ului pe suprafaţa componentei

(deplasarea cursorului acestuia în timp ce unul din butoane este ţinut apăsat), sau deplasarea

cursorului de mouse pe suprafaţa componentei (fără să fie apăsat nici unul din butoanele de

mouse).

Evenimentele de mouse sunt ascultate folosind interfaţa MouseListener, iar cele de mişcare

a mouse-ului sunt ascultate prin interfaţa MouseMotionListener.

În pachetul javax.swing.event există, de asemenea, interfaţa MouseInputListener şi clasa

MouseInputAdapter, care permit ascultarea ambelor categorii de evenimente.

Pentru a se afla care buton a fost apăsat, se folosesc modificatorii obţinuţi prin metoda

getModifiers() şi măştile corespunzătoare din superclasa InputEvent.

Metode

Metodele superclaselor AWTEvent şi InputEvent, la care se adaugă următoarele:

Page 418: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

418

public int getX() - întoarce coordonata x a cursorului de mouse din momentul producerii

evenimentului, în sistemul de coordonate al componentei sursă.

public int getY() - întoarce coordonata y a cursorului de mouse din momentul producerii

evenimentului, în sistemul de coordonate al componentei sursă.

public Point getPoint() - întoarce punctuil în care se găsea cursorul de mouse în

momentul producerii evenimentului, în sistemul de coordonate al componentei sursă.

public void translatePoint(int dx, int dy) - tranlatează punctul în care se găsea

cursorul de mouse în momentul producerii evenimentului, adăugând la cele două coordonate

valorile dx şi dy specificate.

public int getClickCount() - întoarce numărul de clickuri (se are în vedere că este

posibil să se facă succesiv, la intervale mici de timp, mai multe clickuri de mouse).

public boolean isPopupTrigger() - indică dacă acest eveniment de mouse este un trigger

de menu pop-up pentru platforma dată.

Clasa MouseMotionAdapter

public abstract class MouseMotionAdapter extends Object implements MouseMotionListener

Clasă abstractă pentru adaptoarele de ascultoare de evenimente de mişcare a mouse-ului.

Această clasă conţine toate metodele interfeţei MouseMotionListener, dar aceste metode nu

fac nimic (corpul lor este vid). Pentru a realiza un ascultător de evenimente de mişcare a

mouse-ului, se extinde această clasă, redefinind numai metodele care sunt necesare efectiv.

Constructor public MouseMotionAdapter()

Metode

Cele ale interfeţei MouseMotionListener.

Clasa TextEvent

public class TextEvent extends AWTEvent

Eveniment semantic, care indică faptul că a avut loc o modificare a textului conţinut în

componenta care a generat evenimentul.

Page 419: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

419

Metodă

public String paramString() - întoarce un şir, care conţine parametrii evenimentului.

Metodă utilă pentru depanare.

Clasa WindowAdapter

public abstract class WindowAdapter extends Object implements WindowListener

Clasă abstractă, care serveşte la crearea claselor ascultătoare de evenimente de fereastră.

Conţine toate metodele interfeţei WindowListener, dar aceste metode nu fac nimic. Pentru a

crea o clasă ascultătoare de evenimente de fereastră, se crează o subclasă a clasei

WindowAdapter, redefinind numai metodele efectiv necesare în aplicaţia respectivă.

Constructor

public WindowAdapter()

Metode

Toate metodele interfeţei WindowListener.

Clasa WindowEvent

public class WindowEvent extends ComponentEvent

Clasă de evenimente de nivel coborât, care indică faptul că a avut loc o modificare a stării

unei ferestre: fereastra s-a deschis, urmează să se închidă, s-a închis, s-a activat, s-a

dezactivat, s-a iconificat sau deiconificat.

Metode

Metodele superclasei ComponentEvent, la care se adaugă următoarea:

public Window getWindow() - întoarce fereastra care a generat evenimentul.

Interfaţa ActionListener

public interface ActionListener extends EventListener

Page 420: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

420

Această interfaţă este implementată de clasele ascultătoare de evenimente de acţiune. Aceste

ascultătoare pot fi adăugate la componentele care suportă metoda

addActionListener(actionListener l). Când componenta respectivă generează un

ActionEvent, este activată metoda actionPerformed a ascultătorului.

Metodă

public void actionPerformed(ActionEvent e) - metodă invocată când se produce un

eveniment din clasa ActionEvent.

Interfaţa AdjustmentListener

public interface AdjustmentListener extends EventListener

Interfaţă pentru ascultătoarele de evenimente de ajustare.

Metodă

public void adjustmentValueChanged(AdjustmentEvent e) - este invocată când are loc

ajustarea obiectului care generează evenimentul.

Interfaţa ComponentListener

public interface ComponentListener extends EventListener

Interfaţă pentru ascultătoarele de evenimente de componentă. Ascultarea acestor evenimente

se face numai în scop de notificare, deoarece tratarea lor se face automat de către AWT. În

loc de a crea o clasă care implementează direct această interfaţă, se poate crea o subclasă a

clasei ComponentAdapter.

Metode

public void componentResized(ComponentEvent e) - componenta şi-a modificat

dimensiunile.

public void componentMoved(ComponentEvent e) - componenta s-a deplasat.

public void componentShown(ComponentEvent e) - componenta a fost făcută vizibilă.

public void componentHidden(ComponentEvent e) - componenta a fost făcută

invizibilă.

Page 421: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

421

Interfaţa ItemListener

public interface ItemListener extends EventListener

Interfaţa pentru ascultătoare de evenimente de articol.

Metodă

public void itemStateChanged(ItemEvent e) - este invocată atunci, când are loc o

modificare a stării ogiectului care generează evenimente de articol (ItemEvent).

Interfaţa KeyListener

public interface KeyListener extends EventListener

Interfaţă pentru ascultătoarele de evenimente de tastă. În loc de creea un ascultător de

evenimente care implementează direct această interfaţă, se poate extinde clasa KeyAdapter.

Pentru a afla care tastă a provocat generarea evenimentelor, se folosesc metodele şi măştile

din clasa KeyEvent.

Metode

public void keyTyped(KeyEvent e) - a avut loc apăsarea şi eliberarea imediată a unei

taste.

public void keyPressed(KeyEvent e) - a fost apăsată o tastă.

public void keyReleased(KeyEvent e) - a fost eliberată o tastă.

Interfaţa MouseListener

public interface MouseListener extends EventListener

Interfaţă pentru ascultătoarele de mouse care ascultă principalele evenimente generate de

acesta, respectiv apăsarea sau eliberarea unui buton, click de mouse, intrarea cursorului de

mouse pe suprafaţa unei componente sau ieşirea acestuia. Pentru ascultarea evenimentelor de

mişcare a mouse-ului se foloseşte interfaţa MouseMotionListener.

În loc de a se crea o clasă de ascultare care implementează direct această interfaţă, se poate

crea o subclasă a clasei MouseAdapter.

Page 422: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

422

Metode

public void mouseClicked(MouseEvent e) - metodă invocată când s-a produs un click de

mouse.

public void mousePressed(MouseEvent e) - metodă invocată când este apăsat unul din

butoanele de mouse.

public void mouseReleased(MouseEvent e) - metodă invocată când este eliberat unul

din butoanele de mouse.

public void mouseEntered(MouseEvent e) - metodă invocată când cursorul de mouse

intră pe suprafaţa unei componente.

public void mouseExited(MouseEvent e) - metodă invocată când cursorul de mouse

iese de pe suprafaţa unei componente.

Interfaţa MouseMotionListener

public interface MouseMotionListener extends EventListener

Interfaţă pentru ascultătoarele de evenimente care se produc la mişcarea mouse-ului. În loc de

a crea o clasă care implementează direct această interfaţă, se poate crea o subclasă a clasei

MouseMotionAdapter.

Metode

public void mouseDragged(MouseEvent e) - mouse-ul a fost "tras" (adică a fost deplasat

menţinând unul din butoane apăsat).

public void mouseMoved(MouseEvent e) - mouse-ul a fost mişcat (fără să fie apăsat nici

unul din butoane).

Interfaţa TextListener

public interface TextListener extends EventListener

Interfaţă pentru clasele de ascultare a evenimentelor de text. Astfel de evenimente sunt

generate la modificarea textului conţinut într-o componentă.

Metodă

public void textValueChanged(TextEvent e) - metodă invocată când a avut loc o

modificare a textului.

Page 423: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

423

Interfaţa WindowListener

public interface WindowListener extends EventListener

Interfaţă pentru ascultătoarele de evenimente de fereastră. În loc de a crea o clasă ascultătoare

care implementează direct această interfaţă, se poate crea o subclasă a clasei WindowAdapter.

Metode

public void windowOpened(WindowEvent e) - metodă invocată când fereastra a fost

deschisă.

public void windowClosing(WindowEvent e) - metodă invocată când fereastra urmează

să se închidă (a fost apăsat butonul de închidere din colţul dreapta-sus, sau a fost selectat

articolul Close din meniul din colţul stânga-sus).

public void windowClosed(WindowEvent e) - metodă invocată când fereastra a fost

închisă.

public void windowIconified(WindowEvent e) - metodă invocată când fereastra a fost

iconificată.

public void windowDeiconified(WindowEvent e) - metodă invocată când fereastra a

fost deiconificată.

public void windowActivated(WindowEvent e) - metodă invocată când fereastra a fost

activată (poate primi intrări de la tastatură şi poate genera evenimente de tastă)

public void windowDeactivated(WindowEvent e) - metodă invocată când fereastra a

fost dezactivată (nu mai primeşte intrări de la tastatură)

Clasa AbstractButton

public abstract class AbstractButton extends JComponent implements ItemSelectable,

SwingConstants

Clasă abstractă. Superclasă a claselor de butoane şi de articoloe de meniu. Butonul poate

conţine un text şi/sau o pictogramă.

Când este apăsat (se pune pe buton cursorul de mouse şi se apasă unul din butoanele de la

mouse), butonul generează un eveniment de acţiune. Numele acestui eveniment

(ActionCommand) este implicit identic cu textul de pe buton, dar el poate fi modificat prin

metoda setActionCommand şi poate fi aflat prin metoda getActionCommand.

Page 424: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

424

Butonului i se poate ataşa şi o mnemonică, folosind metoda setMnemonic. Aceasta este o

tastă, a cărei acţionare are acelaşi efect ca acţionarea butonului respectiv.

Clasa conţine foarte multe metode, pentru cunoaşterea cărora recomandăm consultarea

documentaţiei Java API.

Constructor public AbstractButton()

Metode principale

public String getText() - întoarce textul butonului.

public void setText(String text) - setează textul butonului.

public boolean isSelected() - indică dacă acest buton sau articol de meniu este selectat.

public void setSelected(boolean b) - setează pentru ascest buton sau articol de meniu

starea selectat sau neselectat.

public void setMargin(Insets m) - setează marginile dintre bordură şi text.

public Insets getMargin() - întoarce marginile dintre bordură şi text.

public Icon getIcon() - întoarce pictograma implicită conţinută în buton.

public void setIcon(Icon defaultIcon) - setează pictograma implicită conţinută în

buton.

public void setActionCommand(String actionCommand) - se setează numele acţiunii de

comandă generată la apăsarea acestui buton.

public String getActionCommand() - întoarce numele acţiunii de comandă produsă de

acest buton.

public int getMnemonic() - întoarce mnemonica ataşată acestui buton (sau null, dacă ea

nu există).

public void setMnemonic(int mnemonic) - setează mnemonica ataşată acestui buton,

specificând ca parametru codul tastei respective (codul conţinut în clasa KeyEvent, de

exemplu KeyEvent.VK_A ).

public void setMnemonic(char mnemonic) - setează mnemonica ataşată acestui buton,

indicând caracterul desenat pe tasta respectivă (de exemplu 'A').

public void addChangeListener(ChangeListener l) - adaugă un ascultător de

evenimente de schimbare.

public void removeChangeListener(ChangeListener l) - elimină ascultătorul de

evenimente de schimbare specificat.

Page 425: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

425

public void addActionListener(ActionListener l) - adaugă un ascultător de

evenimente de acţiune.

public void removeActionListener(ActionListener l) - elimină ascultătorul de

evenimente de acţiune specificat.

public void addItemListener(ItemListener l) - adaugă un ascultător de evenimente

de articol.

public void removeItemListener(ItemListener l) - elimină ascultătorul de

evenimente de acţiune specificat.

public void setEnabled(boolean b) - face ca butonul să fie sau nu valabil.

public String getLabel() - întoarce textul de pe buton.

public void setLabel(String label) - setează textul butonului.

Clasa Box.Filler

public static class Box.Filler extends Component implements Accessible

O componentă invizibilă, folosită în instanţele clasei Box pentru distanţarea altor

componente. Este clasă imbricată în clasa Box.

Constructor

public Box.Filler(Dimension min, Dimension pref, Dimension max) - se creează

un BoxFiller, fiind specificate dimensiunile minimă, preferată şi maximă.

Metode

public void changeShape(Dimension min, Dimension pref, Dimension max) - se

modifică dimensiunile, fiind specificate noile dimensiuni (minimă, preferată şi maximă).

public Dimension getMinimumSize() - intoarce dimensiunea minimă.

public Dimension getPreferredSize() - întoarce dimensiunea preferată.

public Dimension getMaximumSize() - întoarce dimensiunea maximă.

public AccessibleContext getAccessibleContext() - întoarce contextul accesibil.

Page 426: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

426

Clasa ButtonGroup

public class ButtonGroup extends Object implements Serializable

Instanţele clasei ButtonGroup nu sunt componente grafice propriu-zise, rolul lor fiind de a

creea grupuri de butoane. Toate butoanele conţinute într-un grup sunt legate logic între ele,

astfel că numai un singur buton din grup se poate găsi la un moment dat în starea "apăsat",

celelalte fiind în starea "eliberat". Când se apasă un buton, se eliberează automat butonul din

acelaşi grup, care era apăsat anterior.Se foloseşte, de regulă, la gruparea butoanelor din

clasele JRadioButton şi JRadioButtonMenuItem.

Constructor

public ButtonGroup()

Metode principale

public void add(AbstractButton b) - se adaugă la grup butonul specificat.

public void remove(AbstractButton b) - se elimină din grup butonul specificat

public Enumeration getElements() - întoarce o enumeraţie a elementelor grupului.

public int getButtonCount() - întoarce numărul butoanelor din grup.

Clasa JApplet

public class JApplet extends Applet implements Accessible, RootPaneContainer

Este o versiune extinsă a clasei Applet, introdusă în Swing. Principala deosebire faţă de clasa

Applet este că, la fel ca la clasa JFrame, adăugarea de componente nu se face direct la applet.

Fiecare instanţă a clasei JApplet conţine un container numit contentPane, la care se adaugă

toqate celelalte componente. Referinţa la acest container se obţine prin metoda

getContentPane. Tot ca la JFrame, un JApplet poate avea bară de meniu, pusă prin metoda

SetJMenuBar().

Explicatii despre crearea şi utilizarea appleturilor se dau în secţiunea Applet-uri din acest

curs. Explicaţii mai ample se gasesc în secţiunea Writing Applets din Tutorialul Java.

Descrierea tuturor metodelor este dată în Java API.

Metode frecvent utilizate

Toate metodele superclasei Applet, la care se adaugă:

public void update(Graphics g) - invocă metoda paint(g).

public void setJMenuBar(JMenuBar menuBar) - setează bara de meniu specificată.

Page 427: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

427

public JMenuBar getJMenuBar() - întoarce bara de meniu.

public Container getContentPane() - întoarce containerul contentPane al acestui

JApplet.

Clasa JButton

public class JButton extends AbstractButton implements Accessible

Orice instanţă a acestei clase este un buton cu o singură stare stabilă (starea normală). Dacă

butonul este apăsat (punând pe el cursorul de mouse şi apăsând butonul mouse-ului), el îşi

schimbă temporar starea şi aspectul, dar revine la starea normală imediat ce este eliberat.

Butonul poate conţine un text şi/sau o imagine (o pictogramă). Butonului i se poate ataşa un

text volant (ToolTip) şi o mnemonică (o tastă, a cărei apăsare are acelaşi efect cu apăsarea

butonului respectiv).

Consultaţi şi secţiunea Butonul obişnuit din acest manual.

Constructori

public JButton() - creează un buton, care nu conţine text sau pictogramă.

public JButton(Icon icon) - creează un buton, care conţine pictograma specificată.

public JButton(String text) - creează un buton, care conţine textul specificat.

public JButton(Action a) - creează un buton, cu proprietăţile date de acţiunea specificată

ca parametru.

public JButton(String text, Icon icon) - creează un buton, care va conţine textul şui

acţiunea specificate.

Metode

Metodele principale sunt cele ale clasei AbstractButton. Pentru a cunoaşte toate metodele, se

va consulta documentaţia Java API.

Clasa JCheckBoxMenuItem

public class JCheckBoxMenuItem extends JMenuItem implements SwingConstants,

Accessible

Este un articol de meniu care se comportă la fel ca o casetă de validare (JCheckBox). Are

aspectul unui patrat în care apare un simbol de validare (V) dacă este selectat şi nu apare

Page 428: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

428

acest simbol dacă este deselectat. Caseta de validare poate fi însoţită de un text sau/şi o

pictogramă.

Constructori

public JCheckBoxMenuItem() - construieşte un JChecBoxMenuItem fără pictogramă şi

text.

public JCheckBoxMenuItem(Icon icon) - construieşte un JChecBoxMenuItem cu

pictograma specificată.

public JCheckBoxMenuItem(String text) - construieşte un JChecBoxMenuItem cu textul

specificat.

public JCheckBoxMenuItem(String text, Icon icon) - construieşte un

JChecBoxMenuItem cu textul şi pictograma specificate.

public JCheckBoxMenuItem(String text, boolean b) - construieşte un

JChecBoxMenuItem cu textul specificat, indicând dacă în starea iniţială este sau nu selectat.

public JCheckBoxMenuItem(String text, Icon icon, boolean b) - construieşte un

JChecBoxMenuItem cu textul şi pictograma specificate, indicând dacă în starea iniţială este

sau nu selectat.

Metode principale

public boolean getState() - întoarce starea.

public void setState(boolean b) - setează starea.

Clasa JComponent

public abstract class JComponent extends Container implements Serializable

Clasa de bază pentru toate componentele Swing, cu excepţia containerelor de cel mai înalt

nivel (JFrame, JDialog, JApplet). Orice JComponentă poate avea o bordură. Oricărei

JComponente i se poate ataşa un "text volant" ("ToolTip"), adică un text explicativ, care

apare dacă se pune cursorul de mouse pe componenta respectivă.

Clasa JComponent conţine numeroase câmpuri şi metode. Aici se dau numai metodele cele

mai frecvent folosite. Pentru o documentaţie completă se va consulta Java API.

Constructor public JComponent()

Page 429: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

429

Metode frecvent utilizate

public void update(Graphics g) - invocă metoda paint(g) pentru această componentă.

public void paint(Graphics g) - desenează această componentă, folosind contextul

grafic g.

public void setPreferredSize(Dimension preferredSize) - setează dimensiunea

preferată a componentei. Dacă este null, dimensiunea preferată va fi stabilită implicit.

public Dimension getPreferredSize() - întoarce dimensiunea preferată.

public void setMaximumSize(Dimension maximumSize) - setează dimensiunea maximă

a componentei.

public Dimension getMaximumSize() - întoarce dimensiunea maximă a componentei.

public void setMinimumSize(Dimension minimumSize) - setează dimensiunea minimă a

componentei.

public Dimension getMinimumSize() - întoarce dimensiunea minimă a componentei.

public boolean contains(int x, int y) - indică dacă această componentă conţine

punctul de coordonate (x, y). Este utilă la prelucrarea evenimentelor de mouse.

public void setBorder(Border border) - setează bordura componentei.

public Border getBorder() - întoarce bordura componentei.

public Graphics getGraphics() - întoarce contextul grafic al acestei componente.

public void setVisible(boolean aFlag) - setează dacă această componentă este sau nu

vizibilă.

public void setEnabled(boolean enabled) - setează dacă această componentă poate sau

nu primi intrări de la utilizator.

public void setForeground(Color fg) - setează culoarea de prim-plan a componentei.

public void setBackground(Color bg) - setează culoarea de fond a componentei.

public void setFont(Font font) - setează fontul componentei.

public boolean isFocusTraversable() - indică dacă această componentă poate fi

traversată la focalizare (este printre cele care sunt focalizate una după alta, când se apasă tasta

Tab).

public void setToolTipText(String text) - setează textul volant (ToolTip) pentru

această componentă.

Page 430: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

430

public String getToolTipText() - întoarce textul volant (ToolTip) ataşat acestei

componente.

public Point getToolTipLocation(MouseEvent event) - întoarce locaţia textului volant

(ToolTip) ataşat acestei componente.

public static boolean isLightweightComponent(Component c) - indică dacă această

componentă este "uşoară", adică nu are ca suport o componentă nativă de pe platforma

respectivă.

public boolean isOpaque() - indică dacă această componentă este complet opacă.

public void setOpaque(boolean isOpaque) - setează dacă această componentă este sau

nu opacă.

public EventListener[] getListeners(Class listenerType) - întoarce ascultătorii de

evenimente ataşaţi acestei componente.

public void repaint(long tm, int x, int y, int width, int height) -

redesenează dreptunghiul specificat, după tm milisecunde.

public void repaint(Rectangle r) - redesenează dreptunghiul r.

public void paintImmediately(int x, int y, int w, int h) - redesenează imediat

dreptunghiul specificat.

public void paintImmediately(Rectangle r) - redesenează imediat dreptunghiul

specificat.

public JRootPane getRootPane() - întoarce JRoorpane care este ancestor (ascendent) al

acestei componente, sau null, dacă nu există.

protected String paramString() - întoarce un şir, conţinând parametri utili la depanare.

Clasa JDialog

public class JDialog extends Dialog implements WindowConstants, Accessible,

RootPaneContainer

Instanţele acestei clase sunt ferestre de dialog. Componentele nu se adaugă direct la fereastra

JDialog, ci la un container numit contentPane, conţinut în aceasta şi care poate fi obţinut

prin metoda getContentPane(). Fereastra JDialog poate avea şi bară de meniu.

Constructori

public JDialog() - construieşte o fereastră de dialog fără titlu şi fără a se specifica

proprietarul.

Page 431: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

431

public JDialog(Frame owner) - construieşte o fereastră de dialog fără titlu, având ca

proprietar cadrul (Frame) specificat.

public JDialog(Frame owner, boolean modal) - construieşte o fereastră de dialog fără

titlu, având ca proprietar cadrul owner şi indicându-se dacă este sau nu modală.

public JDialog(Frame owner, String title) - construieşte o fereastră de dialog,

specificându-se proprietarul şi titlul ferestrei.

public JDialog(Frame owner, String title, boolean modal) - construieşte o

fereastră de dialog, specificându-se proprietarul, titlul şi dacă este sau nu modală.

public JDialog(Dialog owner) - se construieşte o fereastră de dialog, având ca proprietar

altă fereastră de dialog, dată ca argument.

public JDialog(Dialog owner, boolean modal) - se construieşte o fereastră de dialog,

având ca proprietar altă fereastră de dialog, dată ca argument şi specificându-se dacă este sau

nu modală.

public JDialog(Dialog owner, String title) - construieşte o fereastră de dialog,

specificându-se proprietarul şi titlul ferestrei.

public JDialog(Dialog owner, String title, boolean modal) - construieşte o

fereastră de dialog, specificându-se proprietarul, titlul şi dacă este sau nu modală.

Metode principale

Metodele clasei Dialog, la care se adaugă:

public void setDefaultCloseOperation(int operation) - setează operaţia implicită,

care areloc când se execută comanda Close (când se apasă butonul de închidere a ferestrei dic

bolţul din dreapta sus, sau se selectează opţiunea Close din meniul din colţul din stânga-sus).

Operaţia dată ca argument poate fiuna din următoarele:

WindowConstants.DO_NOTHING_ON_CLOSE - nu se face nimic în mod implicit.

WindowConstants.HIDE_ON_CLOSE - fereasrtra este ascunsă (aceasta este opţiunea

implicită).

WindowConstants.DISPOSE_ON_CLOSE - fereastra este ascunsă şi disponibilizată

(eliminată).

public int getDefaultCloseOperation() - întoarce operaţia Close implicită.

public void update(Graphics g) - invocă metoda paint(g).

public void setJMenuBar(JMenuBar menu) - setează bara de meniu.

public JMenuBar getJMenuBar() - întoarce bara de meniu.

public Container getContentPane() - întoarce containerul contentPane al acestei

ferestre de dialog.

Page 432: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

432

public void setContentPane(Container contentPane) - setează containerul

contentPane.

Clasa JEditorPane

public class JEditorPane extends JTextComponent

Clasă pentru realizarea panourilor de editare care suportă diferite formate de text, cum ar fi

text simplu, text HTML sau text RTF. Are subclasa JTextPane.

Se recomandă consultarea documentaţiei Java API şi a secţiunii UsingTextComponents din

Tutorialul Java.

Class JFileChooser

public class JFileChooser extends JComponent implements Accessible

Instanţele clasei JFileChooser sunt selectoare de fişiere. Ele vizualizează pe ecran arborele

directoarelor şi fişierelor de pe disc şi permit selectarea intercactivă (cu mouse-ul) a fişierului

dorit. Clasa conţine un număr mare de câmpuri, constructori şi metode. Pentru o mai bună

documentare se recomandă a se consulta Java API şi capitolul How to use FileChoosers din

Tutorialul Java.

Constructori principali

public JFileChooser() - construieşte un selector de fişiere cu pointer către directorul

utilizatorului (users home directory).

public JFileChooser(String currentDirectoryPath) - construieşte un selector de

fişiere cu pointer către directorul specificat prin calea dată ca argument.

public JFileChooser(File currentDirectory) - construieşte un selector de fişiere cu

pointer către directorul specificat prin calea dată ca argument.

Metode frecvent utilizate

public File getSelectedFile() - întoarce fişierul selectat.

public void setSelectedFile(File file) - setează fişierul selectat.

public File[] getSelectedFiles() - întoarce tabloul fişierelor selectate.

public void setSelectedFiles(File[] selectedFiles) - setează ca selecate fişierele

specificate prin tabloul dat ca argument.

Page 433: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

433

public File getCurrentDirectory() - întoarce directorul curent.

public void setCurrentDirectory(File dir) - setează directorul curent.

public void changeToParentDirectory() - trece de la directorul curent la părintele

acestuia.

public void ensureFileIsVisible(File f) - asigură că fişierul dat ca argument este

vizibil (visible) şi nu ascuns (hidden).

public int showOpenDialog(Component parent) throws HeadlessException -

creează o fereastră de dialog pentru deschiderea fişierului. Fereastra întoarce o valoare

corespunzătoare butonului pe care s-a apăsat şi care poate fi una din următoarele:

JFileChooser.CANCEL_OPTION, JFileChooser.APPROVE_OPTION,

JFileChooser.ERROR_OPTION (ultima în caz de eroare).

public int showSaveDialog(Component parent) throws HeadlessException -

creează o fereastră de dialog pentru salvarea fişierului. Fereastra întoarce o valoare

corespunzătoare butonului pe care s-a apăsat şi care poate fi una din următoarele:

JFileChooser.CANCEL_OPTION, JFileChooser.APPROVE_OPTION,

JFileChooser.ERROR_OPTION (ultima în caz de eroare).

public void addActionListener(ActionListener l) - adaugă un ascultător de

evenimente de acţiune.

public void removeActionListener(ActionListener l) - elimină un ascultător de

evenimente de acţiune.

public ActionListener[] getActionListeners() - întoarce tabloul ascultătoarelor de

evenimente de acţiune înregistrate la acest JFileChooser.

Clasa JFrame

public class JFrame extends Frame implements WindowConstants, Accessible,

RootPaneContainer

Este varianta Swing a clasei Frame din AWT, fiind o subclasă a acesteia. O deosebire

importantă între cele două clase este că, în clasa JFrame, componentele nu se mai adaugă

direct la fereastra (la frame), ci la un panou conţinut de aceasta, numit contentPane. O

referinţă la contentPane se obţine prin metoda getContentPane(). Operaţiile cu acest

contentPane (adăugarea şi eliminarea de componente, setarea gestionarului de poziţionare

etc) se fac folosind metodele clasei Container.

In JFrame se poate pune, de asemenea, o bară de meniu.

Page 434: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

434

Pentru o mai bună cunoaştere a structurii şi utilizării clasei JFrame, recomandăm să se

studieze capitolul UsingTop-Level Containers din Tutorialul Java.

Constructori

public JFrame() - construieşte un JFrame, iniţial invizibil şi fără titlu.

public JFrame(String title) - construieşte un JFrame, iniţial invizibil, cu titlul

specificat.

public JFrame(GraphicsConfiguration gc) - construieşte un JFrame fără titlu, cu

configuraţia grafică specificată, iniţial invizibil.

public JFrame(String title, GraphicsConfiguration gc) - construieşte un JFrame

cu titlul şi configuraţia grafică specificate, iniţial invizibil.

Metode frecvent utilizate

public void setDefaultCloseOperation(int operation) - se setează acţiunea care va

fi efectuată, dacă se solicită operaţia "close" pentru acest JFrame (se apasă cu mouse-ul pe

butonul de închidere din dreapta-sus, sau se selectează opţiunea Close din meniul din stînga-

sus). Ca argument al metodei se poate da unul din următoarele:

WindowConstants.DO_NOTHING_ON_CLOSE - nu se face nimic

WindowConstants.HIDE_ON_CLOSE - fereasrtra este ascunsă (aceasta este opţiunea

implicită).

WindowConstants.DISPOSE_ON_CLOSE - fereastra este ascunsă şi disponibilizată

(eliminată).

JFrame.EXIT_ON_CLOSE - fereastra este închisă şi se incheie executarea aplicaţiei

(opţiune permisă numai în aplicaţii, nu şi în appleturi).

public int getDefaultCloseOperation() - întoarce operaţia de închidere implicită.

public void update(Graphics g) - invocă metoda paint(g).

public void setJMenuBar(JMenuBar menubar) - pune în JFrame bara de meniu

specificată.

public JMenuBar getJMenuBar() - întoarce bara de meniu (sau null, dacă nu există)

public Container getContentPane() - întoarce containerul contentPane al acestui

JFrame. La acest container se adaugă componentele ferestrei.

public void setContentPane(Container contentPane) - setează containerul

contentPane pentru această fereastră.

Page 435: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

435

Clasa JLabel

public class JLabel extends JComponent implements SwingConstants, Accessible

Componentă de afişare needitabilă, care poate să conţină un text şi/sau o imagine (o

pictogramă).

Constructori

public JLabel(String text, Icon icon, int horizontalAlignment) - se

construieşte un JLabel, care conţine textul şi imaginea specificate. Al treilea parametru

specifică modul în care se face alinierea pe orizontală şi poate fi una din următoarele:

SwingConstants.LEFT - aliniere la stânga

SwingConstants.CENTER - aliniere la centru

SwingConstants.RIGHT - aliniere la dreapta.

public JLabel(String text, int horizontalAlignment) - se construieşte un JLabel,

care conţine textul specificat şi respectă alinierea orizontală indicată.

public JLabel(String text) - se construieşte un JLabel, conţinând textul specificat,

aliniat la stânga.

public JLabel(Icon image, int horizontalAlignment) - construieşte un JLabel, care

conţine imaginea şi respectă alinierea orizontală date ca argumente.

public JLabel(Icon image) - construieşte un JLabel care conţine imaginea specificată.

public JLabel() - construieşte un JLabel care nu conţine nimic.

Metode principale

public String getText() - întoarce textul.

public void setText(String text) - setează textul.

public Icon getIcon() - întoarce imaginea.

public void setIcon(Icon icon) - setează imaginea.

public int getVerticalAlignment() - întoarce alinierea pe verticală (aceasta poate fi una

din următoarele: SwingConstants.TOP, SwingConstants.CENTER sau

SwingConstants.BOTTOM).

public void setVerticalAlignment(int alignment) - setează alinierea pe verticală

(vezi mai sus).

public int getHorizontalAlignment() - întoarce alinierea pe orizontală.

public void setHorizontalAlignment(int alignment) - setează alinierea pe

orizontală.

Page 436: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

436

public int getVerticalTextPosition() - întoarce poziţia pe verticală a textului în raport

cu imaginea (aceasta poate fi una din următoarele: SwingConstants.TOP,

SwingConstants.CENTER sau SwingConstants.BOTTOM).

public void setVerticalTextPosition(int textPosition) - setează poziţia pe

verticală a textului, în raport cu imaginea.

public int getHorizontalTextPosition() - întoarce poziţia pe orizontală a textului în

raport cu imaginea (aceasta poate fi una din: SwingConstants.LEFT,

SwingConstants.CENTER, SWingConstants.RIGHT).

public void setHorizontalTextPosition(int textPosition) - setează poziţia pe

orizontală a textului în raport cu imaginea.

Clasa JMenu

public class JMenu extends JMenuItem implements Accessible, MenuElement

Instanţele acestei clase sunt meniuri, adică ferestre verticale, care conţin articole de meniu.

Întrucât clasa JMenu este o subclasă a JMenuItem, înseamnă că un JMenu poate fi el insuşi

un articol al altui menu (un JMenuItem). În acest fel, se pot crea meniuri cu structură

ierarhică (arborescentă).

Clasa conţine multe metode, dintre care se dau aici câteva mai frecvent utilizate. Pentru

documentare completă se va folosi Java API.

Constructori

public JMenu() - construieşte un meniu fără text.

public JMenu(String s) - construieşte un meniu cu inscripţia s.

public JMenu(Action a) - construieşte un meniu cu proprietăţile acţiunii a.

Metode frecvent utilizate

public boolean isSelected() - indică dacă meniul este selectat.

public void setSelected(boolean b) - setează dacă acest meniu este sau nu selectat.

public boolean isPopupMenuVisible() - indică dacă fereastra cu articolele de meniu este

vizibilă.

public void setPopupMenuVisible(boolean b) - setează dacă fereastra cu articole de meniu

este sau nu vizibilă.

public JMenuItem add(JMenuItem menuItem) - adaugă articolul de meniu specificat.

Page 437: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

437

public JMenuItem add(String s) - adaugă un nou articol de meniu cu inscripţia s.

public void addSeparator() - adaugă un separator.

public void insert(String s, int pos) - înserează pe poziţia pos un nou srticol de

meniu cu inscripţia s.

public JMenuItem insert(JMenuItem mi, int pos) - înserează pe poziţia pos articolul

de meniu mi.

public void insertSeparator(int index) - înserează un separator pe poziţia de indice dat.

public JMenuItem getItem(int pos) - întoarce articolul de pe poziţia pos.

public int getItemCount() - întoarce numărul de articole din acest meniu, inclusiv

separatorii.

public void remove(JMenuItem item) - elimină articolul de meniu specificat.

public void remove(int pos) - elimină articolul de meniu de pe poziţia pos.

public void removeAll() - elimină toate articolele din acest meniu.

public boolean isTopLevelMenu() - indică dacă acest meniu este de cel mai înalt nivel,

adică este ataşat direct la bara de meniu.

public void addMenuListener(MenuListener l) - adaugă ascultătorul de evenimente de

meniu specificat.

public void removeMenuListener(MenuListener l) - elimină ascultătorul de

evenimente de meniu specificat.

Clasa JMenuBar

public class JMenuBar extends JComponent implements Accessible, MenuElement

Instanţele aceste clase sunt folosite ca bare de meniu. Pentru a obţine un meniu cu bară, la

bara de meniu se adaugă diferite meniuri (instanţe ale clasei JMenu).

Vezi şi explicaţiile din secţiunea Meniuri cu bară a acestui curs.

Indicăm aici numai câteva metode mai frecvent utilizate. Pentru o documentare completă se

va consulta Java API.

Constructor public JMenuBar()

Page 438: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

438

Metode principale

public JMenu add(JMenu c) - se adaugă la această bară un nou meniu.

public JMenu getMenu(int index) - întoarce meniul cu indicele specificat.

public int getMenuCount() - întoarce numărul de meniuri din această bară.

public void setHelpMenu(JMenu menu) - setează meniul de ajutor (Help)

public JMenu getHelpMenu() - întoarce meniul de ajutor (Help).

public void setSelected(Component sel) - setează componenta selectată

public boolean isSelected() - indică dacă bara de meniu conţine o componentă

selectată.

Clasa JMenuItem

public class JMenuItem extends AbstractButton implements Accessible, MenuElement

Instanţele acestei clase sunt articole de meniu. Un astfel de obiect se comportă la fel ca un

buton, numai că este plasat într-un meniu. Din această cauză, clasa JMenuItem extinde clasa

AbstractButton. Are ca subclase JCheckBoxMenuItem, JMenu şi JRadioButtonMenuItem.

Instanţele acestei clase se comportă ca butoane obişnuite (au o singură stare stabilă, iar la

apăsare generează un eveniment de acţiune).

Constructori

public JMenuItem() - construieşte un articol de meniu fără text sau pictogramă.

public JMenuItem(Icon icon) - construieşte un articol de meniu cu pictograma

specificată.

public JMenuItem(String text) - construieşte un articol de meniu cu textul specificat.

public JMenuItem(Action a) - construieşte un articol de meniu cu proprietăţile din

acţiunea specificată.

public JMenuItem(String text, Icon icon) - construieşte un articol de meniu cu textul

şi pictograma specificate.

public JMenuItem(String text, int mnemonic) - construieşte un articol de meniu cu

textul şi mnemonica specificate.

Metode principale

Metodele din clasa AbstractButton, la care se adaugă:

Page 439: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

439

public void setArmed(boolean b) - setează dacă articolul de meniu este sau nu "armat"

)dacă butonul de mouse este eliberat când cursorul este pe acest articol, se va genera

evenimentul de acţiune).

public boolean isArmed() - indică dacă acest articol este "armat".

public void setEnabled(boolean b) - setează articolul pentru a fi sau nu activ.

public void setAccelerator(KeyStroke keyStroke) - setează combinaţia de taste care

generează aceeaşi acţiune ca acest articol de meniu, fără a mai parcurge ierarhia meniului.

public KeyStroke getAccelerator() - întoarce acceleratorul.

public MenuElement[] getSubElements() - întoarce tabloul componentelor submeniului

acestui articol.

public Component getComponent() - întoarce componenta utilizată pentru a desena acest

articol.

public void addMenuDragMouseListener(MenuDragMouseListener l) - adaugă un

ascultător de tragere a mouse-lui pentru meniu.

public void removeMenuDragMouseListener(MenuDragMouseListener l) - elimină

ascultătorul de tragere a mouse-ului.

public void addMenuKeyListener(MenuKeyListener l) - adaugă un ascultător de tastă

pentru articolul de meniu.

public void removeMenuKeyListener(MenuKeyListener l) - elimină ascultătorul de tastă

pentru articol de meniu.

Class JOptionPane

public class JOptionPane extends JComponent implements Accessible

Clasa JoptionPane permite să se creeze cu uşurinţă ferestre de dialog frecvent utilizate, având

un format predefinit. În acest scop, classa conţine metode satatice pentru realizarea fiecărui

tip de fereastră.

Clasa conţine un mare număr de câmpuri, constructori şi metode, dintre care vom da aici

numai câteva metode statice frecvent utilizate. Pentru documentare completă recomandăm să

se consulte Java API.

Recomandăm să se consulte şi capitolul Utilizarea ferestrelor de dialog din acest manual.

Page 440: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

440

Metode frecvent utilizate

public static String showInputDialog(Object message) - creează o fereastră de

dialog de intrare. Fereastra conţine mesajul specificat ca parametru, urmat de un câmp de text

în care utilizatorul poate introduce datele solicitate, sub forma unui şir de caractere.

public static String showInputDialog(Component parentComponent, Object

message) - creează o fereastră de dialog de intrare, având ca părinte componenta specificată

prin primul parametru. Fereastra conţine mesajul specificat, plus un câmp de text pentru

introducerea şirului de intrare.

public static String showInputDialog(Component parentComponent, Object

message, String title, int messageType) - similar cu metoda precedentă, dar se

specifică în plus titlul ferestrei şi tipul mesajului. Tipul mesajului poate fi unul din

următoarele: JOptionPane.ERROR_MESSAGE, JOptionPane.INFORMATION_MESSAGE, FOptionPane.WARNING_MESSAGE, JOptionPane.QUESTION_MESSAGE, sau

JOptionPane.PLAIN_MESSAGE. Pe fereastră va apare o pictogramă corespunzătoare tipului

de mesaj.

public static void showMessageDialog(Component parentComponent, Object

message) - se creează o fereastră de dialog, care conţine mesajul specificat.

public static void showMessageDialog(Component parentComponent, Object

message, String title, int messageType) - similar metodei precedente, dar se

specifică în plus titlul ferestrei şi tipul mesajului. Acest tip poate fi unul din: JOptionPane.ERROR_MESSAGE, JOptionPane.INFORMATION_MESSAGE,

JOptionPane.WARNING_MESSAGE, JOPtionPane.QUESTION_MESSAGE, sau

JOptionPane.PLAIN_MESSAGE.

public static void showMessageDialog(Component parentComponent, Object

message, String title, int messageType,Icon icon) - similar cu metoda precedentă,

specificându-se în plus o pictogramă.

public static int showConfirmDialog(Component parentComponent, Object

message) - se creează o fereastră de dialog de confirmare. Această fereastră conţine mesajul

"Select an option" şi trei butoane: Yes, No şi Cancel.

public static int showConfirmDialog(Component parentComponent, Object

message, String title, int optionType) - se creează o fereastră de dialog de

confirmare, fiind specificate: componenta părinte, mesajul conţinut de fereastră, titlul

ferestrei şi tipul de opţiune. Tipul opţiunii poate fi unul din următoarele:

JOptionPane.YES_NO_OPTION, sau JOptionPane.YES_NO_CANCEL_OPTION.

public static int showConfirmDialog(Component parentComponent, Object

message, String title, int optionType, int messageType) - similar cu metoda

precedentă, specificându-se în plus tipul mesajului, care poate fi unul din următoarele: JOptionPane.ERROR_MESSAGE, JOptionPane.INFORMATION_MESSAGE,

JOptionPane.WARNING_MESSAGE, JOPtionPane.QUESTION_MESSAGE, sau

JOptionPane.PLAIN_MESSAGE.

public static int showConfirmDialog(Component parentComponent, Object

message, String title, int optionType, int messageType, Icon icon) - similar

Page 441: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

441

cu metoda de mai sus, specificându-se în plus o pictogramă.

Clasa JPanel

public class JPanel extends JComponent implements Accessible

Clasa JPanel din Swing are un rol similar cu clasa Panel din AWT. Instanţele acestei clase

sunt containere, care apar pe ecran ca nişte suprafeţe dreptunghiulare, pe care se pot plasa

diferite componente, aranjate cu ajutorul unui gestionar de poziţionare. Având în vedere că

clasa JPanel extinde clasa JComponent, panourile din această clasă pot avea şi bordură.

Constructori principali

public JPanel() - construieşte un JPanel cu gestionarul de poziţionare implicit

(FlowLayout).

public JPanel(LayoutManager layout) - construieşte un JPanel cu gestionarul de

poziţionare specificat.

Metode principale

Cele moştenite de la superclase

Class JPasswordField

public class JPasswordField extends JTextField

Instanţele acestei clase sunt câmpuri de text folosite la introducerea parolei. Se deosebesc de

JTextField prin faptul că parola introdusă în câmp de la tastatură nu este vizibilă pe ecran,

fiind substituită printr-un şir de caractere de înlocuire. Caracterul de înlocuire implicit este '*',

Constructori

public JPasswordField() - construieşte un câmp de parolă fără text şi cu lungimea 0

coloane.

public JPasswordField(int columns) - construieşte un câmp de parolă cu lungimea

specificată.

public JPasswordField(String text, int columns) - construieşte un câmp de text,

specificându-se textul conţinut şi lungimea câmpului.

Metode principale

public void setEchoChar(char c) - se setează caracterul de ecou (care va înlocui în

câmpul de pe ecran caracterele efective ale parolei).

Page 442: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

442

public char getEchoChar() - întoarce caracterul de ecou (de înlocuire pe ecran a

caracterelor parolei). Implicit este '*'.

public char[] getPassword() - întoarce un tablou de caractere, care conţine parola.

Clasa JProgressBar

public class JProgressBar extends JComponent implements SwingConstants, Accessible

Instanţele acestei clase sunt bare de progres, folosite în special gradul de realizare a unui

eveniment în curs de desfăşurare. Pe ecran, apare ca o bară a cărei lungime este proporţională

cu un număr întreg, într-un interval de variaţie dat. Bara poate fi orientată orizontal sau

vertical.

Constructori

public JProgressBar() - creează o bară de progres orientată orizontal, cu intervalul de

variaţie 0 .. 100.

public JProgressBar(int orient) - creează o bară de progres cu orientarea specificată,

care poate fi JProgressBar.VERTICAL sau

JProgressBar.HORIZONTAL. Intervalul de variaţie este 0 .. 100.

public JProgressBar(int min, int max) - creează o bară de progres orientată orizontal,

cu intervalul de variaţie specificat.

public JProgressBar(int orient, int min, int max) - creează o bară de progres cu

orientarea şi intervalul de variaţie specificate.

Metode frecvent utilizate

public void setOrientation(int newOrientation) - seteazo orientarea, care poate fi

JProgressBar.VERTICAL sau

JProgressBar.HORIZONTAL.

public int getOrientation() - întoarce orientarea.

public double getPercentComplete() - întoarce gradul de progresare, sub forma unui

număr real în intervalul 0.00 .. 1.00.

public void setBorderPainted(boolean b) - setează dacă bara are sau nu bordură.

Implicit este true.

public boolean isBorderPainted() - indică dacă bara are sau nu bordură.

public void addChangeListener(ChangeListener l) - adaugă un ascultător de

evenimente de schimbare.

Page 443: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

443

public void removeChangeListener(ChangeListener l) - elimină un ascultător de

evenimente de schimbare.

public int getValue() - întoarce valoarea indicată de bară.

public int getMinimum() - întoarce valoarea minimă (marginea inferioară a intervalului).

public int getMaximum() - întoarce valoarea maximă (marginea superioară a intervalului).

public void setValue(int n) - setează valoarea (un număr întreg, cuprins în intervalul de

variaţie impus).

public void setMinimum(int n) - setează valoarea minimă (marginea inferioară a

intervalului).

public void setMaximum(int n) - setează valoarea maximă (marginea superioară a

intervalului).

Clasa JRadioButtonMenuItem

public class JRadioButtonMenuItem extends JMenuItem implements Accessible

Articol de meniu care se comportă ca un buton radio (JRadioButton). Este un buton cu două

stări stabile (selectat şi deselectat). Mai multe butoane radio pot fi grupate folosind un

ButtonGroup, astfel încât, la un moment dat, un singur buton din grup se găseşte în starea

selectat.

Constructori

public JRadioButtonMenuItem() - construieşte un JRadioButtonMenuItem fără text şi fără

pictogramă.

public JRadioButtonMenuItem(Icon icon) - construieşte un JRadioButtonMenuItem cu

pictograma specificată.

public JRadioButtonMenuItem(String text) - construieşte un JRadioButtonMenuItem

cu textul specificat.

public JRadioButtonMenuItem(String text, Icon icon) - construieşte un

JRadioButtonMenuItem cu textul şi pictograma specificate.

public JRadioButtonMenuItem(String text, boolean selected) - construieşte un

JRadioButtonMenuItem cu textul specificat, indicând dacă este sau nu selectat.

public JRadioButtonMenuItem(Icon icon, boolean selected) - construieşte un

JRadioButtonMenuItem cu pictograma specificată, indicând dacă este sau nu selectat.

Page 444: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

444

public JRadioButtonMenuItem(String text, Icon icon, boolean selected) -

construieşte un JRadioButtonMenuItem cu textul şi pictograma specificate, indicând dscă

este sau nu selectat.

Metode

Cele din superclase.

Clasa JScrollBar

public class JScrollBar extends JComponent implements Adjustable, Accessible

Instanţele acestei clase sunt bare de defilare, care pot fi orientate orizontal sau vertical. Se

stabilesc orientarea, valorile minimă şi maximă, valoarea la care exte poziţionat cursorul şi

extensia. Orientarea poate fi una din valorile HORIZONTAL şi VERTICAL definite în

interfaţa Adjustable din pachetul java.awt.

Constructori public JScrollBar(int orientation, int value, int extent, int min, int max)

- creează o bară de defilare, fiind specifiacte orientarea, valoarea, extensia, valoarea minimă

şi valoarea maximă.

public JScrollBar(int orientation) - se creează o bară de defilare cu orientarea

specificată, intervalul 0 .. 100, valoarea 0 şi extensia 100.

public JScrollBar() - se creează o bară de defilare verticală, intervalul 0 .. 100, valoarea 0

şi extensia 100.

Metode frecvent utilizate

public int getOrientation() - întoarce orientarea.

public void setOrientation(int orientation) - setează orientarea.

public int getValue() - întoarce valoarea indicată de bara de defilare.

public void setValue(int value) - setează valoarea indicată de bara de defilare.

public int getMinimum() - întoarce valoarea minimă.

public void setMinimum(int minimum) - setează valoarea minimă.

public int getMaximum() - întoarce valoarea maximă.

public void setMaximum(int maximum) - setează valoarea maximă.

public boolean getValueIsAdjusting() - indică dacă cursorul poate fi tras cu mause-ul.

Page 445: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

445

public void setValueIsAdjusting(boolean b) - setează dacă cursorul poate sau nu să

fie tras cu mouse-ul.

public void addAdjustmentListener(AdjustmentListener l) - adaugă un ascultător

de evenimente de ajustare.

public void removeAdjustmentListener(AdjustmentListener l) - elimină un

ascultător de evenimente de ajustare.

public void setEnabled(boolean x) - face ca poziţia cursorului să poată sau nu fi

schimbată.

Clasa JScrollPane

public class JScrollPane extends JComponent implements ScrollPaneConstants, Accessible

Instanţele acestei clase sunt panouri cu bare de defilare orizontală şi/sau verticală. În Swing,

instanţele clasei JPanel nu au bare de defilare. Dacă dorim să-i punem bare de defilare, un

astfel de JPanel se pune ca singură componentă într-un JScrollPane. In loc de un panou, în

JScrollPane se poate pune orice altă componentă Swing, dar una singură.

Se pot adopta diferite "politici" privind modul de comportare al celor bare de defilare:

- pentru bara de defilare verticală:

JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED - bara apare numai dacă este

necesară;

JScrollPane.VERTICAL_SCROLLBAR_NEVER - bara nu apare niciodată;

JScrollPane.VERTICAL_SCROLLBAR_ALWAYS - bara apare întotdeauna;

- pentru bara de defilare orizontală:

JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED - bara apare numai dacă

este necesară;

JScrollPane.HORIZONTAL_SCROLLBAR_NEVER - bara nu apare niciodată;

JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS - bara apare întotdeauna.

Aceste constante se folosesc ca parametri în constructori şi metode, unde se cer "politicile"

adoptate pentru comportamentul barelor de defilare.

Pentro o documentare completă se recomandă consultarea documentatiei Java API.

Constructori

public JScrollPane(Component view, int vsbPolicy, int hsbPolicy) - se

construieşte un JScrollPane, fiind specificate componenta pe care o vizualizează şi politicile

adoptate pentru comportările barelor de defilare verticală şi orizontală.

public JScrollPane(Component view) - se construieşte un JScrollPane care conţine

componenta specificată, iar barele de defilare apar numai când sunt necesare (când

componenta este mai mare decât partea vizibilă).

Page 446: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

446

public JScrollPane(int vsbPolicy, int hsbPolicy) - construieşte un JScrollPane,

specificând politicile pentru barele de defilare verticală şi orizontală.

public JScrollPane() - constuieşte un JScrollPane, la care barele de defilare orizontală şi

verticală apar numai când sunt necesare.

Metode frecvent utilizate

public int getVerticalScrollBarPolicy() - întoarce politica pentru bara de defilare

verticală.

public void setVerticalScrollBarPolicy(int policy) - setează politica pentru bara

de defilare verticală.

public int getHorizontalScrollBarPolicy() - întoarce politica pentru bara de defilare

orizontală.

public void setHorizontalScrollBarPolicy(int policy) - setează politica pentru

bara de defilare orizontală.

public Border getViewportBorder() - întoarce bordura yonei vizibile.

public void setViewportBorder(Border viewportBorder) - setează bordura zonei

vizibile.

Class JSeparator

public class JSeparator extends JComponent implements SwingConstants, Accessible

Instanţele acestei clase sunt separatori folosiţi în meniuri, pentru a grupa articolele de meniu

în grupuri logice. În loc de a folosi în mod explicit această clasă, se pot utiliza metodele

addSeparator(), existente în clasele JMenu şi JPopupMenu.

Constructori

public JSeparator() - construieşte un separator orizontal.

public JSeparator(int orientation) - construieşte un separator, specificând orientarea

acestuia, care poate fi una din următoarele: SwingConstants.HORIZONTAL sau

SwingConstants.VERTICAL.

Metode principale

public int getOrientation() - întoarce orientarea separatorului.

public void setOrientation(int orientation) - setează orientarea separatorului

(orizontală sau verticală).

Page 447: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

447

Clasa JSplitPane

public class JSplitPane extends JComponent implements Accessible

Instenţele clasei JSplitPane sunt panouri scindate în două zone, fiecare din aceste zone

conţinând câte o singură componentă. Scindarea se poate face vertical sau orizontal.

Orientarea scindării este specificată prin una constantele JSplitPane.HORIZONTAL_SPLIT

sau JSplitPane.VERTICAL_SPLIT .

Clasa conţine un număr mare de câmpuri, constructori şi metode. Pentru documentare

completă recomandăm să se consulte Java API.

Constructori

public JSplitPane() - creează un JSplitPane, în care cele două componente sunt puse una

lângă alta, orizontal.

public JSplitPane(int newOrientation) - creează un JSplitPane, indicându-se orientarea

scindării.

public JSplitPane(int newOrientation, boolean newContinuousLayout) - creează un nou

JSplitPane, fiind specificate orientarea şi dacă aspectul este sau nu continuu (dacă este sau nu

vizibil locul de îmbinare).

public JSplitPane(int newOrientation, Component newLeftComponent, Component

newRightComponent) - se creează un JSplitPane, indicându-se specificarea şi cele două

componente conţinute.

public JSplitPane(int newOrientation, boolean newContinuousLayout, Component

newLeftComponent, Component newRightComponent) - se construieşte un JSplitPane, fiind

specificate orientarea scindării, continuitatea în zona de scindare şi cele două componente

conţinute.

Metode frecvent utilizate

public void setDividerSize(int newSize) - setează lăţimea divizorului dintre cele

două zone, exprimată în pixeli.

public int getDividerSize() - întoarce lăţimea divizorului dintre cele două zone

(exprimată în pixeli).

public void setLeftComponent(Component comp) - setează componenta din stânga (sau

de sus).

public Component getLeftComponent() - întoarce componenta din stânga (sau de sus).

public void setTopComponent(Component comp) - setează componenta de sus (sau din

stânga).

Page 448: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

448

public Component getTopComponent() - întoarce componenta de sus (sau din stânga).

public void setRightComponent(Component comp) - setează componenta dein dreapta

(sau de jos).

public Component getRightComponent() - întoarce componenta din dreapta (sau de jos).

public void setBottomComponent(Component comp) - setează componenta de jos (sau

din dreapta).

public Component getBottomComponent() - întoarce componenta de jos (sau din dreapta).

public void setOrientation(int orientation) - setează orientarea.

public int getOrientation() - întoarce orientarea.

public void setContinuousLayout(boolean newContinuousLayout) - setează continuitatea în

zona de scindare.

public boolean isContinuousLayout() - indică dacă în zona de scindare există sau nu

continuitate.

Clasa JTabbedPane

public class JTabbedPane extends JComponent implements Serializable, Accessible,

SwingConstants

Fiecare instanţă a clasei JTabbedPane realizează metaforic un "clasor", care conţine fişe

plasate una în spatele celeilalte. Fiecare astfel de "fişă" este o componentă a panoului şi are

plasat pe ea un "călăreţ" (tab) care seamănă cu un buton. La apăsarea acestui "călăreţ", fişa

respectivă iese deasupra celorlalte.

Amplasarea "călăreţilor" (tabLayoutPlacement) poate fi sus, jos, stânga sau dreapta şi se

indică prin constantele: JTabbedPane.TOP, JTabbedPane.BOTTOM, JTabbedPane.LEFT sau JTabbedPane.RIGHT.

Modul de prezentare a călăreţilor (layoutPolicy) poate fi unul din:

JTabbedPane.WRAP_TAB_LAYOUT (toţi "călăreţii" sunt vizibili) or

JTabbedPane.SCROLL_TAB_LAYOUT ("călăreţii" defilează).

Clasa conţine numeroase câmpuri şi metode, astfel că pentru o mai bună documentare se

recomandă consultarea documentaţiei Java API. Este utilă, de asemenea, consultarea

capitolului How to Use Tabbed Panes din Tutorialul Java.

Page 449: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

449

Constructori

public JTabbedPane() - construieşte un JTabbedPane cu "călăreţii" plasaţi vizibil

(JTabbedPane.WRAP_TAB_LAYOUT) la partea superioară.

public JTabbedPane(int tabPlacement) - construieşte un JTabbedPane, respectând amplasarea

specificată a "călăreţilor".

public JTabbedPane(int tabPlacement, int tabLayoutPolicy) - se construieşte un

JTabbedPane, fiind specificate atât amplasarea, cât şi politica de vizibilitate a "călăreţilor".

Metode frecvent utilizate

public void addChangeListener(ChangeListener l) - adaugă un ascultător de

evenimente de schimbare.

public void removeChangeListener(ChangeListener l) - elimină un ascultător de

evenimente de schimbare.

public ChangeListener[] getChangeListeners() - elimină un ascultător de evenimente

de schimbare.

public int getTabPlacement() - întoarce amplasarea "călăreţilor".

public void setTabPlacement(int tabPlacement) - setează amplasarea "călăreţilor".

public int getTabLayoutPolicy() - întoarce politica de vizibilitate a "călăreţilor".

public void setTabLayoutPolicy(int tabLayoutPolicy) - setează politica de

vizibilitate a "călăreţilor".

public int getSelectedIndex() - întoarce indicele subpanoului selectat.

public void setSelectedIndex(int index) - setează indicele subpanoului selectat.

public Component getSelectedComponent() - întoarce componenta selectată.

public void setSelectedComponent(Component c) - setează componenta selectată.

public void insertTab(String title, Icon icon, Component component, String

tip, int index) - se înserează un "călăreţ", împreună cu subpanoul corespunzător,

specificându-se: titlul, pictograma, componenta, textul volant şi indicele.

public void addTab(String title, Icon icon, Component component, String

tip) - se adaugă un "călăreţ" (după cele deja existente), specificându-se titlul, pictograma,

componenta şi textul volant.

public void addTab(String title, Icon icon, Component component) - ca şi

metoda precedentă, dar fără text volant.

Page 450: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

450

public void addTab(String title, Component component) - ca şi metoda precedentă,

dar fără pictogramă.

public void removeTabAt(int index) - se elimină "călăreţul" de indice specificat,

împreună cu subpanoul respectiv.

public void removeAll() - elimină toţi "călăreţii".

public int getTabCount() - întoarce numărul de "călăreţi".

public String getTitleAt(int index) - întoarce titlul de la indicele specificat.

public Icon getIconAt(int index) - întoarce pictograma de la indicele specificat.

public String getToolTipTextAt(int index) - întoarce textul volant de la indicele

specificat.

public Component getComponentAt(int index) - întoarce componenta de la indicele

specificat.

Clasa JTable

public class JTable extends JComponent

implements TableModelListener, Scrollable, TableColumnModelListener,

ListSelectionListener, CellEditorListener, Accessible

Clasa JTable permite crearea de componente sub formă de tabele bidimensionale editabile.

Pentru utilizarea acestei clase se recomandă consultarea documentaţiei Java API şi a

capitolului How to Use Tables din Tutorialul Java.

JTextPane

public class JTextPane extends JEditorPane

Subclasă a clasei JEditorPane. Clasă pentru realizarea panourilor de editare care permit să se

folosească stiluri diferite pentru fiecare paragraf.

Se recomandă consultarea documentaţiei Java API şi a secţiunii UsingTextComponents din

Tutorialul Java.

Page 451: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

451

Clasa JToggleButton

public class JToggleButton extends AbstractButton implements Accessible

Este clasa generică pentru butoane cu două stări stabile: starea acţionat (selectat, închis,

validat) şi starea eliberat (neselectat, deschis, nevalidat). Are ca subclase JCheckBox şi

JRadioButton. La fiecare acţionare cu mouse-ul asupra unei instanţe a clasei JToggleBox sau

a subclaselor sale, butonul respectiv trece, din starea în care se gaseşte, în cealaltă stare. Dacă

nu se specifică altfel, starea iniţială implicită este "eliberat".

Constructori

public JToggleButton() - creează un buton fără text sai pictogramă.

public JToggleButton(Icon icon) - creează un buton cu pictograma specificată ca

parametru, dar fără text.

public JToggleButton(Icon icon, boolean selected) - creează un buton, care conţine

pictograma specificată, nu conţine text, iar starea iniţială este dată de al treilea parametru.

public JToggleButton(String text) - creează un buton cu textul specificat.

public JToggleButton(String text, boolean selected) - creează un buton cu textul

specificat, la care starea iniţială este indicată de al treilea parametru.

public JToggleButton(Action a) - creează un buton, cu proprietăţile din acţiunea

specificată.

public JToggleButton(String text, Icon icon, boolean selected) - creează un

buton, care are textul şi pictograma specificate, iar starea iniţială este cea indicată de al treilea

parametru.

Metode principale

Metodele principale sunt cele din clasa AbstractButton. Pentru o documentare completă se va

consulta Java API.

Clasa JWindow

public class JWindow extends Window implements Accessible, RootPaneContainer

Instanţele clasei JWindow sunt ferestre fără bară de titlu, care pot fi plasate oriunde pe ecran

(sunt ferestre de cel mai înalt nivel). Adăugarea componentelor nu se face direct la fereastră,

ci la un container conţinut în aceasta numit contentPane, care poate fi obţinut prin metoda

getContentPane().

Page 452: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

452

Constructori

public JWindow() - construieşte o fereastră fără un proprietar specificat.

public JWindow(GraphicsConfiguration gc) - construieşte o fereastră cu configuraţia

grafică specificată.

public JWindow(Frame owner) - construieşte o fereastră, având ca proprietar cadrul

specificat ca argument.

public JWindow(Window owner) - construieşte o fereastră, având ca proprietar fereastra

specificată ca argument.

public JWindow(Window owner, GraphicsConfiguration gc) - construieşte o fereastră, având

proprietarul owner şi configuraţia grafică gc.

Metode principale

Metodele clasei Window din pachetul java.awt, la care se adaugă:

public Container getContentPane() - întoarce containerul la care se adaugă

componentele ferestrei.

public void setContentPane(Container contentPane) - setează panoul contentPane.

Clasa ChangeEvent

public class ChangeEvent extends EventObject

Evenimentele din această clasă semnalează schimbarea stării componentei sursă. Ele sunt

ascultate cu un ChangeListener.

Constructor

public ChangeEvent(Object source) - se creează un ChangeEvent, fiind specificată sursa

acestuia.

Clasa ListDataEvent

public class ListDataEvent extends EventObject

Eveniment care indică apariţia unor modificări într-o listă. Tipul evenimentului are valoarea

unuia din următoare câmpuri statice finale:

ListDataEvent.CONTENTS_CHANGED - s-a modificat conţinutul listei;

ListDataEvent.INTERVAL_ADDED - s-au adăugat la listă unul sau mai multe articole

Page 453: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

453

care sunt situate unul după altul

ListDataEvent.INTERVAL_REMOVED - s-au eliminat din listă unul sau mai multe articole

situate unul după altul.

Constructor

public ListDataEvent(Object source, int type, int index0, int index1) - se

creează un ListDataEvent fiind specificate: obiectul sursă, tipul evenimentului (unul din cele

menţionate mai sus), indicii marginilor intervalului de articole în care s-a produs modificarea.

Metode

public int getType() - întoarce tipul evenimentului.

public int getIndex0() - întoarce indicele primului articol al intervalului în care s-a produs

modificarea

public int getIndex1() - întoarce indicele ultimului articol al intervalului în care s-a produs

modificarea

Clasa ListSelectionEvent

public class ListSelectionEvent extends EventObject

Eveniment care indică modificarea selecţiei dintr-o listă. Se consideră că schimbarea selecţiei

este limitată la un interval de articole.

Constructor public ListSelectionEvent(Object source, int firstIndex, int lastIndex,

boolean isAdjusting) - creează un ListSelectionEvent, fiind specificate: sursa

evenimentului, indicii inceputului şi sfârşitului intervalului şi dacă acest eveniment este sau

nu unul dintr-o serie rapidă de evenimente.

Metode

public int getFirstIndex() - întoarce indicele primului articol din intervalul selectat.

public int getLastIndex() - întoarce indicele ultimului articol din intervalul selectat.

public boolean getValueIsAdjusting() - indică dacă acest eveniment face parte dintr-o

serie de evenimente care au loc rapid.

Clasa MenuEvent

public class MenuEvent extends EventObject

Page 454: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

454

Evenimentele din această clasă se produc atunci când a avut loc o modificare într-un meniu:

obiectul sursă a fost pus, selectat sau eliminat.

Constructor

public MenuEvent(Object source) - creează un eveniment de meniu, specificându-se

sursa.

Clasa MouseInputAdapter

public abstract class MouseInputAdapter extends Object implements MouseInputListener

Clasă abstractă, folosită ca prototip pentru clasele ascultătoare de evenimente de mouse.

Clasa conţine toate metodele interfeţei MouseInputListener, dar aceste metode nu fac nimic

(au corpul vid). Programatorul poate crea clase derivate, în care rafinează numai acele

metode, care sunt efectiv necesare în aplicaţia respectivă.

Constructor public MouseInputAdapter()

Metode

Metodele interfeţei MouseInputListener.

Clasa PopupMenuEvent

public class PopupMenuEvent extends EventObject

Evenimente generate de meniurile derulante (pop-up).

Constructor

public PopupMenuEvent(Object source) - creează un PopupMenuEvent, specificându-se

sursa evenimentului.

Interfaţa ChangeListener

public interface ChangeListener extends EventListener

Interfaţă pentru clasele de ascultători de evenimente de schimbare a stării.

Page 455: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

455

Metodă

public void stateChanged(ChangeEvent e) - invocată când a avut loc o schimbare de

stare

Interfaţa ListDataListener

public interface ListDataListener extends EventListener

Interfaţă pentru ascultătoarele de evenimente de modificare a conţinutului unei liste.

Metode

public void intervalAdded(ListDataEvent e) - invocată când a avut loc o adăugare

sau înserare de articole în listă

public void intervalRemoved(ListDataEvent e) - invocată când a avut loc o eliminare

de articole din listă

public void contentsChanged(ListDataEvent e) - invocată când a avut loc o modificare în listă

mai complexă decât cele două precedente. De exemplu, când a fost înlocuit un articol.

Interfaţa ListSelectionListener

public interface ListSelectionListener extends EventListener

Interfaţă pentru ascultătoarele de evenimente de selecţie în liste

Metodă

public void valueChanged(ListSelectionEvent e) - invocată când s-a modificat

selecţia dintr-o listă

Interfaţa MenuListener

public interface MenuListener extends EventListener

Interfaţă pentru ascultătoarele de evenimente de meniu.

Metode

public void menuSelected(MenuEvent e) - invocată când meniul este selectat.

Page 456: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

456

public void menuDeselected(MenuEvent e) - invocată când meniul este deselectat.

public void menuCanceled(MenuEvent e) - invocată când meniul este anulat.

Interfaţa MouseInputListener

public interface MouseInputListener extends MouseListener, MouseMotionListener

Interfaţă de ascultare a evenimentelor de mouse, care cumulează metodele celor două

interfeţe pe care le extinde: MouseListener şi MouseMotionListener.

În loc de a crea o clasă care extinde direct această interfaţă, se recomandă extinderea clasei

MouseInputAdapter.

Metode

public void mouseClicked(MouseEvent e) - metodă invocată când s-a produs un click de

mouse.

public void mousePressed(MouseEvent e) - metodă invocată când este apăsat unul din

butoanele de mouse.

public void mouseReleased(MouseEvent e) - metodă invocată când este eliberat unul

din butoanele de mouse.

public void mouseEntered(MouseEvent e) - metodă invocată când cursorul de mouse

intră pe suprafaţa unei componente.

public void mouseExited(MouseEvent e) - metodă invocată când cursorul de mouse

iese de pe suprafaţa unei componente.

public void mouseDragged(MouseEvent e) - mouse-ul a fost "tras" (adică a fost deplasat

menţinând unul din butoane apăsat).

public void mouseMoved(MouseEvent e) - mouse-ul a fost mişcat (fără să fie apăsat nici

unul din butoane).

Interfaţa PopupMenuListener

public interface PopupMenuListener extends EventListener

Interfaţă pentru ascultătoarele de evenimente generate de meniurile derulante (pop-up).

Page 457: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

457

Metode

public void popupMenuWillBecomeVisible(PopupMenuEvent e) - invocată când meniul

pop-up devine vizibil.

public void popupMenuWillBecomeInvisible(PopupMenuEvent e) - invocată când

meniul pop-up devine invizibil.

public void popupMenuCanceled(PopupMenuEvent e) - invocată când meniul pop-up

este anulat.

Page 458: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

458

Surse de documentare

1. Documentaţie originală

Pagina Web de la care puteţi porni căutarea documentaţiei originale oferite de firma Sun

Microsystems pentru utilizatorii limbajului Java este java.sun.com.

Pentru realizarea de aplicaţii şi miniaplicaţii în limbajul Java, puteti folosi documentaţia

originală a firmei Sun Microsystems, al cărei index se găseşte pe internet la adresa:

java.sun.com/docs/index.html. şi la Universitatea Tehnică Timişoara la adresa

www.cs.utt.ro/ro/doc/jdk1.3.1/docs.Pe intranetul Catedrei de Calculatoare şi Informatică

Aplicată de la Universitatea "Dunărea de Jos" din Galaţi gasiti aceasta documentatie la

adresa lib.cs.ugal.ro/java/index.html.

La realizarea aplicaţiilor şi miniaplicaţiilor Java, din această documentaţie veti folosi cel mai

mult descrierea claselor din specificatia API (Application Program Interface) a platformei

Java 2, intitulată "Java 2 Platform, Standard Edition, v1.4 API Specification" pe care o găsiţi

la adresa următoare:

java.sun.com/products/j2se/1.4/docs/api/index.html - la firma Sun Microsystems;

Celor care sunt conectaţi la intranetul Catedrei de Calculatoare şi Informatică Aplicată de

la Universitatea "Dunărea de Jos" din Galaţi le recomandăm să caute aceeaşi

documentaţie la adresa http://lib.cs.ugal.ro/java/jdk140/api/index.html

Pentru studierea mai profundă a limbajului Java, puteţi folosi specificatia riguroasa a

acestuia, dată în documentul "Java Language Specification", care se găseşte la adresele

urmatoare:

java.sun.com/docs/books/jls/second_edition/html/j.title.doc.html .

2. O colecţie bogată de documentaţie

Pentru studierea limbajului Java şi dezvoltarea de aplicaţii puteti folosi, de asemenea:

documentaţia recomandată de situl Sunsite Romania, de la Universitatea "Politehnica"

din Bucureşti, în special cea de la rubrica Java Corner;

documentaţia on-line a catedrei de calculatoare de la Universitatea Tehnica

Timisoara, de la adresa: www.cs.utt.ro/ro/doconline.html;

colectia de documentie din biblioteca studentilor specializarii de Calculatoare de la

Universitatea Tehnica Iasi, situata la adresa: library.cs.tuiasi.ro/0/programming-

java.html.

3. Cărţi în limba română

1. Athanasiu Irina, Costinescu B., Drăgoi O.A., Popovici F.I. Limbajul Java. O perspectivă

pragmatică. Editura Agora, Tg.Mureş

2. Prodan A., Prodan M. Mediul Java pentru Internet. Editura Promedia Plus, Cluj-Napoca,

1997.

3. Norton P., Stanek W. Ghid de programare in Java. Editura Teora, Bucureşti, 1997

Page 459: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

459

4. Rotariu E. Limbajul Java. Editura Agora, Tg.Mureş, 1996.

5. Fraizer C., Bond J. Java API. Pachetele API java.applet si java awt. Editura Teora,

Bucureşti, 1998.

6. Lemay L., Cadenhead R. Java2 Fără profesor în 21 zile. Editura Teora, Bucureşti

7. Chan M.C., Griffith S.W., Iasi A.F. Java - 1001 secrete pentru programatori. Editura

Teora, Bucureşti

NOTA: cu excepţia cărţilor de la poziţiile 1, 6 si 7, care se bazează pe Java2 (JDK 1.2 sau

ulterioare), toate celelalte au la bază JDK 1.0. La trecerea de la 1.0 la 1.1 s-au produs destul

de multe modificări, în special în pachetele API.

4. Tutoriale şi manuale on-line

Pe internet există numeroase tutoriale şi cărţi utile pentru instruire în domeniul limbajului şi

platformei Java. Dintre acestea menţionăm:

manualul on-line de Java al prof. S. Bumbaru, pe intranetul Universitatii "Dunarea de

Jos" din Galati;

tutorialul (manualul on-line) Java recomandat de firma Sun se găseşte la adresa

http://java.sun.com/docs/books/tutorial/, prezentând avantajul că este în permanenţă

ţinut la curent cu evoluţia platformei Java. Acelaşi tutorial (într-o varianta

neactualizată, dar cu avantajul că se obţine rapid) poate fi găsit şi pe intranetul

catedrei de Calculatoare şi Informatică Aplicată http://lib.cs.ugal.ro/TutorialJava/;

lista cu legături spre alte tutoriale, oferită de firma Sun Microsystems:

http://developer.java.sun.com/developer/onlineTraining/

manualele din biblioteca on-line de la Universitatea Tehnica Iaşi;

"Thinking in Java", by Bruce Eckel - un excelent manual de Java, în care accentul se

pune nu pe sintaxă, ci pe semnificaţie.

Page 460: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

460

ANEXA

Listele fişierelor sursă ale claselor date ca

exemple în curs

În această anexă se dau listările fişierelor sursă ale claselor care date ca exemple, care nu sunt

reproduse în capitolele respective. Fişierele sunt grupate pe capitole.

Capitolul 1 460

Capitolul 2 460

Capitolul 3 461

Capitolul 4 470

Capitolul 5 485

Capitolul 6 490

Capitolul 7 502

Capitolul 8 502

Capitolul 9 502

Capitolul 10 504

Capitolul 11 509

Capitolul 12 519

Capitolul 1.

Fişierul PrimaAplicaţie.java

class PrimaAplicatie { public static void main(String args[]) { System.out.println("Prima noastra aplicatie a reusit!"); } }

Capitolul 2.

Fişierul AfisareSiruri.java

/* Exersarea metodelor print si println */

class AfisareSiruri {

public static void main(String args[]) {

System.out.println("sirul 1");

System.out.println("sirul 2"); // se afiseaza sub sirul 1

Page 461: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

461

System.out.println("AB"+"CDE"); // se afiseaza ABCDE

System.out.println("ab"+"cd"+"ef"); // se afiseaza abcdef

System.out.println(("ab"+"cd")+"ef"); // asociativitate

System.out.println("ab"+("cd"+"ef"));

/* Urmatoarele trei instructiuni afiseaza in continuare,

pe o singura linie */

System.out.print("pqrst"); // nu se trece la linie noua

System.out.print("UVW"); // se afiseaza in continuare

System.out.print("xyz\n"); // echivalent cu println("xyz")

/* Trecerea la linia urmatoare se face datorita prezentei

caracterului de control \n in sirul "xyz\n" */

System.out.println("ultima linie afisata");

System.out.println((int)'A'+" "+(int)'q');

}

}

Capitolul 3.

Fişierul Repetare1.java

/* Calcularea repetata a unei expresii pentru diferite valori ale lui k

folosind ciclul cu test initial

*/

class Repetare1 {

public static void main(String argv[]) {

/* Se declara si initializeaza variabilele */

int k, n=12;

/* Se calculeaza si afiseaza in mod repetat valoarea expresiei.

Variabila k este declarata si initializata in for

*/

k=0; // initializarea contorului ciclului

while (k<=n) {

System.out.println("Pentru k="+k+" Valoarea expresiei este "+

2*Math.exp(-0.35*k)*Math.sin(0.17*k-0.08));

k++; // Se pregateste trecerea la ciclul urmator

} // Sfarsit ciclu

}

}

Fişierul Suma1.java

/* Calcularea unei sume folosind ciclul cu test initial */

class Suma1 {

public static void main(String argv[]) {

int n=8, k;

double a=0.72, b=-0.1735, S;

/* Se calculeaza suma S */

S=0; k=0; // Se dau valorile initiale lui S si k

while (k<=n) {

Page 462: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

462

/* Se calculeaza termenul curent al sumei si se adauga la

valoarea precedenta a lui S

*/

S+=Math.sqrt(Math.pow(Math.sin(k*a+b),2)+

Math.pow(Math.cos(k*b-a),2));

k++; // se trece la valoarea urmatoare a lui k

} // sfarsit ciclu

/* Se afiseaza S */

System.out.println("Suma calculata este "+S);

}

}

Fişierul Serie1.java

/* Calcularea sumei unei serii convergente folosind ciclul

cu test initial

*/

class Serie1 {

public static void main(String argv[]) {

/* Se declara si se initializeaza variabilele din program */

double x=1.30726, S=0, t=1;

int k=0;

/* Se calculeaza suma S a seriei */

while (S+t!=S){

S+=t; // Se adauga termenul curent la suma partiala anterioara

k++; // Se trece la indicele termenului urmator

t*=x/k; // Se calculeaza valoarea termenului urmator

} // sfarsit ciclu

/* Se afiseaza rezultatul */

System.out.println("Suma seriei este "+S);

/* Avand in vedere ca suma S calculata mai sus este dezvoltarea

in serie Taylor a functiei matematice exponentiale exp(x),

pentru comparatie afisam si valoarea acestei functii

*/

System.out.println("Pentru comparatie: "+Math.exp(x));

}

}

Fişierul DeosCicluri.java

/* Testarea deosebirii dintre ciclurile cu test initial si cu

test final

*/

class DeosCicluri {

public static void main(String argv[]) {

int k=7;

/* Situatia cand corpul ciclului cu test initial nu se executa

nici o data

*/

while (k<0)

System.out.println("Aceast text nu trebuie sa se afiseze!");

/* Situatia similara, in care insa corpului cu test final se

Page 463: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

463

executa o singura data

*/

do

System.out.println("Acest text trebuie sa se afiseze o singura "

+"data");

while (k<0);

/* Incrementari succesive cu ciclu cu test initial */

k=0;

while (k<5){

System.out.println("In ciclul cu test initial k="+k);

k++;

}

System.out.println("La iesirea din ciclul cu test initial k="+k);

/* Incrementari succesive cu ciclu cu test final si aceeasi

conditie de continuare a ciclului

*/

k=0;

do {

System.out.println("In ciclul cu test final k="+k);

k++;

} while (k<5);

System.out.println("La iesirea din ciclul cu test final k="+k);

}

}

Fişierul Repetare2.java

/* Calcularea repetata a unei expresii pentru diferite valori ale lui k

folosind ciclul cu test final

*/

class Repetare2 {

public static void main(String argv[]) {

/* Se declara si initializeaza variabilele */

int k, n=12;

/* Se calculeaza si afiseaza in mod repetat valoarea expresiei */

k=0;

do {

System.out.println("Pentru k="+k+" Valoarea expresiei este "+

2*Math.exp(-0.35*k)*Math.sin(0.17*k-0.08));

k++; // se trece la valoarea urmatoare a lui k

} while (k<=n);

}

}

Fişierul Suma2.java

/* Calcularea unei sume folosind ciclul cu test final */

class Suma2 {

public static void main(String argv[]) {

Page 464: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

464

int n=8, k;

double a=0.72, b=-0.1735, S;

/* Se calculeaza suma S */

S=0; k=0; // Se dau valorile initiale lui S si k

do {

/* Se calculeaza termenul curent al sumei si se adauga la

valoarea precedenta a lui S

*/

S+=Math.sqrt(Math.pow(Math.sin(k*a+b),2)+

Math.pow(Math.cos(k*b-a),2));

k++; // se trece la valoarea urmatoare a lui k

} while (k<=n);

/* Se afiseaza S */

System.out.println("Suma calculata este "+S);

}

}

Fişierul Serie2.java

/* Calcularea sumei unei serii convergente folosind ciclul

cu test final

*/

class Serie2 {

public static void main(String argv[]) {

/* Se declara si se initializeaza variabilele din program */

double x=1.30726, S=0, t=1;

int k=0;

/* Se calculeaza suma S a seriei */

do {

S+=t; // Se adauga termenul curent la suma partiala anterioara

k++; // Se trece la indicele termenului urmator

t*=x/k; // Se calculeaza valoarea termenului urmator

} while (S+t!=S);

/* Se afiseaza rezultatul */

System.out.println("Suma seriei este "+S);

/* Avand in vedere ca suma S calculata mai sus este dezvoltarea

in serie Taylor a functiei matematice exponentiale exp(x),

pentru comparatie afisam si valoarea acestei functii

*/

System.out.println("Pentru comparatie: "+Math.exp(x));

}

}

Fişierul TestFor.java

/* Testarea instructiunii for */

class TestFor {

public static void main(String arg[]) {

int k, n=9;

double a=2.7465,P;

/* Diferite forme ale instructiunii for pentru realizarea urmatorului

Page 465: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

465

program scris in pseudocod:

P=1;

pentru k de_la 5 la n executa

P=P*(a+k)

sfarsit_ciclu

*/

/* Forma de baza */

for(P=1,k=5; k<=n; k++)

P*=a+k;

System.out.println("P="+P);

/* Varianta (a), in care initializarea se face inainte de

instructiunea for, iar pregatirea pasului parcurgerii

urmatoare se face in corpul ciclului. Atentie: intre

parantezele lui for s-au mentinut separatorii';'

*/

P=1; k=5;

for(;k<=n;){

P*=a+k;

k++;

}

System.out.println("In varianta (a) P="+P);

/* Varianta (b), in care s-a suprimat corpul ciclului, trecand

instructiunea respectiva in zona de pregatire a parcurgerii

urmatoare; corpul ciclului este acum instructiunea vida

*/

for(P=1,k=5;k<=n;P*=a+k,k++);

System.out.println("In varianta (b) P="+P);

/* Variabila "contor al ciclului" poate fi si de tip real

si cresterea ei la fiecera parcurgere a ciclului poate

fi de asemenea de tip real

*/

double v,S;

for(S=0, v=2.75; v<12; v+=0.12876)

S+=2*v;

System.out.println("S="+S);

/* Pasul de variatie al "contorului" poate sa nu fie constant */

for(S=2.87,v=12;v>0.005;v/=2.53)

S+=v;

System.out.println("S="+S);

}

}

Fişierul TestFor1.java

/* Declararea unor variabile in zona de initializare a instructiunii

for

*/

class TestFor1 {

public static void main(String argv[]) {

int j=0, n=7;

double x=0, a=1.2073;

Page 466: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

466

/* Variabila k este declarata si initializata in instructiunea for

*/

for(int k=0; k<n; k++)

x+=a*k;

System.out.println("x="+x);

/* Se declara in zona de initializare a instructiunii for

doua variabile, care sunt apoi folosite in acesta

instructiune

*/

x=0;

for(int k=0,i=9; k<n; k++,i--)

x+=(a+i)*k;

System.out.println("x="+x);

/* Daca incercam acum sa folosim variabilele k si i, declarate

in instructiunea for, apare eroare de compilare,deoarece

ele nu mai sunt vizibile (incercati sa suprimati // din

fata instructiunii urmatoare, apoi sa compilati)

*/

// System.out.println("k="+k+" i="+i);

/* Aceste variabile pot fi insa declarate din nou, chiar si

de alt tip

*/

x=7.28;

for(double k=8.76; k>0.28; k/=2.31) x+=k;

System.out.println("x="+x);

/* In schimb nu putem redeclara in instructiunea for variabila j,

deoarece ea este deja declarata si este vizibila si in

interiorul acestei instructiuni(incercati sa suprimati //

din fata instructiunii urmatoare si sa compilati)

*/

// for(int j=2; j<8; j++)x+=j;

}

}

Fişierul TestBreak.java

/* Testarea instructiunii break */

class TestBreak {

public static void main(String argv[]) {

double x, y, a=3.27;

/* Folosirea instructiunii break fara eticheta pentru iesirea

din ciclul for (in acest exemplu, substituie conditia de iesire

din ciclu, care lipseste din for)

*/

x=0; y=100;

for(;;){

x+=y;

if(y<0.2) break;

y/=a;

}

System.out.println("Testul 1: x="+x);

Page 467: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

467

/* Acelasi efect, in cazul instructiunii while */

x=0; y=100;

while(true){

x+=y;

if(y<0.2) break;

y/=a;

}

System.out.println("Testul 2: x="+x);

/* Folosirea unui break fara eticheta in ciclul interior (se

observa ca se iese fortat din acest ciclu, dar se reia

ciclul exterior)

*/

for(int k=0; k<=2; k++) {

System.out.println("Control 1: k="+k);

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

if(i>k) break;

System.out.println("Control 2: k="+k+" i="+i);

}

System.out.println("Control 3: k="+k);

}

System.out.println("Control 4");

/* Aceleasi doua cicluri ca in cazul precedent, dar se folo-

seste o instructiune break cu trimitere la eticheta

ciclului exterior. Se poate constata ca, in acest caz, la

executarea

instructiunii break se iese din ambele cicluri.

*/

ciclul1: for(int k=0; k<=2; k++) {

System.out.println("Control 1a: k="+k);

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

if(i>k) break ciclul1;

System.out.println("Control 2a: k="+k+" i="+i);

}

System.out.println("Control 3a: k="+k);

}

System.out.println("Control 4a");

/* Instructiunea break care contine o eticheta poate fi folosita si

pentru a iesi din blocul care poarta eticheta respectiva. In cazul

de

fata, se iese din blocul cu eticheta bloc2

*/

{ System.out.println("Intrare in blocul exterior");

int k=7;

bloc2: { System.out.println("Intrare in blocul interior");

if(k>0) break bloc2;

System.out.println("Iesire din blocul interior");

}

System.out.println("Iesire din blocul exterior");

}

System.out.println("S-a iesit din ambele blocuri");

/* Daca avem doua blocuri imbricate si dorim sa iesim din ambele,

blocul

exterior se eticheteaza, iar eticheta lui este pusa in break

*/

bloc1: { System.out.println("Intrare in blocul exterior");

int k=7;

{ System.out.println("Intrare in blocul interior");

Page 468: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

468

if(k>0) break bloc1;

System.out.println("Iesire din blocul interior");

}

System.out.println("Iesire din blocul exterior");

}

System.out.println("S-a iesit din ambele blocuri");

}

}

Fişierul TestCont.java

/* Testarea instructiunii continue */

class TestCont {

public static void main(String argv[]) {

double a=3.25, x=1.17, s, t;

int k;

/* Folosirea instructiunii continue fara eticheta */

System.out.println("Testul 1");

s=0;

for(k=0; k<20; k++) {

x*=a;

s+=x;

if(k<16) continue;

System.out.println("k="+k+" x="+x+" s="+s);

}

/* Instructiunea continue care contine o eticheta produce trecerea

fortata la sfarsitul corpului ciclului care poarta eticheta

respectiva

si continuarea acestui ciclu cat timp este satisfacuta conditia sa */

System.out.println("\nTestul 2");

ciclu1: for(int i=0; i<6; i++) {

System.out.println("Control 1: i="+i);

for(int j=3; j>0; j--) {

System.out.println("Control 2: i="+i+" j="+j);

if(i>1 && i<5) continue ciclu1;

System.out.println("Control 3: i="+i+" j="+j);

} // Sfarsitul ciclului interior

System.out.println("Control 4: i="+i);

} // Sfarsitul ciclului exterior

}

}

Fişierul TestExcept1.java

/* Exemplu de aparitie a unei exceptii */

class TestExcept1 {

public static void main(String argv[]) {

int a=7, b=0, x;

System.out.println("Urmeaza o exceptie de impartire la zero");

Page 469: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

469

x=a/b;

System.out.println("S-a depasit locul de aparitie a exceptiei");

}

}

Fişierul TestExcept2.java

/* Exemplu de aparitie a unei exceptii folosind instructiunea try */

class TestExcept2 {

public static void main(String argv[]) {

int a=7, b=0, x;

try {

System.out.println("Urmeaza o exceptie de impartire la zero");

x=a/b;

System.out.println("S-a depasit locul de aparitie a

exceptiei");

} catch (ArithmeticException e1) {

System.out.println("S-a captat exceptia aritmetica:\n"+e1);

} catch (Exception e2) {

System.out.println("S-a captat exceptia:\n"+e2);

}

System.out.println("S-a trecut de instructiunea try");

System.out.println("Sfarsit normal al programului");

}

}

Fişierul TestExcept3.java

/* Exemplu de aparitie a unei exceptii folosind instructiunea try */

class TestExcept3 {

public static void main(String argv[]) {

int a=7, b=0, x;

try {

System.out.println("Urmeaza o exceptie de impartire la zero");

x=a/b;

System.out.println("S-a depasit locul de aparitie a

exceptiei");

} catch (Exception e) {

System.out.println("S-a captat exceptia:\n"+e);

}

System.out.println("S-a trecut de instructiunea try");

System.out.println("Sfarsit normal al programului");

}

}

Fişierul TestExcept4.java

/* Exemplu de aparitie a unei exceptii folosind instructiunea try */

class TestExcept4 {

Page 470: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

470

public static void main(String argv[]) {

int a=7, b=0, x;

try {

System.out.println("Urmeaza o exceptie de impartire la zero");

x=a/b;

System.out.println("S-a depasit locul de aparitie a

exceptiei");

} catch (ArithmeticException e1) {

System.out.println("S-a captat exceptia e1:\n"+e1);

} catch (Exception e2) {

System.out.println("S-a captat exceptia e2:\n"+e2);

}

finally {

System.out.println("S-a executat secventa din clauza

finally");

}

System.out.println("S-a trecut de instructiunea try");

System.out.println("Sfarsit normal al programului");

}

}

Fişierul TestExcept5.java

/* Exemplu de aparitie a unei exceptii folosind instructiunea try */

class TestExcept5 {

public static void main(String argv[]) {

int a=7, b=1, x;

try {

System.out.println("Urmeaza o impartire intreaga");

x=a/b;

System.out.println("S-a efectuat impartirea fara sa apara "+

"o exceptie");

} catch (ArithmeticException e1) {

System.out.println("S-a captat exceptia e1:\n"+e1);

} catch (Exception e2) {

System.out.println("S-a captat exceptia e2:\n"+e2);

}

finally {

System.out.println("S-a executat secventa din clauza

finally");

}

System.out.println("S-a trecut de instructiunea try");

System.out.println("Sfarsit normal al programului");

}

}

Capitolul 4

Fişierul TestObject.java

/* Testarea clasei Object */

import java.util.*;

Page 471: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

471

class TestObject {

public static void main(String argv[]) {

Object ob1=new Object(), ob2=new String("ABCD"), ob3="abcd", ob4=ob2;

Object ob5=new Object(), ob6=ob5;

String str1="ABCD", str2=str1;

System.out.println("ob1="+ob1);

System.out.println("ob2="+ob2);

System.out.println("ob3="+ob3);

System.out.println("str1="+str1);

System.out.println("Coduri de dispersie:");

System.out.println("ob1: "+ob1.hashCode());

System.out.println("ob5: "+ob5.hashCode());

System.out.println("ob2: "+ob2.hashCode());

System.out.println("str1: "+str1.hashCode());

System.out.println("ob4: "+ob4.hashCode());

System.out.println("ob3: "+ob3.hashCode());

System.out.println("Testarea egalitatii prin == si prin equals():");

/* In clasa Obhect operatorul == si metoda equals() sunt echivalente

*/

System.out.println("ob1==ob5: "+(ob1==ob5)+" ob1.equals(ob5): "+

(ob1.equals(ob5)));

System.out.println("ob5==ob6: "+(ob5==ob6)+" ob5.equals(ob6): "+

(ob5.equals(ob6)));

/* Pentru obiecte din clasa String operatorul == testeaza egalitatea

referintelor, in timp ce metoda equals() testeaza egalitatea

continutului"

*/

System.out.println("ob2==ob4: "+(ob2==ob4)+" ob2.equals(ob4): "+

(ob2.equals(ob4)));

System.out.println("ob2==str1: "+(ob2==str1)+" ob2.equals(str1): "+

(ob2.equals(str1)));

System.out.println("ob2==ob3: "+(ob2==ob3)+" ob2.equals(ob3): "+

(ob2.equals(ob3)));

/* Aplicarea metodei toString() obiectelor din clasa Object */

System.out.println("Aplicarea metodei toString(): ");

System.out.println("pentru ob1: "+ob1.toString());

/* Aplicarea metodei toString() obiectelor din clasa String intoarce

chiar sirul pe care acestea il contin

*/

System.out.println("pentru ob2: "+ob2.toString());

System.out.println("pentru ob3: "+ob3.toString());

System.out.println("pentru str1: "+str1.toString());

/* De altfel, daca un obiect apare ca argument in metoda print() sau

println(), aplicarea conversia lui in sir (deci aplicarea metodei

toString() se face in mod implicit

*/

System.out.println("Aceleasi afisari, cu conversii in sir

implicite:");

System.out.println(ob1);

System.out.println(ob2);

System.out.println(ob3);

System.out.println(str1);

/* Unei variabile din clasa Object i se poate atribui o referinta la

un

obiect din clasa String, deci instructiunea urmatoare nu produce o

Page 472: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

472

eroare de compilare

*/

ob1=str2;

/* Unei variabile din clasa String nu i se poate atribui o referinta

la un obiect din clasa Object. In consecinta, daca se elimina //

din

linia de program urmatoare, apare o eroare la compilare

*/

// str1=ob2;

/* Daca insa suntem siguri ca variabila ob2 din clasa Object contine

in

realitate o referinta la un obiect din clasa String (asa cum este

cazul in situatia de fata) putem cere o conversie explicita de la

Object la String. Din aceasta cauza, instructiunea urmatoare nu

mai

constituie o eroare

*/

str1=(String)ob2;

/* Aplicarea metodei getClass() */

System.out.println("Informatii despre clase: ");

System.out.println("ob5: "+ob5.getClass());

System.out.println("ob2: "+ob2.getClass());

System.out.println("str1: "+str1.getClass());

}

}

Fişierul TestStr.java

/* Testarea clasei String */

class TestStr {

public static void main(String args[]) {

String s1="ABCdef#@&", s2, s3, s4;

char ch1[];

byte tb[];

s2=new String("Un sir nou");

System.out.println("s1="+s1+" s2="+s2);

System.out.println("Lungimile sirurilor: s1="+s1.length()+

" s2="+s2.length());

System.out.println("Conversie in litere mari: s1="+s1.toUpperCase()+

" s2="+s2.toUpperCase());

System.out.println("Conversie in litere mici: s1="+s1.toLowerCase()+

" s2="+s2.toLowerCase());

ch1=s1.toCharArray();

System.out.print("s1 convertit in tablou de caractere: ");

for(int i=0; i<ch1.length; i++) System.out.print(ch1[i]);

System.out.println(); // trecere la linie noua

tb=s1.getBytes();

System.out.print("s1 convertit in tablou de octeti: ");

for(int i=0; i<tb.length; i++) System.out.print(tb[i]+" ");

System.out.print("\nAcelasi tablou convertit in caractere: ");

for(int i=0; i<tb.length; i++) System.out.print((char)tb[i]);

System.out.println();

s3=String.copyValueOf(ch1);

System.out.println("Sirul obtinut din tabloul de caractere: "+s3);

System.out.println("Comparatii de siruri: "+s1.compareTo(s3)+" "+

Page 473: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

473

s1.compareTo(s2)+" "+s2.compareTo(s1));

System.out.println("s1==s3: "+(s1==s3)+" s1.equals(s3): "+

s1.equals(s3));

s4=s2.toUpperCase();

System.out.println("s2="+s2+" s4="+s4);

System.out.println("s2.equals(s4): "+s2.equals(s4)+

" s2.equalsIgnoreCase(s4): "+s2.equalsIgnoreCase(s4));

System.out.println("Subsirul lui s2 intre pozitiile 3 si 8: "+

s2.substring(3,8));

System.out.println("Subsirul lui s2 de la pozitia 3 la sfarsit: "+

s2.substring(3));

}

}

Fişierul TestStrB.java

/* Testarea clasei StringBuffer */

class TestStrB {

public static void main(String args[]) {

StringBuffer stb1=new StringBuffer(), stb2;

String str1="abcdefg", str2;

double d=3.670283105E-3;

char tc1[]={'A','B','C'}, tc2[]=new char[10];

System.out.println("Lungimea si capacitatea initiala a stb1: "+

stb1.length()+" "+stb1.capacity());

stb1.append(str1);

stb1.append(d);

System.out.println("stb1="+stb1+"\nLungime: "+stb1.length()+

" Capacitate: "+stb1.capacity());

str2=stb1.toString(); // Este obligatorie folosirea metodei

toString()

System.out.println("Caracterul de indice 3: "+stb1.charAt(3));

stb2=stb1.insert(3, "PQRS");

System.out.println("Dupa insertia sirului PQRS:\nstb1="+stb1+

"\nstb2="+stb2);

stb1.append(tc1);

System.out.println("Dupa adaugarea tabloului tc1, stb1="+stb1);

System.out.println("Lungime: "+stb1.length()+" Capacitate: "+

stb1.capacity());

stb1.delete(3,25);

System.out.println("Dupa eliminarea zonei 3..25: "+stb1);

System.out.println("Lungime: "+stb1.length()+" Capacitate: "+

stb1.capacity());

stb1.reverse();

System.out.println("Dupa inversare stb1="+stb1);

stb1.getChars(1,4,tc2,3);

System.out.println("Dupa extragerea de caractere, lungimea "+

"tabloului tc2: "+tc2.length);

System.out.print("tc2=");

for(int i=0; i<tc2.length; i++) System.out.print(tc2[i]);

System.out.println();

}

}

Page 474: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

474

Fişierul TestClass.java

/* Testarea clasei Class */

class TestClass {

public static void main(String args[]) {

String s1="Primul sir", s2="al doilea sir";

Object obj=new Object();

Class cls1, cls2, cls3;

cls1=s1.getClass();

System.out.println(cls1.getName());

System.out.println(cls1.toString());

cls2=s2.getClass();

System.out.println(cls1.isAssignableFrom(cls2));

cls3=obj.getClass();

System.out.println(cls3);

System.out.println(cls1.isAssignableFrom(cls3));

System.out.println(cls3.isAssignableFrom(cls1));

System.out.println(cls1.getSuperclass());

System.out.println(cls3.getSuperclass());

System.out.println(cls1.isPrimitive());

}

}

Fişierul testBoolean.java

/* Testarea clasei acoperitoare Boolean */

class TestBoolean {

public static void main(String args[]) {

boolean b1=true, b2=false, b3, b4;

Boolean bc1, bc2, bc3=Boolean.TRUE, bc4=Boolean.FALSE, bc5, bc6;

boolean tb1[]={true, false, true},

tb2[][]={{true,false},{false,true}};

Boolean tcb1[]={Boolean.TRUE,Boolean.FALSE};

Boolean tcb2[][]={{Boolean.FALSE,Boolean.TRUE},

{Boolean.TRUE,Boolean.FALSE}};

String str1, str2;

/* Se aplica constructorul Boolean(boolean value) */

bc1=new Boolean(b1);

bc2=new Boolean(b2);

/* Se afiseaza valorile variabilelor bc1 si bc2 convertite in siruri

(amintim ca in argumentele metodelor print() si println()

aplicarea

metodei toString() este implicita)

*/

System.out.println("bc1="+bc1+" bc2="+bc2);

/* Se afiseaza tablourile cu componente de tip primitiv boolean */

System.out.println("Tabloul tb1: ");

for (int i=0; i<tb1.length; i++) System.out.print(tb1[i]+" ");

System.out.println("\nTabloul bidimensional tb2: ");

for (int i=0; i<tb2.length; i++) {

for (int j=0; j<tb2[i].length; j++)

System.out.print(tb2[i][j]+" ");

System.out.println();

}

/* Se afiseaza tablourile cu componente din clasa Boolean */

Page 475: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

475

System.out.println("Tabloul tcb1: ");

for (int i=0; i<tcb1.length; i++) System.out.print(tcb1[i]+" ");

System.out.println("\nTabloul bidimensional tcb2: ");

for (int i=0; i<tcb2.length; i++) {

for (int j=0; j<tcb2[i].length; j++)

System.out.print(tcb2[i][j]+" ");

System.out.println();

}

/* Afisarea valorii variabilei finale statice TYPE */

System.out.println("Clasa primitiva acoperita de bc1: "+bc1.TYPE);

/* Aplicarea metodei getClass mostenite de la clasa Object */

System.out.println("Clasa obiectului bc1: "+bc1.getClass());

/* Afisarea valorilor variabilelor bc3 si bc4 convertite la sir */

System.out.println("bc3="+bc3+" bc4="+bc4);

/* Compararea obiectelor prin operatorul == si prin metoda equals().

Se obtin rezultate diferite, deoarece operatorul == compara

referintele (iar obiectele bc1 si bc3 au adrese diferite in

memorie)

in timp ce metoda equals() compara obiectele insesi, iar in cazul

de fata ambele contin intern valoarea primitiva true

*/

System.out.println("bc1==bc3: "+(bc1==bc3)+" bc1.equals(bc3): "

+ bc1.equals(bc3));

/* Aplicarea metodei hashCode(). Remarcam ca pentru obiecte identice

se obtin coduri de dispersie identice

*/

System.out.println("Coduri de dispersie: ");

System.out.println("bc1: "+bc1.hashCode()+" bc3: "+bc3.hashCode());

System.out.println("bc2: "+bc2.hashCode()+" bc4: "+bc4.hashCode());

/* Testarea metodei booleanValue() (care intoarce o valoare primitiva

de tip boolean)

*/

b3=bc1.booleanValue(); b4=bc2.booleanValue();

/* Testarea constructorului Boolean(String s) pentru cazul cand are

ca argument sirul "true". Se observa ca nu conteaza daca literele

sunt mari sau mici.

*/

bc5=new Boolean("True");

bc6=new Boolean("TrUe");

System.out.println("bc5="+bc5+" bc6="+bc6);

/* Testarea pentru cazul cand argumentul nu este sirul "true" */

bc5=new Boolean("adevarat");

bc6=new Boolean("fals");

System.out.println("bc5="+bc5+" bc6="+bc6);

/* Testarea faptului ca aceleasi rezultate se obtin aplicand metoda

public static Boolean valueOf(String s)

*/

bc5=Boolean.valueOf("TruE");

bc6=Boolean.valueOf("un sir");

System.out.println("Aplicand metoda valueOf(): bc5="+bc5+"

bc6="+bc6);

/* Se testeaza metoda toString() */

/* Atribuirea din linia urmatoare nu este permisa (incercati sa

suprimati simbolul de comentariu //)

*/

// str1=bc1;

/* Atribuirile urmatoare sunt permise, caci metoda toString intoarce

un sir

*/

str1=bc1.toString();

str2=tcb2[1][0].toString();

Page 476: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

476

System.out.println("str1="+str1+" str2="+str2);

}

}

Fişierul TestInt.java

/* Testarea clasei acoperitoare Integer */

class TestInt {

public static void main(String args[]) {

Integer tI[]=new Integer[5], tI1[]=new Integer[5], a;

int tint[]=new int[5], i1;

String ts[]={"3298","-18765","+987692","-765b32","abcde"};

/* Testarea metodei statice parseInt(String) */

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

try {

tint[i]=Integer.parseInt(ts[i]);

}

catch(NumberFormatException e1) {

System.out.println("i="+i+" eroare in sirul: "+ts[i]);

}

catch(Exception e) {

System.out.println("i="+i+" Exceptie "+e);

}

}

System.out.print("tint=");

for(int i=0; i<tint.length; i++) System.out.print(tint[i]+" ");

System.out.println();

/* Incercam preluarea unui numar mai mare decat valoarea maxima

a unui numar de tip int, care este 2147483647

*/

try {

i1=Integer.parseInt("2147483648");

System.out.println("i1="+i1);

}

catch(Exception e) {

System.out.println("Numarul 2147483648 a produs exceptia:\n"+e);

}

/* Testarea metodei parseInt(String,int) */

System.out.println("38AB3FC7 din baza 16 este: "+

Integer.parseInt("38AB3FC7",16));

System.out.println("-38AB3FC7 din baza 16 este: "+

Integer.parseInt("-38AB3FC7",16));

System.out.println("6423651 din baza 7 este: "+

Integer.parseInt("6423651",7));

System.out.println("7GHA din baza 18 este: "+

Integer.parseInt("7GHA",18));

System.out.println("-AC7D din baza 16 este: "+

Integer.parseInt("-AC7D",16));

/* Incercam preluarea unui numar hexazecimal mai mare de 7FFFFFFF */

try {

i1=Integer.parseInt("80000000",16);

} catch (Exception e) {

System.out.println(e);

}

/* Afisarea aceluiasi numar in diferite baze de numeratie: */

i1=1986895879;

for(int i=2; i<=18; i+=4)

Page 477: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

477

System.out.println("in baza "+i+" i1="+Integer.toString(i1, i));

/* Testarea metodei statice valueOf(String) poate fi facuta

in acelasi mod ca pentru metoda parseInt(String)

*/

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

try {

tI[i]=Integer.valueOf(ts[i]);

}

catch(NumberFormatException e1) {

System.out.println("i="+i+" eroare in sirul: "+ts[i]);

}

catch(Exception e) {

System.out.println("i="+i+" Exceptie "+e);

}

}

System.out.print("tI=");

for(int i=0; i<tI.length; i++) System.out.print(tI[i]+" ");

System.out.println();

/* Repetam acelasi procedeu, testand acum constructorul

Integer(String)

*/

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

try {

tI1[i]=new Integer(ts[i]);

}

catch(NumberFormatException e1) {

System.out.println("i="+i+" eroare in sirul: "+ts[i]);

}

catch(Exception e) {

System.out.println("i="+i+" Exceptie "+e);

}

}

System.out.print("tI1=");

for(int i=0; i<tI1.length; i++) System.out.print(tI1[i]+" ");

System.out.println();

/* Pentru un singur obiect din clasa Integer aplicam toate metodele

de conversie in valoare de tip primitiv

*/

a=new Integer(1763478206);

System.out.println("byte: "+a.byteValue());

System.out.println("short: "+a.shortValue());

System.out.println("int: "+a.intValue());

System.out.println("long: "+a.longValue());

System.out.println("float: "+a.floatValue());

System.out.println("double: "+a.doubleValue());

}

}

Fişierul testDouble.java

/* Testarea clasei acoperitoare Double */

class TestDouble {

public static void main(String args[]) {

Double tD[]=new Double[6], a;

double td[]=new double[6];

String ts[]={"3.2987","-187.659068","+9.87692413","8.0764382e-7",

"-238.0729456E8","4.687b53e7"};

Page 478: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

478

long b;

/* Testarea metodei statice parseDouble(String) */

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

try {

td[i]=Double.parseDouble(ts[i]);

}

catch(NumberFormatException e1) {

System.out.println("i="+i+" eroare in sirul: "+ts[i]);

}

catch(Exception e) {

System.out.println("i="+i+" Exceptie "+e);

}

}

System.out.print("td=");

for(int i=0; i<td.length; i++) System.out.print(td[i]+" ");

System.out.println();

/* Repetam acelasi procedeu, testand acum constructorul

Double(String)

*/

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

try {

tD[i]=new Double(ts[i]);

}

catch(NumberFormatException e1) {

System.out.println("i="+i+" eroare in sirul: "+ts[i]);

}

catch(Exception e) {

System.out.println("i="+i+" Exceptie "+e);

}

}

System.out.print("tD=");

for(int i=0; i<tD.length; i++) System.out.print(tD[i]+" ");

System.out.println();

/* Pentru un singur obiect din clasa Integer aplicam toate metodele

de conversie in valoare de tip primitiv

*/

a=new Double(73416.853209);

System.out.println("byte: "+a.byteValue());

System.out.println("short: "+a.shortValue());

System.out.println("int: "+a.intValue());

System.out.println("long: "+a.longValue());

System.out.println("float: "+a.floatValue());

System.out.println("double: "+a.doubleValue());

/* Forma interna (binara) a numarului */

b=Double.doubleToLongBits(a.doubleValue());

System.out.println("Reprezentarea interna a numarului real

precedent:");

System.out.println("in binar: "+Long.toBinaryString(b));

System.out.println("in hexazecimal: "+Long.toHexString(b));

}

}

Fişierul TestChar.java

/* Testarea clasei acoperitoare Character */

class TestChar {

public static void main(String args[]) {

Page 479: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

479

Character c1=new Character('B'), c2=new Character('b'), c3;

Object ob;

c3=new Character('b');

ob=c3;

System.out.println("'x' este litera: "+Character.isLetter('x'));

System.out.println("'3' este cifra: "+Character.isDigit('3'));

System.out.println("'b' este litera mica:

"+Character.isLowerCase('b'));

System.out.println("'*' este litera mare:

"+Character.isUpperCase('*'));

System.out.println("'\\n' este Whitespace: "+

Character.isWhitespace('\n'));

System.out.println("'\\n' este SpaceChar:

"+Character.isSpaceChar('\n'));

System.out.println("'d' mare este: "+Character.toUpperCase('d'));

System.out.println("In sistemul de numeratie cu baza 27 cifra 19

este: "+

Character.forDigit(19,27));

System.out.println("In acelasi sistem, litera 'M' este cifra: "+

Character.digit('M',27));

/* Testarea operatorului == si a metodei equals() */

System.out.println("c2==c3: "+(c2==c3));

System.out.println("ob==c3: "+(ob==c3));

System.out.println("c2 identic cu c3: "+c2.equals(c3));

System.out.println("c2 identic cu ob: "+c2.equals(ob));

System.out.println("c1 identic cu ob: "+c1.equals(ob));

/* Testarea metodei hashCode() */

System.out.println("Coduri de dispersie pentru c1, c2, c3 si ob:\n"+

c1.hashCode()+" "+c2.hashCode()+" "+c3.hashCode()+" "+

ob.hashCode());

}

}

Fişierul InitTab1.java

/* Declararea si initializarea tablourilor unidimensionale */

class InitTab1 {

public static void main(String args[]) {

int a=27, b=-15, c[]={-3,72,-21}, d=-5, e[]={231,-98};

String s1="un sir", ts1[]={"sirul 0","sirul 1","sirul 2"},

s2="alt sir";

float[] u={-1.24076f, 0.03254f, 27.16f}, v={2.7698E-12f,-3.876e7f};

double aa[]=new double[3], bb[]={3.76,-2.879};

String str[]=new String[2], s3="abcdef1234";

long []k={187658954760876535L, 786432098764319051L},

m={598028476093172L, -9892865429740341L, 92765201};

Object tab1[]=new Object[2],tab2=new String[3],

tab3[]={"aaa","bbb","ccc"};

System.out.println("Valorile variabilelor simple:");

System.out.println("a="+a+" b="+b+" d="+d);

System.out.println("s1="+s1+" s2="+s2+" s3="+s3);

System.out.println("Lungimile tablourilor:");

System.out.println("c: "+c.length+" e: "+e.length+" ts1:

"+ts1.length);

System.out.println("u: "+u.length+" v: "+v.length+" str:

"+str.length);

System.out.println("aa: "+aa.length+" bb: "+bb.length);

Page 480: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

480

System.out.println("k: "+k.length+" m: "+m.length);

System.out.println("Componentele tablourilor:");

System.out.println("Tabloul c:");

for (int i=0; i<c.length; i++) System.out.print(c[i]+" ");

System.out.println("\nTabloul ts1:");

for(int j=0; j<ts1.length; j++) System.out.print(ts1[j]+"; ");

System.out.println();

System.out.println("Tabloul aa:");

for(int i=0; i<aa.length; i++) System.out.print(aa[i]+" ");

System.out.println("\nTabloul de siruri str:");

for (int j=0; j<str.length; j++) System.out.print(str[j]+"; ");

System.out.println();

System.out.println("Tabloul tab3:");

for(int i=0; i<tab3.length; i++) System.out.print(tab3[i]+"; ");

System.out.println();

}

}

Fişierul Tab1.java

/* Utilizarea tablourilor unidimensionale */

class Tab1 {

public static void main(String args[]) {

double a[]={3.276, -5.83, 12.8}, b[];

String ts1[]={"aa", "bb"},ts2[];

/* Variabilelor b si ts1 li se atribuie ca valori referinte la

tablouri

existente, apoi se afiseaza

*/

b=a;

ts2=ts1;

System.out.println("Dupa atribuirile b=a si ts2=ts1:");

for (int i=0; i<a.length; i++)

System.out.println("i="+i+" a[i]="+a[i]+" b[i]="+b[i]);

for (int i=0; i<ts1.length; i++)

System.out.println("i="+i+" ts1[i]="+ts1[i]+" ts2[i]="+ts2[i]);

/* Atribuim o alte valori lui b[0] si b[1], apoi afisam tablourile a

si b

*/

b[0]=-12.7; b[1]=283.6;

System.out.println("Dupa ce s-au dat valori noi componentelor lui

b:");

for (int i=0; i<a.length; i++)

System.out.println("i="+i+" a[i]="+a[i]+" b[i]="+b[i]);

/* Atribuim variabilei b o referinta la un nou tablou. Constatam ca

valorile componentelor noului tablou sunt nule

*/

b=new double[4];

System.out.println("Dupa atribuirea unui nou tablou, b[] indica:");

for (int i=0; i<b.length; i++) System.out.print(b[i]+" ");

System.out.println();

/* Atribuim valori componentelor noului tablou indicat de b[] si

le afisam

*/

for (int i=0; i<b.length; i++) b[i]=Math.cos(0.7*i+0.23);

System.out.println("Noul tablou b dupa atribuirea de valori:");

for(int i=0; i<b.length; i++) System.out.print(b[i]+" ");

Page 481: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

481

System.out.println("\nTabloul a[] a ramas neschimbat:");

for (int i=0; i<a.length; i++) System.out.print(a[i]+" ");

System.out.println();

/* Testam si ce se intampla daca incercam sa folosim o un indice care

iese din domeniul tabloului

*/

try {

System.out.println(b[5]);

} catch (Exception e) {

System.out.println("S-a produs exceptia:\n"+e);

}

System.out.println("Programul s-a incheiat normal");

}

}

Fişierul ConvTip1.java

/* Conversii de tip la atribuiri de referinte la tablouri unidimensionale

*/

class ConvTip1 {

public static void main(String args[]) {

int a[]={54, 23, -17}, b[];

double u[]={-6.237429, 83.17026}, v[];

String str1[]={"abc","def"}, str2[], str3[];

Object ob1, ob2, ob3, tob1[], tob2[];

/* Atribuire permisa: Object este superclasa pentru String */

tob1=str1;

/* Instructiunea urmatoare nu este permisa, deoarece String nu este

superclasa a lui Object (puteti verifica suprimand // din fata ei)

*/

// str2=tob1;

/* Deoarece stim ca tob1[] contine o referinta la un tablou String,

putem face o conversie explicita prin cast

*/

str2=(String[])tob1;

/* Tablourile a[] si u[] sunt considerate obiecte, deci variabilele

bsimple din clasa Object pot primi ca valori referinte la astfel

de

tablouri

*/

ob1=a;

ob2=u;

/* Chiar si un tablou de obiecte este considerat tot un obiect */

ob3=str1;

/* Atribuirile inverse nu sunt permise, deoarece clasele int[],

double[]

si String[] nu sunt superclase ale lui Object (puteti verifica!)

*/

// b=ob1;

// v=ob2;

// str3=ob3;

/* Avand in vedere ca stim ca atribuirile sunt corecte, ne putem

permite sa facem conversiile explicite prin cast

*/

b=(int[])ob1;

v=(double[])ob2;

str3=(String[])ob3;

Page 482: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

482

/* Pentru a face diferite operatii cu componentele tablourilor

referite

de variabilele ob1, ob2 ob3 si tob1 sunt necesare, de asemenea,

conversii explicite, deoarece ob1, ob2, ob3 nu sunt tablouri

*/

System.out.println("Tabloul referit de ob1:");

for (int i=0; i<((int[])ob1).length; i++)

System.out.print(((int[])ob1)[i]+" ");

System.out.println("\nTabloul referit de ob2: ");

for (int j=0; j<((double[])ob2).length; j++)

System.out.print(((double[])ob2)[j]+" ");

System.out.println("\nTabloul referit de ob3:");

for (int k=0; k<((String[])ob3).length; k++)

System.out.print(((String[])ob3)[k]+"; ");

System.out.println();

/* Pentru afisarea elementelor lui tob1[] nu este nevoie de cast,

deoarece acesta este tablou de componente din clasa Object care au

ca

valori referinte la String, iar Object este superclasa pentru

String

*/

System.out.println("Tabloul referit prin tob1[]:");

for (int i=0; i<tob1.length; i++) System.out.print(tob1[i]+"; ");

System.out.println();

/* Atribuim valori unor componente ale acestor tablouri si le afisam

*/

((double[])ob2)[1]=12.7846e-8;

((String[])ob3)[0]="pqrst";

System.out.println("Valori atribuite: "+((double[])ob2)[1]+" "+

((String[])ob3)[0]);

/* Afisam clasele carora le apartin unele din aceste tablouri */

System.out.println("Clasa lui a[]: "+a.getClass().getName());

System.out.println("Clasa lui u[]: "+u.getClass().getName());

System.out.println("Clasa lui str1[]: "+str1.getClass().getName());

System.out.println("Clasa lui ob1: "+ob1.getClass().getName());

System.out.println("Clasa lui ob2: "+ob2.getClass().getName());

System.out.println("Clasa lui ob3: "+ob3.getClass().getName());

}

}

Fişierul Tab2.java

/* Declararea si initializarea tablourilor bidimensionale */

class Tab2 {

public static void main(String args[]) {

double u=5.3127, v[]={1.25, -3.12, 2.6},

w[][]={{2.31, -4.15},{0.35,-12.6, -573.2},{10.9}};

int[] a={3,2,7}, b[]={{43,28,92,-6},{},{-1,17,29}};

char[][] h1={{'a','*'},{'+','$'}}, h2=new char[2][3], h3=new

char[4][];

String ts[][]={{"abc","defg"},{"AB","CD","EF"}};

System.out.println("Numarul de linii din tabloul w: "+w.length);

System.out.println("Numarul de componente din fiecare linie a "+

"tabloului w:");

for (int i=0; i<w.length; i++) System.out.print(w[i].length+" ");

System.out.println("\nComponentele tabloului w:");

for (int i=0; i<w.length; i++) { // Se afiseaza o linie

Page 483: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

483

for (int j=0; j<w[i].length; j++) System.out.print(w[i][j]+" ");

System.out.println(); // Se trece la linie noua

}

System.out.println("Numarul de linii din tabloul b: "+b.length);

System.out.println("Numarul de componente din fiecare linie "+

" a tabloului b:");

for (int i=0; i<b.length; i++) System.out.print(b[i].length+" ");

System.out.println("\nComponentele tabloului b:");

for (int i=0; i<b.length; i++) {

for (int j=0; j<b[i].length; j++) System.out.print(b[i][j]+" ");

System.out.println();

}

System.out.println("Tabloul de caractere h1:");

for (int i=0; i<h1.length; i++) {

for (int j=0; j<h1[i].length; j++) System.out.print(h1[i][j]+"

");

System.out.println();

}

System.out.println("Tabloul de siruri ts:");

for (int i=0; i<ts.length; i++) {

for (int j=0; j<ts[i].length; j++) System.out.print(ts[i][j]+"

");

System.out.println();

}

}

}

Fişierul Tab2a.java

/* Operatii cu tablouri unidimensionale si bidimensionale */

class Tab2a {

public static void main(String args[]) {

int a[][]={{-5,12,52},{8,-4},{},{105}}, b[]={31,-3,17,24};

System.out.println("Dupa initializare:\nTabloul bidimensional a:");

for(int i=0; i<a.length; i++) {

for(int j=0; j<a[i].length; j++) System.out.print(a[i][j]+" ");

System.out.println();

}

System.out.println("Tabloul unidimensional b:");

for(int i=0; i<b.length; i++) System.out.print(b[i]+" ");

System.out.println();

/* Se fac atribuiri de valori ale componentelor si de linii de tablou

*/

a[0][2]=2*b[1]-a[1][1];

a[2]=new int[3]; // s-a creat o noua linie pentru a[2]

a[2][0]=b[3];

a[2][2]=a[3][0];

a[3]=b; // S-a inlocuit vechea linie a[3] prin tabloul b

b=a[1]; // b indica acum spre linia a[1];

b[1]=88; // S-a modificat, de fapt, componenta a[1][1];

/* Se afiseaza noua stare */

System.out.println("Dupa atribuiri:\nTabloul bidimensional a:");

for(int i=0; i<a.length; i++) {

for(int j=0; j<a[i].length; j++) System.out.print(a[i][j]+" ");

System.out.println();

}

System.out.println("Tabloul unidimensional b:");

Page 484: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

484

for(int i=0; i<b.length; i++) System.out.print(b[i]+" ");

System.out.println();

}

}

Fişierul Tab2b.java

/* Conversii de tip la tablouri bidimensionale */

class Tab2b {

public static void main(String args[]) {

Object ob1, ob2, tob2[][];

int ti1[][]={{0,1},{10,11,12,13},{20,21,22}},ti2[][];

String ts[][]={{"aa","ab"},{"ba","bb","bc"},{"ca","cb"}}, ts1[][];

/* Urmatoarele doua atribuiri sunt corecte */

ob1=ti1;

ob2=ts;

System.out.println("Tabloul indicat de ob1:");

for(int i=0; i<((int[][])ob1).length; i++) {

for(int j=0; j<((int[][])ob1)[i].length; j++)

System.out.print(((int[][])ob1)[i][j]+" ");

System.out.println();

}

/* Urmatoarele doua atribuiri nu sunt corecte, deoarece se trece de

la clasa la subclasa (incercati sa suprimati simbolul // )

*/

// ti2=ob1;

// ts1=ob2;

/* In urmatoarele doua atribuiri s-a recurs la conversii explicite,

stiind caror clase apartin efectiv obiectele referite de

variabilele

respective

*/

ti2=(int[][])ob1;

ts1=(String[][])ob2;

System.out.println("Tabloul ti2:");

for(int i=0; i<ti2.length; i++) {

for(int j=0; j<ti2[i].length; j++) System.out.print(ti2[i][j]+"

");

System.out.println();

}

System.out.println("Tabloul ts1:");

for(int i=0; i<ts1.length; i++) {

for(int j=0; j<ts1[i].length; j++) System.out.print(ts1[i][j]+"

");

System.out.println();

}

/* In atribuirea urmatoare, castul este aplicat corect sub aspect

sintactic, deci nu se semnaleaza o eroare la compilare, dar va

apare o exceptie la executie, deoarece in mod efectiv ob2 nu este

o referinta la int[][] ci la String[][]

*/

try {

ti2=(int[][])ob2;

}

catch(Exception e) {

System.out.println("S-a generat exceptia: "+e);

}

Page 485: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

485

tob2=ts;

ts1=(String[][])tob2;

}

}

Fişierul TabEterogen.java

/* Testarea construirii unui tablou eterogen */

class TabEterogen {

public static void main(String args[]) {

/* Construirea structurii */

Object tab[]=new Object[3];

tab[0]=new int[3];

((int[])tab[0])[0]=-87;

((int[])tab[0])[1]=23;

((int[])tab[0])[2]=164;

tab[1]=new double[2];

((double[])tab[1])[0]=32.164;

((double[])tab[1])[1]=-6.237;

tab[2]=new Object[3];

((Object[])tab[2])[0]=new String("abcd");

((Object[])tab[2])[1]=new String("PQRS");

((Object[])tab[2])[2]=new char[2];

((char[])((Object[])tab[2])[2])[0]='@';

((char[])((Object[])tab[2])[2])[1]='$';

/* Afisarea unor componente din structura */

System.out.println(((Object[])tab[2])[0]);

for(int i=0; i<3; i++)

System.out.print(((int[])tab[0])[i]+" ");

System.out.println();

for(int i=0; i<2; i++)

System.out.print(((char[])((Object[])tab[2])[2])[i]+" ");

System.out.println();

}

}

Capitolul 5

Fişierul TestRecursii.java

/* Metode recursive si iterative */

class Recursii {

/* Metode recursive */

public static long factorial(int n) throws Exception {

if(n<0) throw new Exception("factorial(n): n<0");

if(n==0) return 1;

return n*factorial(n-1);

}

public static long fibonacci(int n) throws Exception {

if(n<0) throw new Exception("fibonacci(n): n<0");

Page 486: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

486

if(n==0) return 0;

if(n==1) return 1;

return fibonacci(n-1)+fibonacci(n-2);

}

/* Metode mutual recursive: fct1() o invoca pe fct2() si reciproc */

public static double fct1(int n, double x) throws Exception {

if(n<0) throw new Exception("fct1: n<0");

return 2*fct2(n, 0.4*x+0.3)+x;

}

public static double fct2(int n, double y) throws Exception {

if(n<0) throw new Exception("fct2: n<0");

if(n==0) return y;

return y*fct1(n-1, 1.27*y-0.89)-1;

}

}

class Iteratii {

public static long factorial(int n) throws Exception {

long fact;

if(n<0) throw new Exception("factorial(n): n<0");

fact=1;

for(int i=2; i<=n; i++) fact*=i;

return fact;

}

public static long fibonacci(int n) throws Exception {

if(n<0) throw new Exception("fibonacci(n): n<0");

if(n==0) return 0;

if(n==1) return 1;

long a=0, b=1;

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

b+=a;

a=b-a;

}

return b;

}

}

/* Aplicatia TestRecursii pentru testarea claselor Recursii si Iteratii.

Se pune in executie dand ca parametru in linia de comanda numarul al

carui

factorial se calculeaza

*/

class TestRecursii {

public static void main(String args[]) {

int n;

if(args.length==0) {

System.out.println("Nu ati dat ca parametru un numar intreg");

System.exit(1);

}

n=Integer.parseInt(args[0]);

try {

long fact1, fact2, fib1, fib2;

long time1, time2;

/* Testarea functiilor mutual recursive fct1() si fct2() */

System.out.println("fct1("+n+", 1.76)="+Recursii.fct1(n,1.76));

System.out.println("fct2("+n+", 1.76)="+Recursii.fct2(n,1.76));

Page 487: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

487

/* Calcularea factorialului prin functie recursiva */

time1=System.currentTimeMillis();

fact1=Recursii.factorial(n);

time2=System.currentTimeMillis();

System.out.println("Recursiv factorial("+n+")="+fact1+

" durata: "+(time2-time1));

/* Calcularea iterativa a factorialului */

time1=System.currentTimeMillis();

fact2=Iteratii.factorial(n);

time2=System.currentTimeMillis();

System.out.println("Iterativ factorial("+n+")="+fact2+

" durata: "+(time2-time1));

/* Calcularea recursiva a numarului lui Fibonacci */

time1=System.currentTimeMillis();

fib1=Recursii.fibonacci(n);

time2=System.currentTimeMillis();

System.out.println("Recursiv fibonacci("+n+")="+fib1+

" durata: "+(time2-time1));

/* Calcularea iterativa a numarului lui Fibonacci */

time1=System.currentTimeMillis();

fib2=Iteratii.fibonacci(n);

time2=System.currentTimeMillis();

System.out.println("Iterativ fibonacci("+n+")="+fib2+

" durata: "+(time2-time1));

/* Calcularea numarului lui Fibonacci pentru n=35 */

n=35;

time1=System.currentTimeMillis();

fib1=Recursii.fibonacci(n);

time2=System.currentTimeMillis();

System.out.println("Recursiv fibonacci("+n+")="+fib1+

" durata: "+(time2-time1));

time1=System.currentTimeMillis();

fib2=Iteratii.fibonacci(n);

time2=System.currentTimeMillis();

System.out.println("Iterativ fibonacci("+n+")="+fib2+

" durata: "+(time2-time1));

}

catch(Exception e) {

System.out.println("Eroare in date: "+e);

}

}

}

Fişierul TestComplex.java

/* Testarea clasei Complex */

class TestComplex {

public static void main(String args[]) {

Complex u=new Complex(1,1), v=new Complex(1,-1),

w=new Complex(-1,1), z=new Complex(-1,-1);

Complex x=new Complex(1,1), y;

/* Testarea redefinirii metodei toString() din clasa Object */

System.out.println("u="+u+" v="+v);

Page 488: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

488

/* Testarea redefinirii metodei equals din clasa Object */

System.out.println("u==x: "+(u==x)+" u.equals(x): "+u.equals(x));

y=u;

System.out.println("u==y: "+(u==y)+" u.equals(y): "+u.equals(y));

System.out.println("u==v: "+(u==v)+" u.equals(v): "+u.equals(v));

/* Testarea redefinirii metodei hashCode din clasa Object */

System.out.println("Coduri de dispersie:");

System.out.println("u: "+u.hashCode()+" v: "+v.hashCode()+

" w: "+w.hashCode()+" z: "+z.hashCode());

/* Testarea metodelor care intorc re, im, modul si argument */

System.out.println("Pentru u: re="+u.real()+" im="+u.imag()+

" modul="+u.modul()+" argument="+u.arg());

System.out.println("Pentru v: re="+v.real()+" im="+v.imag()+

" modul="+v.modul()+" argument="+v.arg());

System.out.println("Pentru w: re="+w.real()+" im="+w.imag()+

" modul="+w.modul()+" argument="+w.arg());

System.out.println("Pentru z: re="+z.real()+" im="+z.imag()+

" modul="+z.modul()+" argument="+z.arg());

/* Testarea metodei statice complex */

try {

x=Complex.complex(1.0,0.5); // Se creeaza un nou numar complex

// cu modul 1 si argument 0.5

System.out.println("Noua valoare a lui x: "+x);

System.out.println("Modulul lui x: "+x.modul());

System.out.println("Argumentul lui x: "+x.arg());

y=Complex.complex(-1.0,1.2); // Gresit: modul negativ -1.0

}

catch(Exception e) {

System.out.println(e);

}

/* Operatii intre numere complexe */

Complex a=null, b=null, c=null, d=null;

y=new Complex();

try {

a=u.plus(v);

b=u.inmultitCu(v);

c=u.impartitLa(v);

d=b.minus(c);

System.out.println("a="+a+" b="+b+"\nc="+c+" d="+d);

d=u.impartitLa(y);

}

catch(Exception e) {

System.out.println("impartire complex la complex nul:");

System.out.println(e);

}

/* Operatii intre un numar complex si unul real */

try {

a=u.plus(2.5);

b=u.inmultitCu(3.0);

c=u.impartitLa(2.0);

d=u.minus(4.5);

System.out.println("a="+a+" b="+b+"\nc="+c+" d="+d);

d=u.impartitLa(0.0);

}

catch(Exception e) {

System.out.println("impartire complex la real nul:");

System.out.println(e);

Page 489: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

489

}

/* Operatii intre un numar real si unul complex */

try {

a=Complex.plus(2.5, u);

b=Complex.inmultitCu(3.0, u);

c=Complex.impartitLa(1.0,c);

d=Complex.minus(4.5,u);

System.out.println("a="+a+" b="+b+"\nc="+c+" d="+d);

d=Complex.impartitLa(1.0,y);

}

catch(Exception e) {

System.out.println("impartire real la complex nul:");

System.out.println(e);

}

try {

/* Calcularea expresiei (2*u+w-3)/v */

a=(((Complex.inmultitCu(2,u)).plus(w)).minus(3)).impartitLa(v);

System.out.println("Valoarea expresiei finale: "+a);

/* Aceeasi expresie calculata pas cu pas */

b=Complex.inmultitCu(2,u);

c=b.plus(w);

d=c.minus(3);

a=d.impartitLa(v);

System.out.println("Aceeasi valoare obtinuta pas cu pas: "+a);

}

catch(Exception e) {

System.out.println("La calcularea expresiei finale:\n"+e);

}

}

}

Fişierul Referinţe.java

/* Utilizarea constructorilor si operatorului new */

class Referinte {

public static void main(String argv[]) {

String a="un sir", b=new String(a), c, d, e;

c=new String(b);

d=b;

e=c;

System.out.println("a="+a+" b="+b+" c="+c);

System.out.println("d="+d+" e="+e);

/* Se modifica acum valoarea lui b, construind un nou obiect, si

se reafiseaza obiectele spre care fac referinte toate variabilele

*/

b=new String("alt sir");

System.out.println("Dupa atribuirea unei noi valori lui b:");

System.out.println("a="+a+" b="+b+" c="+c);

System.out.println("d="+d+" e="+e);

/* Se mai fac acum si alte atribuiri */

e=b;

a="sir nou";

c=new String(a);

Page 490: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

490

System.out.println("Dupa atribuirea de valori noi lui e, a si c:");

System.out.println("a="+a+" b="+b+" c="+c);

System.out.println("d="+d+" e="+e);

}

}

Fişierul Finalizari.java

class ProbaFinaliz {

private int a;

public ProbaFinaliz(int m) {

a=m;

System.out.println("S-a construit obiectul "+a);

}

protected void finalize() {

System.out.println("Finalizarea obiectului "+a);

}

}

class Finalizari {

public static void main(String args[]) {

ProbaFinaliz pf1=new ProbaFinaliz(1), pf2=new ProbaFinaliz(2);

pf1=null;

System.out.println("S-a anulat referinta pf1");

pf2=null;

System.out.println("S-a anulat referinta pf2");

System.out.println("Se incheie executia aplicatiei");

}

}

Capitolul 6

Fişierul Cercuri.java

/* Declararea clasei Cerc1 cu metode ale instantei */

class Cerc1 {

static final double PI=3.141592653589793;

double r;

double arie() {

return PI*r*r;

}

double circumferinta() {

return 2*PI*r;

}

}

/* Declararea clasei Cerc2 cu metode ale clasei (statice) */

Page 491: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

491

class Cerc2 {

static final double PI=3.141592653589793;

static double arie(double r) {

return PI*r*r;

}

static double circumferinta(double r) {

return 2*PI*r;

}

}

/* Aplicatia in care se utilizeaza cele doua clase de cercuri

declarate mai sus

*/

class Cercuri {

public static void main(String args[]) {

double r1=1, r2=7.32;

Cerc1 c1=new Cerc1(), c2=new Cerc1();

c1.r=r1; c2.r=r2;

System.out.println("Folosind metodele de instanta din clasa Cerc1:");

System.out.println("Pentru cercul c1: aria="+c1.arie()+

" circumferinta="+c1.circumferinta());

System.out.println("Pentru cercul c2: aria="+c2.arie()+

" circumferinta="+c2.circumferinta());

System.out.println("Folosind metodele statice din clasa Cerc2:");

System.out.println("Pentru raza r1: aria="+Cerc2.arie(r1)+

" circumferinta="+Cerc2.circumferinta(r1));

System.out.println("Pentru raza r2: aria="+Cerc2.arie(r2)+

" circumferinta="+Cerc2.circumferinta(r2));

}

}

Fişierul Cercuri1.java

/* Declararea clasei Cerc cu metode ale instantei */

class Cerc {

public static final double PI=3.141592653589793;

private double r;

public Cerc(double raza) {

r=raza;

}

public double raza() {

return r;

}

public double arie() {

return PI*r*r;

}

public double circumferinta() {

return 2*PI*r;

}

public static double arie(double r) {

Page 492: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

492

return PI*r*r;

}

public static double circumferinta(double r) {

return 2*PI*r;

}

}

/* Aplicatia in care se utilizeaza cele doua clase de cercuri

declarate mai sus

*/

class Cercuri1 {

public static void main(String args[]) {

double r1=1, r2=7.32;

/* Instantierea a doua cercuri */

Cerc c1=new Cerc(r1), c2=new Cerc(r2);

/* Utilizarea metodelor de instanta */

System.out.println("Utilizand metodele de instanta:");

System.out.println("Pentru cercul c1:\n aria="+c1.arie()+

" circumferinta="+c1.circumferinta()+" raza="+c1.raza());

System.out.println("Pentru cercul c2:\n aria="+c2.arie()+

" circumferinta="+c2.circumferinta()+" raza="+c2.raza());

System.out.println("Folosind metodele statice ale clasei Cerc:");

System.out.println("Pentru raza r1: aria="+Cerc.arie(r1)+

" circumferinta="+Cerc2.circumferinta(r1));

System.out.println("Pentru raza r2: aria="+Cerc.arie(r2)+

" circumferinta="+Cerc2.circumferinta(r2));

System.out.println("Pentru raza r=9.23 aria="+Cerc.arie(9.23)+

" circumferinta="+Cerc.circumferinta(9.23));

/* Acelasi calcul, facut calificand numele metodelor prin

referinte la instante ale clasei Cerc

*/

System.out.println("Aria cercului cu raza 9.23: "+

c1.arie(9.23)+" "+c2.arie(9.23));

}

}

Fişierul TestPers.java

/* Testarea clasei Persoana */

class TestPers {

public static void main(String args[]) {

Pers p1=new Pers("Antoniu","Vasile",1981);

Pers p2, p3, p4, p5;

String s1="Vasilescu", s2="Mihai";

p2=new Pers(s1, s2, 1980);

p3=new Pers(s1, "Ion", 1982);

System.out.println("Numele persoanei p1: "+p1.nume());

System.out.println("Prenumele persoanei p2: "+p2.prenume());

System.out.println("Anul nasterii persoanei p3: "+p3.anNastere());

}

}

Page 493: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

493

Fişierul TestExceptie.java

/* Crearea si utilizarea unei Exceptii */

class ExceptieDomeniuFactorial extends Exception {

public ExceptieDomeniuFactorial() {

super();

}

public ExceptieDomeniuFactorial(String str) {

super(str);

}

}

class Fact {

public static double factorial(int n) throws ExceptieDomeniuFactorial {

if(n<0) throw new ExceptieDomeniuFactorial();

if(n==0) return 1;

return n*factorial(n-1);

}

}

class TestExceptie {

public static void main(String args[]) {

int n;

double fact;

if(args.length==0) {

System.out.println("Nu ati dat numarul intreg n ca parametru");

System.exit(1);

}

try {

n=Integer.parseInt(args[0]);

fact=Fact.factorial(n);

System.out.println("Factorialul este "+fact);

}

catch(NumberFormatException e1) {

System.out.println("Parametrul nu are format corect de numar

intreg");

}

catch(ExceptieDomeniuFactorial e2) { // se capteaza exceptia nou

creata

System.out.println("Nu se poate calcula factorial din numar

negativ");

}

catch(Exception e) {

System.out.println("S-a produs exceptia: "+e);

}

}

}

Fişierul Persoana1.java

/* O varianta a clasei Persoana, in care campurile sunt protejate */

public class Persoana1 {

protected String nume, prenume;

protected int anNastere;

Page 494: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

494

public Persoana1() {} // Constructor fara argumente

public Persoana1(String nume, String prenume, int anNastere) {

this.nume=nume;

this.prenume=prenume;

this.anNastere=anNastere;

}

public Persoana1(Persoana1 pers) {

nume=pers.nume;

prenume=pers.prenume;

anNastere=pers.anNastere;

}

public String nume() { return nume; }

public String prenume() { return prenume; }

public int anNastere() { return anNastere; }

public int varsta(int anCurent) { return anCurent-anNastere; }

public String toString() {

return nume+" "+prenume+" "+anNastere;

}

public int hashCode() {

return nume.hashCode()+prenume.hashCode()/1000+anNastere%100;

}

}

Fişierul Student1.java

public class Student1 extends Persoana1 {

private String fac, gr;

private int anStudii;

public Student1(String nume, String prenume, int anNastere,

String facultate, int an, String grupa) {

this.nume=nume;

this.prenume=prenume;

this.anNastere=anNastere;

fac=facultate;

anStudii=an;

gr=grupa;

}

public Student1(Persoana1 pers, String facultate, int an,

String grupa) {

nume=pers.nume;

prenume=pers.prenume;

anNastere=pers.anNastere;

fac=facultate;

anStudii=an;

gr=grupa;

}

public Student1(Student1 stud) {

Page 495: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

495

super(stud.nume(), stud.prenume(), stud.anNastere());

fac=stud.fac;

anStudii=stud.anStudii;

gr=stud.gr;

}

public String facultate() { return fac; }

public int an() { return anStudii; }

public String grupa() { return gr; }

public String toString() {

return super.toString()+" fac: "+fac+" an: "+anStudii+

" grupa: "+gr;

}

}

Fişierul TestStud1.java

/* O varianta a clasei TestStud, pentru testarea claselor Persoana1

si Student1

*/

class TestStud1 {

public static void main(String args[]) {

Persoana1 p1=new Persoana1("Vasiliu","George",1981), p2;

Student1 s1=new Student1(p1, "NIE",2,"2221a"),

s2=new Student1("Ionescu","Maria", 1980, "NIE", 2, "2322b"), s3;

Object ob1, ob2, ob3;

Persoana1 tabPers[]=new Persoana1[3];

ob1=s1;

ob2=p2=s2;

ob3=p1;

System.out.println("p1="+p1);

System.out.println("s1="+s1);

System.out.println("s2="+s2);

System.out.println("ob1="+ob1);

System.out.println("p2="+p2);

System.out.println("ob2="+ob2);

System.out.println("ob3="+ob3);

System.out.println("Numele lui p1: "+p1.nume());

System.out.println("Numele lui s1: "+s1.nume());

System.out.println("Numele lui ob1: "+((Persoana1)ob1).nume());

s3=(Student1)ob2;

System.out.println("s3="+s3);

System.out.println("In anul 2000, s3 are "+s3.varsta(2000)+" ani");

System.out.println("p2.hashCode()="+p2.hashCode());

System.out.println("s1.hashCode()="+s1.hashCode());

tabPers[0]=p1; tabPers[1]=s1; tabPers[2]=s2;

System.out.println("Tabloul de persoane tabPers contine:");

System.out.println("Clasa lui p1: "+p1.getClass().getName());

System.out.println("Clasa lui ob2: "+ob2.getClass().getName());

for(int i=0; i<tabPers.length; i++)

System.out.println(tabPers[i]);

}

}

Page 496: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

496

Fişierul FiguriPlane.java

/* Clase de figuri plane */

/* Declararea unei clase abstracte */

abstract class FiguraPlana {

public abstract double perimetru(); // metoda abstracta

public abstract double arie(); // metoda abstracta

}

/* Clase concrete derivate din cea abstracta */

class Cerc extends FiguraPlana {

private double raza;

public Cerc(double raza) {

this.raza=raza;

}

public double raza() {

return raza;

}

public double perimetru() { // redefinirea metodei abstracte

return 2*Math.PI*raza;

}

public double arie() { // redefinirea metodei abstacte

return Math.PI*raza*raza;

}

public double diametru() {

return 2*raza;

}

}

class Patrat extends FiguraPlana {

private double latura;

public Patrat(double latura) {

this.latura=latura;

}

public double latura() {

return latura;

}

public double perimetru() { // redefinirea metodei abstracte

return 4*latura;

}

public double arie() { // redefinirea metodei abstracte

return latura*latura;

}

public double diagonala() {

return latura*Math.sqrt(2);

}

}

/* Aplicatie pentru testarea claselor. Mod de utilizare:

java FiguriPlane <numarRealPozitiv>

*/

class FiguriPlane {

public static void main(String args[]) {

FiguraPlana f;

Cerc c;

Patrat p;

Page 497: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

497

double a;

/* Instructiunea urmatoare nu este corecta, deoarece o clasa

abstracta

nu poate fi instantiata; daca se elimina din fata // apare eroare

la compilare

*/

// f=new FiguraPlana();

/* Se valideaza parametrul din linia de comnada */

if(args.length==0) {

System.out.println("Dati ca parametru un numar real pozitiv");

System.exit(1);

}

try {

a=Double.parseDouble(args[0]);

if(a<=0) {

System.out.println("Numarul nu este pozitiv");

System.exit(2);

}

/* Se instantiaza clasele Cerc si Patrat */

c=new Cerc(a);

p=new Patrat(a);

/* Variabilei f din clasa abstracta FiguraPlana i se poate da ca

valoare o referinta catre o subclasa instantiabila

*/

f=new Cerc(2*a);

/* Aplicarea metodelor */

System.out.println("Cerc: raza="+c.raza()+" perimetrul="+

c.perimetru()+"\naria="+c.arie()+" diametrul="+c.diametru());

System.out.println("Patrat: latura="+p.latura()+" perimetrul="+

p.perimetru()+"\naria="+p.arie()+" diagonala="+p.diagonala());

/* Daca spre un obiect din clasa Cerc indica o variabila din

superclasa FiguraPlana, este necesara conversia de clasa pentru

invocarea metodelor care nu exista in superclasa

*/

System.out.println("Al doilea cerc: raza="+((Cerc)f).raza()+

" perimetrul="+ f.perimetru()+"\naria="+f.arie()+

" diametrul="+((Cerc)f).diametru()); }

catch(NumberFormatException e1) {

System.out.println("Nu ati respectat formatul de numar real");

}

catch(Exception e) {

System.out.println("S-a produs exceptia: "+e);

}

}

}

Fişierul Integrare.java

/* Aplicatie in care se integreaza functt prin metoda trapezelor */

/* Declararea si utilizarea unor interfete */

/* Interfata pentru o clasa care ofera o functie reala de o variabila reala

*/

interface FunctieReala {

double f(double x);

}

Page 498: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

498

/* Interfata pentru o clasa care ofera o metoda de calcul al integralei

de la inf la sup a functiei f(x) din interfata FunctieReala

*/

interface Integrator {

double integrala(double inf, double sup, FunctieReala func);

}

/* O clasa care implementeaza interfata FunctieReala pentru a oferi

functia f(x)=a*sin(b*x+c)+d*cos(b*x)

*/

class Functie1 implements FunctieReala {

private double a, b, c, d; // parametrii functiei

/* Constructorul clasei introduce valorile parametrilor functiei */

public Functie1(double a, double b, double c, double d) {

this.a=a; this.b=b; this.c=c; this.d=d;

}

/* metoda de calculare a functiei, prin care se concretizeaza metoda

abstracta f(x) din interfata

*/

public double f(double x) {

return a*Math.sin(b*x+c)+d*Math.cos(b*x);

}

}

/* O clasa care implementeaza interfata Integrator, realizand integrarea

prin

metoda trapezelor a functiei f(x) cu nrPasi pasi de integrare

*/

class IntegrareTrapeze implements Integrator {

int nrPasi; // Numarul de pasi de integrare

/* Constructorul initializeaza numarul de pasi */

public IntegrareTrapeze(int nrPasi) throws Exception {

if(nrPasi<=0) throw new Exception("IntegrareTrapeze: nrPasi<=0");

this.nrPasi=nrPasi;

}

/* Metoda de modificare a numarului de pasi */

public void puneNrPasi(int nrPasi) throws Exception {

if(nrPasi<=0) throw new Exception("IntegrareTrapeze: nrPasi<=0");

this.nrPasi=nrPasi;

}

/* Implementarea metodei abstracte din interfata */

public double integrala(double inf, double sup, FunctieReala func) {

double h,s;

h=(sup-inf)/nrPasi; // pasul de integrare

s=0; // initializarea sumei ordonatelor

for(int i=1; i<nrPasi; i++) s+=func.f(inf+i*h);

return ((func.f(inf)+func.f(sup))/2+s)*h;

}

}

/* O aplicatie in care se utilizeaza clasele si interfetele declarate aici

Utilizare:

java Integrare inf sup nrPasi

unde:

inf - marginea inferioara a intervalului de integrare (numar real)

sup - marginea superioara a intervalului de integrare (numar real)

nrPasi - numarul de pasi de integrare (numar intreg pozitiv)

*/

Page 499: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

499

class Integrare {

public static void main(String args[]) {

IntegrareTrapeze inTrap;

FunctieReala f1, f2;

double inf, sup; // marginile intervalului de integrare

int nrPasi; // numarul de pasi de integrare

if(args.length<3) {

System.out.println("Utilizare: java Integrare inf sup nrPasi");

System.exit(1);

}

try {

inf=Double.parseDouble(args[0]);

sup=Double.parseDouble(args[1]);

nrPasi=Integer.parseInt(args[2]);

f1=new Functie1(2.73, 0.15, -0.21, 2.45);

f2=new Functie1(-3.527, -0.43, 0.16, 1.03);

inTrap=new IntegrareTrapeze(nrPasi);

System.out.println("Prima integrala:

"+inTrap.integrala(inf,sup,f1));

System.out.println("A doua integrala:

"+inTrap.integrala(inf,sup,f2));

inTrap.puneNrPasi(2*nrPasi);

System.out.println("Dupa dublarea numarului de pasi de

integrare:");

System.out.println("Prima integrala:

"+inTrap.integrala(inf,sup,f1));

System.out.println("A doua integrala:

"+inTrap.integrala(inf,sup,f2));

}

catch(NumberFormatException e1) {

System.out.println("Nu ati introdus corect parametrii

aplicatiei");

}

catch(Exception e) {

System.out.println("S-a produs exceptia: "+e);

}

}

}

Fişierul Integrare1.java

/* O varianta a aplicatiei din fisierul Integrare.java, in care

se folosesc clase imbricate si interioare

*/

/* Declararea si utilizarea unor interfete */

/* Interfata pentru o clasa care ofera o functie reala de o variabila reala

*/

interface FunctieReala {

double f(double x);

}

/* Interfata pentru o clasa care ofera o metoda de calcul al integralei

de la inf la sup a functiei f(x) din interfata FunctieReala

*/

Page 500: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

500

interface Integrator {

double integrala(double inf, double sup, FunctieReala func);

}

/* O clasa care implementeaza interfata Integrator, realizand integrarea

prin

metoda trapezelor a functiei f(x) cu nrPasi pasi de integrare

*/

class IntegrareTrapeze implements Integrator {

int nrPasi; // Numarul de pasi de integrare

/* Constructorul initializeaza numarul de pasi */

public IntegrareTrapeze(int nrPasi) throws Exception {

if(nrPasi<=0) throw new Exception("IntegrareTrapeze: nrPasi<=0");

this.nrPasi=nrPasi;

}

/* Metoda de modificare a numarului de pasi */

public void puneNrPasi(int nrPasi) throws Exception {

if(nrPasi<=0) throw new Exception("IntegrareTrapeze: nrPasi<=0");

this.nrPasi=nrPasi;

}

/* Implementarea metodei abstracte din interfata */

public double integrala(double inf, double sup, FunctieReala func) {

double h,s;

h=(sup-inf)/nrPasi; // pasul de integrare

s=0; // initializarea sumei ordonatelor

for(int i=1; i<nrPasi; i++) s+=func.f(inf+i*h);

return ((func.f(inf)+func.f(sup))/2+s)*h;

}

}

/* O aplicatie in care se utilizeaza clasele si interfetele declarate aici

Utilizare:

java Integrare inf sup nrPasi

unde:

inf - marginea inferioara a intervalului de integrare (numar real)

sup - marginea superioara a intervalului de integrare (numar real)

nrPasi - numarul de pasi de integrare (numar intreg pozitiv)

*/

class Integrare1 {

public static void main(String args[]) {

Integrare1 int1=new Integrare1();// Instanta a acestei aplicatii

// necesara la utilizarea claselor interioare

IntegrareTrapeze inTrap;

FunctieReala f1, f2;

double inf, sup; // marginile intervalului de integrare

int nrPasi; // numarul de pasi de integrare

if(args.length<3) {

System.out.println("Utilizare: java Integrare inf sup nrPasi");

System.exit(1);

}

try {

inf=Double.parseDouble(args[0]);

sup=Double.parseDouble(args[1]);

nrPasi=Integer.parseInt(args[2]);

f1=int1.new Functie1(2.73, 0.15, -0.21, 2.45);

f2=int1.new Functie1(0.46, -1.23, 1.4, -0.78);

inTrap=new IntegrareTrapeze(nrPasi);

System.out.println("Prima integrala:

"+inTrap.integrala(inf,sup,f1));

Page 501: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

501

System.out.println("A doua integrala: "+

inTrap.integrala(inf,sup,f2));

inTrap.puneNrPasi(2*nrPasi);

System.out.println("Dupa dublarea numarului de pasi de

integrare:");

System.out.println("Prima integrala:

"+inTrap.integrala(inf,sup,f1));

System.out.println("A doua integrala:

"+inTrap.integrala(inf,sup,f2));

/* Utilizarea clasei incuibate statice Functie2 */

Functie2 func2=new Functie2(1,-5,6);

System.out.println("func2.f(sup)="+func2.f(sup));

System.out.println("Functie2.f1(inf,sup)="+Functie2.f1(inf,sup));

System.out.println("Integrala din Functie2.f(x)="+

inTrap.integrala(inf,sup,func2));

}

catch(NumberFormatException e1) {

System.out.println("Nu ati introdus corect parametrii

aplicatiei");

}

catch(Exception e) {

System.out.println("S-a produs exceptia: "+e);

}

}

/* O clasa interioara care implementeaza interfata FunctieReala pentru a

oferi functia f(x)=a*sin(b*x+c)+d*cos(b*x)

*/

class Functie1 implements FunctieReala {

private double a, b, c, d; // parametrii functiei

/* Constructorul clasei introduce valorile parametrilor functiei */

public Functie1(double a, double b, double c, double d) {

this.a=a; this.b=b; this.c=c; this.d=d;

}

/* metoda de calculare a functiei, prin care se concretizeaza metoda

abstracta f(x) din interfata

*/

public double f(double x) {

return a*Math.sin(b*x+c)+d*Math.cos(b*x);

}

}

/* O clasa incuibata statica */

static class Functie2 implements FunctieReala {

private double a, b, c;

public Functie2(double a, double b, double c) {

this.a=a; this.b=b; this.c=c;

}

public double f(double x) {

return (a*x+b)*x+c;

}

public void puneParam(double a, double b, double c) {

this.a=a; this.b=b; this.c=c;

}

public static double f1(double x, double y) {

return 2*x*x+3*y;

}

}

}

Page 502: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

502

Capitolul 7

Toate fişierele sunt conţinute în capitolul 7 al lucrării.

Capitolul 8

Toate fişierele sunt conţinute în capitolul 8 al lucrării.

Capitolul 9

Fişierul TestRGB.java

/* Alegerea culorilor in sistemul RGB (Red, Green, Blue) */

import java.awt.*;

import java.awt.event.*;

import javax.swing.*;

import javax.swing.event.*;

class TestRGB {

static AF af=new AF();

static IUG iug=new IUG("Alegerea culorii in sistemul RGB"+

" (Red, Green, Blue)");

/* clasa imbricata pentru interfata utilizator grafica */

static class IUG extends JFrame {

AjustCuloare red, green, blue; // rigle de ajustare a culorilor

Box box1; // caseta riglelor de ajustare

JPanel panouCuloare; // panoul pe care se prezinta culoarea

Color culoare; // culoarea panoului panouCuloare

IUG(String titlu) { // constructorul clasei IUG

super(titlu);

setSize(500, 200);

setLocation(100, 50);

Container cp=getContentPane();

addWindowListener(af); // adaugarea ascultatorului de fereastra

/* Se creeaza caseta cu dispozitive de ajustare */

box1=Box.createVerticalBox();

red=new AjustCuloare("Rosu "); // ajustare rosu

box1.add(red);

green=new AjustCuloare("Verde "); // ajustare verde

box1.add(green);

blue=new AjustCuloare("Albastru "); // ajustare albastru

blue.ajustare.setPaintLabels(true);

box1.add(blue);

cp.add(box1, BorderLayout.WEST);

panouCuloare=new JPanel(); // crearea panoului pentru culoare

cp.add(panouCuloare, BorderLayout.CENTER);

puneCuloarea(); // se pune culoarea initiala

setVisible(true);

Page 503: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

503

}

/* Metoda de determinare a culorii RGB */

void puneCuloarea() {

culoare=new Color(red.val, green.val, blue.val);

panouCuloare.setBackground(culoare);

}

}

/* Un "dispozitiv" de ajustare a valorii unei culori */

static class AjustCuloare extends Box implements ChangeListener {

JTextField valoare; // camp pentru afisarea valorii HSB

JSlider ajustare; // rigla de ajustare a valorii

int val=0; // valoarea RGB in intervalul 0,..,255

AjustCuloare(String culoare) {

super(BoxLayout.X_AXIS);

add(new JLabel(culoare));

add(Box.createHorizontalGlue());

ajustare=new JSlider(JSlider.HORIZONTAL, 0, 255, 0);

ajustare.setMajorTickSpacing(50);

ajustare.setMinorTickSpacing(10);

ajustare.setPaintTicks(true);

ajustare.addChangeListener(this);

add(ajustare);

add(Box.createHorizontalStrut(5));

valoare=new JTextField("0",4);

valoare.setHorizontalAlignment(JTextField.RIGHT);

valoare.setEditable(false);

valoare.setBackground(Color.white);

valoare.setMaximumSize(valoare.getMinimumSize());

add(valoare);

add(Box.createHorizontalStrut(5));

}

/* metoda de ascultare a deplasarii cursorului riglei */

public void stateChanged(ChangeEvent e) {

val=ajustare.getValue(); // determinarea valorii culorii

valoare.setText(" "+val); // afisarea valorii

iug.puneCuloarea(); // modificarea culorii panoului

}

}

/* Clasa ascultatoare de fereastra */

static class AF extends WindowAdapter {

public void windowClosing(WindowEvent e) {

System.exit(0); // incheierea executarii aplicatiei

}

}

/* Metoda principala a aplicatiei */

public static void main(String args[]) {

}

}

Page 504: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

504

Capitolul 10

Fişierul DouaTexte.java

import java.awt.*;

import java.awt.event.*;

import java.applet.*;

public class DouaTexte extends Applet {

Button b=new Button("Buton pentru schimbare text");

Label lab=new Label("Textul initial");

String text1, text2;

Actiune act=new Actiune();

int k=2;

public void init() {

text1=getParameter("textul1");

text2=getParameter("textul2");

setLayout(new GridLayout(2,1));

add(b);

add(lab);

setBackground(Color.cyan);

b.addActionListener(act);

b.setBackground(Color.magenta);

setVisible(true);

}

class Actiune implements ActionListener {

public void actionPerformed(ActionEvent e) {

k++;

if(k>2) k=1;

if(k==1) {

lab.setText(text1);

lab.setBackground(Color.blue);

lab.setForeground(Color.yellow);

} else {

lab.setText(text2);

lab.setBackground(Color.green);

lab.setForeground(Color.black);

}

setVisible(true);

}

}

}

Fişierul PrimApplet.java

/* Un prim applet */

import java.awt.*;

import java.applet.*;

public class PrimApplet extends Applet {

public void paint(Graphics g) {

Page 505: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

505

g.drawString("Primul nostru applet", 5,50);

}

}

Fişierul PrimApplet.html

<html>

<head>

<title> Primul nostru applet </title>

</head>

<body>

<applet CODE="PrimApplet" WIDTH=200 HEIGHT=100>

Primul nostru applet

</applet>

</body>

</html>

Fişierul CBGroupAp.java

/* Applet prin care se testeaza clasele Checkbox si CheckboxGroup. Appletul

contine trei casete ("butoane radio") si o instanta a clasei Label in

care

se afiseaza eticheta casetei selectate in momentul respectiv */

import java.awt.*;

import java.awt.event.*;

import java.applet.*;

/* Appletul propriu-zis. Se construiesc obiectele grafice: casetele de

validare ("butoanele radio") cb1, cb2, cb3 si eticheta lab. Casetele

sunt

toate afectate grupului cbgr construit in prealabil. Se construieste, de

asemenea, obiectul ecb care intercepteaza si trateaza evenimentele

generate de casetele de validare. Interceptorul ecb este inregistrat sa

asculte evenimentele generate de casetele de validare. Constructorul

interceptorului primeste ca argumente referinte la grupul de casete si

la o

eticheta unde se va afisa eticheta casetei curenta a acestei casete.

*/

public class CBGroupAp extends Applet {

CheckboxGroup cbgr=new CheckboxGroup();

Checkbox cb1=new Checkbox("CB1", false, cbgr),

cb2=new Checkbox("CB2", true,cbgr),

cb3=new Checkbox("CB3", false, cbgr);

Label lab=new Label();

EvCheckboxGroup ecb=new EvCheckboxGroup();

public void init() {

cb1.addItemListener(ecb);

cb2.addItemListener(ecb);

cb3.addItemListener(ecb);

cb1.setBackground(Color.cyan);

cb2.setBackground(Color.cyan);

Page 506: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

506

cb3.setBackground(Color.cyan);

lab.setBackground(Color.green);

lab.setAlignment(Label.CENTER);

setLayout(new BorderLayout());

add("North",lab);

add("West",cb1);

add("Center",cb2);

add("East",cb3);

setVisible(true);

}

/* Clasa imbricata EvCheckboxGroup implementeaza interfata

ItemtListener.

Instantele ei intercepteaza evenimentele de comutare generate de

Checkbox

si introduc in eticheta din applet starea preluata, atunci cand ea se

modifica

*/

class EvCheckboxGroup implements ItemListener {

public void itemStateChanged(ItemEvent e) {

Checkbox cb=cbgr.getSelectedCheckbox();

lab.setText("S-a selectat caseta: "+cb.getLabel());

}

}

}

Fişierul CBGroupAp.html

<html>

<head>

<title> Testarea claselor Checkbox si ChecboxGroup </title>

</head>

<body>

<applet CODE="CBGroupAp" WIDTH=180 HEIGHT=80>

Testarea claselor Checkbox si CheckboxGroup

</applet>

</body>

</html>

Fişierul TestFlowAp.java

/* Aplet de testare a gestionarului de pozitionare FlowLayout.

In cadru exista 2 butoane de comanda: Pune si Elimina. Exista, de

asemenea,

un grup de 3 casete de validare (butoane radio): Stanga, Centru,

Dreapta. La

fiecare apasare pe butonul "Pune", pe suprafata appletului se mai pune o

eticheta, iar la apasarea pe butonul "Elimina" , se elimina ultima

eticheta din applet. Apasarea pe oricare din cele trei butoane radio

comanda alinierea corespunzatoare.Se admit cel mult 20 etichete

Page 507: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

507

*/

import java.awt.*;

import java.awt.event.*;

import java.applet.*;

public class TestFlowAp extends Applet {

Label tlab[]=new Label[20];

FlowLayout fl=new FlowLayout();

public void init() {

/* Construirea obiectelor grafice */

Button pune=new Button("Pune");

Button elimina=new Button("Elimina");

CheckboxGroup cbg=new CheckboxGroup();

Checkbox stanga=new Checkbox("Stanga", false, cbg);

Checkbox centru=new Checkbox("Centru", true, cbg);

Checkbox dreapta=new Checkbox("Dreapta", false, cbg);

/* Construirea interceptoarelor de evenimente */

ApasButon ab=new ApasButon(this);

SelectAlin sa=new SelectAlin(this);

/* Construirea celor 20 etichete si setarea culorii de fond */

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

tlab[i]=new Label("Eticheta nr. "+(i+1));

tlab[i].setBackground(Color.cyan);

}

/* Adaugarea la componente a interceptoarelor de evenimente si

setarea culorii de fond a fiecarii componente

*/

setBackground(Color.yellow);

pune.addActionListener(ab);

pune.setBackground(Color.magenta);

elimina.addActionListener(ab);

elimina.setBackground(Color.magenta);

stanga.addItemListener(sa);

stanga.setBackground(Color.green);

centru.addItemListener(sa);

centru.setBackground(Color.green);

dreapta.addItemListener(sa);

dreapta.setBackground(Color.green);

/* Stabilirea dimensiunii ferestrei si a gestionarului de pozitionare

folosit

*/

setLayout(fl);

/* Adaugarea la fereastra principala a componentelor si vizualizarea

*/

add(pune);

add(elimina);

add(stanga);

add(centru);

add(dreapta);

setVisible(true);

}

/* Clasa care intercepteaza si trateaza evenimentele generate de butoane

*/

static class ApasButon implements ActionListener {

TestFlowAp ap;

int contor;

Page 508: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

508

ApasButon(TestFlowAp ap) {

this.ap=ap;

contor=0;

}

public void actionPerformed(ActionEvent e) {

String actiune=e.getActionCommand();

if(actiune.equals("Pune") && contor<20){

ap.add(ap.tlab[contor]);

contor++;

}

else if(actiune.equals("Elimina") && contor>0) {

contor--;

ap.remove(ap.tlab[contor]);

}

ap.fl.layoutContainer(ap);

ap.setVisible(true);

}

}

/* Clasa care intercepteaza si trateaza evenimentele generate de cele

trei butoane radio

*/

static class SelectAlin implements ItemListener {

TestFlowAp ap;

SelectAlin(TestFlowAp ap) {

this.ap=ap;

}

public void itemStateChanged(ItemEvent e) {

/* Se determina ce buton radio este selectat si ce eticheta are */

Checkbox cb=(Checkbox)e.getItemSelectable();

String cblab=cb.getLabel();

/* Se seteaza alinierea corespunzatoare etichetei butonului radio

selectat

*/

if(cblab.equals("Stanga"))

ap.fl.setAlignment(FlowLayout.LEFT);

else if(cblab.equals("Centru"))

ap.fl.setAlignment(FlowLayout.CENTER);

else if(cblab.equals("Dreapta"))

ap.fl.setAlignment(FlowLayout.RIGHT);

/* Se efectueaza alinierea componentelor din container */

ap.fl.layoutContainer(ap);

ap.setVisible(true);

}

}

}

Fişierul TestFlow.html

<html>

<head>

<title> Testarea clasei FlowLayout </title>

</head>

<body>

<applet CODE="TestFlowAp" WIDTH=400 HEIGHT=250>

Testare FlowLayout

</applet>

Page 509: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

509

</body>

</html>

Capitolul 11

Fişierul TestFile.java

import java.io.*;

class TestFile {

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

/* Fisier situat in directorul curent */

File fis1=new File("TestFile.java");

System.out.println("Calea absoluta: "+fis1.getAbsolutePath());

System.out.println("Fisierul exista: "+fis1.exists());

System.out.println("Pot citi fisier: "+fis1.canRead());

System.out.println("Pot scrie in fisier: "+fis1.canWrite());

System.out.println("Calea: "+fis1.getPath());

System.out.println("Parintele: "+fis1.getParent());

System.out.println("Este director: "+fis1.isDirectory());

System.out.println("Este fisier: "+fis1.isFile());

System.out.println("Ultima modificare: "+fis1.lastModified());

System.out.println("Lungimea fisierului: "+fis1.length());

System.out.println("Sub foorma de URL: "+fis1.toURL());

/* Director */

File dir1=new File("../surse");

System.out.println("Calea absoluta: "+dir1.getAbsolutePath());

System.out.println("Exista: "+dir1.exists());

System.out.println("Este director: "+dir1.isDirectory());

System.out.println("Se poate citi: "+dir1.canRead());

System.out.println("Se poate scrie: "+dir1.canWrite());

/* Fisier situat in alt director */

File fis2=new File("../surse/TestStudent.java");

System.out.println("Calea absoluta: "+fis2.getAbsolutePath());

System.out.println("Exista: "+fis2.exists());

System.out.println("Este director: "+fis2.isDirectory());

System.out.println("Se poate citi: "+fis2.canRead());

System.out.println("Se poate scrie: "+fis2.canWrite());

System.out.println("Parintele: "+fis2.getParent());

}

}

Fişierul TestFileInput.java

/* Testarea clasei FileInputStream

La lansarea in executie, se da ca parametru in linia de comanda numele

unui fisier de text care va fi citit

*/

import java.io.*;

class TestFileInput {

public static void main(String args[]) {

byte b[]=new byte[30];

Page 510: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

510

int n, n1;

long n2;

File fisier=null;

if(args.length==0) {

System.out.println("La lansarea in executie trebuie dat ca "+

"parametru numele unui fisier de text");

System.exit(0);

}

else {

fisier=new File(args[0]);

if(!fisier.exists()) {

System.out.println("Fisierul "+fisier+" nu exista!");

System.exit(0);

}

}

try {

/* Se deschide fisierul dat ca parametru si se conecteaza la

fluxul de intrare f1 */

FileInputStream f1=new FileInputStream(fisier);

System.out.println("S-a deschis fisierul "+fisier+

" conectat la fluxul f1");

System.out.println("Sunt disponibili "+f1.available()+

" octeti");

n1=f1.read();

System.out.println("Primul octet citit este "+n1+

" care este codul ASCII al caracterului "+(char)n1);

n2=f1.skip(3);

System.out.println("S-a sarit peste "+n2+" octeti");

n=f1.read(b);

System.out.println("S-au mai citit urmatorii "+n+" octeti:");

for(int i=0; i<n; i++) System.out.print(b[i]+" ");

System.out.println();

System.out.println("care sunt codurile ASCII ale urmatoarelor "+

" caractere:");

for(int i=0; i<n; i++) System.out.print((char)b[i]);

System.out.println();

System.out.println("In fluxul de intrare mai sunt disponibili "+

f1.available()+" octeti");

/* Descriptorul fluxului f1 este folosit pentru deschiderea

unui nou flux de intrare, f2. Acum fluxurile f1 si f2 sunt

conectate la acelasi fisier de intrare

*/

FileDescriptor fd=f1.getFD();

FileInputStream f2=new FileInputStream(fd);

System.out.println("S-a deschis fluxul f2, identic cu f1");

System.out.println("In fluxul f2 sunt disponibili "+

f2.available()+" octeti");

n2=f2.read(b,0,15);

System.out.println("S-au citit din f2 urmatorii "+n+" octeti:");

for(int i=0; i<n; i++) System.out.print((char)b[i]);

System.out.println();

System.out.println("In f1 sunt disponibili "+f1.available()+

" octeti, iar in f2 "+f2.available()+" octeti");

f2.close();

/* S-a inchis fisierul indicat de fluxul f2. In consecinta

nu mai pot fi folosite nici unul din fluxurile f2 si f1,

care au ca sursa acest fisier

*/

System.out.println("S-a inchis fisierul "+fisier);

/* Se deschide un nou flux de intrare, avand acelasi descriptor

Page 511: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

511

cu intrarea standard System.in, deci datele vor fi citite de

la tastatura

*/

f1=new FileInputStream(FileDescriptor.in);

System.out.println("Introduceti de la tastatura un sir de "+

"cel putin 10 caractere");

n=f1.read(b,0,10);

System.out.print("Caracterele citite de la tastatura: ");

for(int i=0; i<n; i++) System.out.print((char)b[i]);

System.out.println();

}

catch(Exception e) {

System.out.println(e);

}

}

}

Fişierul TestFileReader.java

import java.io.*;

class TestFileReader {

public static void main(String args[]) {

try {

/* Se deschide fisierul si se citeste caracter cu caracter */

FileReader fin=new FileReader("TextProba.txt");

System.out.println("Numele canonic al codificarii textului: "+

fin.getEncoding());

int c;

while(fin.ready()) {

c=fin.read();

System.out.print((char)c);

}

System.out.println();

fin.close();

/* Se redeschide fisierul si se citeste intr-un singur tablou

de caractere

*/

fin=new FileReader("TextProba.txt");

char[] tab=new char[80];

int nrCar;

nrCar=fin.read(tab);

System.out.println("Numar caractere citite: "+nrCar);

for (int i=0; i<nrCar; i++) System.out.print(tab[i]);

System.out.println();

fin.close();

/* Se redeschide fisierul si se citeste pe portiuni, folosind

un tablou de lungime mai mica decat numarul de caractere

din fisier

*/

tab=new char[12];

fin=new FileReader("TextProba.txt");

while(fin.ready()) {

nrCar=fin.read(tab);

for(int i=0; i<nrCar; i++) System.out.print(tab[i]);

}

System.out.println();

fin.close();

}

Page 512: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

512

catch(Exception e) {

System.out.println(e);

}

}

}

Fişierul TestFileOutput.java

/* Testarea clasei FileOutputStream.

La lansarea in executie a programului se da un text oarecare in

linia de comanda (sub forma java FileOutput <text>). Acest text va

fi scris intr-un fisier cu numele "ProbaScriere.txt". Dupa ce se

inchide fisierul, se redeschide pentru citire si se afiseaza pe

ecran. Apoi se inchide si se redeschide pentru adaugare in coada.

Se inchide si se redeschide pentru a citi si afisa noul continut

*/

import java.io.*;

class TestFileOutput {

public static void main(String args[]) {

FileOutputStream fout;

FileInputStream fin;

byte b[];

int k;

if(args.length==0) {

System.out.println("La lansare dati un text in linia de comanda");

System.exit(0);

}

try {

/* Se deschide fisierul pentru scriere */

fout=new FileOutputStream("ProbaScriere.txt");

for(int i=0; i<args.length; i++) {

/* parametrul args[i] se converteste in tablou de octeti */

b=(args[i]+" ").getBytes();

/* tabloul b astfel obtinut se scrie in fisier */

fout.write(b);

}

fout.close();

/* Dupa ce a fost inchis, acelasi fisier se deschide pentru citire

*/

fin=new FileInputStream("ProbaScriere.txt");

/* Se afiseaza continutul fisierului */

System.out.println("Fisierul contine:");

while((k=fin.read()) != -1) System.out.print((char)k);

System.out.println();

fin.close();

/* Se redeschide fisierul pentru scriere prin adaugare la coada */

fout=new FileOutputStream("ProbaScriere.txt",true);

/* Se scrie textul "\nText adaugat\n" */

fout.write(("\nText adaugat\n").getBytes());

fout.close();

/* Se deschide din nou fisierul pentru citire si se afiseaza.

De data aceasta, fin este fisierul din care se citeste, iar

fout este un nou flux de iesire, care se conecteaza la

iesirea standard al sistemului (la ecran) prin intermediul

descriptorului FileDescriptor.out

*/

fin=new FileInputStream("ProbaScriere.txt");

Page 513: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

513

fout=new FileOutputStream(FileDescriptor.out);

fout.write("\nA doua oara fisierul contine:\n".getBytes());

while((k=fin.read()) != -1) fout.write((byte)k);

fout.write('\n');

/* // Pentru comparatie, sub forma de comentariu se da

// programul de afisare obisnuit

System.out.println("\nA doua oara fisierul contine:");

while((k=fin.read()) != -1) System.out.print((char)k);

System.out.println();

*/

fin.close();

}

catch(Exception e) {

System.out.println("Exceptie: "+e);

}

}

}

Fişierul TestFileWriter.java

/* Testarea clasei FileWriter.

La lansarea in executie a programului se da un text oarecare in

linia de comanda (sub forma java FileWriter <text>). Acest text va

fi scris intr-un fisier cu numele "ProbaScriere.txt". Dupa ce se

inchide fisierul, se redeschide pentru citire si se afiseaza pe

ecran. Apoi se inchide si se redeschide pentru adaugare in coada.

Se inchide si se redeschide pentru a citi si afisa noul continut

*/

import java.io.*;

class TestFileWriter {

public static void main(String args[]) {

FileWriter fout;

FileReader fin;

String str;

int k;

if(args.length==0) {

System.out.println("La lansare dati un text in linia de comanda");

System.exit(0);

}

try {

/* Se deschide fisierul pentru scriere */

fout=new FileWriter("ProbaScriere.txt");

for(int i=0; i<args.length; i++) {

fout.write(args[i]);

fout.write(' ');

}

fout.close();

/* Dupa ce a fost inchis, acelasi fisier se deschide pentru citire

*/

fin=new FileReader("ProbaScriere.txt");

/* Se afiseaza continutul fisierului */

System.out.println("Fisierul contine:");

while((k=fin.read()) != -1) System.out.print((char)k);

System.out.println();

fin.close();

/* Se redeschide fisierul pentru scriere prin adaugare la coada */

fout=new FileWriter("ProbaScriere.txt",true);

Page 514: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

514

/* Se scrie textul "\nText adaugat\n" */

str="\nText adaugat\n";

fout.write(str);

fout.close();

/* Se deschide din nou fisierul pentru citire si se afiseaza.

De data aceasta, fin este fisierul din care se citeste, iar

fout este un nou flux de iesire, care se conecteaza la

iesirea standard al sistemului (la ecran) prin intermediul

descriptorului FileDescriptor.out

*/

fin=new FileReader("ProbaScriere.txt");

System.out.println("\nA doua oara fisierul contine:");

while((k=fin.read()) != -1) System.out.print((char)k);

System.out.println();

fin.close();

}

catch(Exception e) {

System.out.println("Exceptie: "+e);

}

}

}

Fişierul AccesDirect.java

/* Crearea si utilizarea unui fisier cu acces direct */

import java.io.*;

class AccesDirect {

public static void main(String args[]) throws IOException {

/* Se deschide fisierul cu acces direct "Proba.fad"

in mod "rw" (citire si scriere)

*/

RandomAccessFile fisier=new RandomAccessFile("Proba.fad","rw");

long fp, fp1, fp2, k;

int i;

char c;

float f;

double d;

String s;

fp=fisier.getFilePointer();

System.out.println("Pozitia initiala a cursorului: "+fp);

/* Se scriu date in fisier incepand de la pozitia 0 */

fisier.writeInt(-176534);

fisier.writeDouble(176.5832987306);

fisier.writeChar('#');

fisier.writeUTF("Primul sir");

/* Se memoreaza si se afiseaza pozitia curenta a cursorului de

fisier

*/

fp1=fisier.getFilePointer();

System.out.println("Pozitia cursorului dupa prima scriere: "+fp1);

/* Se scriu in continuare date in fisier */

fisier.writeLong(157832490245L);

fisier.writeFloat(0.05682369543f);

fisier.writeBytes("Al doilea sir\n");

fp2=fisier.getFilePointer();

System.out.println("Pozitia cursorului dupa a doua scriere: "+fp2);

/* Se deplaseaza cursorul de fisier pe pozitia de la care a inceput

Page 515: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

515

scrierea celei de a doua serii si se citesc datele in ordinea

si sub forma in care au fost scrise, apoi se afiseaza

*/

fisier.seek(fp1);

k=fisier.readLong();

f=fisier.readFloat();

s=fisier.readLine();

System.out.println("Date citite incepand de la pozitia: "+fp1);

System.out.println(k+" "+f+" "+s);

/* Se pozitioneaza cursorul la inceputul fisierului si se

citesc datele scrise in prima serie, apoi se afiseaza

*/

fisier.seek(0);

i=fisier.readInt();

d=fisier.readDouble();

c=fisier.readChar();

s=fisier.readUTF();

System.out.println("Date citite incepand de la pozitia 0:");

System.out.println(i+" "+d+" "+c+" "+s);

/* Se inchide fisierul */

fisier.close();

/* Se redeschide fisierul, se deplaseaza cursorul in pozitia

de la care a inceput scrierea celei de a doua serii de date,

se citesc datele respective si se afiseaza

*/

fisier=new RandomAccessFile("Proba.fad","r");

fisier.seek(fp1);

System.out.println("Dupa redeschiderea fisierului s-au citit:");

System.out.println(fisier.readLong()+" "+fisier.readFloat()+" "+

fisier.readLine());

/* Se inchide fisierul */

fisier.close();

}

}

Fişierul FisierDate.java

/* Testarea claselor DataOutputStream si DataInputStream.

Scrierea datelor se face intr-un fisier, folosind un

FileOutputStream conectat la iesirea unui DataOutputStream.

Citirea datelor se face apoi din acelasi fisier, folosind un

DataInputStream conectat la iesirea unui FileInputStream.

*/

import java.io.*;

class FisierDate {

public static void main(String args[]) throws IOException {

/* Datele care vor fi scrise in fisier */

byte b=67;

char c='A';

boolean t=true, f=false;

short sh=10723;

int i=958716;

long k=847543218045433L;

float fl=95.01462f;

double d=3.2607643218765;

String str="ABCDabcd";

Page 516: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

516

/* Deschiderea fisierului pentru scrierea datelor */

FileOutputStream fout=new FileOutputStream("Proba.dat");

DataOutputStream dout=new DataOutputStream(fout); // acest flux

// de date este conectat la iesire la fluxul de scriere

// in fisier fout deschis anterior

/* Scrierea datelor in fisier */

dout.writeByte(b); // Se scrie ub octet

dout.writeChar(c); // Se scrie un caracter

dout.writeBoolean(t); dout.writeBoolean(f); // Se scriu valori logice

dout.writeShort(sh); // Se scrie un short

dout.writeInt(i); // se scrie un int

dout.writeLong(k); // se scrie un long

dout.writeFloat(fl); // se scrie un float

dout.writeDouble(d); // se scrie un double

dout.writeUTF(str); // se scrie un sir de opt caractere in

// format UTF

/* Inchiderea fluxului de iesire */

dout.close();

/* Deschiderea fisierului pentru a citi datele scrise anterior */

FileInputStream fin=new FileInputStream("Proba.dat");

DataInputStream din=new DataInputStream(fin); // Fluxul de citire

// date este conectat la iesirea fluxului de citire din fisier

// fin deschis anterior

/* Citirea datelor se face in aceeasi ordine in care au fost

scrise

*/

byte b1=din.readByte(); // Se citeste ub octet

char c1=din.readChar(); // Se citeste un caracter

boolean t1=din.readBoolean(),

f1=din.readBoolean(); // Se citesc valori logice

short sh1=din.readShort(); // Se citeste un short

int i1=din.readInt(); // se citeste un int

long k1=din.readLong(); // se citeste un long

float fl1=din.readFloat(); // se citeste un float

double d1=din.readDouble(); // se citeste un double

String str1=din.readUTF(); // se citeste un sir in format UTF

/* Afisarea pe ecran a perechilor de date scrise si citite */

System.out.println("Datele scrise in fisier si cele citite");

System.out.println("byte: "+b+" "+b1);

System.out.println("char: "+c+" "+c1);

System.out.println("boolean: "+t+" "+t1+"\n"+f+" "+f1);

System.out.println("short: "+sh+" "+sh1);

System.out.println("int: "+i+" "+i1);

System.out.println("long: "+k+" "+k1);

System.out.println("float: "+fl+" "+fl1);

System.out.println("double: "+d+" "+d1);

System.out.println("UTF: "+str+" "+str1);

/* Inchiderea fluxului de intrare */

din.close();

}

}

Fişierul FisierObiecte.java

/* Testarea claselor ObjectOutputStream si ObjectInputStream.

Scrierea datelor se face intr-un fisier, folosind un

FileOutputStream conectat la iesirea unui ObjectOutputStream.

Citirea datelor se face apoi din acelasi fisier, folosind un

Page 517: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

517

ObjectInputStream conectat la iesirea unui FileInputStream.

*/

import java.io.*;

class FisierObiecte {

static class Persoana implements Serializable {

String nume;

int anNastere;

Persoana(String nume, int anNastere) {

this.nume=nume; this.anNastere=anNastere;

}

public String toString() {

return "[Persoana: "+nume+" an nastere: "+anNastere+"]";

}

}

static class Student extends Persoana implements Serializable {

int anStudii;

String grupa;

Student(String nume, int anNastere, int anStudii, String grupa) {

super(nume, anNastere);

this.anStudii=anStudii;

this.grupa=grupa;

}

public String toString() {

return "Student: "+nume+" an studii: "+anStudii+" grupa: "+

grupa+"]";

}

}

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

/* Datele care vor fi scrise in fisier */

Persoana pers1=new Persoana("Popescu Vasile", 1978),

pers2=new Persoana("Vasiliu Mihaela", 1981);

Student stud1=new Student("Petrescu Mihai", 1979, 2, "2221a"),

stud2=new Student("Craciun Nelu", 1979, 2, "2321b");

int i=1325479;

double d=3.76523476512;

String str="Exemplu de sir";

int tabInt[]={12, -13, 21, 467823, -12643218};

String tabstr[]={"alpha", "beta", "gamma"};

double w[][]={{3.76521, 1.0256789e-4}, {-0.3709865, 12e7, 1e-9}};

/* Deschiderea fisierului pentru scrierea datelor */

FileOutputStream fout=new FileOutputStream("Proba1.dat");

ObjectOutputStream dout=new ObjectOutputStream(fout); // acest flux

// de obiecte este conectat la iesire la fluxul de scriere

// in fisier fout deschis anterior

/* Scrierea obiectelor in fisier */

dout.writeObject(pers1);

dout.writeObject(stud1);

dout.writeDouble(d);

dout.writeUTF(str);

dout.writeObject(pers2);

dout.writeInt(i);

dout.writeObject(stud2);

dout.writeObject(tabInt);

Page 518: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

518

dout.writeObject(tabstr);

dout.writeObject(w);

/* Inchiderea fluxului de iesire */

dout.close();

/* Deschiderea fisierului pentru a citi datele scrise anterior */

FileInputStream fin=new FileInputStream("Proba1.dat");

ObjectInputStream din=new ObjectInputStream(fin); // Fluxul de citire

// obiecte este conectat la iesirea fluxului de citire din fisier

// fin deschis anterior

/* Citirea obiectelor se face in aceeasi ordine in care au fost

scrise

*/

Persoana pers1a, pers2a;

Student stud1a, stud2a;

int ia, tabInta[];

double da, wa[][];

String stra, tabstra[];

pers1a=(Persoana)din.readObject();

stud1a=(Student)din.readObject();

da=din.readDouble();

stra=din.readUTF();

pers2a=(Persoana)din.readObject();

ia=din.readInt();

stud2a=(Student)din.readObject();

tabInta=(int[])din.readObject();

tabstra=(String[])din.readObject();

wa=(double[][])din.readObject();

/* Afisarea pe ecran a perechilor de date scrise si citite */

System.out.println("Afisarea datelor scrise si citite pe perechi");

System.out.println("int: "+i+" "+ia);

System.out.println("double: "+d+" "+da);

System.out.println("UTF: "+str+" "+stra);

System.out.println(pers1+" "+pers1a);

System.out.println(pers2+" "+pers2a);

System.out.println(stud1+" "+stud1a);

System.out.println(stud2+" "+stud2a);

System.out.print("tabInt: ");

for(int j=0; j<tabInt.length; j++)

System.out.print(tabInt[j]+" ");

System.out.print("\ntabInta: ");

for(int j=0; j<tabInta.length; j++)

System.out.print(tabInta[j]+" ");

System.out.print("\ntabstr: ");

for(int j=0; j<tabstr.length; j++)

System.out.print(tabstr[j]+" ");

System.out.print("\ntabstra: ");

for(int j=0; j<tabstra.length; j++)

System.out.print(tabstra[j]+" ");

System.out.println();

System.out.println("Tabloul bidimensional de tip real");

for(int j=0; j<wa.length; j++) {

for(int k=0; k<wa[j].length; k++)

System.out.print(wa[j][k]+" ");

System.out.println();

}

/* Inchiderea fluxului de intrare */

din.close();

Page 519: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

519

}

}

Capitolul 12

Fişierul Bondari.java

import java.awt.*;

import java.awt.event.*;

import javax.swing.*;

public class Bondari extends JFrame {

JButton nouBondar;

public Bondari() {

super("Bondari");

nouBondar=new JButton("Creare nou bondar");

nouBondar.addActionListener(new CreareBondar());

getContentPane().add(nouBondar, BorderLayout.NORTH);

addWindowListener(new Iesire());

setSize(200,100);

setLocation(new Point(0,20));

setVisible(true);

}

/* Clasa cu interfata Runnable pentru un fir de executie

cu interfata grafica

*/

class Bondar extends JFrame implements Runnable {

JSlider perioada, amplitudine;

Fereastra fereastra;

Thread fir;

boolean esteViu;

public Bondar() {

perioada=new JSlider(JSlider.HORIZONTAL, 100, 500, 200);

perioada.setBorder(BorderFactory.createTitledBorder(

"Perioada saltului"));

perioada.setMajorTickSpacing(200);

perioada.setMinorTickSpacing(100);

perioada.setPaintTicks(true);

perioada.setPaintLabels(true);

amplitudine=new JSlider(JSlider.HORIZONTAL, 0, 40, 10);

amplitudine.setBorder(BorderFactory.createTitledBorder(

"Amplitudinea saltului"));

amplitudine.setMajorTickSpacing(20);

amplitudine.setMinorTickSpacing(2);

amplitudine.setPaintTicks(true);

amplitudine.setPaintLabels(true);

fereastra=new Fereastra();

fereastra.setSize(200,200);

fereastra.setBackground(Color.cyan);

fereastra.culoare=Color.red;

Box box=Box.createVerticalBox();

box.add(perioada);

Page 520: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

520

box.add(amplitudine);

box.add(fereastra);

getContentPane().add(box);

addWindowListener(new SfarsitBondar(this));

setSize(200,350);

setVisible(true);

}

/* Definirea metodei run() a interfetei Runnable */

public void run() {

Rectangle r=fereastra.getBounds();

fereastra.x=r.width/2;

fereastra.y=r.height/2;

esteViu=true;

while(esteViu) {

fereastra.ampl=amplitudine.getValue();

fereastra.repaint();

try {

fir.sleep(perioada.getValue());

}

catch(Exception e) {

System.out.println(e);

}

}

}

} /* Sfarsitul clasei Bondar */

/* Fereastra in care evolueaza "bondarul" */

class Fereastra extends Canvas {

int x, y, ampl;

Color culoare;

public void paint(Graphics g) {

Rectangle r=getBounds();

x+=(int)(ampl*(Math.random()-0.5));

if(x<0) x=0;

else if(x>=r.width) x=r.width-5;

y+=(int)(ampl*(Math.random()-0.5));

if(y<0) y=0;

else if(y>=r.height) y=r.height-5;

g.setColor(culoare);

g.fillRect(x,y,10,10);

g.setColor(Color.red);

g.drawRect(x,y,10,10);

}

} /* Sfarsitul clasei Fereastra */

/* Incheierea executarii aplicatiei */

class Iesire extends WindowAdapter {

public void windowClosing(WindowEvent e) {

System.exit(0);

}

} /* Sfarsitul clasei Iesire */

/* Crearea si lansarea unui nou fir de executie */

class CreareBondar implements ActionListener {

public void actionPerformed(ActionEvent e) {

int x,y;

x=(int)(Math.random()*400);

y=(int)(Math.random()*200);

Bondar bondar=new Bondar();

Page 521: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

521

bondar.setLocation(new Point(x,y));

Thread thread=new Thread(bondar);

thread.start();

}

} /* Sfarsitul clasei CreareBondar */

/* Incheierea executarii unui fir de executie */

class SfarsitBondar extends WindowAdapter {

Bondar bondar;

SfarsitBondar(Bondar bondar) {

this.bondar=bondar;

}

public void vindowClosing(WindowEvent e) {

bondar.esteViu=false;

}

} /* Sfarsitul clasei SfarsitBondar */

/* Metoda principala a aplicatiei */

public static void main(String args[]) {

Bondari b=new Bondari();

}

}

Fişierul Bondari1.java

import java.awt.*;

import java.awt.event.*;

import javax.swing.*;

public class Bondari1 extends JFrame {

Bondar b1,b2;

Thread fir1, fir2, fir3;

Fereastra fereastra;

CutiePostala cutiePostala;

public Bondari1() {

super("Doi bondari in acelasi spatiu");

b1=new Bondar();

fir1=new Thread(b1);

b1.fir=fir1;

b2=new Bondar();

fir2=new Thread(b2);

b2.fir=fir2;

Box box1=Box.createHorizontalBox();

box1.add(b1);

box1.add(b2);

Box box2=Box.createVerticalBox();

fereastra=new Fereastra();

fir3=new Thread(fereastra);

fereastra.setSize(200,200);

fereastra.setBackground(Color.cyan);

box2.add(box1);

box2.add(fereastra);

Container cp1=getContentPane();

cp1.setLayout(new FlowLayout());

cp1.add(box2);

Page 522: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Severin Bumbaru

522

addWindowListener(new Iesire());

setSize(500,400);

setVisible(true);

cutiePostala=new CutiePostala();

fir1.start();

fir2.start();

fir3.start();

}

class Bondar extends JPanel implements Runnable {

Thread fir;

JSlider perioada, amplitudine;

int x, y;

public Bondar() {

perioada=new JSlider(JSlider.HORIZONTAL, 100, 500, 200);

perioada.setBorder(BorderFactory.createTitledBorder(

"Perioada saltului"));

perioada.setMajorTickSpacing(200);

perioada.setMinorTickSpacing(100);

perioada.setPaintTicks(true);

perioada.setPaintLabels(true);

amplitudine=new JSlider(JSlider.HORIZONTAL, 0, 40, 10);

amplitudine.setBorder(BorderFactory.createTitledBorder(

"Amplitudinea saltului"));

amplitudine.setMajorTickSpacing(20);

amplitudine.setMinorTickSpacing(2);

amplitudine.setPaintTicks(true);

amplitudine.setPaintLabels(true);

Box box=Box.createVerticalBox();

box.add(perioada);

box.add(amplitudine);

getContentPane().add(box);

}

public void run() {

Rectangle r=fereastra.getBounds();

x=(int)(r.width*(Math.random()));

y=(int)(r.height*(Math.random()));

for(; ; ) {

x+=(int)(amplitudine.getValue()*(Math.random()-0.5));

if(x<0) x=0;

else if(x>r.width-10) x=r.width-10;

y+=(int)(amplitudine.getValue()*(Math.random()-0.5));

if(y<0) y=0;

else if(y>r.height-10) y=r.height-10;

cutiePostala.amPus();

try {

fir.sleep(perioada.getValue());

}

catch(Exception e) {

System.out.println(e);

}

}

}

}

class Fereastra extends Canvas implements Runnable {

public void paint(Graphics g) {

g.setColor(Color.green);

Page 523: Programarea Orientata Pe Obiecte in Limbajul JAVA, Severin Brumaru

Programarea orientata pe obiecte în limbajul Java

523

g.fillRect(b1.x,b1.y,10,10);

g.setColor(Color.red);

g.drawRect(b1.x,b1.y,10,10);

g.setColor(Color.blue);

g.fillRect(b2.x,b2.y,10,10);

g.setColor(Color.red);

g.drawRect(b2.x,b2.y,10,10);

}

public void run() {

for(;;) {

repaint();

cutiePostala.amLuat();

}

}

}

class CutiePostala {

boolean valoareNoua=false;

synchronized void amPus() {

while(valoareNoua) {

try {

wait();

}

catch(Exception e) {}

}

valoareNoua=true;

notifyAll();

}

synchronized void amLuat() {

while(!valoareNoua) {

try {

wait();

}

catch(Exception e) {}

}

valoareNoua=false;

notifyAll();

}

}

class Iesire extends WindowAdapter {

public void windowClosing(WindowEvent e) {

System.exit(0);

}

}

public static void main(String args[]) {

Bondari1 b=new Bondari1();

}

}