Programarea in Java - 2014 - an II ID.pdf

108
UNIVERSITATEA TITU MAIORESCU FACULTATEA DE INFORMATICĂ PROGRAMAREA ÎN JAVA Conf.univ.dr. Boriga Radu -suport curs - Conf.univ.dr. Dăscălescu Ana Cristina - 2014 -

Transcript of Programarea in Java - 2014 - an II ID.pdf

Page 1: Programarea in Java - 2014 - an II ID.pdf

UNIVERSITATEA TITU MAIORESCU

FACULTATEA DE INFORMATICĂ

PROGRAMAREA ÎN JAVA

Conf.univ.dr. Boriga Radu

-suport curs -

Conf.univ.dr. Dăscălescu Ana Cristina

- 2014 -

Page 2: Programarea in Java - 2014 - an II ID.pdf

2

Introducere Acest curs se adresează studenților anului II, specializarea Informatică, forma de invatamant la

distanță. Modul de prezentare ţine cont de particularităţile învăţământului la distanţă, la care studiul

individual este determinant. În timp ce profesorul sprijină studentul prin coordonarea învățării și

prin feedback periodic asupra acumulării cunoștințelor și a deprinderilor, studentul alege locul,

momentul și ritmul pentru studiu, dispune de capacitatea de a studia independent și totodată își

asumă responsabilitatea pentru inițierea și continuarea procesului educațional.

Disciplina Programarea în Java utilizează noţiunile predate la disciplinele Bazele Informaticii,

Programare procedurală, Programare orientata pe obiecte, discipline studiate în anul I şi în anul

II.

Competențele dobândite de către studenți prin însușirea conținutului cursului sunt folosite la

disciplinele de specialitate precum Tehnici avansate de programare, Proiectarea interfețelor

grafice etc. O neînțelegere a noțiunilor fundamentale prezentate în acest curs poate genera

dificultăți în asimilarea conceptelor mai complexe ce vor fi introduse în aceste cursuri de

specialitate.

Principalele obiective ale disciplinei Programarea în Java sunt:

Cunoaşterea conceptelor fundamentale specifice platformei Java;

Capacitatea de a realiza corect un proces de abstractizare a datelor în vederea proiectarii

unei aplicaţii;

Capacitatea de a implementa corect o sursă de sine stătătoare în limajul Java;

Cunoaşterea pachetelor de clase implicite Java şi utilizarea lor pentru dezvoltarea unor

aplicaţii Java;

Capacitatea de a dezvolta noi pachete de clase;

Capacitatea de a analiza şi de a proiecta o ierarhie de clase necesare pentru dezvoltarea unei

aplicaţii în limajul Java;

Capacitatea de a utiliza clase predefinite pentru fluxul cu fişiere.

Page 3: Programarea in Java - 2014 - an II ID.pdf

3

Structura cursului este următoarea:

Unitatea de învăţare 1. Introducere în limajul Java

Unitatea de învăţare 2. Clase şi obiecte. Pachete de clase

Unitatea de învăţare 3. Extinderea claselor. Polimorfism

Unitatea de învăţare 4. Interfeţe Java

Unitatea de învăţare 5. Tratarea excepţiilor

Unitatea de învăţare 6. Operaţii de intrare/ieşire

.

Fiecare unitate de învatare conţine şi un formular de feedback, care va trebui completat după parcurgerea acesteia.

Pachet software recomandat:

Orice medie de lucru pentru limbajul Java poate fi folosit, dar pentru a face o alegere, mai puțin costisitoare, de altfel gratuită, vă

sugerăm mediul de lucru NetBeans care se poate descărca de pe site-ul http://java.sun.com.

Nota finală care se va acorda fiecărui student, va conţine următoarele

componente în procentele menţionate:

- examen final 60%

- lucrari practice/ proiect 40%

Page 4: Programarea in Java - 2014 - an II ID.pdf

4

Cuprins

Unitatea de învăţare Nr.1…………………………………………………………………………………………………………………….5

STRUCTUR APROGRAMELO JAVA…………………………………………………………………………………………………………5

1.1 Caracteristici de bază ale limbajului Java…………………………………………………………………………………………….5

1.2 Tehnologia Java si componentele sale………………………………………………………………………………………………..6

1.2.1 Platforme de lucru Java…………………………………………………………………………………………………………………..6

1.2.2 Tipuri de programe implementate de Java ……………………………………………………………………………………..6

1.2.3 Etapele dezvoltarii unei aplicații Java……………………………………………………………………………………………….7

1.2 Structura lexicala a limbajului Java……………………………………………………………………………………………………..7

1.3 Tipuri de date si variabile în Java………………………………………………………………………………………………………..9

1.4 Expresii si operatori ………………………………………………………………………………………………………………………..11

1.5 Controlul executiei…………………………………………………………………………………………………………………………..14

1.6 Afisarea datelor pe ecran…………………………………………………………………………………………………………………17

1.7 Siruri de caractere……………………………………………………………………………………………………………………………18

Tema de autoinstruire nr. 1…………………………………………………………………………………………………………………..20

Teste de control…………………………………………………………………………………………………………………………………….20

Unitătea de învăţare nr. 2…………………………………………………………………………………………………………………23

CLASE ȘI OBIECTE………………………………………………………………………………………………………………………………23

2.1 Ciclul de viata al unui obiect…………………………………………………………………………………………………………….23

2.1.1 Crearea obiectelor………………………………………………………………………………………………………………………..24

2.2 Crearea claselor……………………………………………………………………………………………………………………………….25

2.2.1 Corpul unei clase…………………………………………………………………………………………………………………………..26

2.2.2 Constructorii unei clase…………………………………………………………………………………………………………………27

2.2.3 Declararea variabilelor………………………………………………………………………………………………………………….31

2.3 Implementarea metodelor………………………………………………………………………………………………………………33

2.3.1 Declararea metodelor…………………………………………………………………………………………………………………..33

2.3.2 Metode de instanta si metode de clasa……………………………………………………………………………………….35

2.3.3 Domeniul de vizibilitate (acces) al metodelor unei clase. Modificatori de acces…………………………..35

Tema de autoinstruire nr. 2…………………………………………………………………………………………………………………..38

Teste de control…………………………………………………………………………………………………………………………………….39

Unitătea de învăţare nr. 3………………………………………………………………………………………………………………..42

EXTINDEREA CLASELOR. POLIMORFISMUL IN JAVA …………………………………………………………………………..42

3.1 Mostenirea - concept fundamental al programarii orientata obiect…………………………………………………42

3.2 Caracteristicile unei ierarhi de clase………………………………………………………………………………………………...44

3.3 Rescrierea metodelor şi ascunderea câmpurilor………………………………………………………………………………45

3.4 Metode-constructor pentru clase derivate si cuvantul-cheie super…………………………………………………48

3.5 Implementarea polimorfismului……………………………………………………………………………………………………..49

3.6 Metode si clase abstracte………………………………………………………………………………………………………………..52

Testul de autoevaluare nr. 3………………………………………………………………………………………………………………….58

Tema de autoinstruire nr. 3…………………………………………………………………………………………………………………..59

Teste de control…………………………………………………………………………………………………………………………………….59

Unitătea de învăţare nr. 4…………………………………………………………………………………………………………………61

INTERFEȚE JAVA………………………………………………………………………………………………………………………………..61

4. 1 Metode şi clase abstracte ……………………………………………………………………………………………………………61

4.2 Crearea si folosirea interfetelor Java…………………………………………………………………………………………….62

Page 5: Programarea in Java - 2014 - an II ID.pdf

5

4.3 Implementarea unei interfete………………………………………………………………………………………………………….63

4.4 Implementarea unor interfete multiple……………………………………………………………………………………………64

Testul de autoevaluare nr. 4………………………………………………………………………………………………………………….68

Teste de control…………………………………………………………………………………………………………………………………….69

Unitătea de învăţare nr. 5…………………………………………………………………………………………………………………72

TRATAREA EXCEPTIILOR…………………………………………………………………………………………………………………….72

5.1 Excepţii…………………………………………………………………………………………………………………………………………….72

5.2 Clauza throws şi instrucţiunea throw……………………………………………………………………………………………….74

5.3 Construcţia try…………………………………………………………………………………………………………………………………75

5.4 Tratarea excepţiilor…………………………………………………………………………………………………………………………76

5.5 Crearea si semnalarea propriilor exceptii…………………………………………………………………………………………82

Testul de autoevaluare nr. 5………………………………………………………………………………………………………………….85

Teste de control…………………………………………………………………………………………………………………………………….85

Unitătea de învăţare nr. 6…………………………………………………………………………………………………………………88

INTARARI SI IESIRI …………………………………………………………………………………………………………………………….88

6.1 Tipuri de fluxuri de intrare/iesire Java……………………………………………………………………………………………..88

6.2 Fluxuri de octeti si clase predefinite Java…………………………………………………………………………………………90

6.3 Fluxuri de caractere si clase predefinite Java utilizate ……………………………………………………………………102

Bibliografie…………………………………………………………………………………………………………………………………………..108

Page 6: Programarea in Java - 2014 - an II ID.pdf

6

Unitatea de învăţare Nr. 1

STRUCTURA PROGRAMELOR JAVA

Obiectivele Unităţii de învăţare nr. 1

1.1 Caracteristici de bază ale limbajului Java

Scurt istoric

Inceptul limbajului Java este în toamna anului 1991, când firma Sun Microsystems a finanțat un

proiect cu numele Green condus de James Gosling. Tehnologia propusă a avut un impact

remarcabil asupra intregii comunități a dezvoltatorilor de software, impunându-se prin calități

deosebite cum ar fi simplitate, robustețe și nu în ultimul rând portabilitate.

După patru ani de lucru, echipa Green finalizează specificațiile limbajului Java, astfel că în anul

1995 firma Sun Microsystems vinde licența firmelor IBM, Microsoft, Silicon Graphic, Adope și

Netscape.

Începând cu anul 1998, când a aparut versiunea 2 a limbajului (Java 2 Platform), Java a fost extins,

acoperind și mai multe direcții de dezvoltare: programarea aplicațiilor enterprise (aplicații de tip

server) precum și a celor adresate dispozitivelor cu resurse limitate, cum ar fi telefoanele mobile,

pager-e sau PDA-uri (mici dispozitive de calcul, de dimensiuni putin mai mari decat ale unui

telefon mobil, cu facilitati de agenda si capabile sa execute aplicații intr-un mod relativ asemanator

cu cel al unui PC).

Caracteristicile de bază ale limbajului Java:

este un limbaj simplu de folosit : elimină supraîncărcarea operatorilor, moştenirea multiplă,

pointerii;

este portabil;

este complet orientat obiect: elimină complet stilul de programare procedural

este distribuit, avand implementate biblioteci pentru lucrul in retea;

este un limbaj cu securitate ridicata.

Obiective:

După ce veţi parcurge această unitate de învăţare, veţi reuşi să:

cunoașteți noţiunile de bază ale limbajului Java;

cunoașteți structura unei aplicaţii scrise în Java;

utilizați clasele de obiecte din pachetele predefinite (pachete

API) Java; directiva import ; instrucțiunea package

cunoașteți tipuri de date; instructiuni de control.

Page 7: Programarea in Java - 2014 - an II ID.pdf

7

1.2 Tehnologia Java si componentele sale

1.2.1 Platforme de lucru Java

Tehnologiile Java sunt grupate în așa numitele platforme de lucru. Acestea reprezintă seturi de

librarii scrise în limbajul Java, precum și diverse programe utilitare, utilizate pentru dezvoltarea de

aplicații sau componente destinate unei anume categorii de utilizatori.

J2SE (Standard Edition)

Este platforma standard de lucru ce oferă suport pentru crearea de aplicații independente și

appleturi. De asemenea, aici este inclusă și tehnologia JavaWeb Start ce furnizează o modalitate

extrem de facilă pentru lansarea și instalarea locală a programelor scrise în Java direct de peWeb,

oferind cea mai comodă soluție pentru distribuția și actualizarea aplicațiilor Java.

J2ME (Micro Edition)

Folosind Java, programarea dispozitivelor mobile este extrem de simplă, platforma de lucru J2ME

oferind suportul necesar scrierii de program dedicate acestui scop.

J2EE (Enterprise Edition)

Aceasta platforma ofera API-ul necesar dezvoltarii de aplicații complexe, formate din componente

ce trebuie sa ruleze in sisteme eterogene, cu informatiile memorate in baze de date distribuite, etc.

Tot aici gasim si suportul necesar pentru crearea de aplicații si servicii Web, bazate pe componente

cum ar fi servleturi, pagini JSP, etc.

Toate distributiile Java sunt oferite gratuit si pot fi descarcate de pe Internet de la adresa

”http://java.sun.com”.

1.2.2 Tipuri de programe implementate de Java

Cu ajutorul limbajului Java se pot dezvolta trei tipuri de programe:

1. Programe Java care se execută individual prin intermediul unui interpretor Java. Acestea se

incadreaza in programele “clasice” scrise in diverse limbaje de programare, cum ar

fi:C/C++, Pascal etc. Acest tip de programe Java sunt denumite aplicații de sine statatoare.

2. Programe Java care se execută in interiorul unui navigator Internet, dintr-un document

HTML. Acest tip de programe Java sunt denumite applet-uri.

3. Aplicații care se execută pe partea de server numite serveturi.

O aplicație de sine stătătoare este un program Java care se execută în afara browswer-ului Web .

Principlala caracteristica a acestui tip de aplicație este încapsularea în cadrul unei clase principale a

unuei functii main() asemanatoare cu cea folosita în limbajul C, cu urmatoarea signatura:

public static void main(String args[] )

Aplicațiile care se execută pe partea de client sunt cele încarcate de pe un server si apoi executate

de programe speciale cum ar fi navigatoarele Web.

Un applet este un program Java care respecta o multime de reguli astfel încat sa poata rula în cadrul

unui navigator Web.

Page 8: Programarea in Java - 2014 - an II ID.pdf

8

O aplicație care se execută pe partea de server este o aplicație care este rulată de server ca urmare a

unei cererei primate de acesta, iar rezultatul este trimis programului solicitant.

Un servlet este o componenta Web, scrisa în java, si care poate interactiona cu diferiti clienti

folosind o implementare a paradigmei cerere/raspuns bazata pe protocolul HTTP. Servturile extend

functionalitatea unui server, de obicei a unui server HTTP.

1.2.3 Etapele dezvoltarii unei aplicații Java 1.Editarea setului de instructiuni de programare cu ajutorul unui editor de texte. În acest fel este

creat un fisier sursa, care are extensia .java.

2. Compilarea programului. Pentru aceasta operatie se lanseaza în executie un program special,

denumit compilator Java. Compilatorul analizeaza textul sursa al programului din punct de vedere

sintactic, semnaland eventualele erori. Daca programul nu contine erori sintactice, compilatorul

traduce acest program în codul masina pentru masina virtuala Java

Rezultatul compilarii este unul sau mai multe fisiere de tip “bytecode”. Un fisier de tip “bytecode”

este o secventa de instructiuni de asamblare pentru masina virtuala Java cu extensia .class.

3. Conversia (transformarea), de către interpretorul Java, a instructiunilor “bytecode” în

instructiuni inteligibile masinii gazda care apoi sunt executate.

O aplicație Java este compusă din una sau mai multe clase care interactioneaza intre ele prin

intermediul metodelor. În grupul de clase, care formeaza o aplicație Java, trebuie sa existe o clasa

care sa contina o metoda statica avand numele main.

Atunci cand se execută o aplicație Java, masina virtuala va cauta si invoca automat metoda statica

avand numele main.

Observatie: Metoda main poate fi considerata ca fiind echivalentul Java a functiei main din

C/C++.

Cel mai simplu program Java (care nu face nimic) arata astfel:

class aplicatie

{

public static void main (String [ ] args)

{System.out.println(“Primul program Java”);}

}

Observatie: Tipul parametrilor metodei (functiei) main cat si tipul metodei, static void, sunt

obligatorii.

1.2 Structura lexicala a limbajului Java Setul de caractere

Limbajele de programare "clasice" utilizează setul de caractere ASCII. Limbajul Java foloseşte

setul de caractere Unicode, care este reprezentabil pe 16 biţi, deci are 65 536 caractere, cuprinzând

caractere şi simboluri proprii aproape tuturor limbilor existente.

Exemplu 1

Page 9: Programarea in Java - 2014 - an II ID.pdf

9

Primele 256 caractere din Unicode sunt cele din setul de caractere Latin-1, dintre care primele 128

sunt cele din codul ASCII.

Un caracter poate fi reprezentat oriunde în textul sursă şi printr-o aşa numită "secvenţă Escape",

având forma \uhhhh sau \Uhhhh, unde am notat prin h o cifră hexazecimală (cifrele hexazecimale

corespunzătoare lui 10-15 sunt identificate prin a-f sau A-F). O secvenţă Escape poate să apară deci

nu numai în caractere şi şiruri de caractere, dar şi în identificatori. Numărul hexazecimal dintr-o

astfel de secvenţă corespunde numărului de ordine al caracterului în setul Unicode.

Ne mărginim la a indica secvenţele Escape pentru semnele diacritice din limba română:

Ă = \u00c3 ă = \u00e3

 = \u00c2 â = \u00e2

Ş = \u00aa ş = \u00ca

Ţ = \u00de ţ = \u00fe

Î = \u00ce î = \u00ee

În continuare vom înţelege prin spaţii albe caracterele blanc, tab, form-feed, precum şi terminatorii

de linie: return, line-feed (linie nouă) şi return + line-feed.

Anumite caractere pot fi reprezentate printr-o secvenţă Escape de o formă aparte:

\n = \u000a (linie nouă) \\ = \u005c (backslash)

\t = \u0009 (tab) \' = \u0027 (apostrof)

\b = \u0008 (backspace) \f = \u000c (form-feed)

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

Motivaţia utilizării setului Unicode este integrarea în limbaje de tip HTML care să permită

circulaţia pe Internet.

Identificatori

Identificatorii, întalniti si sub denumirea de nume simbolice, au rolul de a denumi elemente ale

programului Java: constante, variabile, clase metode etc.

Din punct de vedere sintactic, un identificator este constituit dintr-o succesiune nelimitata de litere

si cifre Unicode, primul caracter fiind obligatoriu o litera (inclusiv ‘_’).

Limbajul Java este “case-sensitive”, adica face diferenta între literele mici si literele mari.

Cuvintele-cheie (keywords) sunt identificatori speciali, cu înteles predefinit, care pot fi utilizati

numai în constructii sintactice în care sunt specificati. De exemplu: if, while etc. Toate cuvintele-

cheie se scriu numai cu litere mici.

Separatori

Separatorii au rolul de a separa unitatile sintactice. Ca separatori “generali” se utilizeaza caracterele

albe: spatiu (‘ ‘), TAB (‘\t’), sfarsit de linie (‘\n’) si comentariile.

Separatorii specifici sun folosiți, de exemplu, pentru a separa unele constructii sintactice: variabilele

sunt separate prin caracterul virgula (‘,’). Alti separatori specifici sunt ( ) { } [ ] .

Delimitatorii sunt folosiți pentru:

- a delimita sfarsitul unei instructiuni sau al unei declaratii - caracterul punct si virgula (‘;’);

- a delimita o constanta de tip caracter - caracterul apostrof (‘);

Page 10: Programarea in Java - 2014 - an II ID.pdf

10

- a delimita constantele sir de caractere(ghilimelele).

Comentarii

Comentariile sunt texte care vor fi ignorate de compilator, dar au rolul de a explicita si de a face

mai lizibil pentru programator anumite secvențe de program.

În Java exista trei tipuri de comentarii:

- o succesiune de caractere incadrata între /* si */ ; aceste comentarii pot fi formate din mai multe

linii;

- o succesiune de caractere pe mai multe linii care tin de documentatie, încadrate între /** si */;

textul dintre cele doua secvențe este automat mutat în documentatia aplicației de către generatorul

automat de documentatie (javadoc);

- o succesiune de caractere care începe cu // si se termina la sfarsitul unei singure linii.

1.3 Tipuri de date si variabile în Java

Variabila este o zona temporara de stocare, rezidenta în memoria RAM, care are un nume simbolic

(identificator) si stocheaza un anumit tip de date. Ea poate fi modificata pe parcursul executiei

programului. În Java exista variabile care isi pot modifica valoarea si variabile care nu si-o pot

modifica, numite variabile finale. Asupra variabilelor finale vom reveni ulterior dupa intelegerea

conceptelor de clasa de obiecte.

Pentru utilizarea unei variabile într-un program Java trebuie ca aceasta sa fie mai întai declarata. La

declararea variabilei trebuie specificat numele simbolic al variabilei, tipul acesteia si, eventual, o

valoare initiala care se atribuie variabilei.

Un tip de date defineste multimea de valori pe care variabila poate sa le stocheze, modul de

reprezentare a acestora în memorie, ca si setul de operatii pe care programul poate sa le realizeze cu

aceste date.

In limbajul Java a fost exact definita modalitatea de reprezentare a tipurilor primitive de date în

memorie. In acest fel, variabilele Java devin independente de platforma hardware si software pe

care lucreaza.

Enumerăm în continuare tipurile primitive (de bază).

Tipul boolean: Variabilele de acest tip pot lua doar valorile true şi false.

Tipul char: Variabilele de acest tip sunt reprezentate pe 16 biţi şi pot primi ca valoare orice simbol

din codul Unicode. O variabilă de tip caracter poate fi folosită oriunde poate apărea o valoare

întreagă: este considerat numărul său de ordine în setul de caractere Unicode.

Tipuri întregi: Ele sunt următoarele:

byte (octet) short (întreg scurt) int (întreg) long (întreg lung)

reprezentate în ordine pe 1, 2, 4, 8 octeţi.

Precizăm că în calcule tipurile byte şi short sunt convertite la int.

Tipurile în virgulă mobilă float şi double, reprezentate respectiv pe 4 şi 8 octeţi.

Fiecărui tip primitiv din Java îi corespunde o clasă definită standard în Java: Boolean, Character,

Byte, Short, Integer, Long, Float şi Double. În aceste clase apar constante şi metode utile. Am

prezentat deja câteva constante din aceste clase în discuţia asupra literalilor în virgulă mobilă. Mai

Page 11: Programarea in Java - 2014 - an II ID.pdf

11

menţionăm metoda isNaN din clasele Float şi Double: metoda primeşte o valoare de tipul

corespunzător şi întoarce o valoare booleană, care este true dacă şi numai dacă argumentul nu este o

valoare numerică validă.

Tipul void

Tipul void este un tip special, pentru care multimea valorilor este vida. Acest tip se utilizeaza cand

este necesar sa se specifice absenta oricarei valori. De exemplu: pentru tipul de data a metodelor

care nu întorc nici un rezultat, cum a fost cazul metodei main ().

Constante O constanata este folosita pentru a exprima în program o valoare pe care o poate lua tipurile

primitive de date si tipul sir de caractere.

Constantele intregi pot fi reprezentate în baza 10, 16 sau 8. Constantele întregi pot fi întregi

normale sau lungi. Constantele lungi se recunosc prin faptul ca se termina cu sufixul l sau L.

Pentru a reprezenta o constanta întreaga în baza 16 trebuie sa se adauge prefixul 0x sau 0X în fata

numarului. Pentru a reprezenta o constanta întreaga în baza 8 trebuie sa se adauge prefixul 0 (cifra

zero) în fata numarului.

Constantele reale care se pot reprezenta în memoria calculatorului sunt numere rationale din

intervalele specificate la tipurile float si double. Constantele reale pot fi specificate în notatia

obisnuita sau în format stiintific. Sufixul care indica tipul float poate fi f sau F iar sufixul care

indica tipul double poate fi d sau D. Daca nu este specificat nici un sufix, valoarea implicita este de

tip double.

Constantele de tip caracter sunt utilizate pentru a reprezenta caracterele Unicode.

Reprezentarea se face fie folosind o litera sau o cifra, fie o secventa escape.

Caracterele care au reprezentare grafica pot fi scrise între apostroafe. Pentru cele care nu au

reprezentare grafica, se folosesc secvențele escape sau secvențele escape predefinite prezentate

deja. Intern, Java interpreteaza constantele de tip caracter ca pe un numar (codul Unicode al

caracterului respectiv). Ulterior, functiile de scriere vor transforma acest numar în caracterul

corespunzator.

Constantele de tip sir de caractere sunt cuprinse între ghilimele. Caracterele care formeaza sirul de

caractere pot fi caractere grafice sau secvențe escape ca cele prezentate la constantele de tip

caracter. Daca se doreste introducerea de caractere terminatoare de linie într-un sir de caractere,

atunci se foloseste secventa escape \n în sirul de caractere respectiv.

Observatie: Un sir de caractere este, de fapt, o instanta a clasei de obiecte String declarata standard

în pachetul java.lang. Vom reveni asupra sirurilor de caractere într-o lectie separata.

Sintaxa folosita pentru declararea de variabile este: <tip> <nume_v1> [= <expresie>] [, <nume_v2> [=

<expresie2>] … ];

unde:

- <tip> - specifica tipul de data al variabilelor;

- <nume_v1>, <nume_v2>, … - specifica numele simbolic al variabilelor care se declara (adica,

identificatorii);

- <expresie1>, <expresie2>, … - specifica o expresie de initializare; expresia trebuie sa fie

evaluabila în momentul declararii; sunt optionale si sunt folosite pentru a atribui unor variabile

anumite valori initiale.

Page 12: Programarea in Java - 2014 - an II ID.pdf

12

Observatie: Se pot declara simultan mai multe variabile de acelasi tip, separand numele lor prin

virgula.

O variabila trebuie sa fie declarata imediat inainte de a fi folosita. Locul unde este declarata o

variabila determina domeniul de vizibilitate si semnificatia ei.

Limbjul Java permite si definirea de constante. Modul cum se face definirea constantelor va fi

prezentata într-o lectie separata destinata descrieri atributelor statice.

Exemple de declaratii de variabile ce pot fi folosite într-un program:

int a, b=3, c=4;

char g;

float x=b*5.6, y;

1.4 Expresii si operatori

O expresie este compusă dintr-o succesiune de operanzi, legati prin operatori.

Un operand poate fi o constanta, o variabila, un apel de metoda, o expresie încadrata între paranteze

rotunde.

Operatorii desemneaza operatiile care se execută asupra operanzilor si pot fi grupati pe categorii, în

functie de tipul operatiilor realizate.

Operatorii limbajului Java sunt unari (se aplica unui singur operand) sau sunt binari (se aplica

asupra a doi operanzi).

Menţionăm că Java pune la dispoziţia utilizatorului aproximativ 40 de operatori, dintre care unii

sunt descrişi în continuare. Trebuie precizat că programatorul poate defini metode noi, dar nu şi

operatori noi.

Operatori aritmetici

Aceşti operatori sunt următorii:

+ - * / % .

De asemenea este folosit operatorul unar - pentru schimbarea semnului, precum şi operatorul unar +

(introdus pentru simetrie).

În aritmetica întreagă trebuie să ţinem cont de următoarele reguli:

- orice valoare ce depăşeşte limita admisă este redusă modulo această limită; de aceea nu există

depăşiri (overflow şi underflow);

- împărţirea întreagă se face prin trunchiere; de exemplu -8/3==-2, iar 8/3==2 ;

- operatorul % este definit prin:

(x/y)*y+x%y==x

De exemplu 8%3==2, iar -8%3==-2.

Operatorii de incrementare şi decrementare

Este vorba de operatorii unari ++ şi --, care pot fi aplicaţi operanzilor numerici (întregi sau în

virgulă mobilă) atât în formă prefixată cât şi în formă postfixată.

Expresiile x++ şi ++x sunt echivalente cu x=x+1, cu două excepţii:

- sunt atomice (considerate ca o unică operaţie, nu ca o incrementare urmată de o atribuire). Acest

aspect este relevant doar când mai multe fire de executare acţionează asupra unei aceleiaşi

variabile;

Page 13: Programarea in Java - 2014 - an II ID.pdf

13

- operandul x este evaluat o singură dată. Această excepţie are în vedere instrucţiuni de tipul

a[indice()]=a[indice()]+1, în care este folosită o metodă ce întoarce un întreg; astfel, în exemplul de

mai sus, invocarea metodei indice va avea loc o singură dată (în caz contrar este posibil ca în

membrul stâng şi cel drept să nu se refere la aceeaşi componentă a tabloului a, de exemplu dacă

metoda întoarce în mod aleator un indice).

Diferenţa între x++ şi ++x constă în faptul că incrementarea este realizată după, respectiv înainte de

utilizarea lui x în contextul în care apare. Astfel, dacă valoarea curentă a lui x este 4, atunci:

- evaluarea expresiei 2 * ++x conduce la rezultatul 10,

- evaluarea expresiei 2 * x++ conduce la rezultatul 8, după care valoarea lui x va fi în ambele cazuri

5.

Evident, operatorul -- se supune unor reguli analoage.O construcţie de tipurile x++,x--,++x,--x

reprezintă o expresie aritmetică, dar şi o instrucţiune (valoarea expresiei nu este folosită, însă x este

incrementat sau decrementat).

Operatorii de mai sus pot fi aplicaţi şi pentru tipul char, semnificând trecerea la precedentul,

respectiv următorul caracter din setul de caractere Unicode.

Operatorii de atribuire

Pe lângă operatorul = folosit standard pentru atribuire, mai pot fi folosiţi şi operatorii:

+= -= /= *= %=

care reprezintă scrieri prescurtate. Astfel x+=y este echivalent cu x=x+y, cu excepţia faptului că

evaluarea adresei lui x se face o singură dată (vezi paragraful precedent). Desigur, operatorul %= va

fi folosit doar pentru aritmetica întreagă.

Operatorii relaţionali

Este vorba de următorii operatori:

> (mai mare ca) >= (mai mare sau egal cu) == (egal cu)

< (mai mic ca) <= (mai mic sau egal cu) != (diferit de)

Operatori booleeni

Este vorba de următorii operatori:

¦¦ (disjuncţia logică, sau) && (conjuncţia logică, şi) ! (negaţie)

cu menţiunea că la evaluare se face scurtcircuitare (pe scurt, dacă la evaluarea unei expresii

booleene devine la un moment dat clară valoarea ei, nu se mai continuă în mod inutil evaluarea; de

exemplu dacă expresia este disjuncţia logică a trei termeni şi valoarea primului este true, nu se mai

evaluează ceilalţi termeni).

Operatori pe biţi

Este vorba de operatorii binari ¦ şi & care realizează disjuncţia logică şi conjuncţia logică la nivel de

bit, pentru fiecare pereche de biţi de pe aceeaşi poziţie din reprezentarea operanzilor.

Operatorul condiţional ?:

Acest operator se utilizează în expresii sub forma:

( cond ? e1 : e2 )

Page 14: Programarea in Java - 2014 - an II ID.pdf

14

a cărei valoare este e1 dacă cond este true, respectiv e2 dacă cond este false; cond trebuie să fie o

expresie de tip boolean.

Pentru a nu intra în amănunte, vom impune deocamdată regula ca e1 şi e2 să aibă acelaşi tip.

Operatori postfix

Includem aici:

- cuprinderea între paranteze a indicilor (cu []);

- operatorul de calificare (.) folosit pentru accesarea membrilor claselor;

- parantezele rotunde folosite pentru specificarea listei de parametri din invocări;

- operatorii postfix de incrementare/decrementare ++ şi -- de mai sus.

Operatorul de conversie a tipurilor

Ne mărginim la a preciza că o conversie explicită de tip are forma:

(tip) expresie

urmând să discutăm ulterior condiţiile în care poate avea loc o astfel de conversie.

Operatorul + pentru lucrul cu şiruri

Acest operator este folosit pentru concatenarea şirurilor. Trebuie menţionat că dacă un membru al

unei sume este un şir de caractere, atunci are loc o conversie implicită a celorlalţi membri ai sumei

(devenită acum concatenare) la şiruri de caractere; această facilitate a fost de altfel des folosită în

programele prezentate anterior, de exemplu în cadrul invocării System.out.print(...). Adăugăm doar

că printre membrii sumei pot apărea şi variabile referinţă!

Operatorii pentru referinţe

Sunt utilizaţi următorii operatori:

- accesul la câmpuri (prin calificare);

- invocarea metodelor (prin calificare);

- operatorul de conversie;

- operatorii == şi != ;

- operatorul condiţional;

- operatorul instanceof , folosit în contextul:

Precedenţa operatorilor

Ordinea în care are loc efectuarea prelucrărilor determinate de operatori este dată în următorul tabel

de priorităţi ale operatorilor (de la prioritate maximă la prioritate minimă):

- operatorii postfix

- operatorii unari de incrementare/decrementare, operatorii + şi - unari, operatorul de negaţie !

- operatorul new de creare de obiecte şi cel de conversie: (tip) expresie

- operatorii multiplicativi: * / %

- operatorii aditivi: + -

- operatorii relaţionali şi instanceof

- operatorii de egalitate: == !=

- operatorul &

- operatorul ¦

- conjuncţia logică &&

- disjuncţia logică ¦¦

- operatorul condiţional ( ? : )

Page 15: Programarea in Java - 2014 - an II ID.pdf

15

- operatorii de atribuire.

Observaţii:

- la prioritate egală, operatorii "vecini" acţionează conform regulilor de asociativitate prezentate în

continuare;

- utilizarea parantezelor este mai puternică decât prioritatea operatorilor. Astfel, spre deosebire de

x+y*z, în (x+y)*z prima operaţie care va fi executată este adunarea.

Asociativitate

Regula generală o constituie asociativitatea la stânga. Fac excepţie următorii operatori, pentru care

este folosită asociativitatea la dreapta:

- operatorii unari;

- operatorii de atribuire.

- operatorul ( ? : ).

Exemple :

1) În expresia x-y+z întâi se va efectua scăderea şi apoi adunarea;

2) Instrucţiunea:

x = y = z = 0;

este echivalentă cu:

x = ( y = (z = 0));

şi are ca efect atribuirea valorii 0 variabilelor x,y,z. Explicaţia constă în aceea că efectuarea unei

atribuiri conduce şi la obţinerea unui rezultat (valoarea care a fost atribuită) şi care poate fi folosită

ca în exemplul de mai sus.

3) Secvenţa de program:

int a=5, b=10, c=15;

a += b -=c %= 4;

System.out.println(a + " " + b + " " + c);

produce la ieşire:

12 7 3

1.5 Controlul executiei

Instruct¸iunile Java pentru controlul executiei sunt foarte asemanatoare celor din limbajul C si pot fi

impartite în urmatoarele categorii:

Instructiuni de decizie: if-else, switch-case

Instructiuni de salt: for, while, do-while

Instructiuni pentru tratarea except¸iilor: try-catch-finally, throw

Alte instructiuni: break, continue, return, label;

A. Structuri alternative (de decizie)

Instrucțiunea de decizie if

Sintaxa instructiunii este:

if (<expresie>) <instructiune_1>;

[else <instructiune_2>];

unde:

- <expresie> - specifica expresia de evaluat;

- <instructiune_1>, <instructiune_2> - specifica instructiunile (simple sau compuse) de

executat.

Page 16: Programarea in Java - 2014 - an II ID.pdf

16

Semantica: se evalueaza <expresie> si daca valoarea expresiei este true, se execută

<instructiune_1>, altfel se executa <instructiune_2>.

Nota: Instrucțiunea if poate sa faca parte dintr-o alta instrucțiune if sau else, adica instructiunile if

pot fi incluse (imbricate) în alte instructiuni if.

Urmatorul program (denumit arie_triunghi.java) testeaza daca trei numere pot forma

laturile unui triunghi si daca da calculeaza aria triunghiului folosind formula lui Heron.

/** Utilizarea instructiunii if pentru determinarea ariei triunghiului*/

import java.io.*;

public class arie_triunghi

{

public static void main(String[] args) throws IOException

{

double x, y, z, p, aria;

String s;

System.out.print ("Introduceti x= ");

InputStreamReader isrx = new InputStreamReader(System.in);

BufferedReader brx = new BufferedReader(isrx);

s = brx.readLine();

x = Double.parseDouble(s);

System.out.print ("Introduceti y= ");

InputStreamReader isry = new InputStreamReader(System.in);

BufferedReader bry = new BufferedReader(isry);

s = bry.readLine();

y = Double.parseDouble(s);

System.out.print ("Introduceti z= ");

InputStreamReader isrz = new InputStreamReader(System.in);

BufferedReader brz = new BufferedReader(isrz);

s = brz.readLine();

z = Double.parseDouble(s);

if (x<=0 || y<=0 || z<=0)

System.out.println("Numerele introduse nu sunt laturi ale unui triunghi");

else

if (x+y<=z || x+z<=y || y+z<=x)

System.out.println("Numerele introduse nu sunt laturi ale unui triunghi");

else

{

p = (x+y+z)/2;

aria = Math.sqrt(p*(p-x)*(p-y)*(p-z));

System.out.println("Aria triunghiului = " + aria);

}

}

}

Exemplu 2

Page 17: Programarea in Java - 2014 - an II ID.pdf

17

Instrucțiunea switch

Sintaxa instructiunii este:

switch (<expresie>)

{ case <constanta_1> : <grup_de_instructiuni_1>;

case <constanta_2> : <grup_de_instructiuni_2>;

case <constanta_n> : <grup_de_instructiuni_n>;

[default: <grup_de_instructiuni_n+1>;]

}

unde:

- <expresie> - specifica variabila sau expresia de evaluat;

- <constanta_1>, <constanta_2>, …, <constanta_n> - specifica valorile constantelor cu care se face

compararea rezultatului evaluarii expresiei;

- <grup_de_instructiuni_1>, … - o instrucțiune sau un grup de instructiuni care se execută în cazul

in care o alternativa case se potriveste.

Semantica: se evalueaza <expresie>; se compara succesiv valoarea expresiei cu valorile

constantelor <constanta_1>, <constanta_2>, …, <constanta_n> din alternativele case:

- daca se intalneste o constanta din alternativa case cu valoarea expresiei, se execută secventa de

instructiuni corespunzatoare si toate secvențele de instructiuni care urmeaza, pana la intalnirea

instructiunii break sau pana la intalnirea acoladei inchise (}) care marchează sfarsitul instructiunii

switch;

- daca nici una dintre valorile constantelor din alternativa case nu coincide cu valoarea expresiei, se

execută secventa de instructiuni din alternativa default (alternativa implicita sau prestabilita).

Observatii:

1. Spre deosebire de if-else, care permite selectarea unei alternative din maximum doua posibile,

switch permite selectarea unei alternative din maximum n+1 posibile.

2. In instrucțiunea if-else se execută instrucțiunea (instructiunile) corespunzatoare valorii expresiei

si atat, in timp ce in instrucțiunea switch se execută si toate secvențele de instructiuni ale

alternativelor case urmatoare.

B. Structuri repetitive (iterative)

Instrucțiunea while

Sintaxa instructiunii este:

while (<expresie>)

<instructiune>;

unde:

- <expresie> - specifica expresia de testat;

Semantica: se evalueaza <expresie>:

- daca valoarea expresiei este false se iese din ciclul while;

- daca valoarea expresiei este true, se execută instrucțiunea atita tip cat valoarea expresiei

este true.

Instrucțiunea do-while

Sintaxa instructiunii este:

do

<instructiune>;

while (<expresie>);

unde:

- <instructiune> - o instrucțiune simpla de executat;

Page 18: Programarea in Java - 2014 - an II ID.pdf

18

- <expresie> - specifica expresia de testat (de evaluat);

Semantica: se execută instrucțiunea si apoi se evalueaza expresia:

- daca valoarea expresiei este false se iese din ciclul do-while;

- daca valoarea expresiei este true se execută instrucțiunea (din ciclul do-while) atita tip cat

valoarea expresiei este adevarata.

Instrucțiunea for

Este folosita pentru efectuarea unor prelucrari de un anumit numar de ori.

Sintaxa instructiunii este:

for (<valoare_initiala>; <conditie_sfarsit>; <valoare_increment>)

<instructiune>;

Instrucțiunea for foloseste, de obicei, o variabila denumita variabila de control care indica de cate

ori s-a executat instrucțiunea (<instructiune>) din corpul ciclului. Instrucțiunea for contine patru

sectiuni:

- sectiunea <valoare_initiala> atribuie variabilei de control o valoare initiala, care, de cele mai

multe ori, este 0 sau 1;

- sectiunea <conditie_sfarsit> testeaza valoarea variabilei de control pentru a stabili daca programul

a executat instrucțiunea de atatea ori cat s-a dorit;

- sectiunea <valoare_increment> adauga (scade), de obicei, valoarea 1 la variabila de control, de

fiecare data, dupa ce se execută instrucțiunea din corpul ciclului; valoarea de incrementare sau

decrementare poate fi diferita de 1;

- sectiunea <instructiune> reprezinta instrucțiunea (sau instructiunile) care se doreste (doresc) a fi

repetata (repetate).

1.6 Afisarea datelor pe ecran

In limbajul Java nu exista instructiuni specializate pentru citirea/scrierea datelor. Aceste operatii se

realizeaza prin intermediul unor metode existente in pachetele API ale limbajului. Intrarea si iesirea

in Java se realizeaza cu ajutorul claselor de obiecte din pachetul predefinit java.io. Orice program

care foloseste rutinele de intrare/iesire trebuie sa cuprinda instrucțiunea:

import java.io.* Conceptul fundamental in operatiile de intrare/iesire in limbajul Java este fluxul de intrare/iesire

(stream).

Daca stream-ul este de intrare, succesiunea de biti “curge” dinspre exterior (in acest caz, de la

tastatura) către memoria calculatorului.

Daca stream-ul este de iesire, secventa de biti “curge” dinspre memoria calculatorului către exterior

(in acest caz, către ecran).

Java ofera trei fluxuri predefinite pentru operatii I/O standard:

- System.in pentru intrarea standard de la tastatura;

- System.out pentru iesirea standard la ecranul calculatorului;

- System.err pentru fluxul de erori.

Pentru afisarea datelor la ecranul calculatorului se folosesc metodele print si println. Spre

deosebire de C/C++ care dispun de un numar foarte mare de optiuni de formatare, afisarea in Java

se face exclusiv prin concatenare de String-uri fara nici o optiune de formatare.

Observatie: String-urile sunt obiecte Java care descriu sirurile de caractere si le vom studia separat

intr-o lectie viitoare. Sa retinem ca prin concatenarea a doua siruri se obtine un nou sir de caractere

care uneste cele doua siruri initiale. Operatorul de concatenare a doua siruri de caractere folosit de

Java este semnul + (plus).

Sintaxa folosita la apelul metodei print este:

System.out.print (<expresie>);

Page 19: Programarea in Java - 2014 - an II ID.pdf

19

unde:

- <expresie> - este numele unei variabile de un tip de data sau este o expresie care foloseste

operatorul de concatenare pentru siruri de caractere; daca nu toti operanzii din expresie sunt siruri

de caractere, ci alte tipuri primitive de date atunci Java face o conversie temporara la tipul String.

Efectul apelului metodei print este acela ca se realizeaza afisarea la ecran a variabilei data ca

parametru si nu se face salt la o linie noua.

Sintaxa folosita la apelul metodei println este:

System.out.println (<expresie>);

unde:

- <expresie> - este numele unei variabile de un tip de data sau este o expresie care foloseste

operatorul de concatenare pentru siruri de caractere.

Efectul apelului metodei println este acela ca se realizeaza afisarea la ecran a variabilei data ca

parametru si se face salt la o linie noua.

Metoda println se poate apela si fara parametrii, adica in forma:

System.out.println( ); caz in care se face numai un salt la o linie noua fara sa se afiseze nimic.

1.7 Șiruri de caractere

În Java, un șir de caractere poate fi reprezentat printr-un vector format din elemente de tip char, un

obiect de tip String sau un obiect de tip StringBuffer.

Daca un ¸șir de caractere este constant (nu se doreste schimbarea continutului sau pe parcursul

executiei programului) atunci el va fi declarat de tipul String, altfel va fi declarat de tip

StringBuffer. Diferenta principala intre aceste clase este ca StringBuffer pune la dispozitie metode

pentru modificarea continutului șirului, cum ar fi: append, insert, delete, reverse.

Uzual, cea mai folosita modalitate de a lucra cu șiruri este prin intermediul clasei String, care are ¸si

unele particularitati fata de restul claselor menite sa simplifice cat mai mult folosirea șirurilor de

caractere. Clasa StringBuffer va fi utilizata predominant in aplicații dedicate procesarii textelor cum

ar fi editoarele de texte.

Exemple echivalente de declarare a unui șir:

String s = "abc";

String s = new String("abc");

char data[] = {’a’, ’b’, ’c’};

String s = new String(data);

Concatenarea ¸șirurilor de caractere se face prin intermediul operatorului + sau, in cazul șirurilor de

tip StringBuffer, folosind metoda append.

String s1 = "abc" + "xyz";

String s2 = "123";

String s3 = s1 + s2;

In Java, operatorul de concatenare + este extrem de flexibil, in sensul ca permite concatenarea

șirurilor cu obiecte de orice tip care au o reprezentare de tip șir de caractere. Mai jos, sunt cateva

exemple:

System.out.print("Vectorul v are" + v.length + " elemente");

String x = "a" + 1 + "b"

Page 20: Programarea in Java - 2014 - an II ID.pdf

20

Testul de autoevaluare nr. 1

1. Care este diferenţa dintre un constructor şi o metodă şi la ce poate fi folosit un constructor ?

2. Dacă C este o clasă fără un constructor definit, având un câmp x de tip întreg, scrieţi

instrucţiunile prin care se creează un obiect ob de tip C şi se afişează valoarea câmpului x al

obiectului ob.

3. Cum se numeşte posibilitatea de a exista mai mulţi constructori, respectiv mai multe metode

cu acelaşi nume, dar cu signaturi diferite? Exemplificaţi.

4. Ce afişează următorul program ? Justificaţi.

class Pereche{

int x, y;

Pereche (int x1, int y1){x=x1 ; y=y1 ;}

void afis(){ System.out.println(re+" "+im);}

}

class Doi{

void modific(int x){x=2;}

void modific(Pereche c){c.im=2;}

}

class M {

public static void main(String sir[]){

Doi d=new Doi();

Pereche c=new Pereche(5,6); c.afis();

d.modific(c.re); c.afis();

d.modific(c);c.afis();}}

Page 21: Programarea in Java - 2014 - an II ID.pdf

21

Tema de autoinstruire nr. 1

Consultaţi bibliografia pentru a afla :

1. Istoricul şi caracteristicile limbajului Java

2. Modalităţile de editare, compilare şi executare a unui program Java;

3. Alte exemple de programe pentru a înţelege mai bine structura programelor în Java,

diferenţa între programarea procedurală şi programarea orientată pe obiecte, modalităţile

de transmitere a parametrilor în Java.

Teste de control:

1.1 Fie urmatoarea declaratie Java:

public private int h;

Care armatii sunt adevarate:

A. Variabila h va fi accesata in mod public, deoarece se ia in considerare primul modicator de

acces;

B. Variabila h va fi accesata in mod private, deoarece se ia in considerare ultimul modicator de

acces;

C. Va fi o eroare la compilare deoarece o variabila nu poate fi in acelasi timp accesata public si

private;

D. Nici una din variantele de mai sus;

1.2 Ce rezulta din urmatorul fragment de cod Java?

int x=1;

String []names={"Andreea","Matei","Ana"};

names[--x]+=".";

for(int i=0;i<names.length;i++)

System.out.println(names[i]);

A. Output-ul include Andreea;

B. Output-ul include Matei;

C. Output-ul include Ana;

D. Nimic din cele de mai sus;

1.3 Fie urmatorul program Java: public class Program{

static void f(int k){

switch(k){

default: System.out.print("i "); break;

case1: System.out.print("1 "); break;

Page 22: Programarea in Java - 2014 - an II ID.pdf

22

case 2:case3: System.out.print("21 "); break;

case 4:case5: System.out.print("26 ");

}}

public static void main(String []args){

for(int i=0;i<6;i++)

f(i);

}}

Care afrmatii sunt false?

A. Eroare la compilare;

B. Programul se compileaza si la executie afiseaza i 1 21 21 26 26 ;

C. Programul se compileaza si la executie afiseaza i 1 21 26 ;

D. Programul se compileaza si la executie afiseaza i 1 21 21 26 26 i;

1.4 Fie urmatorul cod Java:

byte b=-7 >>> 1;

System.out.println(b);

Ce se poate spune despre acest cod, daca este integrat intr-un program Java?

A. Va produce eroare la compilare;

B. Va produce eroare la executie;

C. Programul se compileaza si la executie afiseaza -3;

D. Programul se compileaza si la executie afiseaza -4;

1.5 Fie urm¸atorul program Java: public class Program{

static void f(int k){

switch(k){

default: System.out.print("i "); break;

case1: System.out.print("1 "); break;

case 2:case3: System.out.print("23 "); break;

case 4:case5: System.out.print("45 ");

}

}

public static void main(String []args){

for(int i=0;i<6;i++)

f(i);

}

}

Care armatii sunt adevarate?

A. Programul produce eroare la compilare;

B. Programul se compileaza si la executie afiseaza i 1 23 23 45 45 ;

C. Programul se compileaza si la executie afiseaza i 1 23 45 ;

D. Programul se compileaza si la executie afiseaza i 1 23 23 45 45 i;

Page 23: Programarea in Java - 2014 - an II ID.pdf

23

Formular de feedback

În dorinţa de ridicare continuă a standardelor desfăşurării activitatilor dumneavoastra, va rugăm să completaţi acest chestionar şi să-l

transmiteţi indrumatorului de an.

Disciplina: ________________________

Unitatea de invatare/modulul:__________________

Anul/grupa:__________________________

Tutore:_________________________

a) Conţinut / Metoda de predare

Partea I

1. Care dintre subiectele tratate in aceasta unitate/modul consideraţi că este cel mai util şi eficient? Argumentati raspunsul.

2. Ce aplicații/proiecte din activitatea dumneavoastra doriţi să imbunatatiti/modificaţi/implementaţi în viitor în urma cunoştinţelor

acumulate în cadrul acestei unitati de invatare/modul?

3. Ce subiecte consideraţi că au lipsit din acesta unitate de invatare/modul?

4. La care aplicații practice ati intampinat dificultati in realizare? Care credeti ca este motivul dificultatilor intalnite?

5. Daca ar fi sa va evaluati, care este nota pe care v-o alocati, pe o scala de la 1-10?. Argumentati.

Partea II. Impresii generale

1. Acest modul a întrunit aşteptările dumneavoastră?

2) Aveţi sugestii care să conducă la creşterea calităţii acestei unitati de invatare/modul?

3) Aveţi propuneri pentru alte unitati de invatare?

Vă mulţumim pentru feedback-ul dumneavoastră

În totalitate

În mare măsură În mică măsură Nu

Page 24: Programarea in Java - 2014 - an II ID.pdf

24

Unitatea de învăţare Nr. 2

Clase si obiecte

Obiectivele Unităţii de învăţare nr. 2

2.1 Ciclul de viata al unui obiect

2.1.1 Crearea obiectelor

In Java, ca in orice limbaj de programare orientat-obiect, crearea obiectelor se realizeaza prin

instantierea unei clase si implica urmatoarele etape:

Declararea

Presupune specificarea tipului acelui obiect, cu alte cuvinte specificarea clasei acestuia

NumeClasa numeObiect;

Instantiere

Se realizeaza prin intermediul operatorului new si are ca efect crearea efectiva a obiectului cu

alocarea spatiului de memorie corespunzator.

numeObiect = new NumeClasa();

Initializarea

Se realizeaza prin intermediul constructorilor clasei respective. Initializarea este de fapt parte

integranta a procesului de instantiere, in sensul ca imediat dupa alocarea memoriei ca efect al

operatorului new este apelat constructorul specificat. Parantezele rotunde de dupa numele clasei

Obiective:

După ce veţi parcurge această unitate de învăţare, veţi reuşi să:

cunoașteți ciclul de viața al obiectelor;

cunoașteți structura structura unei clase Java;

definiți metode membre și constructori;

Page 25: Programarea in Java - 2014 - an II ID.pdf

25

indica faptul ca acolo este de fapt un apel la unul din constructorii clasei si nu simpla specificare a

numelui clasei.

Mai general, instantierea si initializarea apar sub forma:

numeObiect = new NumeClasa([argumente constructor]);

Sa consideram urmatorul exemplu, in care declaram si instantiem doua obiecte din clasa Rectangle,

clasa ce descrie suprafete grafice rectangulare, definite de coordonatele coltului stanga sus

(originea) ¸si latimea, respective inaltimea.

Rectangle r1, r2;

r1 = new Rectangle();

r2 = new Rectangle(0, 0, 100, 200);

In primul caz Rectangle() este un apel către constructorul clasei Rectangle care este responsabil cu

init i̧alizarea obiectului cu valorile implicite. Dupa cum observam in al doilea caz, initializarea se

poate face si cu anumiti parametri, cu conditia sa existe un constructor al clasei respective care sa

accepte parametrii respectivi.

Fiecare clasa are un set de constructori care se ocupa cu initializare obiectelor nou create. De

exemplu, clasa Rectangle are urmatorii constructori:

public Rectangle()

public Rectangle(int latime, int inaltime)

public Rectangle(int x, int y, int latime, int inaltime)

public Rectangle(Point origine)

public Rectangle(Point origine, int latime, int inaltime)

public Rectangle(Point origine, Dimension dimensiune)

Declararea, instantierea si initializarea obiectului pot aparea pe aceiași linie (cazul cel mai uzual):

Rectangle patrat = new Rectangle(0, 0, 100, 100);

Folosirea obiectelor

Odata un obiect creat, el poate fi folosit in urmatoarele sensuri: aflarea unor informatii despre

obiect, schimbarea starii sale sau executarea unor actiuni. Aceste lucruri se realizeaza prin aflarea

sau schimbarea valorilor variabilelor sale, respectiv prin apelarea metodelor sale.

Referirea valorii unei variabile se face prin obiect.variabila De exemplu clasa Rectangle are

variabilele publice x, y, width, height, origin.

Aflarea valorilor acestor variabile sau schimbarea lor se face prin constructii de genul:

Rectangle patrat = new Rectangle(0, 0, 100, 200);

System.out.println(patrat.width); //afiseaza 100

patrat.x = 10;

patrat.y = 20; //schimba originea

patrat.origin = new Point(10, 20); //schimba originea

Accesul la variabilele unui obiect se face in conformitate cu drepturile de acces pe care le ofer˘a

variabilele respective celorlalte clase.

Apelul unei metode se face prin obiect.metoda([parametri]).

Rectangle patrat = new Rectangle(0, 0, 100, 200);

patrat.setLocation(10, 20); //schimba originea

patrat.setSize(200, 300); //schimba dimensiunea

Page 26: Programarea in Java - 2014 - an II ID.pdf

26

Se observa ca valorile variabilelor pot fi modificate indirect prin intermediul metodelor sale.

Programarea orientata obiect descurajeaza folosirea directa a variabilelor unui obiect deoarece

acesta poate fi adus instari inconsistente (ireale). In schimb, pentru fiecare variabil˘a care descrie

starea obiectului trebuie sa existe metode care sa permita schimbarea/aflarea valorilor variabilelor

sale.

Acestea se numesc metode de accesare, sau metode setter - getter si au numele de forma

setVariabila, respectiv getVariabila.

patrat.width = -100; //stare inconsistenta

patrat.setSize(-100, -200); //metoda setter

//metoda setSize poate sa testeze daca noile valori sunt

//corecte si sa valideze sau nu schimbarea lor

Rolul operatorului new

La folosirea operatorului new se execută urmatoarele:

- se creaza o noua instanta a clasei date;

- se aloca memorie pentru aceasta instanta;

- se apeleaza o metoda speciala a clasei numita constructor.

Constructorii reprezinta metode speciale pentru crearea si initializarea noilor instante ale claselor.

Constructorii initializeaza noul obiect si variabilele sale, creaza orice alte obiecte de care are nevoie

obiectul creat si realizeaza orice alte operatii de care obiectul are nevoie la initializarea sa.

Intr-o clasa pot exista mai multe definitii de constructori, fiecare avand un numar diferit de

argumente sau de tipuri.

Cand se foloseste operatorul new, se pot specifica diferite argumente in lista de argumente si va fi

apelat constructorul corespunzator pentru acele argumente.

Intr-o clasa pot fi definiti oricati constructori se doresc pentru a implementa comportamentul clasei.

Distrugerea obiectelor

Multe limbaje de programare impun ca programatorul sa tina evidenta obiectelor create si sa le

distruga in mod explicit atunci cand nu mai este nevoie de ele, cu alte cuvinte sa administreze

singur memoria ocupata de obiectele sale.

In Java programatorul nu mai are responsabilitatea distrugerii obiectelor sale intrucat, in momentul

rularii unui program, simultan cu interpretorul Java, ruleaza si un proces care se ocupa cu

distrugerea obiectelor care nu mai sunt folosite. Acest proces pus la dispozit¸ie de platforma Java de

lucru se numeste garbage collector (colector de gunoi), prescurtat gc.

2.2 Crearea claselor Clasele reprezinta o modalitate de a introduce noi tipuri de date intr-o aplicație Java, cealalta

modalitate fiind prin intermediul interfețelor.

Declararea unei clase respecta urm˘atorul format general:

[<modificatori_acces>] [<modificatori_clasa>] class <nume_clasa> [<clauze_s>]

{<corpul_clasei>}

unde:

- <modificatori_acces> - specifica domeniul de vizibilitate (folosire sau acces) al clasei;

modificatorul de acces este optional si poate fi: public;

- <modificatori_clasa> - specifica tipul clasei definite; modificatorul clasei este optional si poate fi:

abstract, final;

Page 27: Programarea in Java - 2014 - an II ID.pdf

27

- <nume_clasa> - specifica numele clasei de obiecte; este de preferat ca numele clasei sa inceapa cu

o litera majuscula si daca numele clasei contine in interior mai multe cuvinte, aceste cuvinte sa

inceapa cu o litera majuscula;

- <clauze_s> - specifica anumite clauze referitoare la pozitia pe care o ocupa clasa in ierarhia de

clase din care face parte (clauza extends) sau daca aceasta clasa foloseste o interfata (clauza

inplements); despre aceste clauze vom vorbi intr-o lectie viitoare.

- <corpul_clasei> - variabilele clasei (de instana si de clasa) si metodele care lucreaza cu acestea,

numite la un loc membrii clasei.

Observatie: Continutul (corpul) unei clase nu este o succesiune de instructiuni.

Modificatorii pentru tipurile de clasa

O clasa poate fi:

- abstracta, caz in care folosim modificatorul abstract;

- finala, caz in care folosim modificatorul final.

In cazul in care declaram o clasa de obiecte ca fiind abstracta, compilatorul va interzice instantierea

acestei clase, adica nu se permite crearea de obiecte din aceasta clasa.

In cazul in care declaram o clasa de obiecte ca fiind finala, compilatorul va interzice ca pornind de

la aceasta clasa sa se defineasca subclase. Vom reveni intr-o lectie viitoare.

Modificatorii de acces

In cazul in care declaram o clasa de obiecte ca fiind publica, atunci aceasta clasa poate fi folosita

(accesata) si din exteriorul pachetului din care face parte.

Daca o clasa nu este declarata ca fiind de tip public atunci ea va putea fi folosita (accesata) doar de

clasele din cadrul aceluiasi pachet. Acest tip de acces la o clasa se numeste package-friendly si este

implicit in Java.

Nota: Toate clasele care nu fac parte din nici un pachet, sunt considerate automat ca facand parte

din acelasi pachet implicit. Ca o consecinta, accesul de tip friendly se aplica pentru toate aceste

clase. Acesta este motivul pentru care vizibilitatea nu este afectata daca se omite modificatorul

public pentru clasele care nu fac parte dintr-un pachet. Totusi, aceasta modalitate de folosire a

accesului de tip friendly nu este recomandata.

2.2.1 Corpul unei clase

Corpul unei clase urmeaza imediat dupa declararea clasei si este cuprins intre acolade. Continutul

acestuia este format din:

Declararea si, eventual, initializarea variabilelor de instanta si de clasa (cunoscute impreuna

ca variabile membre).

Declararea ¸si implementarea constructorilor.

Declararea ¸si implementarea metodelor de instanta si de clasa (cunoscute impreuna ca

metode membre).

Declararea unor clase imbricate (interne).

Spre deosebire de C++, nu este permisa doar declararea metode in corpul clasei, urmand ca

implementare sa fie facuta in afara ei. Implementarea metodelor unei clase trebuie sa se faca

obligatoriu in corpul clasei.

// C++

class A {

void metoda1();

Page 28: Programarea in Java - 2014 - an II ID.pdf

28

int metoda2() {

// Implementare

}

}

A::metoda1() {

// Implementare

}

// Java

class A {

void metoda1(){

// Implementare

}

void metoda2(){

// Implementare

}

}

Variabilele unei clase pot avea acela¸si nume cu metodele clasei, care poate fi chiar numele clasei,

fara a exista posibilitatea aparitiei vreunei ambiguitati din punctul de vedere al compilatorului.

Acest lucru este insa total nerecomandat daca ne gandim din perspectiva lizibilitatii codului,

dovedind un stil ineficient de progamare.

class A {

int A;

void A() {};

// Corect pentru compilator

// Nerecomandat ca stil de programare

}

2.2.2 Constructorii unei clase

Constructorii unei clase sunt metode speciale care au acelasi nume cu cel al clasei, nu returneaza

nici o valoare si sunt folosiți pentru initializarea obiectelor acelei clase in momentul instantierii lor.

class NumeClasa {

[modificatori] NumeClasa([argumente]) { // Constructor}}

O clasa poate avea unul sau mai multi constructori care trebuie insa sa difere prin lista de argumente

primite. In felul acesta sunt permise diverse tipuri de initializari ale obiectelor la crearea lor, in

functie de numarul parametrilor cu care este apelat constructorul.

Sa consideram ca exemplu declararea unei clase care descrie notiunea de dreptunghi si trei posibili

constructori pentru aceasta clasa.

class Dreptunghi {

double x, y, w, h;

Dreptunghi(double x1, double y1, double w1, double h1) {

// Cel mai general constructor

x=x1; y=y1; w=w1; h=h1;

System.out.println("Instantiere dreptunghi");

}

Dreptunghi(double w1, double h1) {

// Constructor cu doua argumente

x=0; y=0; w=w1; h=h1;

System.out.println("Instantiere dreptunghi");

Page 29: Programarea in Java - 2014 - an II ID.pdf

29

}

Dreptunghi() {

// Constructor fara argumente

x=0; y=0; w=0; h=0;

System.out.println("Instantiere dreptunghi");

}

}

Constructorii sunt apelati automat la instantierea unui obiect. In cazul in care dorim sa apelam

explicit constructorul unei clase folosim expresia

this( argumente )

care apeleaza constructorul corespunzator (ca argumente) al clasei respective.

Aceasta metoda este folosita atunci cand sunt implementati mai multi constructori pentru o clasa,

pentru a nu repeta secvențele de cod scrise deja la constructorii cu mai multe argumente (mai

generali). Mai eficient, fara repeta aceleasi secvențe de cod in toti constructorii (cum ar fi afisarea

mesajului ”Instantiere dreptunghi”), clasa de mai sus poate fi rescrisa astfel:

class Dreptunghi {

double x, y, w, h;

Dreptunghi(double x1, double y1, double w1, double h1) {

// Implementam doar constructorul cel mai general

x=x1; y=y1; w=w1; h=h1;

System.out.println("Instantiere dreptunghi");

}

Dreptunghi(double w1, double h1) {

this(0, 0, w1, h1);

// Apelam constructorul cu 4 argumente

}

Dreptunghi() {

this(0, 0);

// Apelam constructorul cu 2 argumente

}

}

Constructorul implicit

Constructorii sunt apelati automat la instantierea unui obiect. In cazul in care scriem o clasa care nu

are declarat nici un constructor, sistemul ii creeaza automat un constructor implicit, care nu

primeste nici un argument si care nu face nimic. Deci prezenta constructorilor in corpul unei clase

nu este obligatorie. Daca insa scriem un constructor pentru o clasa, care are mai mult de un

argument, atunci constructorul implicit (fara nici un argument) nu va mai fi furnizat implicit de

către sistem. Sa consideram, ca exemplu, urmatoarele declaratii de clase:

class Dreptunghi {

double x, y, w, h;

// Nici un constructor

}

class Cerc {

double x, y, r;

// Constructor cu 3 argumente

Exemplu 1

Page 30: Programarea in Java - 2014 - an II ID.pdf

30

Cerc(double x, double y, double r) { ... };

}

Sa consideram acum doua instantieri ale claselor de mai sus:

Dreptunghi d = new Dreptunghi();

// Corect (a fost generat constructorul implicit)

Cerc c;

c = new Cerc();

// Eroare la compilare !

c = new Cerc(0, 0, 100);

// Varianta corecta

Constructorii unei clase pot avea urmatorii modificatori de acces:

public, protected, private si cel implicit.

public: in orice alta clasa se pot crea instante ale clasei respective.

protected : doar in subclase pot fi create obiecte de tipul clasei respective.

private :in nici o alta clasa nu se pot instantia obiecte ale acestei clase. O astfel de clasa

poate contine metode publice care s˘a fie responsabile cu crearea obiectelor, controland in

felul acesta diverse aspecte legate de instant¸ierea clasei respective.

implicit : doar in clasele din acelasi pachet se pot crea instante ale clasei respective.

Prezentăm o modalitate de a crea şi prelucra o listă înlănţuită, ale cărei elemente alegem să fie

caractere.

După cum ştim, idea de bază este de a forma "celule" care să conţină un element efectiv şi "adresa"

următoarei celule. Pentru aceasta vom defini o clasă elem formată din:

- câmpurile c (de tip caracter) şi leg (de tip elem);

- câmpurile statice p şi u, conţinând referinţele spre primul şi ultimul element al listei;

- un constructor fără parametri, care este folosit pentru crearea în metoda principală a obiectului Ob;

- un constructor, care are un parametru de tip caracter; la crearea unui nou obiect de tip elem,

obiectul va primi în câmpul c caracterul transmis la invocarea constructorului, iar câmpul leg va

deveni în mod implicit referinţa nulă null;

- metoda creare, care creează un prim element al listei (memorând referinţa la el în variabilele p şi

u) şi apoi în mod repetat, până când este citit caracterul '$', obiectul u creează, folosind metoda

adaug, un nou obiect pentru noul caracter citit şi actualizează referinţa u pe baza rezultatului întors;

- metoda adaug, care creează un nou obiect şi întoarce o referinţă către el;

- metodele direct şi invers ce au un parametru x de tip elem şi întorc un rezultat de tip şir de

caractere ce corespunde parcurgerii în ordine normală (de la stânga la dreapta), respectiv în ordine

inversă, a şirului de caractere ce începe de la "adresa" x.

În clasa Lista, în metoda principală, este invocată metoda creare şi apoi metodele direct şi invers,

prin intermediul unui obiect Ob de tipul elem, ultimele două având ca argument câmpul static p al

clasei elem.

Programul corespunzător este prezentat în continuare.

Exemplu 2

Exemplu 3

Page 31: Programarea in Java - 2014 - an II ID.pdf

31

import java.util.*;

class elem {

char c; elem leg; static elem p,u;

elem() { }

elem(char ch) { c = ch; }

elem adaug(char ch) {

elem x = new elem(ch); leg = x; return x;

}

void creare() {

Scanner sc = new Scanner(System.in);

char ch = sc.next().charAt(0); p = new elem(ch); u = p;

ch = sc.next().charAt(0);

while (ch!='$') {

u = u.adaug(ch); ch = sc.next().charAt(0);

}

}

String direct(elem x) {

if (x==null) return "";

else return x.c + direct(x.leg);

}

String invers(elem x) {

if (x==null) return "";

else return invers(x.leg)+x.c;

}

}

class Lista {

public static void main(String[] s) {

elem Ob = new elem();

Ob.creare();

System.out.println( Ob.direct(elem.p) );

System.out.println( Ob.invers(elem.p) );

}

}

unde operatorul != are sensul "diferit de". Să observăm că metodele direct şi invers puteau fi

invocate şi cu argumentul Ob.p.

Să analizăm pe un exemplu modul de funcţionare a programului de mai sus. Să presupunem că la

intrare apare: abc$c1

Este citit caracterul 'a' şi este creat un nou obiect de tipul elem, al cărui câmp c este caracterul 'a' şi

al cărui câmp leg este null. Variabila u de tip elem păstrează referinţa către acest obiect. Pentru

claritate, să notăm cu P1 acest obiect. Variabilele p şi u memorează o referinţă la obiectul P1.

În continuare este citit caracterul 'b'. Apoi obiectul P1 (referit prin u) este "pus la lucru". El creează

un nou obiect de tip elem, al cărui câmp c este caracterul 'b' şi al cărui câmp leg este null; fie P2

acel obiect. Câmpul leg al lui P1 este actualizat şi devine referinţa la P2. Variabila u va conţine

acum o referinţă la obiectul P2.

Page 32: Programarea in Java - 2014 - an II ID.pdf

32

În continuare este citit caracterul 'c'. Apoi obiectul P2 este "pus la lucru". El creează un nou obiect

de tip elem, al cărui câmp c este caracterul 'c' şi al cărui câmp leg este null; fie P3 acel obiect.

Câmpul leg al lui P2 este actualizat şi devine referinţa la P3. Variabila u va conţine acum o referinţă

la obiectul P3.

Cum următorul caracter citit de la intrare este '$', crearea listei de obiecte este încheiată.

Să analizăm efectul executării instrucţiunii

System.out.println(Ob.direct(p));

care prevede scrierea la ieşire a şirului de caractere întors de invocarea p.direct(p).

Întrucât variabila p memorează o referinţă la obiectul P1, obiectul P1 va invoca metoda direct cu

parametrul P1. Este întors şirul format din caracterul 'a' la care se concatenează şirul întors de

invocarea metodei direct efectuată pentru referinţa P2. Acest apel întoarce şirul format din

caracterul 'b', la care se concatenează şirul întors de invocarea metodei direct efectuată pentru

referinţa P3. Cum această din urmă invocare întoarce şirul vid (deoarece câmpul leg al lui P3

conţine null), rezultă că la ieşire va apărea:

abc

În mod analog, executarea instrucţiunii:

System.out.println(Ob.invers(p));

face ca la ieşire să apară:

cba

2.2.3 Declararea variabilelor

Variabilele membre ale unei clase se declara de obicei inaintea metodelor, desi acest lucru nu este

impus de către compilator.

class NumeClasa {

// Declararea variabilelor

// Declararea metodelor

}

Variabilele membre ale unei clase se declara in corpul clasei si nu in corpul unei metode, fiind

vizibile in toate metodele respectivei clase. Variabilele declarate in cadrul unei metode sunt locale

metodei respective.

Declararea unei variabile presupune specificarea urm˘atoarelor lucruri:

numele variabilei

tipul de date al acesteia

nivelul de acces la acea variabila din alte clase

daca este constanta sau nu

daca este variabila de instanta sau de clasa

alti modificatori

Generic, o variabila se declara astfel:

[modificatori] Tip numeVariabila [ = valoareInitiala ];

unde un modificator poate fi :

• un modificator de acces : public, protected, private;

• unul din cuvintele rezervate: static, final, transient, volatile;

Page 33: Programarea in Java - 2014 - an II ID.pdf

33

Exemple de declaratii de variabile membre:

class Exemplu {

double x;

protected static int n;

public String s = "abcd";

private Point p = new Point(10, 10);

final static long MAX = 100000L;

}

Modificatori:

static

Prezenta lui declara ca o variabila este variabila de clasa si nu de instanta.

int variabilaInstanta ;

static int variabilaClasa;

final

Indica faptul ca valoarea variabilei nu mai poate fi schimbata, cu alte cuvinte este folosit pentru

declararea constantelor.

final double PI = 3.14 ;

...

PI = 3.141; // Eroare la compilare !

Prin conventie, numele variabilelor finale se scriu cu litere mari. Folosirea lui final aduce o

flexibilitate sporita in lucrul cu constante, in sensul ca valoarea unei variabile nu trebuie specificata

neaparat la declararea ei (ca in exemplul de mai sus), ci poate fi specificata ¸si ulterior intr-un

constructor, dupa care ea nu va mai putea fi modificata.

class Test {

final int MAX;

Test() {

MAX = 100; // Corect

MAX = 200; // Eroare la compilare !

}

}

2.3 Implementarea metodelor

2.3.1 Declararea metodelor

Metodele sunt responsabile cu descrierea comportamentului unui obiect. Intrucat Java este un

limbaj de programare complet orientat-obiect, metodele se pot gasi doar in cadrul claselor. Generic,

o metoda se declara astfel:

[modificatori] TipReturnat numeMetoda ( [argumente] )

[throws TipExceptie1, TipExceptie2, ...]

{

// Corpul metodei

}

unde un modificator poate fi :

un specificator de acces : public, protected, private

unul din cuvintele rezervate: static, abstract, final, native, synchronized;

Page 34: Programarea in Java - 2014 - an II ID.pdf

34

Modificatorii care pot fi specificati pentru o metoda:

static

Prezenta lui declara ca o metoda este de clasa si nu de instanta.

void metodaInstanta();

static void metodaClasa();

abstract

Permite declararea metodelor abstracte. O metoda abstracta este o metoda care nu are implementare

si trebuie obligatoriu sa faca parte dintr-o clasa abstracta.

final

Specifica faptul ca acea metoda nu mai poate fi supradefinita in subclasele clasei in care ea este

definita ca fiind finala. Acest lucru este util daca respectiva metoda are o implementare care nu

trebuie schimbata sub nici o forma in subclasele ei, fiind critica pentru consistent starii unui obiect.

De exemplu, studentilor unei universitati trebuie sa li se calculeze media finala, in functie de notele

obtinute la examene, in aceiași maniera, indiferent de facultatea la care sunt.

class Student {

...

final float calcMedie(float note[], float ponderi[]) {

...

}

...

}

class StudentInformatica extends Student {

float calcMedie(float note[], float ponderi[]) {

return 10.00;

}

}// Eroare la compilare !

Apelul metodelor Apelul unei metode definita intr-o clasa de obiecte se realizeaza in mai multe moduri:

- prin crearea si utilizarea unei instante a clasei in care a fost definita metoda sau a unei subclase a

clasei respective (ca regula generala de invocare a unei metode); in acest caz se foloseste operatorul

punct ( . ), in stinga acestuia punandu-se numele instantei, iar in dreapa acestuia punandu-se numele

metodei;

- prin simpla folosire a numelui sau, in cazul in care clasa in care este apelata metoda este aceiași cu

clasa in care a fost definita; aceasta modalitate este folosita daca atat metoda apelanta cat si metoda

apelata sunt fie numai metode de instanta, fie numai metode de clasa;

- prin folosirea operatorului punct ( . ), in stanga acestuia punandu-se numele clasei in care a fost

definita, iar in dreapta acestuia punandu-se numele metodei; aceasta modalitate este folosita numai

daca metoda este definita ca metoda de clasa.

Programele urmatoare (ClasaTablou1.java si ClasaTablou2.java) prezinta un exemplu de creare a

unei clase care defineste o metoda numita creareTablou. Acesta preia doua numere naturale (o

limita inferioara si una superioara) si creaza un tablou unidimensional care contine toate numerele

naturale aflate intre cele doua limite, inclusiv aceste limite.

Varianta de apel a unei metode prin crearea si utilizarea unei instante a clasei in care a fost definita

metoda.

public class ClasaTablou1 {

int [] creareTablou(int inf, int sup) {

Exemplu 4

Page 35: Programarea in Java - 2014 - an II ID.pdf

35

int [] tabl = new int[(sup - inf) +1];

for (int i = 0 ; i < tabl.length; i++)

tabl[i] = inf++;

return tabl; }

public static void main(String args[]) {

ClasaTablou1 unTablou = new ClasaTablou1();

int [] tablou = unTablou.creareTablou(1,10);

System.out.print("Tabloul: [ ");

for (int i = 0; i < tablou.length; i++)

System.out.print(tablou[i] + " ");

System.out.println("]");}

}

Varianta de apel a unei metode prin simpla folosire a numelui metodei, deoarece metoda este

definita si apelata in aceiași clasa. Totusi metoda creareTablou trebuie sa fie declarata ca metoda de

clasa (modificatorul static) pentru a putea fi apelata dintr-o alta metoda de clasa.

public class ClasaTablou2 {

static int [] creareTablou(int inf, int sup)

{

int [] tabl = new int[(sup - inf) +1];

for (int i = 0 ; i < tabl.length; i++)

tabl[i] = inf++;

return tabl;

}

public static void main(String args[])

{

int [] tablou = creareTablou(1,10); System.out.print("Tabloul: [ ");

for (int i = 0; i < tablou.length; i++)

System.out.print(tablou[i] + " ");

System.out.println("]");

}

}

2.3.2 Metode de instanta si metode de clasa

Metode de instanta Ca regula generala, o metoda definita intr-o clasa se poate apela prin crearea unei instante a clasei

respective sau a unei subclase a clasei respective. Aceasta se datoreaza faptului ca metoda lucreaza

cu o serie de variabile ale clasei care sunt memorate in interiorul instantei si care au valori diferite

in instante diferite (numite variabile de instanta). Astfel de metode se numesc metode ale

instantelor clasei.

Metodele de instanta sunt aplicate unui anume obiect, nu unei clase intregi. Majoritatea metodelor

definite intr-o clasa sunt metode de instanta.

Metode de clasa Dupa cum stim deja, exista si un alt tip de variabile si anume variabilele de clasa sau variabilele

statice care sunt comune tuturor instantelor clasei respective. Aceste variabile pot fi accesate fara a

avea nevoie de o instanta a clasei in care au fost declarate.

Page 36: Programarea in Java - 2014 - an II ID.pdf

36

In mod similar exista si metode de clasa sau metode statice. Pentru a fi apelate, aceste metode,

definite intr-o clasa, nu au nevoie sa fie creata o instanta a clasei respective sau a subclasei derivata

din clasa respectiva. Metodele de clasa sunt disponibile oricarei instante a clasei.

2.3.3 Domeniul de vizibilitate (acces) al metodelor unei clase. Modificatori de acces

O metoda este accesibila (apelabila) daca este definita in clasa din care este apelata sau intr-una din

subclasele acesteia. Atunci cand se apeleaza metoda unui obiect, Java cauta definitia metodei

respective in clasa obiectului. Daca nu o gaseste, cauta mai sus in ierarhia de clase pana cand

gaseste o definitie.

In acelasi timp pentru a “vedea” o metoda si pentru a o putea apela, este nevoie sa avem drepturile

de acces necesare (date de modificatorii de acces).

Modificatorii de acces (vizibilitate) ai metodelor unei clase

In Java exista trei modificatori de vizibilitate ai variabilelor unei clase:

- modificatorul public;

- modificatorul protected;

- modificatorul private.

Modificatorul public face ca metoda respectiva sa fie accesibila oriunde este accesibila clasa din

care face parte metoda.

Modificatorul protected face ca metoda respectiva sa fie accesibila in orice clasa din pachetul careia

ii apartine clasa in care a fost definita. In acelasi timp, metoda este accesibila in toate subclasele

clasei date, chiar daca ele apartin altor pachete.

Modificatorul private face ca metoda respectiva sa fie accesibila doar in interiorul clasei in care a

fost definita.

Daca pentru o metoda a unei clase nu se precizeaza nici un modificator de acces din cei descrisi mai

sus, atunci metoda respectiva devine package-friendly. O metoda friendly este accesibila in

pachetul din care face parte clasa in interiorul careia a fost definita, dar nu este accesibila in

subclasele clasei date daca acestea apartin altor pachete.

Nota: Modificatorii de acces (public, protected, private) sunt plasati primii in definitia metodei,

urmeaza apoi modificatorii care determina felul metodei (static, abstract, final) si apoi semnatura

metodei.

Urmatorul program (TestCerc.java) ilustreaza modul de folosire al variabilelor de instanata, precum

si al metodelor de instanta. In clasa Cerc variabila de instanta este raza care este vizibila numai in

clasa in care a fost declarata (are modificatorul private). De aceea, accesul la aceasta variabila

(pentru examinare si modificare) se face numai prin intermediul metodelor setRaza si getRaza care

sunt publice.

class Cerc

{

private double raza; public void setRaza(double r) {

raza = r; }

public double getRaza() {

return raza; }

public double arie() {

return Math.PI * raza * raza; }

Page 37: Programarea in Java - 2014 - an II ID.pdf

37

public double lungime() {

return 2 * Math.PI * raza; }

}

public class TestCerc

{

public static void main(String[] args) {

Cerc cerculMeu = new Cerc();

cerculMeu.setRaza(10);

System.out.println("Raza=" + cerculMeu.getRaza()); System.out.println("Aria=" + cerculMeu.arie());

System.out.println("Lungimea=" + cerculMeu.lungime());

}

}

Observatie: Deoarece fisierul-sursa TestCerc.java contine o clasa publica, TestCerc, numele

fisierului trebuie sa fie identic cu numele clasei publice, altfel compilarea nu se va face cu succes.

Intr-un fisier-sursa nu se poate defini decat o singura clasa publica.

Referinta this

Cuvantul-cheie this se refera la obiectul curent, adica obiectul a carei metoda a fost apelata. Metoda

poate folosi variabilele de instanta ale obiectului curent sau poate transmite obiectul curent ca

parametru unei alte metode. Iata cateva exemple de folosire a cuvantului this:

t = this.x; // variabila de instanta x pentru acest obiect

this.resetRaza(this); // apeleaza metoda resetRaza, definita in clasa curenta si

// transmite obiectul curent

return this; // returneaza obiectul curent

In cele mai multe cazuri nu este nevoie sa se foloseasca explicit cuvantul-cheie this, deoarece este

presupus. De exemplu, ne putem referi atat la variabilele de instanta, cat si la apelurile de metode

definite in clasa curenta prin simpla folosire a numelui lor, deoarece this este implicit folosit de

aceste referinte.

De aceea, primele doua exemple se pot rescrie astfel:

t = x; // variabila de instanta x pentru acest obiect

resetRaza(this); // apeleaza metoda resetRaza, definita in clasa curenta

Nu se omite cuvantul-cheie this daca in domeniul de vizibilitate al obiectului curent au fost definite

variabile locale cu acelasi nume ca cel al unei variabile de instanta sau au fost transmisi unei

metode, a obiectului curent, parametrii cu acelasi nume ca cel al unei variabile de instanta. Aceste

aspecte au fost explicate la paragraful referitor la domeniul de vizibilitate al variabilelor clasei.

Nota: Deoarece this este o referinta a instantei curente a clasei, trebuie sa se foloseasca doar in

corpul unei definitii de metoda de instanta. Metodele de clasa, declarate cu modificatorul static, nu

pot folosi this.

Page 38: Programarea in Java - 2014 - an II ID.pdf

38

Tema de autoinstruire nr. 2

1. Care este diferenţa dintre un constructor şi o metodă şi la ce poate fi folosit un constructor ?

2. Dacă C este o clasă fără un constructor definit, având un câmp x de tip întreg, scrieţi

instrucţiunile prin care se creează un obiect ob de tip C şi se afişează valoarea câmpului x al

obiectului ob.

3. Cum se numeşte posibilitatea de a exista mai mulţi constructori, respectiv mai multe metode

cu acelaşi nume, dar cu signaturi diferite? Exemplificaţi.

4. Ce afişează următorul program ? Justificaţi.

class Pereche{

int x, y;

Pereche (int x1, int y1){x=x1 ; y=y1 ;}

void afis(){ System.out.println(re+" "+im);}

}

class Doi{

void modific(int x){x=2;}

void modific(Pereche c){c.im=2;}

}

class M {

public static void main(String sir[]){

Doi d=new Doi();

Pereche c=new Pereche(5,6); c.afis();

d.modific(c.re); c.afis();

d.modific(c);c.afis();

}

}

Page 39: Programarea in Java - 2014 - an II ID.pdf

39

Teste de control

2.1 Declararea constructorilor trebuie sa tina cont de:

A. relatia de moștenire dintre clase;

B. numele constructorului, care trebuie sa fi identic cu numele clasei;

C. comportamentul obiectelor pe care le instantiaza;

D. o metoda prin care poate fi accesat de toate tipurile din Java sau de tipuri mostenite din tipul care

contine membrul in discutie;

2.2 Ce puteti spune despre urmatorul program Java? class C1{

int x=1;

void f(int x){

this.x=x;

}

int getX_C1(){

Return x;}}

Class C2 extens C1{

float x=5.0f;

int f(int x){

super.f((int)x);}

float getX_C2(){

return x;}}

public class Subiect9{

public static void main(String []args){

C2 obiect = new C2();

obiect.f(4);

System.out.print(obiect.getX_C2() + " ");

System.out.println(obiect.getX_C1());}}

A. Programul este corect si va afisa la executie 5 4;

B. Programul este corect si va afisa la executie 4.0 4;

C. Va aparea eroare la compilare deoarece in clasa C2 s-a suprascris gresit atributul x din clasa C1;

D. Va aparea eroare la compilare deoarece metoda suprascrisa f() din clasa C2 intoarce un tip diferit

de void;

2.3 Ce putet i spune despre urmatorul program Java?

public class Test{

public static void main(String []args){

C1 obiect =new C1();

obiect.f(4,3);

}}

class C1{

public void f(int xx, final int yy){

int a=xx+yy;

final int b=xx-yy;

class C2{

public void g(){

System.out.print("a= "+a);

System.out.print(", b= "+b);

}

}

Page 40: Programarea in Java - 2014 - an II ID.pdf

40

C2 obiect2 = new C2();

obiect2.g();}}

A. Programul este corect si va afisa la executie a=4, b=3;

B. Va aparea eroare la compilare, deoarece clasa C2 nu poate fi defnita in metoda f() din clasa C1;

C. Va aparea eroare la compilare deoarece in metoda g() nu putem accesa variabila locala a din

metoda f();

D. Va aparea eroare la compilare deoarece nu se creeaza in clasa Test un obiect de tip C1.C2

2.4 Ce putet»i spune despre urm¸atorul program Java? class C1{

int x=1;

void f(int x){

this.x=x;

}

int getX_C1(){

Return x;

}

}

Class C2 extens C1{

float x=5.0f;

int f(int x){

super.f((int)x);

}

float getX_C2(){

return x;

}

}

public class Subiect9{

public static void main(String []args){

C2 obiect = new C2();

obiect.f(4);

System.out.print(obiect.getX_C2() + " ");

System.out.println(obiect.getX_C1());

}}

A. Programul este corect si va afisa la executie 5 4;

B. Programul este correct si va afisa la executie 4.0 4;

C. Va aparea eroare la compilare deoarece in clasa C2 s-a suprascris gresit atributul x din clasa C1;

D. Va aparea eroare la compilare deoarece metoda suprascrisa f() din clasa C2 intoarce un tip diferit

de void;

Page 41: Programarea in Java - 2014 - an II ID.pdf

41

Formular de feedback

În dorinţa de ridicare continuă a standardelor desfăşurării activitatilor dumneavoastra, va rugăm să completaţi acest chestionar şi să-l

transmiteţi indrumatorului de an.

Disciplina: ________________________

Unitatea de invatare/modulul:__________________

Anul/grupa:__________________________

Tutore:_________________________

a) Conţinut / Metoda de predare

Partea I

1. Care dintre subiectele tratate in aceasta unitate/modul consideraţi că este cel mai util şi eficient? Argumentati raspunsul.

2. Ce aplicații/proiecte din activitatea dumneavoastra doriţi să imbunatatiti/modificaţi/implementaţi în viitor în urma cunoştinţelor

acumulate în cadrul acestei unitati de invatare/modul?

3. Ce subiecte consideraţi că au lipsit din acesta unitate de invatare/modul?

4. La care aplicații practice ati intampinat dificultati in realizare? Care credeti ca este motivul dificultatilor intalnite?

5. Daca ar fi sa va evaluati, care este nota pe care v-o alocati, pe o scala de la 1-10?. Argumentati.

Partea II. Impresii generale

1. Acest modul a întrunit aşteptările dumneavoastră?

2) Aveţi sugestii care să conducă la creşterea calităţii acestei unitati de invatare/modul?

3) Aveţi propuneri pentru alte unitati de invatare?

Vă mulţumim pentru feedback-ul dumneavoastră

În totalitate

În mare măsură În mică măsură Nu

Page 42: Programarea in Java - 2014 - an II ID.pdf

42

Unitatea de învăţare Nr. 3 Capitolul 3 Extinderea claselor. Polimorfismul in Java

Obiectivele Unităţii de învăţare nr. 3

3.1 Moștenirea - concept fundamental al programarii orientata obiect

Moștenirea este un mecanism care permite unei clase sa mosteneasca atributele si comportamentul

unei alte clase cu care este inrudita. Moștenirea modeleaza relatii de tipul ESTE-UN (sau ESTE-O).

Intr-o relatie de tip ESTE-UN, spunem despre o clasa nou creata ca ESTE-O variatiune a unei clase

existente (originala, din care provine). De exemplu, Masina ESTE-UN Vehicul.

Practic, prin moștenire o clasa noua dobandeste toate atributele si comportamentul unei clase

existente (clasa originala). Din acest motiv, noua clasa poate fi creata prin simpla specificare a

diferențelor fata de clasa originala din care provine.

Limbajul Java pune la dispoziţie şi o altă facilitate importantă legată de OOP (programarea

orientată pe obiecte): posibilitatea de extindere a claselor. Foarte pe scurt, deci incomplet şi nu în

întregime riguros, aceasta constă în:

- o clasă poate fi extinsă, adăugându-se noi câmpuri şi noi metode, care permit considerarea unor

atribute suplimentare (dacă ne gândim la câmpuri) şi unor operaţii noi (asupra câmpurilor "iniţiale",

dar şi asupra câmpurilor nou adăugate);

- unele metode ale clasei pe care o extindem pot fi redefinite, iar anumite câmpuri ale acestei clase

pot fi "ascunse";

- un obiect având ca tip clasa extinsă poate fi folosit oriunde este aşteptat un obiect al clasei care a

fost extinsă.

La prima vedere, rezolvarea problemelor de mai sus se poate face simplu: modificăm clasa,

introducând sau/şi modificând câmpurile şi metodele clasei. În practica programării, această soluţie

este de neconceput. Pe de o parte se pot introduce erori, iar pe de altă parte utilizatorii clasei vechi

nu vor mai putea folosi clasa aşa cum o făceau înainte şi cum vor în continuare să o facă, nefiind

Obiective:

După ce veţi parcurge această unitate de învăţare, veţi reuşi să:

cunoașteți tehnica de extindere a claselor;

vă insușiți noțiunile de superclasă și subclasă;

cunoașteți clasa Object;

implementați polimorfismul;

să definiți metode și clase abstracte;

Page 43: Programarea in Java - 2014 - an II ID.pdf

43

interesaţi de noile facilităţi; clasa (firma care a elaborat-o) îşi va pierde astfel vechii clienţi. De

aceea vechea clasă trebuie să rămână nemodificată, iar actualizarea ei trebuie făcută prin

mecanismul de extindere a claselor, prezentat în continuare.

Să reţinem deci ca o regulă generală de programare faptul că nu trebuie modificată o clasă testată şi

deja folosită de mulţi utilizatori; cu alte cuvinte, nu trebuie modificat "contractul" ce a dus la

scrierea clasei.

Să presupunem că dorim să urmărim mişcarea unui punct în plan. Vom începe prin a considera

clasa:

class Punct {

int x,y; Punct urm;

Punct(int x, int y) { this.x=x; this.y=y; }

void Origine() { x=0; y=0; }

Punct Miscare(int x, int y) {

Punct p = new Punct(x,y); urm=p; return p;

}

}

Clasa Punct conţine:

- câmpurile x, y, urm ;

- constructorul Punct cu signatura (int, int);

- metoda Origine cu signatura () şi metoda Miscare cu signatura (int,int).

Vom extinde clasa Punct astfel încât punctul să aibă şi o culoare:

class Pixel extends Punct {

String culoare;

Pixel(int x, int y, String culoare) {

super(x,y); this.culoare=culoare;

}

void Origine() { super.Origine(); culoare="alb"; }

}

Clasa Pixel conţine:

- câmpurile x,y,urm (moştenite de la clasa Punct) şi culoare (care a fost adăugat prin extindere);

- constructorul Pixel cu signatura (int,int,String);

- metoda Miscare cu signatura (int,int), moştenită de la clasa Punct, precum şi metoda Origine cu

signatura (), care redefineşte metoda Origine a clasei Punct.

Este adoptată următoarea terminologie: clasa Punct este superclasă a lui Pixel, iar Pixel este

subclasă (clasă extinsă) a lui Punct.

În Java, clasele formează o structură de arbore în care rădăcina este clasa Object, a cărei definiţie

apare în pachetul java.lang. Orice clasă extinde direct (implicit sau explicit) sau indirect clasa

Object. Ştim că în informatică arborii "cresc în jos", deci rădăcina (clasa Object) se află pe cel mai

de sus nivel.

Exemplu 1

Page 44: Programarea in Java - 2014 - an II ID.pdf

44

extindere, în arborele de clase. Este incorect de a interpreta aceşti termeni în sensul de incluziune!

În exemplul de mai sus, apelurile super.Origine() şi super(x,y) se referă respectiv la metoda Origine

şi la constructorul din superclasa Punct a lui Pixel. Vom reveni însă cu toate detaliile legate de

super.

Fie Sub o clasă ce extinde clasa Super. Sunt importante următoarele precizări:

- obiectele de tip Sub pot fi folosite oriunde este aşteptat un obiect de tipul Super. De exemplu dacă

un parametru al unei metode este de tipul Super, putem invoca acea metodă cu un argument de tipul

Sub;

- spunem că Sub extinde comportarea lui Super;

- o clasă poate fi subclasă a unei singure clase (moştenire simplă) deoarece, reamintim, clasele

formează o structură de arbore. Drept consecinţă o clasă nu poate extinde două clase, deci nu există

moştenire multiplă ca în alte limbaje (există însă mecanisme pentru a simula această facilitate şi

anume interfeţele);

- o metodă din superclasă poate fi rescrisă în subclasă. Spunem că metoda este redefinită (dacă nu

este statică) sau ascunsă (dacă este statică). Evident, ne referim aici la o rescriere a metodei folosind

aceeaşi signatură, pentru că dacă scriem în subclasă o metodă cu o signatură diferită de signaturile

metodelor cu acelaşi nume din superclasă, atunci va fi vorba de o metodă nouă. La rescriere nu

putem modifica tipul valorii întoarse de metodă. Accesul la metoda cu aceeaşi signatură din

superclasă se face, după cum vom vedea, prin precalificare cu super;

- un câmp redeclarat în Sub ascunde câmpul cu acelaşi nume din Super;

- câmpurile neascunse şi metodele nerescrise sunt automat moştenite de subclasă (în exemplul de

mai sus este vorba de câmpurile x şi y şi de metoda Miscare);

- apelurile super din constructorii subclasei trebuie să apară ca primă acţiune.

3.2 Caracteristicile unei ierarhi de clase

Organizarea unei aplicații informatice intr-o ierarhie de clase presupune o planificare atenta.

Proiectarea arborelui de clase de obiecte necesare rezolvarii unei anumite probleme este un talent pe

care fiecare programator trebuie sa si-l descopere si sa si-l cultive cu atentie. De alegerea claselor si

de proiectarea arborelui acestor clase depinde eficienta si flexibilitatea aplicației.

Principalele caracteristici ale unei ierarhie de clase sunt:

atributele si metodele comune mai multor clase pot fi definite in superclase, care permit

folosirea repetata a acestora pentru toate clasele aflate pe nivelele mai joase din ierarhie;

modificarile efectuate in superclasa se reflecta automat in toate subclasele ei, subclasele

acestora si asa mai departe; nu trebuie modificat si recompilat nimic in clasele aflate pe

nivelurile inferioare, deoarece acestea primesc noile informatii prin moștenire;

clasa derivata poate sa adauge noi atribute si metode si poate modifica semnificatia

metodelor mostenite (prin polimorfism, despre care vom vorbi mai incolo in acesta lectie);

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

o clasa derivata este compatibila ca tip cu superclasa, ceea ce inseamna ca o variabila

referinta de tipul superclasei poate referi un obiect al clasei derivate, dar nu si invers; clasele

derivate dintr-o superclasa nu sunt compatibile ca tip.

Page 45: Programarea in Java - 2014 - an II ID.pdf

45

3.3 Rescrierea metodelor şi ascunderea câmpurilor

Câmpurile pot fi ascunse prin redeclararea lor într-o subclasă. Câmpul cu acelaşi nume din

superclasă nu mai poate fi accesat direct prin numele său, dar ne putem referi la el folosind super

(vezi subcapitolul următor) sau o referinţă la tipul superclasei.

O metodă declarată într-o clasă poate fi rescrisă într-o subclasă prin declararea ei în subclasă cu

acelaşi nume, aceeaşi signatură şi acelaşi tip al valorii întoarse.

În metoda rescrisă putem schimba modificatorul de acces, cu condiţia ca dreptul de acces să

crească; reamintim că modificatorii de acces, în ordine de la cel mai restrictiv la cel mai permisiv,

sunt: private, protected, cel implicit (package) şi public.

Spunem că metodele rescrise sunt ascunse (dacă e vorba de metode statice) sau redefinite (în cazul

metodelor nestatice). Nu este vorba numai de o diferenţă de terminologie, deoarece metodele statice

pot fi rescrise (ascunse) numai de metode statice, iar metodele nestatice pot fi rescrise (redefinite)

numai de metode nestatice. Alte precizări vor fi făcute în continuare.

Fie A o clasă şi fie B o subclasă a sa. Să considerăm următoarele patru acţiuni echivalente din

punctul de vedere al obiectului a ce ia naştere:

1) A a; a = new B(...);

2) A a = new B(...);

3) A a; B b; b = new B(...); a = b;

4) A a; B b; b = new B(...); a = (A) b;

Să observăm că este vorba de o conversie de la o subclasă la o superclasă, conversie numită

upcasting ; ea poate fi implicită (ca în primele trei acţiuni) sau explicită (ca în cea de a patra

acţiune).

Vom spune că obiectul a are tipul declarat A şi tipul real B, ceea ce pune în evidenţă noţiunea de

polimorfism.

Tipul real al unui obiect coincide cu tipul său declarat (este cazul obiectului b) sau este o subclasă a

tipului declarat (vezi obiectul a).

Fie camp un câmp al clasei A, ce este redeclarat (ascuns) în subclasa B. Dacă obiectul a face

referire la câmpul camp, atunci este vorba de câmpul declarat în clasa A, adică este folosit tipul

declarat al obiectului.

Fie met o metodă a clasei A, care este rescrisă în subclasa B. La invocarea metodei met de către

obiectul a, este folosită fie implementarea corespunzătoare metodei ascunse (dacă este statică), fie

cea corespunzătoare metodei redefinite (dacă este nestatică). Cu alte cuvinte, pentru metode statice

este folosit tipul declarat (la fel ca pentru câmpuri), iar pentru metode nestatice este folosit tipul real

al obiectului. În ambele cazuri, se pleacă de la tipul indicat mai sus şi se merge în sus spre rădăcină

(clasa Object) în arborele de clase până când se ajunge la primul tip în care apare metoda respectivă

(evident cu signatura corespunzătoare); inexistenţa unui astfel de tip este semnalată chiar în faza de

compilare.

Page 46: Programarea in Java - 2014 - an II ID.pdf

46

Următorul program:

class Super {

static void met1() { System.out.println("static_Super"); }

void met2() { System.out.println("Super"); } } class Sub extends Super { static void

met1() { System.out.println("static_Sub"); } void met2() { System.out.println("Sub"); } }

class Test1 {

public static void main(String[] s) {

Super Ob = new Sub(); Ob.met1(); Ob.met2();

}

}

produce la ieşire:

static_Super

Sub

Considerăm o nouă formă a claselor din Exemplul 2:

class A {

int va=1, v;

A() { v=va; System.out.print(""+met()); }

int met() { return va; }

}

class B extends A {

int vb=2, v;

B() { v=va+vb; }

int met() { return vb; }

}

class Constr {

public static void main (String[] s) {

A a = new B(); System.out.println("\t"+a.met());

}

}

Rezultatele tipărite de programul de mai sus sunt 0 şi 2, deoarece:

- la invocarea metodei met din cadrul constructorului clasei A este folosit tipul real al obiectului,

adică este întors rezultatul furnizat de metoda met redeclarată în B; la momentul invocării, valoarea

curentă a lui vb este 0 (vezi subcapitolul precedent).

- invocarea metodei met în metoda principală, realizată de obiectul a, se va referi tot la metoda met

din clasa B.

Dacă însă în clasa B am înlocui declararea int vb=2 a lui vb prin:

static int vb=1;

Exemplu 2

Exemplu 3

Page 47: Programarea in Java - 2014 - an II ID.pdf

47

static { vb=2; }

atunci la ieşire vor apărea numerele 2 şi 2.

Să considerăm următorul program:

class A {

String s="Super";

void scrie() { System.out.println("A : "+s); }

}

class B extends A {

String s="Sub";

void scrie() { System.out.println("B : "+s); }

}

class AB1 {

public static void main(String[] s) {

B b = new B(); A a = b;

a.scrie(); b.scrie();

System.out.println(a.s + "\t" + b.s);

}

La executare sunt tipărite următoarele:

B : Sub

B : Sub

Super Sub

adică rezultatele aşteptate, ţinând cont că:

- pentru obiectul b: tipul declarat coincide cu cel real şi este B;

- pentru obiectul a: tipul declarat este A, iar tipul real este B.

Să considerăm o clasă C şi două subclase X şi Y ale sale, precum şi următoarea secvenţă de

instrucţiuni:

C Ob;

. . . Ob = new X(...);

. . . Ob = new C(...);

. . . Ob = new Y(...);

. . .

în care Ob are mai întâi tipul real X, apoi tipul real C, apoi tipul real Y. Spunem că Ob este o

variabilă polimorfică, deoarece are pe rând forma (comportamentul) a mai multor clase.

Din exemplul de mai sus rezultă clar că doar la momentul executării putem determina necesarul de

memorie pentru obiectul Ob, ceea ce justifică de ce la creare obiectele sunt "stocate" în heap-ul

memoriei. Mai precis, la crearea unui obiect este alocat spaţiu pentru toate câmpurile nestatice din

clasă, inclusiv pentru cele ascunse.

Exemplu 4

Page 48: Programarea in Java - 2014 - an II ID.pdf

48

3.4 Metode-constructor pentru clase derivate si cuvantul-cheie super

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

metode-constructor.

Daca nu se defineste nici un constructor, Java va genera un constructor implicit (fara parametri).

Acest constructor implicit al clasei derivate:

- va apela automat constructorul implicit (fara parametrii) al superclasei (aflata pe nivelul imediat

superior) pentru membrii care au fost mosteniti, apoi

- va aplica initializarea implicita pentru atributele adaugate in clasa derivata (adica 0/false pentru

tipurile primitive numerice/booleene si null pentru tipurile referinta).

Asadar, construirea unui obiect al unei clase derivate are loc prin construirea prealabila a portiunii

mostenite (constructorul clasei derivate apeleaza automat constructorul superclasei aflata pe nivelul

imediat superior). Acest lucu este normal, deoarece mecanismul incapsularii afirma ca partea

mostenita este un “intreg”, iar constructorul superclasei ne spune cum sa initializam acest “intreg”.

Metodele-constructor ale superclasei pot fi apelate explicit in clasa derivata prin metoda super().

Metoda super poate sa apara doar in prima linie dintr-o metoda-constructor.

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

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

unde:

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

De exemplu, sa presupunem ca o superclasa (ClasaSuper) are un constructor cu doi parametri de tip

int. Constructorul clasei derivate va avea, in general, forma:

public class ClasaDerivata extends ClasaSuper

{

public ClasaDerivata(int x, int y);

{

super(x, y);

// alte instructiuni

}

}

Observatie: Daca in superclasa este definit explicit cel putin un constructor, atunci trebuie apelat

explicit (prin super) constructorul superclasei respective din interiorul constructorului clasei

derivate. Altfel se obtine eroare de compilare.

Programul următor:

class A {

String s="Super";

void scrie() { System.out.println("A : "+s); }

void metoda() { System.out.println("A:"); }

}

class B extends A {

Exemplu 5

Page 49: Programarea in Java - 2014 - an II ID.pdf

49

String s="Sub";

void scrie() { System.out.println("B : "+s+" "+super.s); }

void metoda() { scrie(); super.scrie(); super.metoda(); }

}

class AB2 {

public static void main(String[] x) {

B b = new B(); b.metoda(); System.out.println(b.s);

System.out.println("****************");

A a; a = b; a.metoda(); System.out.println(a.s);

System.out.println("****************");

A c = new A(); c.metoda(); System.out.println(c.s);

}

}

produce la ieşire următorul rezultat:

B : Sub Super

A : Super

A:

Sub

****************

B : Sub Super

A : Super

A:

Super

****************

A:

Super

Sunt incorecte, neîncadrându-se în formele prezentate mai sus de folosire a lui super, construcţii de

forma b.super.metoda() (care ar intenţiona ca pentru obiectul b să invocăm metoda metoda din

superclasa clasei de tipul căreia este) sau urcarea mai multor niveluri în arborele de clase prin

super.super. Pentru a avea acces la un câmp ascuns aflat cu două niveluri mai sus în arborele de

clase putem proceda de pildă ca în exemplul următor.

3.5 Implementarea polimorfismului

Polimorfismul reprezinta capacitatea unui obiect de a aparea sub diferite forme. De exemplu, in

lumea reala, apa apare sub forma solida, sub forma lichida sau sub forma gazoasa.

In Java, polimorfismul inseamna ca o singura variabila referinta x de tipul unei superclase poate fi

folosita pentru a construi diferite obiecte (instante) ale claselor derivate, direct sau indirect din acea

superclasa, in momente diferite ale executiei unui program. Cand variabila referinta x este folosita

pentru a apela o metoda a unui obiect apartinand unei clase derivate, metoda adecvata care va fi

selectata depinde de tipul obiectului pe care variabila referinta x il indica in acel moment. Se spune

ca variabila referinta este polimorfica.

Page 50: Programarea in Java - 2014 - an II ID.pdf

50

De exemplu, sa presupunem ca s-au definit clasele: AnimalDeCasa, Pisica, Caine. Se doreste sa se

afiseze la ecran (programul Polimorfism.java) caracteristicile principale ale claselor Pisica și Caine,

atunci cand instantele lor sunt infometate.

class AnimalDeCasa

{

private boolean stareSuparare;

public boolean flamand;

protected void hranesc() {

System.out.println("Nu se cunoaste");

}

public void caracteristici() {

System.out.println("Caracteristici necunoscute");

}

public boolean getStare() {

return stareSuparare;

}

public void setStare(boolean stare) {

stareSuparare = stare;

}

}

class Pisica extends AnimalDeCasa

{

public void caracteristici() {

String starePisica;

if (getStare() == true)

starePisica = "miauna";

else

starePisica = "nu miauna";

if (flamand == true)

System.out.println("Pisica " + starePisica + ". Este flamanda.");

else

System.out.println("Pisica " + starePisica + ". Este satula.");

}

public void hranesc() {

if (flamand==true)

{System.out.println("Pisica mananca lapte.");

flamand = false;

setStare(false);}

else

System.out.println("Pisica a mancat deja.");}

}

class Caine extends AnimalDeCasa

{

public void caracteristici()

Exemplu 6

Page 51: Programarea in Java - 2014 - an II ID.pdf

51

{

String stareCaine;

if (getStare() == true)

stareCaine = "latra";

else

stareCaine = "nu latra";

if (flamand == true)

System.out.println("Cainele " + stareCaine + ". Este flamand.");

else

System.out.println("Cainele " + stareCaine + ". Este satul.");

}

public void hranesc() {

if (flamand==true)

{System.out.println("Cainele mananca oase.");

flamand = false;

setStare(false);}

else

System.out.println("Cainele a mancat deja.");}

}

public class Polimorfism

{

public static void main(String args[]) {

AnimalDeCasa a = new Pisica(); a.flamand = true;

a.setStare(true);

System.out.println("Caracteristicile primului animal de casa: ");

a.caracteristici();

a.hranesc();

a.caracteristici();

a.hranesc();

a.caracteristici();

a = new Caine(); a.flamand = true;

a.setStare(true);

System.out.println("Caracteristicile celui de al doilea animal de casa: ");

a.caracteristici();

a.hranesc();

a.caracteristici(); }

}

Ceeace este specific acestui program este ca el contine trei metode cu numele caracteristici() care

au aceiași semnatura (nume, tip valoare returnata și numar și tip parametrii) și trei metode cu

numele hranesc() care au, de asemenea, aceeași semnatura. Dar, aceste metode se afla in clase

diferite și anume, intr-o superclasa numita AnimalDeCasa și in doua clase derivate numite Pisica și

Caine care extind clasa AnimalDeCasa.

Spunem ca metodele caracteristici() și hranesc() din clasele derivate redefinesc (override)

metodea caracteristici() și, respectiv, hranesc() din superclasa.

Sa analizam acum instrucțiunea urmatoare:

Page 52: Programarea in Java - 2014 - an II ID.pdf

52

AnimalDeCasa a = new Pisica(); Variabila referinta a care este de tipul AnimalDeCasa desemneaza un obiect de tipul Pisica, care

ESTE-UN AnimalDeCasa prin moștenire.

Sa analizam și instrucțiunea:

a = new Caine();

Variabila a refera (la momente diferite de timp) obiecte de tipuri diferite, dar similare (adica

derivate din aceiași superclasa: AnimalDeCasa).

In concluzie: - pe de o parte, moștenirea permite tratarea unui obiect ca fiind de tipul propriu sau de tipul de baza

(din care este derivat tipul propriu). Aceasta caracteristica permite mai multor tipuri (derivate din

acelasi tip de baza) sa fie tratate ca si cum ar fi un singur tip, ceea ce face ca aceiași secventa de cod

sa fie folosita de către toate aceste tipuri. In cazul din exemplul prezentat, clasa Pisica si clasa

Caine au doua atribute (stareSuparare si flamand) si doua metode setStare() si getStare() mostenite

de la superclasa AnimalDeCasa din care deriva.

- pe de alta parte, polimorfismul permite unui tip de obiect sa exprime distinctia fata de un alt tip de

obiect similar, atata timp cat amandoua sunt derivate din aceiași superclasa. Distinctia este

exprimata prin redefinirea (suprascrierea) metodelor care pot fi apelate prin intermediul unei

variabile-referinta de tipul superclasei (in exemplul nostru este vorba despre metodele

caracteristici() si hranesc()).

Legarea statica si legarea dinamica

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

Cand legarea are loc inainte de rularea programului respectiv (adica, in faza de compilare) spunem

ca este vorba despre o legare statica(early binding). Termenul este specific programarii orientate pe

obiecte. In programarea procedurala (vezi limbajul C sau Pascal) notiunea de legare statica nu

exista, pentru ca toate legaturile se fac in mod static.

Cand legarea are loc in faza de executie a programului respectiv, spunem ca este vorba despre o

legare tarzie (late binding) sau legare dinamica. Legarea tarzie permite determinarea in faza de

executie a tipului obiectului referit de o variabila referinta si apelarea metodei specifice acestui tip

(in exemplul prezentat, metodele caracteristici() si hranesc() din clasa Pisica sau din clasa Caine).

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

3.6 Metode si clase abstracte

O metoda abstracta este o metoda din superclasa care are sens doar pentru clasele derivate direct

din superclasa, nu are implementare (nu are corp) ci numai antet, in superclasa si care in mod

obligatoriu trebuie definita (completata cu corpul ei) in clasele derivate (altfel rezulta eroare de

compilare).

O metoda abstracta este declarata cu modificatorul abstract.

Intr-o ierarhie de clase, cu cat clasa se afla pe un nivel mai inalt, cu atat definirea sa este mai

abstracta. O clasa aflata ierarhic deasupra altor clase poate defini doar atributele si comportamentul

comune celor aflate sub ea pe ramura respectiva a ierarhiei.

In procesul de organizare a unei ierarhi de clase, se poate descoperi, uneori, cate o clasa care nu se

instantiaza direct (adica din ea nu se pot crea direct obiecte). De fapt, aceasta serveste, doar ca loc

de pastrare a unor metode si atribute pe care le folosesc in comun subclasele sale. Acesta clasa se

numeste clasa abstracta si este creata folosind modificatorul abstract.

Page 53: Programarea in Java - 2014 - an II ID.pdf

53

Clasele abstracte pot contine aceleasi tipuri de membri ca o clasa normala, inclusiv metodele-

constructor, deoarece subclasele lor pot avea nevoie sa mosteneasca aceste metode-constructor.

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

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

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

Un exemplu simplu de clasa abstracta este clasa formelor geometrice. Din clasa formelor

geometrice pot deriva forme specifice cum ar fi: cerc, dreptunghi. Se poate, apoi, deriva clasa

patratului ca un caz particular de dreptunghi. Figura de mai jos prezinta ierarhia de clase care

rezulta:

Clasa FormaGeo poate sa aiba membri care sa fie comuni pentru toate subclasele, cum ar fi, de

exemplu tipul formei geometrice, afisarea caracteristicilor formelor geometrice concrete (cerc,

dreptunghi etc).

De asemenea, clasa poate defini metode care se aplica fiecarui obiect in parte, cum ar fi, calculul

ariei unui obiect oarecare (dreptunghi, cerc etc). In consecinta, metoda arie() va fi declarata ca

abstracta.

Clasa FormaGeo fiind abstracta nu se poate instantia. Deci, nu se va putea crea un obiect de tip

FormaGeo, ci numai obiecte din clasele derivate. Totusi, o referinta de tip FormaGeo poate sa

refere orice forma concreta derivata, cum ar fi: Dreptunghi, Cerc, Patrat.

Fisierul-sursa urmator (FormaGeo.java) prezinta clasa abstracta FormaGeo. Constructorul acestei

clase nu va fi apelat niciodata direct, deoarece FormaGeo este o clasa abstracta. Avem totusi nevoie

de constructor, care sa fie apelat din clasele derivate pentru a initializa atributul nume de tip private

care specifica tipul figurii geometrice.

Metoda cu numele arie() este o metoda abstracta, deoarece nu putem furniza nici un calcul implicit

al ariei pentru o clasa derivata care nu isi defineste propria metoda de calcul a ariei.

Metoda maiMic() de comparatie a ariei unui obiect curent de tip FormaGeo cu un alt obiect de tip

FormaGeo (preluat prin parametrul rhs) nu este abstracta, deoarece ea poate fi aplicata la fel pentru

toate clasele derivate. De fapt, definirea ei este invarianta de-a lungul ierarhiei, de aceea am

declarat-o cu tipul final.

Variabila rhs poate sa refere orice instanta a unei clase derivate din FormaGeo (de exemplu, o

instanta a clasei Dreptunghi). Astfel, este posibil sa folosim aceasta metoda pentru a compara aria

obiectului curent (care poate fi, de exemplu, o instanta a clasei Cerc) cu aria unui obiect de alt tip,

derivat din FormaGeo. Acesta este un exemplu de folosire a polimorfismului.

Page 54: Programarea in Java - 2014 - an II ID.pdf

54

Metoda toString afiseaza numele formei geometrice si aria ei. Ea este invarianta de-a lungul

ierarhiei si de aceea a fost declarata cu tipul final.

Observatie: Vom face cateva precizari asupra folosirii metodei toString() in orice clasa in care se

doreste afisarea starii instantelor unei clase. In general, afisarea starii unui obiect se face utilizand

metoda print() din clasa System.out. Pentru a putea face acest lucru, trebuie ca in clasa obiectului

care se doreste a fi afisat sa existe o metoda cu numele de toString(). Aceasta metoda trebuie sa

intoarca o valoare de tip String (reprezentand starea obiectului) care poate fi afisata. Astfel, in cazul

nostru, am definit o metoda toString care permite sa afisam un obiect oarecare de un tip derivat din

clasa FormaGeo folosind instrucțiunea System.out.println(). Practic, compilatorul Java apeleaza

automat toString() pentru fiecare obiect care se afiseaza cu metoda print().

abstract class FormaGeo {

private String nume;

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

nume = numeForma;

}

final public boolean maiMic(FormaGeo rhs) {

return arie() < rhs.arie();

}

final public String toString() {

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

}

}

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

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

formele geometrice ordonate dupa arie.

Mai intai, trebuie sa definim subclasele Cerc, Dreptunghi si Patrat. Definirea lor se face distinct in

fisiere-sursa separate (Cerc.java, Dreptunghi.java si Patrat.java).

public class Cerc extends FormaGeo {

private double raza; public Cerc(double rad) {

super("Cerc");

raza = rad;

}

public double arie() {

return Math.PI * raza * raza;}

}

public class Dreptunghi extends FormaGeo {

private double lungime;

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

this(lg, lat, "Dreptunghi");

}

Exemplu 7

Page 55: Programarea in Java - 2014 - an II ID.pdf

55

Dreptunghi(double lg, double lat, String nume) {

super(nume);

lungime = lg;

latime = lat;

}

public double arie() {

return lungime * latime;

}

}

/* clasa Patrat

* derivata din Dreptunghi

* CONSTRUCTORI: cu latura ptr. patrat

* ------------------- metode publice ---------------------

* double arie()-->Implementeaza metoda abstracta din FormaGeo

*/

public class Patrat extends Dreptunghi

{

public Patrat(double latura) {

super(latura, latura, "Patrat");

}

}

Observatie: Clasa Patrat mosteneste de la clasa Dreptunghi metoda arie() si de aceea nu o mai

defineste in interiorul ei.

Pentru rezolvarea problemei ordonarii formelor geometrice dupa aria lor, se foloseste un tablou de

tip FormaGeo cu numele forme[] cu o dimensiune citita de la tastatura. Sa retinem ca tablou

forme[] este un tablou de referinte de tip FormaGeo pentru care se aloca zona de memorie. Acest

tablou nu stocheaza obiecte din clasele derivate ale clasei FormaGeo (de tip Cerc, Dreptunghi,

Patrat) ci numai referinte către aceste obiecte.

Fisierul-sursa (TestForma.java) care realizeaza ordonarea si punerea in executie a aplicației se

prezinta in continuare.

Metoda citesteForma() citeste de la tastatura atributele obiectelor de tipul Cerc, Dreptunghi, Patrat,

pe baza unor optiuni care precizeaza tipul figurii, creaza un nou obiect de un tip derivat (Cerc,

Dreptunghi, Patrat) din tipul FormaGeo si returneaza o referinta către obiectul creat.

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

Metoda sortare() este folosita pentru a sorta formele geometrice referite prin tabloul forme[] in

functie de aria calculata a fiecarui tip de figura geometrica. Metoda arie() este apelata prin

intermediul metodei maiMic() care la randul ei este apelata in metoda sortare().

import java.io.* ;

class TestForma {

private static BufferedReader in;

public static void main(String[] args) throws IOException {

//Citeste numarul de figuri

in = new BufferedReader(new

InputStreamReader(System.in));

System.out.print("Numarul de figuri: ");

int numForme = Integer.parseInt(

in.readLine());

//citeste formele

FormaGeo[] forme = new FormaGeo[numForme];

Page 56: Programarea in Java - 2014 - an II ID.pdf

56

for (int i = 0; i < numForme; ++i)

{forme[i] = citesteForma();}

//sortare si afisare

sortare(forme); System.out.println("Sortarea dupa arie: ");

for (int i = 0; i < numForme; ++i)

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

}

//creaza un obiect adecvat de tip FormaGeo. Functie de datele de intrare.

//utilizatorul introduce 'c', 'p' sau 'd' pentru a indica forma, apoi introduce dimensiunile

//in caz de eroare se intoarce un cerc de raza 0

private static FormaGeo citesteForma() throws IOException {

double rad;

double lg;

double lat;

String s;

System.out.println("Introduceti tipul formei: ");

do

{

s = in.readLine();

} while (s.length() == 0);

switch (s.charAt(0))

{

case 'c':

System.out.println("Raza cercului: ");

rad = Integer.parseInt(in.readLine());

return new Cerc(rad); case 'p':

System.out.println("Latura patratului: ");

lg = Integer.parseInt(in.readLine());

return new Patrat(lg); case 'd':

System.out.println("Lungimea si latimea "

+ " dreptunghiului pe linii separate: ");

lg = Integer.parseInt(in.readLine());

lat= Integer.parseInt(in.readLine());

return new Dreptunghi(lg, lat); default:

System.err.println("Tastati c, p sau d: ");

return new Cerc(0); }

}

//sortare

private static void sortare(FormaGeo [] a) {

FormaGeo temp;

for (int i = 0; i <= a.length - 2; i++)

{for (int j = i+1; j <= a.length - 1; j++)

{if (a[j].maiMic(a[i]))

{temp = a[i];

a[i] = a[j];

a[j] = temp;}

Page 57: Programarea in Java - 2014 - an II ID.pdf

57

}}

}

}

Dupa executia programului TestForma.class pe ecran se afiseaza:

Sortarea dupa arie:

Cerc, avand aria 3.141592653589793

Dreptunghi, avand aria 6.0

Dreptunghi, avand aria 8.0

Dreptunghi, avand aria 24.0

Patrat, avand aria 36.0

Cerc, avand aria 78.53981633974483

Patrat, avand aria 100.0

Cerc, avand aria 314.1592653589793

Cerc, avand aria 452.3893421169302

Cerc, avand aria 452.3893421169302

Page 58: Programarea in Java - 2014 - an II ID.pdf

58

Testul de autoevaluare nr. 3

1. Care este clasa moştenită direct sau indirect de orice clasa în Java?

2. Sub ce forme poate fi folosit cuvâtul cheie super ?

3. Ce afişează programul următor ? Justificaţi. class Unu{

int x;

Unu(int x){this.x=x; afis();}

void afis(){ System.out.println(x);}

void dublu(){x*=2;}

static void nume(){System.out.println("Unu");}

}

class Doi extends Unu{

int y;

Doi(int x,int y){

super(x); this.y=y; afis();

}

void afis(){ System.out.println(x+" "+y);}

void dublu(){

super.dublu();

y*=2;

}

static void nume(){System.out.println("Doi");}

}

class Test{

public static void main(String sir[]){

Doi d=new Doi(4,5);

d.dublu(); d.afis();

Unu u=(Unu)d;

u.dublu(); u.afis();

d.afis();

u.nume();d.nume();

}

}

Page 59: Programarea in Java - 2014 - an II ID.pdf

59

Tema de autoinstruire nr. 1

Consultaţi bibliografia pentru afla despre:

1. alte exemple legate de moştenire, rescrierea câmpurilor şi ascunderea metodelor.

2. metode existente în clasa Object (toString, equals) şi la ce pot fi folosite acestea.

3. informaţii complete despre modificatorii de acces

Teste de control:

3.1 Ce puteti spune despre urmatorul program Java? class C1{

int x=1;

void f(int x){

this.x=x;}

int getX_C1(){

Return x;}}

Class C2 extens C1{

float x=5.0f;

int f(int x){

super.f((int)x);}

float getX_C2(){

return x;}}

public class Test{

public static void main(String []args){

C2 obiect = new C2();

obiect.f(4);

System.out.print(obiect.getX_C2() + " ");

System.out.println(obiect.getX_C1());}}

A. Programul este corect si va afisa la executie 5 4;

B. Programul este correct si va afisa la executie 4.0 4;

C. Va aparea eroare la compilare deoarece in clasa C2 s-a suprascris gresit atributul x din clasa C1;

D. Va aparea eroare la compilare deoarece metoda suprascrisa f() din clasa C2 intoarce un tip diferit

de void;

3.2 O subclasa a unei clase abstracte poate fi instantiata numai daca:

A. Se foloseste cuvantul cheie abstract;

B. Suprascrie fiecare metoda declarata abstracta in superclasa sa, si furnizeaza implementari pentru

toate acestea;

C. Se foloseste moștenirea multipla;

D. O subclasa abstracta nu poate fi instantiata;

Page 60: Programarea in Java - 2014 - an II ID.pdf

60

Formular de feedback

În dorinţa de ridicare continuă a standardelor desfăşurării activitatilor dumneavoastra, va rugăm să completaţi acest chestionar şi să-l

transmiteţi indrumatorului de an.

Disciplina: ________________________

Unitatea de invatare/modulul:__________________

Anul/grupa:__________________________

Tutore:_________________________

a) Conţinut / Metoda de predare

Partea I

1. Care dintre subiectele tratate in aceasta unitate/modul consideraţi că este cel mai util şi eficient? Argumentati raspunsul.

2. Ce aplicații/proiecte din activitatea dumneavoastra doriţi să imbunatatiti/modificaţi/implementaţi în viitor în urma cunoştinţelor

acumulate în cadrul acestei unitati de invatare/modul?

3. Ce subiecte consideraţi că au lipsit din acesta unitate de invatare/modul?

4. La care aplicații practice ati intampinat dificultati in realizare? Care credeti ca este motivul dificultatilor intalnite?

5. Daca ar fi sa va evaluati, care este nota pe care v-o alocati, pe o scala de la 1-10?. Argumentati.

Partea II. Impresii generale

1. Acest modul a întrunit aşteptările dumneavoastră?

2) Aveţi sugestii care să conducă la creşterea calităţii acestei unitati de invatare/modul?

3) Aveţi propuneri pentru alte unitati de invatare?

Vă mulţumim pentru feedback-ul dumneavoastră

În totalitate

În mare măsură În mică măsură Nu

Page 61: Programarea in Java - 2014 - an II ID.pdf

61

Unitatea de învăţare Nr. 4

INTERFEȚE JAVA

Obiectivele Unităţii de învăţare nr. 4

4.1 Metode şi clase abstracte

Se întâmplă frecvent ca atunci când lucrăm cu clase extinse, pentru o clasă să nu putem preciza

implementarea unei metode, deoarece în subclasele sale ea va fi specifică fiecăreia dintre ele.

Atunci metodele din această categorie vor fi marcate cu cuvântul cheie abstract şi se vor reduce la

antetul lor; în acelaşi timp şi clasa trebuie însoţită de atributul abstract. Fiecare metodă abstractă

trebuie implementată, adică (re)definită în orice subclasă care nu este la rândul său abstractă.

Nu este posibil să creăm obiecte ca instanţe ale unei clase abstracte. Pe de altă parte, într-o subclasă

putem să redefinim o metodă a superclasei transformând-o într-o metodă abstractă; aceasta are sens

de exemplu dacă în subarborele având ca rădăcină subclasa, comportamentul materializat prin acea

clasă nu mai este valabil în subarbore şi este specific fiecărei extensii a subclasei.

Următoarea clasă are ca scop să măsoare timpul necesitat de executarea unei metode oarecare

fără parametri şi care nu întoarce vreun rezultat:

abstract class C {

abstract void met();

public long timp() {

long t0 = System.currentTimeMillis();

met();

return System.currentTimeMillis()-t0;

}

}

Obiective:

După ce veţi parcurge această unitate de învăţare, veţi reuşi să:

creați interfețe Java;

să utilizați interfețe predefinite și pe cele create;

să implementați componente generice;

inţelegeţi diferenţa dintre clase abstracte şi interfeţe

Exemplu 1

Page 62: Programarea in Java - 2014 - an II ID.pdf

62

unde a fost folosită metoda statică currentTimeMillis() a clasei System, metodă care întoarce

timpul curent în milisecunde. Într-o clasă ce extinde C, se poate redefini metoda met şi apoi,

folosind un obiect ce este o instanţiere a noii clase, putem apela metoda timp pentru a determina

timpul de executare a metodei met, ce are acum o implementare precisă:

class C1 extends C {

void met () {

int x=0;

for (int i=0; i<1000000; i++) x=x+1-1;

}

}

class Abstr {

public static void main(String[] s) {

C1 Ob = new C1();

System.out.println( "durata="+Ob.timp() );

}

}

Legat de exemplul de mai sus, nu trebuie să ne mire că e posibil ca la executări diferite să obţinem

timpi diferiţi: aceasta este o consecinţă a faptului că pe perioada executării programului nostru

sistemul gazdă "mai face şi altceva", sau că a intervenit colectorul de reziduuri.

4.2 Crearea si folosirea interfețelor Java

Aşa cum s-a menţionat anterior, este posibil să declarăm clase abstracte în care toate metodele sunt

abstracte. Acest lucru poate fi realizat şi prin intermediul interfeţelor. În plus, aşa cum vom vedea în

continuare, ele reprezintă mecanismul propus de Java pentru tratarea problemelor ridicate de

moştenirea multiplă.

Moştenirea multiplă este facilitatea oferită de unele limbaje de programare ca o clasă să

moştenească (prin extindere) membri ai mai multor clase. Evident, această caracteristică importantă

a programării orientate pe obiecte nu este neglijată în Java. Modul în care această facilitate poate fi

implementată în Java va fi tratat în continuare.

Interfeţele reprezintă o modalitate de a declara un tip constând numai din constante şi din metode

abstracte. Ca sintaxă, o interfaţă este asemănătoare unei clase, cu deosebire că în loc de class trebuie

precizat interface, iar metodele nu au corp, acesta fiind înlocuit cu ';'.

Putem spune că interfeţele reprezintă numai proiecte, pe când clasele sunt o combinaţie de proiecte

şi implementări.

Ca şi în cazul claselor abstracte, este evident că nu pot fi create obiecte de tipul unei interfeţe.

Câmpurile unei interfeţe au în mod implicit modificatorii static şi final, deci sunt constante.

Metodele interfeţelor sunt totdeauna publice şi au în mod implicit modificatorul abstract. În plus ele

nu pot fi statice, deoarece fiind abstracte, nu pot fi specifice claselor.

Orice interfaţă este gândită pentru a fi ulterior implementată de o clasă, în care metodele interfeţei

să fie redefinite, adică să fie specificate acţiunile ce trebuie întreprinse. Faptul că o clasă C

implementează o interfaţă I trebuie specificat prin inserarea informaţiei implements I în antetul

clasei.

Page 63: Programarea in Java - 2014 - an II ID.pdf

63

Sintaxa de definire a unei interfețe este urmatoarea:

[<modificatori] interface <nume_interfata> [extends <nume_interfata1> [, <nume_interfata2>][,

<nume_interfata3>], …]]

{

<corpul interfetei>

}

unde:

- <modificatori> - sunt specificati prin cuvintele-cheie public si abstract; o interfata publica poate fi

accesata si de alte pachete decat cel care a definit-o; fiecare interfata este in mod implicit abstracta

deci cuvantul-cheie abstract poate lipsi;

- <nume_interfata> - specifica numele interfeței; este de preferat ca numele interfeței sa respecte

aceiași conventie de numire ca si cea de numire a claselor;

- <nume_interfata1>, <nume_interfata2>, .. - specifica numele superinterfețelor din care poate

deriva interfata;

- <corpul_clasei> - contine declaratii de variabile si declaratii de metode (numai antetul acestora).

Interfețele, ca si clasele, pot apartine unui pachet daca se foloseste instrucțiunea package in prima

linie din fisierul-sursa. De asemenea, interfețele pot importa interfețe sau clase din alte pachete.

Un exemplu de interfata este Compara, prezentata mai jos:

/* INTERFATA folosita de mai multe clase pentru comparatii

* --------------------Metode publice---------------

* int comparaCu --> Compara doua obiecte de tip Compara

* metoda trebuie definita in clasa care o implementeaza

*/

package clasegenerice;

public interface Compara {

int comparaCu(Compara rhs); }

Interfata Compara declara o metoda pe care orice clasa derivata din ea (in declaratia clasei se

foloseste cuvantul-cheie implements) trebuie sa o implementeze. Metoda comparaCu () se va

comporta similar cu metoda compareTo() din clasa String. Metoda este implicit publica si abstracta

si deci nu trebuie sa folosim modificatorii de acces public si de metoda abstract.

4.3 Implementarea unei interfețe

O clasa implementeaza o interfata in doi pasi:

- declara ca implementeaza interfata, folosind cuvantul-cheie implements in antetul sau;

- defineste implementari pentru toate metodele din interfata.

Pentru a exemplifica implementarea unei interfețe ne vom referi la clasa FormaGeo descrisa in

lectia 3.

Aceasta clasa implementeaza interfata Compara si, deci, trebuie sa definim si metoda comparaCu()

din interfata Compara. Implementarea metodei in clasa FormaGeo trebuie sa fie identica cu

declaratia din interfata si, din acest motiv, metoda comparaCu() are ca parametru un obiect de tip

Exemplu 2

Page 64: Programarea in Java - 2014 - an II ID.pdf

64

Compara si nu un obiect de tip FormaGeo. Codul clasei este ilustrat in continuare

(FormaGeo.java):

/* Superclasa abstracta pentru forme */

package formegeometrice;

import clasegenerice.*;

public abstract class FormaGeo implements Compara {

private String nume;

abstract public double arie();

public FormaGeo(String numeForma) {

nume = numeForma;

}

public int comparaCu(Compara rhs) {

if (arie() < ((FormaGeo) rhs).arie())

return -1;

else

if (arie() == ((FormaGeo) rhs).arie())

return 0;

else

return 1;

}

final public String toString() {

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

}

}

Nota:

1. O clasa care implementeaza o interfata poate sa extinda si o alta clasa. In acest caz in declaratia

clasei se foloseste mai intai cuvantul-cheie extends urmat de numele clasei din care deriveaza si

apoi cuvantul-cheie implements urmat de numele interfeței pe care o implementeaza.

2. Retinem ca definirea metodelor declarate intr-o interfata trebuie obligatoriu sa fie facuta in

fiecare clasa in parte, care implementeaza interfata respectiva.

3. Metodele interfeței definite in clasa care o implementeaza sunt mostenite de toate subclasele

clasei respective. Aceste metode pot fi redefinite (suprascrise) in subclase.

4. Daca o clasa extinde o superclasa care implementeaza o interfata, atunci si clasa respectiva

mosteneste interfata.

4.4 Implementarea unor interfețe multiple

O clasa poate sa implementeze mai mult decat o singura interfata. O clasa poate implementa mai

multe interfe in doi pasi:

- declara toate interfețele pe care le implementeaza, folosind cuvantul-cheie implements in

antetul sau urmat de numele tuturor interfețelor separate prin virgula;

- defineste implementari pentru toate metodele din toate interfețele pe care le

implementeaza.

Folosirea unor interfețe multiple poate crea totusi complicatii.

Page 65: Programarea in Java - 2014 - an II ID.pdf

65

Derivarea interfețelor

Ca si in cazul claselor, interfețele pot fi organizate intr-o ierarhie. Atunci cand o interfata

mosteneste o alta interfata, subinterfata primeste toate metodele si constantele definite in

superinterfata.

Pentru a deriva (extinde) o interfata se foloseste tot cuvantul-cheie extends, la fel ca in cazul

definitiilor de clasa:

public interface <nume_interfata> extends <nume_superinterfata> {

…..

}

Nota: In cazul interfețelor nu exista o radacina comuna a arborelui de derivare asa cum exista

pentru arborele de clasa, clasa Object. Interfețele pot exista independent sau pot mosteni o alta

interfata.

Ierarhia de interfețe este cu moștenire multipla. O singura interfata poate mosteni oricate clase are

nevoie.

Implementarea unei stive

Dorim sa implementam un nou tip dedate numit Stack, care sa modeleze notiunea de stiva de

obiecte. Obiectelede tip stiva, indiferent de implementarea lor, vor trebui sa contina metodele:

• push - adauga un nou element in stiva

• pop - elimina elementul din varful stivei

• peek - returneaza varful stivei

• empty - testeaza daca stiva este vida

• toString - returneaza continutul stivei sub forma unui sir de caractere.

Din punctul de vedere al structurii interne, o stiva poate fi implementata folosind un vector sau o

lista inlantuita, ambele solutii avand avantaje si dezavantaje. Prima solutie este mai simplu de

inteles, in timp ce a doua este mai eficienta din punctul de vedere al folosirii memoriei. Deoarece nu

dorim sa legam tipul de date Stack de o anumita implementare structurala, il vom defini prin

intermediul unei interfețe. Vom vedea imediat avantajele acestei abordari.

public interface Stack {

void push ( Object item ) throws StackException ;

void pop () throws StackException ;

Object peek () throws StackException ;

boolean empty ();

String toString ();

}

// Implementarea stivei folosind un vector de obiecte .

public class StackImpl1 implements Stack {

private Object items [];

// Vectorul ce contine obiectele

private int n=0;

// Numarul curent de elemente din stiva

public StackImpl1 (int max ) {

// Constructor

items = new Object [ max ];

}

public StackImpl1 () {

Exemplu 3

Page 66: Programarea in Java - 2014 - an II ID.pdf

66

this (100) ;

}

public void push ( Object item ) throws StackException {

if (n == items . length )

throw new StackException (" Stiva este plina !");

items [n++] = item ;

}

public void pop () throws StackException {

if ( empty ())

throw new StackException (" Stiva este vida !");

items [--n] = null ;

}

public Object peek () throws StackException {

if ( empty ())

throw new StackException (" Stiva este vida !");

return items [n -1];

}

public boolean empty () {

return (n ==0) ;

}

public String toString () {

String s="";

for (int i=n -1; i >=0; i --)

s += items [i]. toString () + " ";

return s;

}

}

// Implementarea stivei folosind o lista inlantuita .

public class StackImpl2 implements Stack {

class Node {

// Clasa interna ce reprezinta un nod al listei

Object item ; // informatia din nod

Node link ; // legatura la urmatorul nod

Node ( Object item , Node link ) {

this . item = item ;

this . link = link ;

}

}

private Node top= null ;

// Referinta la varful stivei

public void push ( Object item ) {

Node node = new Node (item , top);

top = node ;

}

public void pop () throws StackException {

if ( empty ())

throw new StackException (" Stiva este vida !");

top = top . link ;

}

public Object peek () throws StackException {

if ( empty ())

throw new StackException (" Stiva este vida !");

Page 67: Programarea in Java - 2014 - an II ID.pdf

67

return top. item ;

}

public boolean empty () {

return (top == null );

}

public String toString () {

String s="";

Node node = top;

while ( node != null ) {

s += ( node . item ). toString () + " ";

node = node . link ;

}

return s;

}

}

In continuare este prezentata o mica aplicație demonstrativa care foloseste tipul de date nou creat ¸si

cele doua implementari ale sale:

public class TestStiva {

public static void afiseaza ( Stack s) {

System . out. println (" Continutul stivei este : " + s);

}

public static void main ( String args []){

try {

Stack s1 = new StackImpl1 ();

s1. push ("a");

s1. push ("b");

afiseaza (s1);

Stack s2 = new StackImpl2 ();

s2. push ( new Integer (1));

s2. push ( new Double (3.14) );

afiseaza (s2);

} catch ( StackException e) {

System . err. println (" Eroare la lucrul cu stiva !");

e. printStackTrace ();

}

}

}

Page 68: Programarea in Java - 2014 - an II ID.pdf

68

Testul de autoevaluare nr. 4

1. Pot exista metode implementate (cu corp) într-o clasă abstractă? Dar într-o interfaţă?

2. Într-o clasă care implementează o interfaţă se poate modifica valoarea unui câmp din această

interfaţă?

3. Unde poate fi folosită o clasă internă ?

4. Ce puteţi spune despre următorul program?

interface I1{

int a=5;

int f(int x);

}

interface I2 extends I1{

float b=10;

float f(float x);

}

class C implements I2{

public int f(int x){return x+a;}

public float f(float x){return x/b;}

}

class Test{

public static void main(String sir[]){

I2 ob=new C();

System.out.print(ob.f(1)+" "+ob.f(1.5f)); }

}

a) Apare eroare la compilare deoarece metoda f din interfata I1 intră în contradicţie cu metoda f din

interfaţa I2;

b) Apare eroare la compilare deoarece în clasa C nu este definită variabila a.

c) Apare eroare la compilare deoarece nu se pot defini obiecte având ca tip o interfaţă.

d) Este corect şi afişează la execuţie : 6 0.15

e) Este corect şi afişează la execuţie : 6 0.15f

Page 69: Programarea in Java - 2014 - an II ID.pdf

69

Teste de control

4.1 Ce se va afisa la executia urmatorului program Java? interface I1{

float x=2.3f;

}

public class Test implements I1{

public static void main(String [] args){

System.out.print(x+" ");

x=6.7f;

System.out.print(x);

}

}

a) va aparea eroare la compilare deoarece valoarea variabilei x nu se mai poate

modifica;

b) la executie se va afisa: 2.3f 6.7f;

c) la executie se va afisa: 2.3f 2.3f;

d) la executie se va afisa: 2.3 6.7;

4.2 În Java o interfaţă poate extinde:

a) cel mult o interfată

b) oricâte interfeţe

c) cel mult o clasă

d) oricâte clase

4.3 În Java o clasă poate implementa:

a) o clasă

b) oricâte clase

c) o interfaţă

d) oricâte interfeţe

4.4 Fie următorul program Java:

interface Student { public void afisare(); }

class Student_1 implements Student

{

String nume;

int grupa;

public Student_1(String n, int g) { nume=n; grupa=g; }

public void afisare() { System.out.print(nume+" "+grupa+" "); }

}

class Student_2 extends Student_1 implements Student

{

String curs;

int nota;

public Student_2(String ns, int g, String c, int n)

Page 70: Programarea in Java - 2014 - an II ID.pdf

70

{

super(ns,g);

curs=c;

nota=n;

}

public void afisare()

{

..................................

System.out.println(curs+" "+nota);

}

}

public class test

{

public static void main(String[] args)

{

Student_2 s=new Student_2("Popescu",314,"Java",10);

s.afisare();

}

}

După executarea programului, pentru a se afisa Popescu 314 Java 10, spaţiile punctate din metoda

afisare a clasei Student_2 trebuie înlocuite cu:

afisare();

Student_1.afisare();

super.afisare();

nimic, deoarece se apelează automat metoda afisare a clasei Student_1.

Page 71: Programarea in Java - 2014 - an II ID.pdf

71

Formular de feedback

În dorinţa de ridicare continuă a standardelor desfăşurării activitatilor dumneavoastra, va rugăm să completaţi acest chestionar şi să-l

transmiteţi indrumatorului de an.

Disciplina: ________________________

Unitatea de invatare/modulul:__________________

Anul/grupa:__________________________

Tutore:_________________________

a) Conţinut / Metoda de predare

Partea I

1. Care dintre subiectele tratate in aceasta unitate/modul consideraţi că este cel mai util şi eficient? Argumentati raspunsul.

2. Ce aplicații/proiecte din activitatea dumneavoastra doriţi să imbunatatiti/modificaţi/implementaţi în viitor în urma cunoştinţelor

acumulate în cadrul acestei unitati de invatare/modul?

3. Ce subiecte consideraţi că au lipsit din acesta unitate de invatare/modul?

4. La care aplicații practice ati intampinat dificultati in realizare? Care credeti ca este motivul dificultatilor intalnite?

5. Daca ar fi sa va evaluati, care este nota pe care v-o alocati, pe o scala de la 1-10?. Argumentati.

Partea II. Impresii generale

1. Acest modul a întrunit aşteptările dumneavoastră?

2) Aveţi sugestii care să conducă la creşterea calităţii acestei unitati de invatare/modul?

3) Aveţi propuneri pentru alte unitati de invatare?

Vă mulţumim pentru feedback-ul dumneavoastră

În totalitate

În mare măsură În mică măsură Nu

Page 72: Programarea in Java - 2014 - an II ID.pdf

72

Unitatea de învăţare Nr. 5

Tratarea exceptiilor

Obiectivele Unităţii de învăţare nr. 5

5.1 Excepţii

Un aspect important de care trebuie ţinut cont ori de câte ori scriem un program este de a asigura

robusteţea sa. Prin aceasta înţelegem identificarea situaţiilor nedorite (de exemplu introducerea unor

date eronate, eşecul la încercarea de a avea acces la Internet etc.) şi specificarea acţiunile

corespunzătoare.

Există însă şi reversul aspectului descris mai sus. Introducerea de verificări prin instrucţiuni de

control face programul greu de citit şi afectează buna sa structurare.

Ceea ce dorim este să avem un mecanism care:

- să permită ca fiecare condiţie legată de robusteţea programului să fie verificată exact acolo unde

poate să apară;

- atunci când condiţia apare (suntem în situaţia că s-a întâmplat ceva nedorit), controlul să fie trecut

automat unei secţiuni de cod aflată în program "într-un loc potrivit" (care poate fi "departe" de locul

unde condiţia a fost detectată), cod care realizează acţiunea ce trebuie întreprinsă. Acest cod va fi

numit handler (mânuitor) de excepţie.

Limbajul Java rezolvă problema de mai sus printr-un mecanism numit excepţie. Excepţia

semnalează faptul că a intervenit o anumită condiţie specială (nedorită); spunem că segmentul de

cod care a detectat condiţia lansează o excepţie de tipul corespunzător. Lansarea unei excepţii

atrage după sine captarea ei de către un handler de excepţie; în lipsa acestuia, programul se va

încheia cu un mesaj de eroare.

Mai precis, trebuie să realizăm următoarele:

- să definim tipurile de excepţie care să permită lansarea excepţiilor dorite;

- să lansăm o excepţie la "locul potrivit" în program;

Obiective:

După ce veţi parcurge această unitate de învăţare, veţi reuşi să:

înţelegeţi conceptul de excepţie şi utilitatea folosirii excepţiilor

pentru a asigura robusteţea programelor;

lansaţi o excepţie prin instrucţiunea throw şi să trataţi o excepţie

prin construcţia try;

scrieţi programe ce tratează excepţii

Page 73: Programarea in Java - 2014 - an II ID.pdf

73

- să prevedem la "locul potrivit" un handler de excepţie, care să apteze excepţia şi să întreprindă

acţiunile corespunzătoare.

O excepţie este în fapt o instanţă a unei clase derivate din clasa java.lang.Exception. Rezultă că o

excepţie este un obiect, care are câmpurile sale, constructorii săi şi metodele sale.

Când un program detectează o condiţie care cere ca o excepţie să fie raportată, el creează un obiect

corespunzător excepţiei, care poate fi folosit pentru a invoca metode ale a clasei respective.

Trebuie subliniat că o excepţie poate fi o eroare, dar şi orice situaţie pentru care vrem să

întreprindem acţiuni specifice. Pentru situaţiile în care consideră că este vorba de o eroare, Java

lansează automat o excepţie care, dacă nu este captată de un handler de eroare, conduce la tipărirea

unui mesaj, după care programul se termină; este însă posibil să captăm excepţia şi să întreprindem

ce acţiune dorim.

Exemplul se referă la metoda System.in.read() care lansează, atunci când are loc o eroare la citire

(nu poate fi citit un caracter), o excepţie de tipul IOException. Există două posibilităţi de a trata

această situaţie:

1). Se precizează, în antetul metodei care execută apelul respectiv, clauza:

throws IOException

după lista de parametri a metodei. Drept urmare ia naştere un obiect de tipul IOException care

tipăreşte un mesaj de eroare şi întrerupe executarea programului; putem gândi că este executată

implicit o metodă care întreprinde aceste acţiuni.

2). Se prevede o acţiune explicită specificată de programator prin:

try {

... System.in.read();...

}

catch (IOException e){

handler de excepţie

}

prin care este creat obiectul e de tipul IOException, care poate fi folosit în prelucrările prevăzute de

handlerul de excepţie. Acţiunea respectivă poate consta de exemplu în tipărirea unui mesaj

edificator, atribuirea unor valori prin lipsă, invocarea unor metode (presupunând că acestea există)

ale clasei IOException prin intermediul obiectului e etc.

în această a doua variantă nu mai este necesar să declarăm clauza throws IOException în antetul

metodei. De asemenea trebuie observat că nu mai este întreprinsă o acţiune implicită, deoarece este

prevăzut explicit un cod ce trebuie executat (cel din handlerul de excepţie).

De exemplu acţiunea poate fi:

System.out.println("Eroare : " + e);

prin care este tipărit mesajul "Eroare" urmat de numele excepţiei.

Clasa Exception are un constructor implicit cu zero argumente, un constructor cu un argument de

tip String şi o metodă fără nume care se execută implicit la lansarea unei excepţii şi care constă în

tipărirea unui mesaj de eroare specific (la care se poate adăuga şirul transmis constructorului, în

cazul în care a fost folosit acest constructor).

Cel mai brutal mod de utilizare a clauzei throws este:

throws Exception

Exemplu 1

Page 74: Programarea in Java - 2014 - an II ID.pdf

74

prin care are loc terminarea programului pentru toate excepţiile prevăzute de Java. Nu este însă

indicat să procedăm în acest mod, deoarece în general nu vom obţine suficiente informaţii pentru

depanarea programului.

5.2 Clauza throws şi instrucţiunea throw

Pentru a lansa o excepţie, este folosită instrucţiunea throw, ce are forma:

throw Ob;

Obiectul excepţie Ob poate fi creat ca de obicei, folosind operatorul new:

tip_exceptie Ob = new tip_exceptie(...);

drept urmare luând naştere o instanţă a clasei tip_excepție ce extinde clasa Exception. Crearea este

însoţită de invocarea acelui constructor al clasei tip_exceptie, ce are signatura respectivă. O

excepţie fiind un obiect, ea trebuie întâi creată şi apoi lansată.

De obicei lansarea într-o metodă a unei excepţii se face din cadrul unei instrucţiuni if sau a unei

instrucţiuni switch, ca de exemplu în:

tip Met(...)throws Exceptie {

...

if(...) throw new Exceptie(...);

...

}

unde Exceptie este o clasă ce extinde clasa Exception.

Dacă este îndeplinită condiţia din if, atunci este creat, folosind un constructor, un obiect având tipul

(de excepţie) Exceptie.

Observăm că în antetul metodei Met de mai sus apare clauza "throws Exceptie".

Să remarcăm că mecanismul seamănă cu crearea obişnuită a unui obiect:

class ... {

tip Met(...) {

...

if(...) Exceptie Ob = new Exceptie(...);

...

}

}

Lucrurile nu sunt însă identice: nu există constructorii de care am vorbit mai sus şi nu au loc

automat tipărirea unui mesaj de excepţie şi terminarea programului.

Sunt importante următoarele precizări:

- precizarea tipului de excepţie prin clauza throws este importantă pentru că programatorul (ca şi

compilatorul) trebuie să ştie ce excepţie poate fi lansată şi care este tipul ei, la fel cum trebuie să

cunoască tipul valorii întoarse de o metodă;

- dacă din interiorul metodei dorim să prevedem lansarea mai multor excepţii, atunci toate tipurile

lor trebuie precizate în clauza throws, despărţite între ele prin virgulă;

- o metodă poate lansa numai excepţiile care sunt precizate în antetul său (mai precis în clauza

throws); lansarea poate avea loc din interiorul metodei sau din interiorul altei metode pe care ea o

invocă;

- nu este permis să lansăm excepţii din interiorul iniţializărilor statice; în schimb acest lucru este

permis din interiorul constructorilor;

- la redefinirea unei metode într-o subclasă, nu putem preciza în throws excepţii suplimentare.

Page 75: Programarea in Java - 2014 - an II ID.pdf

75

5.3 Construcţia try

Mecanismul incipient descris mai sus permite crearea unei excepţii şi invocarea unui constructor al

său. Dar o excepţie lansată în corpul unei metode trebuie să aibă drept consecinţă executarea unor

acţiuni cuprinse într-un handler de excepţie prezent tot în corpul metodei. Tipul de excepţie

respectiv este însă o clasă, care poate avea şi metode. În handlerul de excepţie este posibilă

invocarea unor metode ale clasei a cărei instanţiere este obiectul în discuţie. Toate aceste aspecte

sunt rezolvate de construcţia try.

Construcţia try are forma:

try bloc

catch(E_1 e_1) bloc1

catch(E_2 e_2) bloc2

...

finally bloc_final

unde:

- E_1, E_2, ... sunt tipuri de excepţie (clase ce extind Exception);

- e_1, e_2, ... sunt identificatori;

- clauza finally este opțională;

- blocurile reprezintă tocmai handlerele de excepţie.

Dacă în blocul bloc asociat lui try nu este lansată nici o excepţie, atunci se trece de ultimul catch.

Să presupunem acum că din bloc este lansată o excepţie; fie E tipul său. Se încearcă pe rând, în

ordinea în care apar clauzele catch, asocierea ei cu una dintre ele. Dacă E coincide cu E_1 sau este

derivată din (extinde pe) E_1, atunci se execută blocul bloc_1, după care se trece de ultima clauză

catch. în caz contrar se încearcă pe rând asocierea excepţiei cu E_2, E_3 etc. Dacă nu s-a reuşit o

asociere, se merge "la un nivel superior" într-o construcţie try care o cuprinde pe cea în discuţie etc.

Dacă nici în acest mod nu s-a identificat o asociere, se trece în codul care a invocat metoda curentă

etc. în final se va reuşi o asociere, deoarece altfel ar apare o eroare chiar în faza de compilare.

Tot o eroare la compilare va apare şi dacă de exemplu E_2 este derivată din E_1; explicaţia constă

în faptul că lansarea unei excepţii de tipul E_2 nu va putea conduce la captarea ei de către clauza

identificată prin E_2 (excepţia va fi captată de clauza catch precedentă).

Conform celor de mai sus, este posibil ca o construcţie try să nu aibă ataşată nici o clauză catch.

Să mai observăm că la lansarea unor excepţii din bloc (vezi forma generală a construcţiei try),

instrucţiunile care îi urmează în acest bloc nu vor mai fi executate. Mai este clar şi că o construcţie

try poate fi utilizată pentru captarea mai multor excepţii.

Aşa cum am anunţat anterior, o construcţie try poate avea şi o clauză finally. Aceasta permite

executarea unei secvenţe de instrucţiuni indiferent dacă din blocul bloc este lansată sau nu o

excepţie. Odată inclusă, clauza finally nu poate fi în nici un fel ocolită şi blocul bloc_final este

totdeauna executat. Un caz limită este de exemplu următorul:

try { ... return 0; ... }

finally { return 1; }

pentru care valoarea întoarsă este totdeauna 1.

Page 76: Programarea in Java - 2014 - an II ID.pdf

76

De obicei clauza finally este folosită pentru a elibera anumite resurse, ca de exemplu resurse grafice

sau fişiere (prin închiderea lor).

5.4 Tratarea excepţiilor

Descriem în continuare modul tipic de utilizare a excepţiilor. Pentru simplificare vom considera un

singur tip de excepţie cu un unic constructor şi o unică metodă.

La construcţia următoarei clase:

class Clasa {

Clasa(..) {..}

.. Met(..)throws Exceptie {

...

if(..) throw new Exceptie(..)

..

}

}

programatorul a identificat în metoda Met o condiţie deosebită care ar putea interveni şi de aceea a

conceput şi clasa Exceptie pentru a putea prevedea acţiunile ce trebuie întreprinse la îndeplinirea

condiţiei:

class Exceptie extends Exception {

Exceptie(...) {...}

... MetExc(...) {...}

}

în mod normal, aceste activităţi sunt întreprinse o singură dată, în vederea unor aplicaţii ce urmează

a fi dezvoltate. Pe de altă parte, clasa Exceptie poate fi folosită şi de altă clasă decât Clasa; de

exemplu atât pentru lucrul cu stive, cât şi pentru cel cu cozi, prelucrările prevăzute pentru o

încercare de adăugare a unui element în stiva/coada plină pot fi aceeaşi. De aceea de multe ori este

natural ca cele două clase să se afle în unităţi de compilare separate.

Ulterior, programatorul scrie un program care cuprinde o clasă C, din care este invocată metoda

Met a clasei Clasa, ceea ce poate conduce la lansarea excepţiei respective. Este clar că aici este

locul cel mai potrivit pentru a specifica acţiunea ce trebuie întreprinsă la lansarea excepţiei. Pentru

aceasta este folosită construcţia try, care captează obiectul excepţie şi prin intermediul lui invocă

metoda MetExc a clasei Exceptie:

class C {

Clasa Ob = new Clasa(...);

...

try {

....

Ob.Met(...);

....

}

catch (Exceptie e){

... e.MetExc(...); ...

}

.....

}

S-a prevăzut invocarea metodei Met a clasei Clasa din interiorul construcţiei try. în cazul în care

apare condiţia în discuţie, este creat un obiect de tipul Exceptie prin invocarea constructorului său.

Page 77: Programarea in Java - 2014 - an II ID.pdf

77

Apoi controlul este trecut clauzei catch care captează (primeşte în parametrul său) obiectul creat,

ceea ce permite invocarea metodei MetExc din Exceptie.

Acum discuţia de la începutul capitolului capătă consistenţă: o excepţie de tipul Exceptie este

lansată din clasa Clasa şi este captată în clasa C.

Vom aplica cele de mai sus la rezolvarea următoarei probleme:

Un vector a de lungime n conţine n caractere. Ele trebuie mutate

într-o ordine oarecare în vectorul b, prin intermediul unui vector auxiliar stack de lungime lung,

care implementează o stivă. Operaţiile permise sunt:

- mutarea unui element din a în vectorul stack : elementul curent (cel cu numărul de ordine cel mai

mic) din a este mutat după elementele deja existente în stivă;

- extragerea (inclusiv ştergerea) unui element din vârful stivei şi înscrierea sa în b, după ultimul

element înscris în b.

Dificultatea problemei constă în tratarea cazului în care se încearcă extragerea unui element din

stiva vidă şi a cazului în care se încearcă introducerea unui element în stiva plină.

Prezentăm în continuare programul, urmat de explicaţiile necesare.

Unitatea de compilare Plina.java

class Plina extends Exception {

void print(String s) { System.out.print(s); }

}

Unitatea de compilare Vida.java : class Vida extends Exception {

void print(String s) { System.out.print(s); }

}

Unitatea de compilare S.java : class S {

int lung, ns; char[] stack;

S(int lung) { this.lung=lung ; stack = new char[lung]; }

void pune(char c) throws Plina {

if (ns==lung) throw new Plina();

else { System.out.print(" P"+c); stack[ns]=c; ns++; }

}

char ia() throws Vida {

if (ns==0) throw new Vida();

else {

System.out.print(" I"+stack[--ns]); return

stack[ns];

}

}

}

Unitatea de compilare Stiva.java : import java.util.*;

class Stiva {

public static void main(String[] sir) {

Exemplu 2

Page 78: Programarea in Java - 2014 - an II ID.pdf

78

int n=10,na,nb,i; char[] a,b; char c;

a = new char[n]; b = new char[n];

Random R = new Random();

for (c='a',i=0; i<n; i++,c++) a[i]=c;

na=0; nb=0; S Ob = new S(3);

while (nb!=n) {

try {

if (R.nextInt()<0 && na<n) { Ob.pune(a[na]); na++;

}

else { b[nb] = Ob.ia(); nb++;} }

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

catch (Plina e) {e.print(" ~P");}

}

System.out.println();

for (i=0; i<n; i++) System.out.print(b[i]+" ");

System.out.println();

}

}

Clasa principală este Stiva. Metoda sa main foloseşte, în afară de vectorii a şi b, următoarele:

- variabila na desemnează poziţia din a de pe care va fi mutat un element în stivă;

- variabila nb desemnează poziţia din b pe care va fi înscris următorul element;

- obiectul R de tipul Random (clasă din pachetul java.util) este folosit pentru apelarea metodei

nextInt fără argumente, ce întoarce în mod aleator un număr întreg;

- obiectul Ob de tipul S, unde clasa S implementează operaţiile asupra stivei: metoda pune are un

parametru de tip char pe care îl adaugă stivei, iar metoda ia fără parametri întoarce elementul din

vârful stivei.

Metoda main din Stiva repetă, atâta timp cât în b nu au fost înscrise n caractere, următoarele acţiuni:

- este generat aleator un nou număr întreg;

- dacă valoarea sa este negativă i mai există elemente în a, este invocată metoda pune din clasa S cu

intenţia de a muta un element din a în stivă; invocarea este urmată de mărirea lui na cu o unitate. în

caz contrar este invocată metoda ia cu intenţia de a obţine un element din stivă şi de a-l muta în

vectorul b;

- în final sunt listate elementele lui b.

Observăm că nu sunt tratate aici cazurile de excepţie (adăugare la stivă plină sau extragere din stiva

vidă), aceste verificări căzând în sarcina clasei S. Utilizarea clasei Random permite un

nedeterminism în succesiunea de operaţii asupra stivei, ceea ce va conduce la vectori b diferiţi de la

o executare la alta.

În clasa S este folosit vectorul stack de lungime lung pentru implementarea stivei. în ns este

memorat numărul de elemente din stivă. În antetul metodei pune este declarat tipul de excepţie

plina, căruia îi corespunde clasa plina ce extinde clasa Exception. Deosebim două situaţii:

- dacă stiva este plină (ns=lung), atunci prin throw este creată o excepţie (un obiect de tip Plina).

Controlul este trecut acelei clauze catch din Stiva care este identificată prin tipul Plina al excepţiei.

Obiectul creat este transmis în e. Prin invocarea e.print(...) este apelată metoda print a clasei Plina

care tipăreşte mesajul primit la invocare. Să observăm că în acest mod se evită incrementarea lui na;

- dacă stiva nu este plină, atunci este înscris un nou element în stivă.

Modul în care acţionează metoda ia este analog.

Este uşor de observat că s-a folosit exact schema descrisă anterior, cu clasele Plina şi Vida în rolul

clasei Exceptie, cu S în postura clasei Clasa şi cu Stiva în locul clasei C.

Page 79: Programarea in Java - 2014 - an II ID.pdf

79

Urmatorul exemplu (cireste un sir de caractere si “incearca”, intr-un bloc try, sa il converteasca la

un numar intreg. In caz de nereusita, se “intercepteaza”, in blocul catch, o exceptie de tip

NumberFormatException, care este “aruncata” de metoda Integer.parseInt() atunci cand numarul

introdus nu este un numar intreg. Tratarea acestui tip de eroare se face printr-un mesaj de avertizare

si returnarea valorii implicite 0 pentru un numar intreg.

De asemenea, atunci cand “se incearca” citirea sirului de caractere de la tastatura, intr-un bloc tray,

“se pot intercepta”, intr-un bloc catch, eventualele excepții de tip IOException, care sunt “aruncate”

de metoda readLine(). Tratarea acestui tip de eroare se face prin returnarea valorii implicite null

pentru un String.

package intrareiesire;

import java.io.*;

/* cieste un sir de caractere si incerca sa il converteasca la tipul int */

public class CitesteDate

{

public static String citesteString() {

BufferedReader br = new BufferedReader(new

InputStreamReader(System.in));

try {

return br.readLine(); }

catch(IOException ioe) {

return null; }

}

public static int citesteNrInt() {

try {

return Integer.parseInt(citesteString()); }

catch(NumberFormatException nfe) {

System.out.println("Nu este numar intreg.");

return 0; }

} }

Programul urmator (TestCiesteNumere.java) apeleaza metodele din clasa CitesteDate, (care

semnaleaza, intercepteaza si trateaza erorile care apar in cadrul lor) pentru a citi un sir de numere de

tastatura.

import intrareiesire.*;

class TestCitesteNumere {

public static void main(String[] args) {

citesteDate valIntreg = new citesteDate();

System.out.println("Introduceti numarul de elemente ale sirului:");

int n = valIntreg.citesteNrInt(); int [] numere = new int [n];

System.out.println ("Introduceti elementele sirului: ");

for (int i = 0; i < numere.length; i++)

numere [i] = valIntreg.citesteNrInt(); System.out.println ("Sirul de numere introdus este: ");

for (int i = 0; i < numere.length; i++)

Exemplu 3

Page 80: Programarea in Java - 2014 - an II ID.pdf

80

System.out.print(numere[i] + " "); } }

Exemplul, descris mai sus, prezinta modul de interceptare a unui anumit tip de exceptie. Deoarece

clasele de excepții sunt organizate ierarhic, nu este necesar ca tipul de exceptie tratat de blocul

catch si tipul de exceptie “aruncat” de o metoda din blocul try sa fie identice. Un bloc catch, care

trateaza un tip de excepții va intercepta si trata si clasele de excepții derivate din exceptia

respectiva.

In exemplul de fata, se poate intercepta in blocul catch, exceptia creata de tipul

NumberFormatException, folosind clasa Exception care este superclasa pentru

NumberFormatException. Astfel, codul ar putea arata astfel:

public static int citesteNrInt() {

try {

return Integer.parseInt(citesteString()); }

catch(Exception nfe) {

System.out.println("Nu este numar intreg.");

return 0; }

}

}

In aceasta situatie, blocul catch intercepteaza toate excepțiile Exception, dar si clase de excepții

derivate din clasa Exception, cum este si cazul clasei de excepții FormatNumberException.

Se prefera totusi, utilizarea blocurilor catch specializate, care ofera mai multe detalii despre situatia

de eroare, si nu a celor generale.

Nota: Toate clasele de excepții mostenesc de la clasa Throwable cateva metode utile pentru aflarea

de informatii despre situatia de eroare. O folosire uzuala are metoda getMessage(). Ea afiseaza un

mesaj detaliat referitor la ce s-a intamplat.

Daca se doreste interceptarea si tratarea, in blocul catch, a unor tipuri foarte diferite de excepții

semnalate in blocul try, care nu sunt inrudite prin moștenire, atunci se asocieaza blocului try mai

multe blocuri catch.

Blocurile catch sunt examinate in ordinea in care ele apar in fisierul sursa. In timpul procesului de

examinare, primul bloc catch care va corespunde exceptiei semnalate va fi executat, iar celelalte

ignorate.

Declararea metodelor care pot semnala (“arunca”) excepții către alte metode (transmiterea

excepțiilor către baza stivei de apel)

Observatii:

1.Excepțiile specificate in clauza throws nu trebuie sa fie interceptate (“prinse”) si tratate in cadrul

metodei respective care foloseste clauza throws.

2.Semnalarea (“aruncarea”) excepțiilor incepe cu metoda originala care daca nu intercepteaza si nu

trateaza excepțiile generate, le semnaleaza (“le arunca”) mai departe metodei care o apeleaza, care

la randul ei daca nu le intercepteaza si nu trateaza le semnaleaza (“le arunca”) mai departe unei alte

metode care o apeleaza pe aceasta din urma si asa mai departe. In final exceptia va trebui

interceptata (“prinsa”) si tratata in cadrul unei metode. Astfel, masina virtuala Java cauta in stiva de

Page 81: Programarea in Java - 2014 - an II ID.pdf

81

apel metoda care intercepteaza si trateaza exceptia, pornind de la metoda in care a aparut exceptia,

deci dinspre varful stivei spre baza stivei.

Forma antetului metodei care specifica tipurile de excepții semnalate (“aruncate”) de metoda este:

[<modificatori_acces>] [<modificatori_metoda>] <tip_returnat> <nume_metoda>

([<param1>, <param2>, …]) throws <nume_clasa_de_exceptii1>[,

<nume_clasa_de_exceptii2>, …]

Nota: Specificarea prin clauza throws a excepțiilor aruncate de metoda originala nu se poate omite,

daca metoda respectiva genereaza excepții pe care nu le trateaza, deoarece compilatorul detecteaza

aceasta “scapare” si o raporteaza ca eroare de compilare, propunand doua solutii: tratarea lor in

cadrul metodei (prin blocuri try…catch) sau specificarea lor in clauza throws.

Exemplul prezentat anterior, al clasei CitesteDate, poate fi modificat astfel incat excepțiile de tipul

IOException care sunt semnalate (“aruncate”) in metoda citesteString (), de către metoda

readLine(), sa fie semnalate (“aruncate”) mai departe in metoda citesteNrInt(), care apoi sa le

semnaleaza metodei main() din clasa TestCitesteNumereThrows (care reprezinta aplicatia Java).

Astfel, s-a creat o noua clasa CitesteDateThrows care are definitia:

package intrareiesire;

import java.io.*;

/* cieste un sir de caractere si incerca sa il converteasca la tipul int */

public class CitesteDateThrows

{

public static String citesteString() throws IOException {

BufferedReader br = new BufferedReader(new

InputStreamReader(System.in));

return br.readLine();

}

public static int citesteNrInt() throws IOException {

try

{

return Integer.parseInt(citesteString()); }

catch(NumberFormatException nfe)

{

System.out.println("Nu este numar intreg.");

return 0;

}

}

}

Clasa TestCitesteNumereThrows (care reprezinta programul principal) are definitia

data de secventa de cod:

import intrareiesire.*;

import java.io.*;

class TestCitesteNumereThrows

{

public static void main(String[] args) throws IOException {

Page 82: Programarea in Java - 2014 - an II ID.pdf

82

CitesteDateThrows valIntreg = new CitesteDateThrows();

System.out.println("Introduceti numarul de elemente ale sirului:");

int n = valIntreg.citesteNrInt(); int [] numere = new int [n];

System.out.println ("Introduceti elementele sirului: ");

for (int i = 0; i < numere.length; i++)

numere [i] = valIntreg.citesteNrInt(); System.out.println ("Sirul de numere introdus este: ");

for (int i = 0; i < numere.length; i++)

System.out.print(numere[i] + " ");

}

}

5.5 Crearea si semnalarea propriilor excepții

Pe langa excepțiile definite de platforma Java, programatorul poate defini propriile clase de

excepții. Aceste clase proprii de excepții descriu situatii de excepții particulare aplicației respective

care nu exista in ierarhia de clase de excepții oferită de platforma Java.

Clasele proprii de excepții sunt derivate (direct sau indirect) din clasa Throwable.

De regula, se creaza propriile clase de excepții derivate din clasa Exception.

Nota: In definirea noilor clase de excepții, se recomanda adaugarea la numele clasei a sufixului

Exception, pentru toate clasele derivate (direct sau indirect) din clasa Exception (de exemplu,

MyNewException).

Clasele proprii de excepții sunt clase Java obisnuite.

Clasele proprii de excepții poseda, de obicei, doi constructori:

- primul constructor nu primeste nici un parametru;

- al doilea constructor primeste ca parametru un sir de caractere care reprezinta un mesaj ce

evidentiaza situatia de eroare.

Definirea propriilor clase de excepții

De regula, o clasa proprie de excepții este definita ca in exemplul de mai jos:

package excepții;

public class IndexException extends Exception {

public IndexException()

{

super(); }

public IndexException(String msg)

{

super(msg); }

}

Clasa IndexException definita mai sus nu aduce practic nimic nou clasei Exception, deoarece

defineste doar doi constructori care apeleaza constructorii superclasei Exception. Totusi, tipul

exceptiei in sine este important pentru ca ajuta programatorul sa intercepteze tip respectiv de

exceptie atunci cand este necesar.

Semnalarea (“aruncarea”) propriilor excepții

Page 83: Programarea in Java - 2014 - an II ID.pdf

83

Sa ne reamintim ca, toate excepțiile sunt instante ale unei clase de exceptie oarecare, definite fie in

biblioteca Java standard, fie de programator.

Pentru a semnala (“arunca”) un tip de exceptie definita de programator, trebuie sa se creeze, mai

intai, o instanta a sa.

Folosind definirea de clasa de exceptie prezentata, crearea unei instante a clasei de excepie

IndexException poate fi facuta in doua moduri:

new IndexException();

new IndexException("Stiva vida. ");

In cel de al doilea caz situatia de eroare transmite si o informatie, sub forma mesajului “Stiva

vida.”, care poate fi folosit de codul care trateaza exceptia aparuta pentru a afisa un mesaj

informativ.

Odata creata o instanta a unei clase proprii de excepții, aceasta devine o exceptie Java si este

semnalata (“aruncata”) folosind instrucțiunea throw.

Instrucțiunea throw are un singur argument, care trebuie sa fie o instanta a unei clase de excepții

derivate din clasa Exception.

Forma instructiunii throw este:

throw <instanta_clasa_de_exceptii>;

De exemplu, pentru semnalarea (“aruncarea”) unei excepții din metoda topAndPop() (exceptie care

poate fi generata cand o stiva este vida) se poate folosi urmatoarea secventa de cod:

public Object topAndPop() throws IndexException {

if (isEmpty())

{

throw new IndexException("Stiva vida. "); }

return elemStiva[pozitieVarf--];

}

Pentru transmiterea exceptiei semnalate (“aruncate”) in metoda topAndPop(), cu ajutorul

instrucțiunea throw, către o alta metoda apelanta se foloseste clauza throws in antetul metodei

topAndPop(). In metoda apelanta exceptia IndexException se poate, eventual intercepta (“prinde”)

si trata sau poate fi transmisa mai departe la o alta metoda apelanta.

In exemplul prezentatat, interceptarea si tratarea exceptiei de tip IndexException este realizata in

metoda main() a aplicației (clasa TestStiva1). Iata codul-sursa in care se realizeaza acest lucru:

/* Clasa de test simpla pentru o stiva, care adauga 10 numere

* dupa care le extrage in ordine inversa */

import clasegenerice.*;

import exceptii.*;

public class TestStiva1

{

public static void main(String[] args) {

Stiva1 s = new StivaArr(10);

//introducem elemente in stiva

for (int i = 0; i < 10; i++)

{

s.push(new Integer(i));

Page 84: Programarea in Java - 2014 - an II ID.pdf

84

}

//scoatem elementele din stiva si le afisam

System.out.print("Continutul stivei este: ");

try {

while (true)

{

System.out.print(s.topAndPop() + " "); }

}

catch(IndexException ie) {

System.out.println();

System.out.print("Eroare: " + ie.getMessage()); }

}

}

Observatie: In secveta de mai sus, iesirea din bucla while se realizeaza in momentul in care stiva

devine vida si metoda topAndPop() semnaleaza (“arunca”) exceptia IndexException care este

interceptata si tratata in blocul catch.

Page 85: Programarea in Java - 2014 - an II ID.pdf

85

Testul de autoevaluare nr. 5

1. Ce este o excepţie în Java?

2. Cum se poate lansa o excepţie în interiorul unei metode ?

3. O metoda poate lansa mai multe excepţii? Cum se specifică ce excepţii lansează o metodă?

4. Presupunem că avem următoarea clasă cu o metodă afisFisier care citeşte datele dintr-un

fişier linie cu linie şi le afişează pe ecran. Metoda lansează excepţiile

FileNotFoundException dacă fişierul nu este găsit şi IOException dacă apar probleme la

citire.

Scrieţi o clasă care să conţina metoda main în care sa afişaţi datele dintr-un fişier cu numele

"exceptii.txt" folosind metoda afisFisier şi care să trateze erorile lansate de aceasta, afişând

un mesaj corespunzator: "Fisier inexistent" sau "Eroare la citire".

import java.util.*;

import java.io.*;

class Fisier{

void afisFisier(String numeFisier)

throws FileNotFoundException,IOException{

Scanner sc=new Scanner(new File(numeFisier));

while(sc.hasNextLine())

System.out.println(sc.nextLine());

sc.close();

}

}

Teste de control

5.1 Fie urm¸atorul cod Java: int x=0;

if (double.isInfinite(2/x))

System.out.println("Infinit");

else

System.out.println("2/0");

Ce puteti spune despre acest cod, daca este integrat in cadrul unui program Java?

A. Va produce eroare la compilare din cauza impartirii la 0;

B. Va produce eroare la executie din cauza impartirii la 0 (se arunca o except»ie:

"ArithmeticExpetion");

C. Codul este corect si va afisa Infnit;

D. Codul este corect si va afisa NaN

Page 86: Programarea in Java - 2014 - an II ID.pdf

86

5.2 Prin modalitatea sa de tratare a excepțiilor, Java are urmatoarele avantaje fata de mecanismul

traditional de tratare a erorilor:

A. Exista o metoda care se ocupa cu acest lucru;

B. Separarea codului pentru tratarea unei erori de codul in care ea poate sa apara;

C. Propagarea unei erori pana la un analizor de excepții corespunzator;

D. Gruparea erorilor dupa tipul lor;

5.3 Metodele care sunt apelate uzual pentru un obiect de tip exceptie sunt defnite in clasa

Throwable si sunt:

A. Declarate cu modicatorul de acces private;

B. dinamice;

C. publice;

D. excepții;

Page 87: Programarea in Java - 2014 - an II ID.pdf

87

Formular de feedback

În dorinţa de ridicare continuă a standardelor desfăşurării activitatilor dumneavoastra, va rugăm să completaţi acest chestionar şi să-l

transmiteţi indrumatorului de an.

Disciplina: ________________________

Unitatea de invatare/modulul:__________________

Anul/grupa:__________________________

Tutore:_________________________

a) Conţinut / Metoda de predare

Partea I

1. Care dintre subiectele tratate in aceasta unitate/modul consideraţi că este cel mai util şi eficient? Argumentati raspunsul.

2. Ce aplicații/proiecte din activitatea dumneavoastra doriţi să imbunatatiti/modificaţi/implementaţi în viitor în urma cunoştinţelor

acumulate în cadrul acestei unitati de invatare/modul?

3. Ce subiecte consideraţi că au lipsit din acesta unitate de invatare/modul?

4. La care aplicații practice ati intampinat dificultati in realizare? Care credeti ca este motivul dificultatilor intalnite?

5. Daca ar fi sa va evaluati, care este nota pe care v-o alocati, pe o scala de la 1-10?. Argumentati.

Partea II. Impresii generale

1. Acest modul a întrunit aşteptările dumneavoastră?

2) Aveţi sugestii care să conducă la creşterea calităţii acestei unitati de invatare/modul?

3) Aveţi propuneri pentru alte unitati de invatare?

Vă mulţumim pentru feedback-ul dumneavoastră

În totalitate

În mare măsură În mică măsură Nu

Page 88: Programarea in Java - 2014 - an II ID.pdf

88

Unitatea de învăţare Nr. 6 Intarari si iesiri

Obiectivele Unităţii de învăţare nr. 6

6.1 Tipuri de fluxuri de intrare/iesire Java

Toate datele din Java sunt scrise sau citite folosind fluxuri.

Un flux (stream) reprezinta o succesiune de octeti (bytes) sau de caractere transportat de la sau către

memoria RAM in care se afla programul Java.

Un flux de intrare transporta datele de la o sursa externa (tastatura, fisier pe hard-disc etc) către

programul Java.

Un flux de iesire transporta datele din programul Java către o destinatie externa (ecranul

calculatorului, fisier pe hard-disc etc).

Fluxurile de intrare/iesire in Java sunt create si manevrate cu ajutorul claselor din pachetul

predefinit java.io. Din acest motiv orice program care execută operatii de intrare/iesire trebuie sa

includa instrucțiunea:

import java.io.*;

Numarul claselor si a metodelor lor, definite in pachetul java.io, este foarte mare. De aceea se

recomanda programatorului sa consulte in permanenta documentatia ce insoteste versiunea de Java

folosita.

Java foloseste doua tipuri principale de fluxuri:

- fluxuri de octeti;

- fluxuri de caractere.

Obiective:

După ce veţi parcurge această unitate de învăţare, veţi reuşi să:

creați fluxuri de intrare/ieșire

utilizați clase predefinite pentru construcția fluxurilor de octeți;

filtrați fluxuri de octeți

creați fluxuri de caractere

Page 89: Programarea in Java - 2014 - an II ID.pdf

89

Fluxurile de octeti pot pastra valori intregi din domeniul 0 - 255. In acest format pot fi reprezentate

o multitudine de date, cum ar fi: date numerice, programe executabile, comunicatii Internet sau cod

Java (bytecode) etc.

Generic, fluxurile de octeti sunt subclase ale claselor abstracte predefinite:

- InputStream - pentru fluxuri de octeti de intrare si

- OutputStream - pentru fluxuri de octeti de iesire.

Fluxurile de caractere reprezinta un tip special de flux de octeti, care se folosesc numai pentru date

de tip text (tiparibile). Ele difera de fluxurile de octeti prin faptul ca setul de caractere Java suporta

codificarea Unicode (cu doi octeti pe caracter).

Toate datele de tip text, cum ar fi fisierele text, paginile Web, sau alte formate de text, este necesar

sa foloseasca fluxurile de caractere.

Generic, fluxurile de caractere sunt subclase ale claselor abstracte predefinite:

- Reader - pentru fluxuri de caractere de intrare si

- Writer - pentru fluxuri de caractere de iesire.

Java ofera trei fluxuri predefinite pentru operatii de I/O standard (de la tastatura, la ecranul

calculatorului sau pentru erori) care sunt campuri ale clasei System inclusă in pachetul java.lang:

- System.in - reprezinta intrarea standard (implicit, tastatura calculatorului); acest flux este de tip

InputStream;

- System.out - reprezinta iesirea standard (implicit, ecranul calculatorului); acest flux este de tip

PrintStream;

- System.err - reprezinta fluxul standard de iesire pentru mesaje de eroare (implicit, ecranul

calculatorului); acest flux este de tip PrintStream.

Dintre metodele clasei System, referitoare la fluxurile predefinite descrise mai sus, mentionam:

- metoda setIn, care redirecteaza fluxul de intrare standard către o alta sursa decat tastatura (de

exemplu, un fisier pe disc); aceasta metoda are antetul:

- void setIn(InputStream <in>)

- metoda setOut, care redirecteaza fluxul de iesire standard către o alta destinatie decat ecranul

calculatorului (de exemplu, un fisier pe disc); aceasta metoda are antetul:

void setOut(PrintStream <out>)

- metoda setErr, care redirecteaza fluxul de iesire standard al mesajelor de eroare către o alta

destinatie decat ecranul calculatorului (de exemplu, un fisier pe disc); aceasta metoda are antetul:

void setErr(PrintStream <out>)

Asocierea fluxului de intrare sau de iesire cu un filtru

Majoritatea claselor Java folosite in prezent permit realizarea de operatii de intrare/iesirmai

performante prin asocierea fluxului cu un filtru, inainte de a citi sau scrie date.

Un filtru este un tip de flux care schimba modul in care se lucreaza cu un flux existent.

Procedura de folosire a unui filtru pentru un flux presupune urmatorii pasi:

1. crearea (deschiderea) unui flux asociat cu sursa de date sau cu destinatia datelor;

2. crarea (deschiderea) unui flux de tip filtru asociat cu fluxul deschis la pasul 1;

3. citirea/scrierea datelor de la /in filtru si nu direct in flux.

Page 90: Programarea in Java - 2014 - an II ID.pdf

90

6.2 Fluxuri de octeti si clase predefinite Java

A. Fluxuri nefiltrate de octeti si clase predefinite utilizate

Fluxuri nefiltrate de octeti de intrare care folosesc ca sursa un fisier

Sunt folosite pentru transferul de date de la fisierele aflate pe hard-discuri, pe CD-ROM sau pe alte

dispozitive de stocare (ce pot fi referite printr-o cale de director si un nume) către aplicatia Java.

Crearea (deschiderea) unui flux de intrare de la un fisier se realizeaza cu ajutorulconstructorului

clasei FileInputStream, care are forma:

FileInputStream(String <sir>)

unde:

- <sir> - reprezinta numele, si eventual calea, fisierului; la specificarea caii fisierului trebuie sa se

foloseasca doua caractere backslash pentru a nu se confunda cu o secventa escape.

Daca fisierul nu poate fi deschis, atunci este lansata exceptia FileNotFoundException.

De exemplu, urmatoarea instrucțiune deschide un flux de intrare de la fisierul “test.dat”:

FileInputStream fis = new FileInputStream(“test.dat”);

Dupa deschiderea fluxului de intrare din fisier se pot folosi metodele acestui flux pentru realizarea

diverselor operatii de intrare. Descriem cateva dintre ele.

Metoda read() citeste un octet din fluxul de intrare; rezultatul intors este un intreg din intervalul 0 -

255. Daca s-a detectat sfarsitul de fisier, rezultatul intors este -1.

Metoda read cu trei parametrii are forma:

read (byte [] <b>, int <poz_ini>, int <lungime>)

unde:

- <b> - un tablou de octeti in care se vor memora datele citite;

- <poz_ini> - pozitia elementului din cadrul tabloului unde se va stoca primul octet de date;

- <lungime> - numarul de octeti care se vor citi din fluxul de intrare repetand metoda read fara

parametri.

Metoda returneaza un intreg care reprezinta numarul de octeti cititi sau -1 daca, de la inceput, fluxul

de intrare este la sfarsitul sau.

Metoda skip avanseaza cu n pozitii (octeti) in fluxul de intrare, nedepasind bineinteles sfarsitul

fluxului. Rezultatul intors de metoda este numarul de pozitii peste care s-a trecut efectiv.

Metoda skip are forma:

skip(long <n>)

unde :

<n> - nr de octeti sariti in fluxul de intrare.

Metoda available() este folosita pentru a returna numarul de octeti ce mai pot fi cititi la momentul

curent din fluxul de intrare.

Metoda close() inchide fluxul de intrare respectiv si elibereaza resursele sistem asociate cu acesta.

Page 91: Programarea in Java - 2014 - an II ID.pdf

91

De exemplu, programul “CitesteFiserOcteti .java” citeste octeti dintr-un flux de intrare al unui fisir

cu numele “test.doc”. Dupa citirea ultimului octet din fisier, pentru inchiderea fluxului de intrare se

foloseste metoda close(). Aceasta operatie trebuie realizata pentru a elibera resursele sistemului

asociate fisierului deschis.

Fisierul de intrare cu numele “test.dat” din care se citesc date in forma binara contine doua linii:

0123456789

Ionescu Florin

Acest fisier a fost creat cu utilitarul Notepad.

import java.io.*;

public class CitesteFisierOcteti

{

public static void main(String [] args)

{

try {

FileInputStream fis = new FileInputStream("test.dat");

int index = 0;

int octet = fis.read();

while (octet != -1)

{

System.out.print(octet + " ");

index++;

octet = fis.read();

}

fis.close();

System.out.println("\nOcteti cititi: " + index);

}

catch (IOException e) {

System.out.println("Eroare - " + e.getMessage());

}

}

}

Dupa executia programului va fi afisat fiecare octet din fisierul “test.dat”, urmat de numarul total de

octeti cititi, ca mai jos:

48 49 50 51 52 53 54 55 56 57 13 10 73 111 110 101 115 99 117 32 70 108 111 114

105 110

Octeti cititi: 26

Observatie: Se observa ca valorile octetilor afisati sunt codurile ASCII ale caracterelor din cele

doua linii existente in fisier.

Fluxuri nefiltrate de octeti de iesire care folosesc ca destinatie un fisier

Sunt folosite pentru transferul de date de la aplicatia Java către fisierele aflate pe hard-discuri, pe

CD-ROM sau pe alte dispozitive de stocare (ce pot fi referite printr-o cale de director si un nume).

Exemplu 1

Page 92: Programarea in Java - 2014 - an II ID.pdf

92

Crearea (deschiderea) unui flux de iesire către un fisier se realizeaza cu ajutorul constructorului

clasei FileOutputStream, care are forma:

FileOutputStream(String <sir>)

unde:

- <sir> - reprezinta numele, si eventual calea, fisierului; la specificarea caii fisierului trebuie sa se

foloseasca doua caractere backslash pentru a nu se confunda cu o secventa escape.

Trebuie sa se aiba o grija deosebita atunci cand se specifica numele fisierului in care se scrie. Daca

se foloseste numele unui fisier deja existent, odata cu inceperea scrierii datelor, acesta va fi sters

definitiv.

Constructorul cu doi parametrii are forma:

FileOutputStream(String <sir>, boolean <adauga>)

unde:

- <sir> - reprezinta numele, si eventual calea, fisierului; la specificarea caii fisierului trebuie sa se

foloseasca doua caractere backslash pentru a nu se confunda cu o secventa escape.

- <adauga> - poate avea valoare true, caz in care se face adaugarea datelor la sfarsitul fisierului,

sau poate avea valoarea false, caz in care nu se face adaugarea de date la sfarsitul fisierului ci

suprascrierea datele existente; daca fisierul nu poate fi deschis, atunci este lansata exceptia

FileNotFoundException.

De exemplu, urmatoarea instrucțiune deschide un flux de iesire către fisierul “test1.dat”:

FileOutputStream fis = new FileOutStream(“test1.dat”);

Urmatoarea instrucțiune deschide un flux de iesire către fisierul “test1.dat” pentru a adauga octeti la

sfarsitul fisierului:

FileOutputStream fis = new FileOutStream(“test1.dat”, true);

Dupa deschiderea fluxului de iesire din fisier se pot folosi metodele acestui flux pentru realizarea

diverselor operatii de iesire. Descriem cateva dintre ele.

Metoda write cu un parametru scrie un octet in fluxul de iesire. Aceasta metoda are forma:

write(int <b>)

unde: <b> - variabila care contine octetul de scris in fluxul de iesire.

Metoda write cu doi parametrii scrie un tablou de octeti in fluxul de iesire si are forma:

write (byte [] <b>)

unde:

- <b> - specifica un tablou de octeti care va fi scris in fluxul de iesire; in fisier vor fi scrisi

b.length octeti.

Metoda write cu trei parametrii are forma:

write (byte [] <b>, int <poz_ini>, int <lungime>)

unde:

- <b> - specifica un tablou de octeti care va fi scris in fluxul de iesire;

- <poz_ini> - pozitia elementului din cadrul tabloului de la care se incepe scrierea in fluxul

de iesire;

- <lungime> - numarul de octeti care se vor scrie in fluxul de iesire.

Metoda close() inchide fluxul de iesire respectiv.

Page 93: Programarea in Java - 2014 - an II ID.pdf

93

Programul urmator (ScrieFisierOcteti.java) scrie un tablou de octeti intr-un flux de iesire intr-un

fisier date cu numele “test1.gif”. Dupa scrierea ultimului octet in fisier, pentru inchiderea fluxului

de iesire se foloseste metoda close(). Aceasta operatie trebuie realizata pentru a elibera resursele

sistemului asociate fisierului deschis.

import java.io.*;

public class ScrieFisierOcteti

{

public static void main (String [] args)

{

int [] octeti = { 71, 73, 70, 56, 57, 97, 15, 0, 15, 0,

128, 0, 0, 111, 111, 111, 0, 0, 0, 44, 0, 0, 0,

0, 15, 0, 15, 0, 0, 2, 33, 132, 127, 161, 200,

185, 205, 84, 128, 241, 81, 35, 175, 155, 26,

228, 25, 105, 33, 102, 0, 165, 201, 145, 169,

154, 142, 112, 0, 200, 200, 0, 200, 200, 200, 200 } ;

try {

FileOutputStream fis = new FileOutputStream("test1.gif");

for (int i = 0; i < octeti.length; i++)

fis.write(octeti[i]);

fis.close();

}

catch(IOException e) {

System.out.println("Eroare - " + e.getMessage());

}

}

}

B. Filtrarea fluxurilor de octeti si clase predefinite Java utilizate

Fluxurile filtrate sunt fluxuri care selecteaza si, astfel, modifica informatia transmisa printr-un flux

existent (de tip InputStream sau OutputStream). Acestea sunt create folosind subclase ale claselor

FilterInputStream si FilterOutputStream.

Fluxurile FilterInputStream si FilterOutputStream nu realizeaza in mod direct nici un fel de

operatie de filtrare. Dar, din ele deriveaza subclase (de exemplu, BufferedInputStream) care sunt

folosite pentru anumite tipuri de filtrari.

B.1 Fluxuri de octeti cu o zona tampon (“buffer”)

Un tampon (“buffer”) reprezinta o zona de memorie RAM in care se pot pastra date din fluxul de

intrare sau de iesire pana la momentul citirii sau scrierii lor intr-o aplicație Java. Prin folosirea unui

tampon se pot accesa (citi sau scrie) date fara a folosi sursa originala (fisierul) sau destinatia

originala (fisierul) de date.

Exemplu 2

Page 94: Programarea in Java - 2014 - an II ID.pdf

94

Zona tampon este folosita ca o zona intermediara pentru citirea/ scrierea datelor din/in fluxul de

intrare/iesire. Pentru memoria tampon se mai foloseste si termenul de “memorie de lucru”.

Aceasta tehnica este mai eficienta intrucat utilizarea zonei tampon evita accesarea fisierului pentru

fiecare citire/scriere, in acest mod micsorandu-se timpul de lucru al aplicației Java.

Nota: Deoarece fluxurile de intrare/iesire cu tampon semnaleaza exceptia IOException la aparitia

unei erori, toate operatiile legate de fluxuri se incadreaza in blocuri try … catch, care sa

intercepteze aceasta exceptie.

Fluxuri de octeti de intrare cu o zona tampon

Un flux de intrare cu tampon poseda un tampon cu date din care se face citirea. Cand aplicatia Java

citeste date, acestea sunt cautate mai intai in zona tampon si apoi in sursa originala de intrare.

Fluxurile de octeti de intrare cu tampon folosesc clasa BufferedInputStream.

Crearea (deschiderea) unui flux de intrare cu tampon se realizeaza cu ajutorul constructorilor clasei

BufferedInputStream. Cand este deschis un flux de intrare cu tampon se creaza si o zona tampon,

sub forma unui tablou de octeti, atasata acestuia.

Constructorii clasei BufferedInputStream au una din formele:

a) BufferedInputStream(InputStream <in>)

unde:

- <in> - reprezinta fluxul original de tip InputStream.

Nota: Zona tampon are o lungime care este aleasa implicit (automat).

b)BufferedInputStream(InputStream <in>, int <lg_buffer>)

unde:

- <in> - reprezinta fluxul original de tip InputStream;

- <lg_buffer> - reprezinta lungimea zonei tampon a fluxului de intare.

Dupa deschiderea fluxului de intrare cu tampon se pot folosi metodele acestui flux pentru realizarea

diverselor operatii de intrare. Descriem cateva dintre ele.

Metoda read() citeste un octet din fluxul de intrare cu tampon; rezultatul intors este un intreg din

intervalul 0 - 255. Daca s-a detectat sfarsitul de fisier, rezultatul intors este -1.

Metoda read cu trei parametrii are forma:

read (byte [] <b>, int <poz_ini>, int <lungime>)

unde:

- <b> - un tablou de octeti in care se vor memora datele citite;

- <poz_ini> - pozitia elementului din cadrul tabloului unde se va stoca primul octet de date;

- <lungime> - numarul de octeti care se vor citi din fluxul de intrare cu tampon repetand metoda

read fara parametri.

Metoda returneaza un intreg care reprezinta numarul de octeti cititi sau -1 daca, de la inceput, fluxul

de intrare este la sfarsitul sau.

Metoda skip avanseaza cu n pozitii (octeti) in fluxul de intrare cu tampon si descarca n octeti din

flux, nedepasind, bineinteles, sfarsitul fluxului. Rezultatul intors de metoda este numarul de pozitii

peste care s-a trecut efectiv.

Metoda skip are forma:

skip(long <n>)

unde :

<n> - nr de octeti sariti in fluxul de intrare si descarcati din fluxul de intare.

Metoda available() este folosita pentru a returna numarul de octeti ce mai pot fi cititi la momentul

curent atat din zona tampon, cat si din fluxul de intrare.

Page 95: Programarea in Java - 2014 - an II ID.pdf

95

Metoda close() inchide fluxul de intrare cu tampon si elibereaza resursele sistem asociate cu acesta.

Fluxuri de octeti de iesire cu o zona tampon

Un flux de iesire cu tampon poseda un tampon cu date care nu au fost inca scrise in destinatia

originala a fluxului. Atunci cand datele sunt directionate intr-un flux de iesire cu tampon, continutul

acestuia nu va fi transmis către destinatie decat dupa ce zona tampon atasata s-a umplut. Fluxurile

de octeti de iesire cu tampon folosesc clasa BufferedOutputStream.

Crearea (deschiderea) unui flux de iesire cu tampon se realizeaza cu ajutorul constructorilor clasei

BufferedOutputStream. Cand este deschis un flux de iesire cu tampon se creaza si o zona tampon,

sub forma unui tablou de octeti, atasata acestuia.

Constructorii clasei BufferedOutputStream au una din formele:

a) BufferedOuputStream(OutputStream <out>)

unde:

- <out> - reprezinta fluxul de iesire de tip OutputStream.

Nota: Zona tampon are o lungime care este aleasa implicit (automat).

b)BufferedOutputStream(OutputStream <out>, int <lg_buffer>)

unde:

- <out> - reprezinta fluxul de iesire de tip OutputStream;

- <lg_buffer> - reprezinta lungimea zonei tampon a fluxului de iesire.

Dupa deschiderea fluxului de iesire cu tampon se pot folosi metodele acestui flux pentru realizarea

diverselor operatii de iesire. Descriem cateva dintre ele.

Metoda write cu un parametru scrie un octet in fluxul de iesire cu tampon. Aceasta metoda are

forma:

write(int <b>)

unde: <b> - variabila care contine octetul de scris in fluxul de iesire cu tampon; valoarea acestei

variabile trebuie sa apartina intervalului 0 - 255; daca se incearca scrierea unei valori care este mai

mare decat 255 va fi stocat numai restul impartirii acestei valori la 256.

Metoda write cu trei parametrii are forma:

write (byte [] <b>, int <poz_ini>, int <lungime>)

unde:

- <b> - specifica un tablou de octeti care va fi scris in fluxul de iesire cu tampon;

- <poz_ini> - pozitia elementului din cadrul tabloului de la care se incepe scrierea in fluxul de iesire

cu tampon;

- <lungime> - numarul de octeti care se vor scrie in fluxul de iesire cu tampon.

Metoda flush() transmite (scrie) continutul zonei tampon la destinatia fluxului de iesire original

chiar daca aceasta zona tampon nu s-a umplut inca. Cu ajutorul acestei metode se realizeaza golirea

zonei tampon chiar daca aceasta nu s-a umplut inca.

Metoda close() inchide fluxul de iesire cu tampon si elibereaza resursele sistem asociate cu acesta.

Urmatorul program (IOBinarTampon.java) scrie o serie de octeti intr-un flux de iesire cu tampon

asociat cu un fisier pe disc. Limita inferioara si limita superioara din seria de numere sunt

specificate in doua argumente transmise prin linia de comanda, ca in exemplul urmator:

Page 96: Programarea in Java - 2014 - an II ID.pdf

96

java IOBinarTampon 2 30

Daca nu se transmit argumente prin linia de comanda, implicit limita inferioara este 0 iar

limita superioara este 255.

Dupa scrierea in fisier, programul deschide un flux de intrare cu tampon si citeste octetii

scrisi in fisier.

import java.io.*;

public class IOBinarTampon {

public static void main (String [] args) {

int limInf = 0;

int limSup = 255;

try {

if (args.length > 1)

{

limInf = Integer.parseInt(args[0]);

limSup = Integer.parseInt(args[1]); }

else

if(args.length > 0)

limInf = Integer.parseInt(args[0]);

FluxOcteti fo = new FluxOcteti(limInf, limSup); System.out.println("\nScrie: ");

boolean succesScrie = fo.scrieFlux(); System.out.println("\nCiteste: ");

boolean succesCiteste = fo.citesteFlux(); }

catch(NumberFormatException nfe) {

System.out.println("Eroare: " + "Nu ati introdus un numar intreg");

}

}

}

class FluxOcteti {

private int inceput = 0;

private int sfarsit = 255; public FluxOcteti(int inceput, int sfarsit) {

this.inceput = inceput;

this.sfarsit = sfarsit;

}

boolean scrieFlux() {

try {

BufferedOutputStream fluxTampon = new BufferedOutputStream(

new FileOutputStream("numere.dat")); for (int i = inceput; i <= sfarsit; i++)

{

fluxTampon.write(i); System.out.print(" " + i);

}

fluxTampon.close(); return true;

Exemplu 3

Page 97: Programarea in Java - 2014 - an II ID.pdf

97

}

catch(IOException e) {

System.out.print("Eroare: " + e.getMessage());

return false;

}

}

boolean citesteFlux() {

try {

BufferedInputStream fluxTampon = new BufferedInputStream(

new FileInputStream("numere.dat")); int i = 0;

do

{

i = fluxTampon.read(); if (i != -1)

System.out.print(" " + i);

} while (i != -1);

fluxTampon.close(); return true;

}

catch(IOException e) {

System.out.print("Eroare: " + e.getMessage());

return false;

}

}

}

Observatie: Aplicatia Java prezentata mai sus poate primi unul sau doua argumente atunci cand este

lansata. Modul de transmitere a unor argumente la aplicații Java depinde de platforma pe care se

execută Java. In Windows si Unix se pot transmite argumente prin intermediul liniei de comanda.

Argumentele trebuie adaugate la executie dupa numele programului si daca sunt mai multe decat

unul, atunci argumentele sunt separate prin spatii.

In cadrul aplicației Java, argumentele din linia de comanda sunt preluate de metoda main() sub

forma unui tablou de siruri:

public static void main(String [] args) {

//corpul metodei

}

Argumentele din linia de comanda sunt stocate in tabloul de siruri de caractere incepand cu primul

element din tablou (care are indexul 0). Deci, in tabloul de siruri de caractere al metodei main() nu

se preia si numele programului ca la C/C++.

Observatie: Aplicatia Java prezentata mai sus poate primi unul sau doua argumente atunci cand este

lansata. Modul de transmitere a unor argumente la aplicații Java depinde de platforma pe care se

execută Java. In Windows si Unix se pot transmite argumente prin intermediul liniei de comanda.

Argumentele trebuie adaugate la executie dupa numele programului si daca sunt mai multe decat

unul, atunci argumentele sunt separate prin spatii.

Page 98: Programarea in Java - 2014 - an II ID.pdf

98

In cadrul aplicației Java, argumentele din linia de comanda sunt preluate de metoda main() sub

forma unui tablou de siruri:

public static void main(String [] args) {

//corpul metodei

}

Argumentele din linia de comanda sunt stocate in tabloul de siruri de caractere incepand cu primul

element din tablou (care are indexul 0). Deci, in tabloul de siruri de caractere al metodei main() nu

se preia si numele programului ca la C/C++.

B2. Fluxuri filtrate cu date de tipuri primitive

Clasele DataInputStream si DataOutputStream ofera, ca facilitate suplimentara, posibilitatea ca

fluxurile sa nu mai fie privite strict la nivel de octet, ci ca succesiuni de date primitive. Prin aceasta,

datele vor fi scrise in fluxul de iesire intr-un format independent de modul de reprezentare al datelor

in sistemul pe care se lucreaza.

Constructorul clasei DataInputStream creaza un nou flux de intrare ce suprapune pe cel existent

primit ca argument. Constructorul are forma:

DataInputStream(InputStream <in>) unde:

- <in> - specifica fluxul de intrare existent, de exemplu, un flux de intrare cu tampon sau un

flux de intrare din fisier.

Constructorul clasei DataOutputStream creaza un nou flux de iesire ce suprapune pe cel existent

primit ca argument. Constructorul are forma:

DataOutputStream(OutputStream <out>) unde:

- <out> - specifica fluxul de iesire existent, de exemplu, un flux de iesire cu tampon sau un flux de

iesire in fisier.

Deoarece fluxurile filtrate de intrare/iesire cu date de tipuri primitive semnaleaza exceptia

IOException la aparitia unei erori, toate operatiile legate de fluxuri se incadreaza in blocuri try …

catch, care sa intercepteze aceasta exceptie.

Urmatoarea lista prezinta metodele de citire si de scriere ce pot fi folosite pentru fluxurile de tipul

DataInputStream, si respectiv de tipul DataOutputStream:

- readBoolean(); writeBoolean(boolean <v>);

- readChar(); writeChar(char <v>);

- readDouble(); writeDouble(double <v>);

- readFloat(); writeFloat(float <v>);

- readInt(); writeInt(int <v>);

- readLong(); writeLong(long <v>);

- readShort(); writeShort(short <v>);

Fiecare dintre metodele de citire prezentate incearca sa citeasca un numar de octeti egal cu

lungimea pe care sunt reprezentate tipurile respective indicate in numele metodei. De exemplu,

metoda readBoolean() citeste un octet si returneaza true daca octetul citit este diferit de zero.

Fiecare dintre metodele de scriere prezentate incearca sa scrie un numar de octeti egal cu lungimea

pe care sunt reprezentate tipurile respective indicate in numele metodei. De exemplu, metoda

writeBoolean() scrie intr-un octet valoarea 1 sau valoarea 0, dupa cum parametrul <v> este true sau

false.

Observatii:

Page 99: Programarea in Java - 2014 - an II ID.pdf

99

1. Datele citite folosind metodele clasei DataInputStream trebuie sa fi fost scrise in fisier cu

metodele complementare ale clasei DataOutputStream.

2. Nu toate metodele de citire dintr-un flux de tip DataInputStream returneaza o valoare ce poate

indica faptul ca s-a ajuns la sfarsitul fluxului. In astfel de cazuri se semnaleaza exceptia

EOFException care indica faptul ca s-a ajuns la sfarsitul fluxului de intrare.

Urmatorul program (IODataTampon.java) scrie o serie de valori de tip float intr-un flux de iesire

DataOutputStream cu tampon asociat cu un fisier pe disc. Limita inferioara si limita superioara din

seria de numere reale sunt specificate in doua argumente transmise prin linia de comanda, ca in

exemplul urmator:

java IOBinarTampon 2 30

Daca nu se transmit argumente prin linia de comanda, implicit limita inferioara este 0 iar limita

superioara este 255.

Dupa scrierea in fisier, programul deschide un flux de intrare cu tampon si citeste datele de tip float

scrise in fisier.

import java.io.*;

public class IODataTampon {

public static void main (String [] args) {

float limInf = 0;

float limSup = 255;

try {

if (args.length > 1)

{

limInf = Float.parseFloat(args[0]);

limSup = Float.parseFloat(args[1]); }

else

if(args.length > 0)

limInf = Float.parseFloat(args[0]); FluxDatePrimitive fd = new FluxDatePrimitive(limInf, limSup);

boolean succesScrie = fd.scrieFlux();

System.out.println("\nCiteste: ");

boolean succesCiteste = fd.citesteFlux();

}

catch(NumberFormatException nfe) {

System.out.println("Eroare: " + "Nu ati introdus un numar real");

}

}

}

class FluxDatePrimitive {

private float inceput = 0;

private float sfarsit = 255;

public FluxDatePrimitive(float inceput, float sfarsit) {

this.inceput = inceput;

this.sfarsit = sfarsit;

}

boolean scrieFlux() {

try {

Exemplu 4

Page 100: Programarea in Java - 2014 - an II ID.pdf

100

DataOutputStream fluxDate = new DataOutputStream(

new BufferedOutputStream(new FileOutputStream("numere.dat"))); for (float i = inceput; i <= sfarsit; i+=0.5)

fluxDate.writeFloat(i);

fluxDate.close(); return true;

}

catch(IOException e) {

System.out.print("Eroare: " + e.getMessage());

return false;

}

}

boolean citesteFlux() {

try {

DataInputStream fluxDate = new DataInputStream(

new BufferedInputStream(new FileInputStream("numere.dat"))); float i = 0;

try {

while (true)

{

i = fluxDate.readFloat(); System.out.print(" " + i);

}

}

catch(EOFException eof) {

fluxDate.close(); }

return true;

}

catch(IOException e) {

System.out.print("Eroare: " + e.getMessage());

return false;

}

}

}

Aplicatia prezentata este un exemplu de suprapunere a mai multor filtre peste un flux original de tip

FileInputStream. Fluxul filtrat este construit in trei etape:

- se creaza un flux de iesire in fisier, asociat cu fisierul “numere.dat”;

- se asocieaza fluxului de fisier un flux de iesire filtrat cu tampon;

- se asociaza fluxului de iesire cu tampon un flux de tip DataInputStream.

Instrucțiunea while(true) din metoda citesteFlux() creaza un ciclu infinit in aparenta, pentru ca la un

moment dat va fi atins sfarsitul fluxului si va fi semnalata o exceptie EOFException. Metoda

readFloat() citeste valorile intregi din flux.

B3. Fluxuri filtrate cu date formatate

Clasa PrintStream furnizeaza un flux filtru de iesire care permite afisarea de numere, valori

boolean, String si alte tipuri de obiecte in format text. Filtrul de iesire PrintStream converteste

numerele si alte tipuri de date la reprezentari text, inainte de transmiterea datelor la fluxul de iesire.

Page 101: Programarea in Java - 2014 - an II ID.pdf

101

De exemplu, atunci cand programul afiseaza valoarea intreaga 42, clasa PrintStream converteste

numarul la caracterele “4” si “2” si apoi transmite caracterele mai departe in flux.

In plus, fluxul PrintStream da posibilitatea (optional) de a goli automat zona tampon dupa ce a fost

scris un tablou de octeti sau un octet egal cu ‘\n’. Metodele acestei clase nu semnaleaza niciodata

exceptia IOException.

Fluxul System.out, pe care l-am folosit aproape in toate lectiile de pana acum pentru afisarea

mesajelor la ecranul calculatorului, este de fapt un flux de tip PrintStream.

Prezentam doi dintre constructorii acestei clase:

PrintStream(OutputStream <out>)

PrintStream(OutputStream <out>, boolean <auto_golire>)

unde:

- <out> - specifica fluxul de iesire existent;

<auto_golire> - specifica daca se goleste automat zona tampon dupa ce a fost scris un tablou de

octeti sau un octet egal cu ‘\n’ (daca valoarea este true).

Mentionam cateva metode ale acestei clase:

- print (String <s>)

- print (char <c>)

- print (boolean <b>)

- print (char <c>)

- print (int <i>)

- print (long <l>)

- print (float <f>)

- print (double <d>)

Pentru fiecare metoda print exista si perechea ei println, care adauga caracterul ‘\n’ in fluxul de

iesire.

In plus, exista si metoda println fara parametrii, care scrie doar caracterul de sfarsit de linie ‘\n’.

Metodele print si println scriu argumentul lor intr-un format de tip text si anume identic cu cel

produs de apelurile metodei String.valueOf(x).

Un flux PrintStream nu are ca destinatie numai ecranul calculatorului ci orice destinatie de flux,

inclusiv un fisier text ASCII. De exemplu, urmatoul program (PrintStreamFile.java) afiseaza un

String, un intreg si un numar in virgula mobila intr-un fisier, “print.txt”.

import java.io.*;

public class PrintStreamFile {

public static void main(String [] args) {

double nr1 = 234.5;

int nr2 = 120;

try {

PrintStream ps = new PrintStream(new FileOutputStream("print.txt"));

ps.println ("Date pentru testarea fluxului PrintStream");

ps.print(nr1);

ps.print(' ');

ps.print(nr2);

ps.println();

ps.println(Math.PI);

ps.close();

}

catch(IOException e) {

System.out.println("Eroare la scrierea fisierului: " + e.getMessage());

}

Page 102: Programarea in Java - 2014 - an II ID.pdf

102

}

}

6.3 Fluxuri de caractere si clase predefinite Java utilizate

Fluxurile de caractere se folosesc pentru lucrul cu orice text reprezentat in format ASCII sau

Unicode (set de caractere international care include si ASCII). Ele opereaza asupra sirurilor de

caractere si tablourilor de caractere.

Exemple de fisiere cu care putem lucra prin intermediul fluxurilor de caractere sunt fisierele de text

simplu, documentele HTML sau fisiere care contin cod sursa Java.

A. Fluxuri de caractere de intrare nefiltrate si filtrate

Clasa Reader este o clasa abstracta si din ea deriveaza toate celelalte clase care creaza fluxuri de

caractere de intrare si realizeaza operatii de intrare pe aceste fluxuri.

Nota: Deoarece fluxurile de intrare semnaleaza exceptia IOException la aparitia unei erori, toate

operatiile legate de fluxuri se incadreaza in blocuri try … catch, care sa intercepteze aceasta

exceptie.

Este indicat sa folosim clasa Reader pentru lucru cu text si nu fluxuri de octeti.

A.1 Fluxuri nefiltrate de caractere de intrare care folosesc ca sursa un fisier

Sunt folosite pentru transferul de date de la fisierele aflate pe hard-discuri, pe CD-ROM sau pe alte

dispozitive de stocare (ce pot fi referite printr-o cale de director si un nume) către aplicatia Java.

Principala clasa folosita pentru citirea de fluxuri de caractere dintr-un fisier este FileReader.

Aceasta clasa mosteneste clasa InputStreamReader, care citeste un flux de octeti si ii converteste in

valori intregi corespunzatoare caracterelor Unicode.

Crearea (deschiderea) unui flux de intrare de la un fisier se realizeaza cu ajutorul constructorului

clasei FileReader, care are forma:

FileReader(String <sir>)

unde:

- <sir> - reprezinta numele, si eventual calea, fisierului; la specificarea caii fisierului trebuie sa se

foloseasca doua caractere backslash pentru a nu se confunda cu o secventa escape.

Daca fisierul nu poate fi deschis, atunci este lansata exceptia FileNotFoundException.

De exemplu, urmatoarea instrucțiune deschide un flux de intrare de la fisierul “test.doc”:

FileReader document = new FileReader(“test.doc”);

Dupa deschiderea fluxului de caractere de intrare din fisier se pot folosi metodele acestui flux

pentru realizarea diverselor operatii de intrare. Descriem cateva dintre ele.

Metoda read() citeste un caracter din fluxul de intrare; rezultatul intors este un intreg din intervalul

0 - 65535. Daca s-a detectat sfarsitul de fisier, rezultatul intors este -1.

Metoda read cu trei parametrii are forma:

read (char [] <c>, int <poz_ini>, int <lungime>)

unde:

- <c> - un tablou de caractere in care se vor memora datele citite;

- <poz_ini> - pozitia elementului din cadrul tabloului unde se va stoca primul caracter de date;

Page 103: Programarea in Java - 2014 - an II ID.pdf

103

- <lungime> - numarul de caractere care se vor citi din fluxul de intrare repetand metoda read fara

parametri.

Metoda returneaza un intreg care reprezinta numarul de caractere citite sau -1 daca, de la inceput,

fluxul de intrare este la sfarsitul sau.

Nota: Deoarece metoda read() a unui flux de caractere returneaza o valoare intreaga, trebuie sa se

converteasca explicit prin cast aceasta valoare inainte de a o afisa sau de a o salva intr-un tablou de

caractere. Fiecare caracter poseda un cod numeric care reprezinta pozitia sa in setul de caractere

Unicode. Valoarea intreaga citita din flux reprezinta chiar acest cod numeric.

Metoda skip avanseaza cu n pozitii (caractere) in fluxul de intrare, nedepasind bineinteles sfarsitul

fluxului. Rezultatul intors de metoda este numarul de pozitii peste care s-a trecut efectiv.

Metoda skip are forma:

skip(long <n>)

unde :

<n> - nr de caractere sarite in fluxul de intrare.

Metoda ready() specifica daca acest flux de caractere este disponibil pentru a fi citit. Un flux de

caractere dintr-un fisier este disponibil pentru a fi citit daca zona tampon de intrare nu este goala (in

caz ca ea exista) sau daca exista octeti disponibili de a fi cititi de la fluxul de octeti de tip

InputStreamReader.

Metoda close() inchide fluxul de intrare respectiv si elibereaza resursele sistem asociate cu acesta.

A.2 Fluxuri filtrate de caractere de intrare cu o zona tampon (“buffer”)

Fluxurile de caractere cu o zona tampon (“buffer”) permit utilizarea unei zone tampon pentru

cresterea eficientei operatiilor de citire.

Fluxurile de caractere de intrare cu tampon folosesc clasa BufferedReader.

Crearea (deschiderea) unui flux de caractere cu tampon se realizeaza cu ajutorul constructorilor

clasei BufferedReader.

Constructorii clasei BufferedReader au una din formele:

a) BufferedReader(Reader <in>)

unde:

- <in> - reprezinta fluxul original de tip Reader.

Nota: Zona tampon are o lungime care este aleasa implicit (automat).

b) BufferedReader(Reader <in>, int <lg_buffer>)

unde:

- <in> - reprezinta fluxul original de tip Reader;

- <lg_buffer> - reprezinta lungimea zonei tampon a fluxului de intare.

Dintr-un flux de caractere cu tampon se poate citi folosind metodele read() si

read (char [] <c>, int <poz_ini>, int <lungime>) , asemanatoare celor descrise pentru clasa

FileReader.

Metodele skip(), ready() si close() sunt asemanatoare celor descrise pentru clasa FileReader.

Programul urmator (CitesteSiruri.java) citeste doua siruri de caractere de la tastatura si le stocheaza

intr-un tablou de caractere de lungime 20. Daca dupa citirea primului sir, in zona tampon mai exista

caractere necitite (ceea ce inseamna ca s-a introdus un sir de lungime mai mare de 20) atunci

acestea vor fi sarite din fluxul de intrare pentru a permite eliberarea zonei tampon si citirea de la

tastatura a celui de al doilea sir.

Page 104: Programarea in Java - 2014 - an II ID.pdf

104

import java.io.*;

class CitesteSiruri {

public static void main(String[] args)

{

char[] caractere1 = new char[20];

char[] caractere2 = new char[20];

for (int i=0; i <=19; i++)

caractere1[i] = ' ';

for ( int i=0; i <=19; i++)

caractere2[i] = ' ';

try {

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

System.out.println ("Introduceti primul sir");

br.read(caractere1, 0, 20); String sir1 = new String(caractere1);

System.out.println(sir1);

while (br.ready() )

br.skip (1); System.out.println ("Introduceti al doilea sir");

br.read(caractere2, 0, 20); String sir2 = new String(caractere2);

System.out.println(sir2);

boolean rezultat = false;

rezultat = sir1.equals(sir2);

if (rezultat ==true)

System.out.println ("siruri egale");

else

System.out.println ("siruri diferite");

}

catch(IOException e) {

System.out.println ("Eroare la sirul citit" + e.getMessage());

}

}

}

Metoda readLine() citeste din fluxul de intrare o linie de text. Metoda returneaza un obiect de tip

String care contine linia de text citita din flux , fara a include si caracterul (sau caracterele) care

reprezinta sfarsitul de linie. Daca se ajunge la sfarsitul fluxului, valoarea sirului returnat va fi null.

Sfarsitul de linie este indicat astfel:

- un caracter de linie noua (newline - ‘\n’);

- un caracter de retur de car (carriage return - ‘\r’);

- un retur de car urmat de o linie noua.

Ca exemplu, putem ilustra deschiderile de flux de intare cu tampon si citirile de linii de text de la

tastatura, facute in aproape toate programele Java prezentate pana acum.

Dintr-un fisier se poate citi o intreaga linie de text, si nu caracter cu carecter, daca se foloseste un

flux de caractere cu tampon de tip BufferedReader suprapus peste un flux de tip FileReader.

Exemplu 5

Page 105: Programarea in Java - 2014 - an II ID.pdf

105

Programul urmator (CitesteLiniiFisier.java) ilustreaza modul de citire linie cu linie dintr-un fisier

care contine instructiuni Java (numit “CitesteLiniiFisier.java”), folosind un flux de caractere cu

zona tampon.

import java.io.*;

public class CitesteLiniiFisier {

public static void main (String [] args) {

try {

BufferedReader fisier = new BufferedReader(

new FileReader("CitesteLiniiFisier.java")); boolean eof = false;

while(!eof)

{

String linie = fisier.readLine(); if (linie == null)

eof = true;

else

System.out.println(linie);

}

fisier.close(); }

catch(IOException e) {

System.out.println("Eroare: " + e.getMessage());

}

}

}

A.3 Fluxuri filtrate de caractere de intrare cu o zona tampon care tin evidenta numerelor de

linie

Fluxurile de caractere de intrare cu tampon care tin evidenta numerelor de linie dintr-un fisier

folosesc clasa LineNumberReader. Acest filtru al fluxului de intrare urmareste numarul de linie pe

masura citirii din fluxul de intrare.

Crearea (deschiderea) unui flux de caractere cu tampon care tin evidenta numerelor de linie se

realizeaza cu ajutorul constructorilor clasei LineNumberReader.

Constructorii clasei LineNumberReader au una din formele:

a) LineNumberReader(Reader <in>)

unde:

- <in> - reprezinta fluxul original de tip Reader.

Nota: Zona tampon are o lungime care este aleasa implicit (automat).

b) LineNumberReader(Reader <in>, int <lg_buffer>)

unde:

- <in> - reprezinta fluxul original de tip Reader;

- <lg_buffer> - reprezinta lungimea zonei tampon a fluxului de intare.

Metodele pentru citirea, inchiderea, testarea unui flux de intrare cu tampon sunt mostenite de la

clasa BufferedReader si ele au fost prezentate deja.

In plus, aceasta clasa ofera metoda getLineNumber() care este folosita pentru a obtine numarul

liniei curente din fluxul de intrare atunci cand acesta este citit cu metoda readLine().

Metoda returneaza un intreg care reprezinta numarul liniei curente din flux.

Page 106: Programarea in Java - 2014 - an II ID.pdf

106

Dintr-un fisier se poate citi o intreaga linie de text si se poate tine evidenta numerelor citite daca se

foloseste un flux de caractere cu tampon de tip LineNumberReader suprapus peste un flux de tip

FileReader.

Programul urmator (CitesteLiniiFisier.java) afiseaza numerele liniilor citite dintr-un fisier care

contine instructiuni Java (numit “CitesteLiniiFisier1.java”), folosind un flux de caractere cu zona

tampon tip LineNumberReader.

import java.io.*;

public class CitesteLiniiFisier1 {

public static void main (String [] args) {

try {

LineNumberReader fisier = new LineNumberReader(new

FileReader("CitesteLiniiFisier1.java"));

boolean eof = false;

while(!eof)

{

String linie = fisier.readLine();

if (linie == null)

eof = true;

else

System.out.println(fisier.getLineNumber() + " " + linie);

}

fisier.close();

}

catch(IOException e) {

System.out.println("Eroare: " + e.getMessage());

}

}

}

Page 107: Programarea in Java - 2014 - an II ID.pdf

107

Formular de feedback

În dorinţa de ridicare continuă a standardelor desfăşurării activitatilor dumneavoastra, va rugăm să completaţi acest chestionar şi să-l

transmiteţi indrumatorului de an.

Disciplina: ________________________

Unitatea de invatare/modulul:__________________

Anul/grupa:__________________________

Tutore:_________________________

a) Conţinut / Metoda de predare

Partea I

1. Care dintre subiectele tratate in aceasta unitate/modul consideraţi că este cel mai util şi eficient? Argumentati raspunsul.

2. Ce aplicații/proiecte din activitatea dumneavoastra doriţi să imbunatatiti/modificaţi/implementaţi în viitor în urma cunoştinţelor

acumulate în cadrul acestei unitati de invatare/modul?

3. Ce subiecte consideraţi că au lipsit din acesta unitate de invatare/modul?

4. La care aplicații practice ati intampinat dificultati in realizare? Care credeti ca este motivul dificultatilor intalnite?

5. Daca ar fi sa va evaluati, care este nota pe care v-o alocati, pe o scala de la 1-10?. Argumentati.

Partea II. Impresii generale

1. Acest modul a întrunit aşteptările dumneavoastră?

2) Aveţi sugestii care să conducă la creşterea calităţii acestei unitati de invatare/modul?

3) Aveţi propuneri pentru alte unitati de invatare?

Vă mulţumim pentru feedback-ul dumneavoastră

În totalitate

În mare măsură În mică măsură Nu

Page 108: Programarea in Java - 2014 - an II ID.pdf

108

Bibliografie

1. Horia Georescu, “Introducere in universul Java”, Editura Tehnica,2002.

2. Kevin Taylor, Java Programming Tutorial, http://java.about.com/od/beginningjava/a/beginjavatutor.htm

3. Bruce Eckel, Thinking in Java, 3rd ed. Revision 4.0, http://arh.pub.ro/mirrors/eckelbooks/TIJ3/TIJ3.htm

4. Sun Microsystems, The Java™ Tutorials, http://java.sun.com/docs/books/tutorial/java/TOC.html

5. Stefan Tanasa, Cristian Olaru, Stefan Andrei, “JAVA de la 0 la expert”, Editura Polirom, 2003.

6. Bruce Eckel, “Thinking in Java, 3rt Edision”, Editura Prentice – Hall, 2002.

7. Doina Logofatu, “Algoritmi fundamentali in Java. Aplicații “, Editura Polirom 2007.