Laborator JAVA IESC UNITBV PDF
Laborator JAVA IESC UNITBV PDF
Laborator JAVA IESC UNITBV PDF
Introducere în Java
2 octombrie 2011
I. NOŢIUNI TEORETICE
A. Ce este Java?
Java nu este doar un limbaj de programare ci este şi mediu de programare ce oferă utilizato-
rului atât cadrul cât şi uneltele necesare pentru a dezvolta aplicaţii Java. Limbajul Java poate fi
caracterizat ca un limbaj:
1. simplu: tehnologia Java conţine aşa numitul Garbage Colector care eliberează programatorul
de grija dezalocării memoriei.
3. robust: un program Java este mai puţin supus erorilor datorită celor două nivele de verificare
ale acestuia. Un nivel de verificare este la compilare şi unul este la rulare.
4. orientat pe obiecte: spre deosebire de limbajul C++, Java este în întregime orientat pe
obiecte.
5. dinamic: multe decizii privind evoluţia programului se iau in momentul rulării, la runtime.
6. ce asigură un nivel ridicat de securitate: programele Java sunt verificate pas cu pas în timpul
rulării, astfel evitându-se accesul la zone nepermise.
7. independent de platformă: un program Java poate fi rulat pe orice platformă pe care a fost
instalată o maşină virtuală Java (Java Virtual Machine).
8. adaptat pentru multithreading: tehnologia Java permite ca un program să execute mai multe
sarcini aparent în acelaşi timp, utilizând mai multe fire de execuţie (thread-uri).
B. Pachetul JDK
Mediul JDK (Java Developers Kit) conţine o serie de biblioteci de clase Java necesare scrierii
unui program şi un set de utilitare necesare compilării, execuţiei şi documentării unei aplicaţii
2
Java. În Java o bibliotecă este cunoscută sub numele de package. Package-urile Java incluse în
JDK formează API (Application Programming Interface). Mai multe informaţii se găsesc aici.
Paşii ce trebuie urmaţi pentru a putea crea un program Java sunt următorii:
1. scrierea codului;
2. compilarea;
1 package main ;
2
3 public c l a s s MyProgram {
4 public s t a t i c void main ( S t r i n g args [ ] ) {
5 // i n t r u c t i u n i
6 }
7 }
• linia 1: main reprezintă pachetul din care face parte clasa MyProgram. Fizic, un pachet este
un director al proiectului.
3
• linia 3: clasa MyProgram are modificatorul de acces public;
• linia 4: metoda main are modificatorul de acces public, are ca parametru şirul de caractere
args şi nu returnează nimic. De asemenea, cuvântul rezervat static determină ca metoda
main să depindă de clasa MyProgram şi nu de o instanţă a acesteia.
Codul sursă Java constă din unul sau mai multe fişiere text ce au extensia .java. Pentru scrierea
codului se poate folosi orice editor de text. Ca exemplu se foloseşte codul următor:
1 public c l a s s H e l l o W o r l d {
2 public s t a t i c void main ( S t r i n g args [ ] ) {
3 System . o u t . p r i n t l n ( " H e l l o ␣ World ! ! ! " ) ;
4 }
5 }
De reţinut că numele clasei trebuie să coincidă cu numele fişierului a cărui extensie este .java.
Pasul următor este compilarea programului. Acest lucru se realizează dintr-o fereastră de sistem
cu ajutorul comenzii: javac HelloWorld.java
Dacă operaţia de compilare s-a desfăşurat cu succes, în acelaşi director ar trebui să apară
un fişier cu acelaşi nume, dar cu extensia .class. În cazul în care fişierul amintit anterior nu s-a
generat, înseamnă că s-au întâmpinat probleme la compilare.
O posibilă problemă ar fi ca sistemul de operare să nu poată lansa în execuţie utilitarul
javac. Mesajul de eroare este, în acest caz, ” ’javac’ is not recognized as an internal or external
command, operable program or batch file”. Pentru a rezolva această eroare trebuie setată variabila
de sistem path pentru a cuprinde şi directorul în care se află javac (Exemplu: C:\Program Files
\Java \jdk1.6.0_23 \bin).
O altă cauză ar putea fi lipsa pachetului JDK din sistem. Soluţia ar fi instalarea acestuia.
Pachetul poate fi descarcat de la această adresă.
4
C. Lansarea în execuţie a unei aplicaţii Java
După compilare s-a obţinut HelloWorld.class. Pentru a-l lansa în execuţie se foloseşte comanda:
java HelloWorld . În urma acestei comenzi va apărea în consolă mesajul ”Hello World!!!”.
Următorul exemplu este o aplicaţie care spune ”Hello” utilizatorilor ce îşi dau numele ca para-
metru de apel al acesteia. Aplicaţia va prelua toţi aceşti parametri din argumentul metodei main
numit args. Acesta este un tablou de şiruri de caractere ce va conţine toţi parametrii din linie de
comandă ce urmează după numele programului.
1 public c l a s s HelloUsers {
2 public s t a t i c void main ( S t r i n g args [ ] ) {
3 if ( a r g s . l e n g t h == 0 ) { // daca nu s u n t argumente
4 System . o u t . p r i n t l n ( " I n t r o d u c e t i ␣ c e l ␣ p u t i n ␣un␣nume " ) ;
5 }
6 for ( int i =0; i <a r g s . l e n g t h ; i ++){
7 System . o u t . p r i n t l n ( " H e l l o , ␣ "+a r g s [ i ]+ " ! " ) ; // s e afiseaza fiecare element din tabloul args
8 }
9 }
10 }
După ce programul a fost compilat şi a fost obţinut fişierul class, se lansează în execuţie astfel:
java Hello Mihai Radu Ana . În consolă se afişează:
Hello, Mihai!
Hello, Radu!
Hellor, Ana!
III. TEMĂ
5
Laborator 2:
Instrucţiuni Java şi lucru cu şiruri de caractere
18 octombrie 2011
I. NOŢIUNI TEORETICE
A. Instrucţiuni condiţionale
1. Intrucţiunea if else
Forma generală:
if(expresie_condiţională)
secvenţă_if;
else
secvenţă_else;
Dacă expresie_condiţională este evaluată la true, atunci se execută secvenţă_if. În caz con-
trar, se execută secvenţă_else. Este necesar ca expresie_condiţională să fie evaluată la o valoare
booleană. În plus, prezenţa structurii else nu este obligatorie şi pot exista cazuri de folosire a
instrucţiunii if else în cascadă.
2. Intrucţiunea switch
Forma generală:
switch(expresie_condiţie) {
case val1:
secvenţa1;
<break>;
...;
case valN:
secvenţaN;
<break>;
<default:>
secvenţa_default;
Pentru utilizarea acestei instrucţiuni este necesar ca atât tipul de date al lui expresie_condiţie
cât şi cel al valorilor val1, . . . , valN să fie din categoria tipurilor numerice: byte, char, short,
2
int. Astfel că, primul pas constă în evaluarea valorii expresiei expresie_condiţie. Apoi se compară
valoarea evaluată cu prima valoare a lui case, val1. Dacă această valoare este egală cu val1 atunci
se execută secvenţa1 până la întâlnirea lui break. Dacă instrucţiunea break nu este prezentă, atunci
se trece la execuţia celorlalte secvenţe de tipul secvenţaN, fără a mai testa celelalte valori din case.
În cazul în care valoarea din condiţie nu este egală cu nici o valoare din case atunci se execută
secvenţa_default ce urmează lui default:. Cazul default permite executarea secvenţei de după el
indiferent de valoarea expresiei de evaluat. Acesta poate lipsi.
B. Instrucţiuni de ciclare
1. Intrucţiunea for
Forma generală:
for(<secvenţă_iniţializare>;<expresie_condiţie>;<secvenţă_incrementare>)
<secvenţă_repetată>;
Intrucţiunea for face parte din instrucţiunile de ciclare cu test iniţial. De reţinut că
secvenţă_repetată se execută înaintea secvenţă_incrementare şi că variabilele definite în sec-
venţă_iniţializare sunt valabile doar în interiorul for-ului.
Tot ce este între <> poate lipsi, astfel încât putem avea for(;;) pentru a putea realiza un ciclu
infinit.
2. Intrucţiunea while
Forma generală:
while(expresie_condiţie)
secvenţă_repetată;
3
3. Intrucţiunea do while
Forma generală:
do
secvenţă_repetată
while(expresie_condiţie);
C. Instrucţiuni de salt
Intrucţiunea:
1. break este utilizată pentru întreruperea execuţiei instrucţiunilor de ciclare şi a celor switch;
Cele mai cunoscute clase care lucrează cu şiruri de caractere sunt: String, StringBuffer.
1. Clasa String
Cea mai importantă caracteristică a clasei String este că obiectele o dată iniţializate nu se mai
pot modifica, fiecare dintre aceste obiecte indicând spre o zonă diferită de memorie.
O altă proprietate a obiectelor de tip String este că pot fi utilizate impreună cu operatorul ’+’,
pentru concatenarea şirurilor. Prin concatenare se instanţiază un nou obiect de tip String care va
referenţia un şir alcătuit din şirurile alipite cu ajutorul operatorului ’+’.
Această clasă oferă o serie de metode pentru lucru cu şiruri de caractere. Aceste metode au în
vedere compararea şirurilor, căutarea în şiruri, şamd. Se recomandă studierea API-ului.
4
2. Clasa StringBuffer
Un obiect StringBuffer reprezintă ca şi în cazul clasei String un şir de caractere. Diferenţa între
cele două este că primul obiect poate suferi modificări. Acest lucru este posibil datorită metodelor
insert() şi append() care permit inserarea, respectiv adăugarea unor şiruri de caractere. Pentru mai
multe informaţii se recomandă studierea API-ului.
A. Instrucţiuni Java
Codul sursă de mai jos exemplifică modul de utilizare al instrucţiunilor din secţiunile I A, I B,
I C.
1 import j a v a . u t i l . S c a n n e r ;
2
3 public c l a s s TestIntructiuni {
4 public s t a t i c void main ( S t r i n g args [ ] ) {
5 S c a n n e r s = new S c a n n e r ( System . i n ) ; // cu a j u t o r u l acestei instructiuni se citeste t e x t de l a
tastatura
6 System . o u t . p r i n t l n ( " I n t r o d u c e t i ␣un␣numar : ␣ " ) ;
7 int x = s . nextInt ( ) ; // i n x s e va r e t i n e numarul t a s t a t
8 System . o u t . p r i n t l n ( " R e z u l t a t u l ␣ f u n c t i e i ␣ e s t e : ␣ " + t e s t ( x ) ) ; /∗ s e a p e l e a z a metoda t e s t cu p a r a m e t r u x
∗/
9 }
10
11 public s t a t i c int t e s t ( int x ) {
12 i n t suma = 0 ; // s e initializeaza v a r i a b i l a suma cu 0
13 for ( int i = 0; i < 4; i ++) {
14 System . o u t . p r i n t l n ( "Am␣ i n t r a t ␣ i n ␣ n i v e l ␣ 1 " ) ;
15 int j = 0;
16 while ( j++ < x ) { // i n t a i se efectueaza evaluarea expresiei j < x si abia apoi se incrementeaza
variabila j
17 System . o u t . p r i n t l n ( "Am␣ i n t r a t ␣ i n ␣ n i v e l ␣ 2 " ) ;
18 System . o u t . p r i n t l n ( " i=␣ " + i + " ; ␣ j=␣ " + j ) ;
19 switch ( i ) {
20 // i n cazul in care i =0 , 1 s a u 2 s e sare la urmatorul pas si se ignora restul instructiunilor
de dupa c o n t i n u e din ciclul curent ( while )
21 case 0 :
22 continue ;
23 case 1 :
24 continue ;
25 case 2 :
26 continue ;
27 case 3 : // i n cazul in care i =3 s e a c t u a l i z e a z a suma s i apoi se iese fortat din switch
28 suma += i+j ;
29 break ;
30 }
31 }
32 System . o u t . p r i n t l n ( "Am␣ i e s i t ␣ d i n ␣ n i v e l ␣ 2 " ) ;
5
33 }
34 System . o u t . p r i n t l n ( "Am␣ i e s i t ␣ d i n ␣ n i v e l ␣ 1 " ) ;
35 return suma ; // s e iese fortat d i n metoda t e s t
36 }
37
38 }
Exemplul următor evidenţează caracterul imuabil pe care-l au obiectele de tip String. Se citeşte
de la tastatură un şir de caractere şi se verifică dacă acesta coincide cu un alt şir de caractere.
1 import j a v a . u t i l . ∗ ;
2 public c l a s s CheckPassword {
3 public s t a t i c void main ( S t r i n g args [ ] ) {
4 S c a n n e r s = new S c a n n e r ( System . i n ) ;
5 String password = " java " ;
6 String userInput ;
7 System . o u t . p r i n t l n ( " Care ␣ e ␣ p a r o l a ? " ) ;
8 u s e r I n p u t= s . n e x t ( ) ;
9
10 System . o u t . p r i n t l n ( " Ai ␣ t a s t a t : ␣ " ) ;
11 System . o u t . p r i n t l n ( u s e r I n p u t ) ;
12 System . o u t . p r i n t l n ( " Dar ␣ p a r o l a ␣ e s t e : ␣ " ) ;
13 System . o u t . p r i n t l n ( p a s s w o r d ) ;
14
15 // i f ( password . e q u a l s ( u s e r I n p u t ) ) {
16 if ( p a s s w o r d == u s e r I n p u t ) {
17 System . o u t . p r i n t l n ( " Ai ␣ t r e c u t ␣ mai ␣ d e p a r t e ! " ) ;
18 } else {
19 System . o u t . p r i n t l n ( "NU␣ a i ␣ t r e c u t ␣ mai ␣ d e p a r t e ! " ) ;
20 }
21 }
22 }
Deşi variabila userInput ar conţine aceleaşi caractere ca variabila password, folosind operatorul
’==’ se va afişa textul de pe ramura else a instrucţiunii if. Acest lucru se întâmplă din cauza
faptului că se compară adresele de memorie ale variabilelor şi nu conţinutul de la acele zone de
memorie.
Decomentaţi linia 15 şi comentaţi linia 16. Observaţi ce se intâmplă dacă variabilele conţin
acelaşi şir de caractere.
6
1 import j a v a . u t i l . S c a n n e r ;
2 public c l a s s R e p l a c e V o w e l {
3 public s t a t i c void main ( S t r i n g args [ ] ) {
4 S c a n n e r s = new S c a n n e r ( System . i n ) ;
5 System . o u t . p r i n t l n ( " I n t r o d u c e t i ␣ c u v a n t u l : ␣ " ) ;
6 S t r i n g word = s . n e x t L i n e ( ) ;
7 System . o u t . p r i n t l n ( " Cuvantul ␣ r e z u l t a t ␣ e s t e : ␣ "+r e p l a c e V o w e l ( word . toLowerCase ( ) ) ) ;
8 }
9
10 public s t a t i c boolean checkVowel ( char c ) {
11 c = C h a r a c t e r . toLowerCase ( c ) ;
12 return ( " a e i o u " . i n d e x O f ( c ) >= 0 ) ; /∗ ∗ s e returneaza t r u e daca metoda i n d e x O f aplicata sirului de
13 caractere " a e i o u " impreuna cu p a r a m e t r u c r e t u r n e a z a o v a l o a r e p o z i t i v a ∗/
14 }
15
16 public s t a t i c String r e p l a c e V o w e l ( S t r i n g word ) {
17 StringBuffer s b = new S t r i n g B u f f e r ( word ) ; /∗ ∗ v a r i a b i l a sb este intializata cu v a l o a r e a
18 variabilei word ∗/
19 for ( int i =0; i <s b . l e n g t h ( ) ; i ++){ /∗ ∗ s b s e parcurge c a r a c t e r cu c a r a c t e r ∗/
20 if ( checkVowel ( s b . c h a r A t ( i ) ) ) { /∗ ∗ f i e c a r e caracter al lui sb este verificat daca este v o c a l a ∗/
21 sb . setCharAt ( i , ( char ) ( s b . c h a r A t ( i ) +1) ) ; /∗ ∗ s e pune pe pozitia i i n sb urmatorul caracter
22 din a l f a b e t ∗/
23 }
24 }
25 return s b . t o S t r i n g ( ) ;
26 }
27 }
III. TEMĂ
7
Laborator 3:
Introducere în Programarea Orientată pe Obiecte
23 octombrie 2011
I. NOŢIUNI TEORETICE
A. Clase şi obiecte
Unul dintre conceptele care defineşte programarea orientată pe obiecte este obiectul. Obiectul
este caracterizat prin stare, modelată de atributele unei clase, şi prin comportament, modelat de
metodele unei clase.
Un alt concept este clasa. Clasa este o colecţie de obiecte care partajează aceeaşi lista de
atribute informaţionale (de stare) şi comportamentale. Aşadar, aceasta reprezintă atât structura
unui obiect, cât şi funcţionalitatea acestuia. Mai mult, în acest context se spune că obiectul este o
instanţă a unei clase.
Forma generală a unei clase:
[lista_Modificatori] class NumeClasa[extends NumeClasaDeBaza][implements lista_Interfata]
corp clasa
Definiţia unei clase trebuie să conţină obligatoriu cuvântul cheie class, numele clasei şi corpul
clasei prins între acolade. Toţi ceilalţi termeni pot lipsi. Vom discuta despre aceşti termeni la
momentul potrivit.
B. Supraîncărcarea metodelor
corp metoda
O metodă se defineşte prin semnătură şi prin corp. Semnătura constă în tipul returnat, numele
metodei şi lista de parametri, pe când corpul metodei este reprezentat de instrucţiuni.
În Java, în aceeaşi clasă, se pot defini metode cu acelaşi nume, dar cu semnături diferite.
Diferenţa poate consta în numărul de parametri, în tipul de date al acestora sau în ambele. Acest
2
proces se numeşte supraîncărcare. Este important de reţinut că Java nu ia în considerare tipul
valorii returnate pentru a face diferenţierea metodelor supraîncărcate.
Motivul pentru care se folosesc acest gen de metode este că se elimină nevoia de a defini metode
complet diferite care să facă în principiu acelaşi lucru. De asemenea, supraîncărcarea face posibilă
comportarea diferită a metodelor în funcţie de argumentele primite.
C. Constructori
Într-o clasă, pe lângă atribute şi metode, se pot defini şi constructori. Aceştia sunt un tip de
metodă specială cu următoarele caracteristici:
• numele lor trebuie să fie identic cu cel al clasei din care fac parte;
• nu au tip de returnat.
[lista_Modificatori] NumeClasa([lista_parametrii])
corp constructor
Constructorii sunt utilizaţi pentru instanţierea unui obiect care face parte dintr-o anumită clasă
şi sunt apelaţi în funcţie de variabilele pe care le primesc ca parametru. În cazul în care nu se
declară niciun constructor(doar în acest caz) compilatorul creează un constructor implicit, având
numele clasei, fără niciun parametru formal şi având corpul constructorului fără instrucţiuni.
Metodele constructor pot fi şi ele supraîncărcate, la fel ca metodele obişnuite, pentru a crea un
obiect care are proprietăţi specifice în funcţie de argumentele transmise prin operatorul new.
D. Moştenire
Unul dintre principiile programării orientate pe obiecte este moştenirea. Acest principiu se
bazează pe extinderea comportamentului unei clase existente prin definirea unei clase noi care
moşteneşte conţinutul primei clase la care se adaugă noi proprietăţi şi funcţionalităţi.
Clasa existentă, care va fi moştenită, se numeşte clasa de bază, clasă părinte sau superclasă.
3
Clasa care realizează extinderea se numeşte subclasă, clasă derivată, clasă descendentă sau clasă
copil. Cuvântul predefinit care se utilizează pentru moştenire este extends.
[lista_Modificatori] class NumeSubclasa [extends NumeClasaDeBaza]
corp subclasa
În ce priveşte tipul de moştenire, în Java este permisă doar cea simplă. Adică, o subclasă poate
extinde o singură superclasă. În aceeaşi ordine de idei, o superclasă poate fi moştenită de mai
multe subclase diferite. Moştenirea multiplă nu este permisă în Java, dar este simulată cu ajutorul
interfeţelor. Acest aspect îl vom trata ulterior.
Prin operaţia de derivare, constructorii clasei de bază nu se moştenesc, în schimb fiecare
constructor al clasei derivate apelează un constructor al clasei de bază. Acest apel se poate face
implicit(adăugat de compilator) sau explicit. Apelul explicit se face prin intermediul cuvântului
cheie super. În plus, constructorii se apelează în ordinea derivării, de la superclasă la sublcasă.
public class NumeSubclasa extends NumeClasaDeBaza {
NumeSubclasa(){
super();
Codul sursă următor exemplifică conceptul de clasă şi obiect, împreună cu ideea de supraîncăr-
care atât a constructorilor unei clase, cât şi a metodelor unei clase. Clasa Point are ca atribute
coordonatele in plan ale unui punct şi calculează distanţa între două puncte. Metoda care descrie
funcţionalitatea clasei Point (computeDistance()) este supraîncărcată. Acest lucru s-a realizat prin
schimbarea numărului de parametri ai acesteia şi tipul lor.(observaţi linia de cod 29)
4
1 public c l a s s Point {
2 public double x , y ;
3
4 public P o i n t ( ) { // c o n s t r u c t o r fara parametri
5 // this e s t e un c u v a n t cheie ce reprezinta obiectul curent al clasei , i n t r u c a t nu s e s t i e cum s e
numeste obiectul
6 this . x = 0;
7 this . y = 0;
8 }
9
10 // c o n s t r u c t o r cu 2 p a r a m e t r i ; constructorul a fost supraincarcat
11 public P o i n t ( double x , double y ) {
12 this . x = x ;
13 this . y = y ;
14 }
15
16 // c o n s t r u c t o r cu un p a r a m e t r u ; constructorul a fost supraincarcat
17 public P o i n t ( double x ) {
18 this . x = x ;
19 this . y = 0;
20 }
21
22 // metoda c a l c u l e a z a distanta i n t r e 2 puncte aflate in plan
23 public s t a t i c double c o m p u t e D i s t a n c e ( P o i n t p1 , P o i n t p2 ) {
24 // s e folosesc metode a l e c l a s e i Math d i n pachetul java . lang
25 return Math . s q r t ( Math . pow ( p1 . x − p2 . x , 2 ) + Math . pow ( p1 . y − p2 . y , 2) ) ;
26 }
27
28 // metoda e s t e supraincarcata
29 public s t a t i c double c o m p u t e D i s t a n c e ( double x1 , double y1 , double x2 , double y2 ) {
30 return Math . s q r t ( Math . pow ( x1 − x2 , 2 ) + Math . pow ( y1 − y2 , 2) ) ;
31 }
32
33 public s t a t i c double c o m p u t e D i s t a n c e ( P o i n t p1 ) { /∗ ∗ metoda e s t e s u p r a i n c a r c a t a ∗/
34 return Math . s q r t ( Math . pow ( p1 . x , 2 ) + Math . pow ( p1 . y , 2) ) ;
35 }
36
37 public S t r i n g toString (){
38 return " x=␣ "+x+" ; ␣ y=␣ "+y ;
39 }
40 }
Următoarea clasă creează obiecte de tipul Point. Aceste obiecte sunt instanţiate în moduri
diferite. De asemenea, se apelează metoda statică computeDistance() cu parametri diferiţi.
1 public c l a s s TestPoint {
2 public s t a t i c void main ( S t r i n g [ ] args ) {
3 P o i n t p1 = new P o i n t ( ) ;
4 System . o u t . p r i n t l n ( " I n s t a t i e r e ␣ o b i e c t ␣ p r i n ␣ c o n s t r u c t o r ␣ f a r a ␣ p a r a m e t r i : ␣P1 : ␣ "+p1 . t o S t r i n g ( ) ) ;
5 P o i n t p2 = new P o i n t ( 2 , 2) ;
6 System . o u t . p r i n t l n ( " I n s t a t i e r e ␣ o b i e c t ␣ p r i n ␣ c o n s t r u c t o r ␣ cu ␣ 2 ␣ p a r a m e t r i : ␣P2 : ␣ "+p2 . t o S t r i n g ( ) ) ;
7 P o i n t p3 = new P o i n t ( 3 ) ;
8 System . o u t . p r i n t l n ( " I n s t a t i e r e ␣ o b i e c t ␣ p r i n ␣ c o n s t r u c t o r ␣ cu ␣ 1 ␣ p a r a m e t r u : ␣P3 : ␣ "+p3 . t o S t r i n g ( ) ) ;
9
10 System . o u t . p r i n t l n ( " C a l c u l e a z a ␣ d i s t a n t a ␣ i n t r e ␣P2␣ s i ␣P3 : ␣ "+P o i n t . c o m p u t e D i s t a n c e ( p2 , p3 ) ) ;
11 System . o u t . p r i n t l n ( " C a l c u l e a z a ␣ d i s t a n t a ␣ i n t r e ␣P2␣ s i ␣P3 : ␣ "+P o i n t . c o m p u t e D i s t a n c e ( p2 . x , p2 . y , p3 . x , p3
. y) ) ;
5
12 System . o u t . p r i n t l n ( " C a l c u l e a z a ␣ d i s t a n t a ␣ i n t r e ␣P ( 0 , 0 ) ␣ s i ␣P2 : ␣ "+P o i n t . c o m p u t e D i s t a n c e ( p2 ) ) ;
13 }
14 }
B. Moştenire
Clasa Para este subclasă a clasei Fruct. Para este un fruct, aşadar se respectă principiul moşteni-
rii. În clasa Para se adaugă noi atribute informaţionale (greutate, culoare) şi un nou comportament
reprezentat de metodele getGreutate(), getCuloare().
1 public c l a s s Para extends F r u c t {
2 // a t r i b u t e l e sunt private , deci domeniul lor de vizibilitate se afla doar i n cadrul clasei Para
3 p r i v a t e double g r e u t a t e ;
4 private S t r i n g culoare ;
5
6 public Para ( S t r i n g t i p F r u c t , double g r e u t a t e , S t r i n g forma ) {
7 super ( t i p F r u c t ) ; // a p e l a r e explicita a constructorului clasei de baza cu p a r a m e t r u l tipFruct
8 System . o u t . p r i n t l n ( " C o n s t r u c t o r ␣ Para . . . " ) ;
9 this . greutate = greutate ;
10 t h i s . c u l o a r e = forma ;
11 }
12
13 // m e t o d e l e s u n t publice si deci pot fi vazute si in afara clasei , spre d e o s e b i r e de a t r i b u t e
14 public double g e t G r e u t a t e ( ) {
15 return g r e u t a t e ;
16 }
17
18 public S t r i n g getCuloare () {
19 return c u l o a r e ;
20 }
21 }
Clasa TestFruct instanţiază un obiect de tip Para, implicit de tip Fruct. De aceea avem acces
şi la metoda getTipFruct() care nu aparţine propriu-zis clasei Para.
6
1 public c l a s s TestFruct {
2 public s t a t i c void main ( S t r i n g [ ] args ){
3 Para obPara = new Para ( " p a r a " , 3 , " g a l b e n " ) ; // r e f e r i n t a de tipul para
4 System . o u t . p r i n t l n ( " Tip ␣ F r u c t : ␣ "+obPara . g e t T i p F r u c t ( ) ) ; // a p e l a r e metoda d i n c l a s a de baza
5 System . o u t . p r i n t l n ( " g r e u t a t e : ␣ "+obPara . g e t G r e u t a t e ( ) ) ; // a p e l a r e metoda d i n sublclasa
6 System . o u t . p r i n t l n ( " c u l o a r e : ␣ "+obPara . g e t C u l o a r e ( ) ) ;
7 }
8 }
III. TEMĂ
7
Laborator 4:
Continuare Programare Orientată pe Obiecte
29 octombrie 2011
I. NOŢIUNI TEORETICE
A. Suprascrierea metodelor
O clasă derivată poate declara o metodă cu aceeaşi semnătură cu a unei metode din clasa
de bază. Metoda din clasa derivată substituie astfel metoda din clasa de bază. Această tehnică
se numeşte suprascriere. Cu alte cuvinte, la apelul metodei suprascrise din clasa derivată se va
executa metoda declarată în clasa derivată. Dacă se doreşte apelul metodei ce aparţine clasei de
bază, atunci în metoda din clasa descendentă se foloseşte cuvântul cheie super urmat de operatorul
”.” şi numele metodei suprascrise.
Sunt cazuri în care suprascrierea unei metode nu este dorită. Acest lucru se poate realiza prin
adăugarea cuvântului cheie final. Astfel că, o metodă declarată final în superclasă nu poate fi
suprascrisă în subclasă.
Diferenţa între o metodă suprascrisă şi una supraîncărcată este că în cazul celei suprascrise
semnătura este identică(atât numărul parametrilor cât şi tipul acestora).
B. Clasa Object
În Java, toate clasele formează o anumită structură arborescentă, care are ca rădăcină clasa
Object. Implicit, aceasta este superclasa tuturor claselor şi nu are o clasă părinte.
Metodele principale ale clasei Object sunt:
• clone
Semnătura aceste metode este: protected Object clone() şi returnează o clonă a obiectului
căruia i se aplică, deci un obiect cu aceeaşi stare şi acelaşi comportament. Cu toate acestea,
obiectul rezultat nu este tocmai identic deoarece adresa de memorie către care face referinţă
este diferită de cea a obiectului original.
După ce se execută instrucţiunea b=a.clone(), în care a şi b sunt referinţe la obiecte, expresia
a==b va avea valoarea false, deoarece valorile variabilelor referinţă a si b sunt diferite, în
timp ce expresia a.equals(b) va întoarce valoarea true, deoarece cele două obiecte comparate
au conţinuturi identice.
2
• equals
Semnătura metodei este public boolean equals(Object obj) şi returnează valoarea true dacă
şi numai dacă obiectele comparate sunt într-adevăr identice; adică obiectele au acelaşi conţi-
nut şi aceeaşi adresă de memorie.
• hashCode
Semnătura metodei este public int hashCode() şi returnează un întreg care este folosit de
Java pentru a diferenţia două obiecte. Se recomandă ca atunci când se doreşte suprascrierea
metodei equals(), să se suprascrie şi metoda hashcode(). Este important ca două obiecte egale
conform metodei equals() să aibă aceleaşi hashcode-uri.
• toString
Semnătura metodei este public String toString() şi returnează un şir de caractere de forma
java.lang.Object@hashCode în care hashCode este exprimat în hexazecimal. Acest şir de
caractere reprezintă obiectul căruia i se aplică. De aceea, se recomandă suprascrierea metodei
toString() în toate subclasele clasei Object pentru ca mesajul să poată fi înţeles cu mai multă
uşurinţă.
O clasă abstractă este utilizată pentru modelarea unor concepte abstracte şi poate reprezenta
doar clasa de bază în procesul de moştenire. Un lucru important de reţinut atunci când se lucrează
cu clase abstracte este acela că o clasă abstractă nu poate fi instanţiată.
Alte caracterisitici ale unor clase de acest fel sunt următoarele:
3
• pot avea metode abstracte. O metodă abstractă este o metodă ce nu are corp (instrucţiuni) şi
care într-o clasă descendentă a clasei abstracte trebuie implementată. Dacă metoda declarată
abstractă în clasa de bază nu este implementată în subclasă, atunci trebuie declarată din nou
abstractă. Astfel şi subclasa devine una abstractă.
• pot avea şi metode clasice (corpul acestora este implementat în clasa abstractă);
• deşi clasele abstracte nu pot fi instanţiate, se pot declara obiecte de tipul claselor abstracte
şi să fie instanţiate de clasele derivate.
D. Interfeţe
O interfaţă este un fel de clasă abstractă cu diferenţa că într-o interfaţă nici o metodă declarată
nu are voie să aibă corp. Interfeţele sunt utilizate pentru a separa implementarea de definiţia
metodelor.
Spre deosebire de o clasă abstractă, o interfaţă nu poate defini un constructor, iar atributele
existente sunt implicit declarate ca fiind statice şi finale, acestea devenind constante. Iar spre
deosebire de o clasă obişnuită, o interfaţă poate moşteni mai multe interfeţe (intervine ideea de
moştenire multiplă).
Forma generală a unei clase care moşteneşte o interfaţă sau o listă de interfeţe este:
[modificator_acces] class NumeClasa [extends NumeSuperclasa] implements lista_interfete{
De aici se poate trage concluzia că o clasă poate implementa una sau mai multe interfeţe.
De asemenea, se păstrează regula de la clasele abstracte cum că o clasă care moşteneşte o
interfaţă trebuie să îi implementeze toate metodele. Dacă acest lucru un se întâmplă, atunci în
clasă metodele devin abstracte.
4
II. PREZENTAREA LUCRĂRII DE LABORATOR
A. Suprascrierea metodelor
Se dă clasa Superclasa care conţine o singură metodă. Clasa Subclasa moşteneşte Superclasa şi
suprascrie metoda afiseazaDescriere. Observaţi semnăturile metodelor; sunt identice.
1 public c l a s s Superclasa {
2 public void a f i s e a z a D e s c r i e r e ( ) {
3 System . o u t . p r i n t l n ( " a p e l a r e ␣ a f i s e a z a D e s c r i e r e ␣ d i n ␣ s u p e r c l a s a . . . " ) ;
4 }
5 }
1 public c l a s s S u b c l a s a extends S u p e r c l a s a {
2 public void a f i s e a z a D e s c r i e r e ( ) {
3 // a p e l a r e e x p l i c i t a a metodei din c l a s a de baza
4 // s u p e r . a f i s e a z a D e s c r i e r e ( ) ;
5 System . o u t . p r i n t l n ( " a p e l a r e ␣ a f i s e a z a D e s c r i e r e ␣ d i n ␣ s u b c l a s a . . . " ) ;
6 }
7 }
În clasa descendentă, în metoda suprascrisă se poate apela metoda originală (din clasa de bază)
folosind cuvântul cheie super. Decomentaţi linia de cod numărul 4 din Subclasa şi observaţi ce se
afişează la următoarea rulare.
1 public c l a s s TestSuprascriere {
2 public s t a t i c void main ( S t r i n g [ ] args ){
3 Superclasa s u p e r C l a s a = new S u p e r c l a s a ( ) ;
4 S u b c l a s a s u b C l a s a = new S u b c l a s a ( ) ;
5 superClasa . a f i s e a z a D e s c r i e r e () ; System . o u t . p r i n t l n ( ) ;
6 subClasa . a f i s e a z a D e s c r i e r e ( ) ; System . o u t . p r i n t l n ( ) ;
7 superClasa = subClasa ;
8 superClasa . a f i s e a z a D e s c r i e r e () ;
9 }
10 }
B. Clasa Object
Clasa Point are două atribute de tipul double şi suprascrie metodele clone, equals, hashCode şi
toString ale clasei Object. Observaţi în linia de cod 1 cuvintele implements Cloneable. Orice clasă
care extinde clasa Object şi care îi suprascrie metodele trebuie să implementeze interfaţa Cloneable.
Despre interfeţe se discută pe larg în secţiunile I D şi II D.
Pentru a respecta proprietăţile metodei hasCode, de a returna un număr întreg care să dife-
renţieze două obiecte diferite, se implementează un algoritm care produce un astfel de număr. În
5
exemplul prezentat (linia de cod 30), algoritmul constă în înmulţirea cu un număr prim şi însuma-
rea membrilor obiectului. Cu cât algoritmul matematic este mai complex cu atât regulile hashCode
sunt respectate în mai multe cazuri.
1 public c l a s s P o i n t implements C l o n e a b l e {
2 p r i v a t e double x , y ;
3
4 public void s e t X ( double x ) {
5 this . x = x ;
6 }
7
8 public void s e t Y ( double y ) {
9 this . y = y ;
10 }
11
12 protected P o i n t clone () {
13 P o i n t pObj = new P o i n t ( ) ;
14 pObj . x = t h i s . x ;
15 pObj . y = t h i s . y ;
16 return pObj ; // o b i e c t u l pObj a r e membrii identici cu cei ai obiectului curent
17 }
18
19 public boolean e q u a l s ( O b j e c t o b j ) {
20 if ( o b j == t h i s )
21 return true ; // r e f e r i n t e egale
22 if ( ! ( obj instanceof Point ) )
23 return f a l s e ; // o b j nu e s t e de tipul Point
24 Point p = ( Point ) obj ; // s e f a c e un d o w n c a s t i n g , adica obj este convertit la tipul Point
25 if ( t h i s . x != p . x || t h i s . y != p . y )
26 return f a l s e ; // c o o r d o n a t a x s a u y e s t e diferita
27 return true ;
28 }
29
30 public i n t hashCode ( ) {
31 double r e s u l t = 1 7 ;
32 r e s u l t = 37∗ r e s u l t + t h i s . x ;
33 r e s u l t = 37∗ r e s u l t + t h i s . y ;
34 return ( i n t ) r e s u l t ; /∗ s e f a c e un c a s t la tipul int , intrucat variabila result e s t e una
35 de t i p double , iar f u n t i a hashCode r e t u r n e a z a o v a l o a r e de t i p i n t ∗/
36 }
37
38 public S t r i n g toString (){
39 return " x=␣ "+x+" ; ␣ y=␣ "+y ;
40 }
41 }
Clasa TestObject creează un obiect de tipul Point, îi setează proprietăţile şi îi apelează metodele.
1 public c l a s s TestObject {
2 public s t a t i c void main ( S t r i n g [ ] args ){
3 P o i n t p1 = new P o i n t ( ) ;
4 p1 . s e t X ( 3 ) ;
5 p1 . s e t Y ( 4 ) ;
6 P o i n t p1Clone = p1 . c l o n e ( ) ;
7 System . o u t . p r i n t l n ( " P1 : ␣ "+p1 . t o S t r i n g ( ) ) ;
8 System . o u t . p r i n t l n ( " Clona ␣ l u i ␣P1 : ␣ "+p1Clone . t o S t r i n g ( ) ) ;
9 if ( p1 . e q u a l s ( p1Clone ) )
6
10 System . o u t . p r i n t l n ( " O b i e c t e l e ␣ s u n t ␣ i d e n t i c e ! " ) ;
11 e l s e System . o u t . p r i n t l n ( " O b i e c t e l e ␣nu␣ s u n t ␣ i d e n t i c e ! " ) ;
12 System . o u t . p r i n t l n ( " Hashcode−u l ␣ l u i ␣P1␣ e s t e : ␣ "+p1 . hashCode ( ) ) ;
13 System . o u t . p r i n t l n ( " Hashcode−u l ␣ c l o n e i ␣ l u i ␣P1␣ e s t e : ␣ "+p1Clone . hashCode ( ) ) ;
14 }
15 }
Pentru a exemplifica utilizarea claselor şi metodelor abstracte vom folosi clasa Produs. Să pre-
supunem că vrem să derivăm un număr mai mare de clase din Produs: Carte, RamaFoto, etc. Se
observă că acestea au în comun preţul, o descriere şi eventual o reducere a preţului în funcţie de
anumite proprietăţi ale fiecărui produs în parte.
În acest caz, obiecte de genul Carte sau RamaFoto trebuie să facă parte din clase care moştenesc
o superclasă comună, Produs. Mai mult, ar trebui ca Produs să implementeze metodele afiseaza-
Descriere şi calculeazaReducere. Pentru că implementarea metodelor depinde de tipul obiectului şi
proprietăţilor acestuia, metodele se declară abstracte în clasa Produs.
1 public a b s t r a c t c l a s s Produs {
2 p r i v a t e double p r e t U n i t a r ;
3
4 Produs ( double p r e t U n i t a r ) {
5 this . pretUnitar = pretUnitar ;
6 }
7
8 public double g e t P r e t U n i t a r ( ) {
9 return p r e t U n i t a r ;
10 }
11
12 // m e t o d e l e a b s t r a c t e nu au c o r p
13 // e l e vor fi implementate in clasele copil ale clasei Produs
14 public a b s t r a c t void a f i s e a z a D e s c r i e r e ( ) ;
15 public a b s t r a c t double c a l c u l e a z a R e d u c e r e ( i n t p r o c e n t ) ;
16 }
Clasa Carte extinde clasa Produs şi implementează metodele abstracte ale acesteia în modul ei
propriu. La fel se întâmplă şi pentru clasa RamaFoto.
1 public c l a s s C a r t e extends Produs {
2 private S t r i n g titlu , autor ;
3
4 public C a r t e ( double p r e t U n i t a r , String titlu , String autor ) {
5 super ( p r e t U n i t a r ) ;
6 this . t i t l u = t i t l u ;
7 this . autor = autor ;
8 }
9
7
10 // metoda a f i s e a z a D e s c r i e r e este implementata i n sublclasa
11 public void a f i s e a z a D e s c r i e r e ( ) {
12 System . o u t . p r i n t l n ( " T i t l u ␣ c a r t i i ␣ e s t e : ␣ "+t h i s . t i t l u +" , ␣ i a r ␣ a u t o r u l ␣ e s t e : ␣ "+t h i s . a u t o r ) ;
13 }
14
15 // metoda c a l c u l e a z a R e d u c e r e este implementata i n sublclasa
16 public double c a l c u l e a z a R e d u c e r e ( i n t p r o c e n t ) {
17 System . o u t . p r i n t l n ( " C a l c u l e a z a ␣ r e d u c e r e ␣ d i n ␣ C a r t e . . . " ) ;
18 return 0.0;
19 }
20 }
Clasa TestProdus creează un vector de obiecte de tipul Produs şi calculează preţul total al
tuturor produselor declarate. Cum un obiect dintr-o clasă abstractă nu poate fi instanţiat cu tipul
clasei abstracte, se instanţiază cu tipul subclaselor, în acest caz Carte şi RamaFoto.
1 public c l a s s T e s t P r o d u s {
2 public s t a t i c void main ( S t r i n g [ ] args ) {
3 Produs [ ] l i s t a P r o d u s e = new Produs [ 4 ] ;
4 for ( int i =0; i <l i s t a P r o d u s e . l e n g t h ; i ++){
5 if ( i % 2 == 0 ) { // daca i este par a t u n c i se c r e e a z a un o b i e c t de tipul Carte
6 l i s t a P r o d u s e [ i ] = new C a r t e ( 1 2 . 3 , " F u n d a t i a ␣ "+i , " I s a a c ␣ Asimov " ) ;
7 } e l s e { // daca i e s t e impar a t u n c i se c r e e a z a un o b i e c t de t i p u l RamaFoto
8 l i s t a P r o d u s e [ i ] = new RamaFoto ( 5 . 5 , 20− i , 15− i ) ;
9 }
10 }
11 double p r e t T o t a l = 0 . 0 ;
12 for ( int i =0; i <l i s t a P r o d u s e . l e n g t h ; i ++){
13 // putem a v e a a c c e s l a metoda g e t P r e t U n i t a r ( ) pentru ca a c e a s t a se afla in clasa parinte .
14 double p r e t P r o d u s O r i g i n a l = l i s t a P r o d u s e [ i ] . g e t P r e t U n i t a r ( ) ;
15 double r e d u c e r e = l i s t a P r o d u s e [ i ] . c a l c u l e a z a R e d u c e r e ( i ) ;
16 p r e t T o t a l += p r e t P r o d u s O r i g i n a l − r e d u c e r e ;
17 listaProduse [ i ] . afiseazaDescriere () ;
18 }
19 System . o u t . p r i n t l n ( " P r e t u l ␣ t o t a l ␣ a l ␣ p r o d u s e l o r ␣ e s t e : ␣ "+p r e t T o t a l ) ;
8
20 }
21 }
D. Interfeţe
Clasa Student implementează interfaţa IStudent, deci implementează atât metodele acesteia, cât
şi pe cele ale interfeţei pe care IStudent o moşteneşte.
1 public c l a s s S t u d e n t implements I S t u d e n t {
2 S t r i n g nume ;
3 double medieNote ;
4
5 public S t u d e n t ( S t r i n g nume , double medieNote ) {
6 t h i s . nume = nume ;
7 t h i s . medieNote = medieNote ;
8 }
9
10 // s e i m p l e m e n t e a z a metoda d i n I S t u d e n t
11 public boolean v e r i f i c a S t u d e n t I n t e g r a l i s t ( ) {
12 if ( t h i s . medieNote >= 5 ) {
13 return true ;
14 }
15 return f a l s e ;
16 }
17
18 // s e i m p l e m e n t e a z a metoda m o s t e n i t a de I S t u d e n t d i n I P e r s o a n a
19 public S t r i n g returneazaNumePersoana ( ) {
20 return t h i s . nume ;
21 }
22 }
Clasa TestStudent creează un obiect de tipul Student şi verifică dacă studentul este integralist
sau nu, afişând un mesaj corespunzător.
1 public c l a s s TestStudent {
2 public s t a t i c void main ( S t r i n g [ ] args ) {
3 S t u d e n t s t u d e n t = new S t u d e n t ( " I o n e s c u ␣Radu " , 6.3) ;
4 if ( student . v e r i f i c a S t u d e n t I n t e g r a l i s t () )
5 System . o u t . p r i n t l n ( s t u d e n t . r e t u r n e a z a N u m e P e r s o a n a ( )+" ␣ e s t e ␣ i n t e g r a l i s t " ) ;
6 else
9
7 System . o u t . p r i n t l n ( s t u d e n t . r e t u r n e a z a N u m e P e r s o a n a ( )+" ␣nu␣ e s t e ␣ i n t e g r a l i s t " ) ;
8 }
9 }
III. TEMĂ
1. Folosind conceptul de clase şi metode abstracte creaţi o aplicaţie care calculează pentru un
cub şi pentru o sfera:
• aria totala;
• volumul;
• centrul de greutate.
• metoda care calculează distanţa dintre 2 puncte aflate în spaţiu. Aceasta este necesară
pentru aflarea lungimii unei laturi.
10
Laborator Nr. 5:
Structuri de date 1
A. Array
Un şir de date sau un array este o structură ce conţine valori multiple de acelaşi tip de data. Lungimea
unui şir de date se stabileşte la crearea array-ului şi va fi fixa pe ı̂ntreaga existenţă a acestuia. De regulă,
primul element se află pe poziţia 0, iar ultimul pe poziţia n − 1, unde n reprezintă numărul de elemente din
şir.
int [] s;
s = new int[3];
sau:
Declararea unui array de un tip de date referinţă se face ı̂n acelaşi mod ca şi pentru şirurile de tipul de
date primitive. Doar că un astfel de şir va avea ca elemente obiectele unei clase. Astfel că, dacă se dă o clasă
cu numele Country, un şir de elemente din această clasă se declară astfel:
1 c l a s s Country
2 {
3 S t r i n g name ;
4 long p o p u l a t i o n ;
5 }
6
7 p u b l i c c l a s s CountryDemo {
8 p u b l i c s t a t i c void main ( S t r i n g [ ] args )
9 {
10
2
11 Country [ ] s i r = new Country [ 2 ] ;
12 s i r [ 0 ] . name = ” I t a l i a ” ;
13 s i r [ 0 ] . population = 600000000000 l ;
14
15 s i r [ 1 ] . name = ” F r a n t a ” ;
16 s i r [ 1 ] . population = 650000000000 l ;
17 }
18 }
Deoarece un şir de date poate conţine referinţe către alte obiecte, este posibil ca un şir să conţină referinţe
şi catre alte şiruri. În acest caz, se spune că se folosesc şiruri multidimensionale. Cele mai comune şiruri
multimensionale sunt matricile. Exemplu de sir multidimensional:
int matrix[][] = new int[3][2];
matrix[0][1] = 12;
În acest caz se dă un şir bidimensional, astfel: 3 şiruri ı̂n care sunt reţinute şiruri de câte două elemente
de tip int. Accesarea elementelor unui astfel de şir se face prin precizarea tuturor indicilor (ı̂n cazul acesta
sunt 2 indici).
Nu este obligatoriu ca toate subşirurile să aibă aceeaşi dimensiune. În exemplul următor este prezentat
un şir multidimensional ı̂n care subşirurile au dimensiuni diferite:
1 float sir [ ] [ ] = new f l o a t [ 4 ] [ ] ;
2
3 sir [0] = new float [5];
4 sir [1] = new float []{2.3 f ,5 ,6.7 f ,11};
5 sir [2] = new float []{1 f , 4 . 2 f ,7 f , 4 . 1 f ,10 f ,9 f };
6 sir [3] = new float [20];
B. Clasa Vector
Clasa Vector face parte din pachetul java.util şi reprezintă o clasă specială pentru lucrul cu şirurile de
elemente. Cele mai uzuale metode folosite pentru declararea şi crearea unui astfel de şir sunt:
Vector v = new Vector();
//sau
Vector v = new Vector(5);//se creeaza un vector de 5 elemente
3
1. Metode şi operaţii specifice clasei V ector
Deoarece manipularea elementelor unui şir este o operaţie ce necesită multă muncă, clasa V ector are
definite o serie de metode şi operaţii ce pot fi de folos:
C. Clasa Stack
Stiva este o structură de date de tipul LIF O (Last In, First Out).
Clasa Stack este considerată a fi ,,copilul” clasei V ector. ı̂nsă are definite o serie de operaţii specifice
stivelor.
• Adăugarea elementelor.
Aceasta operatiune se face prin metoda push():
4
public Object push(Object element)
• Ştergerea unui element Aceasta operatiune se va face prin apelul functiei pop():
public Object pop()
• Verificare dacă stiva este goală
public boolean empty()
• Preluarea elementului din vârful stivei
public Object peek()
• Căutarea unui element ı̂n stivă
public int search(Object element)
Exemplu de utilizare a clasei Stack:
1 import j a v a . u t i l . S t a c k ;
2 public c l a s s S t i v a
3 {
4 p u b l i c s t a t i c void main ( S t r i n g a r g s [ ] )
5 {
6 S t a c k s = new S t a c k ( ) ;
7 s . push ( ” P r i m u l e l e m e n t ” ) ;
8 s . push ( ” Al d o i l e a e l e m e n t ” ) ;
9 s . push ( ” Al t r e i l e a e l e m e n t ” ) ;
10 System . o u t . p r i n t l n ( ” Next : ” + s . p e e k ( ) ) ;
11
12 s . push ( ” Al patrulea element ” ) ;
13 System . o u t . p r i n t l n ( s . pop ( ) ) ;
14 s . push ( ” Al c i n c i l e a element ” ) ;
15 s . push ( ” Al s a s e l e a element ” ) ;
16 System . o u t . println ( s ) ;
17
18 i n t c o u n t = s . s e a r c h ( ” Al d o i l e a e l e m e n t ” ) ;
19 w h i l e ( c o u n t != −1 && c o u n t > 1 )
20 {
21 s . pop ( ) ;
22 c o u n t −−;
23 }
24
25 System . o u t . p r i n t l n ( s . pop ( ) ) ;
26
27 System . o u t . p r i n t l n ( s . empty ( ) ) ;
28 System . o u t . p r i n t l n ( s ) ;
29 }
30 }
1. Se consideră un şir de elemente ce conţine n numere reale. Se spune că două elemente ale sale formează
o ,,pereche ı̂n dezordine” dacă sunt ı̂ndeplinite simultan condiţiile:
• i<j
• a[i] > a[j], unde1 ≤ i < n şi 1 < j ≤ n
Să se creeze un program care afişează perechile ı̂n dezordine din şir şi numărul lor. Exemplu: Pentru
n=4 şi şirul (1, 13,2,4), se va afişa: 13 2 13 4 2
2. Se consideră două tablouri bidimensionale de dimensiuni identice (nxm). Să se afişeze transpusa
matricei sumă. Transpusa unei matrice se obţine prin schimbarea liniilor cu coloanele.
3. Determinaţi suma maximă care se poate forma cu m numere distincte dintr-un vector ce conţine n
valori ı̂ntregi. Dacă şirul conţine mai puţin de m valori distincte se va afişa mesajul Imposibil. Pentru
rezolvarea problemei se va folosi clasa V ector.
4. Folosind o stivă, realizaţi şi afişaţi programul dumneavoastră dintr-o zi, pe ore. Eliminaţi acţiunile pe
care le efectuaţi până la ora 14 şi afişaţi ceea ce urmează să faceţi la ora 15.
5
Laborator Nr. 5:
Structuri de date 2
A. Liste
Lista reprezintă cea mai simplă structură de date ı̂nlănţuită. Se folosesc doua tipuri de liste:
• liste simplu ı̂nlănţuite;
• liste dublu ı̂nlănţuite;
Pot fi definite ca fiind o secvenţă de obiecte alocate dinamic, ı̂n fiecare obiect se păstrânduse atât informaţia
utilă cât şi o referinţă către succesorul sau din listă. Există o multitudine de moduri prin care se poate
implementa această structură de date,ı̂nsă cel mai utilizat mod este prin definirea unei clase cu doi membri,
unul ı̂n care se reţine informaı̂ia utilă şi unul În care se reţine adresa următorului element din listă.
1 public class LinkedList {
2
3 int data ;
4 LinkedList next ;
5
6 public LinkedList () {
7
8 data = 0 ;
9 next = null ;
10 }
11
12 }
Se observă că membrul next este de acelaşi tip de date ca şi clasa, acesta pentru că următorul element din
listă este tot de acest tip de date. Pe lângă aceşti membri se mai pot adăuga şi alţii care să conţină diverse
informaţii, ı̂n funcţie de aplicaţia care cere utilizarea unei astfel de structuri.
Următorul exemplu ilustrează crearea şi afişarea unei liste simplu ı̂nlănţuite. Iniţial a fost creat un ele-
ment cu ajutorul constructorului, informaaţia din acest element a primit valoarea 23, iar pentru crearea
următorului element s-a instanţiat membrul next, ş.a.m.d. Această operaţie poate fi numită ,,alipirea
următorului element de elementul curent”. Pentru a parcurge lista se foloseşte un iterator.
1 c l a s s LinkedListDemo {
2 p u b l i c s t a t i c void main ( S t r i n g a r g s [ ] )
3 {
4 L i n k e d L i s t l i s t = new L i n k e d L i s t ( ) ;
5 l i s t . d a t a =23;
6 l i s t . n e x t = new L i n k e d L i s t ( ) ;
7 l i s t . next . data = 1 0 ;
8 l i s t . n e x t . n e x t = new L i n k e d L i s t ( ) ;
9 l i s t . next . next . data = 4 9 ;
10
11 // p a r c u r g e r e a listei de la primul element
12
13 LinkedList i t e r a t o r = l i s t ;
14 do
15 {
16 System . o u t . p r i n t l n ( i t e r a t o r . d a t a ) ;
17 }
18 w h i l e ( ( i t e r a t o r = i t e r a t o r . n e x t ) != n u l l ) ;
19
20 }
21 }
Un alt mod de folosire al listelor ı̂nlănţuite este prin declararea şi reţinerea primului element din listă:
1 class LinkedList2 {
2
3 int data ;
4 LinkedList2 next ;
5 LinkedList2 head ;
6
7 public LinkedList2 () {
8
9 head = t h i s ;
10 next = null ;
11 d a t a =0;
12 }
13
14 public LinkedList2 ( LinkedList2 head ) {
15
16 t h i s . head = head ;
2
17 next = null ;
18 d a t a =0;
19 }
20 }
21
22
23 // / / / / / / / / / / / / / / / / / / / / / / / / / / / /
24
25
26 class LinkedList2Demo {
27
28 public static void main ( S t r i n g args [ ] ) {
29
30 L i n k e d L i s t 2 l i s t = new L i n k e d L i s t 2 ( ) ;
31 l i s t . head = l i s t ;
32 l i s t . d a t a =23;
33 l i s t . n e x t = new L i n k e d L i s t 2 ( l i s t ) ;
34 l i s t . next . data = 1 0 ;
35 l i s t . n e x t . n e x t = new L i n k e d L i s t 2 ( l i s t ) ;
36 l i s t . next . next . data = 4 9 ;
37
38 // p a r c u r g e r e a l i s t e i de l a p r i m u l element
39 w h i l e ( l i s t . n e x t != n u l l ) {
40
41 System . o u t . p r i n t l n ( l i s t . d a t a ) ;
42 l i s t = l i s t . next ;
43 }
44
45 System . o u t . p r i n t l n ( l i s t . d a t a ) ;
46 l i s t = l i s t . head ;
47
48 while ( l i s t . next != n u l l ) {
49
50 System . o u t . p r i n t l n ( l i s t . d a t a ) ;
51 l i s t = l i s t . next ;
52 }
53 System . o u t . p r i n t l n ( l i s t . d a t a ) ;
54 }
55 }
Se observă că prin reţinerea primunul element al listei se poate ajunge mult mai repede si mai uşor la
primul element din listă. De asemenea, se poate observa că acest mod de construire al unei liste nu este
eficient, deoarece, ı̂n cazul unei liste cu sute sau chiar mii de elemente adăugarea noilor elemente va fi
imposibil de realizat. De aceea, adăugarea unui element nou precum şi ştergerea unui element sunt operaţii
specifice pentru lucrul cu liste alături de modificarea informaţiei utile, modificarea legăturii dintre elemente,
căutarea unui element ı̂n liste, aflarea poziţiei unui element.
În cazul ı̂n care se doreşte parcurgerea listei şi ı̂n celalalt sens (şi nu doar de la predecesor la succesor),
avem lista dublu ı̂nlănţuită. Aceasta păstreaz conceptele listei simplu ı̂nlănţuite, cu specificarea că fiecare
element al listei mai conţine o referinţă şi către elementul precedent. Un mod de declararea al unei astfel de
liste este următorul:
1 public c l a s s Nod {
2
3 p r i v a t e Nod n e x t ;
4 p r i v a t e Nod p r e v ;
5 private int data ;
6
7 p u b l i c Nod ( i n t data , Nod n e x t , Nod p r e v )
8 {
9 this . data = data ;
10 this . next = next ;
11 this . prev = prev ;
12 }
13 }
Operaţile specifice lister simplu ı̂nlănţuite se menţin şi pentru listele dublu, doar că trebuie să se ţină cont
şi de legătura prev.
Java pune la dispoziţia utilizatorilor o serie de interfeţe şi clase ce pot fi folosite pentru crearea şi utilizarea
diferitelor colecţii de date. Printre acestea amintim:
• interfaţa Collection - are definite metode pentru o serie de operaţii ce se aplică unei colecţii (detalii
aici)
3
• interfaţa Iterator - iteratorul este acel obiect ce permite parcurgerea colecţiilor (detalii aici)
• interfaţa List - interfaţă ce implementează Collection. Există două clase ce implementează această
interfaţă: ArrayList şi LinkedList. Interfaţa List oferă posibilitatea de a lucra ordonat, deci permite
păstrarea secvenţială a elementelor dintr-o colecţie (detalii aici)
• clasa ArrayList - clasa este echivalentul clasei Vector, dar sub forma unei colecţii. Un ArrayList este
o colecţie de elemente indexate ı̂ntr-o anumită ordine, dar nu neapărat sortate. (detalii)
• clasa LinkedList - aceasta este implementarea listei dublu ı̂nlănţuite. (detalii)
Interfaţa Set reprezintă un grup de elemente fără duplicate. Nu există o condiţie anume ce impune acest
lucru, ci implementările din clasele Set, sunt cele care impun aceasta condiţie. Interfaţa Set derivă din
Collections, deci va implementa aceleaşi metode ca şi această interfaţă. Un element, aflat deja ı̂n mulţime,
nu mai poate fi modificat. API-ul interfeţei se poate găsii aici
F. Clasa HashSet
Face parte din interfaţa Set şi are ca operaţii specifice următoarele:
• adăugarea elementelor;
• ştergerea elementelor;
• verificare dacă lista este goală;
• verificare daca un anumit obiect este conţinut ţn listă;
Un exemplu de utilizare al clasei HashSet este următorul:
1 import j a v a . u t i l . A r r a y L i s t ;
2 class Point {
3
4 public int x;
5 public int y;
6
7 public Point ( int x , int y) {
8
9 this . x = x ;
10 this . y = y ;
11 }
12
13 public boolean equ als ( Object o) {
14
15 if ( ! ( o instanceof Point ) )
16 return f a l s e ;
17 Point pt = ( Point ) o ;
18 return ( ( p t . x == t h i s . x ) && ( p t . y==t h i s . y ) ) ;
19 }
20
21 public int hashCode ( ) {
22
23 return 17∗ t h i s . x +23∗ t h i s . y +43;
24 }
25
26 public S t r i n g t o S t r i n g ( ) {
27 return ” x = ” +x+ ” y = ” +y + ” i d = ”+ hashCode ( )+ ” \n ” ;
28 }
29 }
30
31 // / / / / / / / / / / / / / / / / / / /
32
33 public class Multimi
34 {
35 public static void main ( S t r i n g args [ ] ) {
36
37 Set s e t = new H a s h S e t ( ) ;
38
39 // Adaug i n m u l t i m e
40 s e t . add (new P o i n t ( 1 , 2 ) ) ;
41 s e t . add (new P o i n t ( 2 , 1 ) ) ;
42 s e t . add ( ” c ” ) ;
43
4
44 // S t e r g un e l e m e n t din multime
45 s e t . remove ( ” c ” ) ;
46
47 // Marimea u n e i m u l t i m i
48 int s i z e = set . s i z e () ;
49 System . o u t . p r i n t l n ( s i z e ) ;
50
51 // Adaug un e l e m e n t c e e x i s t a deja
52 s e t . add (new P o i n t ( 1 , 2 ) ) ;
53
54 // f a r a a a v e a i n s a e f e c t
55 size = set . size () ;
56 System . o u t . p r i n t l n ( s i z e ) ;
57
58 // V e r i f i c a m d a c a un e l e m e n t e s t e d e j a i n m u l t i m e
59 boolean b = s e t . c o n t a i n s (new P o i n t ( 2 , 1 ) ) ; // t r u e
60 System . o u t . p r i n t l n ( b ) ;
61
62 b = set . contains (”c”) ; // false
63 System . o u t . p r i n t l n ( b ) ;
64
65 // Parcurgem m u l t i m e a
66 Iterator it = set . iterator () ;
67 while ( i t . hasNext ( ) ) {
68 // s i a f i s a m e l e m e n t e l e
69 Object element = i t . next ( ) ;
70 System . o u t . p r i n t l n ( e l e m e n t ) ;
71 }
72 }
73 }
5
Laborator 7:
Tratarea excepţiilor în Java
13 noiembrie 2011
I. NOŢIUNI TEORETICE
A. Ce este o excepţie?
O excepţie este un eveniment care apare în execuţia unui program şi care întrerupe evoluţia
normală a acestuia.
Încercarea de a soluţiona aceste excepţii folosind metode clasice duce la creşterea semnificativă
a complexităţii codului, ceea ce afectează, în mod indirect, corectitudinea codului şi claritatea
acestuia. De aceea, cei care au creat limbajul Java s-au gândit la un sistem de tratare a excepţiilor
ce permite programatorului:
B. Ierarhia excepţiilor
Pentru a crea un obiect excepţie, Java pune la dispoziţia programatorului o ierarhie de clase,
aflată în pachetul java.lang, ierarhie ce poate fi observată în imaginea de mai jos.
2
După cum se poate observa din figura de mai sus, clasa Throwable are doi descendenţi: clasa
Error şi clasa Exception. Nici una nu adaugă metode suplimentare, dar au fost introduse în acest
fel pentru a delimita două tipuri fundamentale de excepţii ce pot apărea într-o aplicaţie Java.
Clasa Error corespunde excepţiilor ce nu mai pot fi recuperate de către programator. Apariţia
unei astfel de excepţii înseamnă că a apărut o eroare deosebit de gravă şi aceasta determină ter-
minarea programului. Deşi este datoria programatorului să arunce şi să trateze excepţiile apărute,
excepţiile de tipul Error nu trebuie tratate în acest fel. Ele sunt utilizate de maşina virtuală Java
(JVM).
Clasa Exception este, de fapt, cea utilizată efectiv de programator în procesul de tratare a ex-
cepţiilor. Atât această clasă cât şi descendenţii ei se ocupă de excepţii ce pot fi rezolvate de către
program, fără oprirea acestuia.
Există o mare varietate de clase derivate din Exception care pot fi utilizate. Lista completă se
află aici.
Aruncarea unei excepţii se face cu ajutorul cuvântului cheie throw în felul următor:
throw <obiectExceptie>
sau
throw new <clasaExceptie>(”Mesaj”)
unde <obiectExceptie> şi new <clasaExceptie>(”Mesaj”) sunt instanţe ale clasei Throwable sau
ale unei clase derivate din aceasta.
O metodă poate arunca mai multe excepţii, însă prin aruncarea unei excepţii se iese din metodă
fără a mai executa instrucţiunile care urmau. În cazul în care o metodă aruncă o excepţie, fie prin
throw, fie prin apelul unei alte metode, fără a avea o secvenţă try - catch de prindere, atunci această
metodă trebuie să specifice clar acest lucru.
public void <numeMetoda> throws <classException1>, <classException2>, . . . {
...
throw <obExceptie1>
...
throw <obExceptie2>
3
...
O dată ce o excepţie a fost aruncată, ea trebuie prinsă. Acest lucru se poate realiza cu ajutorul
unui bloc try-catch, a cărui formă generală este prezentată mai jos:
try{
catch(<classExcept1> <idExcept1>){
catch(<classExcept2> <idExcept2>){
...
finally{
După cum se poate observa, structura de prinderere a excepţiilor poate fi delimitată în trei blocuri:
• try
Secvenţa de cod din acest bloc poate arunca, în anumite condiţii, excepţii. În cazul în care se
aruncă o exepţie, execuţia secvenţei din blocul try se întrerupe şi se declanşează procedura
de tratare a excepţiei. În caz contrar, secvenţa de cod din interiorul blocului se execută în
întregime, controlul fiind predat primei instrucţiuni de dupa blocul try-catch.
• catch
Numite şi handlere de excepţii, blocurile catch tratează excepţiile. În momentul în care
apare o excepţie în blocul try, se parcurge lista blocurilor catch în ordinea în care apar în
codul sursă. În cazul în care excepţia corespunde unui bloc catch, se execută secvenţa de
4
cod care corespunde blocului respectiv şi căutarea ia sfârşit, considerându-se că excepţia a
fost rezolvată. După cum se poate observa, pot exista mai multe blocuri catch, acest lucru
subliniind faptul că se pot trata excepţii de mai multe tipuri. Important este ca acestea să
fie introduse în ordinea copil - părinte pentru că blocurile catch se parcurg secvenţial.
• finally
Blocul finally cuprinde secvenţa de cod care se execută în final, indiferent dacă a apărut o
situaţie de excepţie sau nu.
Este obligatoriu ca blocul try să fie urmat de cel puţin un bloc catch sau finally.
În dezvoltarea unei aplicaţii Java pot exista cazuri în care excepţiile apărute să nu poată fi
tratate de clasele de excepţie deja existente în pachetele Java (java.util, java.io, java.net). Astfel,
dezvoltatorii de aplicaţii sunt nevoiţi să-şi creeze propriile clase de excepţie. Acest lucru se poate
realiza foarte uşor şi anume, creând clase care extind clasa Throwable sau clase descendente ale
acesteia. Se recomandă, dintre subclasele lui Throwable, să se extindă clasa Exception. Clasa Error
este specifică erorilor grave, care duc la terminarea execuţiei programului, şi este puţin probabil să
avem nevoie de ea.
1. Programul următor conţine funcţia main() care apelează metoda metoda1() având ca para-
metru un număr întreg. Funcţia metoda1() va arunca o excepţie în cazul în care parametru
trimis este diferit de 0, altfel funcţia se va executa până la capăt. Observaţi ce se afişează
pentru i=0 şi pentru i=1; când se execută funcţia metoda1() până la capăt şi când nu. De
asemenea, observaţi şi prezenţa blocului finally.
1 public c l a s s TestExceptions1 {
2 public s t a t i c void main ( S t r i n g [ ] args ) {
3 for ( int i = 0; i <= 1 ; i ++) {
4 try {
5 System . o u t . p r i n t l n ( " \n␣ Caz ␣ "+i ) ;
5
6 // a p a r i t i a exceptiei se realizeaza prin apelul m e t o d e i metoda1
7 metoda1 ( i ) ;
8 System . o u t . p r i n t l n ( " \n␣ S f a r s i t ␣ c a z ␣ "+i ) ;
9 } catch ( E x c e p t i o n ex ) {
10 // t r a t a r e a exceptiei intalnite i n metoda1
11 // a p e l a r e a functiei getMessage ( ) a clasei Exception
12 System . o u t . p r i n t l n ( "A␣ a p a r u t ␣ o ␣ e x c e p t i e . ␣ M e s a j u l ␣ e i ␣ e s t e : ␣ "+ex . g e t M e s s a g e ( ) ) ;
13 } finally {
14 System . o u t . p r i n t l n ( " Se ␣ e x e c u t a ␣ b l o c u l ␣ f i n a l l y " ) ;
15 }
16 }
17 }
18
19 // metoda1 specifica prin intermediul cuvantului cheie " throws " ce tipuri de exceptii arunca
20 p r i v a t e s t a t i c void metoda1 ( i n t i ) throws E x c e p t i o n {
21 System . o u t . p r i n t l n ( "Am␣ i n t r a t ␣ i n ␣ metoda1 " ) ;
22 if ( i != 0 ) {
23 // a r u n c a r e a exceptiei de tipul Exception
24 throw new E x c e p t i o n ( " e x c e p t i e ␣ d i n ␣ metoda1 " ) ;
25 }
26 System . o u t . p r i n t l n ( "Am␣ i e s i t ␣ d i n ␣ metoda1 " ) ;
27 }
28 }
2. Acest program conţine funcţia main() care apelează funcţia metoda1(), care, la rândul ei ape-
lează funcţia metoda2() ce poate arunca o excepţie. Observaţi că ambele funcţii (metoda1()
şi metoda2()) specifică ce tip de excepţie aruncă (Throwable). Deşi blocul try-catch are mai
multe blocuri catch, excepţia apărută este tratată de blocul corespunzător acesteia, adică
Throwable. Acestă clasă conţine diverse metode care pot ajuta programatorul în localizarea
excepţiei. Despre acestea puteţi citi aici.
1 public c l a s s TestExceptions2 {
2 public s t a t i c void main ( S t r i n g [ ] args ) {
3 for ( int i = 0; i <= 1 ; i ++) {
4 try {
5 System . o u t . p r i n t l n ( " \n␣ Caz ␣ " + i ) ;
6 metoda1 ( i ) ;
7 System . o u t . p r i n t l n ( " \n␣ S f a r s i t ␣ c a z ␣ " + i ) ;
8 } catch ( E x c e p t i o n ex ) {
9 System . o u t
10 . p r i n t l n ( "A␣ a p a r u t ␣ o ␣ e x c e p t i e ␣ E x c e p t i o n . ␣ M e s a j u l ␣ e i ␣ e s t e : ␣ "
11 + ex . g e t M e s s a g e ( ) ) ;
12 } catch ( Throwable exTh ) {
13 System . o u t . p r i n t l n ( "A␣ a p a r u t ␣ o ␣ e x c e p t i e ␣ Throwable ␣ i n ␣ main " ) ;
14 /∗ a p e l a r e a metodei printStackTrace ( ) a clasei Throwable c a r e afiseaza , conform
principiului unei s t i v e LIFO ,
15 informatii despre locatiile p a r c u r s e de e x c e p t i e ∗/
16 exTh . p r i n t S t a c k T r a c e ( System . o u t ) ;
17 } finally {
18 System . o u t . p r i n t l n ( " Se ␣ e x e c u t a ␣ b l o c u l ␣ f i n a l l y ␣ d i n ␣ main " ) ;
19 }
20 }
21 }
6
22
23 p r i v a t e s t a t i c void metoda1 ( i n t i ) throws Throwable {
24 System . o u t . p r i n t l n ( "Am␣ i n t r a t ␣ i n ␣ metoda1 " ) ;
25 metoda2 ( i ) ;
26 System . o u t . p r i n t l n ( "Am␣ i e s i t ␣ d i n ␣ metoda1 " ) ;
27 }
28
29 p r i v a t e s t a t i c void metoda2 ( i n t i ) throws Throwable {
30 System . o u t . p r i n t l n ( "Am␣ i n t r a t ␣ i n ␣ metoda2 " ) ;
31 if ( i != 0 ) {
32 throw new Throwable ( " e x c e p t i e ␣ d i n ␣ metoda2 " ) ;
33 }
34 System . o u t . p r i n t l n ( "Am␣ i e s i t ␣ d i n ␣ metoda2 " ) ;
35 }
36 }
3. Programul următor este unul didactic întrucât aruncă clase de excepţie descendente ale clasei
RuntimeException. Nu este obligatoriu ca acest gen de excepţii să fie ”prinse” (tratate), dar
exemplul a fost introdus pentru o mai bună înţelegere a mecanismului de aruncare/prindere
a excepţiilor.
După cum se poate observa la o primă rulare a programului, va fi prinsă prima excepţie,
NumberFormatException. Comentaţi, respectiv decomentaţi, secvenţe de cod din program,
astfel încât să obţineţi, pe rând, toate excepţiile tratate.
De asemenea, programul conţine o metodă callException() ce primeşte ca parametru un tip
de dată excepţie. Aceasta apelează câteva dintre metodele implementate de clasele de tip
excepţie. Metodele respective au rolul de a oferi mai multe informaţii despre locaţia şi tipul
de excepţie apărut.
1 public c l a s s TestExceptions3 {
2 public s t a t i c void main ( S t r i n g [ ] args ) {
3 try {
4 System . o u t . p r i n t l n ( " \n␣Number␣ Format ␣ E x c e p t i o n " ) ;
5 String s t r 1 = " 123 r " ;
6 Integer n = Integer . parseInt ( str1 ) ;
7
8 System . o u t . p r i n t l n ( " \n␣ A r r a y I n d e x O u t O f B o u n d s E x c e p t i o n " ) ;
9 int s i r [ ] = { 1 , 2 , 3 , 4 };
10 s i r [ 6 ] = 3;
11
12 System . o u t . p r i n t l n ( " \n␣ S t r i n g I n d e x O u t O f B o u n d s E x c e p t i o n " ) ;
13 String s t r 2 = " abcde " ;
14 char c 1 = s t r 2 . c h a r A t ( −1) ;
15
16 System . o u t . p r i n t l n ( " \n␣ N u l l P o i n t e r E x c e p t i o n " ) ;
17 String s t r 3 = null ;
18 System . o u t . p r i n t l n ( s t r 3 . l e n g t h ( ) ) ;
19
20 System . o u t . p r i n t l n ( " \n␣ A r i t h m e t i c E x c e p t i o n " ) ;
7
21 i n t n2 = 1 2 / 0 ;
22
23 } catch ( NumberFormatException n f e x ) {
24 System . o u t . p r i n t l n ( " T r a t a r e ␣ e x c e p t i e ␣ NumberFormatException . . . " ) ;
25 callException ( nfex ) ;
26 } catch ( A r r a y I n d e x O u t O f B o u n d s E x c e p t i o n a r r a y E x ) {
27 System . o u t . p r i n t l n ( " T r a t a r e ␣ e x c e p t i e ␣ A r r a y I n d e x O u t O f B o u n d s E x c e p t i o n . . . " ) ;
28 c a l l E x c e p t i o n ( arrayEx ) ;
29 } catch ( S t r i n g I n d e x O u t O f B o u n d s E x c e p t i o n s t r E x ) {
30 System . o u t . p r i n t l n ( " T r a t a r e ␣ e x c e p t i e ␣ S t r i n g I n d e x O u t O f B o u n d s E x c e p t i o n . . . " ) ;
31 c a l l E x c e p t i o n ( strEx ) ; ;
32 } catch ( N u l l P o i n t e r E x c e p t i o n nullEx ) {
33 System . o u t . p r i n t l n ( " T r a t a r e ␣ e x c e p t i e ␣ N u l l P o i n t e r E x c e p t i o n . . . " ) ;
34 c a l l E x c e p t i o n ( nullEx ) ;
35 } catch ( A r i t h m e t i c E x c e p t i o n aEx ) {
36 System . o u t . p r i n t l n ( " T r a t a r e ␣ e x c e p t i e ␣ A r i t h m e t i c E x c e p t i o n . . . " ) ;
37 c a l l E x c e p t i o n ( aEx ) ;
38 }
39 }
40
41 p r i v a t e s t a t i c void c a l l E x c e p t i o n ( R u n t i m e E x c e p t i o n r t e x ) {
42 System . o u t . p r i n t l n ( " M e s a j u l ␣ s t a n d a r d ␣ a l ␣ e x c e p t i e i : ␣ " ) ;
43 System . o u t . p r i n t l n ( r t e x ) ;
44 System . o u t . p r i n t l n ( " M e s a j u l ␣ e x c e p t i e i : ␣ " ) ;
45 System . o u t . p r i n t l n ( r t e x . g e t M e s s a g e ( ) ) ;
46 System . o u t . p r i n t l n ( " M e s a j u l ␣ l o c a l : ␣ " ) ;
47 System . o u t . p r i n t l n ( r t e x . g e t L o c a l i z e d M e s s a g e ( ) ) ;
48 System . o u t . p r i n t l n ( " \ n S t a c k ␣ t r a c e : ␣ " ) ;
49 r t e x . p r i n t S t a c k T r a c e ( System . o u t ) ;
50 }
51 }
Crearea propriilor excepţii se face prind crearea unei clase obişnuite, dar care moşteneşte clasa
Exception. Clasa următoare face exact acest lucru. IncompatibleMatrixException conţine doi con-
structori, unul fără parametri şi unul cu un parametru şi care apelează constructorul clasei de
bază.
1 public c l a s s I n c o m p a t i b l e M a t r i x E x c e p t i o n extends E x c e p t i o n {
2
3 public I n c o m p a t i b l e M a t r i x E x c e p t i o n ( ) {
4 }
5
6 public I n c o m p a t i b l e M a t r i x E x c e p t i o n ( S t r i n g m e s s a g e ) {
7 super ( m e s s a g e ) ;
8 }
9 }
Clasa prezentata mai jos, declară două matrici de dimensiuni diferite şi se încearcă înmulţirea
acestora. Metoda multiplyMatr() este apelată în cadrul unui bloc try şi verifică dacă două matrici
8
sunt compatibile. În cazul în care numărul de coloane ale primei matrici este diferit de numărul de
linii ale celei de-a doua, atunci se aruncă excepţia creată anterior, IncompatibleMatrixException.
1 public c l a s s TestMatrixException {
2 public s t a t i c void main ( S t r i n g [ ] args ) {
3 int [ ] [ ] matr1 , matr2 ;
4 matr1 = new i n t [ 2 ] [ 3 ] ;
5 matr2 = new i n t [ 4 ] [ 4 ] ;
6
7 try {
8 m u l t i p l y M a t r ( matr1 , matr2 ) ;
9 } catch ( I n c o m p a t i b l e M a t r i x E x c e p t i o n imEx ) {
10 System . o u t . p r i n t l n ( " M e s a j u l ␣ e s t e : ␣ "+imEx . g e t M e s s a g e ( ) ) ;
11 imEx . p r i n t S t a c k T r a c e ( System . o u t ) ;
12 }
13 }
14
15 p r i v a t e s t a t i c void m u l t i p l y M a t r ( i n t [ ] [ ] matr1 , int [ ] [ ] matr2 ) throws I n c o m p a t i b l e M a t r i x E x c e p t i o n {
16 if ( matr1 [ 0 ] . l e n g t h != matr2 . l e n g t h ) {
17 throw new I n c o m p a t i b l e M a t r i x E x c e p t i o n ( " m a t r i c i ␣ i n c o m p a t i b i l e ␣ p t ␣ i n m u l t i r e " ) ;
18 }
19 // cod d e s t i n a t pt inmultirea matricilor
20 }
21
22 }
III. TEMĂ
9
Laborator Nr. 8:
Fluxuri Java
Fluxurile Java pun la dispoziţie modalitatea prin care o aplicaţie permite citirea unor informaţii care se
găsesc pe o sursă externă, respectiv trimiterea unor informaţii către o destinaţie externă. Informaţia se
poate găsi oriunde: ı̂ntr-un fişier pe disc, ı̂n reţea, ı̂n memorie sau ı̂n alt program şi poate fi de orice tip:
date primitive, obiecte, imagini, sunete, etc. Mai mult, prin fluxuri este posibilă comunicarea ı̂ntre două
sau mai multe fire de execuţie ale aceleiaşi aplicaţii. Fluxurile sunt secvenţe de octeţi. Indiferent de tipul
informaţiilor, citirea/scrierea lor de pe un mediu extern, respectiv pe un mediu extern respectă următorii
algoritmi:
• Citirea:
• Scrierea:
Fluxurile pentru lucrul cu fişiere sunt cele mai uşor de ı̂nteles. Clasele care implementează aceste fluxuri
sunt urmatoarele:
FileReader caractere
FileWriter caractere
FileInputStream octeti
FileOutputStream octeti
Constructorii acestor clase acceptă ca argument un obiect prin care se specifică fişierul folosit. Acesta
poate fi un şir de caractere, un obiect de tip File sau un obiect de tip FileDescriptor.
Constructorii clasei FileReader (vezi şi API):
public FileReader( String fileName ) throws FileNotFoundException
public FileReader( File file ) throws FileNotFoundException
public FileReader( FileDescriptor fd )
Constructorii clasei FileWriter (vezi şi API):
public FileWriter( String fileName ) throws IOException
public FileWriter( File file ) throws IOException
public FileWriter( FileDescriptor fd )
public FileWriter( String fileName, boolean append ) throws IOException
Constructorii clasei FileOutputStream (vezi şi API):
2
FileOutputStream(File file) throws FileNotFoundException
FileOutputStream(File file, boolean append) throws FileNotFoundException
FileOutputStream(FileDescriptor fd)
FileOutputStream(String name) throws FileNotFoundException
FileOutputStream(String name, boolean append) throws FileNotFoundException
Constructorii clasei FileInputStream (vezi şi API):
InputStreamReader(InputStream in)
InputStreamReader(InputStream in, Charset cs)
InputStreamReader(InputStream in, CharsetDecoder dec)
InputStreamReader(InputStream in, String charsetName) throws UnsupportedEncodingException
Cei mai uzuali constructori sunt cei care primesc ca argument numele fişierului. Aceştia pot provoca
excepţii de tipul FileNotFoundException ı̂n cazul ı̂n care fişierul cu numele specificat nu există. Din acest
motiv orice creare a unui flux de acest tip trebuie facută ţntr-un bloc try....catch sau metoda ı̂n care sunt
create fluxurile respective trebuie să arunce excepţii de tipul FileNotFoundException sau de tipul superclasei
IOException.
Următoarele programe copiază conţinutul unui fişier ı̂ntr-un alt fişier.
1 import j a v a . i o . ∗ ;
2 p u b l i c c l a s s Copy1 {
3 p u b l i c s t a t i c void main ( S t r i n g [ ] args ) throws I O E x c e p t i o n {
4
5 FileReader i n = new F i l e R e a d e r ( ” i n . t x t ” ) ;
6 FileWriter o u t = new F i l e W r i t e r ( ” o u t . t x t ” ) ;
7
8 int c ;
9 while ( ( c = i n . r e a d ( ) ) != −1)
10 out . w r i t e ( c ) ;
11
12 in . close () ;
13 out . c l o s e ( ) ;
14 }
15 }
Se observă ca metoda main aruncă excepţii de tipul IOException, deci nu este necesară folosirea blocurilor
try....catch. Pentru citirea şi scrierea din\ı̂n fişiere s-au folosit clasele FileReader şi
textitFileWriter
În următorul exemplu este exemplificat modul de lucru cu clasele FileInputStream şi FileOutputStream,
precum şi folosirea blocurilor try...catch.
1 import j a v a . i o . ∗ ;
2 p u b l i c c l a s s Copy2 {
3 p u b l i c s t a t i c void main ( S t r i n g args [ ] ) {
4
5 FileInputStream in ;
6 FileOutputStream out ;
7
8 i n t ok ;
9 try {
10 i n = new F i l e I n p u t S t r e a m ( a r g s [ 0 ] ) ;
11 try {
12 o u t = new
13 FileOutputStream ( args [ 1 ] ) ;
14 ok = 0 ;
15
16 w h i l e ( ok != −1) {
17 try {
18 ok = i n . r e a d ( ) ;
19 o u t . w r i t e ( ok ) ;
20 System . o u t . p r i n t ( ( char ) ok ) ;
21 }
22 catch ( I O E x c e p t i o n e ) {
23 System . o u t . p r i n t l n ( e . g e t M e s s a g e ( ) ) ;
24 System . e x i t ( 1 ) ;
25 }
26
27 }
28 }
29 catch ( I O E x c e p t i o n e ) {
30 System . o u t . p r i n t l n ( e . g e t M e s s a g e ( ) ) ;
31 System . e x i t ( 1 ) ;
32 }
33 }
34 catch ( F i l e N o t F o u n d E x c e p t i o n e ) {
35 System . o u t . p r i n t l n ( e . g e t M e s s a g e ( ) ) ;
36 System . e x i t ( 1 ) ;
37 }
38 }
39 }
3
Se recomandă folosirea claselor FileReader şi FileWriter atunci când se citesc sau se scriu şiruri de carac-
tere. Pentru citirea sirurilor de octeţi(de exemplu pentru imagini) se vor folosii clasele FileOutputStream şi
FileInputStream.
Sunt folosite pentru a introduce o zonă tampon ţn procesul de scriere/citire a informaţiilor, reducând
astfel numarul de accese la dispozitivul ce reprezintă sursa originală de date. Sunt mult mai eficiente decât
fluxurile fără buffer şi din acest motiv se recomandă folosirea lor ori de câte ori este posibil.
Clasele pentru citirea/scrierea cu zonă tampon sunt:
BufferedReader caractere
BufferedWriter caractere
BufferedInputStream octeti
BufferedOutputStream octeti
Clasele BufferedReader şi BufferedInputStream citesc ţn avans date şi le memorează şntr-o zonă tampon.
Atunci când se execută o operaţie read(), octetul citit va fi preluat din buffer. În cazul ı̂n care buffer-ul
este gol citirea se face direct din flux şi, odata cu citirea octetului, vor fi memorati ı̂n buffer şi octeţii care ı̂i
urmează. Similar, se lucrează şi cu clasele BufferedWriter şi BufferedOutputStream.
Fluxurile de citire/scriere cu buffer sunt fluxuri de procesare şi sunt folosite prin suprapunere cu alte
fluxuri.
Exemplu de folosire a zonei tampon pentru realizarea citirii din fişier:
BufferedInputStream out = new BufferedInputStream(new FileInputStream("out.dat"), 1024)
Constructorii clasei BufferedReader sunt:
BufferedReader( Reader in )
BufferedReader( Reader in, int dim_buffer )
Constructorii clasei BufferedWriter sunt:
BufferedWriter( Writer out )
BufferedWriter( Writer out, int dim_buffer )
Constructorii clasei BufferedInputStream sunt:
BufferedInputStream( InputStream in )
BufferedInputStream( InputStream in, int dim_buffer )
Constructorii clasei BufferedOutputStream sunt:
BufferedOutputStream( OutputStream out )
BufferedOutputStream( OutputStream out, int dim_buffer )
În cazul constructorilor ı̂n care dimensiunea buffer-ului nu este specificată, aceasta primeâte valoarea im-
plicită de 512 octeţi.
Metodele acestor clase sunt cele uzuale de tipul read şi write (vezi API Reader, API Writer). Pe lângă
acestea, clasele pentru scriere prin buffer mai au şi metoda flush care goleşte explicit zona tampon chiar
dacă aceasta nu este plină.
Exemplu pentru folosirea zonelor tampon:
1 B u f f e r e d W r i t e r o u t = new B u f f e r e d W r i t e r (new F i l e W r i t e r ( ” o u t . d a t ” ) , 1024) ; //am c r e a t un flux cu buffer de 1024
octeti
2 f o r ( i n t i =0; i <1024; i ++)
3 o u t . w r i t e ( i ) ; // b u f f e r u l nu e s t e p l i n −> i n f i s i e r nu s−a s c r i s nimic
4 o u t . f l u s h ( ) ; // b u f f e r u l e s t e g o l i t −> d a t e l e s e s c r i u i n f i s i e r
4
C. Intrări/Ieşiri formatate
Fluxul standard de iesire se foloseşte pentru afişarea datelor pe ecran, ı̂n modul consola: Sys-
tem.out.println(”mesaj”). Fluxul standard pentru afişarea erorilor se foloseşte similar:
catch (IOException e) {
System.err.println("Eroare de intrare/iesire!")
}
Fluxurile de ieşire pot fi folosite, aşadar fără probleme deoarece tipul lor este PrintStream, clasa primitivă
pentru scrierea efectivă a datelor. În schimb, fluxul standard de intrare System.out, de tip InputStream care
este o clasa abstractă, deci pentru a-l putea utiliza va trebui să-l folosim ı̂mpreuna cu un flux de procesare
a datelor sau cu orice alt flux ce permite citirea efectiva a datelor.
Uzual, se foloseşte metoda readLine pentru citirea datelor de la tastatură şi din acest motiv vom folosi
intrarea standard ı̂mpreună cu o clasa de procesare care implementează metoda readLine. Exemplul tipic
este:
5
II. TEME DE LABORATOR
1. Într-un fişier se regăsesc pe prima linie dimensiunile nxm ale unei matrice, iar pe următoarele linii
elementele matricei corespunzatoare dimensiunilor date. Să se citească de la tastatură ı̂ncă o matrice
de dimensiune mxn şi să se scrie ı̂ntr-un alt fişier produsul celor doua matrici.(Se vor folosi clasele
FileWriter, FileReader, iar citirea de la tastatură se va face folosind clasa BufferedReader )
2. Să se citească de la tastatură un user şi o parolă. Acestea se vor compara cu ı̂nregistrările existente ı̂n
fişierul parole.txt. Dacă user-ul şi parola se regăsesc printre acestea (pe aceeaşi linie), se va afişa mesajul
”acces permis”, dacă se regăseşte doar user-ul, iar parola este greşită se va afişa ”parola gresita” şi se
va mai cere introducerea parolei ı̂ncă o dată, dar nu mai mult de 3 ori, dacă se atinge acest prag se va
afişa mesajul ”cont blocat”. În caz contrar se reia procesul de introduce a datelor, dar nu mai mult
de 5 ori. Dacă se atinge limita de 5 intrări se va afişa mesajul ”Nu ai cont. Inregistreaza-te.” (Se vor
folosi clasele FileInputStream şi FileOutputStream.)
Exemplu de date in fisierul parole.txt:
user user
gigi parolaMea
user1 parola1
3. Într-un fişier numit clienti.txt sunt memorate date despre clienţii unui magazin virtual. Pe fiecare linie
se reţine numele, prenumele şi vârsta clienţilor. Se cere să se afişeze numărul şi lista clienţilor majori
şi numărul clienţilor minori.
6
Laborator 9:
Fire de execuţie
20 noiembrie 2011
I. NOŢIUNI TEORETICE
Înainte de a defini conceptul de fir de execuţie sau thread, ne vom opri asupra conceptului
de multitasking. Acesta se referă la capacitatea unui computer de a executa mai multe programe
(task-uri, procese) în acelaşi timp. Având în vedere această noţiune, putem defini conceptul de
multithreading care se referă la execuţia mai multor secvenţe de cod în acelaşi timp, în cadrul
aceluiaşi program. O astfel de secvenţă de cod se numeşte fir de execuţie sau thread.
Un thread se execută în contextul unui program şi nu poate fi tratat decât în cadrul unui
program. Exemplele prezentate până acum au dispus de un sigur fir de execuţie, adică de o singură
structură secvenţială de instrucţiuni.
Limbajul Java pune la dispoziţia programatorului, in pachetul java.lang, două clase şi o interfaţă
pentru lucrul cu thread-uri:
• clasa ThreadGroup: crearea unor grupuri de thread-uri în vederea tratării acestora în mod
unitar;
Operaţiile următoare reprezintă numărul minim de paşi ce trebuie îndepliniţi pentru lucrul cu
un thread creat prin moştenirea clasei Thread:
2
2. suprascrierea metodei public void run() a clasei Thread în clasa derivată, MyThread. Instruc-
ţiunile din această metodă trebuie să implementeze ceea ce se doreşte ca thread-ul să facă.
Aceasta poate apela alte metode, folosi alte clase şi declara variabile ca orice metodă.Metoda
run() este apelată atunci când se execută un thread.
Pentru a înţelege mai bine se face o paralelă cu metoda main. Aceasta care este apelată atunci
când se execută o aplicaţie Java. Mai mult, atunci când JVM este pornită, se porneşte o
dată cu ea un thread care apelează metoda main.
4. pornirea thread-ului instanţiat prin apelul metodei start() moştenită din clasa Thread.
obThread.start();
Operaţiile care trebuie îndeplinite pentru a putea crea un thread prin implementarea interfeţei
Runnable sunt următorele:
2. clasa care implementează interfaţa Runnable trebuie să suprascrie toate metodele definite
în aceasta, dar cum interfaţa conţine doar metoda run(), ea este singura metodă ce trebuie
suprascrisă. Metoda run() implementează ceea ce se doreşte ca thread-ul să facă.
3
5. se porneşte thread-ul.
thread.start();
Clasa Thread defineşte o serie de metode ce pot fi suprascrise de clasa ce derivă din Thread.
Singura care trebuie suprascrisă obligatoriu este run(). Însă, această condiţie se impune şi in cazul
clasei care implementează interfaţa Runnable. Aşadar, dacă nu se doreşte suprascrierea altor me-
tode din Thread, atunci este mai bine să folosim a doua metodă.
Mai mult, cum în Java nu este permisă moştenirea multiplă, creare unui thread prin implementa-
rea interfeţei Runnable devine un avantaj pentru că acel thread poate să moştenească funcţionalităţi
definite în alte clase Java.
Un thread se poate afla la un moment dat într-una din stările următoare: nou creat, în execuţie,
blocat, terminat.
Clasa Thread conţine o serie de metode ce controlează execuţia unui thread. Iată câteva dintre
cele mai importante:
Nume metodă Descriere
String getName() se obţine numele thread-ului
int getPriority() se obţine prioritatea thread-ului
boolean isAlive() determină faptul că un thread mai este în execuţie sau nu
void join() forţează un thread să aştepte terminarea altuia
void run() entry point pentru un thread
static void sleep(long millis) suspendă execuţia unui thread pentru millis milisecunde
void start() începe execuţia unui fir printr-un apel run()
void stop() opreşte execuţia unui thread
Pentru mai multe informaţii despre metodele clasei Thread consultaţi API-ul clasei.
4
D. Priorităţi
Aparent thread-urile se execută simultan, dar la un moment dat doar un singur thread are
acces la resursele de sistem. Fiecare thread obţine o perioadă de timp în care are acces la resurse,
accesul făcându-se în mod organizat de către un planificator. Una dintre regulile pe care se bazează
planificatorul o reprezintă mecanismul de priorităţi.
Având în vedere cele spuse mai sus, fiecărui thread i se asociază un nivel de prioritate (un număr
întreg). Cu cât acest nivel este mai mare cu atât thread-ul va avea prioritate mai mare la resurse.
Dacă totuşi mai multe thread-uri au acelaşi nivel de prioritate, mecanismul de priorităţi dă dreptul
de execuţie fiecăruia printr-un algoritm circular.
Lucrul cu priorităţi este exemplificat în secţiunea II D.
Există cazuri în care mai multe thread-uri accesează aceeaşi resursă aparent în acelaşi timp.
Pentru a evita astfel de situaţii, care pot crea confuzie, limbajul Java oferă conceptul de monitor.
Acest lucru se realizează prin declararea unor metode, blocuri de cod ale unui obiect synchronized.
Modificatorul synchronized permite unui singur thread accesul, la un moment dat, la acele metode
sau blocuri de cod ale obiectului. Aşadar, dacă un thread apeleză o metodă synchronized a unui
obiect, un alt thread nu are acces la ea până când primul thread nu a terminat-o de executat.
Exemplul este prezentat în secţiunea II E.
Exemplul este destul de simplu şi nu necesită explicaţii suplimentare o dată ce au fost urmăriţi
paşii din secţiunea I B 1.
1 public c l a s s MyThread extends Thread {
2 p r i v a t e i n t countDown = 1 0 ;
3
4 public void run ( ) {
5 System . o u t . p r i n t l n ( " \ t ␣ b e g i n ␣ run ␣ method . . . " ) ;
6 while ( countDown >=0){
7 System . o u t . p r i n t l n ( " \ t \ t ␣ S t e p s ␣ l e t f t ␣ t o ␣ do : ␣ "+countDown ) ;
5
8 countDown−−;
9 }
10 System . o u t . p r i n t l n ( " \ t ␣ end ␣ run ␣ method ! " ) ;
11 }
12 }
1 public c l a s s DemoThread {
2
3 public s t a t i c void main ( S t r i n g [ ] args ) {
4 System . o u t . p r i n t l n ( " b e g i n ␣ main . . . " ) ;
5 MyThread obThread = new MyThread ( ) ;
6 System . o u t . p r i n t l n ( " s t a r t ␣ t h e ␣ t h r e a d " ) ;
7 obThread . s t a r t ( ) ;
8 System . o u t . p r i n t l n ( " s t i l l ␣ i n ␣ main . . . " ) ;
9 }
10
11 }
Un singur lucru pare să fie curios: apariţia mesajului ”still in main...” imediat după mesajul
”start the thread”. Acest lucru se întâmplă din cauza faptului că metoda main are propriul său fir
de execuţie în care rulează. Prin apelul metodei start() a thread-ului se cere maşinii virtuale Java
crearea şi pornirea unui nou thread. Din acest moment JVM preia controlul execuţiei programului
creând contextul necesar unui thread şi în acest context se apelează metoda run(). Ca urmare se
iese imediat din metoda start().
Exemplul prezentat mai jos este puţin mai complex în sensul că profităm de avantajele imple-
mentării unei interfeţe, putând totuşi moşteni orice altă clasă.
1 public c l a s s Display {
2 public void p r i n t M e s s a g e ( S t r i n g m e s s a g e ) {
3 System . o u t . p r i n t l n ( m e s s a g e ) ;
4 }
5 }
Clasa MyRunnable moşteneşte clasa Display, dar beneficiază de proprietăţile unei clase de tip
thread prin implementarea interfeţei Runnable. Unele dintre îmbunătăţirile ce sunt aduse progra-
mului sunt mutarea instanţierii thread-ului (se trimite ca parametru obiectul curent, deci un obiect
de tipul MyRunnable) şi pornirea acestuia în constructorul clasei MyRunnable.
1 public c l a s s MyRunnable extends D i s p l a y implements Runnable {
2 p r i v a t e i n t countDown = 1 0 ;
3 p r i v a t e Thread t h r e a d ;
4
5 public MyRunnable ( ) {
6
6 t h r e a d = new Thread ( t h i s ) ;
7 System . o u t . p r i n t l n ( " s t a r t ␣ t h e ␣ t h r e a d " ) ;
8 thread . s t a r t () ;
9 }
10
11 public void run ( ) {
12 p r i n t M e s s a g e ( " \ t ␣ b e g i n ␣ run ␣ method . . . " ) ;
13 while ( countDown >= 0 ) {
14 p r i n t M e s s a g e ( " \ t \ t ␣ S t e p s ␣ l e t f t ␣ t o ␣ do : ␣ " + countDown ) ;
15 countDown−−;
16 }
17 p r i n t M e s s a g e ( " \ t ␣ end ␣ run ␣ method ! " ) ;
18 }
19 }
Clasa DemoThread creează două thread-uri. Pe primul îl porneşte şi îl suspendă pentru 4000
de milisecunde. Observaţi starea în care se află thread-ul după suspendarea temporară a acestuia
7
(apelul metodei isAlive()). Apoi, se porneşte thread-ul al doilea şi se blochează resursele acestuia
până când se reia execuţia lui (apelul metodei resume()). Observaţi starea thread-ului după apelul
metodei suspend().
În cele din urmă, se forţează blocarea thread-ului principal până când myThread2 işi termină
execuţia (linia de cod 29).
1 public c l a s s DemoThread {
2 public s t a t i c void main ( S t r i n g [ ] a r g s ) throws I n t e r r u p t e d E x c e p t i o n {
3 System . o u t . p r i n t l n ( " b e g i n ␣ main ␣ t h r e a d . . . " ) ;
4 MyThread myThread1 = new MyThread ( " t h r e a d ␣ 1 " ) ;
5 myThread1 . s t a r t ( ) ;
6 System . o u t . p r i n t l n ( myThread1 . getName ( ) ) ;
7 try {
8 myThread1 . s l e e p ( 4 0 0 0 ) ;
9 } catch ( I n t e r r u p t e d E x c e p t i o n e ) {
10 e . printStackTrace () ;
11 }
12 if ( myThread1 . i s A l i v e ( ) ) {
13 System . o u t . p r i n t l n ( myThread1 . getName ( )+" ␣ i s ␣ a l i v e ! " ) ;
14 } else {
15 System . o u t . p r i n t l n ( myThread1 . getName ( )+" ␣ i s ␣ t e r m i n a t e d ! " ) ;
16 }
17
18 MyThread myThread2 = new MyThread ( " t h r e a d ␣ 2 " ) ;
19 System . o u t . p r i n t l n ( myThread2 . getName ( ) ) ;
20 myThread2 . s t a r t ( ) ;
21 myThread1 . s u s p e n d ( ) ;
22 if ( myThread2 . i s A l i v e ( ) ) {
23 System . o u t . p r i n t l n ( myThread2 . getName ( )+" ␣ i s ␣ a l i v e ! " ) ;
24 } else {
25 System . o u t . p r i n t l n ( myThread2 . getName ( )+" ␣ i s ␣ t e r m i n a t e d ! " ) ;
26 }
27
28 System . o u t . p r i n t l n ( " b e f o r e ␣ main ␣ t h r e a d ␣ s l e e p s " ) ;
29 Thread . s l e e p ( 2 0 0 0 ) ;
30 System . o u t . p r i n t l n ( " a f t e r ␣ main ␣ t h r e a d ␣ h a s ␣ s l e p t " ) ;
31
32 myThread2 . s l e e p ( 2 0 0 0 ) ;
33 myThread2 . resume ( ) ;
34 try {
35 myThread2 . j o i n ( ) ;
36 } catch ( I n t e r r u p t e d E x c e p t i o n e ) {
37 e . printStackTrace () ;
38 }
39 myThread2 . s l e e p ( 1 0 0 0 ) ;
40 System . o u t . p r i n t l n ( " end ␣ main ␣ t h r e a d ! ! ! " ) ;
41 }
42 }
8
D. Priorităţi
9
E. Sincronizarea firelor de execuţie
Clasa MySynchronized are un constructor cu doi parametri. Unul este de tip String şi reprezintă
numele thread-ului, iar cel de-al doilea este un număr întreg. Constructorul este cel care instanţiază
thread-ul şi tot el este cel care îl porneşte.
Observaţi cele două metode care folosesc modificatorul synchronized. Prima metodă îl foloseşte
ca modificator al funcţiei, iar ce-a de-a doua metodă, cea între comentarii, îl foloseşte ca şi bloc.
Important de reţinut este că în varianta bloc synchronized se aplică doar pe obiecte.
1 public c l a s s MySynchronized implements Runnable {
2 private int count ;
3 p r i v a t e Thread t h r e a d ;
4
5 public MySynchronized ( S t r i n g name , int count ) {
6 this . count = count ;
7 t h r e a d = new Thread ( t h i s , name ) ;
8 thread . s t a r t () ;
9 }
10
11 public synchronized i n t add ( ) {
12 c o u n t ++;
13 try {
14 Thread . s l e e p ( 1 0 0 0 ) ;
15 } catch ( I n t e r r u p t e d E x c e p t i o n e ) {
16 System . o u t . p r i n t l n ( " main ␣ t h r e a d ␣ i n t e r r u p t e d " ) ;
17 }
18 ++c o u n t ;
19 return c o u n t ;
20 }
21
22 /∗ p u b l i c i n t add ( ) {
23 synchronized ( thread ) {
24 c o u n t ++;
25 try {
26 Thread . s l e e p ( 1 0 0 0 ) ;
27 } catch ( InterruptedException e ) {
28 System . o u t . p r i n t l n ( " main t h r e a d interrupted ") ;
29 }
30 ++c o u n t ;
31 r e t u r n count ;
32 }
33 } ∗/
34
35 public void run ( ) {
36 System . o u t . p r i n t l n ( t h r e a d . getName ( ) + " ␣ s t a r t i n g . " ) ;
37 System . o u t . p r i n t l n ( " \ t ␣ t h e ␣ numer ␣ o f ␣ "+t h r e a d . getName ( )+" ␣ i s : ␣ "+add ( ) ) ;
38 System . o u t . p r i n t l n ( t h r e a d . getName ( ) + " ␣ t e r m i n a t i n g . " ) ;
39 }
40 }
10
2 public s t a t i c void main ( S t r i n g [ ] args ) {
3 System . o u t . p r i n t l n ( " b e g i n ␣ main ␣ t h r e a d . . . " ) ;
4 MySynchronized t h r e a d 1 = new MySynchronized ( " t h r e a d 1 " , 1 ) ;
5 MySynchronized t h r e a d 2 M y S y n c r o n i z e d = new MySynchronized ( " t h r e a d 2 " , 2 ) ;
6 System . o u t . p r i n t l n ( " b e g i n ␣ main ␣ t h r e a d . . . " ) ;
7 }
8 }
III. TEMĂ
1. Realizaţi un program care creează cel puţin două fire de execuţie ce calculează produsul
elementelor aceluiaşi vector. Elementele vectorului se vor citi din fişierul in.txt, iar rezultatul
se va afişa într-un alt fişier, out.txt. Cerinţe de implementare:
• pentru calculul produsului folosiţi synchronized (ori modificatorul de acces ori ca bloc);
• pentru implementarea thread-urilor puteţi folosi oricare dintre cele două metode pre-
zentate în laborator;
• atât pentru lucrul cu fişiere cât şi pentru lucrul cu thread-uri se vor folosi mecanisme
de tratare a excepţiilor.
11
Laborator Nr. 10:
Interfeţe grafice ı̂n Java
Interfaţa grafică, - GUI, este un termen cu ı̂nţeles larg care se referă la toate tipurile de comunicare dintre
un program şi utilizatorii săi. Aceasta este o particularizare a interfeţei cu utilizatorul - UI, prin care se
ı̂ntelege interacţiune dintre un program şi utilizatorii săi. Aşadar, UI se referă nu numai la ceea ce utilizatorul
vede pe ecran ci şi la toate mecanismele de comunicare ı̂ntre acesta şi program.
Limbajul Java pune la dispoziţie numeroase clase pentru implementarea diverselor funcţionalităţi UI, ı̂nsă
ı̂n continuare sunt prezentate acelea care permit realizarea unei intefeţe grafice cu utilizatorul (GUI).
Biblioteca de clase care oferă servicii grafice se numeste java.awt, AWT fiind prescurtarea de la Abstract
Window Toolkit. În principiu, crearea unei aplicaţii grafice presupune următoarele:
• Crearea unei suprafeţe de afişare (cum ar fi o fereastră) pe care vor fi aşezate obiectele grafice care
servesc la comunicarea cu utilizatorul (butoane, controale de editare, texte, etc);
• Crearea şi aşezarea obiectelor grafice pe suprafaţa de afişare ı̂n poziı̂iile corespunzătoare;
• Definirea unor acţiuni care trebuie să se execute ı̂n momentul când utilizatorul interacţionează cu
obiectele grafice ale aplicaţiei;
• ,,Ascultarea” evenimentelor generate de obiecte ı̂n momentul interacţiunii cu utilizatorul şi executarea
acţiunilor corespunzătoare aşa cum au fost ele definite.
Printr-o componentă grafică se ı̂nţelege un obiect care are o reprezentare grafică ce poate fi afişată pe
ecran şi care poate interacţiona cu utilizatorul. Exemple de componente sunt ferestrele, butoanele, bare de
defilare, etc. În general, toate componentele sunt definte de clase proprii ce se gasesc ı̂n pachetul java.awt.
Vezi API aici.
Crearea obiectelor grafice nu realizează automat şi afişarea lor pe ecran. Mai ı̂ntâi ele trebuie aăezate pe
o suprafaţă de afişare, care poate fi o fereastră sau suprafaţa unui applet, şi vor deveni vizibile ı̂n momentul
ı̂n care suprafaţa pe care sunt afişate va fi vizibilă.
În general, toate componentele sunt definte de clase proprii ce se găsesc ı̂n pachetul java.awt, clasa
Component este o superclasă abstractă a tuturor acestor clase. Ierarhia acestor clase este sumarizată ı̂n
diagrama de mai jos.
Din cauza modului de imlementare a meniurilor pe diferite sisteme de operare, acestea nu au putut fi
integrate ca obiecte de tip Component. Superclasa cu ajutorul căreia se pot crea meniuri este MenuComponent,
iar subclasele sale sunt:
2
A. Suprafeţe de afişare
Suprafaţa pe care se aşează obiectele grafice se numeşte suprafaţă de afişare sau container şi reprezintă
o instanţă a unei clase obtinută prin extensia superclasei Container. O parte din ierarhia a carei rădăcină
este Container este prezentată ı̂n figura de mai jos:
Componentele adăugate sunt memorate ı̂ntr-o listă, iar poziţiile lor din această listă vor defini ordinea
de transpunere a acestora ı̂n cadrul containerului. Dacă nu este specificat niciun index la adăugarea unei
componente, atunci ea va fi adăugată pe ultima pozitie a listei.
Clasa Container pune la dispoziţie metoda add pentru adăugarea unei componente pe o suprafaţă de
afişare. O componentă nu poate aparţine decât unui singur container, ceea ce ı̂nseamnă că pentru a muta
un obiect dintr-un container ı̂n altul trebuie să-l eliminam mai ı̂ntâi de pe containerul iniţial. Eliminarea
unei componente de pe un container se face cu metoda remove.
Exemplu de butoane adăugate ı̂ntr-un container:
1 import j a v a . awt . ∗ ;
2 public c l a s s Test1 {
3 p u b l i c s t a t i c void main ( S t r i n g args [ ] ) {
4
5 // c r e e z c o n t a i n e r −u l − o b i e c t de t i p frame
6 Frame f = new Frame ( ”O f e r e a s t r a ” ) ;
7
8 // s e t e z modul de d i p u n e r e a ob . pe suprafata ferestrei
9 f . s e t L a y o u t (new FlowLayout ( ) ) ;
10
11 // c r e e z c e l e doua b u t o a n e
12 B u t t o n b1 = new B u t t o n ( ”OK” ) ;
13 B u t t o n b2 = new B u t t o n ( ” C a n c e l ” ) ;
14
15 // adaug p r i m u l buton pe suprafata ferestrei
16 f . add ( b1 ) ;
17 f . pack ( ) ;
18
19 // adaug a l doile buton pe suprafata ferestrei
20 f . add ( b2 ) ;
21 f . pack ( ) ;
22
23 // a f i s e z f e r e a s t r a (o fac vizibila )
24 f . show ( ) ;
25 }
26 }
3
2. Gestionarea poziţionării componentelor ı̂ntr-un container
Un gestionar de pozişionare layout manager este un obiect care controlează dimensiunea şi aranjarea
(poziţia) componentelor unui container. Aşadar, modul de aranjare a componentelor pe o suprafaţă de afişare
nu este o caracteristică a clasei Container. Fiecare obiect de tip Container, sau o extensie a lui (Applet,
Frame, Panel) are asociat un obiect care se ocupă cu dispunerea componentelor pe suprafaţa sa. Toate
clasele care instanţiază obiecte pentru gestionarea poziţionării implementează interfaţa LayoutManager. La
instanţierea unui container se creează implicit un gestionar de poziţionare asociat acestuia. De exemplu,
pentru o fereastră (un obiect de tip Window sau o subclasa a sa) gestionarul implict este de tip BorderLayout,
ı̂n timp ce pentru un container de tip Panel este o instanta a clasei FlowLayout.
Cei mai utilizaţi gestionari din pachetul java.awt sunt:
• FlowLayout
• BorderLayout
• GridLayout
• CardLayout
• GridBagLayout
Detalii despre modul de utilizare a gestionarilor de poziţionare se găsesc aici.
Plasarea componentelor direct pe suprafaţa de afişare poate deveni incomodă ı̂n cazul ı̂n care avem multe
obiecte grafice. Din acest motiv se recomandă gruparea obiectelor grafice ı̂nrudite ca funcţii astfel ı̂ncât să
putem fi siguri că, indiferent de gestionarul de poziţionare al suprafeţei de afişare, ele se vor găsi ı̂mpreună.
Gruparea componentelor se face folosind panel-uri.
Un panel este cel mai simplu model de container. El nu are o reprezentare vizibilă, rolul său fiind de a oferi
o suprafaţa de afişare pentru componente grafice, inclusiv pentru alte panel-uri. Clasa care instanţiază aceste
obiecte este Panel, extensie a superclasei Container. Pentru a aranja corespunzator componentele grupate
ı̂ntr-un panel, acestuia i se poate specifica un gestionar de poziţionare anume, folosind metoda setLayout.
Gestionarul implicit pentru containerele de tip Panel este FlowLayout.
Aşadar, o aranjare eficientă a componentelor unei ferestre ı̂nseamnă:
• gruparea componentelor ,,ı̂nfrăţite” (care nu trebuie sa fie despartie de gestionarul de pozitionare al
ferestrei) ı̂n panel-uri;
• aranjarea componentelor unui panel, prin specificarea acestuia a unui gestionar de poziţionare core-
spunzător;
• aranjarea panel-urilor pe suprafaţa ferestrei, prin specificarea gestionarului de poziţionare al ferestrei.
Exemplu
1 import j a v a . awt . ∗ ;
2 public c l a s s Test2 {
3 p u b l i c s t a t i c void main ( S t r i n g a r g s [ ] ) {
4 Frame f = new Frame ( ” P a n e l ” ) ;
5
6 Panel p a n e l = new P a n e l ( ) ;
7 panel . s e t L a y o u t (new FlowLayout ( ) ) ;
8 panel . add (new L a b e l ( ” Text : ” ) ) ;
9 panel . add (new T e x t F i e l d ( ” ” , 2 0 ) ) ;
10 panel . add (new B u t t o n ( ” R e s e t ” ) ) ;
11
12 f . add ( p a n e l , B o r d e r L a y o u t .NORTH) ;
13 f . add (new B u t t o n ( ”OK” ) , B o r d e r L a y o u t . EAST) ;
14 f . add (new B u t t o n ( ” C a n c e l ” ) , B o r d e r L a y o u t .WEST) ;
15 f . pack ( ) ;
16
17 f . show ( ) ;
18 }
19 }
4
C. Componente grafice
Unele dintre cele mai utilizate componente grafice sunt: etichetele, butoanele, câmpurile de text, listele
derulante, etc. O listă completă a claselor cu ajutorul cărora se definesc componentele grafice, precum şi
proprietăţile lor se găseşte aici.
1. Clasa Label
Un obiect de tip Label (etichetă) reprezintă o componentă pentru plasarea unui text pe o suprafaţă de
afiâare. O eticheta este formata dintr-o singura linie de text static ce nu poate fi modificat de catre utilizator,
dar poate fi modificat din program. Exemplu: Cinci etichete şi adăugate ı̂ntr-un container.
1 import j a v a . awt . ∗ ;
2
3 public c l a s s TestLabel {
4 p u b l i c s t a t i c void main ( S t r i n g a r g s [ ] ) {
5 Frame f = new Frame ( ” T e s t L a b e l ” ) ;
6 f . s e t L a y o u t (new B o r d e r L a y o u t ( ) ) ;
7
8 L a b e l nord , sud , e s t , v e s t , c e n t r u ;
9 n o r d = new L a b e l ( ” Nord ” , L a b e l .CENTER) ;
10 s u d = new L a b e l ( ” Sud ” , L a b e l .CENTER) ;
11 e s t = new L a b e l ( ” E s t ” , L a b e l . RIGHT) ;
12 v e s t = new L a b e l ( ” V e s t ” , L a b e l . LEFT) ;
13 c e n t r u = new L a b e l ( ” C e n t r u ” , L a b e l .CENTER) ;
14 centru . setBackground ( Color . yellow ) ;
15 c e n t r u . s e t F o n t (new Font ( ” A r i a l ” , Font . BOLD, 14) ) ;
16
17 f . add ( nord , B o r d e r L a y o u t .NORTH) ;
18 f . add ( sud , B o r d e r L a y o u t . SOUTH) ;
19 f . add ( e s t , B o r d e r L a y o u t . EAST) ;
20 f . add ( v e s t , B o r d e r L a y o u t .WEST) ;
21 f . add ( c e n t r u , B o r d e r L a y o u t .CENTER) ;
22 f . pack ( ) ;
23
24 f . show ( ) ;
25 }
26 }
2. Clasa Button
Un obiect de tip Button se foloseşte pentru plasarea unui buton etichetat pe o suprafata de afisare.
Exemplu: Doua butoane adăugate pe o fereastră;
1 import j a v a . awt . ∗ ;
2
3 public c l a s s TestButton {
4 p u b l i c s t a t i c void main ( S t r i n g a r g s [ ] ) {
5 Frame f = new Frame ( ” B u t t o n ” ) ;
6 f . s e t L a y o u t (new FlowLayout ( ) ) ;
7 f . s e t S i z e (200 , 200) ;
8
9 B u t t o n b1 = new B u t t o n ( ”OK” ) ;
10 b1 . s e t B o u n d s ( 3 0 , 3 0 , 5 0 , 7 0 ) ;
11 b1 . s e t F o n t (new Font ( ” A r i a l ” , Font . BOLD, 1 4 ) ) ;
12 b1 . s e t B a c k g r o u n d ( j a v a . awt . C o l o r . o r a n g e ) ;
13 f . add ( b1 ) ;
14
15 B u t t o n b2 = new B u t t o n ( ” C a n c e l ” ) ;
16 b2 . s e t B o u n d s ( 1 0 0 , 3 0 , 7 0 , 5 0 ) ;
17 b2 . s e t F o r e g r o u n d ( j a v a . awt . C o l o r . b l u e ) ;
18 f . add ( b2 ) ;
19 f . pack ( ) ;
20 f . show ( ) ;
21
22 }
23 }
3. Clasa Checkbox
Un obiect de tip Checkbox reprezintă o componentă care are două stări : selectată sau neselectată. Este
folosit pentru a prelua anumite opţiuni de la utilizator.
5
1 import j a v a . awt . ∗ ;
2
3 p u b l i c c l a s s TestCheckBox {
4 p u b l i c s t a t i c void main ( S t r i n g a r g s [ ] ) {
5 Frame f = new Frame ( ” CheckBox ” ) ;
6 f . s e t L a y o u t (new G r i d L a y o u t ( 5 , 1 ) ) ;
7 f . s e t S i z e (200 , 200) ;
8
9 Label l a b e l 1 = new L a b e l ( ” I n g r e d i e n t e P i z z a : ” , L a b e l .CENTER) ;
10 label1 . setBackground ( Color . orange ) ;
11 Label l a b e l 2 = new L a b e l ( ” ” ) ;
12 label2 . setBackground ( Color . lightGray ) ;
13
14 Checkbox c b x 1 = new Checkbox ( ” c a s c a v a l ” ) ;
15 Checkbox c b x 2 = new Checkbox ( ” s u n c a ” ) ;
16 Checkbox c b x 3 = new Checkbox ( ” a r d e i ” ) ;
17
18 f . add ( l a b e l 1 ) ;
19 f . add ( l a b e l 2 ) ;
20 f . add ( c b x 1 ) ;
21 f . add ( c b x 2 ) ;
22 f . add ( c b x 3 ) ;
23
24 f . pack ( ) ;
25 f . show ( ) ;
26
27 }
28 }
4. Clasa Choice
Un obiect de tip Choice defineşte o listă de opţiuni din care utilizatorul poate selecta una singură. La un
moment dat, din ı̂ntreaga listă doar o singura opţiune este vizibilă, cea selectată ı̂n momentul curent.
1 import j a v a . awt . ∗ ;
2
3 public c l a s s Choice {
4 p u b l i c s t a t i c void main ( S t r i n g a r g s [ ] ) {
5 Frame f = new Frame ( ” C h o i c e ” ) ;
6 f . s e t L a y o u t (new G r i d L a y o u t ( 4 , 1 ) ) ;
7 f . s e t S i z e (200 , 200) ;
8
9 L a b e l l a b e l = new L a b e l ( ” A l e g e t i culoarea ”) ;
10 label . setBackground ( Color . red ) ;
11
12 Choice c u l o r i = new C h o i c e ( ) ;
13 culori . add ( ” Rosu ” ) ;
14 culori . add ( ” Verde ” ) ;
15 culori . add ( ” A l b a s t r u ” ) ;
16 culori . s e l e c t ( ” Rosu ” ) ;
17
18 f . add ( l a b e l ) ;
19 f . add ( c u l o r i ) ;
20
21 f . pack ( ) ;
22 f . show ( ) ;
23
24 }
25 }
5. Clasa TextField
Un obiect de tip TextField defineşte un control de editare a textului pe o singură linie. Este util pentru
interogarea utilizatorului asupra unor valori.
1 import j a v a . awt . ∗ ;
2
3 public c l a s s TestText {
4 p u b l i c s t a t i c void main ( S t r i n g a r g s [ ] ) {
5 Frame f = new Frame ( ” Text ” ) ;
6 f . s e t L a y o u t (new G r i d L a y o u t ( 3 , 1 ) ) ;
7 f . s e t S i z e (200 , 200) ;
8 f . setBackground ( Color . lightGray ) ;
9
10 T e x t F i e l d nume = new T e x t F i e l d ( ” ” , 3 0 ) ;
11 T e x t F i e l d p a r o l a = new T e x t F i e l d ( ” ” , 1 0 ) ;
12 p a r o l a . setEchoChar ( ’ ∗ ’ ) ;
13
14 P a n e l p1 = new P a n e l ( ) ;
15 p1 . s e t L a y o u t (new FlowLayout ( FlowLayout . LEFT) ) ;
16 p1 . add (new L a b e l ( ”Nume : ” ) ) ;
17 p1 . add ( nume ) ;
18
19 P a n e l p2 = new P a n e l ( ) ;
20 p2 . s e t L a y o u t (new FlowLayout ( FlowLayout . LEFT) ) ;
6
21 p2 . add (new L a b e l ( ” P a r o l a : ” ) ) ;
22 p2 . add ( p a r o l a ) ;
23
24 L a b e l a c c e s = new L a b e l ( ” I n t r o d u c e t i numele si parola ! ” , L a b e l .CENTER) ;
25 f . add ( p1 ) ;
26 f . add ( p2 ) ;
27 f . add ( a c c e s ) ;
28
29 f . pack ( ) ;
30 f . show ( ) ;
31
32 }
33 }
II. TEMA
1. Compilaţi şi rulaţi aplicaţile prezentate. Modificaţi programele astfel ı̂ncât să se pună ı̂n evidenţă toate
tipurile de ,,aranjare” a componentele pe container.
2. Realizaţi un program, pe o anumită temă, ı̂n care să utilizaţi cât mai multe diintre componentele ce
pot fi adăugate pe un container. Folosiţi cel puţin o componentă care nu a fost prezentată ı̂n acest
laborator(vedeţi API-ul.)
3. Realizaţi o interfaţă pentru un calculator. Vezi calculatorul din Windows. Container-ul va trebui să
conţină butoanele pentru cifre, butoanele pentru operaţii aritmetice, ,,fereastra” pentru afişare, precum
şi alte butoane necesare efectuării calculelor aritmetice..
7
Laborator 11:
Evenimente generate de componente AWT
4 decembrie 2011
I. NOŢIUNI TEORETICE
A. Ce este un eveniment?
La acţiunea utilizatorului asupra unei componente grafice, JVM generează aşa numitele eve-
nimente. Evenimentul este de fapt o instanţă a unei clase Java, instanţă care conţine o serie de
informaţii despre acţiune.
B. Modelul de evenimente
2
Figura 1: Modelul de evenimente jdk1.1
C. Tipuri de evenimente
• ContainerEvent: specifică dacă s-a modificat conţinutul unui container în urma adăugării
sau eliminării unei componente;
• MouseEvent: precizează dacă a avut loc o acţiune de genul apasarea unei taste a mouse-ului,
şamd.;
3
Pentru a răspunde unui eveniment este necesară crearea unuia sau mai multor handlere de
eveniment (delegaţi) şi asocierea lor cu componenta corespunzătoare. Pentru crearea unui handler
e nevoie de implementarea unei anumite interfeţe (în funcţie de tipul evenimentului) într-o anumită
clasă. Asocierea handler - componentă se face prin intermediul unor metode ale clasei Component,
în funcţie de tipul evenimentului.
4
Interfaţă Metode ce trebuie implementate
ActionListener actionPerformed(ActionEvent e)
ComponentListener componentResized(ComponentEvent e)
componentMoved(ComponentEvent e)
componentShown(ComponentEvent e)
componentHidden(ComponentEvent e)
MouseListener mouseClicked(MouseEvent e)
mousePressed(MouseEvent e)
mouseReleased(MouseEvent e)
mouseEntered(MouseEvent e)
mouseExited(MouseEvent e)
MouseMotionListener mouseDragged(MouseMotionEvent e)
mouseMoved(MouseMotionEvent e)
KeyListener keyTyped(KeyEvent e)
keyPressed(KeyEvent e)
keyReleased(KeyEvent e)
WindowListener windowOpened(WindowEvent e)
windowClosed(WindowEvent e)
windowActivated(WindowEvent e)
etc.
D. Componenta FileDialog
Clasa FileDialog este o clasă derivată din clasa Dialog, iar aceasta din urmă derivată din clasa
Window. FileDialog este aşadar o fereastră, fereastră utilizată pentru selecţia unui fişier. Aceasta
afişează un arbore ce reprezintă structura ierarhică a directoarelor şi fişierelor şi permite utilizato-
rului căutarea în această structură şi selecţia unui fişier.
Există două tipuri de ferestre FileDialog: fereastră de tipul load şi una de tipul save. Primul
tip permite doar selecţia unui fişier existent, pe când al doilea tip oferă şi posibilitatea creării unui
fişier nou. O dată un fişier selectat, fereastra se închide automat.
5
Pentru a şti mai multe despre această clasă se recomandă citirea API-ului.
Clasa MenuBar este utilizată pentru a crea o bară de meniuri. Această bară de meniuri poate
fi asociată doar unei ferestre grafice de tipul Frame utilizând metoda setMenuBar(MeniuBar mb)
a clasei Frame. O bară de meniuri este utilizată ca şi cadru în care se adaugă componente de tip
Menu. API-ul clasei se află aici.
Clasa MenuItem reprezintă clasa ce implementeză un meniu. La selecţia unui meniu acesta
generează un eveniment de tipul ActionEvent care poate fi preluat de un handler de tipul Action-
Listener. API-ul clasei se află aici.
Clasa Menu este derivată din MenuItem şi este componenta ce oferă posibilitatea creării unei
structuri verticale de meniuri. În plus faţă de clasa MenuItem, clasa Menu poate crea o componentă
cadru în care se pot adăug alte meniuri (componente de tip MenuItem). API-ul clasei se află aici.
Clasa MenuShortcut nu reprezintă o componentă grafică, dar este corelată lucrului cu me-
niuri. Aceasta este utilizată pentru a asocia unei componente de tip MenuItem o combinaţie de
taste. API-ul clasei se află aici.
A. Evenimentul ActionEvent
Componenta Button creează imaginea unui buton asupra căruia se poate acţiona prin apăsare
(cu ajutorul mouse-ului sau a tastaturii). La ”apăsarea” acestui tip de componentă se va genera un
eveniment de tipul ActionEvent care poate fi tratat de programator printr-un handler înregistrat
la această componentă. Handler-ul în acest caz este reprezentat de clasa MyButtonListener.
După instanţierea unui obiect de acest tip, programatorul trebuie să asocieze respectivul obiect
instanţiat cu componenta Button (addActionListener()). Observaţi că înaintea acestui pas, com-
ponentei Button i s-a setat un şir care va fi înscris în obiectul eveniment de tip ActionEvent ce se
generează când se apasă butonul. Acest lucru a fost realizat prin apelarea metodei setActionCom-
mand().
1 import j a v a . awt . ∗ ;
6
2 import j a v a . awt . e v e n t . A c t i o n L i s t e n e r ;
3
4 public c l a s s T e s t B u t t o n {
5
6 public s t a t i c void main ( S t r i n g [ ] args ) {
7 Frame f = new Frame ( " F e r e a s t r a ␣ Buton " ) ;
8 f . s e t L a y o u t (new FlowLayout ( ) ) ;
9
10 Button b = new Button ( " B o n j o u r " ) ;
11 f . add ( b ) ;
12 b . setActionCommand ( " B o n j o u r " ) ;
13
14 ActionListener a c t i o n L i s t e n e r = new M y B u t t o n L i s t e n e r ( ) ;
15 b . addActionListener ( actionListener ) ;
16
17 b = new Button ( " Good␣Day " ) ;
18 f . add ( b ) ;
19 b . addActionListener ( actionListener ) ;
20
21 b = new Button ( " A u r e v o i r " ) ;
22 f . add ( b ) ;
23 b . setActionCommand ( " E x i t " ) ;
24 b . addActionListener ( actionListener ) ;
25
26 f . pack ( ) ;
27 f . s e t V i s i b l e ( true ) ;
28 }
29 }
Pentru crearea handler-ului sau delegatului acestui eveniment, programatorul trebuie să imple-
menteze interfaţa ActionListener într-o clasă (MyButtonListener). Metoda ce trebuie suprascrisă
în acest caz este actionPerformed(). De asemenea, observaţi folosirea metodei getActionCommand
care returnează informaţia setată în clasa TestButton.
1 import j a v a . awt . e v e n t . ∗ ;
2
3 public c l a s s M y B u t t o n L i s t e n e r implements A c t i o n L i s t e n e r {
4 public void a c t i o n P e r f o r m e d ( A c t i o n E v e n t a e ) {
5 String s = a e . getActionCommand ( ) ;
6 if ( s . equals ( " Exit " ) ) {
7 System . e x i t ( 0 ) ;
8 } else if ( s . e q u a l s ( " Bonjour " ) ) {
9 System . o u t . p r i n t l n ( " Good␣ Morning " ) ;
10 } else {
11 System . o u t . p r i n t l n ( s + " ␣ c l i c k e d " ) ;
12 }
13 }
14 }
7
B. Evenimentul KeyEvent
Clasa următoare creeză o etichetă şi o componentă de tip text pe care le adaugă într-o fereastră.
La apasarea oricărei taste se declansează un eveniment de tipul KeyEvent. Evenimentul este
tratat de către handler-ul MyKeyListener şi a fost asociat componentei de tip text prin intermediul
metodei addKeyListener().
1 import j a v a . awt . ∗ ;
2 import j a v a . awt . e v e n t . K e y L i s t e n e r ;
3
4 public c l a s s TestKey {
5
6 public s t a t i c void main ( S t r i n g [ ] args ) {
7 Frame f = new Frame ( " F e r e a s t r a ␣ keyEvent " ) ;
8
9 L a b e l l a b e l = new L a b e l ( " S c r i e : ␣ " ) ;
10 TextField t x t F i e l d = new T e x t F i e l d ( 2 0 ) ;
11 KeyListener k e y L i s t e n e r = new MyKeyListener ( ) ;
12 t x t F i e l d . addKeyListener ( keyListener ) ;
13
14 f . add ( t x t F i e l d , B o r d e r L a y o u t .CENTER) ;
15 f . add ( l a b e l , B o r d e r L a y o u t .NORTH) ;
16
17 f . pack ( ) ;
18 f . s e t V i s i b l e ( true ) ;
19 }
20 }
Întrucât handler-ul implementează interfaţa KeyListener trebuie să-i suprascrie toate metodele.
S-a scris cod doar pentru metoda keyPressed() care se va apela doar în momentul apăsării unei
taste.
1 import j a v a . awt . e v e n t . ∗ ;
2
3 public c l a s s MyKeyListener implements K e y L i s t e n e r {
4
5 @Ove rrid e
6 public void k e y P r e s s e d ( KeyEvent keyEvent ) {
7 char i = keyEvent . getKeyChar ( ) ;
8 String s t r = Character . toString ( i ) ;
9 System . o u t . p r i n t l n ( " Key␣ p r e s s e d : ␣ "+ s t r ) ;
10
11 }
12
13 @Ove rrid e
14 public void k e y R e l e a s e d ( KeyEvent a r g 0 ) {}
15 @Ove rrid e
16 public void keyTyped ( KeyEvent a r g 0 ) {}
17 }
8
C. Evenimentul MouseEvent
Exemplul de mai jos crează două etichete şi un buton. La apăsarea butonului se va afişa în
consolă suma numerelor conţinute de etichete.
1 import j a v a . awt . ∗ ;
2 import j a v a . awt . e v e n t . ∗ ;
3
4 public c l a s s T e s t M o u s e C l i c k {
5 public s t a t i c void main ( S t r i n g [ ] args ) {
6 Frame f = new Frame ( " F e r e a s t r a ␣ mouse ␣ c l i c k " ) ;
7
8 L a b e l l a b e l Y = new L a b e l ( " 2 " ) ;
9 f . add ( l a b e l Y , B o r d e r L a y o u t .NORTH) ;
10 L a b e l l a b e l X = new L a b e l ( " 1 " ) ;
11 f . add ( l a b e l X , B o r d e r L a y o u t .CENTER) ;
12
13 Button b u t t o n = new Button ( " C l i c k ␣Me" ) ;
14 M o u s e L i s t e n e r m o u s e L i s t e n e r = new MyMouseListener ( l a b e l X , labelY ) ;
15 button . addMouseListener ( mouseListener ) ;
16 f . add ( button , B o r d e r L a y o u t .SOUTH) ;
17
18 f . pack ( ) ;
19 f . s e t V i s i b l e ( true ) ;
20 }
21 }
9
23 @Ove rrid e
24 public void m o u s e P r e s s e d ( MouseEvent a r g 0 ) {}
25 @Ove rrid e
26 public void m o u s e R e l e a s e d ( MouseEvent a r g 0 ) {}
27 }
D. Componenta FileDialog
10
E. Componente AWT de lucru cu meniuri
Clasa de mai jos realizează o bara de meniuri care conţine elementele următoare: File cu sub-
meniul format din: Open, Exit şi Edit cu submeniul format din Undo. Atât Exit cât şi Undo au şi
un shortcut creat cu clasa MenuShortcut. Explicaţiile suplimentare le aveţi trecute în comentariu.
1 import j a v a . awt . ∗ ;
2 import j a v a . awt . e v e n t . ∗ ;
3
4 public c l a s s TestMenu {
5 public s t a t i c void main ( S t r i n g [ ] args ) {
6 Frame f r a m e = new Frame ( " Meniu " ) ;
7 // s e seteaza dimendiunea ferestrei
8 frame . s e t S i z e ( 1 0 0 , 100) ;
9
10 // s−a c r e a t si s−a a d a u g a t o b a r a de m e n i u r i in fereastra
11 MenuBar myMenuBar = new MenuBar ( ) ;
12 f r a m e . setMenuBar ( myMenuBar ) ;
13
14 // s e c r e e a z a componente Menu c a r e s e adauga i n b a r a de m e n i u r i
15 Menu myFileMenu = new Menu ( " F i l e " ) ;
16 Menu myEditMenu = new Menu ( " E d i t " ) ;
17 myMenuBar . add ( myFileMenu ) ;
18 myMenuBar . add ( myEditMenu ) ;
19
20 // s e creeaza o b i e c t e de t i p u l MenuItem
21 MenuItem myFileOpenMenuItem = new MenuItem ( " Open . . . " ) ;
22 /∗ s e foloseste clasa MenuShortcut p t crearea unei c o m b i n a t i i de t a s t e pt a c c e s a r e a
23 c o m p o n e n t e i MenuItem E x i t ∗/
24 MenuItem myFileExitMenuItem = new MenuItem ( " E x i t " , new MenuShortcut (
25 KeyEvent .VK_X) ) ;
26 MenuItem myEditUndoMenuItem = new MenuItem ( " Undo " , new MenuShortcut (
27 KeyEvent .VK_Z) ) ;
28
29 // s e adauga fiecare componente MenuItem i n componenta Menu c o r e s p u n z a t o a r e
30 myFileMenu . add ( myFileOpenMenuItem ) ;
31 myFileMenu . a d d S e p a r a t o r ( ) ;
32 myFileMenu . add ( myFileExitMenuItem ) ;
33 myEditMenu . add ( myEditUndoMenuItem ) ;
34
35 // s e seteaza informatiile ce vor fi transmise h a n d l e r −u l u i o d a t a cu d e c l a n s a r e a evenimentului
36 myFileOpenMenuItem . setActionCommand ( " open " ) ;
37 myFileExitMenuItem . setActionCommand ( " e x i t " ) ;
38 myEditUndoMenuItem . setActionCommand ( " undo " ) ;
39
40 // s e asociaza componentele grafice cu h a n d l e r −u l MyActionListener
41 ActionListener a c t i o n L i s t n e r = new M y A c t i o n L i s t e n e r ( ) ;
42 myFileOpenMenuItem . a d d A c t i o n L i s t e n e r ( a c t i o n L i s t n e r ) ;
43 myFileExitMenuItem . a d d A c t i o n L i s t e n e r ( a c t i o n L i s t n e r ) ;
44 myEditUndoMenuItem . a d d A c t i o n L i s t e n e r ( a c t i o n L i s t n e r ) ;
45
46 f r a m e . s e t V i s i b l e ( true ) ;
47 }
48 }
11
Clasa handler MyActionListener :
1 import j a v a . awt . e v e n t . ∗ ;
2
3 public c l a s s M y A c t i o n L i s t e n e r implements A c t i o n L i s t e n e r {
4
5 @Ove rrid e
6 public void a c t i o n P e r f o r m e d ( A c t i o n E v e n t e ) {
7 S t r i n g cmd = e . getActionCommand ( ) ;
8 if ( cmd . e q u a l s ( " open " ) ) {
9 System . o u t . p r i n t l n ( " open " ) ;
10 } else if ( cmd . e q u a l s ( " e x i t " ) ) {
11 System . e x i t ( 0 ) ;
12 } else if ( cmd . e q u a l s ( " undo " ) ) {
13 System . o u t . p r i n t l n ( " undo " ) ;
14 }
15 }
16 }
III. TEMĂ
12
Laborator 12:
Interfeţe grafice în Java
Componente Swing
11 decembrie 2011
I. NOŢIUNI TEORETICE
Swing este o librărie a limbajului Java, librărie ce este considerată o extensie a lui AWT. Swing
conţine componente noi şi îmbunătăţite care sporesc funcţionalitatea şi înfăţişarea GUI-ului în
Java. Pachetul din care vom lua componentele necesare se numeşte javax.swing.
Câteva dintre caracteristicile care au fost adăugate în acest pachet sunt următoarele:
• S-au introdus componente diverse cum ar fi: tabele, arbori, slider-e, bare de progres, com-
ponente text;
• componentele Swing au tooltip-uri plasate deasupra lor. Un tooltip este o fereastră de tipul
popup care apare temporar deasupra unei componente atunci când cursorul mouse-ului se
află pe componenta respectivă. Acestea sunt utilizate pentru a oferi mai multe informaţii
despre componenta în cauză.
Priviţi în imaginea următoare relaţia dintre clasele pachetului awt şi clasele pachetului swing:
2
Având în vedere faptul că librăria Swing a fost construită peste AWT, paşii ce trebuie urmaţi
pentru a realiza o aplicaţie grafică în Java rămân aceiaşi:
• Crearea unei suprafeţe de afişare pe care vor fi aşezate componentele grafice (butoane, con-
troale de editare, texte, etc);
• Definirea unor acţiuni care trebuie să se execute în momentul când utilizatorul interacţionează
cu obiectele grafice ale aplicaţiei;
3
B. Componente meniu în Swing
Bara de meniu poate fi creată cu ajutorul clasei JMenuBar care permite adăugarea compo-
nentelor de tipul JMenu pentru a construi meniul propriu-zis.
JMenu este o fereastră popup care conţine componente JMenuItem şi care este afişată atunci
când utilizatorul selectează o componentă JMenuBar. În plus, o componentă JMenu poate conţine
JSeparator.
Clasa JMenuItem realizează de fapt un buton din lista care se afişează utilizatorului atunci
când acesta selectează o componentă JMenu. Clasele sale copil sunt: JCheckBoxMenuItem, JMenu,
JRadioButtonMenuItem. De ce şi JMenu? Pentru că un JMenu poate conţine ca JMenuItem un
submeniu. Nu consider necesar explicarea componentelor JCheckBoxMenuItem, JRadioButtonMe-
nuItem. Urmăriţi exemplul prezentat în secţiunea II D.
A. Componenta JLabel
Exemplul de mai jos creează o multitudine de etichete Swing, aranjându-le în moduri diferite.
Ce se poate observa este că, spre deosebire de etichetele AWT, cele Swing pot introduce şi imagini
pe lângă textul propriu-zis. De asemenea, se vor folosi aceiaşi gestionari de poziţie din pachetul
AWT. În acest caz avem FlowLayout.
Imaginile se vor adăuga cu ajutorul clasei ImageIcon al cărei constructor conţine ca şi parametru
un String ce reprezintă calea către imaginea dorită.
Metoda makeLabel() returnează un obiect JLabel, obiect instanţiat cu şirul de caractere ”Smile”
concatenat cu numărul etichetei, iar al doilea parametru reprezintă obiectul imagine. Tot în metoda
makeLabel se setează poziţia şirului de caractere pe verticală şi pe orizontală cu ajutorul unor
numere întregi primite ca parametru. Aceste numere întregi sunt de fapt constante ale clasei
JLabel.
1 import j a v a . awt . ∗ ;
2 import j a v a x . s w i n g . ∗ ;
3
4 public c l a s s LableExample {
5 public s t a t i c Icon i c o n = new I m a g e I c o n ( " r e s u r s e / s m i l e . g i f " ) ;
6
7 public s t a t i c void main ( S t r i n g [ ] args ) {
4
8 JFrame f r a m e = new JFrame ( " L a b e l ␣ Example " ) ;
9 frame . s e t S i z e ( 3 5 0 , 200) ;
10 f r a m e . s e t L a y o u t (new FlowLayout ( ) ) ;
11
12 JLabel [ ] l a b e l s = new J L a b e l [ 9 ] ;
13 l a b e l s [ 0 ] = makeLabel ( J L a b e l . TOP, J L a b e l . LEFT, 0) ;
14 l a b e l s [ 1 ] = makeLabel ( J L a b e l . TOP, J L a b e l .CENTER, 1) ;
15 l a b e l s [ 2 ] = makeLabel ( J L a b e l . TOP, J L a b e l . RIGHT, 2) ;
16 l a b e l s [ 3 ] = makeLabel ( J L a b e l .CENTER, J L a b e l . LEFT, 3) ;
17 l a b e l s [ 4 ] = makeLabel ( J L a b e l .CENTER, J L a b e l .CENTER, 4) ;
18 l a b e l s [ 5 ] = makeLabel ( J L a b e l .CENTER, J L a b e l . RIGHT, 5) ;
19 l a b e l s [ 6 ] = makeLabel ( J L a b e l .BOTTOM, J L a b e l . LEFT, 6) ;
20 l a b e l s [ 7 ] = makeLabel ( J L a b e l .BOTTOM, J L a b e l .CENTER, 7) ;
21 l a b e l s [ 8 ] = makeLabel ( J L a b e l .BOTTOM, J L a b e l . RIGHT, 8) ;
22
23 // d e z a c t i v e a z a eticheta 0
24 l a b e l s [ 0 ] . setEnabled ( false ) ;
25
26 // s e dezactiveaza eticheta 1. In a c e s t caz , se seteaza alta imagine
27 l a b e l s [ 1 ] . setEnabled ( false ) ;
28 l a b e l s [ 1 ] . s e t D i s a b l e d I c o n (new I m a g e I c o n ( " r e s u r s e / no . g i f " ) ) ;
29
30 // m o d i f i c a distanta intre imagine si text la etichetele 2 si 3
31 l a b e l s [ 2 ] . setIconTextGap ( 1 5 ) ;
32 l a b e l s [ 3 ] . setIconTextGap ( 0 ) ;
33
34 // s e adauga etichetele in fereastra
35 for ( int i = 0; i < 9; i ++) {
36 f r a m e . add ( l a b e l s [ i ] ) ;
37 }
38
39 f r a m e . s e t V i s i b l e ( true ) ;
40 }
41
42 public s t a t i c J L a b e l makeLabel ( i n t v e r t , int horiz , int contor ) {
43 JLabel l = new J L a b e l ( " S m i l e ␣ " + c o n t o r , icon , S w i n g C o n s t a n t s .CENTER) ;
44 l . setVerticalTextPosition ( vert ) ;
45 l . setHorizontalTextPosition ( horiz ) ;
46 l . setBorder ( BorderFactory . createLineBorder ( Color . blue ) ) ;
47 return l;
48 }
49 }
Componentele text au fost îmbunătăţite în pachetul Swing. Dacă în pachetul AWT nu era
permisă crearea unui câmp text în care să se seteze poziţionarea scrisului, iată că JTextField face
posibil acest lucru (linia de cod 15 şi 19).
1 import j a v a x . s w i n g . ∗ ;
2 import j a v a . awt . ∗ ;
3
4 public c l a s s T e x t F i e l d E x a m p l e {
5
5
6 public s t a t i c void main ( S t r i n g [ ] args ) {
7 JFrame f r a m e = new JFrame ( " T e x t F i e l d ␣ Example " ) ;
8
9 J L a b e l l a s t N a m e L a b e l = new J L a b e l ( " L a s t ␣Name " , S w i n g C o n s t a n t s . LEFT) ;
10 J L a b e l f i r s t N a m e L a b e l = new J L a b e l ( " F i r s t ␣Name " , S w i n g C o n s t a n t s .CENTER) ;
11 J L a b e l p a s s w o r d L a b e l = new J L a b e l ( " Password " , S w i n g C o n s t a n t s . RIGHT) ;
12
13 J T e x t F i e l d lastNameTF = new J T e x t F i e l d ( 1 5 ) ;
14 lastNameTF . s e t F o n t (new Font ( " b o l d " , Font . BOLD, 12) ) ;
15 lastNameTF . s e t H o r i z o n t a l A l i g n m e n t ( J T e x t F i e l d . RIGHT) ;
16
17 J T e x t F i e l d firstNameTF = new J T e x t F i e l d ( ) ;
18 firstNameTF . s e t F o n t (new Font ( " i t a l i c " , Font . ITALIC , 13) ) ;
19 firstNameTF . s e t H o r i z o n t a l A l i g n m e n t ( J T e x t F i e l d .CENTER) ;
20
21 J P a s s w o r d F i e l d passwordTF = new J P a s s w o r d F i e l d ( ) ;
22
23 J P a n e l p = new J P a n e l ( ) ;
24 p . s e t L a y o u t (new G ri dL ay ou t ( 3 , 1) ) ;
25
26 p . add ( l a s t N a m e L a b e l ) ;
27 p . add ( lastNameTF ) ;
28 p . add ( f i r s t N a m e L a b e l ) ;
29 p . add ( firstNameTF ) ;
30 p . add ( p a s s w o r d L a b e l ) ;
31 p . add ( passwordTF ) ;
32
33 f r a m e . add ( p ) ;
34
35 f r a m e . pack ( ) ;
36 f r a m e . s e t V i s i b l e ( true ) ;
37 }
38 }
C. Componenta JButton
Exemplul prezentat mai jos afişează într-o fereastră trei butoane. Primul conţine doar text, cel
de-al doilea conţine doar o imagine, iar cel de-al treilea conţine şi text şi o imagine. Toate cele trei
butoane au fost create cu ajutorul clasei JButton.
Mai mult, numele apărut pe cel de-al treilea buton are subliniată prima literă, iar la combinaţia
de taste ALT şi prima literă butonul este selectat. Acest lucru este posibil datorită metodei setM-
nemonic() a clasei JButton care primeşte ca parametru prima literă a numelui de pe buton. Astfel
butonul răspunde atât la click-urile de mouse cât şi la combinaţia ALT+prima literă.
Observaţi ce se afişează atunci când plasaţi mouse-ul deasupra butoanelor. Depistaţi liniile de
cod care realizează acest lucru.
6
1 import j a v a . awt . ∗ ;
2 import j a v a x . s w i n g . ∗ ;
3
4 public c l a s s ButtonExample {
5
6 public s t a t i c void main ( S t r i n g args [ ] ) {
7 JFrame f r a m e = new JFrame ( " JButton ␣ Example " ) ;
8 frame . s e t S i z e ( 3 0 0 , 100) ;
9
10 J P a n e l p a n e l = new J P a n e l ( ) ;
11 p a n e l . s e t L a y o u t (new FlowLayout ( FlowLayout . LEFT) ) ;
12
13 JButton c u t B u t t o n = new JButton ( " Cut " ) ;
14 c u t B u t t o n . s e t T o o l T i p T e x t ( " T o o l t i p : ␣ buton ␣ c u t " ) ;
15 JButton copyButton = new JButton (new I m a g e I c o n ( " r e s u r s e / copy . g i f " ) ) ;
16 copyButton . s e t T o o l T i p T e x t ( " T o o l t i p : ␣ buton ␣ copy " ) ;
17
18 S t r i n g buttonName = " P a s t e " ;
19 String icon = " resurse / paste . g i f " ;
20 f i n a l char key = buttonName . c h a r A t ( 0 ) ;
21 JButton p a s t e B u t t o n = new JButton ( buttonName , new I m a g e I c o n ( i c o n ) ) ;
22 p a s t e B u t t o n . setMnemonic ( key ) ;
23 p a s t e B u t t o n . s e t T o o l T i p T e x t ( " T o o l t i p : ␣ buton ␣ p a s t e " ) ;
24
25 p a n e l . add ( c u t B u t t o n ) ;
26 p a n e l . add ( copyButton ) ;
27 p a n e l . add ( p a s t e B u t t o n ) ;
28
29 f r a m e . add ( p a n e l , B o r d e r L a y o u t .NORTH) ;
30
31 f r a m e . s e t V i s i b l e ( true ) ;
32 }
33 }
D. Componente Meniu
Clasa MenuExample afişează o fereastră ce conţine o bară de meniu cu două componente meniu.
Prima componentă meniu mai conţine, însă, alte obiecte meniu şi un submeniu.
În acest exemplu, meniul este afişat pe verticală datorită metodei setLayout() care este apelată
de către componenta JMenuBar cu parametrul GridLayout în linia de cod 19.
Observaţi că asemenea componentelor JButton şi JLabel, şi JMenuItem poate conţine imagini.
De asemenea, meniul prezintă separatori între componentele diferite ale unui JMenu (liniile de cod
36, 50 şi 58).
1 import j a v a . awt . G ri dL ay ou t ;
2 import j a v a x . s w i n g . ∗ ;
3
4 public c l a s s MenuExample {
5
7
6 public s t a t i c void main ( S t r i n g s []) {
7 JFrame f r a m e ;
8 JMenuBar menuBar ;
9 JMenu menu , submenu ;
10 JMenuItem menuItem ;
11 JRadioButtonMenuItem rbMenuItem ;
12 JCheckBoxMenuItem cbMenuItem ;
13
14 f r a m e = new JFrame ( " Menu␣ example " ) ;
15 frame . s e t S i z e ( 2 0 0 , 200) ;
16
17 // s e c r e e a z a b a r a de meniu
18 menuBar = new JMenuBar ( ) ;
19 menuBar . s e t L a y o u t (new G ri dL ay ou t ( 2 , 1 ) ) ;
20
21 // s e construieste p r i m u l meniu
22 menu = new JMenu ( "Un␣ Meniu " ) ;
23 menuBar . add ( menu ) ;
24
25 // un grup de componente JMenuItems
26 menuItem = new JMenuItem ( " Doar ␣ t e x t " ) ;
27 menu . add ( menuItem ) ;
28
29 menuItem = new JMenuItem ( " S i ␣ t e x t ␣ s i ␣ i m a g i n e " , new I m a g e I c o n ( " r e s u r s e / r o l l i n g . g i f " ) ) ;
30 menu . add ( menuItem ) ;
31
32 menuItem = new JMenuItem (new I m a g e I c o n ( " r e s u r s e / r o l l i n g . g i f " ) ) ;
33 menu . add ( menuItem ) ;
34
35 // un grup de componente r a d i o −buton
36 menu . a d d S e p a r a t o r ( ) ; // adauga l a sfarsitul g r u p u l u i de componente a n t e r i o a r e o linie orizontala ,
considerata separator
37 ButtonGroup g r o u p = new ButtonGroup ( ) ;
38
39 rbMenuItem = new JRadioButtonMenuItem ( " o ␣ componenta ␣ r a d i o −b u t t o n " ) ;
40 rbMenuItem . s e t S e l e c t e d ( true ) ;
41 // b u t o n u l radio s e adauga g r u p u l u i si meniului
42 g r o u p . add ( rbMenuItem ) ;
43 menu . add ( rbMenuItem ) ;
44
45 rbMenuItem = new JRadioButtonMenuItem ( " a l t a ␣ componenta ␣ r a d i o −buton " ) ;
46 g r o u p . add ( rbMenuItem ) ;
47 menu . add ( rbMenuItem ) ;
48
49 // un grup de componente c h e c k−box
50 menu . a d d S e p a r a t o r ( ) ;
51 cbMenuItem = new JCheckBoxMenuItem ( " o ␣ componenta ␣ c h e c k−box " ) ;
52 menu . add ( cbMenuItem ) ;
53
54 cbMenuItem = new JCheckBoxMenuItem ( " a l t a ␣ componenta ␣ c h e c k−box " ) ;
55 menu . add ( cbMenuItem ) ;
56
57 // un submeniu
58 menu . a d d S e p a r a t o r ( ) ;
59 submenu = new JMenu ( " Submeniu " ) ;
60
61 menuItem = new JMenuItem ( " a l t ␣ o b i e c t ␣ i n ␣ submeniu " ) ;
62 submenu . add ( menuItem ) ;
63
8
64 menu . add ( submenu ) ;
65
66 // s e construieste al d o i l e a meniu c e s e adauga i n b a r a de meniu
67 menu = new JMenu ( " A l t ␣ Meniu " ) ;
68 menuItem = new JMenuItem ( " o b i e c t ␣ i n ␣ A l t ␣ Meniu " ) ;
69 menu . add ( menuItem ) ;
70 menuBar . add ( menu ) ;
71
72 // s e ataseaza ferestrei b a r a de meniu
73 f r a m e . setJMenuBar ( menuBar ) ;
74
75 f r a m e . pack ( ) ;
76 f r a m e . s e t V i s i b l e ( true ) ;
77 }
78 }
III. TEMĂ
9
Laborator Nr. 13:
Evenimente generate de Componente SWING
Aşa cum este precizat şi ı̂n Laboratorul 11, un eveniment reprezintă o instanţă a unei clase Java, instanţă
care conţine o serie de informaţii despre actiunea utilizatorului asupra unei componente grafice. Un ,,eveni-
ment” poate fi ı̂nţeles, aici, ca un eveniment asincron, independent de evoluţia programului şi al cărui moment
de producere nu poate fi prevăzut la scrierea codului. Evenimentele cele mai des ı̂ntâlnite sunt:
• apăsarea unei taste;
• actionarea unui buton de mouse;
• deplasarea cursorului peste anumite zone;
Pentru gestionarea unui eveniment sunt implicaţi trei participanţi:
• sursa evenimentului - obiectul a cărui stare se modifică;
• obiectul eveniment - reprezintă evenimentul ı̂n sine;
• event listener - obiectul ce trebuie anunţat despre modificarea ce se produce;
La fel ca şi ı̂n AWT, şi ı̂n SWING sunt folosiţi delegaţi - handleri pentru prelucrarea informaţiei provenită
de la eveniment, precum şi ascultători - listeneri pentru tratarea evenimentelor. Ceea ce se ı̂ntâmplă la
apariţia unui eveniment este ilustrat ı̂n figura de mai jos:
Se apelează un ascultător atunci când utilizatorul interacţionează cu interfaţa, ceea ce provoacă un eveni-
ment. Deşi evenimentele provin de obicei din interfaţa utilizator, ele pot avea şi alte surse: conexiunea la
internet, window manager, timer, etc. În funcţie de ce anume a declanşat apariţia unui eveniment există
interfeţe care se folosesc pentru prelucrarea sa:
2
Asocierea dintre componentă şi handler se face cu ajutorul interfeţelor Listener astfel:
Pentru prelucrarea evenimentelor generate de butoane trebuie folosit un handler care să implementeze
interfaţa Listener corespunzătoare acţiunii ce se monitorizează.
A. Interfaţa ActionListener
Evenimentele care se prelucrează cu ajutorul metodelor suprascrise din această interfaţă sunt evenimentele
care se generează la folosirea butonelor, a meniurilor etc. Pentru prelucrarea acestor evenimente trebuie să
se utilizeze o clasă handler (aici HandlerButoane) ce implementează interfaţa ActionListener, şi suprascrie
metoda actionPerformed(ActionEvent e).
1 import javax . swing . ∗ ;
2 import javax . swing . border . ∗ ;
3
3 import j a v a . awt . ∗ ;
4 import j a v a . awt . e v e n t . ∗ ;
5
6 class H a n d l e r B u t o a n e implements ActionListener {
7
8 private int n r C l i c k = 0 ;
9 private int i n d i c e C u l o a r e = 0 ;
10 f i n a l p r i v a t e C o l o r c u l o r i [ ] = { C o l o r . LIGHT GRAY , C o l o r . RED, C o l o r .ORANGE, C o l o r . PINK } ;
11
12 public void actionPerformed ( ActionEvent e) {
13
14 JButton butonApasat = ( JButton ) e . g e t S o u r c e ( ) ;
15
16 // i n functie de denumirea evenimentului generat de buton se implementeaza o anumita actiune :
17
18 // p e n t r u b u t o n u l ” c o n t o r ”
19 i f ( b u t o n A p a s a t . getActionCommand ( ) . e q u a l s ( ” c o n t o r ” ) ) {
20 n r C l i c k ++;
21 butonApasat . s e t T e x t ( ” Apasat : ” + n r C l i c k ) ;
22 }
23
24 // p e n t r u b u t o n u l ” c u l o a r e ”
25 i f ( b u t o n A p a s a t . getActionCommand ( ) . e q u a l s ( ” c u l o a r e ” ) ) {
26 i n d i c e C u l o a r e ++;
27 i f ( i n d i c e C u l o a r e == c u l o r i . l e n g t h )
28 indiceCuloare = 0;
29 butonApasat . setBackground ( c u l o r i [ i n d i c e C u l o a r e ] ) ;
30 }
31
32 // p e n t r u b u t o n u l ” e x i t ”
33 i f ( b u t o n A p a s a t . getActionCommand ( ) . e q u a l s ( ” e x i t ” ) ) {
34 System . e x i t ( 0 ) ;
35 }
36 }
37 }
B. Interfaţa KeyListener
Pentru evenimentele generate cu ajutorul tastaturii trebuie să se utilizeze o clasă han-
dler (aici KeyHandler) ce implementează interfaţa KeyListener, şi suprascrie metodele
keyPressed(), keyReleased(), keyTyped(). Nu este obligatoriu să se implementeze toate metodele dacă
aplicaţia nu necesită acest lucru.
1 import j a v a . awt . e v e n t . ∗ ;
2
3 public class K e y H a n d l e r implements KeyListener {
4
4
5 @Override
6 p u b l i c void k e y P r e s s e d ( KeyEvent k e y E v e n t ) {
7 char i = k e y E v e n t . getKeyChar ( ) ;
8 String s t r = Character . toString ( i ) ;
9 System . o u t . p r i n t l n ( ”Key pressed : ”+ s t r ) ;
10
11 }
12
13 @Override
14 p u b l i c void k e y R e l e a s e d ( KeyEvent a r g 0 ) {}
15 @Override
16 p u b l i c void keyTyped ( KeyEvent a r g 0 ) {}
17 }
1 mport j a v a . awt . ∗ ;
2 import j a v a x . s w i n g . ∗ ;
3
4 public class TestKey {
5
6 p u b l i c s t a t i c void main ( S t r i n g [ ] args ) {
7 JFrame f = new JFrame ( ” F e r e a s t r a keyEvent ” ) ;
8 f . s e t L a y o u t (new FlowLayout ( ) ) ;
9
10 J L a b e l l a b e l = new J L a b e l ( ” S c r i e : ” ) ;
11 J T e x t F i e l d t x t F i e l d = new J T e x t F i e l d (20) ;
12
13
14 K e y H a n d l e r keyH = new K e y h a n d l e r ( ) ;
15 t x t F i e l d . a d d K e y L i s t e n e r ( keyH ) ;
16
17 f . add ( l a b e l ) ;
18 f . add ( t x t F i e l d ) ;
19
20
21 f . pack ( ) ;
22 f . setVisible ( true ) ;
23 }
24 }
C. Interfaţa MouseListener
Evenimentele generate de mouse, clasa handler trebuie să implementeze interfaţa MouseListener şi să
suprascrie metodele: mouseClicked(),mouseEntered(), mouseExited(), mousePressed(), mouseReleased().
la fel ca şi la evenimentele pentru taste, dacă nu se cere utilizarea tuturor metodelor, nu este necesară
implemetarea lor.
1
2 import j a v a . awt . e v e n t . ∗ ;
3 import javax . swing . ∗ ;
4
5
6 public class M y M o u s e L i s t e n e r implements MouseListener {
7
8 JLabel labelX , labelY ;
9 public MyKeyListener ( JLabel x , JLabel y )
10 {
11 this . labelX = x ;
12 this . labelY = y ;
13 }
14
15
16 @Override
17 p u b l i c void m o u s e C l i c k e d ( MouseEvent e ) {
18 int x = I n t e g e r . p a r s e I n t ( labelX . getText ( ) ) ;
19 int y = I n t e g e r . p a r s e I n t ( labelY . getText ( ) ) ;
20 System . o u t . p r i n t l n ( x+” + ”+y+” = ”+(x+y ) ) ;
21
22
23 }
24
25 @Override
26 p u b l i c void m o u s e E n t e r e d ( MouseEvent e ) {
27 // TODO Auto−g e n e r a t e d method s t u b
28
29 }
30
31 @Override
32 p u b l i c void m o u s e E x i t e d ( MouseEvent e ) {
33 // TODO Auto−g e n e r a t e d method s t u b
34
35 }
36
37 @Override
38 p u b l i c void m o u s e P r e s s e d ( MouseEvent e ) {
39 // TODO Auto−g e n e r a t e d method s t u b
40
41 }
42
43 @Override
44 p u b l i c void m o u s e R e l e a s e d ( MouseEvent e ) {
5
45 // TODO Auto−g e n e r a t e d method stub
46
47 }
48
49 }
1 import j a v a . awt . ∗ ;
2 import javax . swing . ∗ ; ;
3
4 p u b l i c c l a s s TestMouse {
5 p u b l i c s t a t i c void main ( S t r i n g [ ] args ) {
6 Frame f = new Frame ( ” F e r e a s t r a mouse click ” ) ;
7
8 J L a b e l l a b e l Y = new J L a b e l ( ” 2 ” ) ;
9 f . add ( l a b e l Y , B o r d e r L a y o u t .NORTH) ;
10 J L a b e l l a b e l X = new J L a b e l ( ” 1 ” ) ;
11 f . add ( l a b e l X , B o r d e r L a y o u t .CENTER) ;
12
13 J B u t t o n b u t t o n = new J B u t t o n ( ” C l i c k Me” ) ;
14 M y M o u s e L i s t e n e r m o u s e L i s t e n e r = new M y M o u s e L i s t e n e r ( labelX , labelY ) ;
15 button . addMouseListener ( mouseListener ) ;
16 f . add ( b u t t o n , B o r d e r L a y o u t . SOUTH) ;
17
18 f . pack ( ) ;
19 f . setVisible ( true ) ;
20 }
21 }
D. Interfaţa WindowListener
Se foloseşte pentru evenimentele care au loc la deschiderea, ı̂nchiderea unei ferestre sau ı̂n momentul ı̂n
care o fereastra este sau nu activă. Spre deosebire de celelalte interfeţe, pentru aceasta trebuie suprascrise
toate metodele:
Metoda Descriere
windowActivated(WindowEvent e) se apelează când fereastra devine activă
windowClosed(WindowEvent e) se apelează la ı̂nchiderea ferestrei
windowClosing(WindowEvent e) se apelează in momentul ı̂n care se ı̂ncearcă ı̂nchiderea ferestrei
windowDeactivated(WindowEvent e) se apelează când fereastra nu mai este activă
windowDeiconified(WindowEvent e) se apelează când fereastra işi modifică starea
din minimize(din taskbar) ı̂n starea normală (pe ecran)
windowIconified(WindowEvent e) se apelează când fereastra işi modifică starea
din starea normală (de pe ecran) ı̂n minimize (ı̂n taskbar)
windowOpened(WindowEvent e) se apelează când fereastra devine vizibilă
În cazul ı̂n care se doresc efectuarea unor operaţii pentru anumite evenimente clasa handler poate extinde
clasa WindowAdapter şi astfel vor putea fi suprascrise doar metodele dorite.
1 import j a v a . awt . ∗ ;
2 import javax . swing . ∗ ;
3
4
5 p u b l i c c l a s s TestWindow {
6 p u b l i c s t a t i c void main ( S t r i n g [ ] args ) {
7
8 JFrame f = new JFrame ( ” t e s t ” ) ;
9 f . s e t S i z e (150 , 150) ;
10
11 f . a d d W i n d o w L i s t e n e r (new MyWindowListener ( ) ) ;
12 f . s e t V i s i b l e ( true ) ;
13 }
14 }
1 import j a v a . awt . ∗ ;
2 import j a v a . awt . e v e n t . ∗ ;
3
4
5 public class MyWindowListener extends WindowAdapter {
6
7 p u b l i c void w i n d o w C l o s i n g ( WindowEvent e v e n t ) {
8 System . o u t . p r i n t l n ( ” Eveniment pe f e r e s t r e ” ) ;
9 System . e x i t ( 0 ) ;
10 }
11 }
6
E. Tratarea evenimentelor pentru meniuri
Tratarea evenimentelor pentru meniuri ı̂n Swing se face ı̂n mod similar cu tratarea evenimentelor pentru
meniuri din AWT.
1 import j a v a . awt . ∗ ;
2 import j a v a . awt . e v e n t . A c t i o n L i s t e n e r ;
3
4 import javax . swing . ∗ ;
5
6 public class TestMeniuri {
7 public s t a t i c void main ( S t r i n g [ ] args ) {
8
9 JFrame f r a m e = new JFrame ( ” Meniu ” );
10
11 frame . setSize (100 , 100) ;
12
13
14 JMenuBar myMenuBar = new JMenuBar ( ) ;
15 myMenuBar . s e t L a y o u t (new G r i d L a y o u t ( 1 , 2 ) ) ;
16 f r a m e . setJMenuBar ( myMenuBar ) ;
17
18
19 JMenu myFileMenu = new JMenu ( ” File ” ) ;
20 JMenu myEditMenu = new JMenu ( ” Edit ” ) ;
21 myMenuBar . add ( myFileMenu ) ;
22 myMenuBar . add ( myEditMenu ) ;
23
24
25 JMenuItem myFileOpenMenuItem = new JMenuItem ( ”Open . . . ” ) ;
26
27 JMenuItem m y F i l e E x i t M e n u I t e m = new JMenuItem ( ” Exit ” ) ;
28 JMenuItem myEditUndoMenuItem = new JMenuItem ( ”Undo” ) ;
29
30
31 myFileMenu . add ( myFileOpenMenuItem ) ;
32 myFileMenu . addSeparator ( ) ;
33 myFileMenu . add ( m y F i l e E x i t M e n u I t e m ) ;
34 myEditMenu . add ( myEditUndoMenuItem ) ;
35
36
37 myFileOpenMenuItem . setActionCommand ( ” open ” ) ;
38 m y F i l e E x i t M e n u I t e m . setActionCommand ( ” e x i t ” ) ;
39 myEditUndoMenuItem . setActionCommand ( ” undo ” ) ;
40
41
42 A c t i o n L i s t e n e r a c t i o n L i s t n e r = new MyMenuListener ( ) ;
43 myFileOpenMenuItem . a d d A c t i o n L i s t e n e r ( a c t i o n L i s t n e r ) ;
44 myFileExitMenuItem . a d d A c t i o n L i s t e n e r ( a c t i o n L i s t n e r ) ;
45 myEditUndoMenuItem . a d d A c t i o n L i s t e n e r ( a c t i o n L i s t n e r ) ;
46
47 frame . setVisible ( true ) ;
48 }
49 }
III. TEMA