Laborator 1:
Introducere în Java
Întocmit de: Adina Neculai
Îndrumător: Asist. Drd. Gabriel Danciu
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.
2. familiar: limbajul Java respectă o mare parte a gramaticii şi a sintaxei de programare
C/C++.
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).
9. adaptat pentru aplicaţii distribuite
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.
C. Dezvoltarea şi execuţia unei aplicaţii Java
Paşii ce trebuie urmaţi pentru a putea crea un program Java sunt următorii:
1. scrierea codului;
2. compilarea;
3. interpretarea şi lansarea în execuţie.
Aceste operaţii sunt prezentate în figura următoare:
Figura 1: Etapele dezvoltării şi execuţiei unei aplicaţii Java stand-alone.
D. Structura unui program Java
1 package main ;
2
3 public c l a s s MyProgram {
4 public s t a t i c void main ( St r ing args [ ] ) {
5 // i n t r u c t i u n i
6 }
7 }
Listing 1: Descriptive Caption Text
• 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.
II. PREZENTAREA LUCRĂRII DE LABORATOR
A. Editarea unei aplicaţii Java
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 HelloWorld {
2 public s t a t i c void main ( St r ing args [ ] ) {
3 System . out . p r i n t l n ( " He l lo ␣World ! ! ! " ) ;
4 }
5 }
Listing 2: Descriptive Caption Text
De reţinut că numele clasei trebuie să coincidă cu numele fişierului a cărui extensie este .java.
B. Compilarea unei aplicaţii 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!!!”.
D. Preluarea parametrilor din linie de comandă
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 Hel loUsers {
2 public s t a t i c void main ( St r ing args [ ] ) {
3 i f ( args . l ength == 0){//daca nu sunt argumente
4 System . out . p r i n t l n ( " I n t r oduc e t i ␣ c e l ␣ putin ␣un␣nume" ) ;
5 }
6 for ( int i =0; i<args . l ength ; i++){
7 System . out . p r i n t l n ( " Hel lo , ␣ "+args [ i ]+ " ! " ) ; // se a f i s e a z a f i e c a r e element din t ab l ou l args
8 }
9 }
10 }
Listing 3: Descriptive Caption Text
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Ă
Editaţi, compilaţi şi lansaţi în execuţie aplicaţiile:
1. HelloWorld din secţiunea IIA;
2. HelloUsers din secţiunea IID.
5
Laborator 2:
Instrucţiuni Java şi lucru cu şiruri de caractere
Întocmit de: Adina Neculai
Îndrumător: Asist. Drd. Gabriel Danciu
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ă;
În execuţia instrucţiunii while, la început, se evaluează expresie_condiţie. Dacă aceasta are
valoarea true atunci se trece la execuţia secvenţă_repetată. Dacă valoarea este de la bun început
false, secvenţa din cadrul buclei nu va mai fi deloc executată. Se observă că şi această instrucţiune
face parte din cele de ciclare cu test iniţial.
3
3. Intrucţiunea do while
Forma generală:
do
secvenţă_repetată
while(expresie_condiţie);
În execuţia instrucţiunii do while, întâi se execută secvenţă_repetată şi abia apoi se evaluează
expresie_condiţie. Astfel, chiar dacă expresia de evaluat este falsă, secvenţă_repetată tot se execută
măcar o dată. De aceea, instrucţiunea do while face parte din cele de ciclare cu test final.
C. Instrucţiuni de salt
Intrucţiunea:
1. break este utilizată pentru întreruperea execuţiei instrucţiunilor de ciclare şi a celor switch;
2. continue poate fi folosită doar în interiorul instrucţiunilor de ciclare forţând trecerea la un
nou ciclu;
3. return este utilizată pentru ieşirea forţată dintr-o metodă.
D. Lucru cu şiruri de caractere
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.
II. PREZENTAREA LUCRĂRII DE LABORATOR
A. Instrucţiuni Java
Codul sursă de mai jos exemplifică modul de utilizare al instrucţiunilor din secţiunile IA, I B,
I C.1 import java . u t i l . Scanner ;
2
3 public c l a s s Tes t In t ru c t i un i {
4 public s t a t i c void main ( St r ing args [ ] ) {
5 Scanner s = new Scanner ( System . in ) ; //cu a j u t o ru l a c e s t e i i n s t r u c t i u n i se c i t e s t e text de l a
ta s t a tu ra
6 System . out . p r i n t l n ( " I n t r oduc e t i ␣un␣numar : ␣ " ) ;
7 int x = s . next Int ( ) ; // in x se va r e t i n e numarul t a s t a t
8 System . out . p r i n t l n ( " Rezu l ta tu l ␣ f u n c t i e i ␣ e s t e : ␣ " + t e s t ( x ) ) ; /∗ se ape leaza metoda t e s t cu parametru x
∗/
9 }
10
11 public s t a t i c int t e s t ( int x ) {
12 int suma = 0 ; // se i n i t i a l i z e a z a v a r i a b i l a suma cu 0
13 for ( int i = 0 ; i < 4 ; i++) {
14 System . out . p r i n t l n ( "Am␣ i n t r a t ␣ in ␣ n i v e l ␣1 " ) ;
15 int j = 0 ;
16 while ( j++ < x) {// i n t a i se e f e c tueaza eva luarea e x p r e s i e i j < x s i abia apoi se incrementeaza
v a r i a b i l a j
17 System . out . p r i n t l n ( "Am␣ i n t r a t ␣ in ␣ n i v e l ␣2 " ) ;
18 System . out . p r i n t l n ( " i=␣ " + i + " ; ␣ j=␣ " + j ) ;
19 switch ( i ) {
20 // in cazu l in care i =0, 1 sau 2 se sa r e l a urmatorul pas s i se ignora r e s t u l i n s t r u c t i u n i l o r
de dupa cont inue din c i c l u l curent ( whi le )
21 case 0 :
22 continue ;
23 case 1 :
24 continue ;
25 case 2 :
26 continue ;
27 case 3 : // in cazu l in care i=3 se a c tua l i z e a z a suma s i apoi se i e s e f o r t a t din switch
28 suma += i+j ;
29 break ;
30 }
31 }
32 System . out . p r i n t l n ( "Am␣ i e s i t ␣ din ␣ n i v e l ␣2 " ) ;
5
33 }
34 System . out . p r i n t l n ( "Am␣ i e s i t ␣ din ␣ n i v e l ␣1 " ) ;
35 return suma ; // se i e s e f o r t a t din metoda t e s t
36 }
37
38 }
B. Lucru cu şiruri de caractere
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 java . u t i l . ∗ ;
2 public c l a s s CheckPassword {
3 public s t a t i c void main ( St r ing args [ ] ) {
4 Scanner s = new Scanner ( System . in ) ;
5 St r ing password = " java " ;
6 St r ing user Input ;
7 System . out . p r i n t l n ( " Care␣e␣ paro la ? " ) ;
8 user Input= s . next ( ) ;
9
10 System . out . p r i n t l n ( "Ai␣ t a s t a t : ␣ " ) ;
11 System . out . p r i n t l n ( user Input ) ;
12 System . out . p r i n t l n ( "Dar␣ paro la ␣ e s t e : ␣ " ) ;
13 System . out . p r i n t l n ( password ) ;
14
15 // i f ( password . equa l s ( user Input ) ) {
16 i f ( password == userInput ){
17 System . out . p r i n t l n ( "Ai␣ t r e cu t ␣mai␣ departe ! " ) ;
18 } e l s e{
19 System . out . p r i n t l n ( "NU␣ a i ␣ t r e cu t ␣mai␣ departe ! " ) ;
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.
Următorul exemplu citeşte de la tastatură un şir de caractere şi înlocuieşte fiecare vocală
întâlnită cu următorul caracter din alfabet. Acesta foloseşte clasa StringBuffer.
6
1 import java . u t i l . Scanner ;
2 public c l a s s ReplaceVowel {
3 public s t a t i c void main ( St r ing args [ ] ) {
4 Scanner s = new Scanner ( System . in ) ;
5 System . out . p r i n t l n ( " I n t r oduc e t i ␣ cuvantul : ␣ " ) ;
6 St r ing word = s . nextLine ( ) ;
7 System . out . p r i n t l n ( " Cuvantul␣ r e z u l t a t ␣ e s t e : ␣ "+replaceVowel (word . toLowerCase ( ) ) ) ;
8 }
9
10 public s t a t i c boolean checkVowel ( char c ) {
11 c = Character . toLowerCase ( c ) ;
12 return ( " ae iou " . indexOf ( c ) >= 0) ; /∗∗ se re turneaza true daca metoda indexOf ap l i c a t a s i r u l u i de
13 ca r a c t e r e " ae iou " impreuna cu parametru c returneaza o va loa re po z i t i v a ∗/
14 }
15
16 public s t a t i c St r ing replaceVowel ( S t r ing word ){
17 S t r i ngBu f f e r sb = new St r i ngBu f f e r (word ) ; /∗∗ v a r i a b i l a sb e s t e i n t i a l i z a t a cu va loarea
18 v a r i a b i l e i word∗/
19 for ( int i =0; i<sb . l ength ( ) ; i++){/∗∗ sb se parcurge ca r a c t e r cu ca r a c t e r ∗/
20 i f ( checkVowel ( sb . charAt ( i ) ) ) {/∗∗ f i e c a r e c a r a c t e r a l l u i sb e s t e v e r i f i c a t daca e s t e voca la ∗/
21 sb . setCharAt ( i , ( char ) ( sb . charAt ( i )+1) ) ; /∗∗ se pune pe p o z i t i a i in sb urmatorul c a r a c t e r
22 din a l f a b e t ∗/
23 }
24 }
25 return sb . t oS t r ing ( ) ;
26 }
27 }
III. TEMĂ
1. Rulaţi programele din secţiunea II.
2. Citiţi un şir de caractere de la tastatură. Folosind intrucţiunea switch, realizaţi un meniu
pentru următoarele cerinţe:
(a) să se afişeze lungimea şirului de caractere;
(b) să se returneze ultima poziţie pe care se întâlneşte caracterul ’a’;
(c) să se numere de câte ori apare în şirul de caractere secvenţa ’abc’;
(d) să se verifce dacă şirul de caractere este palindrom.
(e) să se şteargă toate caracterele de pe poziţiile pare.
Implementaţi cerinţele de la punctele 2a pana la 2e.
7
Laborator 3:
Introducere în Programarea Orientată pe Obiecte
Întocmit de: Adina Neculai
Îndrumător: Asist. Drd. Gabriel Danciu
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
Forma generală a unei metode:
[lista_Modificatori] tip_de_returnat numeMetoda([lista_parametrii])
{
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();
//alte instructiuni constructor
}
}
II. PREZENTAREA LUCRĂRII DE LABORATOR
A. Supraîncărcarea metodelor şi constructorilor
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 Point ( ) {// cons t ruc to r f a r a parametr i
5 // t h i s e s t e un cuvant che i e ce r ep r e z i n t a ob i e c t u l curent a l c l a s e i , i n t ru ca t nu se s t i e cum se
numeste ob i e c t u l
6 this . x = 0 ;
7 this . y = 0 ;
8 }
9
10 // cons t ruc to r cu 2 parametr i ; c on s t ru c t o ru l a f o s t supra inca r ca t
11 public Point (double x , double y ) {
12 this . x = x ;
13 this . y = y ;
14 }
15
16 // cons t ruc to r cu un parametru ; c on s t ru c t o ru l a f o s t supra inca r ca t
17 public Point (double x ) {
18 this . x = x ;
19 this . y = 0 ;
20 }
21
22 // metoda ca l cu l e a z a d i s t an ta i n t r e 2 puncte a f l a t e in plan
23 public s t a t i c double computeDistance ( Point p1 , Point p2 ){
24 // se f o l o s e s c metode a l e c l a s e i Math din pachetu l java . lang
25 return Math . sq r t (Math . pow(p1 . x − p2 . x , 2) + Math . pow(p1 . y − p2 . y , 2) ) ;
26 }
27
28 // metoda e s t e supra inca rca ta
29 public s t a t i c double computeDistance (double x1 , double y1 , double x2 , double y2 ){
30 return Math . sq r t (Math . pow( x1 − x2 , 2) + Math . pow( y1 − y2 , 2) ) ;
31 }
32
33 public s t a t i c double computeDistance ( Point p1 ){/∗∗ metoda e s t e supra inca rca ta ∗/
34 return Math . sq r t (Math . pow(p1 . x , 2) + Math . pow(p1 . y , 2) ) ;
35 }
36
37 public St r ing toS t r ing ( ) {
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 ( St r ing [ ] a rgs ) {
3 Point p1 = new Point ( ) ;
4 System . out . p r i n t l n ( " I n s t a t i e r e ␣ ob i e c t ␣ pr in ␣ cons t ruc to r ␣ f a r a ␣ parametr i : ␣P1 : ␣ "+p1 . t oS t r i ng ( ) ) ;
5 Point p2 = new Point (2 , 2) ;
6 System . out . p r i n t l n ( " I n s t a t i e r e ␣ ob i e c t ␣ pr in ␣ cons t ruc to r ␣cu␣2␣ parametr i : ␣P2 : ␣ "+p2 . t oS t r ing ( ) ) ;
7 Point p3 = new Point (3 ) ;
8 System . out . p r i n t l n ( " I n s t a t i e r e ␣ ob i e c t ␣ pr in ␣ cons t ruc to r ␣cu␣1␣parametru : ␣P3 : ␣ "+p3 . t oS t r ing ( ) ) ;
9
10 System . out . p r i n t l n ( " Calcu leaza ␣ d i s t an ta ␣ i n t r e ␣P2␣ s i ␣P3 : ␣ "+Point . computeDistance (p2 , p3 ) ) ;
11 System . out . p r i n t l n ( " Calcu leaza ␣ d i s t an ta ␣ i n t r e ␣P2␣ s i ␣P3 : ␣ "+Point . computeDistance ( p2 . x , p2 . y , p3 . x , p3
. y ) ) ;
5
12 System . out . p r i n t l n ( " Calcu leaza ␣ d i s t an ta ␣ i n t r e ␣P(0 ,0 ) ␣ s i ␣P2 : ␣ "+Point . computeDistance ( p2 ) ) ;
13 }
14 }
B. Moştenire
Pentru a exemplifica principiul moştenirii se dă clasa de bază Fruct.1 public c l a s s Fruct {
2 private St r ing t ipFruct ;
3
4 public Fruct ( St r ing t ipFruct ) {
5 this . t ipFruct = t ipFruct ;
6 System . out . p r i n t l n ( " Constructor ␣Fruct . . . " ) ;
7 }
8
9 //metoda getTipFruct e s t e una de t i p f i n a l , ad ica aceas ta nu mai poate f i mod i f i ca ta de c l a s e l e care o
mostenesc
10 f i n a l St r ing getTipFruct ( ) {
11 return this . t ipFruct ;
12 }
13 }
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 Fruct{
2 // a t r i b u t e l e sunt pr ivate , dec i domeniul l o r de v i z i b i l i t a t e se a f l a doar in cadru l c l a s e i Para
3 private double greutate ;
4 private St r ing cu loa r e ;
5
6 public Para ( St r ing t ipFruct , double greutate , S t r ing forma ) {
7 super ( t ipFruct ) ; // ape l a r e e x p l i c i t a a c on s t r u c t o ru l u i c l a s e i de baza cu parametrul t ipFruct
8 System . out . p r i n t l n ( " Constructor ␣Para . . . " ) ;
9 this . g r euta te = greutate ;
10 this . cu l oa r e = forma ;
11 }
12
13 //metodele sunt pub l i c e s i dec i pot f i vazute s i in a fa ra c l a s e i , spre deo s eb i r e de a t r i bu t e
14 public double getGreutate ( ) {
15 return greutate ;
16 }
17
18 public St r ing getCuloare ( ) {
19 return cu l oa 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 ( St r ing [ ] a rgs ) {
3 Para obPara = new Para ( " para " , 3 , " galben " ) ; // r e f e r i n t a de t i p u l para
4 System . out . p r i n t l n ( " Tip␣Fruct : ␣ "+obPara . getTipFruct ( ) ) ; // ape l a r e metoda din c l a s a de baza
5 System . out . p r i n t l n ( " g reuta te : ␣ "+obPara . getGreutate ( ) ) ; // ape l a r e metoda din sub l c l a s a
6 System . out . p r i n t l n ( " cu l oa r e : ␣ "+obPara . getCuloare ( ) ) ;
7 }
8 }
Observaţi în urma rulării aplicaţiei ordinea în care se apelează constructorii.
III. TEMĂ
1. Să se construiască o clasă Fractie care să implementeze operaţiile de adunare, scădere, în-
mulţire, împărţire şi simplificare. Să se folosească această clasă într-un program.
2. Să se construiască o clasă Forma2D şi o clasă Cerc care moşteneşte clasa Forma2D. Să se
afişeze lungimea cercului şi suprafaţa acestuia.
7
Laborator 4:
Continuare Programare Orientată pe Obiecte
Întocmit de: Adina Neculai
Îndrumător: Asist. Drd. Gabriel Danciu
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ţă.
Pentru mai multe informaţii se recomandă citirea API-ului.
C. Clase şi metode abstracte
Forma generală a unei clase abstracte este:
[modificator_acces] abstract class NumeClasa{
}
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:
• pot implementa constructori;
• pot avea atribute ce suportă modificări;
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
Forma generală a unei interfeţe este:
[modificator_acces] interface NumeInterfata [extends lista_interfete] {
}
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 Superc lasa {
2 public void a f i s e a z aDe s c r i e r e ( ) {
3 System . out . p r i n t l n ( " ape l a r e ␣ a f i s e a z aDe s c r i e r e ␣ din ␣ supe r c l a s a . . . " ) ;
4 }
5 }
1 public c l a s s Subclasa extends Superc lasa {
2 public void a f i s e a z aDe s c r i e r e ( ) {
3 // ape l a r e e x p l i c i t a a metodei din c l a s a de baza
4 // super . a f i s e a z aDe s c r i e r e ( ) ;
5 System . out . p r i n t l n ( " ape l a r e ␣ a f i s e a z aDe s c r i e r e ␣ din ␣ subc la sa . . . " ) ;
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 Tes tSupra s c r i e r e {
2 public s t a t i c void main ( St r ing [ ] a rgs ) {
3 Superc lasa superClasa = new Superc lasa ( ) ;
4 Subclasa subClasa = new Subclasa ( ) ;
5 superClasa . a f i s e a z aDe s c r i e r e ( ) ; System . out . p r i n t l n ( ) ;
6 subClasa . a f i s e a z aDe s c r i e r e ( ) ; System . out . p r i n t l n ( ) ;
7 superClasa = subClasa ;
8 superClasa . a f i s e a z aDe 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 ID şi IID.
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 Point implements Cloneable {
2 private double x , y ;
3
4 public void setX (double x ) {
5 this . x = x ;
6 }
7
8 public void setY (double y ) {
9 this . y = y ;
10 }
11
12 protected Point c lone ( ) {
13 Point pObj = new Point ( ) ;
14 pObj . x = this . x ;
15 pObj . y = this . y ;
16 return pObj ; // ob i e c t u l pObj are membrii i d e n t i c i cu c e i a i o b i e c t u l u i curent
17 }
18
19 public boolean equa l s ( Object obj ) {
20 i f ( obj == this )
21 return true ; // r e f e r i n t e ega l e
22 i f ( ! ( obj instanceof Point ) )
23 return f a l s e ; // obj nu e s t e de t i p u l Point
24 Point p = ( Point ) obj ; // se f a c e un downcasting , ad ica obj e s t e c onv e r t i t l a t i p u l Point
25 i f ( this . x != p . x | | this . y != p . y )
26 return f a l s e ; // coordonata x sau y e s t e d i f e r i t a
27 return true ;
28 }
29
30 public int hashCode ( ) {
31 double r e s u l t = 17 ;
32 r e s u l t = 37∗ r e s u l t + this . x ;
33 r e s u l t = 37∗ r e s u l t + this . y ;
34 return ( int ) r e s u l t ; /∗ se f a c e un cas t l a t i p u l int , i n t ru ca t v a r i a b i l a r e s u l t e s t e una
35 de t i p double , i a r f un t i a hashCode returneaza o va loa re de t i p i n t ∗/
36 }
37
38 public St r ing toS t r ing ( ) {
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 ( St r ing [ ] a rgs ) {
3 Point p1 = new Point ( ) ;
4 p1 . setX (3) ;
5 p1 . setY (4) ;
6 Point p1Clone = p1 . c lone ( ) ;
7 System . out . p r i n t l n ( "P1 : ␣ "+p1 . t oS t r ing ( ) ) ;
8 System . out . p r i n t l n ( " Clona␣ l u i ␣P1 : ␣ "+p1Clone . t oS t r ing ( ) ) ;
9 i f ( p1 . equa l s ( p1Clone ) )
6
10 System . out . p r i n t l n ( " Ob i ec t e l e ␣ sunt ␣ i d e n t i c e ! " ) ;
11 e l s e System . out . p r i n t l n ( " Ob i ec t e l e ␣nu␣ sunt ␣ i d e n t i c e ! " ) ;
12 System . out . p r i n t l n ( " Hashcode−ul ␣ l u i ␣P1␣ e s t e : ␣ "+p1 . hashCode ( ) ) ;
13 System . out . p r i n t l n ( " Hashcode−ul ␣ c l o n e i ␣ l u i ␣P1␣ e s t e : ␣ "+p1Clone . hashCode ( ) ) ;
14 }
15 }
C. Clase şi metode abstracte
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 abstract c l a s s Produs {
2 private double pretUnitar ;
3
4 Produs (double pretUnitar ) {
5 this . p retUnitar = pretUnitar ;
6 }
7
8 public double getPretUnitar ( ) {
9 return pretUnitar ;
10 }
11
12 //metodele ab s t r a c t e nu au corp
13 // e l e vor f i implementate in c l a s e l e c o p i l a l e c l a s e i Produs
14 public abstract void a f i s e a z aDe s c r i e r e ( ) ;
15 public abstract double ca l cu l eazaReducere ( int procent ) ;
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 Carte extends Produs{
2 private St r ing t i t l u , autor ;
3
4 public Carte (double pretUnitar , S t r ing t i t l u , S t r ing autor ) {
5 super ( pretUnitar ) ;
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 aDe s c r i e r e e s t e implementata in sub l c l a s a
11 public void a f i s e a z aDe s c r i e r e ( ) {
12 System . out . p r i n t l n ( " T i t lu ␣ c a r t i i ␣ e s t e : ␣ "+this . t i t l u+" , ␣ i a r ␣ autoru l ␣ e s t e : ␣ "+this . autor ) ;
13 }
14
15 //metoda ca lcu l eazaReducere e s t e implementata in sub l c l a s a
16 public double ca l cu l eazaReducere ( int procent ){
17 System . out . p r i n t l n ( " Calcu leaza ␣ reducere ␣din ␣Carte . . . " ) ;
18 return 0 . 0 ;
19 }
20 }
1 public c l a s s RamaFoto extends Produs{
2 private int lungime , la t ime ;
3
4 public RamaFoto(double pretUnitar , int lungime , int l a t ime ) {
5 super ( pretUnitar ) ;
6 this . lungime = lungime ;
7 this . l a t ime = lat ime ;
8 }
9
10 //metoda a f i s e a z aDe s c r i e r e e s t e implementata in sub l c l a s a
11 public void a f i s e a z aDe s c r i e r e ( ) {
12 System . out . p r i n t l n ( " Lungimea␣ ramei ␣ e s t e : ␣ "+this . lungime+" , ␣ i a r ␣ lat imea ␣ e s t e : ␣ "+this . l a t ime ) ;
13 }
14
15 //metoda ca lcu l eazaReducere e s t e implementata in sub l c l a s a
16 public double ca l cu l eazaReducere ( int procent ){
17 System . out . p r i n t l n ( " Calcu leaza ␣ reducere ␣ in ␣RamaFoto␣ in ␣ f un c t i e ␣de␣ lat ime ␣ s i ␣ lungime . . . " ) ;
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 TestProdus {
2 public s t a t i c void main ( St r ing [ ] a rgs ) {
3 Produs [ ] l i s t aProdus e = new Produs [ 4 ] ;
4 for ( int i =0; i<l i s t aProdus e . l ength ; i++){
5 i f ( i % 2 == 0){ //daca i e s t e par atunc i se c reeaza un ob i e c t de t i p u l Carte
6 l i s t aProdus e [ i ] = new Carte ( 12 . 3 , " Fundatia ␣ "+i , " I saac ␣Asimov " ) ;
7 } e l s e { //daca i e s t e impar atunc i se c reeaza un ob i e c t de t i p u l RamaFoto
8 l i s t aProdus e [ i ] = new RamaFoto ( 5 . 5 , 20− i , 15− i ) ;
9 }
10 }
11 double pretTota l = 0 . 0 ;
12 for ( int i =0; i<l i s t aProdus e . l ength ; i++){
13 //putem avea acces l a metoda getPretUnitar ( ) pentru ca aceas ta se a f l a in c l a s a par in t e .
14 double pretProdusOr ig ina l = l i s t aProdus e [ i ] . getPretUnitar ( ) ;
15 double reducere = l i s t aProdus e [ i ] . ca l cu l eazaReducere ( i ) ;
16 pretTota l += pretProdusOr ig ina l − reducere ;
17 l i s t aProdus e [ i ] . a f i s e a z aDe s c r i e r e ( ) ;
18 }
19 System . out . p r i n t l n ( " Pretu l ␣ t o t a l ␣ a l ␣ produse lo r ␣ e s t e : ␣ "+pretTota l ) ;
8
20 }
21 }
D. Interfeţe
Avem interfaţa IPersoana în care se află definiţia unei metode.1 public interface IPersoana {
2 public St r ing returneazaNumePersoana ( ) ;
3 }
Interfaţa IStudent moşteneşte interfaţa IPersoana, implicit şi metoda unică a acesteia.1 public interface IStudent extends IPersoana{
2 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 ( ) ;
3 }
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 Student implements IStudent {
2 St r ing nume ;
3 double medieNote ;
4
5 public Student ( St r ing nume , double medieNote ){
6 this . nume = nume ;
7 this . medieNote = medieNote ;
8 }
9
10 // se implementeaza metoda din IStudent
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 i f ( this . medieNote >= 5){
13 return true ;
14 }
15 return f a l s e ;
16 }
17
18 // se implementeaza metoda mostenita de IStudent din IPersoana
19 public St r ing returneazaNumePersoana ( ) {
20 return this . 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 ( St r ing [ ] a rgs ) {
3 Student student = new Student ( " Ionescu ␣Radu" , 6 . 3 ) ;
4 i f ( 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 . out . p r i n t l n ( student . returneazaNumePersoana ( )+" ␣ e s t e ␣ i n t e g r a l i s t " ) ;
6 e l s e
9
7 System . out . p r i n t l n ( student . returneazaNumePersoana ( )+" ␣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.
Pentru acestea veţi avea nevoie de:
• cub (reprezentat de 8 puncte);
• sferă (reprezentată de 2 puncte: centrul şi un punct de pe margine);
• punct (reprezentat de cele 3 coordonate în spatiu: x, y şi z);
• 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
Intocmit de: Dobrinas Alexandra
Indrumator: Asist. Drd. Danciu Gabriel
October 28, 2011
I. NOTIUNI TEORETICE
A. Array
Un sir de date sau un array este o structura ce contine valori multiple de acelasi tip de data. Lungimeaunui sir de date se stabileste la crearea array-ului si va fi fixa pe ıntreaga existenta a acestuia. De regula,primul element se afla pe pozitia 0, iar ultimul pe pozitia n− 1, unde n reprezinta numarul de elemente dinsir.
1. Declararea unui sir de date
In Java, declararea unui array se face astfel:
tip_de_date [] nume_sir;
unde, tip de date reprezinta tipul de date atribuit sirului (int, float, char, String, sau orice tip referinta),iar nume sir reprezinta numele variabilei ın care se stocheaza sirul.
Odata ce sirul de date a fost declarat, acesta se poate instantia. Pentru instatiere se foloseste operatorulnew.
De exemplu, pentru un sir de date de tipul int, cu 3 elemente, declararea si instantierea acestuia se faceastfel:
int [] s;s = new int[3];
sau:
int [] s=new int[3]
Setarea valorilor pentru elementele sirului s creat, se face astfel:
s[0]=14;s[1]=2;s[2]=12;
sau, elementelor li se pot atribui valori ınca de la instantiere:
int[] s = {14,2,12};
Pentru atribuirea de valori ale unui sir, se pot folosii si instructiunile repetitive. De exemplu, ın cazul Incare se citeste un sir de la tastatura, atribuirea valorilor se poate face astfel:
1 BufferReader s td in = new BufferReader (new InputStreamReader ( System . in ) ) ;2 int [ ] s = new int [ 5 ] ;3 for ( int i =0; i <5; i++)4 {5 s [ i ]= In t ege r . pa r s e In t ( s td in . readLine ( ) ) ;6 }
Declararea unui array de un tip de date referinta se face ın acelasi mod ca si pentru sirurile de tipul dedate primitive. Doar ca un astfel de sir va avea ca elemente obiectele unei clase. Astfel ca, daca se da o clasacu numele Country, un sir de elemente din aceasta clasa se declara astfel:
1 c lass Country2 {3 St r ing name ;4 long populat ion ;5 }67 public c lass CountryDemo {8 public stat ic void main ( St r ing [ ] 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 ] . populat ion = 600000000000 l ;1415 s i r [ 1 ] . name = ”Franta” ;16 s i r [ 1 ] . populat ion = 650000000000 l ;17 }18 }
2. Declararea sirurilor multidimensionale
Deoarece un sir de date poate contine referinte catre alte obiecte, este posibil ca un sir sa contina referintesi catre alte siruri. In acest caz, se spune ca se folosesc siruri multidimensionale. Cele mai comune sirurimultimensionale sunt matricile. Exemplu de sir multidimensional:
int matrix[][] = new int[3][2];matrix[0][1] = 12;
In acest caz se da un sir bidimensional, astfel: 3 siruri ın care sunt retinute siruri de cate doua elementede tip int. Accesarea elementelor unui astfel de sir se face prin precizarea tuturor indicilor (ın cazul acestasunt 2 indici).
Nu este obligatoriu ca toate subsirurile sa aiba aceeasi dimensiune. In exemplul urmator este prezentatun sir multidimensional ın care subsirurile au dimensiuni diferite:
1 f loat s i r [ ] [ ] = new f loat [ 4 ] [ ] ;23 s i r [ 0 ] = new f loat [ 5 ] ;4 s i r [ 1 ] = new f loat [ ] { 2 . 3 f , 5 , 6 . 7 f , 1 1} ;5 s i r [ 2 ] = new f loat [ ]{ 1 f , 4 . 2 f , 7 f , 4 . 1 f , 10 f , 9 f } ;6 s i r [ 3 ] = new f loat [ 2 0 ] ;
B. Clasa Vector
Clasa Vector face parte din pachetul java.util si reprezinta o clasa speciala pentru lucrul cu sirurile deelemente. Cele mai uzuale metode folosite pentru declararea si crearea unui astfel de sir sunt:
Vector v = new Vector();//sauVector v = new Vector(5);//se creeaza un vector de 5 elemente
3
1. Metode si operatii specifice clasei V ector
Deoarece manipularea elementelor unui sir este o operatie ce necesita multa munca, clasa V ector aredefinite o serie de metode si operatii ce pot fi de folos:
Metoda Operatia specifica
add() Adauga un element intr-un vector.
addAll() Adauga o colectie de elemente intr-un vector.
addElement() asemenea metodei add().
capacity() Returneaza capacitatea adica marimea sirului intern.
clear() sterge toate elementele unui vector.
clone() Creeaza o clona a vectorului.
contains() Verifica daca un vector contine un element.
containsAll() Verifica daca un vector contine o colectie.
copyInto() Copiaza elementele unui vector intr-un array.
elementAt() Returneaza elementul de la pozitia specificata.
elements() Returneaza un obiect al vectorului care permite vizitarea tuturor cheilor vectorului.
ensureCapacity() Verifica si se asigura ca marimea buffer-ului intern sa fie de o anumita marime.
equals() verifica egalitatea cu un obiect.
firstElement() returneaza primul element.
get() returneaza un element de la o anumita pozitie.
indexOf() cauta prima aparitie a unui element in sir.
insertElementAt() Insereaza un element in sir.
isEmpty() verifica daca un vector este gol.
iterator() returneaza un iterator, adica un obiect ce permite vizitarea elementelor din sir.
lastElement() Returneaza ultimul element din sir.
lastIndexOf() Cauta pozitia ultimului element din sir care este egal cu obiectul specificat.
listIterator() Returneaza un obiect care permite ca toate elementele sa fie vizitate secvential.
remove() Sterge un anumit element din vector.
removeAll() Sterge toate elementele specificate in colectia data ca parametru.
removeAllElements() Sterge toate elementele din sir si seteaza marimea acestui cu zero.
set() Schimba un element de la o anumita pozitie.
setElementAt() Acelasi lucru ca si set.
setSize() modifica marimea buffer-ului intern.
size() returneaza numarul de elemente din sir.
subList() returneaza o sectiune din sir.
toArray() returneaza elementele vectorului ca array.
trimToSize() taie o portiune din sir, astfel ca el sa ramana de marimea specificata.
C. Clasa Stack
Stiva este o structura de date de tipul LIFO (Last In, First Out).Clasa Stack este considerata a fi ,,copilul” clasei V ector. ınsa are definite o serie de operatii specifice
stivelor.
• Adaugarea elementelor.
Aceasta operatiune se face prin metoda push():
4
public Object push(Object element)
• Stergerea unui element Aceasta operatiune se va face prin apelul functiei pop():
public Object pop()
• Verificare daca stiva este goala
public boolean empty()
• Preluarea elementului din varful stivei
public Object peek()
• Cautarea unui element ın stiva
public int search(Object element)
Exemplu de utilizare a clasei Stack:
1 import java . u t i l . Stack ;2 public c lass St iva3 {4 public stat ic void main ( St r ing args [ ] )5 {6 Stack s = new Stack ( ) ;7 s . push ( ”Primul element ” ) ;8 s . push ( ”Al do i l e a element ” ) ;9 s . push ( ”Al t r e i l e a element ” ) ;
10 System . out . p r i n t l n ( ”Next : ” + s . peek ( ) ) ;1112 s . push ( ”Al pat ru l ea element ” ) ;13 System . out . 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 . out . p r i n t l n ( s ) ;1718 int count = s . search ( ”Al do i l e a element ” ) ;19 while ( count != −1 && count > 1)20 {21 s . pop ( ) ;22 count−−;23 }2425 System . out . p r i n t l n ( s . pop ( ) ) ;2627 System . out . p r i n t l n ( s . empty ( ) ) ;28 System . out . p r i n t l n ( s ) ;29 }30 }
II. TEME DE LABORATOR
1. Se considera un sir de elemente ce contine n numere reale. Se spune ca doua elemente ale sale formeazao ,,pereche ın dezordine” daca sunt ındeplinite simultan conditiile:
• i < j
• a[i] > a[j], unde1 ≤ i < n si 1 < j ≤ n
Sa se creeze un program care afiseaza perechile ın dezordine din sir si numarul lor. Exemplu: Pentrun=4 si sirul (1, 13,2,4), se va afisa: 13 2 13 4 2
2. Se considera doua tablouri bidimensionale de dimensiuni identice (nxm). Sa se afiseze transpusamatricei suma. Transpusa unei matrice se obtine prin schimbarea liniilor cu coloanele.
3. Determinati suma maxima care se poate forma cu m numere distincte dintr-un vector ce contine nvalori ıntregi. Daca sirul contine mai putin de m valori distincte se va afisa mesajul Imposibil. Pentrurezolvarea problemei se va folosi clasa V ector.
4. Folosind o stiva, realizati si afisati programul dumneavoastra dintr-o zi, pe ore. Eliminati actiunile pecare le efectuati pana la ora 14 si afisati ceea ce urmeaza sa faceti la ora 15.
5
Laborator Nr. 5:
Structuri de date 2
Intocmit de: Dobrinas Alexandra
Indrumator: Asist. Drd. Danciu Gabriel
November 3, 2011
I. NOTIUNI TEORETICE
A. Liste
Lista reprezinta cea mai simpla structura de date ınlantuita. Se folosesc doua tipuri de liste:
• liste simplu ınlantuite;
• liste dublu ınlantuite;
B. Liste simplu ınlantuite
Pot fi definite ca fiind o secventa de obiecte alocate dinamic, ın fiecare obiect se pastranduse atat informatiautila cat si o referinta catre succesorul sau din lista. Exista o multitudine de moduri prin care se poateimplementa aceasta structura de date,ınsa cel mai utilizat mod este prin definirea unei clase cu doi membri,unul ın care se retine informaıia utila si unul In care se retine adresa urmatorului element din lista.
1 public c lass LinkedList {23 int data ;4 LinkedList next ;56 public LinkedList ( ) {78 data = 0 ;9 next = null ;
10 }1112 }
Se observa ca membrul next este de acelasi tip de date ca si clasa, acesta pentru ca urmatorul element dinlista este tot de acest tip de date. Pe langa acesti membri se mai pot adauga si altii care sa contina diverseinformatii, ın functie de aplicatia care cere utilizarea unei astfel de structuri.
Urmatorul exemplu ilustreaza crearea si afisarea unei liste simplu ınlantuite. Initial a fost creat un ele-ment cu ajutorul constructorului, informaatia din acest element a primit valoarea 23, iar pentru creareaurmatorului element s-a instantiat membrul next, s.a.m.d. Aceasta operatie poate fi numita ,,alipireaurmatorului element de elementul curent”. Pentru a parcurge lista se foloseste un iterator.
1 c lass LinkedListDemo {2 public stat ic void main ( St r ing args [ ] )3 {4 LinkedList l i s t = new LinkedList ( ) ;5 l i s t . data =23;6 l i s t . next = new LinkedList ( ) ;7 l i s t . next . data = 10 ;8 l i s t . next . next = new LinkedList ( ) ;9 l i s t . next . next . data = 49 ;
1011 // parcurgerea l i s t e i de l a primul element1213 LinkedList i t e r a t o r = l i s t ;14 do15 {16 System . out . p r i n t l n ( i t e r a t o r . data ) ;17 }18 while ( ( i t e r a t o r = i t e r a t o r . next ) !=null ) ;1920 }21 }
Un alt mod de folosire al listelor ınlantuite este prin declararea si retinerea primului element din lista:
1 c lass LinkedList2 {23 int data ;4 LinkedList2 next ;5 LinkedList2 head ;67 public LinkedList2 ( ) {89 head = this ;
10 next = null ;11 data =0;12 }1314 public LinkedList2 ( LinkedList2 head ) {1516 this . head = head ;
2
17 next = null ;18 data =0;19 }20 }212223 // ////////////////////////////242526 c lass LinkedList2Demo {2728 public stat ic void main ( St r ing args [ ] ) {2930 LinkedList2 l i s t = new LinkedList2 ( ) ;31 l i s t . head = l i s t ;32 l i s t . data =23;33 l i s t . next = new LinkedList2 ( l i s t ) ;34 l i s t . next . data = 10 ;35 l i s t . next . next = new LinkedList2 ( l i s t ) ;36 l i s t . next . next . data = 49 ;3738 // parcurgerea l i s t e i de l a primul element39 while ( l i s t . next !=null ) {4041 System . out . p r i n t l n ( l i s t . data ) ;42 l i s t = l i s t . next ;43 }4445 System . out . p r i n t l n ( l i s t . data ) ;46 l i s t = l i s t . head ;4748 while ( l i s t . next !=null ) {4950 System . out . p r i n t l n ( l i s t . data ) ;51 l i s t = l i s t . next ;52 }53 System . out . p r i n t l n ( l i s t . data ) ;54 }55 }
Se observa ca prin retinerea primunul element al listei se poate ajunge mult mai repede si mai usor laprimul element din lista. De asemenea, se poate observa ca acest mod de construire al unei liste nu esteeficient, deoarece, ın cazul unei liste cu sute sau chiar mii de elemente adaugarea noilor elemente va fiimposibil de realizat. De aceea, adaugarea unui element nou precum si stergerea unui element sunt operatiispecifice pentru lucrul cu liste alaturi de modificarea informatiei utile, modificarea legaturii dintre elemente,cautarea unui element ın liste, aflarea pozitiei unui element.
C. Liste dublu ınlantuite
In cazul ın care se doreste parcurgerea listei si ın celalalt sens (si nu doar de la predecesor la succesor),avem lista dublu ınlantuita. Aceasta pastreaz conceptele listei simplu ınlantuite, cu specificarea ca fiecareelement al listei mai contine o referinta si catre elementul precedent. Un mod de declararea al unei astfel deliste este urmatorul:
1 public c lass Nod {23 private Nod next ;4 private Nod prev ;5 private int data ;67 public Nod( int data , Nod next ,Nod prev )8 {9 this . data = data ;
10 this . next = next ;11 this . prev = prev ;12 }13 }
Operatile specifice lister simplu ınlantuite se mentin si pentru listele dublu, doar ca trebuie sa se tina contsi de legatura prev.
D. Framework -ul Java pentru Colectii
Java pune la dispozitia utilizatorilor o serie de interfete si clase ce pot fi folosite pentru crearea si utilizareadiferitelor colectii de date. Printre acestea amintim:
• interfata Collection - are definite metode pentru o serie de operatii ce se aplica unei colectii (detaliiaici)
3
• interfata Iterator - iteratorul este acel obiect ce permite parcurgerea colectiilor (detalii aici)
• interfata List - interfata ce implementeaza Collection. Exista doua clase ce implementeaza aceastainterfata: ArrayList si LinkedList. Interfata List ofera posibilitatea de a lucra ordonat, deci permitepastrarea secventiala a elementelor dintr-o colectie (detalii aici)
• clasa ArrayList - clasa este echivalentul clasei Vector, dar sub forma unei colectii. Un ArrayList esteo colectie de elemente indexate ıntr-o anumita ordine, dar nu neaparat sortate. (detalii)
• clasa LinkedList - aceasta este implementarea listei dublu ınlantuite. (detalii)
E. Multimi - Interfata Set
Interfata Set reprezinta un grup de elemente fara duplicate. Nu exista o conditie anume ce impune acestlucru, ci implementarile din clasele Set, sunt cele care impun aceasta conditie. Interfata Set deriva dinCollections, deci va implementa aceleasi metode ca si aceasta interfata. Un element, aflat deja ın multime,nu mai poate fi modificat. API-ul interfetei se poate gasii aici
F. Clasa HashSet
Face parte din interfata Set si are ca operatii specifice urmatoarele:
• adaugarea elementelor;
• stergerea elementelor;
• verificare daca lista este goala;
• verificare daca un anumit obiect este continut tn lista;
Un exemplu de utilizare al clasei HashSet este urmatorul:
1 import java . u t i l . ArrayList ;2 c lass Point {34 public int x ;5 public int y ;67 public Point ( int x , int y) {89 this . x = x ;
10 this . y = y ;11 }1213 public boolean equa l s ( Object o ) {1415 i f ( ! ( o instanceof Point ) )16 return fa l se ;17 Point pt = ( Point ) o ;18 return ( ( pt . x == this . x ) && ( pt . y==this . y ) ) ;19 }2021 public int hashCode ( ) {2223 return 17∗ this . x +23∗ this . y+43;24 }2526 public Str ing toSt r ing ( ) {27 return ”x = ” +x+ ” y = ” +y + ” id = ”+ hashCode ( )+ ”\n” ;28 }29 }3031 // ///////////////////3233 public c lass Multimi34 {35 public stat ic void main ( St r ing args [ ] ) {3637 Set s e t = new HashSet ( ) ;3839 // Adaug in multime40 s e t . add (new Point (1 ,2 ) ) ;41 s e t . add (new Point (2 ,1 ) ) ;42 s e t . add ( ”c” ) ;43
4
44 // Sterg un element din multime45 s e t . remove ( ”c” ) ;4647 //Marimea unei multimi48 int s i z e = se t . s i z e ( ) ;49 System . out . p r i n t l n ( s i z e ) ;5051 // Adaug un element ce e x i s t a deja52 s e t . add (new Point (1 ,2 ) ) ;5354 // fa ra a avea insa e f e c t55 s i z e = se t . s i z e ( ) ;56 System . out . p r i n t l n ( s i z e ) ;5758 // Ver i f i cam daca un element e s t e deja in multime59 boolean b = se t . conta ins (new Point (2 ,1 ) ) ; // true60 System . out . p r i n t l n (b) ;6162 b = se t . conta ins ( ”c” ) ; // f a l s e63 System . out . p r i n t l n (b) ;6465 // Parcurgem multimea66 I t e r a t o r i t = se t . i t e r a t o r ( ) ;67 while ( i t . hasNext ( ) ) {68 // s i af isam e lemente l e69 Object element = i t . next ( ) ;70 System . out . p r i n t l n ( element ) ;71 }72 }73 }
II. TEME DE LABORATOR
1. Editati, compilati si lansati ın executie aplicatile prezentate la I B.
2. Creati o lista dublu ınlantuita si afisati-o.
3. Editati, compilati si lansati ın executie aplicatile prezentate la I F.
4. Se da o clasa de numere complexe. Folosind clasa HashSet creati o lista ın care sa se retina numerecomplexe. Adaugati minim 5 astfel de numere si realizati un meniu prin care sa se rezolve urmatoarelecerinte:
• Afisati dimensiunea listei.
• Verificati daca un numar citit exista ın lista. Daca nu exista, adaugati-l si afisati noua lungime alistei.
• Eliminati un numar din lista.
• Afisati suma numerelor din lista.
• Afisati elementele listei.
5
Laborator 7:
Tratarea excepţiilor în Java
Întocmit de: Adina Neculai
Îndrumător: Asist. Drd. Gabriel Danciu
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:
• tratarea excepţiilor la un nivel superior celui în care apar;
• propagarea excepţiilor la nivelele superioare în mod ierarhic;
• tratarea unitară a excepţiilor de acelaşi tip.
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.
Figura 1: Ierarhia simplificată a claselor de tip excepţie din pachetul java.lang
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.
C. Aruncarea unei excepţii
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
. . .
}
D. Prinderea unei excepţii
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{
//cod ce poate arunca o exceptie
}
catch(<classExcept1> <idExcept1>){
//handler exceptie de tip <classExcept1>
}
catch(<classExcept2> <idExcept2>){
//handler exceptie de tip <classExcept2>
}
. . .
finally{
//secventa de cod executata oricum
}
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.
E. Crearea propriilor excepţii
Î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.
II. PREZENTAREA LUCRĂRII DE LABORATOR
A. Exemple de programe ce demonstrează lucrul cu excepţiile
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 ( St r ing [ ] a rgs ) {
3 for ( int i = 0 ; i <= 1 ; i++) {
4 try {
5 System . out . p r i n t l n ( " \n␣Caz␣ "+i ) ;
5
6 // apa r i t i a e x c e p t i e i se r e a l i z e a z a pr in ape lu l metodei metoda1
7 metoda1 ( i ) ;
8 System . out . p r i n t l n ( " \n␣ S f a r s i t ␣ caz ␣ "+i ) ;
9 } catch ( Exception ex ) {
10 // t r a t a r e a e x c e p t i e i i n t a l n i t e in metoda1
11 // ape la r ea f u n c t i e i getMessage ( ) a c l a s e i Exception
12 System . out . p r i n t l n ( "A␣aparut ␣o␣ exc ep t i e . ␣Mesajul ␣ e i ␣ e s t e : ␣ "+ex . getMessage ( ) ) ;
13 } f i n a l l y {
14 System . out . p r i n t l n ( " Se␣ executa ␣ b l o cu l ␣ f i n a l l y " ) ;
15 }
16 }
17 }
18
19 //metoda1 s p e c i f i c a pr in in t e rmed iu l cuvantu lu i che i e " throws " ce t i p u r i de e x c e p t i i arunca
20 private s t a t i c void metoda1 ( int i ) throws Exception {
21 System . out . p r i n t l n ( "Am␣ i n t r a t ␣ in ␣metoda1 " ) ;
22 i f ( i != 0){
23 // aruncarea e x c e p t i e i de t i p u l Exception
24 throw new Exception ( " ex c ep t i e ␣ din ␣metoda1 " ) ;
25 }
26 System . out . p r i n t l n ( "Am␣ i e s i t ␣ din ␣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 ( St r ing [ ] a rgs ) {
3 for ( int i = 0 ; i <= 1 ; i++) {
4 try {
5 System . out . p r i n t l n ( " \n␣Caz␣ " + i ) ;
6 metoda1 ( i ) ;
7 System . out . p r i n t l n ( " \n␣ S f a r s i t ␣ caz ␣ " + i ) ;
8 } catch ( Exception ex ) {
9 System . out
10 . p r i n t l n ( "A␣aparut ␣o␣ exc ep t i e ␣Exception . ␣Mesajul ␣ e i ␣ e s t e : ␣ "
11 + ex . getMessage ( ) ) ;
12 } catch ( Throwable exTh) {
13 System . out . p r i n t l n ( "A␣aparut ␣o␣ exc ep t i e ␣Throwable␣ in ␣main " ) ;
14 /∗ ape la r ea metodei pr intStackTrace ( ) a c l a s e i Throwable care a f i s e a za , conform
p r i n c i p i u l u i unei s t i v e LIFO ,
15 i n f o rma t i i despre l o c a t i i l e parcurse de exc ep t i e ∗/
16 exTh . pr intStackTrace ( System . out ) ;
17 } f i n a l l y {
18 System . out . p r i n t l n ( " Se␣ executa ␣ b l o cu l ␣ f i n a l l y ␣din ␣main " ) ;
19 }
20 }
21 }
6
22
23 private s t a t i c void metoda1 ( int i ) throws Throwable {
24 System . out . p r i n t l n ( "Am␣ i n t r a t ␣ in ␣metoda1 " ) ;
25 metoda2 ( i ) ;
26 System . out . p r i n t l n ( "Am␣ i e s i t ␣ din ␣metoda1 " ) ;
27 }
28
29 private s t a t i c void metoda2 ( int i ) throws Throwable {
30 System . out . p r i n t l n ( "Am␣ i n t r a t ␣ in ␣metoda2 " ) ;
31 i f ( i != 0) {
32 throw new Throwable ( " ex c ep t i e ␣ din ␣metoda2 " ) ;
33 }
34 System . out . p r i n t l n ( "Am␣ i e s i t ␣ din ␣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 ( St r ing [ ] a rgs ) {
3 try {
4 System . out . p r i n t l n ( " \n␣Number␣Format␣Exception " ) ;
5 St r ing s t r 1 = " 123 r " ;
6 In t ege r n = Int ege r . pa r s e In t ( s t r 1 ) ;
7
8 System . out . p r i n t l n ( " \n␣ArrayIndexOutOfBoundsException " ) ;
9 int s i r [ ] = { 1 , 2 , 3 , 4 } ;
10 s i r [ 6 ] = 3 ;
11
12 System . out . p r i n t l n ( " \n␣StringIndexOutOfBoundsException " ) ;
13 St r ing s t r 2 = " abcde " ;
14 char c1 = s t r 2 . charAt (−1) ;
15
16 System . out . p r i n t l n ( " \n␣Nul lPo interExcept ion " ) ;
17 St r ing s t r 3 = null ;
18 System . out . p r i n t l n ( s t r 3 . l ength ( ) ) ;
19
20 System . out . p r i n t l n ( " \n␣ArithmeticExcept ion " ) ;
7
21 int n2 = 12/0;
22
23 } catch ( NumberFormatException nfex ) {
24 System . out . p r i n t l n ( " Tratare ␣ exc ep t i e ␣NumberFormatException . . . " ) ;
25 ca l lExcept i on ( nfex ) ;
26 } catch ( ArrayIndexOutOfBoundsException arrayEx ) {
27 System . out . p r i n t l n ( " Tratare ␣ exc ep t i e ␣ArrayIndexOutOfBoundsException . . . " ) ;
28 ca l lExcept i on ( arrayEx ) ;
29 } catch ( StringIndexOutOfBoundsException strEx ) {
30 System . out . p r i n t l n ( " Tratare ␣ exc ep t i e ␣StringIndexOutOfBoundsException . . . " ) ;
31 ca l lExcept i on ( strEx ) ; ;
32 } catch ( Nul lPo interExcept ion nullEx ) {
33 System . out . p r i n t l n ( " Tratare ␣ exc ep t i e ␣Nul lPo interExcept ion . . . " ) ;
34 ca l lExcept i on ( nullEx ) ;
35 }catch ( ArithmeticExcept ion aEx){
36 System . out . p r i n t l n ( " Tratare ␣ exc ep t i e ␣ArithmeticExcept ion . . . " ) ;
37 ca l lExcept i on (aEx) ;
38 }
39 }
40
41 private s t a t i c void ca l lExcept i on ( RuntimeException r tex ){
42 System . out . p r i n t l n ( " Mesajul ␣ standard ␣ a l ␣ e x c e p t i e i : ␣ " ) ;
43 System . out . p r i n t l n ( r t ex ) ;
44 System . out . p r i n t l n ( " Mesajul ␣ e x c e p t i e i : ␣ " ) ;
45 System . out . p r i n t l n ( r t ex . getMessage ( ) ) ;
46 System . out . p r i n t l n ( " Mesajul ␣ l o c a l : ␣ " ) ;
47 System . out . p r i n t l n ( r t ex . getLoca l i zedMessage ( ) ) ;
48 System . out . p r i n t l n ( " \nStack␣ t ra c e : ␣ " ) ;
49 r tex . pr intStackTrace ( System . out ) ;
50 }
51 }
B. Crearea propriilor excepţii
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 IncompatibleMatr ixExcept ion extends Exception{
2
3 public IncompatibleMatr ixExcept ion ( ) {
4 }
5
6 public IncompatibleMatr ixExcept ion ( St r ing message ) {
7 super ( message ) ;
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 ( St r ing [ ] a rgs ) {
3 int [ ] [ ] matr1 , matr2 ;
4 matr1 = new int [ 2 ] [ 3 ] ;
5 matr2 = new int [ 4 ] [ 4 ] ;
6
7 try{
8 multiplyMatr (matr1 , matr2 ) ;
9 }catch ( IncompatibleMatr ixExcept ion imEx){
10 System . out . p r i n t l n ( " Mesajul ␣ e s t e : ␣ "+imEx . getMessage ( ) ) ;
11 imEx . pr intStackTrace ( System . out ) ;
12 }
13 }
14
15 private s t a t i c void multiplyMatr ( int [ ] [ ] matr1 , int [ ] [ ] matr2 ) throws IncompatibleMatr ixExcept ion{
16 i f (matr1 [ 0 ] . l ength != matr2 . l ength ){
17 throw new IncompatibleMatr ixExcept ion ( " mat r i c i ␣ incompat ib i l e ␣pt␣ inmu l t i r e " ) ;
18 }
19 //cod de s t i na t pt inmu l t i r ea ma t r i c i l o r
20 }
21
22 }
III. TEMĂ
1. Rulaţi toate programele prezentate ca exemplu în secţiunea II.
2. Realizaţi un program în care să se testeze captarea şi tratarea excepţiilor generate la calcu-
larea a cel puţin 10 funcţii matematice din clasa Math aflată în pachetul java.lang. Folosiţi
blocuri de catch specifice pentru fiecare funcţie în parte.
9
Laborator Nr. 8:
Fluxuri Java
Intocmit de: Dobrinas Alexandra
Indrumator: Asist. Drd. Danciu Gabriel
November 15, 2011
I. NOTIUNI TEORETICE
Fluxurile Java pun la dispozitie modalitatea prin care o aplicatie permite citirea unor informatii care segasesc pe o sursa externa, respectiv trimiterea unor informatii catre o destinatie externa. Informatia sepoate gasi oriunde: ıntr-un fisier pe disc, ın retea, ın memorie sau ın alt program si poate fi de orice tip:date primitive, obiecte, imagini, sunete, etc. Mai mult, prin fluxuri este posibila comunicarea ıntre douasau mai multe fire de executie ale aceleiasi aplicatii. Fluxurile sunt secvente de octeti. Indiferent de tipulinformatiilor, citirea/scrierea lor de pe un mediu extern, respectiv pe un mediu extern respecta urmatoriialgoritmi:
• Citirea:
deschide canal comunicatie;cat timp (mai sunt informatii) {citeste informatie;}inchide canal comunicatie;
• Scrierea:
deschide canal comunicatiecat timp (mai sunt informatii) {scrie informatie;}inchide canal comunicatie;
A. Fluxuri pentru lucrul cu fisiere
Fluxurile pentru lucrul cu fisiere sunt cele mai usor de ınteles. Clasele care implementeaza aceste fluxurisunt urmatoarele:
FileReader caractere
FileWriter caractere
FileInputStream octeti
FileOutputStream octeti
Constructorii acestor clase accepta ca argument un obiect prin care se specifica fisierul folosit. Acestapoate fi un sir de caractere, un obiect de tip File sau un obiect de tip FileDescriptor.
Constructorii clasei FileReader (vezi si API):
public FileReader( String fileName ) throws FileNotFoundExceptionpublic FileReader( File file ) throws FileNotFoundExceptionpublic FileReader( FileDescriptor fd )
Constructorii clasei FileWriter (vezi si API):
public FileWriter( String fileName ) throws IOExceptionpublic FileWriter( File file ) throws IOExceptionpublic FileWriter( FileDescriptor fd )public FileWriter( String fileName, boolean append ) throws IOException
Constructorii clasei FileOutputStream (vezi si API):
2
FileOutputStream(File file) throws FileNotFoundExceptionFileOutputStream(File file, boolean append) throws FileNotFoundExceptionFileOutputStream(FileDescriptor fd)FileOutputStream(String name) throws FileNotFoundExceptionFileOutputStream(String name, boolean append) throws FileNotFoundException
Constructorii clasei FileInputStream (vezi si 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 fisierului. Acestia pot provocaexceptii de tipul FileNotFoundException ın cazul ın care fisierul cu numele specificat nu exista. Din acestmotiv orice creare a unui flux de acest tip trebuie facuta tntr-un bloc try....catch sau metoda ın care suntcreate fluxurile respective trebuie sa arunce exceptii de tipul FileNotFoundException sau de tipul superclaseiIOException.
Urmatoarele programe copiaza continutul unui fisier ıntr-un alt fisier.
1 import java . i o . ∗ ;2 public c lass Copy1 {3 public stat ic void main ( St r ing [ ] args ) throws IOException {45 Fi leReader in = new Fi leReader ( ” in . txt ” ) ;6 F i l eWr i te r out = new Fi l eWr i te r ( ”out . txt ” ) ;78 int c ;9 while ( ( c = in . read ( ) ) != −1)
10 out . wr i te ( c ) ;1112 in . c l o s e ( ) ;13 out . c l o s e ( ) ;14 }15 }
Se observa ca metoda main arunca exceptii de tipul IOException, deci nu este necesara folosirea blocurilortry....catch. Pentru citirea si scrierea din\ın fisiere s-au folosit clasele FileReader sitextitFileWriter
In urmatorul exemplu este exemplificat modul de lucru cu clasele FileInputStream si FileOutputStream,precum si folosirea blocurilor try...catch.
1 import java . i o . ∗ ;2 public c lass Copy2 {3 public stat ic void main ( St r ing args [ ] ) {45 Fi leInputStream in ;6 FileOutputStream out ;78 int ok ;9 try {
10 in = new FileInputStream ( args [ 0 ] ) ;11 try {12 out = new13 FileOutputStream ( args [ 1 ] ) ;14 ok = 0 ;1516 while ( ok != −1) {17 try {18 ok = in . read ( ) ;19 out . wr i t e ( ok ) ;20 System . out . p r in t ( ( char ) ok ) ;21 }22 catch ( IOException e ) {23 System . out . p r i n t l n ( e . getMessage ( ) ) ;24 System . ex i t (1) ;25 }2627 }28 }29 catch ( IOException e ) {30 System . out . p r i n t l n ( e . getMessage ( ) ) ;31 System . ex i t (1) ;32 }33 }34 catch ( FileNotFoundException e ) {35 System . out . p r i n t l n ( e . getMessage ( ) ) ;36 System . ex i t (1) ;37 }38 }39 }
3
Se recomanda folosirea claselor FileReader si FileWriter atunci cand se citesc sau se scriu siruri de carac-tere. Pentru citirea sirurilor de octeti(de exemplu pentru imagini) se vor folosii clasele FileOutputStream siFileInputStream.
B. Citirea si scrierea cu ajutorul buffer-elor
Sunt folosite pentru a introduce o zona tampon tn procesul de scriere/citire a informatiilor, reducandastfel numarul de accese la dispozitivul ce reprezinta sursa originala de date. Sunt mult mai eficiente decatfluxurile fara buffer si din acest motiv se recomanda folosirea lor ori de cate ori este posibil.
Clasele pentru citirea/scrierea cu zona tampon sunt:
BufferedReader caractere
BufferedWriter caractere
BufferedInputStream octeti
BufferedOutputStream octeti
Clasele BufferedReader si BufferedInputStream citesc tn avans date si le memoreaza sntr-o zona tampon.Atunci cand se executa o operatie read(), octetul citit va fi preluat din buffer. In cazul ın care buffer-uleste gol citirea se face direct din flux si, odata cu citirea octetului, vor fi memorati ın buffer si octetii care ıiurmeaza. Similar, se lucreaza si cu clasele BufferedWriter si BufferedOutputStream.
Fluxurile de citire/scriere cu buffer sunt fluxuri de procesare si sunt folosite prin suprapunere cu altefluxuri.
Exemplu de folosire a zonei tampon pentru realizarea citirii din fisier:
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 )
In cazul constructorilor ın care dimensiunea buffer-ului nu este specificata, aceasta primeate valoarea im-plicita de 512 octeti.
Metodele acestor clase sunt cele uzuale de tipul read si write (vezi API Reader, API Writer). Pe langaacestea, clasele pentru scriere prin buffer mai au si metoda flush care goleste explicit zona tampon chiardaca aceasta nu este plina.
Exemplu pentru folosirea zonelor tampon:
1 Buf feredWriter out = new BufferedWriter (new Fi l eWr i te r ( ”out . dat” ) , 1024) ; //am crea t un f l ux cu bu f f e r de 1024o c t e t i
2 for ( int i =0; i <1024; i++)3 out . wr i te ( i ) ; // bu f f e r u l nu e s t e p l i n −> in f i s i e r nu s−a s c r i s nimic4 out . f l u s h ( ) ; // bu f f e r u l e s t e g o l i t −> dat e l e se s c r i u in f i s i e r
4
C. Intrari/Iesiri formatate
Orice program Java are:
• o intrare standard;
• o iesire standard;
• o iesire standard pentru erori;
In general intrarea standard este tastatura, iar iesirea standard este ecranul. Intrarea si iesirea standardsunt de fapt, obiecte pre-create ce descriu fluxuri de date pentru citirea respectiv scrierea la dispozitivelestandard ale sistemului. Aceste obiecte sunt definite publice ın clasa System si sunt:
Variabila Semnificatie Tip flux
System.in flux standard de intrare InputStream
System.out flux standard de iesire PrintStream
System.err flux standard pentru afisarea erorilor PrintStream
Fluxul standard de iesire se foloseste pentru afisarea datelor pe ecran, ın modul consola: Sys-tem.out.println(”mesaj”). Fluxul standard pentru afisarea erorilor se foloseste similar:
catch (IOException e) {System.err.println("Eroare de intrare/iesire!")}
Fluxurile de iesire pot fi folosite, asadar fara probleme deoarece tipul lor este PrintStream, clasa primitivapentru scrierea efectiva a datelor. In schimb, fluxul standard de intrare System.out, de tip InputStream careeste o clasa abstracta, deci pentru a-l putea utiliza va trebui sa-l folosim ımpreuna cu un flux de procesarea datelor sau cu orice alt flux ce permite citirea efectiva a datelor.
Uzual, se foloseste metoda readLine pentru citirea datelor de la tastatura si din acest motiv vom folosiintrarea standard ımpreuna cu o clasa de procesare care implementeaza metoda readLine. Exemplul tipiceste:
BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));System.out.print("Introduceti o linie:");String linie = stdin.readLine()System.out.println(linie);
Exemplu: un program care afiseaza liniile introduse de la tastatura
1 import java . i o . ∗ ;2 public c lass Af i s a r e {34 public stat ic void main ( St r ing [ ] args ) {56 BufferedReader s td in = new BufferedReader (new InputStreamReader ( System . in ) ) ;7 St r ing s ;8 try {9 while ( ( s = std in . readLine ( ) ) . l ength ( ) != 0)
10 System . out . p r i n t l n ( s ) ; //Programul se opre s t e cu o l i n i e vida11 }12 catch ( IOException e ) {13 e . pr intStackTrace ( ) ;14 }15 }16 }
Se observa ca metoda readLine poate provoca exceptii de tipul IOException.
5
II. TEME DE LABORATOR
1. Intr-un fisier se regasesc pe prima linie dimensiunile nxm ale unei matrice, iar pe urmatoarele liniielementele matricei corespunzatoare dimensiunilor date. Sa se citeasca de la tastatura ınca o matricede dimensiune mxn si sa se scrie ıntr-un alt fisier produsul celor doua matrici.(Se vor folosi claseleFileWriter, FileReader, iar citirea de la tastatura se va face folosind clasa BufferedReader)
2. Sa se citeasca de la tastatura un user si o parola. Acestea se vor compara cu ınregistrarile existente ınfisierul parole.txt. Daca user-ul si parola se regasesc printre acestea (pe aceeasi linie), se va afisa mesajul”acces permis”, daca se regaseste doar user-ul, iar parola este gresita se va afisa ”parola gresita” si seva mai cere introducerea parolei ınca o data, dar nu mai mult de 3 ori, daca se atinge acest prag se vaafisa mesajul ”cont blocat”. In caz contrar se reia procesul de introduce a datelor, dar nu mai multde 5 ori. Daca se atinge limita de 5 intrari se va afisa mesajul ”Nu ai cont. Inregistreaza-te.” (Se vorfolosi clasele FileInputStream si FileOutputStream.)Exemplu de date in fisierul parole.txt:user usergigi parolaMeauser1 parola1
3. Intr-un fisier numit clienti.txt sunt memorate date despre clientii unui magazin virtual. Pe fiecare liniese retine numele, prenumele si varsta clientilor. Se cere sa se afiseze numarul si lista clientilor majorisi numarul clientilor minori.
!!! Pentru toate problemele se vor folosii mecanisme de aruncare a exceptilor.
6
Laborator 9:
Fire de execuţie
Întocmit de: Adina Neculai
Îndrumător: Asist. Drd. Gabriel Danciu
20 noiembrie 2011
I. NOŢIUNI TEORETICE
A. Ce este un fir de execuţie?
Î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.
B. Lucrul cu fire de execuţie
Limbajul Java pune la dispoziţia programatorului, in pachetul java.lang, două clase şi o interfaţă
pentru lucrul cu thread-uri:
• clasa Thread: lucru cu thread-uri ca entităţi separate;
• clasa ThreadGroup: crearea unor grupuri de thread-uri în vederea tratării acestora în mod
unitar;
• interfaţa Runnable: lucru cu thread-uri ca entităţi separate.
1. Crearea unui thread derivând clasa Thread
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:
1. crearea unei clase obişnuite care moşteneşte clasa Thread.
class MyThread extends 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 metodamain. 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.
3. instanţierea unui obiect thread prin intermediul operatorului new;
MyThread obThread = new MyThread();
4. pornirea thread-ului instanţiat prin apelul metodei start() moştenită din clasa Thread.
obThread.start();
Urmăriţi un exemplu de lucru cu thread-uri prin derivarea clasei Thread în secţiunea IIA.
2. Crearea unui thread implementând interfaţa Runnable
Operaţiile care trebuie îndeplinite pentru a putea crea un thread prin implementarea interfeţei
Runnable sunt următorele:
1. crearea unei clase care să implementeze interfaţa Runnable.
class MyRunnable implements Runnable {
}
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. se instanţiază un obiect al clasei create utilizând operatorul new.
MyRunnable myRunnableObj = new MyRunnable();
4. se instanţiază un obiect al clasei Thread utilizând un constructor ce are ca şi parametru un
obiect de tipul clasei care implementează interfaţa Runnable.
Thread thread = new Thread(myRunnableObj);
3
5. se porneşte thread-ul.
thread.start();
Pentru o mai bună înţelegere urmăriţi exemplul prezentat în secţiunea II B.
3. Clasa Thread vs interfaţa Runnable
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.
C. Controlul unui fir de execuţie
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 IID.
E. Sincronizarea firelor de execuţie
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.
II. PREZENTAREA LUCRĂRII DE LABORATOR
A. Crearea unui thread derivând clasa Thread
Exemplul este destul de simplu şi nu necesită explicaţii suplimentare o dată ce au fost urmăriţi
paşii din secţiunea IB 1.1 public c l a s s MyThread extends Thread{
2 private int countDown = 10 ;
3
4 public void run ( ) {
5 System . out . p r i n t l n ( " \ t ␣ begin ␣run␣method . . . " ) ;
6 while ( countDown >=0){
7 System . out . p r i n t l n ( " \ t\ t ␣ Steps ␣ l e t f t ␣ to ␣do : ␣ "+countDown) ;
5
8 countDown−−;
9 }
10 System . out . 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 ( St r ing [ ] a rgs ) {
4 System . out . p r i n t l n ( " begin ␣main . . . " ) ;
5 MyThread obThread = new MyThread ( ) ;
6 System . out . p r i n t l n ( " s t a r t ␣ the ␣ thread " ) ;
7 obThread . s t a r t ( ) ;
8 System . out . p r i n t l n ( " s t i l l ␣ in ␣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().
B. Crearea unui thread implementând interfaţa Runnable
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 printMessage ( St r ing message ){
3 System . out . p r i n t l n ( message ) ;
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 Display implements Runnable {
2 private int countDown = 10 ;
3 private Thread thread ;
4
5 public MyRunnable ( ) {
6
6 thread = new Thread ( this ) ;
7 System . out . p r i n t l n ( " s t a r t ␣ the ␣ thread " ) ;
8 thread . s t a r t ( ) ;
9 }
10
11 public void run ( ) {
12 printMessage ( " \ t ␣ begin ␣run␣method . . . " ) ;
13 while ( countDown >= 0) {
14 printMessage ( " \ t\ t ␣ Steps ␣ l e t f t ␣ to ␣do : ␣ " + countDown) ;
15 countDown−−;
16 }
17 printMessage ( " \ t ␣end␣run␣method ! " ) ;
18 }
19 }
Clasa DemoRunnable instanţiază un obiect de tipul MyRunnable. Astfel se apelează construc-
torul unde se creează şi se porneşte thread-ul.1 public c l a s s DemoRunnable {
2 public s t a t i c void main ( St r ing [ ] a rgs ) {
3 System . out . p r i n t l n ( " begin ␣main . . . " ) ;
4 MyRunnable myRunnableObj = new MyRunnable ( ) ;
5 System . out . p r i n t l n ( " s t i l l ␣ in ␣main . . . " ) ;
6 }
7 }
C. Controlul unui fir de execuţie
Exemplul următor prezintă modul de utilizare al metodelor clasei Thread.
Clasa MyThread moşteneşte clasa Thread şi creează un constructor cu un parametru ce apelează
constructorul clasei de bază. Metoda run() este identică cu cea din exemplele anterioare.1 public c l a s s MyThread extends Thread{
2 private int countDown = 5 ;
3
4 public MyThread( St r ing name){
5 super (name) ;
6 }
7
8 public void run ( ) {
9 System . out . p r i n t l n ( " \ t ␣ begin ␣run␣method . . . " ) ;
10 while ( countDown >=0){
11 System . out . p r i n t l n ( " \ t\ t ␣ Steps ␣ l e t f t ␣ to ␣do : ␣ "+countDown) ;
12 countDown−−;
13 }
14 System . out . p r i n t l n ( " \ t ␣end␣run␣method ! " ) ;
15 }
16 }
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 ( St r ing [ ] a rgs ) throws Inter ruptedExcept ion {
3 System . out . p r i n t l n ( " begin ␣main␣ thread . . . " ) ;
4 MyThread myThread1 = new MyThread( " thread ␣1 " ) ;
5 myThread1 . s t a r t ( ) ;
6 System . out . p r i n t l n (myThread1 . getName ( ) ) ;
7 try {
8 myThread1 . s l e ep (4000) ;
9 } catch ( Inter ruptedExcept ion e ) {
10 e . pr intStackTrace ( ) ;
11 }
12 i f (myThread1 . i sA l i v e ( ) ) {
13 System . out . p r i n t l n (myThread1 . getName ( )+" ␣ i s ␣ a l i v e ! " ) ;
14 } e l s e{
15 System . out . p r i n t l n (myThread1 . getName ( )+" ␣ i s ␣ terminated ! " ) ;
16 }
17
18 MyThread myThread2 = new MyThread( " thread ␣2 " ) ;
19 System . out . p r i n t l n (myThread2 . getName ( ) ) ;
20 myThread2 . s t a r t ( ) ;
21 myThread1 . suspend ( ) ;
22 i f (myThread2 . i sA l i v e ( ) ) {
23 System . out . p r i n t l n (myThread2 . getName ( )+" ␣ i s ␣ a l i v e ! " ) ;
24 } e l s e{
25 System . out . p r i n t l n (myThread2 . getName ( )+" ␣ i s ␣ terminated ! " ) ;
26 }
27
28 System . out . p r i n t l n ( " be f o r e ␣main␣ thread ␣ s l e e p s " ) ;
29 Thread . s l e ep (2000) ;
30 System . out . p r i n t l n ( " a f t e r ␣main␣ thread ␣has␣ s l e p t " ) ;
31
32 myThread2 . s l e ep (2000) ;
33 myThread2 . resume ( ) ;
34 try {
35 myThread2 . j o i n ( ) ;
36 } catch ( Inter ruptedExcept ion e ) {
37 e . pr intStackTrace ( ) ;
38 }
39 myThread2 . s l e ep (1000) ;
40 System . out . p r i n t l n ( " end␣main␣ thread ! ! ! " ) ;
41 }
42 }
8
D. Priorităţi
Clasa PriorityThread implementează interfaţa Runnable şi are un constructor cu un parametru
ce setează nivelul de prioritate al thread-ului şi care instanţiază un obiect de tip thread, prezent
ca atribut al clasei. Metoda run() apelează metoda toString() a clasei Thread cât timp atributul
countDown este mai mare ca 0.1 public c l a s s Prior i tyThread implements Runnable {
2 private int countDown = 5 ;
3 private int p r i o r i t y ;
4 public Thread thread ;
5
6 public Prior i tyThread ( int p r i o r i t y ) {
7 this . p r i o r i t y = p r i o r i t y ;
8 thread = new Thread ( this ) ;
9 }
10
11 public void run ( ) {
12 thread . s e tP r i o r i t y ( p r i o r i t y ) ;
13 System . out . p r i n t l n ( " \ t ␣ begin ␣run␣method . . . " ) ;
14 while ( countDown >=0){
15 System . out . p r i n t l n ( thread . t oS t r ing ( )+" ␣countDown : ␣ "+countDown) ;
16 countDown−−;
17 }
18 System . out . p r i n t l n ( " \ t ␣end␣run␣method ! " ) ;
19 }
20 }
Clasa DemoPriority creează două obiecte de tipul PriorityThread cu parametri declaraţi ca
şi constante în clasa Thread. Se porneşte execuţia acestora şi thread-ul principal este obligat să
aştepte terminarea execuţiei celor două thread-uri anterioare înainte de a deveni inactiv.
Observaţi ordinea în care se pornesc thread-urile şi ordinea în care se execută.1 public c l a s s DemoPriority {
2 public s t a t i c void main ( St r ing [ ] a rgs ) {
3 System . out . p r i n t l n ( " begin ␣main␣ thread . . . " ) ;
4 Pr ior i tyThread threadMin = new Prior i tyThread (Thread .MIN_PRIORITY) ;
5 Pr ior i tyThread threadMax = new Prior i tyThread (Thread .MAX_PRIORITY) ;
6 threadMin . thread . s t a r t ( ) ;
7 threadMax . thread . s t a r t ( ) ;
8 try{
9 threadMax . thread . j o i n ( ) ;
10 threadMin . thread . j o i n ( ) ;
11 }catch ( Inter ruptedExcept ion e ) {
12 System . out . p r i n t l n ( " i n t e r rupt ed ␣ except ion " ) ;
13 }
14 System . out . p r i n t l n ( " end␣main␣ thread ! ! ! " ) ;
15 }
16 }
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 private Thread thread ;
4
5 public MySynchronized ( St r ing name , int count ){
6 this . count = count ;
7 thread = new Thread ( this , name) ;
8 thread . s t a r t ( ) ;
9 }
10
11 public synchronized int add ( ) {
12 count++;
13 try{
14 Thread . s l e ep (1000) ;
15 }catch ( Inter ruptedExcept ion e ) {
16 System . out . p r i n t l n ( "main␣ thread ␣ in t e r rupt ed " ) ;
17 }
18 ++count ;
19 return count ;
20 }
21
22 /∗ pub l i c i n t add ( ) {
23 synchronized ( thread ) {
24 count++;
25 try {
26 Thread . s l e ep (1000) ;
27 } catch ( Inter ruptedExcept ion e ) {
28 System . out . p r i n t l n ( " main thread in t e r rupt ed " ) ;
29 }
30 ++count ;
31 return count ;
32 }
33 }∗/
34
35 public void run ( ) {
36 System . out . p r i n t l n ( thread . getName ( ) + " ␣ s t a r t i n g . " ) ;
37 System . out . p r i n t l n ( " \ t ␣ the ␣numer␣ o f ␣ "+thread . getName ( )+" ␣ i s : ␣ "+add ( ) ) ;
38 System . out . p r i n t l n ( thread . getName ( ) + " ␣ terminat ing . " ) ;
39 }
40 }
Clasa DemoSynchronized creează două obiecte de tipul MySynchronized.1 public c l a s s DemoSynchronized {
10
2 public s t a t i c void main ( St r ing [ ] a rgs ) {
3 System . out . p r i n t l n ( " begin ␣main␣ thread . . . " ) ;
4 MySynchronized thread1 = new MySynchronized ( " thread1 " ,1) ;
5 MySynchronized thread2MySyncronized = new MySynchronized ( " thread2 " ,2) ;
6 System . out . p r i n t l n ( " begin ␣main␣ thread . . . " ) ;
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:
Interfete grafice ın Java
Intocmit de: Dobrinas Alexandra
Indrumator: Asist. Drd. Danciu Gabriel
November 30, 2011
I. NOTIUNI TEORETICE
Interfata grafica, - GUI, este un termen cu ınteles larg care se refera la toate tipurile de comunicare dintreun program si utilizatorii sai. Aceasta este o particularizare a interfetei cu utilizatorul - UI, prin care seıntelege interactiune dintre un program si utilizatorii sai. Asadar, UI se refera nu numai la ceea ce utilizatorulvede pe ecran ci si la toate mecanismele de comunicare ıntre acesta si program.
Limbajul Java pune la dispozitie numeroase clase pentru implementarea diverselor functionalitati UI, ınsaın continuare sunt prezentate acelea care permit realizarea unei intefete grafice cu utilizatorul (GUI).
Biblioteca de clase care ofera servicii grafice se numeste java.awt, AWT fiind prescurtarea de la Abstract
Window Toolkit. In principiu, crearea unei aplicatii grafice presupune urmatoarele:
• Crearea unei suprafete de afisare (cum ar fi o fereastra) pe care vor fi asezate obiectele grafice careservesc la comunicarea cu utilizatorul (butoane, controale de editare, texte, etc);
• Crearea si asezarea obiectelor grafice pe suprafata de afisare ın poziıiile corespunzatoare;
• Definirea unor actiuni care trebuie sa se execute ın momentul cand utilizatorul interactioneaza cuobiectele grafice ale aplicatiei;
• ,,Ascultarea” evenimentelor generate de obiecte ın momentul interactiunii cu utilizatorul si executareaactiunilor corespunzatoare asa cum au fost ele definite.
Printr-o componenta grafica se ıntelege un obiect care are o reprezentare grafica ce poate fi afisata peecran si care poate interactiona cu utilizatorul. Exemple de componente sunt ferestrele, butoanele, bare dedefilare, etc. In general, toate componentele sunt definte de clase proprii ce se gasesc ın pachetul java.awt.Vezi API aici.
Crearea obiectelor grafice nu realizeaza automat si afisarea lor pe ecran. Mai ıntai ele trebuie aaezate peo suprafata de afisare, care poate fi o fereastra sau suprafata unui applet, si vor deveni vizibile ın momentulın care suprafata pe care sunt afisate va fi vizibila.
In general, toate componentele sunt definte de clase proprii ce se gasesc ın pachetul java.awt, clasaComponent este o superclasa abstracta a tuturor acestor clase. Ierarhia acestor clase este sumarizata ındiagrama de mai jos.
Din cauza modului de imlementare a meniurilor pe diferite sisteme de operare, acestea nu au putut fiintegrate ca obiecte de tip Component. Superclasa cu ajutorul careia se pot crea meniuri este MenuComponent,iar subclasele sale sunt:
2
A. Suprafete de afisare
Suprafata pe care se aseaza obiectele grafice se numeste suprafata de afisare sau container si reprezintao instanta a unei clase obtinuta prin extensia superclasei Container. O parte din ierarhia a carei radacinaeste Container este prezentata ın figura de mai jos:
Componentele adaugate sunt memorate ıntr-o lista, iar pozitiile lor din aceasta lista vor defini ordineade transpunere a acestora ın cadrul containerului. Daca nu este specificat niciun index la adaugarea uneicomponente, atunci ea va fi adaugata pe ultima pozitie a listei.
1. Adaugarea unei componente
Clasa Container pune la dispozitie metoda add pentru adaugarea unei componente pe o suprafata deafisare. O componenta nu poate apartine decat unui singur container, ceea ce ınseamna ca pentru a mutaun obiect dintr-un container ın altul trebuie sa-l eliminam mai ıntai de pe containerul initial. Eliminareaunei componente de pe un container se face cu metoda remove.
Exemplu de butoane adaugate ıntr-un container:
1 import java . awt . ∗ ;2 public c lass Test1 {3 public stat ic void main ( St r ing args [ ] ) {45 // c r e e z conta iner−ul − ob i e c t de t i p frame6 Frame f = new Frame( ”O f e r e a s t r a ” ) ;78 // s e t e z modul de dipunere a ob . pe supra fa ta f e r e s t r e i9 f . setLayout (new FlowLayout ( ) ) ;
1011 // c r e e z c e l e doua butoane12 Button b1 = new Button ( ”OK” ) ;13 Button b2 = new Button ( ”Cancel ” ) ;1415 //adaug primul buton pe supra fa ta f e r e s t r e i16 f . add (b1 ) ;17 f . pack ( ) ;1819 //adaug a l d o i l e buton pe supra fa ta f e r e s t r e i20 f . add (b2 ) ;21 f . pack ( ) ;2223 // a f i s e z f e r e a s t r a ( o fac v i z i b i l a )24 f . show ( ) ;25 }26 }
3
2. Gestionarea pozitionarii componentelor ıntr-un container
Un gestionar de pozisionare layout manager este un obiect care controleaza dimensiunea si aranjarea(pozitia) componentelor unui container. Asadar, modul de aranjare a componentelor pe o suprafata de afisarenu este o caracteristica a clasei Container. Fiecare obiect de tip Container, sau o extensie a lui (Applet,Frame, Panel) are asociat un obiect care se ocupa cu dispunerea componentelor pe suprafata sa. Toateclasele care instantiaza obiecte pentru gestionarea pozitionarii implementeaza interfata LayoutManager. Lainstantierea unui container se creeaza implicit un gestionar de pozitionare asociat acestuia. De exemplu,pentru o fereastra (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 utilizati gestionari din pachetul java.awt sunt:
• FlowLayout
• BorderLayout
• GridLayout
• CardLayout
• GridBagLayout
Detalii despre modul de utilizare a gestionarilor de pozitionare se gasesc aici.
B. Gruparea componentelor (Clasa Panel)
Plasarea componentelor direct pe suprafata de afisare poate deveni incomoda ın cazul ın care avem multeobiecte grafice. Din acest motiv se recomanda gruparea obiectelor grafice ınrudite ca functii astfel ıncat saputem fi siguri ca, indiferent de gestionarul de pozitionare al suprafetei de afisare, ele se vor gasi ımpreuna.Gruparea componentelor se face folosind panel-uri.
Un panel este cel mai simplu model de container. El nu are o reprezentare vizibila, rolul sau fiind de a oferio suprafata de afisare pentru componente grafice, inclusiv pentru alte panel-uri. Clasa care instantiaza acesteobiecte este Panel, extensie a superclasei Container. Pentru a aranja corespunzator componentele grupateıntr-un panel, acestuia i se poate specifica un gestionar de pozitionare anume, folosind metoda setLayout.Gestionarul implicit pentru containerele de tip Panel este FlowLayout.
Asadar, o aranjare eficienta a componentelor unei ferestre ınseamna:
• gruparea componentelor ,,ınfratite” (care nu trebuie sa fie despartie de gestionarul de pozitionare alferestrei) ın panel-uri;
• aranjarea componentelor unui panel, prin specificarea acestuia a unui gestionar de pozitionare core-spunzator;
• aranjarea panel-urilor pe suprafata ferestrei, prin specificarea gestionarului de pozitionare al ferestrei.
Exemplu
1 import java . awt . ∗ ;2 public c lass Test2 {3 public stat ic void main ( St r ing args [ ] ) {4 Frame f = new Frame( ”Panel ” ) ;56 Panel panel = new Panel ( ) ;7 panel . setLayout (new FlowLayout ( ) ) ;8 panel . add (new Label ( ”Text : ” ) ) ;9 panel . add (new TextField ( ”” , 20) ) ;
10 panel . add (new Button ( ”Reset ” ) ) ;1112 f . add ( panel , BorderLayout .NORTH) ;13 f . add (new Button ( ”OK” ) , BorderLayout .EAST) ;14 f . add (new Button ( ”Cancel ” ) , BorderLayout .WEST) ;15 f . pack ( ) ;1617 f . show ( ) ;18 }19 }
4
C. Componente grafice
Unele dintre cele mai utilizate componente grafice sunt: etichetele, butoanele, campurile de text, listelederulante, etc. O lista completa a claselor cu ajutorul carora se definesc componentele grafice, precum siproprietatile lor se gaseste aici.
1. Clasa Label
Un obiect de tip Label (eticheta) reprezinta o componenta pentru plasarea unui text pe o suprafata deafiaare. 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 si adaugate ıntr-un container.
1 import java . awt . ∗ ;23 public c lass TestLabel {4 public stat ic void main ( St r ing args [ ] ) {5 Frame f = new Frame( ”TestLabel ” ) ;6 f . setLayout (new BorderLayout ( ) ) ;78 Label nord , sud , est , vest , centru ;9 nord = new Label ( ”Nord” , Label .CENTER) ;
10 sud = new Label ( ”Sud” , Label .CENTER) ;11 e s t = new Label ( ”Est” , Label .RIGHT) ;12 vest = new Label ( ”Vest” , Label .LEFT) ;13 centru = new Label ( ”Centru” , Label .CENTER) ;14 centru . setBackground ( Color . ye l low ) ;15 centru . setFont (new Font ( ” Ar ia l ” , Font .BOLD, 14) ) ;1617 f . add ( nord , BorderLayout .NORTH) ;18 f . add ( sud , BorderLayout .SOUTH) ;19 f . add ( est , BorderLayout .EAST) ;20 f . add ( vest , BorderLayout .WEST) ;21 f . add ( centru , BorderLayout .CENTER) ;22 f . pack ( ) ;2324 f . show ( ) ;25 }26 }
2. Clasa Button
Un obiect de tip Button se foloseste pentru plasarea unui buton etichetat pe o suprafata de afisare.Exemplu: Doua butoane adaugate pe o fereastra;
1 import java . awt . ∗ ;23 public c lass TestButton {4 public stat ic void main ( St r ing args [ ] ) {5 Frame f = new Frame( ”Button” ) ;6 f . setLayout (new FlowLayout ( ) ) ;7 f . s e t S i z e (200 , 200) ;89 Button b1 = new Button ( ”OK” ) ;
10 b1 . setBounds (30 , 30 , 50 , 70) ;11 b1 . setFont (new Font ( ” Ar ia l ” , Font .BOLD, 14) ) ;12 b1 . setBackground ( java . awt . Color . orange ) ;13 f . add (b1 ) ;1415 Button b2 = new Button ( ”Cancel ” ) ;16 b2 . setBounds (100 , 30 , 70 , 50) ;17 b2 . setForeground ( java . awt . Color . blue ) ;18 f . add (b2 ) ;19 f . pack ( ) ;20 f . show ( ) ;2122 }23 }
3. Clasa Checkbox
Un obiect de tip Checkbox reprezinta o componenta care are doua stari : selectata sau neselectata. Estefolosit pentru a prelua anumite optiuni de la utilizator.
5
1 import java . awt . ∗ ;23 public c lass TestCheckBox {4 public stat ic void main ( St r ing args [ ] ) {5 Frame f = new Frame( ”CheckBox” ) ;6 f . setLayout (new GridLayout (5 , 1) ) ;7 f . s e t S i z e (200 , 200) ;89 Label l ab e l 1 = new Label ( ” Ing r ed i en t e Pizza : ” , Label .CENTER) ;
10 l ab e l 1 . setBackground ( Color . orange ) ;11 Label l ab e l 2 = new Label ( ”” ) ;12 l ab e l 2 . setBackground ( Color . l ightGray ) ;1314 Checkbox cbx1 = new Checkbox ( ” cascava l ” ) ;15 Checkbox cbx2 = new Checkbox ( ” sunca” ) ;16 Checkbox cbx3 = new Checkbox ( ” a rde i ” ) ;1718 f . add ( l ab e l 1 ) ;19 f . add ( l ab e l 2 ) ;20 f . add ( cbx1 ) ;21 f . add ( cbx2 ) ;22 f . add ( cbx3 ) ;2324 f . pack ( ) ;25 f . show ( ) ;2627 }28 }
4. Clasa Choice
Un obiect de tip Choice defineste o lista de optiuni din care utilizatorul poate selecta una singura. La unmoment dat, din ıntreaga lista doar o singura optiune este vizibila, cea selectata ın momentul curent.
1 import java . awt . ∗ ;23 public c lass Choice {4 public stat ic void main ( St r ing args [ ] ) {5 Frame f = new Frame( ”Choice ” ) ;6 f . setLayout (new GridLayout (4 , 1) ) ;7 f . s e t S i z e (200 , 200) ;89 Label label = new Label ( ” A l ege t i cu loarea ” ) ;
10 label . setBackground ( Color . red ) ;1112 Choice c u l o r i = new Choice ( ) ;13 c u l o r i . add ( ”Rosu” ) ;14 c u l o r i . add ( ”Verde” ) ;15 c u l o r i . add ( ”Albastru ” ) ;16 c u l o r i . s e l e c t ( ”Rosu” ) ;1718 f . add ( label ) ;19 f . add ( c u l o r i ) ;2021 f . pack ( ) ;22 f . show ( ) ;2324 }25 }
5. Clasa TextField
Un obiect de tip TextField defineste un control de editare a textului pe o singura linie. Este util pentruinterogarea utilizatorului asupra unor valori.
1 import java . awt . ∗ ;23 public c lass TestText {4 public stat ic void main ( St r ing args [ ] ) {5 Frame f = new Frame( ”Text” ) ;6 f . setLayout (new GridLayout (3 , 1) ) ;7 f . s e t S i z e (200 , 200) ;8 f . setBackground ( Color . l ightGray ) ;9
10 TextFie ld nume = new TextField ( ”” , 30) ;11 TextFie ld paro la = new TextField ( ”” , 10) ;12 paro la . setEchoChar ( ’∗ ’ ) ;1314 Panel p1 = new Panel ( ) ;15 p1 . setLayout (new FlowLayout ( FlowLayout .LEFT) ) ;16 p1 . add (new Label ( ”Nume: ” ) ) ;17 p1 . add (nume) ;1819 Panel p2 = new Panel ( ) ;20 p2 . setLayout (new FlowLayout ( FlowLayout .LEFT) ) ;
6
21 p2 . add (new Label ( ”Parola : ” ) ) ;22 p2 . add ( paro la ) ;2324 Label acces = new Label ( ” In t r oduc e t i numele s i paro la ! ” , Label .CENTER) ;25 f . add (p1 ) ;26 f . add (p2 ) ;27 f . add ( acces ) ;2829 f . pack ( ) ;30 f . show ( ) ;3132 }33 }
II. TEMA
1. Compilati si rulati aplicatile prezentate. Modificati programele astfel ıncat sa se puna ın evidenta toatetipurile de ,,aranjare” a componentele pe container.
2. Realizati un program, pe o anumita tema, ın care sa utilizati cat mai multe diintre componentele cepot fi adaugate pe un container. Folositi cel putin o componenta care nu a fost prezentata ın acestlaborator(vedeti API-ul.)
3. Realizati o interfata pentru un calculator. Vezi calculatorul din Windows. Container-ul va trebui sacontina butoanele pentru cifre, butoanele pentru operatii aritmetice, ,,fereastra” pentru afisare, precumsi alte butoane necesare efectuarii calculelor aritmetice..
7
Laborator 11:
Evenimente generate de componente AWT
Întocmit de: Adina Neculai
Îndrumător: Asist. Drd. Gabriel Danciu
4 decembrie 2011
I. NOŢIUNI TEORETICE
Unei componente grafice îi este asociată:
• o formă (ceea ce este afişat pe ecran);
• o serie de evenimente la care poate răspunde (mişcări de mouse, apăsare de taste);
• un model obiectual de responsabil cu prelucrarea evenimentului (ceea ce face componenta
propriu-zis).
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
Modelul de lucru cu evenimente prezentat în această documentaţie (modelul jdk1.1) conţine
o sursă, care poate genera un eveniment, şi unul sau mai mulţi delegaţi. Sursa poate fi oricare
dintre componentele grafice. Delegaţii, numiţi şi handleri, sunt cei responsabili de răspunsul la
eveniment (cei care prelucrează informaţia provenită de la eveniment). Mai mult, ei sunt definiţi
de programator şi datorită acestui model de implementare a evenimentelor, pot fi orice ce clasă ce
implementează o interfaţă corespunzătoare evenimentului respectiv. Pe lângă implementarea clasei
delegat, programatorul este responsabil de asocierea acesteia cu sursa de evenimente. Această
asociere se poate face printr-o metodă a sursei (a componentei grafice), metodă dependentă de
tipul delegatului ce trebuie conectat.
2
Figura 1: Modelul de evenimente jdk1.1
C. Tipuri de evenimente
Diferite surse (componente grafice) pot genera diferite tipuri de evenimente.
• ActionEvent: indică dacă a avut loc o acţiune definită de o componentă;
• ComponentEvent: clasa rădăcină a evenimentelor; indică dacă o componentă şi-a modificat
dimensiunea, vizibilitatea sau dacă a fost mutată;
• ContainerEvent: specifică dacă s-a modificat conţinutul unui container în urma adăugării
sau eliminării unei componente;
• KeyEvent: precizează dacă s-a apăsat sau nu o tastă;
• MouseEvent: precizează dacă a avut loc o acţiune de genul apasarea unei taste a mouse-ului,
şamd.;
• MouseMotionEvent: precizează dacă a avut loc o acţiune de genul mişcare de mouse;
• WindowEvent: eveniment generat în momentul în care s-a deschis/inchis, activat/dezactivat
o fereastră.
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.
Componentă grafică Interfaţă Metode de asociere handler - componentă
Component ComponentListener addComponentListener(ComponentListener l)
KeyListener addKeyListener(KeyListener l)
MouseListener addMouseListener(MouseListener l)
MouseMotionListener addMouseMotionListener(MouseMotionListener l)
Button ActionListener addActionListener(ActionListener l)
CheckBox ItemListener addItemListener(ItemListener l)
Choice
List ActionListener addActionListener(ActionListener l)
ItemListener addItemListener(ItemListener l)
ComponentListener cele de la clasa Component
TextField ActionListener addActionListener(ActionListener l)
TextListener addTextListener(TextListener l)
ComponentListener cele de la clasa Component
Window ComponentListener cele de la clasa Component
Frame ContainerListener addContainerListener(ContainerListener l)
Dialog WindowListener addWindowListener(WindowListener l)
FileDialog
MenuItem ActionListener addActionListener(ActionListener l)
Menu
PopupMenu
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.
E. Componente AWT de lucru cu meniuri
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.
II. PREZENTAREA LUCRĂRII DE LABORATOR
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 java . awt . ∗ ;
6
2 import java . awt . event . Act ionL i s t ene r ;
3
4 public c l a s s TestButton {
5
6 public s t a t i c void main ( St r ing [ ] a rgs ) {
7 Frame f = new Frame( " Fereas t ra ␣Buton " ) ;
8 f . setLayout (new FlowLayout ( ) ) ;
9
10 Button b = new Button ( " Bonjour " ) ;
11 f . add (b) ;
12 b . setActionCommand ( " Bonjour " ) ;
13
14 Act ionL i s t ener a c t i onL i s t en e r = new MyButtonListener ( ) ;
15 b . addAct ionListener ( a c t i onL i s t en e r ) ;
16
17 b = new Button ( "Good␣Day" ) ;
18 f . add (b) ;
19 b . addAct ionListener ( a c t i onL i s t en e r ) ;
20
21 b = new Button ( " Aurevoir " ) ;
22 f . add (b) ;
23 b . setActionCommand ( " Exit " ) ;
24 b . addAct ionListener ( a c t i onL i s t en e r ) ;
25
26 f . pack ( ) ;
27 f . s e tV 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 java . awt . event . ∗ ;
2
3 public c l a s s MyButtonListener implements Act ionL i s t ene r {
4 public void act ionPerformed ( ActionEvent ae ) {
5 St r ing s = ae . getActionCommand ( ) ;
6 i f ( s . equa l s ( " Exit " ) ) {
7 System . e x i t (0 ) ;
8 } e l s e i f ( s . equa l s ( " Bonjour " ) ) {
9 System . out . p r i n t l n ( "Good␣Morning " ) ;
10 } e l s e {
11 System . out . p r i n t l n ( s + " ␣ c l i c k ed " ) ;
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 java . awt . ∗ ;
2 import java . awt . event . KeyListener ;
3
4 public c l a s s TestKey {
5
6 public s t a t i c void main ( St r ing [ ] a rgs ) {
7 Frame f = new Frame( " Fereas t ra ␣keyEvent " ) ;
8
9 Label label = new Label ( " S c r i e : ␣ " ) ;
10 TextFie ld tx tF i e l d = new TextFie ld (20) ;
11 KeyListener keyL i s t ene r = new MyKeyListener ( ) ;
12 tx tF i e l d . addKeyListener ( keyL i s t ene r ) ;
13
14 f . add ( txtF ie ld , BorderLayout .CENTER) ;
15 f . add ( label , BorderLayout .NORTH) ;
16
17 f . pack ( ) ;
18 f . s e tV 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 java . awt . event . ∗ ;
2
3 public c l a s s MyKeyListener implements KeyListener {
4
5 @Override
6 public void keyPressed (KeyEvent keyEvent ) {
7 char i = keyEvent . getKeyChar ( ) ;
8 St r ing s t r = Character . t oS t r ing ( i ) ;
9 System . out . p r i n t l n ( "Key␣ pres sed : ␣ "+ s t r ) ;
10
11 }
12
13 @Override
14 public void keyReleased (KeyEvent arg0 ) {}
15 @Override
16 public void keyTyped (KeyEvent arg0 ) {}
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 java . awt . ∗ ;
2 import java . awt . event . ∗ ;
3
4 public c l a s s TestMouseClick {
5 public s t a t i c void main ( St r ing [ ] a rgs ) {
6 Frame f = new Frame( " Fereas t ra ␣mouse␣ c l i c k " ) ;
7
8 Label labelY = new Label ( " 2 " ) ;
9 f . add ( labelY , BorderLayout .NORTH) ;
10 Label labelX = new Label ( " 1 " ) ;
11 f . add ( labelX , BorderLayout .CENTER) ;
12
13 Button button = new Button ( " Cl i ck ␣Me" ) ;
14 MouseListener mouseListener = new MyMouseListener ( labelX , labelY ) ;
15 button . addMouseListener ( mouseListener ) ;
16 f . add ( button , BorderLayout .SOUTH) ;
17
18 f . pack ( ) ;
19 f . s e tV i s i b l e ( true ) ;
20 }
21 }
Clasa handler se numeşte MyMouseListener şi suprascrie toate metodele interfeţei MouseListe-
ner, dar scrie cod efectiv doar pentru metoda care se declanşează în momentul apăsării unei taste
a mouse-ului. Această metodă preia informaţiile conţinute de etichetele transmise ca parametru la
instanţierea handler-ului şi afişează în consolă.1 import java . awt . Label ;
2 import java . awt . event . ∗ ;
3
4 public c l a s s MyMouseListener implements MouseListener {
5 Label labelX , labe lY ;
6
7 public MyMouseListener ( Label x , Label y ){
8 this . labe lX = x ;
9 this . labe lY = y ;
10 }
11
12 @Override
13 public void mouseClicked (MouseEvent mouseEvent ) {
14 int x = Int ege r . pa r s e In t ( labelX . getText ( ) ) ;
15 int y = Int ege r . pa r s e In t ( labelY . getText ( ) ) ;
16 System . out . p r i n t l n (x+" ␣+␣ "+y+" ␣=␣ "+(x+y) ) ;
17 }
18
19 @Override
20 public void mouseEntered (MouseEvent arg0 ) {}
21 @Override
22 public void mouseExited (MouseEvent arg0 ) {}
9
23 @Override
24 public void mousePressed (MouseEvent arg0 ) {}
25 @Override
26 public void mouseReleased (MouseEvent arg0 ) {}
27 }
D. Componenta FileDialog
La pornirea aplicaţiei se va deschide o fereastră FileDialog de tipul load cu numele ”Choose a
file”. Structura de directoare din care se porneşte este ”D:\”.1 import java . awt . ∗ ;
2
3 public c l a s s TestF i l eD ia log {
4 public s t a t i c void main ( St r ing [ ] a rgs ) {
5 Frame frame = new Frame( " Test ␣ f i l eD i a l o g " ) ;
6 F i l eD ia l og f i l eD i a l o g = new Fi l eD ia l og ( frame , " Choose␣a␣ f i l e " , F i l eD ia l og .LOAD) ;
7 f i l eD i a l o g . s e tD i r e c t o ry ( "D:\\ " ) ;
8 frame . addWindowListener (new MyFi leDia logLis tener ( f i l eD i a l o g ) ) ;
9 frame . s e tV i s i b l e ( true ) ;
10 }
11 }
În urma implementării interfeţei WindowListener trebuie suprascrise o sumedenie de metode
(vezi al doilea tabel din sectiunea IC). Cum exemplul are scris cod doar pentru metoda windowO-
pened() care se va apela în momentul în care se deschide fereastra, dorim să nu mai suprascriem
toate celelalte metode asa cum au fost definite in exemplele anterioare. Astfel că se moşteneşte
clasa WindowAdapter. Clase de tipul Adapter există pentru fiecare eveniment în parte.1 import java . awt . F i l eD ia l og ;
2 import java . awt . event . ∗ ;
3 /∗am f o l o s i t c l a s a WindowAdapter pentru a sup r a s c r i e doar anumite metode s i nu toate cum am f i f o s t
4 o b l i g a t i daca implementam i n t e r f a t a WindowListener∗/
5 public c l a s s MyFi leDia logLis tener extends WindowAdapter {
6 F i l eD ia l og f i l eD i a l o g ;
7
8 public MyFi leDia logLis tener ( F i l eD ia l og f i l eD i a l o g ) {
9 this . f i l eD i a l o g = f i l eD i a l o g ;
10 }
11
12 @Override
13 public void windowOpened (WindowEvent e ) {
14 f i l eD i a l o g . s e tV i s i b l e ( true ) ;
15 St r ing f i leName = f i l eD i a l o g . g e tF i l e ( ) ;
16 i f ( f i leName == null )
17 System . out . p r i n t l n ( "You␣ canc e l l e d ␣ the ␣ cho i c e " ) ;
18 e l s e
19 System . out . p r i n t l n ( "You␣ chose ␣ " + fi leName ) ;
20 }
21 }
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 java . awt . ∗ ;
2 import java . awt . event . ∗ ;
3
4 public c l a s s TestMenu {
5 public s t a t i c void main ( St r ing [ ] a rgs ) {
6 Frame frame = new Frame( "Meniu " ) ;
7 // se s e t eaza dimendiunea f e r e s t r e i
8 frame . s e t S i z e (100 , 100) ;
9
10 //s−a c r ea t s i s−a adaugat o bara de meniuri in f e r e a s t r a
11 MenuBar myMenuBar = new MenuBar ( ) ;
12 frame . setMenuBar (myMenuBar) ;
13
14 // se c reeaza componente Menu care se adauga in bara de meniuri
15 Menu myFileMenu = new Menu( " F i l e " ) ;
16 Menu myEditMenu = new Menu( " Edit " ) ;
17 myMenuBar . add (myFileMenu ) ;
18 myMenuBar . add (myEditMenu) ;
19
20 // se c reeaza ob i e c t e de t i p u l MenuItem
21 MenuItem myFileOpenMenuItem = new MenuItem( "Open . . . " ) ;
22 /∗ se f o l o s e s t e c l a s a MenuShortcut pt c r ea r ea unei combinat i i de t a s t e pt acce sa r ea
23 componentei MenuItem Exit ∗/
24 MenuItem myFileExitMenuItem = new MenuItem( " Exit " , new MenuShortcut (
25 KeyEvent .VK_X) ) ;
26 MenuItem myEditUndoMenuItem = new MenuItem( "Undo" , new MenuShortcut (
27 KeyEvent .VK_Z) ) ;
28
29 // se adauga f i e c a r e componente MenuItem in componenta Menu corespunzatoare
30 myFileMenu . add (myFileOpenMenuItem ) ;
31 myFileMenu . addSeparator ( ) ;
32 myFileMenu . add (myFileExitMenuItem ) ;
33 myEditMenu . add (myEditUndoMenuItem) ;
34
35 // se s e t eaza i n f o rma t i i l e ce vor f i t ransmise handler−u lu i o data cu dec l ansa rea evenimentulu i
36 myFileOpenMenuItem . setActionCommand ( " open " ) ;
37 myFileExitMenuItem . setActionCommand ( " e x i t " ) ;
38 myEditUndoMenuItem . setActionCommand ( " undo " ) ;
39
40 // se a soc i a za componentele g r a f i c e cu handler−ul MyActionListener
41 Act ionL i s t ener a c t i onL i s t n e r = new MyActionListener ( ) ;
42 myFileOpenMenuItem . addAct ionListener ( a c t i onL i s t n e r ) ;
43 myFileExitMenuItem . addAct ionListener ( a c t i onL i s t n e r ) ;
44 myEditUndoMenuItem . addAct ionListener ( a c t i onL i s t n e r ) ;
45
46 frame . s e tV i s i b l e ( true ) ;
47 }
48 }
11
Clasa handler MyActionListener :1 import java . awt . event . ∗ ;
2
3 public c l a s s MyActionListener implements Act ionL i s t ene r {
4
5 @Override
6 public void act ionPerformed ( ActionEvent e ) {
7 St r ing cmd = e . getActionCommand ( ) ;
8 i f (cmd . equa l s ( " open " ) ) {
9 System . out . p r i n t l n ( " open " ) ;
10 } e l s e i f (cmd . equa l s ( " e x i t " ) ) {
11 System . e x i t (0 ) ;
12 } e l s e i f (cmd . equa l s ( " undo " ) ) {
13 System . out . p r i n t l n ( " undo " ) ;
14 }
15 }
16 }
III. TEMĂ
1. Continuaţi exerciţiul 3 din Laborator10.pdf în felul următor:
• Implementaţi funcţionalităţile calculatorului (operaţiile aritmetice specificate). Calcu-
latorul va efectua operaţiile atât la apasarea butoanelor cu ajutorul mouse-ului cât şi
la apăsarea tastelor corespunzătoare de pe tastatură.
• Pe lângă cerinţele de implementare ale interfeţei specificate în laboratorul anterior,
adăugaţi o bară de meniu asemănătoare cu cea a calculatorului din Windows. (File:
Exit Ctrl+X; Edit: Copy Ctrl+C, Paste Ctrl+V).
Pentru nota 10 implementaţi şi funcţionalităţile meniului.
12
Laborator 12:
Interfeţe grafice în Java
Componente Swing
Întocmit de: Adina Neculai
Îndrumător: Asist. Drd. Gabriel Danciu
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:
Figura 1: Ierarhia claselor Swing şi relaţia cu clasele AWT
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);
• 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.
A. Componente grafice Swing
Cele mai folosite componente grafice sunt reprezentate în figura următoare:
Figura 2: Ierarhia componentelor Swing
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 IID.
II. PREZENTAREA LUCRĂRII DE LABORATOR
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 java . awt . ∗ ;
2 import javax . swing . ∗ ;
3
4 public c l a s s LableExample {
5 public s t a t i c Icon icon = new ImageIcon ( " r e s u r s e / smi l e . g i f " ) ;
6
7 public s t a t i c void main ( St r ing [ ] a rgs ) {
4
8 JFrame frame = new JFrame ( " Label ␣Example " ) ;
9 frame . s e t S i z e (350 , 200) ;
10 frame . setLayout (new FlowLayout ( ) ) ;
11
12 JLabel [ ] l a b e l s = new JLabel [ 9 ] ;
13 l a b e l s [ 0 ] = makeLabel ( JLabel .TOP, JLabel .LEFT, 0) ;
14 l a b e l s [ 1 ] = makeLabel ( JLabel .TOP, JLabel .CENTER, 1) ;
15 l a b e l s [ 2 ] = makeLabel ( JLabel .TOP, JLabel .RIGHT, 2) ;
16 l a b e l s [ 3 ] = makeLabel ( JLabel .CENTER, JLabel .LEFT, 3) ;
17 l a b e l s [ 4 ] = makeLabel ( JLabel .CENTER, JLabel .CENTER, 4) ;
18 l a b e l s [ 5 ] = makeLabel ( JLabel .CENTER, JLabel .RIGHT, 5) ;
19 l a b e l s [ 6 ] = makeLabel ( JLabel .BOTTOM, JLabel .LEFT, 6) ;
20 l a b e l s [ 7 ] = makeLabel ( JLabel .BOTTOM, JLabel .CENTER, 7) ;
21 l a b e l s [ 8 ] = makeLabel ( JLabel .BOTTOM, JLabel .RIGHT, 8) ;
22
23 // dezac t iveaza e t i c h e t a 0
24 l a b e l s [ 0 ] . setEnabled ( f a l s e ) ;
25
26 // se dezac t iveaza e t i c h e t a 1 . In ace s t caz , se s e t eaza a l t a imagine
27 l a b e l s [ 1 ] . setEnabled ( f a l s e ) ;
28 l a b e l s [ 1 ] . s e tD i sab l ed I con (new ImageIcon ( " r e s u r s e /no . g i f " ) ) ;
29
30 // modi f i ca d i s t an ta i n t r e imagine s i t ext l a e t i c h e t e l e 2 s i 3
31 l a b e l s [ 2 ] . setIconTextGap (15) ;
32 l a b e l s [ 3 ] . setIconTextGap (0) ;
33
34 // se adauga e t i c h e t e l e in f e r e a s t r a
35 for ( int i = 0 ; i < 9 ; i++) {
36 frame . add ( l a b e l s [ i ] ) ;
37 }
38
39 frame . s e tV i s i b l e ( true ) ;
40 }
41
42 public s t a t i c JLabel makeLabel ( int vert , int hor iz , int contor ) {
43 JLabel l = new JLabel ( " Smile ␣ " + contor , icon , SwingConstants .CENTER) ;
44 l . s e tVe r t i c a lTex tPo s i t i on ( ver t ) ;
45 l . s e tHor i zonta lTextPos i t i on ( ho r i z ) ;
46 l . setBorder ( BorderFactory . c reateLineBorder ( Color . blue ) ) ;
47 return l ;
48 }
49 }
B. Componentele JTextField şi JTextPassword
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 javax . swing . ∗ ;
2 import java . awt . ∗ ;
3
4 public c l a s s TextFieldExample {
5
5
6 public s t a t i c void main ( St r ing [ ] a rgs ) {
7 JFrame frame = new JFrame ( " TextFie ld ␣Example " ) ;
8
9 JLabel lastNameLabel = new JLabel ( " Last ␣Name" , SwingConstants .LEFT) ;
10 JLabel f i r stNameLabel = new JLabel ( " F i r s t ␣Name" , SwingConstants .CENTER) ;
11 JLabel passwordLabel = new JLabel ( " Password " , SwingConstants .RIGHT) ;
12
13 JTextField lastNameTF = new JTextFie ld (15) ;
14 lastNameTF . setFont (new Font ( " bold " , Font .BOLD, 12) ) ;
15 lastNameTF . setHor izonta lAl ignment ( JTextFie ld .RIGHT) ;
16
17 JTextField firstNameTF = new JTextFie ld ( ) ;
18 firstNameTF . setFont (new Font ( " i t a l i c " , Font . ITALIC , 13) ) ;
19 firstNameTF . setHor izonta lAl ignment ( JTextField .CENTER) ;
20
21 JPasswordField passwordTF = new JPasswordField ( ) ;
22
23 JPanel p = new JPanel ( ) ;
24 p . setLayout (new GridLayout (3 , 1) ) ;
25
26 p . add ( lastNameLabel ) ;
27 p . add ( lastNameTF) ;
28 p . add ( f i rstNameLabel ) ;
29 p . add ( firstNameTF ) ;
30 p . add ( passwordLabel ) ;
31 p . add ( passwordTF ) ;
32
33 frame . add (p) ;
34
35 frame . pack ( ) ;
36 frame . s e tV 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 java . awt . ∗ ;
2 import javax . swing . ∗ ;
3
4 public c l a s s ButtonExample {
5
6 public s t a t i c void main ( St r ing args [ ] ) {
7 JFrame frame = new JFrame ( " JButton␣Example " ) ;
8 frame . s e t S i z e (300 , 100) ;
9
10 JPanel panel = new JPanel ( ) ;
11 panel . setLayout (new FlowLayout ( FlowLayout .LEFT) ) ;
12
13 JButton cutButton = new JButton ( "Cut " ) ;
14 cutButton . setToolTipText ( " Tool t ip : ␣buton␣ cut " ) ;
15 JButton copyButton = new JButton (new ImageIcon ( " r e s u r s e /copy . g i f " ) ) ;
16 copyButton . setToolTipText ( " Too l t ip : ␣buton␣copy " ) ;
17
18 St r ing buttonName = " Paste " ;
19 St r ing icon = " r e su r s e / paste . g i f " ;
20 f i n a l char key = buttonName . charAt (0) ;
21 JButton pasteButton = new JButton (buttonName , new ImageIcon ( i con ) ) ;
22 pasteButton . setMnemonic ( key ) ;
23 pasteButton . setToolTipText ( " Too l t ip : ␣buton␣ paste " ) ;
24
25 panel . add ( cutButton ) ;
26 panel . add ( copyButton ) ;
27 panel . add ( pasteButton ) ;
28
29 frame . add ( panel , BorderLayout .NORTH) ;
30
31 frame . s e tV 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 java . awt . GridLayout ;
2 import javax . swing . ∗ ;
3
4 public c l a s s MenuExample {
5
7
6 public s t a t i c void main ( St r ing s [ ] ) {
7 JFrame frame ;
8 JMenuBar menuBar ;
9 JMenu menu , submenu ;
10 JMenuItem menuItem ;
11 JRadioButtonMenuItem rbMenuItem ;
12 JCheckBoxMenuItem cbMenuItem ;
13
14 frame = new JFrame ( "Menu␣example " ) ;
15 frame . s e t S i z e (200 , 200) ;
16
17 // se c reeaza bara de meniu
18 menuBar = new JMenuBar ( ) ;
19 menuBar . setLayout (new GridLayout (2 , 1 ) ) ;
20
21 // se c on s t r u i e s t e primul meniu
22 menu = new JMenu( "Un␣Meniu " ) ;
23 menuBar . add (menu) ;
24
25 //un grup de componente JMenuItems
26 menuItem = new JMenuItem( "Doar␣ text " ) ;
27 menu . add (menuItem) ;
28
29 menuItem = new JMenuItem( " S i ␣ text ␣ s i ␣ imagine " , new ImageIcon ( " 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 ImageIcon ( " 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 radio−buton
36 menu . addSeparator ( ) ; //adauga l a s f a r s i t u l grupu lu i de componente an t e r i o a r e o l i n i e o r i z on ta l a ,
cons ide ra ta separa to r
37 ButtonGroup group = new ButtonGroup ( ) ;
38
39 rbMenuItem = new JRadioButtonMenuItem ( " o␣componenta␣ radio−button " ) ;
40 rbMenuItem . s e t S e l e c t e d ( true ) ;
41 // butonul rad io se adauga grupu lu i s i meniului
42 group . add ( rbMenuItem ) ;
43 menu . add ( rbMenuItem ) ;
44
45 rbMenuItem = new JRadioButtonMenuItem ( " a l t a ␣componenta␣ radio−buton " ) ;
46 group . add ( rbMenuItem ) ;
47 menu . add ( rbMenuItem ) ;
48
49 // un grup de componente check−box
50 menu . addSeparator ( ) ;
51 cbMenuItem = new JCheckBoxMenuItem( " o␣componenta␣check−box " ) ;
52 menu . add ( cbMenuItem) ;
53
54 cbMenuItem = new JCheckBoxMenuItem( " a l t a ␣componenta␣check−box " ) ;
55 menu . add ( cbMenuItem) ;
56
57 // un submeniu
58 menu . addSeparator ( ) ;
59 submenu = new JMenu( " Submeniu " ) ;
60
61 menuItem = new JMenuItem( " a l t ␣ ob i e c t ␣ in ␣submeniu " ) ;
62 submenu . add (menuItem) ;
63
8
64 menu . add ( submenu ) ;
65
66 // se c on s t r u i e s t e a l d o i l e a meniu ce se adauga in bara de meniu
67 menu = new JMenu( " Alt ␣Meniu " ) ;
68 menuItem = new JMenuItem( " ob i e c t ␣ in ␣Alt ␣Meniu " ) ;
69 menu . add (menuItem) ;
70 menuBar . add (menu) ;
71
72 // se ataseaza f e r e s t r e i bara de meniu
73 frame . setJMenuBar (menuBar ) ;
74
75 frame . pack ( ) ;
76 frame . s e tV i s i b l e ( true ) ;
77 }
78 }
III. TEMĂ
1. Realizaţi cerinţele 2 şi 3 din Laborator10.pdf. Folosiţi componente din pachetul javax.swing.
Consultaţi figura din secţiunea IA şi API-ul.
9
Laborator Nr. 13:
Evenimente generate de Componente SWING
Intocmit de: Dobrinas Alexandra
Indrumator: Asist. Drd. Danciu Gabriel
January 8, 2012
I. NOTIUNI TEORETICE
Asa cum este precizat si ın Laboratorul 11, un eveniment reprezinta o instanta a unei clase Java, instantacare contine o serie de informatii despre actiunea utilizatorului asupra unei componente grafice. Un ,,eveni-ment” poate fi ınteles, aici, ca un eveniment asincron, independent de evolutia programului si al carui momentde producere nu poate fi prevazut la scrierea codului. Evenimentele cele mai des ıntalnite sunt:
• apasarea unei taste;
• actionarea unui buton de mouse;
• deplasarea cursorului peste anumite zone;
Pentru gestionarea unui eveniment sunt implicati trei participanti:
• sursa evenimentului - obiectul a carui stare se modifica;
• obiectul eveniment - reprezinta evenimentul ın sine;
• event listener - obiectul ce trebuie anuntat despre modificarea ce se produce;
A. Aparitia si tratarea evenimentelor
La fel ca si ın AWT, si ın SWING sunt folositi delegati - handleri pentru prelucrarea informatiei provenitade la eveniment, precum si ascultatori - listeneri pentru tratarea evenimentelor. Ceea ce se ıntampla laaparitia unui eveniment este ilustrat ın figura de mai jos:
Se apeleaza un ascultator atunci cand utilizatorul interactioneaza cu interfata, ceea ce provoaca un eveni-ment. Desi evenimentele provin de obicei din interfata utilizator, ele pot avea si alte surse: conexiunea lainternet, window manager, timer, etc. In functie de ce anume a declansat aparitia unui eveniment existainterfete care se folosesc pentru prelucrarea sa:
2
Asocierea dintre componenta si handler se face cu ajutorul interfetelor Listener astfel:
Componenta Interfata Metode asociate
JButton
JTextField ActionListener actionPerformed(ActionEvent e)
JMenuItem
JSlider ChangeListener stateChanged(ChangeEvent e)
JCheckBox ItemListenerr itemstateChanged()
key keyPressed()
on KeyListener keyReleased()
component keyTyped()
mouseClicked()
mouse mouseEntered()
on MouseListener mouseExited()
component mousePressed()
mouseReleased()
mouse on MouseMotionListener() mouseMoved())
component mouseDragged()
JFrame WindowListener() windowClosing(WindowEvent e)
II. PREZENTAREA LUCRARII DE LABORATOR
Pentru prelucrarea evenimentelor generate de butoane trebuie folosit un handler care sa implementezeinterfata Listener corespunzatoare actiunii ce se monitorizeaza.
A. Interfata ActionListener
Evenimentele care se prelucreaza cu ajutorul metodelor suprascrise din aceasta interfata sunt evenimentelecare se genereaza la folosirea butonelor, a meniurilor etc. Pentru prelucrarea acestor evenimente trebuie sase utilizeze o clasa handler (aici HandlerButoane) ce implementeaza interfata ActionListener, si suprascriemetoda actionPerformed(ActionEvent e).
1 import javax . swing . ∗ ;2 import javax . swing . border . ∗ ;
3
3 import java . awt . ∗ ;4 import java . awt . event . ∗ ;56 c lass HandlerButoane implements Act ionL i s t ener {78 private int nrCl ick = 0 ;9 private int i nd i ceCu loare = 0 ;
10 f ina l private Color c u l o r i [ ] = {Color .LIGHT GRAY, Color .RED, Color .ORANGE, Color .PINK } ;1112 public void act ionPerformed ( ActionEvent e ) {1314 JButton butonApasat = ( JButton ) e . getSource ( ) ;1516 // in f un c t i e de denumirea evenimentulu i generat de buton se implementeaza o anumita act iune :1718 // pentru butonul ” contor ”19 i f ( butonApasat . getActionCommand ( ) . equa l s ( ” contor ” ) ) {20 nrCl ick++;21 butonApasat . setText ( ”Apasat : ” + nrCl ick ) ;22 }2324 // pentru butonul ” cu loa re ”25 i f ( butonApasat . getActionCommand ( ) . equa l s ( ” cu loa re ” ) ) {26 ind i ceCu loare++;27 i f ( ind i ceCu loare == cu l o r i . l ength )28 ind i ceCu loare = 0 ;29 butonApasat . setBackground ( c u l o r i [ ind i ceCu loare ] ) ;30 }3132 // pentru butonul ” ex i t ”33 i f ( butonApasat . getActionCommand ( ) . equa l s ( ” ex i t ” ) ) {34 System . ex i t (0) ;35 }36 }37 }
1 public c lass TestButoane extends JFrame {23 public stat ic void main ( St r ing args [ ] ) {4 TestButoane app = new TestButoane ( ) ;56 // c rea rea propriu−z i s a a butoane lor7 JButton butonulNumara = new JButton ( ”Apasa : 0” ) ;8 butonulNumara . setActionCommand ( ” contor ” ) ;9 butonulNumara . setAlignmentX (Component .CENTER ALIGNMENT) ;
1011 JButton butonulCulor i = new JButton ( ”Schimba cu loarea ” ) ;12 butonulCulor i . setActionCommand ( ” cu loa re ” ) ;13 butonulCulor i . setAlignmentX (Component .CENTER ALIGNMENT) ;1415 JButton butonulExit = new JButton ( ”Exit ” ) ;16 butonulExit . setActionCommand ( ” ex i t ” ) ;17 butonulExit . setAlignmentX (Component .CENTER ALIGNMENT) ;181920 // s e ta r ea de l i s t e n e r i pentru f i e c a r e buton in parte21 butonulNumara . addAct ionListener (new ButtonHandler ( ) ) ;22 butonulCulor i . addAct ionListener (new ButtonHandler ( ) ) ;23 butonulExit . addAct ionListener (new ButtonHandler ( ) ) ;242526 // adaugarea butoane lor in Panel27 JPanel panou = new JPanel ( ) ;28 panou . setLayout (new BoxLayout ( panou , BoxLayout . Y AXIS) ) ;2930 panou . add ( butonulNumara ) ;31 panou . add (Box . createRig idArea (new Dimension (0 , 10) ) ) ;32 panou . add ( butonulCulor i ) ;33 panou . add (Box . createRig idArea (new Dimension (0 , 10) ) ) ;34 panou . add ( butonulExit ) ;35 panou . setBorder ( BorderFactory . createEmptyBorder (20 , 20 , 20 , 20) ) ;3637 app . getContentPane ( ) . add ( panou ) ;38 app . pack ( ) ;39 app . se tDe fau l tCloseOperat ion ( JFrame .EXIT ON CLOSE) ;40 app . show ( ) ;41 }42 }
B. Interfata KeyListener
Pentru evenimentele generate cu ajutorul tastaturii trebuie sa se utilizeze o clasa han-dler (aici KeyHandler) ce implementeaza interfata KeyListener, si suprascrie metodelekeyPressed(), keyReleased(), keyTyped(). Nu este obligatoriu sa se implementeze toate metodele dacaaplicatia nu necesita acest lucru.
1 import java . awt . event . ∗ ;23 public c lass KeyHandler implements KeyListener {4
4
5 @Override6 public void keyPressed (KeyEvent keyEvent ) {7 char i = keyEvent . getKeyChar ( ) ;8 St r ing s t r = Character . t oS t r ing ( i ) ;9 System . out . p r i n t l n ( ”Key pressed : ”+ s t r ) ;
1011 }1213 @Override14 public void keyReleased (KeyEvent arg0 ) {}15 @Override16 public void keyTyped (KeyEvent arg0 ) {}17 }
1 mport java . awt . ∗ ;2 import javax . swing . ∗ ;34 public c lass TestKey {56 public stat ic void main ( St r ing [ ] args ) {7 JFrame f = new JFrame ( ” Fereas t ra keyEvent ” ) ;8 f . setLayout (new FlowLayout ( ) ) ;9
10 JLabel label = new JLabel ( ” S c r i e : ” ) ;11 JTextField tx tF i e l d = new JTextField (20) ;121314 KeyHandler keyH = new Keyhandler ( ) ;15 tx tF i e l d . addKeyListener ( keyH ) ;1617 f . add ( label ) ;18 f . add ( tx tF i e l d ) ;192021 f . pack ( ) ;22 f . s e tV i s i b l e ( true ) ;23 }24 }
C. Interfata MouseListener
Evenimentele generate de mouse, clasa handler trebuie sa implementeze interfata MouseListener si sasuprascrie metodele: mouseClicked(),mouseEntered(), mouseExited(), mousePressed(), mouseReleased().la fel ca si la evenimentele pentru taste, daca nu se cere utilizarea tuturor metodelor, nu este necesaraimplemetarea lor.
12 import java . awt . event . ∗ ;3 import javax . swing . ∗ ;456 public c lass MyMouseListener implements MouseListener {78 JLabel labelX , labelY ;9 public MyKeyListener ( JLabel x , JLabel y )
10 {11 this . labelX = x ;12 this . labelY = y ;13 }141516 @Override17 public void mouseClicked (MouseEvent e ) {18 int x = Intege r . pa r s e In t ( labelX . getText ( ) ) ;19 int y = Intege r . pa r s e In t ( labelY . getText ( ) ) ;20 System . out . p r i n t l n ( x+” + ”+y+” = ”+(x+y ) ) ;212223 }2425 @Override26 public void mouseEntered (MouseEvent e ) {27 // TODO Auto−generated method stub2829 }3031 @Override32 public void mouseExited (MouseEvent e ) {33 // TODO Auto−generated method stub3435 }3637 @Override38 public void mousePressed (MouseEvent e ) {39 // TODO Auto−generated method stub4041 }4243 @Override44 public void mouseReleased (MouseEvent e ) {
5
45 // TODO Auto−generated method stub4647 }4849 }
1 import java . awt . ∗ ;2 import javax . swing . ∗ ; ;34 public c lass TestMouse {5 public stat ic void main ( St r ing [ ] args ) {6 Frame f = new Frame ( ” Fereas t ra mouse c l i c k ” ) ;78 JLabel labelY = new JLabel ( ”2” ) ;9 f . add ( labelY , BorderLayout .NORTH) ;
10 JLabel labelX = new JLabel ( ”1” ) ;11 f . add ( labelX , BorderLayout .CENTER) ;1213 JButton button = new JButton ( ” Cl ick Me” ) ;14 MyMouseListener mouseListener = new MyMouseListener ( labelX , labelY ) ;15 button . addMouseListener ( mouseListener ) ;16 f . add ( button , BorderLayout .SOUTH) ;1718 f . pack ( ) ;19 f . s e tV i s i b l e ( true ) ;20 }21 }
D. Interfata WindowListener
Se foloseste pentru evenimentele care au loc la deschiderea, ınchiderea unei ferestre sau ın momentul ıncare o fereastra este sau nu activa. Spre deosebire de celelalte interfete, pentru aceasta trebuie suprascrisetoate metodele:
Metoda Descriere
windowActivated(WindowEvent e) se apeleaza cand fereastra devine activa
windowClosed(WindowEvent e) se apeleaza la ınchiderea ferestrei
windowClosing(WindowEvent e) se apeleaza in momentul ın care se ıncearca ınchiderea ferestrei
windowDeactivated(WindowEvent e) se apeleaza cand fereastra nu mai este activa
windowDeiconified(WindowEvent e) se apeleaza cand fereastra isi modifica starea
din minimize(din taskbar) ın starea normala (pe ecran)
windowIconified(WindowEvent e) se apeleaza cand fereastra isi modifica starea
din starea normala (de pe ecran) ın minimize (ın taskbar)
windowOpened(WindowEvent e) se apeleaza cand fereastra devine vizibila
In cazul ın care se doresc efectuarea unor operatii pentru anumite evenimente clasa handler poate extindeclasa WindowAdapter si astfel vor putea fi suprascrise doar metodele dorite.
1 import java . awt . ∗ ;2 import javax . swing . ∗ ;345 public c lass TestWindow {6 public stat ic void main ( St r ing [ ] args ) {78 JFrame f = new JFrame ( ” t e s t ” ) ;9 f . s e t S i z e (150 , 150) ;
1011 f . addWindowListener (new MyWindowListener ( ) ) ;12 f . s e tV i s i b l e ( true ) ;13 }14 }
1 import java . awt . ∗ ;2 import java . awt . event . ∗ ;345 public c lass MyWindowListener extends WindowAdapter {67 public void windowClosing (WindowEvent event ) {8 System . out . p r i n t l n ( ”Eveniment pe f e r e s t r e ” ) ;9 System . ex 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 pentrumeniuri din AWT.
1 import java . awt . ∗ ;2 import java . awt . event . Act ionL i s t ener ;34 import javax . swing . ∗ ;56 public c lass TestMeniuri {7 public stat ic void main ( St r ing [ ] args ) {89 JFrame frame = new JFrame ( ”Meniu ” ) ;
1011 frame . s e t S i z e (100 , 100) ;121314 JMenuBar myMenuBar = new JMenuBar ( ) ;15 myMenuBar . setLayout (new GridLayout ( 1 , 2 ) ) ;16 frame . setJMenuBar (myMenuBar ) ;171819 JMenu myFileMenu = new JMenu( ” F i l e ” ) ;20 JMenu myEditMenu = new JMenu( ” Edit ” ) ;21 myMenuBar . add (myFileMenu ) ;22 myMenuBar . add (myEditMenu) ;232425 JMenuItem myFileOpenMenuItem = new JMenuItem( ”Open . . . ” ) ;2627 JMenuItem myFileExitMenuItem = new JMenuItem( ” Exit ” ) ;28 JMenuItem myEditUndoMenuItem = new JMenuItem( ”Undo” ) ;293031 myFileMenu . add (myFileOpenMenuItem ) ;32 myFileMenu . addSeparator ( ) ;33 myFileMenu . add (myFileExitMenuItem ) ;34 myEditMenu . add (myEditUndoMenuItem) ;353637 myFileOpenMenuItem . setActionCommand ( ” open ” ) ;38 myFileExitMenuItem . setActionCommand ( ” ex i t ” ) ;39 myEditUndoMenuItem . setActionCommand ( ” undo ” ) ;404142 Act ionL i s t ener a c t i onL i s tn e r = new MyMenuListener ( ) ;43 myFileOpenMenuItem . addAct ionListener ( a c t i onL i s tn e r ) ;44 myFileExitMenuItem . addAct ionListener ( a c t i onL i s tn e r ) ;45 myEditUndoMenuItem . addAct ionListener ( a c t i onL i s tn e r ) ;4647 frame . s e tV i s i b l e ( true ) ;48 }49 }
1 import java . awt . event . ∗ ;23 public c lass MyMenuListener implements Act ionL i s t ener {45 @Override6 public void act ionPerformed ( ActionEvent e ) {7 St r ing cmd = e . getActionCommand ( ) ;89 i f (cmd . equa l s ( ” open ” ) ) {
10 System . out . p r i n t l n ( ” open ” ) ;11 }12 else13 i f (cmd . equa l s ( ” ex i t ” ) ) {14 System . out . p r i n t l n ( ” ex i t ” ) ;15 System . ex i t ( 0 ) ;1617 }18 else19 i f (cmd . equa l s ( ” undo ” ) ) {20 System . out . p r i n t l n ( ” undo ” ) ;21 }22 }23 }
III. TEMA
Adaugati evenimente pentru calculatorul realizat ın SWING.
7