Sunteți pe pagina 1din 126

Tehnologii Java 

DEPARTAMENTUL DE INFORMATICĂ 
LUCRARE DE LABORATOR 1 

Elemente de baza ale limbajului Java 


I. SCOPUL LUCRĂRII 

Lucrarea de faţă are rolul de a prezenta şi familiariza studentul cu noţiuni şi elemente de bază ale  
limbajului Java cum ar fi: Setul de caractere, Cuvinte cheie, Cuvinte rezervate, Identificatori, Literali, 
Separatori, Comentarii, Operatori, Variabile, Expresii, Vectori. 
La sfârşitul acestei lucrări, studentul va avea posibilitatea să scrie programe Java în care să 
utilizeze elementele limbajului menţionate mai sus. 

II. NOŢIUNI TEORETICE 

Prezentarea si operarea cu IDE-urile actuale 

Observaţie: Vezi capitolul 1 din curs. 

Primul program Java 

import java.io.*; 
class PrimulProgram{ 
public static void main(String[ ] arg) {  
System.out.print("Primul program Java");  
System.out.println(". . . dar nu si ultimul!"); 

Din secventa de mai sus se poate constata, la o prima privire, ca cel putin elementele de 
delimitare a propozitiilor sunt foarte asemanatoare cu cele din C: este vorba despre acolade si 
caracterele ; de la sfarsitul instructiunilor. 
Programul prezentat nu face altceva decat sa afiseze o secventa de caractere pe ecran, dar poate 
servi la evidentierea unor elemente de baza care apar in orice program Java. In primul rand
trebuie spus ca programele Java sunt constituite ca seturi de clase. 

NU EXISTA ceea ce in programele C numim date globale. 


De asemenea, NU EXISTA functii de sine statatoare: avem DOAR functii (metode) 
incluse in clase. 

Pentru descrierea unei clase se foloseste o constructie sintactica de

forma: class nume_clasa { 

//continut clasa 
}
 

Apoape orice program, indiferent ca este scris intr-un limbaj procedural sau obiectual, are o 
radacina sau un punct de plecare. Astfel, in programele Pascal avem ceea ce se numeste 
program principal, iar in C avem functiamain. 
In programele Java vom avea o clasa principală (radacină) care se caracterizeaza prin 
faptul ca include o functie al carei prototip este: 

public static void main(String[ ] arg) 

Elementele desemnate prin cuvintele public si static vor fi lamurite putin mai tarziu. 
Deocamdata le folosim asa cum le vedem. 
Numele clasei radacina este un identificator dat de programator. 
Parametrul functiei main este de tip tablou de elemente String (siruri de caractere). Prin 
intermediul acestui parametru putem referi si utiliza in program eventualele argumente 
specificate la lansarea in executie a programului. 
In ceea ce priveste clauza import plasata chiar la inceput, ea se refera la faptul ca programul 
utilizeaza operatii ale unor clase aflate in pachetul numit java.io. 
Actiunile executate de programul de mai sus presupun două operatii de afisare: print si
println.  Observam modul putin mai ciudat de apel al acestor operatii. Prefixul System.out
care insoteste  numele celor două operatii reprezinta numele unui obiect: este vorba despre un
obiect predefinit  care se utilizeaza atunci cand destinatia unei operatii de scriere este ecranul
monitorului. Asa  dupa cum vom vedea si in lucrarile urmatoare, deoarece metodele sunt
incluse in clase si,  majoritatea, si in instantele claselor, apelul presupune precizarea numelui
clasei (daca e vorba de  metode statice) sau al obiectului "posesor". Cu alte cuvinte, in Java,
apelul unei operatii se  realizeaza folosind una din notatiile: 

nume_obiect.nume_metoda(parametri_actuali)  
sau:  
nume_clasa.nume_metoda(parametri_actuali) 

Pe parcurs vom clarifica diferentele dintre cele două tipuri de notatii. 


Metodele print/println pot primi ca parametru un sir de caractere dat fie sub forma de
constanta,  asa ca in exemplul nostru, fie sub forma de expresii al caror rezultat este de tip
String. Metodele  print/println mai pot primi ca parametru si valori ale tipurilor primitive sau
referinte de clase,  dar acestea sunt convertite tot la tipul String inainte de afisare. Diferenta
dintre print si println  este aceea ca println realizeaza, dupa afisarea textului dat ca
parametru, un salt la linie noua. Se  precizeaza ca println poate fi apelata si fara parametri, caz
in care executa doar un salt la linie  noua: 

System.out.println( ); 

Am afirmat ca parametrul metodei main din clasa radacina serveste la accesarea eventualelor 
argumente date in linia de comanda la lansarea in executie a programului. Pentru a ilustra acest 
aspect, vom considera un program care afiseaza o formula de salut, urmata de numele si 
prenumele utilizatorului, date ca argumente: 

import java.io.*;  
class Salutare{ 
public static void main(String[ ] arg) {  
System.out.println("Te salut, "+arg[0]+" "+arg[1]); 

Dupa ce compilam acest program, il putem lansa in executie de exemplu cu comanda:


 

java Salutare mai Popescule 

Observatii: 
Programului i se dau 2 argumente (mai si Popescule). Acestea sunt interpretate ca 
primele 2 elemente ale tabloului arg ce figureaza ca parametru formal al metodei 
main (se poate spune ca arg este un omolog al lui _argv din programele C). La fel ca 
si in C, in Java elementele unui tablou se indexeaza incepand cu 0. 

Daca programului nu i se furnizeaza cele 2 argumente, rezultatul este oprirea  executiei


cu un mesaj prin care se reclama depasirea indicelui de tablou 
(IndexOutOfBoundsException).Estevorbadetabloulargcarearedimensiunea0in 
cazul lipsei argumentelor. 
De aceea, daca dorim sa fim mai rigurosi, e bine sa prevedem secvente de verificare 
in program, prin care sa testam daca utilizatorul a furnizat numarul necesar de 
parametri: 

import java.io.*;  
class Salutare{ 
public static void main(String[ ] arg) {  
if(arg.length<2) 
System.out.println("Nu ati dat parametrii necesari!!");   
else 
System.out.println("Te salut, "+arg[0]+" "+arg[1]); 


Expresia arg.length utilizata in secventa de mai sus ne da numarul de elemente ale 
tabloului arg. Posibilitatea de a folosi aceasta expresie explica de ce metoda main nu 
are nevoie de un al 2-lea parametru, omolog al lui _argcdin programele C. 

O alta observatie care trebuie facuta in contextul acestui exemplu priveste parametrul 
functiei println. De data acesta am folosit o expresie construita prin aplicarea 
operatorului + asupra unor operanzi de tip String, al carei rezultat este un sir de 
caractere obtinut prin concatenarea operanzilor. 
Ceea ce trebuie sa retinem de aici este faptul ca, spre deosebire de functiile printf
din  C, care acceptau un numar variabil de parametri, functiile print/println din
Java  accepta UN SINGUR parametru. Ca urmare, atunci cand dorim sa scriem
printr-o  singura instructiune mai multe valori trebuie sa le concatenam, spre a forma
un  singur sir. 

Elemente de bază ale limbajului Java 

Observaţie: Vezi capitolul 1 din curs. 

1. Variabile automatice şi iniţializarea lor 

O variabilă automatică este o variabilă locală unei metode (este creată la intrarea în
metodă,  există numai pe durată execuţiei metodei). 
Variabilele locale nu sunt iniţializate de către sistem şi trebuie iniţializate explicit înainte de a
fi  utilizate. 

class VarLoc{
 

public static void main(String args[]){  


int i; 
i=i+5;  
System.out.println(i); 


În exemplul de mai sus, compilatorul semnalează o eroare la linia 4 “Variable i might not
have been initialized”. 

2. Operatori în limbajul Java 

Operatorul modulo % 
class TestModulo{ 
public static void main(String args[]){  
int i=33,j=6;  
System.out.println(i%j); 
int a=-29,b=4;  
System.out.println(a%b);  
float f1=10.7f,f2=4.5f;  
System.out.println(f1%f2);  
double d1=-8.7d,d2=-4.5d;  
System.out.println(d1%d2); 

Exerciţiu: Să se verifice printr-un calcul pe hârtie, valorile afişate de program. 

Operatorii de deplasare <<, >>, >>> 

Operanzii trebuie să fie de un tip întreg, în general int sau long. 


Operandul din partea dreaptă este redus modulo x, unde x depinde de tipul rezultatului
operaţiei.  Tipul este fie int, fie long, operatorii de tip mai mic fiind supuşi promovării aritmetice. Dacă
operatorul  din partea stângă este de tip int atunci x este 32, iar dacă acesta este de tip long atunci x este
64. 
Operatorul << deplasează spre stânga şi biţi de 0 sunt introduşi pe poziţiile cele mai puţin  
semnificative. Deplasarea spre stânga cu o poziţie corespunde dublării operandul stâng, deplasarea spre 
stânga cu mai mult de o poziţie corespunde înmulţirii operandului stâng cu 2,4,8,16, ş.a.m.d. 
Operatorul >> efectuează o deplasare cu semn (sau aritmetică) spre dreapta. Rezultatul are biţi
de 0 pe cele mai semnificative poziţii dacă operandul stâng este pozitiv, şi biţi de 1 pe cele mai 
semnificative poziţii dacă operandul stâng este negativ. Rezultatul aproximează împărţirea operandului 
stâng la 2 ridicat la puterea operandului drept. 
Operatorul >>> efectuează o deplasare fără semn (sau logică) spre dreapta. Rezultatul are biţi
de  0 pe cele mai semnificative poziţii şi poate să nu reprezinte întotdeauna o divizare a operandului
stâng.  Exemplu: 

class TestOpShift{ 
public static void main(String args[]){  
int i=192;  
System.out.println(i<<2);  
System.out.println(i>>2);  
System.out.println(i<<33); 
long j=-192;  
System.out.println(j<<1);  
System.out.println(j>>2);  
System.out.println(j>>66);  
System.out.println(64>>>4);  
System.out.println(-64>>>4);
 


Operatorul condiţional ?: 

Observaţie: 
Într-o expresie de forma a= x ? b : c 
- tipurile expresiilor b şi c trebuie să fie compatibile şi sunt făcute identice prin
promovare  aritmetică 
- tipul expresiei x trebuie să fie boolean 
- tipul expresiilor b şi c trebuie să fie compatibile la asignare cu tipul lui a 
- valoarea asignată lui a va fi b dacă x este adevărat, sau va fi c dacă x este fals 

Operatorii de asignare 

Observaţii: 
Operatorii de asignare setează valoarea unei variabile sau expresii la o nouă valoare. Asignarea  
simplă utilizează =. Operatori ca “+=” şi “*=” au o funcţie compusă de calcul şi asignare. Aceşti 
operatori compuşi au forma generală “op=”, unde op poate oricare dintre operatorii binari non-
booleeni.  În general, pentru orice expresii compatibile x şi y, expresia x op=y este o prescurtare pentru
x=x op y. 
Totuşi trebuie avute în vedere două aspecte. Primul se referă la faptul că expresia x este
evaluată  exact o dată în cazul primei scrieri, ci nu de 2 ori aşa cum se sugerează în cazul utilizării
scrierii  expandate. Al doilea aspect se referă la faptul că operatorii de asignare includ un “cast”
(conversie)  implicit. Să considerăm următoarele situaţii: 

byte x=2;  
x+=3; 
Dacă s-ar fi scris codul anterior utilizând scrierea expandată: 

byte x=2;  
x=(byte)(x+3); 

operaţia de cast spre tipul byte ar fi fost necesară, deoarece rezultatul adunării unui număr întreg este
cel  puţin int. În prima situţie, operaţia de cast este implicită. 

3. Ordinea evaluării operanzilor 

Se face de la stânga la dreapta. Rezultatul oricărei expresii va fi ca şi cum toţi operanzii sunt 
evaluaţi de la stânga la dreapta, chiar dacă ordinea executării operaţiilor este câteodată diferită (şi din 
motive de optimizare a calculului). Exemplu: 

int a[]={4,4};  
int b=1;  
a[b]=b=0; 

Evaluarea operanzilor de la stânga la dreapta cere ca a[b] să fie evaluat întâi (deci a[1]). Apoi este 
evaluat b iar apoi expresia constantă 0. Acum că operanzii au fost evaluaţi, sunt efectuate operaţiile (în  
ordinea precedenţei şi asociativităţii). Pentru asignări, asociativitatea este de la dreapta la stânga, deci 
valoarea 0 este asignată întâi variabilei b iar apoi elementului din vector a[1] . 

4. Conversia tipurilor primitive: promovarea aritmetică a operanzilor


Să considerăm următorul fragment de cod:
 

short s=9;  
int i=10; 
float f=11.1f;  
double d=12.2; 
if (-s*i > = f/d)  
System.out.println(“>>>>”); 
else 
System.out.println(“<<<<”); 

Conversiile de promovare aritmetică sunt toate conversii de la tipuri mici spre tipuri mari, şi sunt  
efectuate automat de către sistem. Regulile de promovare aritmetică disting între operatorii unari şi cei  
binari. 

Pentru operatorii unari, se aplică 2 reguli, în funcţie de tipul operandului: 


- dacă operandul este de tip byte, short, sau char, atunci acesta este convertit la int (cu
excepţia  operatorilor ++ , - - , când nu se aplică nici o conversie) 
- altfel nu se efectuează nici o conversie 
Pentru operatorii binari există 4 reguli, în funcţie de tipurile celor doi operanzi: 
- dacă unul dintre operanzi este de tip double, atunci celălalt operand este convertit la
double - altfel dacă unul dintre operanzi este de tip float, atunci celălalt operand este
convertit la float - altfel dacă unul dintre operanzi este de tip long, atunci celălalt operand
este convertit la long - altfel ambii operanzi suntconvertiţi la int 
Pentru exemplul anterior, iată cum lucrează sistemul: 
1. Variabila s de tip short este promovată la un int si apoi negată 
2. Rezultatul de la pasul 1 (un int) este înmulţit cu variabila i de tip int. În acest caz nu este 
necesară nici o conversie. Evident, rezultatul înmulţirii este un int. 
3. Înainte de a împărţi f de tip float la d de tip double, f este promovat la double. Rezultatul 
împărţirii este de tip double. 
4. Rezultatul de la pasul 2 (un int) trebuie să fie comparat cu rezultatul de la pasul 3 (un
double),  şi este promovat la double apoi se efectuează compararea. Rezultatul unei comparări
este  întotdeauna de tip boolean. 

1. Vectori în Java 

Un vector în Java este o colecţie omogenă şi ordonată de primitive, referinţe ale obiectelor
sau  alţi vectori. Pentru a crea şi utiliza un vector trebuie urmaţi trei paşi: 
1. declararea 
2. construirea 
3. iniţializarea 
Declararea spune compilatorului care este numele vectorului şi de ce tip vor fi  elementele sale.
De exemplu: 

int [] ints;  
double dubs[];  
float [][] floats; 
Declararea nu specifică şi dimensiunea vectorului, aceasta fiind specificată la
executarea  programului, când vectorul este alocat prin intermediul cuvântului cheie new.
Exemple: 

int [] ints;  
ints=new int[25]; 

vectorului intr-o singura linie 


// declararea si construireaint vec_int[]=new int[25]; 

// dimensiunea specificata ca o variabila, nu ca un


literal int size=12*23;
 

float [] floats;  
floats=new float[size]; 

Atunci când un vector este construit, elementele sale sunt automat iniţializate la valorile
lor  implicite (default). Vezi tabelul de mai jos: 
Tipul elementului  Valoare iniţială  Tipul elementului  Valoare iniţială

Byte  0  Float  0.0f

Short  0  Double  0.0d

Int  0  Char  „\u0000‟

Long  0L  Boolean  false

Se poate combina declararea, construirea şi iniţializarea vectorului într-un singur


pas. float [] vec={1.1f,2.3f,7.9f,5.7f,9.2f}; 

Cel mai sigur mod de a ne referi la dimensiunea unui vector este de aplica
.length numelui vectorului. Exemplu: 
long vec[];  
vec=new long[600]; 
for(int i=0;i<vec.length;i++)  
Vec[i]=i*i; 

III. MODUL DE LUCRU 

1. Se foloseşte utilitarul instalat la primul laborator: Eclipse sau NetBeans sau oricare
altul! 2. Pe calculatorul personal este instalata o versiune functionala JDK, in
conformitate cu  precizarile de la primul laborator. 
IV. TEMĂ 

Se vor parcurge toate exemplele prezentate în platforma de laborator testându-se practic (acolo 
unde este cazul). 
Să se răspundă la următoarele întrebări grilă, explicând şi alegerea rezultatului: 

1. După executarea fragmentului de cod de mai jos, care sunt valorile variabilelor x, a şi b? 

int x, a=6,b=7;  
x=a++ + b++;
 

A. x=15, a=7, b=8 


B. x=15, a=6, b=7 
C. x=13, a=7, b=8 
D. x=13, a=6, b=7 

2. Care din următoarele expresii sunt legale? (Alegeţi una sau mai multe.) 

A. int x=6; x=!x; 


B. int x=6; if (!(x>3)) { } 
C. int x=6; x=~x; 

3. Care dintre următoarele expresii rezultă într-o expresie pozitivă a lui x? (Alegeţi una.) 

A. int x=-1; x=x >>> 5; 


B. int x=-1; x=x >>> 32; 
C. byte x=-1; x=x >>> 5; 
D. int x=-1; x=x >> 5; 

4. Ce rezultă după rularea următorului cod? 

class Xor{ 
public static void main(String args[]){  
byte b=10; // 00001010 in binar  
byte c=15; // 00001111 in binary  
b=(byte) (b ^ c);  
System.out.println(“b contine ”+b); 

A. Output-ul este: b contine 10 


B. Output-ul este: b contine 5 
C. Output-ul este: b contine 250 
D. Output-ul este: b contine 245 

5. Ce rezultă după încercarea de a compila şi rula următorul cod? 


1.class Conditional{ 
2. public static void main(String args[]){ 
3. int x=4; 
4. System.out.println(“valoarea este ”+((x > 4) ? 99.99:9)); 5. } 
6.} 

A. Output-ul este: valoarea este 99.99 


B. Output-ul este: valoarea este 9 
C. Output-ul este: valoarea este 9.0 
D. Se semnalează eroare de compilare la linia 4. 

6. Care este output-ul acestui fragment de cod? 

int x=3; int y=10;  


System.out.println(y % x); 

A. 0 
B. 1 
C. 2 
D. 3
 

7. Ce rezultă din următorul fragment de cod? 

int x=1; 
String []names={“Fred”,”Jim”,”Sheila”};  
names[--x]+=”.”; 
for(int i=0;i<names.length;i++)  
System.out.println(names[i]); 

A. Output-ul include Fred. 


B. Output-ul include Jim. 
C. Output-ul include Sheila. 
D. Nimic din cele de mai sus. 

8. Care linie din următorul cod nu se va compila? 

1. byte b=5; 
2. char c=’5’; 
3. short s=55; 
4. int i=555; 
5. float f=555.5f; 
6. b=s; 
7. i=c; 
8. if(f>b) 
9. f=i; 

9. Se va compila următorul cod ? 


byte b=2;  
byte b1=3;  
b=b*b1; 

10. În codul de mai jos, care sunt posibilele tipuri pentru variabila result? (Alegeţi cel mai 
complet răspuns adevărat.) 

byte b=11;  
short s=13;  
result=b* ++s; 

A. byte, short, int, long, float, double 


B. boolean, byte, short, char, int, long, float,
double C. byte, short, char, int, long, float,
double 
D. byte, short, char 
E. int, long, float, double

TEHNOLOGII JAVA 
LUCRARE DE LABORATOR 2 

Instrucţiuni ale limbajului Java 


I. SCOPUL LUCRĂRII 

Lucrarea de faţă are rolul de a prezenta şi familiariza studentul cu câteva instrucţiuni de 
bază ale limbajului Java: (if( )/else, switch( )), construcţiile iterative while( ), do/while( ),
for( ),  instrucţiunile de salt break, continue; cu importanţa şi situaţiile de utilizare a acestora. 
La sfârşitul acestei lucrări, studentul va avea posibilitatea să scrie programe Java în care
să  folosească instrucţiunile limbajului menţionate anterior. 

II. NOŢIUNI TEORETICE 


Observaţie: Va rog sa studiati notiunile prezentate la Cursul 1 si in suportul electronic.

1. Instrucţiunea de selecţie if( )/else 

Instrucţiunea if( )/else primeşte un argument de tip boolean, ca bază a alegerii. Adesea
se  utilizează o expresie de comparare pentru a furniza argumentul. Exemplu: 

1. if (x>=10) { 
2. System.out.println(“x este mai mare decat 10”);  
3. } 

Linia 2 a codului se execută dacă testul (x>=10) din linia 1 returnează adevărat. Putem
furniza cod care să se execute atunci când testul returnează fals în partea else a 
instrucţiunii. Exemplu: 

1. if (x>=10) { 
2. System.out.println(“x este mai mare sau egal decat 10”); 
3. } 
4. else { 
5. System.out.println(“x este mai mic decat 10”);  
6. } 

Construcţia if( )/else efectuează un test numai între două posibile căi de execuţie, dar se
pot  utiliza intrucţiuni if( )/else imbricate pentru a selecta între mai multe posibilităţi.
Exemplu: 

class Selectie { 
public static void main(String args[]) {  
int x=7,y=20,z=2; 
if ((x>10) && (y>6)){ 
System.out.println(x+y); 

else if(x<12){  
if(y>50){
 
x++; 

else { 
y--; 

z++;y--; 
System.out.println(“z=”+z+” y=”+y); 


else { 
System.out.println(x-y); 


2. Instrucţiunea de selecţie switch( ) 

Dacă este nevoie să se aleagă între mai multe căi de execuţie alternative, şi dacă alegerea
se  poate baza pe o valoare int, atunci se poate utiliza instrucţiunea switch( ). Exemplu: 

switch(x) { 
case 1: 
System.out.println(“1”); 
case 2: System.out.println(“2”); 
case 3: 
System.out.println(“3”);  
break; 
default: 
System.out.println(“ altceva in afara de 1,2 sau 3”);  
break; 

Observaţii: 
• Variabila x poate să fie numai de tipul byte, short, char sau int (sau pe scurt,
valoarea  lui x trebuie să fie compatibilă la asignare cu tipul int). 
• Compararea valorilor care urmează după etichetele case cu valoarea expresiei
furnizate  de argumentul lui switch( ) determină calea de execuţie. Argumentele etichetelor
case trebuie să  fie constante, sau cel puţin expresii constante care să poată fi complet evaluate
la momentul  compilării (nu se pot utiliza variabile sau expresii ce utilizează variabile). 
• Fiecare etichetă case primeşte un singur argument, dar când execuţia sare la una
dintre  aceste etichete, continuă în jos până când atinge o instrucţiune break. 
• Eticheta default este comparabilă ca efect cu partea else a unei instrucţiuni if( )/else.
Execuţia sare la eticheta default dacă nici unul dintre argumentele etichetelor case nu se 
potriveşte cu argumentul furnizat de switch( ). Deşi se obişnuieşte ca eticheta default să fie 
plasată la sfârşitul blocului switch( ), nu există nici o regulă care să impună acest lucru. 

Exemplu: 
class TestSwitch { 
public static void main(String args[ ]) {  
int i=7; 
switch(i) {  
case 1: 
System.out.println(i+1);  
break; 
case 2+5:

case 8:  
i=i+3;  
System.out.println(i); 

default: 

case 10: 




System.out.println(i+4);  break; 

System.out.println(i+10);  break; 

System.out.println(i+2); 

3. Instrucţiunea de ciclare while( ) 

Vezi Curs 3, secţiunea 2.10.1. 


Este o instrucţiune de ciclare cu test iniţial şi are număr necunoscut de paşi. 

Observaţie: 
Se recomandă utilizarea unui bloc pentru a conţine codul corpului buclei iterative (chiar 
dacă acesta constă dintr-o singură instrucţiune; în general este puţin probabil să rămână aşa, iar 
lipsa acoladelor este o eroare greu de depistat într-un program mare). Observaţia este valabilă
şi  pentru celelalte intrucţiuni. 

Exemple: 
class TestW1 { 
public static void main(String args[ ]) {  
char c=’a’; 
while(++c <= ’m’) 
System.out.print(c+” ”);  
System.out.println(”\n”);  
while(c-- > ’d’) 

System.out.print(c+” ”); 


class TestW2 { 
public static void main(String args[ ]) {  
double d1=34.8,d2=7; 
while(d1 > 0) 

d1-=d2; 
System.out.println(d1); 

System.out.println(”\n”);  
while(d2<5.3) 

System.out.println(d2--); 
}
 


4. Instrucţiunea de ciclare do/while( ) 

Vezi Curs 3, secţiunea 2.10.2. 


Este o instrucţiune de ciclare cu test final (corpul se execută cel puţin o dată) şi are
număr  necunoscut de paşi. 
Exemplu: 

class TestDo { 
public static void main(String args[ ]) {  
char c=’a’; 
int j=9;  
do { 
System.out.println(c++); 
} while(++c <= ’i’);  
j=c; 
System.out.println(”\n j=”+j);  
do { 
System.out.println(j--); 
}while(j<95); 

5. Instrucţiunea de ciclare for( ) 

Vezi Curs 3, secţiunea 2.10.3. 


Permite efectuarea de iteraţii peste un interval de valori. Este o instrucţiune de ciclare
cu  test iniţial şi are număr cunoscut de paşi. 
Exemple: 

class TestFor1 { 
public static void main(String args[ ]) {  
int i; 
for(i=1;i<=5;i+=2)  
System.out.println(”i=”+i); 


class TestFor2 { 
public static void main(String args[ ]) {  
float f; 
char c;  
for(f=1.1f;f<=10.5;f++){ 
System.out.println(”f=”+f); 

for(c=’m’;c>’a’;c-=2){  
System.out.println(”c=”+c); 


Variabila cu rol de contor se poate declara chiar în cadrul intrucţiunii for( ). O astfel de
variabilă  va avea domeniul de valabilitate restricţionat la blocul instrucţiunii for( ). Acest fapt
protejează  împotriva interferenţei variabilelor contor şi a reutilizării accidentale a acestora.
 

for(int i=0;i<10;i++){ 
System.out.println("i="+i); 

Codul echivalent implementat folosind intrucţiune while( ) arată astfel: 


int i=0;  
while(i<10) { 
System.out.println("i="+i);  
i++; 

Astfel, se poate mai uşor observa că: scopul variabilei i din cadrul instrucţiunii for( ) este 
restricţionat la blocul corespunzător lui for( ), incrementarea contorului se face după
executarea  corpului principal al intrucţiunii for( ), iar apoi se efectuează din nou testul. 

class TestFor3 { 
public static void main(String args[ ]) { 

for(int i=0;i<10;i++){  
System.out.println("i="+i); 

+i); eroare la compilare 
// System.out.println("i=" for(int i=0;i<10;i++){ 
System.out.println("i="+i); 


Intrucţiunea for( ) permite utilizarea separatorului virgulă într-un mod special. Exemple: 

int j,k; 
for(j=0,k=1; j+k<20; j++,k+=3) {  
System.out.println(“j=”+j+” k=”+k); 

for(int i=7,j=0; i<15; j++) {  


System.out.println(“i=”+(i++)+“ j=”+j); 

Dar nu se poate utiliza separatorul virgulă în orice mod. Astfel următoarele utilizări
sunt ilegale: 
int i=7; 
for(i++,int j=0; i<10; j++) { } // ilegal  

for(int i=7, long j=0; i<10; j++) { } // ilegal 

6. Instrucţiunile de salt break, continue


 
Instrucţiunile break şi continue se utlizează atunci când este nevoie să se abandoneze 
execuţia corpului unei instrucţiuni de ciclare, sau poate a unui număr de bucle iterative
imbricate. Exemple: 
class TestCont1 

public static void main(String args[ ]) 

char array[][]=new char[3][5];  
for(int i=0;i<array.length;i+=2) 

for(int j=0;j<array[i].length;j++) 

array[i][j]='a'; 


mainLoop: for(int i=0; i<array.length; i++) 

for(int j=0; j<array[i].length; j++) 

if(array[i][j]== '\u0000')  
continue mainLoop; 
System.out.println(array[i][j]); 

System.out.println("\n"); 


Adevărata putere a instrucţiunii continue este aceea că permite ieşirea din corpul unor 
bucle iterative imbricate. 
Să observăm şi utilizarea etichetei (label) mainLoop care a fost aplicată instrucţiunii
for( ) de la linia 13. De obicei etichetele se aplică la începutul unor instrucţiuni de ciclare
while( ),  do/while( ), for( ). 
Când procesarea vectorului bidimensional de caractere ajunge la o valoare zero, aceasta 
este abandonată şi se sare la efectuarea incrementării i++ din cadrul instrucţiunii for( ) 
corespunzătoare etichetei mainLoop de la linia 13. 

class TestCont2 

public static void main(String args[ ]) 

int vec[]=new int[10];  
for(int i=0;i<vec.length;i+=2) 
vec[i]=i*i+20; 
for(int i=0;i<vec.length;i++) 

if (vec[i]==0) 
continue;  
System.out.println(vec[i]); 


class TestB1
 


public static void main(String args[ ]) 

int vec[]=new int[10];  
for(int i=0;i<vec.length;i+=2) 
vec[i]=i*i+20; 
for(int i=0;i<vec.length;i++) 

if (vec[i]==0) 
break;  
System.out.println(vec[i]); 


Utilizarea instrucţiunii break cauzează abandonarea întregului ciclu. În acest caz, în loc 
de a se sări peste procesarea lui vec[i] şi de a se continua cu procesarea lui vec[i+1] aşa cum se 
întâmplă în cazul utilizării instrucţiunii continue, se abandonează întregul ciclu for( ) de îndată 
ce este întâlnit un element cu valoarea 0. 
Se pot utiliza etichete şi în cazul instrucţiunilor break. 

Observaţie: 
Etichetele pot fi aplicate oricărei instrucţiuni, iar break poate fi utilizat pentru a se ieşi din
orice  bloc etichetat, chiar dacă blocul este corpul unei instrucţiuni de ciclare sau nu. 

class TestB2 { 
public static void main(String args[ ]) {  
int vec[]={1,4,6,8,12,56,77,2,5}; 
for(int i=0;i<vec.length;i++) {  
et: { 
System.out.println(++vec[i]);  
if(i%2==0) break et;  
System.out.println(--vec[i]); 

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


7. Alte exemple utile 


class Ex1 { 
static char f(int n) {  
System.out.print(n);  
if(n>=0) return '+';  
return '-'; 

public static void main(String args[ ]) {  
System.out.print(" "+f(1)+"\n"); 
System.out.print(" "+f(-1)); 

}
 

III. MODUL DE LUCRU 

1. Se foloseşte utilitarul instalat la primul laborator: Eclipse sau NetBeans sau oricare
altul! 2. Pe calculatorul personal este instalata o versiune functionala JDK, in
conformitate cu  precizarile de la primul laborator. 

IV. TEMĂ 

Se vor parcurge toate exemplele prezentate în platforma de laborator testându-se practic 


(acolo unde este cazul). 
Să se răspundă la următoarele întrebări grilă, explicând şi alegerea rezultatului. 

1. Ce se va afişa după executarea fragmentului de cod de mai jos? 


int x=0, y=4, z=5;  
if (x>2) { 
if (y<5){ 
System.out.println(“mesaj unu”); 

else { 
System.out.println(“mesaj doi”); 


else if (z>5) {  
System.out.println(“mesaj trei”); 

else { 
System.out.println(“mesaj patru”); 

A. mesaj unu 
B. mesaj doi 
C. mesaj trei 
D. mesaj patru 

2. Care afirmaţie despre următorul fragment de cod este adevărată? 

1. int j=2; 
2. switch(j) { 
3. case 2:
 

4. System.out.println(“valoarea este doi”); 


5. case 1+2: 
6. System.out.println(“valoarea este trei”); 
7. break; 
8. default: 
9. System.out.println(“valoarea este “+j); 
10. break; 
11. } 

A. Codul este ilegal datorită expresiei de la linia 5 


B. Tipurile acceptate pentru variabila j, care este argument
al  construcţiei switch(), pot fi byte, short, int sau long. 
C. Output-ul va fi: valoarea este doi 
D. Output-ul va fi: valoarea este doi, urmat de valoarea este trei E.
Output-ul va fi: valoarea este doi, urmat de valoarea este trei, urmat de
valoarea este 2 

3. Să considerăm următorul fragment de cod: 


for(int i=0;i<2;i++) {  
for(int j=0;j<3;j++) { 
if(i==j) {  
continue; 

System.out.println(“i=”+i+” j=”+j); 

Care linii vor face parte din output? 


A. i=0 j=0 
B. i=0 j=1 
C. i=0 j=2 
D. i=1 j=0 
E. i=1 j=1 
F. i=1 j=2 

4. Să considerăm următorul fragment de cod: 


outer: for(int i=0;i<2;i++) {  
for(int j=0;j<3;j++) { 
if(i==j) { 
continue outer; 

System.out.println(“i=”+i+” j=”+j); 

Care linii vor face parte din output? 


A. i=0 j=0 
B. i=0 j=1 
C. i=0 j=2 
D. i=1 j=0 
E. i=1 j=1 
F. i=1 j=2 

5. Care dintre următoarele construcţii de ciclare sunt legale? (Alegeţi una sau mai multe.)

A. 
while(int i<7) {  
i++; 
System.out.println(“i=”+i); 

B. 
int i=3;  
while(i) { 
System.out.println(“i=”+i); 

C. 
int j=0; 
for(int k=0;j+k !=10; j++,k++) {  
System.out.println(“j=”+j+” k=”+k); 

D. 
int j=0;  
do { 
System.out.println(“j=”+j);  
if(j==3) { continue loop; } 
}while(j<10); 

Scrieţi un program Java pentru a rezolva ecuaţia de gradul doi. 


Scrieţi un program Java care să determine numărul de parametri furnizaţi în linia de 
comandă la execuţia programului. Dacă acest număr este 0, atunci programul afişează “0 
argumente”; dacă în linia de comandă se furnizează un singur parametru atunci programul 
afişează “1 argument” precum şi valoarea acestui argument; altfel se va afişa textul “mai 
multe argumente” şi valorile acestora. 
Scrieţi un program Java ce constă dintr-o clasă care la rândul ei conţine două funcţii.  Prima
este o funcţie static String f(String s) care afişează valoarea şirului de caractere sla  care
se concatenează şirul de caractere “< - - >” şi apoi returnează s. A doua este metoda  main
în cadrul cărei se apelează funcţia f de mai sus în cadrul unor comenzi  System.out.println;
funcţia f se va apela o dată pentru un şir de caractere oarecare (ales  de programator) şi apoi
pentru primul argument din linia de comandă dacă acesta există. 
Scrieţi un program Java ce constă din următoarele: Se construieşte un vector 
unidimensional cu elemente de tip float şi se iniţializează elementele cu valori arbitrare 
alese de programator (atât pozitive cât şi negative). Într-o buclă iterativă se vor afişa 
valorile acestor elemente cu următoarea specificare: dacă se întâlneşte un element negativ 
nu se va afişa ci se va sări la următorul element din vector.

  

TEHNOLOGII JAVA  
LUCRARE DE LABORATOR 3  

Clase şi obiecte în Java. Crearea obiectelor. Constructori.


Variabile  clasă. Metode statice. Moştenirea 
I. SCOPUL LUCRĂRII 

Lucrarea de faţă are rolul de a prezenta şi familiariza studentul cu noţiuni privind obiectele
şi  clasele în limbajului Java: clase şi crearea obiectelor, rolul constructorilor, semnificaţia şi
utilizarea  variabilelor clasă, metodele clasă, subclasele şi moştenirea; cu importanţa şi situaţiile
de utilizare a  acestora.  
La sfârşitul acestei lucrări, studentul va avea posibilitatea să scrie programe Java în care
să  folosească noţiunile menţionate anterior.  

II. NOŢIUNI TEORETICE 

 Observaţie: Vezi noţiunile prezentate în cursul 2. 

1. Crearea obiectelor 

Să considerăm următorul exemplu:  


public class Vehicul  
{  
public String categoria; 
public String marca; 
public int nrRoti;  
public boolean aerCond;  
public boolean volan;  

public Vehicul(String nume,boolean aerCond) {  


categoria="automobil";  
marca=nume;  
nrRoti=4;  
this.aerCond=aerCond;  
volan=true;  
}  
public Vehicul(String nume) {  
categoria="bicicleta";  
marca=nume;  
nrRoti=2;  
aerCond=false;  
volan=false;  

public void afisare() {  
System.out.println("Categorie vehicul "  
+categoria); 
System.out.println("Denumire "+categoria+": "+marca); 
 
 System.out.println("Nr roti: "+nrRoti);  
 System.out.print("Aer conditionat: ");  
 if(aerCond)  
 System.out.println("da");  
 else  
 System.out.println("nu");  
 System.out.print("Volan: ");  
 if(volan)  
 System.out.println("da");  
 else  
 System.out.println("nu");  
 System.out.print("\n");  
 }  
  
 public static void main(String args[ ]) {  
  
 Vehicul b1,m1,m2;  
 b1=new Vehicul("Pegas");  
 m1=new Vehicul("Dacia",false);  
 m2=new Vehicul("Cielo",true);  
 b1.afisare();  
 m1.afisare();  
 m2.afisare();  
 }  
}  

Observaţii:  

1. Un fişier sursă java care conţine o clasă publică trebuie salvat cu numele clasei respective  la
care se adaugă extensia .java.   
2. Într-un fişier sursă java poate exista cel mult o clasă declarată publică. Astfel programul  de
mai sus se va salva într-un fişier cu numele Vehicul.java. Altfel, la compilare se va  semnala
eroare.  
3. Clasa Vehicul conţine doi constructori. Utilizarea mai multor constructori pentru aceeaşi clasă 
se recomandă atunci când se urmăreşte iniţializarea obiectelor clasei în moduri diferite. Astfel, 
în main( ) se vor crea obiecte (vehicule) ce reprezintă biciclete şi automobile, în funcţie de 
utilizarea unui constructor sau al altuia.  
4. Unul din contextele în care utilizarea notaţiei bazate pe this (this este referinţa către obiectul 
curent) este necesară, este atunci când se defineşte un parametru sau o variabilă locală cu 
acelaşi nume ca o dată membru a clasei. Astfel, pentru a se face diferenţa între variabila locală 
sau parametru şi data membru a clasei, aceasta din urmă este accesată explicit prin referinţa 
this (vezi primul constructor al clasei Vehicul: this.aerCond=aerCond).  
5. Într-un constructor se poate referi ca primă instrucţiune un constructor al clasei curente. Este 
singura poziţie din definiţia unui constructor în care poate să apară o referire la un alt 
constructor. Un astfel de apel apare sub forma:  
this(listaDeArgumente); // constructor din aceeasi clasa  unde listaDeArgumente

reprezintă lista valorilor parametrilor constructorului invocat. 

Exemplul 2:  
public class Floare  
{  
 public String denumire;  
 public int nrPetale;  
 public String zonaClima="-";  

 public Floare(String denum,int nrP) {  


 denumire=denum;  
 nrPetale=nrP;  
 }  
 public Floare(String denum,int nrP,String clima) {   this(denum,nrP);  
 zonaClima=clima;  
 }  
 public void afisare() {  
 System.out.println("Denumire: "+denumire);  
 System.out.println("Numar petale : "+nrPetale);   System.out.println("Zona climatica:
"+zonaClima+"\n");   }  
  
 public static void main(String args[ ]) {  
  
 Floare floare1=new Floare("narcisa",7);  
 Floare floare2=new Floare("orhidee",30,"tropicala");   floare1.afisare();  
 floare2.afisare();  
 }  
}  

Observaţii:  

1. Variabilele membru se pot iniţializa când sunt declarate. Se recomandă ca iniţializarea să se 
facă în constructor (în principal, pentru ca fiecare obiect al clasei să poată avea valori diferite 
pentru datele membru).  
2. În cazul în care o dată membru membru este iniţializată la declarare iar apoi şi în constructor, 
atunci valoarea sa va fi cea pe care o primeşte în constructor. Dacă în constructor nu mai 
primeşte nici o valoare, atunci valoarea sa va rămâne cea de la declarare. Astfel, obiectul 
floare1 va avea pentru data membru zonaClima valoarea “-” deoarece în primul constructor 
(cel care este utilizat pentru crearea acestui obiect), aceasta dată membru nu primeşte nici o 
valoare. Obiectul floare2, în schimb, este creat cu ajutorul celui de-al doilea constructor, care 
iniţialiazează data membru zonaClima la valoarea celui de-al treilea parametru al sau – care 
este “tropicala”.  
2. Variabile clasă 

Să considerăm clasa Vehicul prezentată în secţiunea anterioară. O vom modifica


adăugându-i o  dată membru statică numită contor care numără obiectele clasei ce sunt create în
program. Această  nouă variabilă, fiind declarată static, este asociată clasei, ci nu instanţelor
clasei. O variabilă clasă  poate fi accesată prin numele clasei, deci nu este nevoie de crearea unei
instanţe a clasei doar pentru  a o accesa. O variabilă statică este creată o singură dată, la
încărcarea clasei. 
 

public class Vehicul  


{  
 static int contor=0;  
 public String categoria;  
 public String marca;  
 public int nrRoti;  
 public boolean aerCond;  
 public boolean volan;  

 public Vehicul(String nume,boolean aerCond)  


 {  
 categoria="automobil";  
 marca=nume;  
 nrRoti=4;  
 this.aerCond=aerCond;  
 volan=true;  
 contor++;  
 }  
 public Vehicul(String nume)  
 {  
 categoria="bicicleta";  
 marca=nume;  
 nrRoti=2;  
 aerCond=false;  
 volan=false;  
 contor++;  
 }  
 public void afisare()  
 {  
 System.out.println("Categorie vehicul "+contor+": "   +categoria);  
 System.out.println("Denumire "+categoria+": "+marca);   System.out.println("Nr roti:
"+nrRoti);  
 System.out.print("Aer conditionat: ");  
 if(aerCond)  
 System.out.println("da");  
 else  
 System.out.println("nu");  
 System.out.print("Volan: ");  
 if(volan)  
 System.out.println("da");  
 else  
 System.out.println("nu");  
 System.out.print("\n");  
 }  
  
 public static void main(String args[ ]) {  
  
 Vehicul b1,m1,m2;  
 b1=new Vehicul("Pegas");  
 b1.afisare();  
 m1=new Vehicul("Dacia",false);  
 m1.afisare();  
 m2=new Vehicul("Cielo",true);  
 m2.afisare();  
 System.out.println("\nExista "+Vehicul.contor+" obiecte   ale clasei Vehicul");   }  

 

Să considerăm un alt exemplu:  

class Salariat  
{  
 public static final double impozit=0.15;  
 public String nume;  
 public String functia;  
 public int varsta;  
 public double salariuBrut;  
  
 public Salariat(String num,String func,int ani,double sal)   { 
 nume=num;  
 functia=func;  
 varsta=ani;  
 salariuBrut=sal;  
 }  
 public double salariuNet()  
 {  
 return salariuBrut*(1-impozit);  
 }  
 public void afisare()  
 {  
 System.out.println("Nume salariat: "+nume);  
 System.out.println("Functia: "+functia);  
 System.out.println("Varsta: "+varsta);  
 System.out.println("SalariuBrut: "+salariuBrut+" lei");   System.out.println("SalariuNet:
"+salariuNet()+" lei \n");   }  
}  
  

public class UtilSal  


{  
 public static void main(String args[ ])  
 {  
 Salariat s1=new Salariat("Popa Ion","contabil",36,7300000);   Salariat s2=new Salariat("Rada
Alina","secretara",28,6000000);   System.out.println("Impozit: "+(int)(Salariat.impozit*100)+"%
\n");   s1.afisare();  
 s2.afisare();  
 }  
}  

Observaţie:  
  
Am utilizat în clasa Salariat o dată membru impozit care este declarată şi static şi final, ceea
ce  înseamnă că este considerată o constantă de către compilator (valoarea sa nu poate fi
modificată). 

3. Metode clasă (statice) 


Să considerăm următorul exemplu:  

public class Film  


{  
 static int pretBilet=30000; 
 

 static String cinematograf="Patria";  


 public String nume;  
 public int durata; // in minute  
 public boolean luatOscar;  

 public Film(String num,int nrMin,boolean oscar)   {  


 nume=num;  
 durata=nrMin;  
 luatOscar=oscar;  
 }  

 static int getPretBilet()  


 {  
 return pretBilet;  
 }  

 static void printCinema(Film f)  


 {  
 System.out.println("Filmul "+f.nume+" este difuzat la   cinematograful
"+cinematograf);   }  
 public void afisare()  
 {  
 System.out.println("Nume: "+nume);  
 System.out.println("Durata (in minute): "+durata);   if(luatOscar)  
 System.out.println("Filmul a primit premiul Oscar\n");   else  
 System.out.println("Filmul nu a primit premiul   Oscar\n");  
 }  
  
 public static void main(String args[ ]) {  
 System.out.println("Pretul unui bilet este: "   +Film.getPretBilet()+" lei");  
Film f1=new Film("Titanic",180,true);  
 f1.afisare();  
 Film.printCinema(f1);  
 }  
}  

Observaţii:  
1. O metodă statică este considerată că aparţine clasei şi nu instanţierilor clasei. O metodă statică 
poate să refere numai variabile sau metode statice (pentru că numai acestea există fără a se fi 
instanţiat un obiect din clasa respectivă), dar poate să fie apelată din orice metodă a clasei.  
2. Metoda main( ) care reprezintă punctul de plecare pentru orice program Java, este declarată ca 
fiind statică şi deci poate să fie referită fără instanţierea unui obiect.  
3. Limbajul Java permite declararea unei secvenţe de cod ca fiind statică în modul următor:  static {  
 secventa de cod  
}  
4. Astfel de secvenţe se pot declara numai în afara metodelor. Corespunzător, în momentul în  care
clasa respectivă ajunge să fie încărcată (pentru că a fost referită) se vor executa toate 
secvenţele de cod declarate în acest mod la nivelul clasei. Să considerăm următoarea aplicaţie 
Java: 
 

class Floare  
{  
 int nrPetale;  
 static  
 {  
 System.out.println("floarea");  
 }  
 public Floare(int nrPetale)  
 {  
 this.nrPetale=nrPetale;  
 }  
 public void afiseaza()  
 {  
 System.out.println(nrPetale);  
 }  
}  
public class Exemplu  
{  
 static  
 {  
 Floare f=new Floare(10);  
 f.afiseaza();  
 }  
 public static void main(String args[])  
 {  
 }  
}  

Programul afişează:  

Floarea  
10  
deşi în metoda main( ) nu sunt prevăzute prelucrări, s-au executat secvenţele de cod indicate cu 
atributul static din ambele clase definite. 

Să considerăm un alt exemplu:  

public class Test  


{  
 int x;  
 static int y=0;  
  
 static void modificaY() {  
 y+=10;  
 }  
 void modificaY(int y) {  
 this.y=y;  
 }  
 void modificaX(int x) {  
 this.x=x;  
 }  
 void func() {  
 Test t=new Test();  
 y=1;  
 t.y=1;  
 Test.y=1; 
 

 Test.modificaY();  
 t.modificaY(2);  
 System.out.println(y);  
 x=1;  
 t.modificaX(2);  
 System.out.println(x);  
 }  

 public static void main(String args[]) {  


 Test t=new Test();  
 t.func();  
 }  
}  
În metoda func( ) a clasei Test a fost creat un obiect care reprezintă o instanţiere a clasei.
Se  observă că în timp ce pentru variabila statică y există 5 variante pentru atribuirea unei valori
(toate  referindu-se la variabila globală y), pentru variabila x cele două modificări ale valorii lui
x se referă  la variabile diferite – în primul caz (x=1) este vorba despre data membru x a
obiectului pentru care  se execută metoda, iar în cel de-al doilea caz (t.modifica(x)) este vorba
despre data membru x a  obiectului de tip Test creat în metoda func().  

4. Moştenirea 
Să considerăm următorul exemplu (programul Vehicule.java):  

class Vehicul  
{  
 public String denumire;  
 public int nrRoti;  

 public Vehicul(String denumire,int nrRoti)  


 {  
 this.denumire=denumire;  
 this.nrRoti=nrRoti;  
 }  
 public void afisareVehicul()  
 {  
 System.out.println("\n");  
 System.out.println("Denumire: "+denumire);  
 System.out.println("Nr roti: "+nrRoti);  
 }  
}  

class Bicicleta extends Vehicul  


{  
 public boolean combustibil;  

 public Bicicleta(String denumire,int nrRoti)  


 {  
 super(denumire,nrRoti);  
 combustibil=false;  
 }  
 public void afisareBicicleta()  
 {  
 afisareVehicul();  
 System.out.println("Bicicleta nu consuma benzina");   }  

 

class Motocicleta extends Bicicleta  


{  
 public Motocicleta(String denumire,int nrRoti)   {  
 super(denumire,nrRoti);  
 combustibil=true;  
 }  
 public void afisareMotocicleta()  
 {  
 afisareVehicul();  
 System.out.println("Motocicleta consuma combustibil");   }  
}  

class Automobil extends Vehicul  


{  
 public String combustibil;  
 public boolean volan;  

 public Automobil(String denumire,int nrRoti,String  combustibil)  


 {  
 super(denumire,nrRoti);  
 this.combustibil=combustibil;  
 volan=true;  
 }  
 public void afisareAutomobil()  
 {  
 afisareVehicul();  
 System.out.println("Combustibil: "+combustibil);  
System.out.println("Volan: da");  
 }  
}  

public class Vehicule  


{  
 public static void main(String args[ ])  
 {  
  
 Vehicul v;  
 Bicicleta b=new Bicicleta("Pegas",2);   b.afisareBicicleta();  
 Automobil a=new Automobil("BMW",4,"benzina");   a.afisareAutomobil();  
 v=a;  
 v.afisareVehicul();  
 // v.afisareAutomobil(); eroare  
 Motocicleta m=new Motocicleta("Honda",2);  
m.afisareMotocicleta();  
 b=m;  
//corect b.afisareBicicleta();  
 v=m; //corect  
 }  

0  
III. MODUL DE LUCRU 

1. Se foloseşte utilitarul instalat la primul laborator: Eclipse sau NetBeans sau oricare
altul! 2. Pe calculatorul personal este instalata o versiune functionala JDK, in
conformitate cu precizarile de la primul laborator.

IV. TEMĂ 
Se vor parcurge toate exemplele prezentate în platforma de laborator testându-se practic  (acolo
unde este cazul).  

Modificaţi clasa Salariat astfel încât salariul fiecărui angajat să poată fi exprimat şi în
dolari.  De asemenea, programul să afişeze şi cursul de schimb al dolarului utilizat în
calcule.  

Scrieţi clasa Student. Fiecare student are un nume, an, grupă, şi două note obţinute la o 
anumită materie - una pe semestrul 1 iar cealaltă pe semestrul 2. Clasa conţine un 
constructor ce iniţializează datele membru ale clasei la valorile parametrilor săi, o funcţie 
care calculează şi returnează media celor două note, şi o funcţie de afişare ce afişează 
valorile datelor membru şi valoarea mediei. Scrieţi un program complet în care să utilizaţi 
obiecte ale clasei Student.  

Modificaţi clasa Film astfel:  


- adăugaţi clasei o metodă statică care să returneze valoarea datei membru durata. -
încercaţi să apelaţi metoda afisare( ) în cadrul metodei printCinema( ) şi invers, apelaţi
metoda printCinema( ) în cadrul metodei afisare( ). 
Explicaţi la fiecare caz în parte rezultatele obţinute. 

Creaţi următoarea ierarhie de clase:  


Un disc are un nume şi o capacitate. O discheta are în plus o stare (1 dacă este “write-protected”,
0  altfel). Un hard-disk are în plus un controler (de tip sir de caractere; exemplu: “IDE”,
“SCSI”).  Superclasa are un constructor (cu parametri) şi o funcţie de afişare (afişează valorile
datelor  membru). Clasa discheta are un constructor, o funcţie de afişare şi o funcţie care setează
(modifică)  starea dischetei. Clasa hard-disk are un constructor şi o funcţie de afişare.  
Scrieţi un program Java care lucrează cu obiecte de tipul celor 3 clase.  

  

TEHNICI AVANSATE DE PROGRAMARE  


LUCRARE DE LABORATOR 4  

Variabile shadow. Suprascrierea metodelor. Ascunderea


şi  încapsularea datelor. Clase şi metode abstracte în
Java 

I. SCOPUL LUCRĂRII 

Lucrarea de faţă are rolul de a prezenta şi familiariza studentul cu noţiuni privind obiectele
şi  clasele în limbajului Java: variabile “shadow”, suprascrierea metodelor, ascunderea şi
încapsularea  datelor, clase abstracte şi interfeţe; cu importanţa şi situaţiile de utilizare a
acestora.  
La sfârşitul acestei lucrări, studentul va avea posibilitatea să scrie programe Java în care
să  folosească noţiunile menţionate anterior.  

II. NOŢIUNI TEORETICE 

 Observaţie: Vezi noţiunile prezentate în cursul 2. 


1. Variabile “shadow” 
Consideram următorul exemplu:  

public class Televizor  


{  
int diagonala;  
public String nume; 
static public int an_fabricatie;  
public boolean merge;  

public Televizor(String num,int an,int diag,boolean stare)  { 


nume=num;  
 an_fabricatie=an;  
 diagonala=diag;  
merge=stare;  
}  

static int getAnFabricatie()  


{  
return an_fabricatie;  

public void afisare()  


{  
System.out.println("Nume: "+nume);  
if(merge)  
System.out.println("Televizorul este in stare buna de  functionare\n");  
else  
System.out.println("Televizorul nu este in stare buna 
 

 de functionare \n");  


 }  
  
 public static void main(String args[ ]) {  
 System.out.println("Anul fabricatiei este: "  
 +Televizor.getAnFabricatie());   Televizor t1=new Televizor("Panasonic", 2002, 51, true);  
t1.afisare();  
 }  
}  

public class TelevizorColor extends Televizor  


{  
 int diagonala;  
 public TelevizorColor(String num, int an, int diag,   boolean stare)  
 {  
 nume=num;  
 an_fabricatie=an;  
 diagonala=diag;  
 merge=stare; 
 }  
... //cititi observatiile de mai jos si accesati variabila  //diagonala in cadrul acestei
clase  
}  

Observaţii:  
1. Observăm declaraţia în clasa TelevizorColor a unei variabile cu numele diagonala,  care
„umbreşte” variabila cu acelaşi nume declarată în clasa Televizor.  
2. Dacă accesăm numele diagonala sau sinonimul this.diagonala în cadrul clasei 
TelevizorColor vom accesa variabila diagonala declarată în TelevizorColor.  
3. Altfel, putem sa distribuim (cast) pe this clasei corespunzătoare apoi să accesăm 
variabila shadow: ((Televizor this) .diagonala.  
4. Această tehnică este utilă atunci când în cadrul unei clase se doreşte să se acceseze o
variabilă shadow dintr-o clasă care nu este superclasa acesteia. 

2. Suprascrierea metodelor în Java 


Considerăm următorul exemplu:  

public class Televizor  


{  
 int diagonala=51;  
 int an_fabricatie=2001;  

 int getAnFabricatie()  
 {  
 return an_fabricatie;  
 }  
 int getDiagonala() 
 {  
 return diagonala;  
 }  

 

public class TelevizorColor extends Televizor  


{  
int diagonala=52;  
 int an_fabricatie=2000;  

 int getAnFabricatie()  
 {  
 return an_fabricatie+1;  
 }  
 int getDiagonala()  
 {  
 return diagonala-1;  
 }  
  
}  
...//realizati afisarea anumitor informatii folosind metodele  //descrise mai sus 

Observaţii:  
1. Am declarat în clasa TelevizorColor metodele getAnFabricatie() şi getDiagonala()
având acelaşi nume, tip şi aceleaşi argumente cu metodele din cadrul superclasei 
Televizor. Când aceste metode sunt invocate pentru un obiect al clasei TelevizorColor
este apelată metoda din cadrul ei şi nu cea a superclasei Televizor.  
2. Trebuie reţinut faptul că suprascrierea metodelor nu este acelaşi lucru cu  supraîncărcarea
metodelor (în cazul supraîncărcării metodelor este vorba de mai multe  metode cu
acelaşi nume dar cu liste de argumente diferite).  
3. De asemenea, trebuie ştiut faptul că suprascrierea metodelor nu reprezintă, la nivelul 
metodelor, acelaşi lucru ca şi variabilele shadow 

3. Ascunderea şi încapsularea datelor 


Java oferă diverşi modificatori utilizaţi în controlul scopului metodelor şi variabilelor 
(câmpurilor): private, protected, public, package.  
Implicit metodele/variabilele au scopul package, sunt non-statice (aparţin fiecărei
instanţe),  şi non-finale(pot fi suprascrise în clasele derivate). Tendinţa este să folosim
modificatorii impliciţi.  Programarea obiectuală însă, indică "ascunderea" metodelor/câmpurilor
şi expunerea doar  a celor strict necesare. Constantele ar trebui marcate static final. De
asemenea metodele/câmpurile  dacă se poate ar trebui declarate final, şi chiar private. Dacă se
poate chiar şi static (metodele statice  sunt mai rapide).  
Când discutăm despre drepturile de acces la membrii unei clase trebuie să abordăm
acest  subiect din 2 perspective:  

A. Interiorul clasei sau, mai concret, metodele clasei. În cadrul metodelor unei clase
există acces nerestrictiv la toţi membrii, date sau funcţii. De exemplu, în metodele clasei Punct
se face  referire la câmpurile x şi y. În mod asemănător s-ar fi putut referi (apela) şi metodele.
De exemplu,  am fi putut defini funcţia move pe baza funcţiei init astfel:  

class Punct{  
 //. . .  
 public void move(int dx, int dy) {  
 init(x+dx, y+dy);  
 }  
 //. . .  

 
Se observă că în interiorul clasei nu se foloseşte notaţia cu punct pentru a referi
membrii,  aceştia fiind pur şi simplu accesaţi prin numele lor. Când o metodă face referire la alţi
membri ai  clasei, de fapt sunt accesaţi membrii corespunzători ai obiectului receptor, indiferent
care ar fi el.  De exemplu, cand se apelează metoda init a obiectului referit de p1, are loc
iniţializarea membrilor  x şi y ai acelui obiect. În legatură cu accesul din interiorul unei clase,
trebuie spus că absenţa  restricţiilor se aplică şi dacă este vorba despre membrii altui obiect din
aceeaşi clasă, dar diferit de  cel receptor. De exemplu, dacă în clasa Punct am avea câte o
metodă de calcul al distanţei pe  vericală/orizontală dintre 2 puncte, unul fiind obiectul receptor,
iar celălalt un obiect dat ca  parametru, atunci am putea scrie:  

class Punct{  
 //. . .  
 public int distV(Punct p) {  
 return y - p.y;  
 }  
 public int distH(Punct p) {  
 return x - p.x;  
 }  
 //. . .  
}  

Se observă că din interiorul metodelor distV / distH putem accesa liber membrii privaţi
ai  obiectului p dat ca parametru. La fel ar sta lucrurile şi daca p ar fi o variabilă locală a unei
metode  din clasa Punct.  

B. Exteriorul sau clienţii clasei. Clienţii unei clase pot accesa doar acei membri care au
ca  modificator de acces cuvântul public. Membrii declaraţi cu modificatorul private NU sunt
vizibili  în afară, sunt ascunşi. Dacă am încerca să folosim în metoda main din exemplul nostru
o referinţă de genul:  

p1.x  
  
compilatorul ar raporta o eroare. O observaţie importantă pe care o putem desprinde din
exemplul  clasei Punct este aceea că structura unei clase, sau modul ei de reprezentare, care este
dat de  variabilele membru, de regulă se ascunde faţă de clienţi. Dacă este necesar ca aceştia să
poată consulta valorile datelor membru, se va opta pentru definirea unor metode de genul
getValoare, iar  nu pentru declararea datelor respective ca fiind publice.  
Într-o clasă Java putem declara membri care să nu fie precedaţi de nici unul dintre 
modificatorii public sau private. În acest caz, membrii respectivi se spune că sunt accesibili la
nivel  de pachet ("package").  

Să considerăm următorul exemplu:  


Un program pentru Pentagon ce controlează toate rachetele nucleare adăpostite în silozuri de pe 
teritoriul S.U.A. În acest caz, programul ar putea folosi obiecte de tip silo (vezi clasa silo de mai 
jos). Din motive de securitate, pentru a lansa o rachetă programul trebuie să specifice o parolă. 
Dacă parola este corectă, variabila lanseaza_rachete primeşte valoarea 1, iar rachetele vor fi 
lansate. Dacă parola nu este corectă, variabila rămâne 0 iar rachetele nu vor fi lansate. Dacă toţi 
membrii clasei ar fi declaraţi public, atunci orice clasă Java care utilizează obiecte silo va putea 
folosi următoarea instrucţiune pentru a lansa rachete ignorând funcţia de acces prin parolă (void 
lansare_rachete(char *Parola)):  
wyoming_silo.lanseaza_rachete=1;  
(unde wyoming_silo este un obiect de tipul silo) 
 

Când se folosesc obiecte, accesul la majoritatea variabilelor membru trebuie limitat la 
funcţiile membru. Astfel, singura modalitate ca programul să aibă acces la variabila membru 
lanseaza_rachete este prin folosirea unei funcţii membru (în cazul nostru lansare_rachete(char 
*Parola)), adică programul este forţat să joace după regulile impuse de creatorul său. Pentru a 
restricţiona accesul la membrii clasei, se poate folosi cuvântul cheie private.  

class silo  
{  
 private String locatia;  
 private int tip_racheta;  
 private int lanseaza_rachete; // daca este 0 nu se lanseaza,   // daca este 1 se lanseaza  
private String parola;  
 public silo(int tipRacheta, String loc)  
 {  
 tip_racheta=tipRacheta;  
 locatia=loc;  
 lanseaza_rachete=0;  
 parola="hillary";  
 }  
 public void lansare_rachete(String Parola)  
 {  
 if (parola.compareTo(Parola)==0)  
 lanseaza_rachete=1;  
 else lanseaza_rachete=0;  
 }  

 public void mesaj()  


 {  
 if (lanseaza_rachete==1)  
 {  
 System.out.println("parola corecta; rachetele s-au lansat");   System.out.println("tip
rachete="+tip_racheta+" --   destinatie="+locatia+" \n");   }  
 else  
 System.out.println("parola incorecta; rachetele nu s-au   lansat \n");  
 }  
}  
  
public class siloTest  
{  
 public static void main(String args[ ])  
 {  
  
 silo s=new silo(1,"Moscova");  
 s.lansare_rachete("ana");  
 s.mesaj();  
 s.lansare_rachete("hillary");  
 s.mesaj();  
 }  

 

Să considerăm şi alte câteva exemple utile: 


package pac1;  
public class produs  
{  
 private String denumire;  
 protected int cantitate;  
 public int cod;  
 public produs(String den,int cant,int cod)  
 {  
 denumire=den;  
 cantitate=cant;  
 this.cod=cod;  
 }  
 public void afis( )  
 {  
 System.out.println("denumire="+denumire+"  
 cantitate="+cantitate+" cod="+cod+" \n");   }  
}  

package pac2;  
import pac1.produs;  
public class TestProdus  
{  
 public static void main(String args[ ])  
 {  
 produs p=new produs("Poiana",23,287);  
 p.afis( );  
 p.cod=112; // ok; "cod" este "public"  
 p.afis();  
// p.cantitate+=10; eroare - "cantitate" este "protected"  // p.denumire="Laura";
eroare - "denumire" este "private"   }  
}  
package pac;  
class produs  
{  
 private String denumire;  
 protected int cantitate;  
 public int cod;  
 public produs(String den,int cant,int cod)  
 {  
 denumire=den;  
 cantitate=cant;  
 this.cod=cod;  
 }  
 public void afis()  
 {  
 System.out.println("denumire="+denumire+"  
 cantitate="+cantitate+" cod="+cod+" \n");   }  

 

package pac;  
public class TestProdus  
{  
 public static void main(String args[])  
 {  
 produs p=new produs("Poiana",23,287);  
 p.afis();  
 p.cod=112; // ok; "cod" este "public"  
 p.cantitate+=10;// ok - "cantitate" este "protected"   p.afis();  
// p.denumire="Laura"; eroare - "denumire" este "private"   }  
}  

4. Clase abstracte. Interfeţe în Java 

Cateodată avem nevoie să declarăm o clasă, dar nu ştim cum să definim toate metodele
care  aparţin clasei. De exemplu, sa încercăm să declarăm o clasă numită Mamifer în care să
includem o  metoda membru numită MarcheazaTeritoriul(). Oricum, nu ştim cum să scriem 
MarcheazaTeritoriul() pentru ca aceasta se întâmplă diferit în funcţie de specia de Mamifer . 
Bineînţeles, o să rezolvăm acest lucru derivând subclase din clasa Mamifer, clase cum ar fi 
Maimuta şi Om. Dar ce cod să conţină funcţia MarcheazaTeritoriul() din clasa Mamifer?  
În Java funcţia MarcheazaTeritoriul() se poate declara în clasa Mamifer ca fiind o metodă
abstract. Făcând aceasta se permite declararea metodei fără a scrie cod pentru subclase. Se va
scrie  însă cod în subclase.  
Dacă o metodă este declarată abstract, atunci şi clasa trebuie declarată abstract. Pentru 
Mamifer şi subclasele sale, acest lucru înseamnă că trebuie să arate după cum urmează:  

abstract class Mamifer {  


abstract void MarcheazaTeritoriul();  
}  
public class Om extends Mamifer {  
public void MarcheazaTeritoriul() {  
//cod prin care se marcheaza teritoriul construind un gard  }  
}  

public class UnMembruAlGastii extends Mamifer {  


public void MarcheazaTeritoriul() {  
//cod prin care se marcheaza teritoriul cu graffiti  
}  
}  

public class Maimuta extends Mamifer {  


public void MarcheazaTeritoriul() {  
//cod prin care se marcheaza teritoriul cu frunze si crengi  }  
}  

În declaraţiile precedente, clasa Mamifer nu conţine nici un fel de cod pentru 


MarcheazaTeritoriul(). Clasa Om poate conţine cod despre cum omul marchează teritoriul 
construind un gard în jurul lui, în timp ce clasa UnMembruAlGastii poate conţine cod despre
cum  acesta îşi marchează teritoriul pictând cu spray graffiti. Clasa Maimuta işi va marca
teritoriul cu  ajutorul crengilor (sau altfel). 
 

Tipic, o clasă abstractă va avea câteva metode declarate abstract şi altele care nu sunt 
declarate astfel. Dacă se declară o clasă care este în totalitate abstractă, atunci se declară ceea ce
în  Java este cunoscut sub numele de interfaţă. O interfaţă este o clasă abstractă în întregime. Se
pot  deriva clase dintr-o interfaţă într-o manieră complet analoagă cu aceea a derivării claselor
din alte  clase.  
Ca exemplu, să presupunem că dezvoltăm o aplicaţie care trebuie să afişeze ora.
Utilizatorii  vor avea două opţiuni pentru a obţine această informaţie. Pot să o preia dintr-un
ceas electronic sau  dintr-un ceas cu limbi. S-ar putea implementa ca mai jos:  

interface Ceas {  


public String CitesteTimpul(int ora);  
}  

class CeasMecanic implements Ceas {  


public String CitesteTimpul(int ora) {  
StringBuffer str = new StringBuffer();  
for (int i=0; i < ora; i++) 
str.append("CeasCuLimbi ");  
return str.toString();  
}  
}  
class CeasElectronic implements Ceas {  
public String CitesteTimpul(int ora) {  
return new String("Este ora " + hour + ":00");  
}  
}  

In acest exemplu, Ceas este o interfaţă care furnizează o singură funcţie,


CitesteTimpul().  Aceasta înseamnă că orice clasă care este derivată (sau, în alte cuvinte,
implementată - implements) din interfaţa Ceas trebuie să implementeze o funcţie
CitesteTimpul(). CeasCuLimbi este un exemplu de clasă care implementează Ceas, şi săi
observăm că în loc de class CeasCuLimbi extends Ceas, sintaxa care ar fi trebuit folosită în
cazul în care Ceas ar fi fost o  clasă abstractă, este folosita sintaxa class CeasCuLimbi
implements Ceas.  
Pentru că CeasCuLimbi implementează interfaţa Ceas, ea furnizează o funcţie 
CitesteTimpul(). Clasa CeasElectronic implementează de asemenea Ceas şi furnizează o
funcţie  CitesteTimpul().  

Precizări: 
1. Interfeţele şi superclasele nu se exclud reciproc. O clasă nouă poate fi derivată dintr-o 
superclasă şi poate implementa una sau mai multe interfeţe. Acest lucru se poate efectua 
ca mai jos, pentru o clasă care implementează doua interfeţe şi are o superclasă:  

class SubClasaMea extends SuperClasaMea implements  


 PrimaInterfata, ADouaInterfata  { // implementarea clasei } 

Pentru că este posibil ca o clasă să implementeze mai mult de o interfaţă, interfeţele


reprezintă o alternativă pentru moştenirea multiplă, care nu este permisă în Java. 

2. Metodele abstracte sunt metode care nu au corp de implementare. Ele sunt declarate 
  

numai pentru a forţa subclasele, care se vor instanţia, să implementeze metodele 


respective.  
3. Metodele abstracte trebuie declarate numai în interiorul claselor care au fost declarate
abstracte. Altfel compilatorul va semnala o eroare de compilare. Orice subclasă a
claselor abstracte care nu este declarată abstractă trebuie să ofere o implementare a
acestor metode, altfel va fi generată o eroare de compilare. 
4. Prin acest mecanism ne asigurăm că toate instanţele care pot fi convertite către clasa care
conţine definiţia unei metode abstracte au implementată metoda respectivă dar, în
acelaşi timp, nu este nevoie să implementăm în nici un fel metoda chiar în clasa care o
declară, deoarece nu ştim pe moment cum va fi implementată. 
5. O metodă statică nu poate fi declarată şi abstractă pentru că o metodă statică este implicit
finală şi nu poate fi rescrisă. 
III. MODUL DE LUCRU 

1. Se foloseşte utilitarul instalat la primul laborator: Eclipse sau NetBeans sau oricare
altul! 2. Pe calculatorul personal este instalata o versiune functionala JDK, in
conformitate cu precizarile de la primul laborator.

IV. TEMĂ 

Se vor parcurge toate exemplele prezentate în platforma de laborator testându-se practic  (acolo
unde este cazul).  

Implementaţi clasa Mamifer din cadrul exemplului de mai sus astfel:  - scrieţi codul pentru
implementarea metodei: public void MarcheazaTeritoriul(), în fiecare din clasele: Om,
UnMembruAlGastii, Maimuta; 
- încercaţi să apelaţi metoda: public void MarcheazaTeritoriul(), în cadrul claselor, şi
din afara lor. 
Explicaţi, la fiecare caz în parte, rezultatele obţinute. 

Integraţi clasele Televizor şi TelevizorColor într-un program Java funcţional, în care să se 
definească câte două instanţe pentru fiecare din clasele de mai sus şi să se folosească 
metodele definite pentru a afişa proprietăţile instanţelor.  
Explicaţi la fiecare caz în parte rezultatele obţinute.  
  

TEHNOLOGII JAVA 
LUCRARE DE LABORATOR 5  

Excepţii în Java. Aplicaţii 

I. SCOPUL LUCRĂRII 

Lucrarea de faţă are rolul de a prezenta şi familiariza studentul cu noţiuni privind excepţiile
şi  tratarea acestora în limbajului Java.  
La sfârşitul acestei lucrări, studentul va avea posibilitatea să scrie programe Java în care să 
folosească noţiunile legate de excepţii precum şi tratarea acestora.  

II. NOŢIUNI TEORETICE 

 Observaţie: Vezi noţiunile prezentate în cursul 3. 

1. Tratarea excepţiilor 
Tratarea excepţiilor se realizează prin intermediul blocurilor de instrucţiuni try, catch şi finally.
O  secvenţă de cod care tratează anumite excepţii trebuie să arate astfel: 

try { 
// Instructiuni care pot genera exceptii 

catch (TipExceptie1 variabila) { 
// Tratarea exceptiilor de tipul 1 

catch (TipExceptie2 variabila) { 
// Tratarea exceptiilor de tipul 2 

. . . 
finally { 
// Cod care se executa indiferent 
// daca apar sau nu exceptii 

Să considerăm următorul exemplu: citirea unui fişier octet cu octet şi afisarea lui pe ecran. Fără
a  folosi tratarea excepţiilor metoda responsabilă cu citirea fişierului ar arăta astfel: 
 

public static void citesteFisier(String fis) { 


FileReader f = null; 
// Deschidem fisierul 
System.out.println("Deschidem fisierul " + fis); 
f = new FileReader(fis); 
// Citim si afisam fisierul caracter cu caracter 
int c; 
while ( (c=f.read()) != -1) 
System.out.print((char)c); 
// Inchidem fisierul 
System.out.println("\\nInchidem fisierul " + fis); 
f.close(); 

Observatii: 
Această secvenţă de cod va furniza erori la compilare deoarece în Java tratarea erorilor
este  obligatorie. Folosind mecanismul excepţiilor metoda citeste îşi poate trata singură erorile
care pot  surveni pe parcursul execuţiei sale.  
Mai jos este codul complte şi corect al unui program ce afişează pe ecran conţinutul unui 
fişier al cărui nume este primit ca argument de la linia de comandă. Tratarea excepţiilor este 
realizată complet chiar de către metoda citeste. 
import java .io .*; 
public class CitireFisier { 
public static void citesteFisier ( String fis) { 
FileReader f = null ; 
try { 
// Deschidem fisierul 
System . out. println (" Deschidem fisierul " + fis); 
f = new FileReader (fis ); 
// Citim si afisam fisierul caracter cu caracter 
int c; 
while ( (c=f. read ()) != -1) 
System . out. print (( char )c); 
} catch ( FileNotFoundException e) { 
// Tratam un tip de exceptie
 

System . err. println (" Fisierul nu a fost gasit !"); 


System . err. println (" Exceptie : " + e. getMessage ()); 
System . exit (1); 
} catch ( IOException e) { 
// Tratam alt tip de exceptie 
System . out. println (" Eroare la citirea din fisier !"); 
e. printStackTrace (); 
} finally { 
if (f != null ) { 
// Inchidem fisierul 
System . out. println ("\ nInchidem fisierul ."); 
try { 
f. close (); 
} catch ( IOException e) { 
System . err. println (" Fisierul nu poate fi inchis !"); 
e. printStackTrace (); 




public static void main ( String args []) { 
if ( args . length > 0) 
citesteFisier ( args [0]) ; 
else 
System . out. println (" Lipseste numele fisierului !"); 

}
 

2. “Aruncarea” excepţiilor 

În exemplul de mai sus dacă nu facem tratarea excepţiilor în cadrul metodei citeste atunci
metoda  apelantă (main) va trebui să facă acest lucru: 
import java .io .*; 
public class CitireFisier { 
public static void citesteFisier ( String fis) 
throws FileNotFoundException , IOException { 
FileReader f = null ; 
f = new FileReader (fis ); 
int c; 
while ( (c=f. read ()) != -1) 
System . out. print (( char )c); 
f. close (); 

public static void main ( String args []) { 
if ( args . length > 0) { 
try { 
citesteFisier ( args [0]) ; 
} catch ( FileNotFoundException e) { 
System . err. println (" Fisierul nu a fost gasit !"); 
System . err. println (" Exceptie : " + e); 
} catch ( IOException e) { 
System . out. println (" Eroare la citirea din fisier !"); 
e. printStackTrace (); 

} else 
System . out. println (" Lipseste numele fisierului !"); 

Observaţi că, în acest caz, nu mai putem diferenţia excepţiile provocate de citirea din fişier şi de 
inchiderea fişierului, ambele fiind de tipul IOException. 
De asemenea, inchiderea fişierului nu va mai fi facută în situatia în care apare o excepţie la
citirea  din fişier. Este situaţia în care putem folosi blocul finally fără a folosi nici un bloc catch:
public static void citesteFisier(String fis)
 

throws FileNotFoundException, IOException { 


FileReader f = null; 
try { 
f = new FileReader(numeFisier); 
int c; 
while ( (c=f.read()) != -1) 
System.out.print((char)c); 

finally { 
if (f!=null) 
f.close(); 

Metoda apelantă poate arunca la rândul sâu excepţiile mai departe către metoda care a apelat-o
la  rândul ei. Această înlănţuire se termină cu metoda main care, dacă va arunca excepţiile ce pot 
apărea în corpul ei, va determina trimiterea excepţiilor către maşina virtuală Java. 
Tratarea excepţiilor de către JVM se face prin terminarea programului şi afişarea
informaţiilor  despre excepţia care a determinat acest lucru. 
Exemplu: Comuniacarea client/server prin datagrame 

/* 
* Server 
*/ 
public class DatagramServer { 
  public static final int PORT = 8200; 
  private DatagramSocket socket = null ; 
  DatagramPacket cerere , raspuns = null ; 
  
  public void start () throws IOException { 
  socket = new DatagramSocket ( PORT ); 
  try { 
  while ( true ) { 
  // Declaram pachetul in care va fi receptionata cererea  
  byte [] buf = new byte [256]; 
  cerere = new DatagramPacket (buf , buf. length ); 
  System . out. println (" Asteptam un pachet ... "); 
  socket . receive ( cerere ); 
  // Aflam adresa si portul de la care vine cererea 
  InetAddress adresa = cerere . getAddress (); 
  int port = cerere . getPort (); 
  // Construim raspunsul 
  String mesaj = " Hai " + new String ( cerere . getData ()); 
  buf = mesaj . getBytes ();
 

 // Trimitem un pachet cu raspunsul catre client 


  raspuns = new DatagramPacket (buf , buf.length , adresa , port );  socket .
send ( raspuns ); 
  } 
  }  
  finally { 
  if ( socket != null ) 
  socket . close (); 
  } 
  } 
  
  public static void main ( String [] args ) throws IOException { 
  new DatagramServer (). start (); 
  } 

/* 
* Client 
*/ 
import java . net .*; 
import java .io .*; 

public class DatagramClient { 

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


  // Adresa IP si portul la care ruleaza serverul 
  InetAddress adresa = InetAddress . getByName ("127.0.0.1");  int
port =8200; 
  DatagramSocket socket = null ; 
  DatagramPacket packet = null ; 
  byte buf []; 
  try { 
  // Construim un socket pentru comunicare 
  socket = new DatagramSocket (); 
  // Construim si trimitem pachetul cu cererea catre server  buf = "
Craiova ". getBytes (); 
  packet = new DatagramPacket (buf , buf.length , adresa , port );  socket .
send ( packet ); 
  // Asteaptam pachetul cu raspunsul de la server 
  buf = new byte [256]; 
  packet = new DatagramPacket (buf , buf. length ); 
  socket . receive ( packet ); 
  // Afisam raspunsul (" Hai Craiova !") 
  System . out. println ( new String ( packet . getData ()));  }  
  finally { 
  if ( socket != null ) 
  socket . close (); 
  } 
  } 
}
 

∙ Precizări: 
O datagramă, in Java, este reprezentata printr-un obiect din clasa DatagramPacket.
Rutarea  datagramelor de la o maşină la alta se face exclusiv pe baza informaţiilor conţinute de
acestea.  Primirea şi trimiterea datagramelor se realizează prin intermediul unui socket, modelat
prin  intermediul clasei DatagramSocket. 

Clasa DatagramPacket conţine următorii constructori: 

DatagramPacket(byte[] buf, int length, InetAddress address, int port) 


DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int
port) DatagramPacket(byte[] buf, int offset, int length, SocketAddress
address) 
DatagramPacket(byte[] buf, int length, SocketAddress address) 
DatagramPacket(byte[] buf, int length) 
DatagramPacket(byte[] buf, int offset, int length) 

Primele două perechi de constructori sunt pentru creare pachetelor ce vor fi expediate, 
diferenţa între ele fiind utilizarea claselor InetAddress, respectiv SocketAddress pentru
specificarea  adresei desinaţie. A treia pereche de constructori este folosită pentru crearea unui
pachet în care vor  fi recepţionate date, ei nespecificând vreo sursă sau destinaţie.  
După crearea unui pachet procesul de trimitere şi primire a acestuia implică apelul 
metodelor send şi receive ale clasei DatagramSocket. Deoarece toate informaţiile sunt incluse în 
datagramă, acelaşi socket poate fi folosit atât pentru trimiterea de pachete, eventual către
destinaţii  diferite, cât şi pentru recepţionarea acestora de la diverse surse. In cazul în care
refolosim pachete,  putem schimba conţinutul acestora cu metoda setData(), precum şi adresa la
care le trimitem prin  setAddress(), setPort() ¸si setSocketAddress().  
Extragerea informaţiilor conţiunte de un pachet se realizează prin metoda getData() din clasa 
DatagramPacket. De asemenea, această clasă oferă metode pentru aflarea adresei IP şi a portului 
procesului care a trimis datagrama, pentru a-i putea răspunde dacă este necesar. Acestea sunt: 
getAdress(), getPort() ¸si getSocketAddress(). 

3. Introducerea datelor de la tastatură 


O metodă pentru introducerea datelor de la tastatură ar fi: 

static String citireSir( ) throws IOException{ 


InputStreamReader f=new InputStreamReader(System.in);  
BufferedReader g=new BufferedReader(f); 
String h; 
h=g.readLine( ); 
return h; 

∙ Precizări: 
În corpul metodei citireSir apar instrucţiuni de lucru cu aşa numitele fluxuri. Un flux 
(stream) poate fi flux de intrare sau flux de ieşire. Un flux de intrare este o cale pe care o parcurg 
datele de la o sursă de date la spaţiul din memoria internă a calculatorului unde se înregistrează 
valorile variabilelor programului care solicită datele, iar un flux de ieşire este o cale pe care o 
parcurg datele de la spaţiul din memoria internă rezervat variabilelor unui program spre o
destinaţie 
 

unde se înregistrează datele.  


Ca urmare a apelului metodei citesteSir(), se creează fluxul necesar pentru a prelua un şir de la 
tastatură şi apoi se trece la execuţia metodei readLine( ). Metoda readLine( ) este o metodă care  
aparţine unei clase din Java API. În momentul în care se începe execuţia ei, programul trece în 
starea de aşteptare a unui şir de caractere.  
Şirul de caractere pe care-l tastăm este preluat de program după ce acţionăm tasta Enter.
Se  impune să precizăm că şirul tastat de noi este preluat de program şi dacă în locul tastei Enter
tastăm  Alt-13.  
După ce tastăm Enter, sau Alt-13, şirul introdus de noi este preluat ca valoare a variabilei
h  din metoda citireSir( ) şi returnat. Ca urmare, variabila s din instrucţiunea s=citireSir( ) va
avea ca  valoare şirul tastat de noi.  
Valoarea variabilei s este convertită într-un număr întreg de instrucţiunea: 
a=Integer.valueOf(s).intValue( );  
Şirul pe care îl introducem de la astatură trebuie să fie un număr întreg. Dacă nu
respectăm  această condiţie, atunci Java emite un mesaj de eroare şi abandonează execuţia (vezi
cursul 3:  Excepţii şi tratarea acestora în Java). 
Pe parcurs vom avea şi probleme în care trebuie să introducem numere reale pe care le vom  
asocia unor variabile de tip float. În acest caz trebuie să folosim pentru conversia de la un şir s la
un  număr real r instrucţiunea: 
r=Float.valueOf(s).floatValue( ); 

Exemplu util: 

import java.io.*; 

class Putere 

public static void main (String[] args) throws IOException 
{  
InputStreamReader inStream =  
new InputStreamReader( System.in ) ; 
BufferedReader stdin =  
new BufferedReader( inStream ); 

String inData; 
int num, square; // declaram doua variabile intregi 
System.out.println("Introduceti un intreg:"); 
inData = stdin.readLine(); 

num = Integer.parseInt( inData ); // se converteste inData la intreg 


square = num * num ; // calculul puterii 
System.out.println("Patratul lui " + inData + " este " + square); 

}
  
III. MODUL DE LUCRU 

1. Se foloseşte utilitarul instalat la primul laborator: Eclipse sau NetBeans sau oricare
altul! 2. Pe calculatorul personal este instalata o versiune functionala JDK, in conformitate
cu precizarile de la primul laborator.

IV. TEMĂ 

Se vor parcurge toate exemplele prezentate în platforma de laborator testându-se practic  (acolo
unde este cazul).  

Implementaţi o clasa ce descrie parţial o stivă de numere întregi cu operaţiile de adăugare a 


unui element, respective de scoatere a elementului din vârful stivei. Dacă presupunem că 
stiva poate memora maxim 100 de elemente, ambele operaţii pot provoca excepţii. Pentru a
personaliza aceste excepţii se va crea o clasă specifică denumită ExceptieStiva.  

Implementaţi o aplicaţie client/server pentru comunicarea cu socket-uri(socluri de 


comunicatie). 
  

TEHNOLOGII JAVA 
LUCRARE DE LABORATOR 5  

Excepţii în Java. Aplicaţii 

I. SCOPUL LUCRĂRII 

Lucrarea de faţă are rolul de a prezenta şi familiariza studentul cu noţiuni privind excepţiile
şi  tratarea acestora în limbajului Java.  
La sfârşitul acestei lucrări, studentul va avea posibilitatea să scrie programe Java în care să 
folosească noţiunile legate de excepţii precum şi tratarea acestora.  

II. NOŢIUNI TEORETICE 

 Observaţie: Vezi noţiunile prezentate în cursul 3. 

1. Tratarea excepţiilor 
Tratarea excepţiilor se realizează prin intermediul blocurilor de instrucţiuni try, catch şi finally.
O  secvenţă de cod care tratează anumite excepţii trebuie să arate astfel: 

try { 
// Instructiuni care pot genera exceptii 

catch (TipExceptie1 variabila) { 
// Tratarea exceptiilor de tipul 1 

catch (TipExceptie2 variabila) { 
// Tratarea exceptiilor de tipul 2 

. . . 
finally { 
// Cod care se executa indiferent 
// daca apar sau nu exceptii 

Să considerăm următorul exemplu: citirea unui fişier octet cu octet şi afisarea lui pe ecran. Fără
a  folosi tratarea excepţiilor metoda responsabilă cu citirea fişierului ar arăta astfel: 
 

public static void citesteFisier(String fis) { 


FileReader f = null; 
// Deschidem fisierul 
System.out.println("Deschidem fisierul " + fis); 
f = new FileReader(fis); 
// Citim si afisam fisierul caracter cu caracter 
int c; 
while ( (c=f.read()) != -1) 
System.out.print((char)c); 
// Inchidem fisierul 
System.out.println("\\nInchidem fisierul " + fis); 
f.close(); 

Observatii: 
Această secvenţă de cod va furniza erori la compilare deoarece în Java tratarea erorilor
este  obligatorie. Folosind mecanismul excepţiilor metoda citeste îşi poate trata singură erorile
care pot  surveni pe parcursul execuţiei sale.  
Mai jos este codul complte şi corect al unui program ce afişează pe ecran conţinutul unui 
fişier al cărui nume este primit ca argument de la linia de comandă. Tratarea excepţiilor este 
realizată complet chiar de către metoda citeste. 
import java .io .*; 
public class CitireFisier { 
public static void citesteFisier ( String fis) { 
FileReader f = null ; 
try { 
// Deschidem fisierul 
System . out. println (" Deschidem fisierul " + fis); 
f = new FileReader (fis ); 
// Citim si afisam fisierul caracter cu caracter 
int c; 
while ( (c=f. read ()) != -1) 
System . out. print (( char )c); 
} catch ( FileNotFoundException e) { 
// Tratam un tip de exceptie
 

System . err. println (" Fisierul nu a fost gasit !"); 


System . err. println (" Exceptie : " + e. getMessage ()); 
System . exit (1); 
} catch ( IOException e) { 
// Tratam alt tip de exceptie 
System . out. println (" Eroare la citirea din fisier !"); 
e. printStackTrace (); 
} finally { 
if (f != null ) { 
// Inchidem fisierul 
System . out. println ("\ nInchidem fisierul ."); 
try { 
f. close (); 
} catch ( IOException e) { 
System . err. println (" Fisierul nu poate fi inchis !"); 
e. printStackTrace (); 




public static void main ( String args []) { 
if ( args . length > 0) 
citesteFisier ( args [0]) ; 
else 
System . out. println (" Lipseste numele fisierului !"); 

}
 

2. “Aruncarea” excepţiilor 

În exemplul de mai sus dacă nu facem tratarea excepţiilor în cadrul metodei citeste atunci
metoda  apelantă (main) va trebui să facă acest lucru: 
import java .io .*; 
public class CitireFisier { 
public static void citesteFisier ( String fis) 
throws FileNotFoundException , IOException { 
FileReader f = null ; 
f = new FileReader (fis ); 
int c; 
while ( (c=f. read ()) != -1) 
System . out. print (( char )c); 
f. close (); 

public static void main ( String args []) { 
if ( args . length > 0) { 
try { 
citesteFisier ( args [0]) ; 
} catch ( FileNotFoundException e) { 
System . err. println (" Fisierul nu a fost gasit !"); 
System . err. println (" Exceptie : " + e); 
} catch ( IOException e) { 
System . out. println (" Eroare la citirea din fisier !"); 
e. printStackTrace (); 

} else 
System . out. println (" Lipseste numele fisierului !"); 

Observaţi că, în acest caz, nu mai putem diferenţia excepţiile provocate de citirea din fişier şi de 
inchiderea fişierului, ambele fiind de tipul IOException. 
De asemenea, inchiderea fişierului nu va mai fi facută în situatia în care apare o excepţie la
citirea  din fişier. Este situaţia în care putem folosi blocul finally fără a folosi nici un bloc catch:
public static void citesteFisier(String fis)
 

throws FileNotFoundException, IOException { 


FileReader f = null; 
try { 
f = new FileReader(numeFisier); 
int c; 
while ( (c=f.read()) != -1) 
System.out.print((char)c); 

finally { 
if (f!=null) 
f.close(); 

Metoda apelantă poate arunca la rândul sâu excepţiile mai departe către metoda care a apelat-o
la  rândul ei. Această înlănţuire se termină cu metoda main care, dacă va arunca excepţiile ce pot 
apărea în corpul ei, va determina trimiterea excepţiilor către maşina virtuală Java. 
Tratarea excepţiilor de către JVM se face prin terminarea programului şi afişarea
informaţiilor  despre excepţia care a determinat acest lucru. 

Exemplu: Comuniacarea client/server prin datagrame 

/* 
* Server 
*/ 
public class DatagramServer { 
  public static final int PORT = 8200; 
  private DatagramSocket socket = null ; 
  DatagramPacket cerere , raspuns = null ; 
  
  public void start () throws IOException { 
  socket = new DatagramSocket ( PORT ); 
  try { 
  while ( true ) { 
  // Declaram pachetul in care va fi receptionata cererea  
  byte [] buf = new byte [256]; 
  cerere = new DatagramPacket (buf , buf. length ); 
  System . out. println (" Asteptam un pachet ... "); 
  socket . receive ( cerere ); 
  // Aflam adresa si portul de la care vine cererea 
  InetAddress adresa = cerere . getAddress (); 
  int port = cerere . getPort (); 
  // Construim raspunsul 
  String mesaj = " Hai " + new String ( cerere . getData ()); 
  buf = mesaj . getBytes ();
 

 // Trimitem un pachet cu raspunsul catre client 


  raspuns = new DatagramPacket (buf , buf.length , adresa , port );  socket .
send ( raspuns ); 
  } 
  }  
  finally { 
  if ( socket != null ) 
  socket . close (); 
  } 
  } 
  
  public static void main ( String [] args ) throws IOException { 
  new DatagramServer (). start (); 
  } 

/* 
* Client 
*/ 

import java . net .*; 


import java .io .*; 
public class DatagramClient { 

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


  // Adresa IP si portul la care ruleaza serverul 
  InetAddress adresa = InetAddress . getByName ("127.0.0.1");  int
port =8200; 
  DatagramSocket socket = null ; 
  DatagramPacket packet = null ; 
  byte buf []; 
  try { 
  // Construim un socket pentru comunicare 
  socket = new DatagramSocket (); 
  // Construim si trimitem pachetul cu cererea catre server  buf = "
Craiova ". getBytes (); 
  packet = new DatagramPacket (buf , buf.length , adresa , port );  socket .
send ( packet ); 
  // Asteaptam pachetul cu raspunsul de la server 
  buf = new byte [256]; 
  packet = new DatagramPacket (buf , buf. length ); 
  socket . receive ( packet ); 
  // Afisam raspunsul (" Hai Craiova !") 
  System . out. println ( new String ( packet . getData ()));  }  
  finally { 
  if ( socket != null ) 
  socket . close (); 
  } 
  } 
}
 

∙ Precizări: 
O datagramă, in Java, este reprezentata printr-un obiect din clasa DatagramPacket.
Rutarea  datagramelor de la o maşină la alta se face exclusiv pe baza informaţiilor conţinute de
acestea.  Primirea şi trimiterea datagramelor se realizează prin intermediul unui socket, modelat
prin  intermediul clasei DatagramSocket. 

Clasa DatagramPacket conţine următorii constructori: 

DatagramPacket(byte[] buf, int length, InetAddress address, int port) 


DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int
port) DatagramPacket(byte[] buf, int offset, int length, SocketAddress
address) 
DatagramPacket(byte[] buf, int length, SocketAddress address) 
DatagramPacket(byte[] buf, int length) 
DatagramPacket(byte[] buf, int offset, int length) 

Primele două perechi de constructori sunt pentru creare pachetelor ce vor fi expediate, 
diferenţa între ele fiind utilizarea claselor InetAddress, respectiv SocketAddress pentru
specificarea  adresei desinaţie. A treia pereche de constructori este folosită pentru crearea unui
pachet în care vor  fi recepţionate date, ei nespecificând vreo sursă sau destinaţie.  
După crearea unui pachet procesul de trimitere şi primire a acestuia implică apelul 
metodelor send şi receive ale clasei DatagramSocket. Deoarece toate informaţiile sunt incluse în 
datagramă, acelaşi socket poate fi folosit atât pentru trimiterea de pachete, eventual către
destinaţii  diferite, cât şi pentru recepţionarea acestora de la diverse surse. In cazul în care
refolosim pachete,  putem schimba conţinutul acestora cu metoda setData(), precum şi adresa la
care le trimitem prin  setAddress(), setPort() ¸si setSocketAddress().  
Extragerea informaţiilor conţiunte de un pachet se realizează prin metoda getData() din clasa 
DatagramPacket. De asemenea, această clasă oferă metode pentru aflarea adresei IP şi a portului 
procesului care a trimis datagrama, pentru a-i putea răspunde dacă este necesar. Acestea sunt: 
getAdress(), getPort() ¸si getSocketAddress(). 

3. Introducerea datelor de la tastatură 


O metodă pentru introducerea datelor de la tastatură ar fi: 

static String citireSir( ) throws IOException{ 


InputStreamReader f=new InputStreamReader(System.in);  
BufferedReader g=new BufferedReader(f); 
String h; 
h=g.readLine( ); 
return h; 

∙ Precizări: 
În corpul metodei citireSir apar instrucţiuni de lucru cu aşa numitele fluxuri. Un flux 
(stream) poate fi flux de intrare sau flux de ieşire. Un flux de intrare este o cale pe care o parcurg 
datele de la o sursă de date la spaţiul din memoria internă a calculatorului unde se înregistrează 
valorile variabilelor programului care solicită datele, iar un flux de ieşire este o cale pe care o 
parcurg datele de la spaţiul din memoria internă rezervat variabilelor unui program spre o
destinaţie 
 

unde se înregistrează datele.  


Ca urmare a apelului metodei citesteSir(), se creează fluxul necesar pentru a prelua un şir de la 
tastatură şi apoi se trece la execuţia metodei readLine( ). Metoda readLine( ) este o metodă care  
aparţine unei clase din Java API. În momentul în care se începe execuţia ei, programul trece în 
starea de aşteptare a unui şir de caractere.  
Şirul de caractere pe care-l tastăm este preluat de program după ce acţionăm tasta Enter.
Se  impune să precizăm că şirul tastat de noi este preluat de program şi dacă în locul tastei Enter
tastăm  Alt-13.  
După ce tastăm Enter, sau Alt-13, şirul introdus de noi este preluat ca valoare a variabilei
h  din metoda citireSir( ) şi returnat. Ca urmare, variabila s din instrucţiunea s=citireSir( ) va
avea ca  valoare şirul tastat de noi.  
Valoarea variabilei s este convertită într-un număr întreg de instrucţiunea: 
a=Integer.valueOf(s).intValue( );  
Şirul pe care îl introducem de la astatură trebuie să fie un număr întreg. Dacă nu
respectăm  această condiţie, atunci Java emite un mesaj de eroare şi abandonează execuţia (vezi
cursul 3:  Excepţii şi tratarea acestora în Java). 
Pe parcurs vom avea şi probleme în care trebuie să introducem numere reale pe care le vom  
asocia unor variabile de tip float. În acest caz trebuie să folosim pentru conversia de la un şir s la
un  număr real r instrucţiunea: 
r=Float.valueOf(s).floatValue( ); 

Exemplu util: 

import java.io.*; 

class Putere 

public static void main (String[] args) throws IOException 
{  
InputStreamReader inStream =  
new InputStreamReader( System.in ) ; 
BufferedReader stdin =  
new BufferedReader( inStream ); 

String inData; 
int num, square; // declaram doua variabile intregi 
System.out.println("Introduceti un intreg:"); 
inData = stdin.readLine(); 

num = Integer.parseInt( inData ); // se converteste inData la intreg 


square = num * num ; // calculul puterii 
System.out.println("Patratul lui " + inData + " este " + square); 

}
  

III. MODUL DE LUCRU 


1. Se foloseşte utilitarul instalat la primul laborator: Eclipse sau NetBeans sau oricare
altul! 2. Pe calculatorul personal este instalata o versiune functionala JDK, in conformitate
cu precizarile de la primul laborator.

IV. TEMĂ 

Se vor parcurge toate exemplele prezentate în platforma de laborator testându-se practic  (acolo
unde este cazul).  

Implementaţi o clasa ce descrie parţial o stivă de numere întregi cu operaţiile de adăugare a 


unui element, respective de scoatere a elementului din vârful stivei. Dacă presupunem că 
stiva poate memora maxim 100 de elemente, ambele operaţii pot provoca excepţii. Pentru a
personaliza aceste excepţii se va crea o clasă specifică denumită ExceptieStiva.  

Implementaţi o aplicaţie client/server pentru comunicarea cu socket-uri(socluri de 


comunicatie). 

  

TEHNOLOGII JAVA 
LUCRARE DE LABORATOR 6  

Componentele interfeţei grafice. Evenimente generate


de  componentele AWT  

I. SCOPUL LUCRĂRII 

Lucrarea de faţă are rolul de a prezenta şi familiariza studentul cu modul de construire a 


unei interfeţe grafice utilizator si cu modul de tratare a evenimentelor generate de
componentele  grafice. Se vor prezenta câteva componente vizuale utile, împreună cu modul de
creare şi  dispunere a acestora pe suprafaţa unui applet.  
La sfârşitul acestei lucrări, studentul va avea posibilitatea să scrie mini-aplicaţii Java în
care  să utilizeze noţiunile învăţate si să scrie applet-uri Java cu interfaţă grafică complet
funcţională.  

II. NOŢIUNI TEORETICE 


Observaţie: Vezi noţiunile prezentate în cursul 5. 

1. Construirea unei interfeţe grafice 

Interfeţele grafice utilizator GUI (graphic user interface) sunt o parte importantă a 
oricărui program. Pachetul java.awt (Abstract Window Toolkit) furnizează funţionalităţi
extinse  în acest sens.  

1.1 Componentele interfeţei grafice  

Componentele Java sunt implementate printr-o serie de subclase ale superclasei 


java.awt.Component şi ale superclasei java.awt.MenuComponent.  
O modalitate de a grupa componentele grafice este următoarea: componente vizuale,
componente  container şi componene meniu.  
Există 11 componente vizuale. În cele ce urmează vom prezenta numai o parte dintre 
acestea: Button, Checkbox, Choice, Label, List, TextArea, TextField. Pentru a utiliza una 
dintre acestea într-o GUI, se va crea întâi o instanţă prin apelarea constructorului
corespunzător,  apoi se va adăuga componenta unui container.  
Există 4 componente container: Applet, Frame, Panel, Dialog (vor fi prezentate în
următoarele  lucrări de laborator). Container-ele sunt componente capabile să conţină alte
componente în  cadrul lor.  
Câteva metode sunt implementate de toate componentele vizuale şi container, în virtutea 
moştenirii din clasa java.awt.Component.  

• getSize( ) – returnează dimensiunea unei componente. Tipul returnat este Dimension,


care are datele membru publice height şi width. 
• setForeground( ), setBackground( ) – setează culoarea de scriere a textului şi respectiv
 

culoarea de fond pentru o componentă. Fiecare primeşte ca argument o instanţă a clasei


java.awt.Color. Dacă aceste culori nu se vor seta explicit, se vor utiliza culorile
implicite  ale containerului căruia îi aparţine componenta.  
• setFont( ) – determină font-ul pe care o componentă îl va utiliza la scrierea textului. 
Dacă nu se setează explicit un font, componenta va utiliza font-ul containerului său.  •
setSize( ), setBounds( ) – stabilesc dimensiunile unei componente. Metoda setSize() 
primeşte 2 argumente: width (lăţime) şi height (înălţime). Metoda setBounds()
stabileşte  atât poziţia cât şi dimensiunea. Poziţia este specificată relativ la containerul
componentei,  sau în cazul unei ferestre relativ la ecran. O formă a metodei are 4
argumente: x, y , width  şi height.  
• setVisible( ) – primeşte un argument de tip Boolean şi stabileşte dacă componenta va
fi  vizibilă sau nu. Se utilizează în general pentru Frame-uri.  

1.2 Layout Managers  

Alte sisteme GUI încurajează programatorul să gândească în termenii unei specificări precise a 
dimensiunii şi locaţiei componentelor interfeţei grafice. Java, în schimb, furnizează o serie de 5 
layout managers, fiecare având propria politică de dispunere a componentelor în containere.  
Fiecare componentă Java are o dimensiune preferată. Dimensiunea preferată este în general
cea  mai mică dimensiune necesară pentru a reprezenta componenta într-un mod vizual ce are
sens. De  exemplu, dimensiunea preferată a unui buton este dimensiunea etichetei sale, plus o
mică margine  de spaţiu liber din jurul textului, plus decoraţiunile care marchează marginea
butonului.  Dimensiunea preferată este dependentă de platformă, deoarece decoraţiunile
marginii  componentei variază de la un sistem la altul. Când un layout manager aşează
componentele unui  container, trebuie să ia în considerare 2 criterii: politica sa şi dimensiunea
preferată a fiecărei  componente. (Prima prioritate este de a respecta politica de aşezare a
componentelor, ignorându se dimesiunea preferată a componentelor.)  
În această lucrare de laborator vom prezenta numai două dintre cele 5 layout mangers,
şi  anume Flow Layout Manager şi Border Layout Manager.  
Flow Layout Manager aranjează componentele în rânduri orizontale. Este managerul 
implicit pentru applet-uri şi pentru panel-uri. Întotdeauna onorează dimensiunea preferată a 
componentelor.  
Border Layout Manager este managerul implicit pentru frame-uri. Îşi divide teritoriul
în  5 regiuni: NORTH, SOUTH, EAST, WEST şi CENTER. Fiecare regiune poate fi vidă sau
poate  conţine o singură componentă.  
2. Exemple  

// App1.java  
import java.applet.Applet;  
import java.awt.*;  

public class App1 extends Applet  


{  
 public void init()  
 {  
 setLayout(new FlowLayout(FlowLayout.RIGHT));  
 Label label=new Label("Introduceti text: ");  
 add(label);  
  
 TextField text1=new TextField("");  
 add(text1); 
 

 TextField text2=new TextField("textul 2");  


 add(text2);  
 Button but=new Button("OK");  
 add(but);  
  
 }  
 public void paint(Graphics g)  
 {  
 g.drawString("Acesta este un exemplu",30,100);  
 }  
}  

// App1.html  
<html>  
<body>  
<applet code=App1.class width=250 height=400>  
</applet>  
</body>  
</html>  

Exerciţiu:  
- Comentaţi prima linie de cod din metoda init() a applet-ului.  
- Modificaţi în App1.html lăţimea applet-ului; setaţi width=350 şi reîncărcaţi pagina 
html.  

În ambele situaţii observaţi şi explicaţi rezultatele.  

//App2.java  
import java.applet.Applet;  
import java.awt.*;  

public class App2 extends Applet  


{  
 public void init()  
 {  
 setLayout(new BorderLayout());  
 Panel toolbar=new Panel();  
 toolbar.setLayout(new FlowLayout(FlowLayout.LEFT));  
toolbar.setBackground(Color.orange);  
 toolbar.add(new Button("Buton 1"));  
 toolbar.add(new Button("Buton 2"));  
 add(toolbar,BorderLayout.NORTH);  
 TextArea txA1=new TextArea();  
 StringBuffer s=new StringBuffer("Acesta este un text \n mai   lung. Ca sa observati ");
s.append("\n plasarea \n sagetilor \n de defilare");   txA1.setText(s.toString());  
 txA1.setFont(new Font("Arial",Font.ITALIC,24));  
 txA1.setBackground(Color.blue);  
 txA1.setForeground(Color.white);  
 add(txA1,BorderLayout.CENTER);  
  
 TextArea txA2=new TextArea("Al doilea text.",5,20);   txA2.setFont(new
Font("Monospaced",Font.ITALIC|Font.BOLD,20));   txA2.setBackground(Color.white);  
 txA2.setForeground(Color.blue); 
 

 txA2.setEditable(false);  
 add(txA2,BorderLayout.SOUTH);  
 Checkbox chk=new Checkbox("Bifati aici!");  
 add(chk,BorderLayout.WEST);  
 Panel option=new Panel();  
 CheckboxGroup chgroup=new CheckboxGroup();  
 option.add(new Checkbox("Prima",false,chgroup));  
 option.add(new Checkbox("A doua",true,chgroup));  
 add(option,BorderLayout.EAST);  
 }  
}  

//App2.html  
<html>  
<body>  
<applet code=App2.class width=400 height=400>  
</applet>  
</body>  
</html>  

//App3.java  
import java.applet.Applet;  
import java.awt.*;  
public class App3 extends Applet  
{  
 public void init()  
 {  
 setBackground(Color.cyan);  
 setFont(new Font("Arial",Font.BOLD,16));  
 Label label1=new Label("Checkbox:");  
 add(label1);  
 Choice ch=new Choice();  
 ch.addItem("Prima");  
 ch.addItem("A doua");  
 ch.addItem("A treia");  
 ch.setForeground(Color.red);  
 add(ch);  
 Label label2=new Label("List:");  
 add(label2);  
 List list=new List(3,true);  
 for(int i=1;i<10;i++)  
 list.add("Floare "+i);  
 list.setForeground(Color.blue);  
 list.setFont(new Font("Courier new",Font.ITALIC,20));   add(list);  
 }  
}  

//App3.html  
<html>  
<body>  
<applet code=App3.class width=500 height=200>  
</applet>  
</body>  
</html> 
 

3. Clasele Eveniment  

  
Subclasele clasei java.awt.AWTEvent reprezintă diferite tipuri de evenimente care pot fi 
generate de diferitele componente AWT. Aceste subclase conţin toate informaţiile necesare cu 
privire la activitatea care a declanşat evenimentul. Iată care sunt:  
• ActionEvent – generat de activarea unei componente  
• AdjustmentEvent – generat prin ajustarea componentelor ajustabile cum ar fi 
“scroll bars”  
• ContainerEvent – generat când componentele sunt adăugate sau scoase dintr-
un  container  
• FocusEvent – generat când o componentă primeşte sau pierde focus-ul asupra
ei  • ItemEvent – generat când o opţiune este selectată dintr-o listă (Choice, List) sau 
Checkbox  
• KeyEvent – generat de activitatea tastaturii  
• MouseEvent - generat de activitatea cu mouse-ul  
• PaintEvent - generat când o componentă este desenată 
• TextEvent – generat când o componentă text este modificată 
• WindowEvent – generat de activitatea cu fereastra (iconificarea, 
deziconificarea)  

4. Event Listeners  

Există două moduri de a trata evenimentele prezentate mai sus. Primul este de a delega 
tratarea evenimentului unui obiect care “ascultă” (listens). Al doilea este de a permite explicit 
componentei care generează evenimentele să-şi manipuleze propriile evenimente.  
Iată ce presupune prima variantă. Să considerăm următorul exemplu. Fie un buton într-un 
applet. Când butonul este apăsat, un eveniment ActionEvent va fi trimis unei instanţe a clasei 
MyActionListener. Clasa MyActionListener implementează interfaţa ActionListener, 
garantându-se astfel prezenţa metodei actionPerformed().  

class MyActionListener implements ActionListener {  


 public void actionPerformed(ActionEvent e) {  
 System.out.println(“Action performed.”);   }  
}  

public class ListenerTest extends Applet {  


 public void init() {  
 Button btn=new Button(“OK”);  
 MyActionListener myAl=new MyActionListener();  
btn.addActionListener(myAl);  
 add(btn);  
 }  
}  

Putem rezuma tehnica de lucru în patru paşi:  


1. Se creează o clasă „listener” care implementează interfaţa ActionListener (pt. 
exemplul nostru).  
2. Se construieşte componenta.  
3. Se construieşte o instanţă a clasei „listener”. 
 

4. Se apelează metoda addActionListener() pentru componentă, transmiţându-i ca 


parametru obiectul „listener”.  

Există 11 tipuri de “listeners”, fiecare reprezentat de o interfaţă. În continuare vom


prezenta  numai o parte dintre acestea, împreună cu metodele din interfaţă şi cu metodele 
addXXXListener() corespunzătoare.  
(Pentru celelalte interfeţe, anume AdjustmentListener, ComponentListener, ContainerListener, 
FocusListener, TextListener, WindowListener se vor căuta informaţii în documentaţia jsdk).  
Interfaţă  Metodele din interfaţă  Metoda add 

ActionListener  actionPerformed(ActionEvent e) addActionListener( )

ItemListener  itemStateChanged(ItemEvent e)  addItemListener( ) 

KeyListener  keyPressed(keyEvent e)   addKeyListener( ) 


keyReleased(keyEvent e)  
keyTyped(keyEvent e) 

MouseListener  mouseClicked(MouseEvent e)  addMouseListener( ) 


mouseEntered(MouseEvent e) 
mouseExited(MouseEvent e) 
mousePressed(MouseEvent e) 
mouseReleased(MouseEvent e) 

MouseMotionListener mouseDragged(MouseEvent e)  addMouseMotionListener(


mouseMoved(MouseEvent e)  )

Reversul metodei addXXXListener() este metoda removeXXXListener() care înlătură


pentru  o componentă obiectul ataşat ei care “asculta” evenimentele generate de aceasta. Pentru 
exemplul anterior avem:  
btn.removeActionListener(myAl);  

Aşa cum deja am menţionat, o a doua tehnică de lucru permite explicit componentei care 
generează evenimentele să-şi manipuleze propriile evenimente. În continuare vom prezenta 
câteva exemple sugestive.  

// App4.java  
import java.applet.Applet;  
import java.awt.*;  
import java.awt.event.*;  

public class App4 extends Applet implements ActionListener  {  


 Button but1,but2;  
 int x=0,y=0;  
 public void init()  
 {  
 but1=new Button("Deseneaza");  
 add(but1);  
 but2=new Button("Sterge");  
 add(but2);  
 but1.addActionListener(this);  
 but2.addActionListener(this); 
 

 }  
  
 public void actionPerformed(ActionEvent e)  
 {  
 Button b=(Button)e.getSource();  
 if (b==but1)  
 {  
 x=150;y=150;  
 repaint();  
 }  
 else if(b==but2)  
 {  
 x=y=0;  
 repaint();  
 }  
 }  
 public void paint(Graphics g)  
 {  
 setBackground(Color.blue);  
 setForeground(Color.magenta);  
 if(x>0)  
 g.fillOval(x,y,100,100);  
 }  
}  

// App4.html  
<html>  
<body>  
<applet code=App4.class width=500 height=400>  
</applet>  
</body>  
</html>  

//App5.java  
import java.applet.Applet;  
import java.awt.*;  
import java.awt.event.*;  
import java.util.Vector;  

public class App5 extends Applet  


 implements ActionListener, MouseListener  {  
 Button but;  
 Vector points;  
 public void init()  
 {  
 but=new Button("Clear all");  
 add(but);  
 but.addActionListener(this);  
 addMouseListener(this);  
 points=new Vector();  
 }  
 public void actionPerformed(ActionEvent e)  
 {  
 Button b=(Button)e.getSource();  
 if (b==but)  
 { 
 

 points.setSize(0);  
 repaint();  
 }  
  
 }  
 public void mouseClicked(MouseEvent e)  
 {  
 e.consume();  
 points.addElement(new Point(e.getPoint()));  
 repaint();  
 }  
 public void mouseEntered(MouseEvent e)  
 {  
 }  
 public void mouseExited(MouseEvent e)  
 {  
 }  
 public void mousePressed(MouseEvent e)  
 {  
 }  
 public void mouseReleased(MouseEvent e)  
 {  
 }  
  
 public void paint(Graphics g)  
 {  
 setBackground(Color.orange);  
 setForeground(Color.black);  
 for(int i=0;i<points.size();i++)  
 {  
  
 Point p=(Point)points.elementAt(i);  
 g.fillRect(p.x,p.y,70,30);  
 }  
 }  
}  
//App5.html  
<html>  
<body>  
<applet code=App5.class width=500 height=500>  
</applet>  
</body>  
</html>  

//App6.java  
import java.applet.Applet;  
import java.awt.*;  
import java.awt.event.*;  
import java.util.Vector;  

public class App6 extends Applet  


 implements ActionListener, MouseListener  {  
 Button but;  
 Vector lines;  
 int x1,y1,x2,y2;  
 public void init()  
 { 
 

 but=new Button("Clear all");  


 add(but);  
 but.addActionListener(this);  
 addMouseListener(this);  
 lines=new Vector();  
 }  
 public void actionPerformed(ActionEvent e)  
 {  
 Button b=(Button)e.getSource();  
 if (b==but)  
 {  
 lines.setSize(0);  
 repaint();  
 }  
 }  
 public void mouseClicked(MouseEvent e)  
 {  
 }  
  
 public void mouseEntered(MouseEvent e)  
 {  
 }  
 public void mouseExited(MouseEvent e)  
 {  
 }  
 public void mousePressed(MouseEvent e)  
 {  
 e.consume();  
 x1=e.getX();  
 y1=e.getY();  
 }  
 public void mouseReleased(MouseEvent e)  
 {  
 e.consume();  
 x2=e.getX();  
 y2=e.getY();  
 lines.addElement(new Rectangle(x1,y1,x2,y2));  
 repaint();  
 }  
  
 public void paint(Graphics g)  
 {  
 for(int i=0;i<lines.size();i++)  
 {  
  
 Rectangle r=(Rectangle)lines.elementAt(i);  
g.drawLine(r.x,r.y,r.width,r.height);  
 }  
 }  
}  

//App6.html  
<html>  
<body>  
<applet code=App6.class width=500 height=500>  
</applet>  
</body>  
</html> 

//App7.java  
import java.applet.Applet;  
import java.awt.*;  
import java.awt.event.*;  

public class App7 extends Applet  


 implements ActionListener, ItemListener  {  
 Button but;  
 Choice ch;  
 String color;  

 public void init()  


 {  
 but=new Button("Draw");  
 add(but);  
 but.addActionListener(this);  
 ch=new Choice();  
 ch.addItem("red");  
 ch.addItem("yellow");  
 ch.addItem("pink");  
 add(ch);  
 ch.addItemListener(this);  
 color=new String();  
 setFont(new Font("Arial",Font.PLAIN,14));  
 }  
  
 public void actionPerformed(ActionEvent e)  
 {  
 Button b=(Button)e.getSource();  
 if (b==but)  
 {  
 repaint();  
 }  
 }  
  
 public void itemStateChanged(ItemEvent e)  
 {  
 color=ch.getSelectedItem();  
 }  
  
 public void paint(Graphics g)  
 {  
 setBackground(Color.black);  
 if(color.compareTo("red")==0)  
 g.setColor(Color.red);  
 else if(color.compareTo("yellow")==0)  
 g.setColor(Color.yellow);  
 else if(color.compareTo("pink")==0)  
 g.setColor(Color.pink);  
  
 g.drawString(color,70,150);  
 }  
}  

//App7.html  
<html>  
<body>  
<applet code=App7.class width=200 height=300> 

</applet>  
</body>  
</html>  

//App8.java  
import java.applet.Applet;  
import java.awt.*;  
import java.awt.event.*;  

public class App8 extends Applet implements ActionListener  {  


 Button but;  
 TextField tx;  
 myFrame f;  

 public void init()  


 {  
 setFont(new Font("Arial",Font.PLAIN,14));  
 tx=new TextField("",10);  
 add(tx);  
 but=new Button("Open window");  
 add(but);  
 but.addActionListener(this);  
 }  
  
 public void actionPerformed(ActionEvent e)  
 {  
 Button b=(Button)e.getSource();  
 if (b==but)  
 {  
 f=new myFrame("Little window",tx.getText());   f.setSize(300,300);  
 f.setVisible(true);  
 }  
 }  
}  

class myFrame extends Frame implements ActionListener  {  


 String text;  
 Button buton;  
 public myFrame(String s,String tx)  
 {  
 super(s);  
 text=tx;  
 setLayout(new FlowLayout());  
 buton=new Button("Close");  
 add(buton);  
 buton.addActionListener(this);  
 }  
 public void actionPerformed(ActionEvent e)  
 {  
 Button b=(Button)e.getSource();  
 if (b==buton)  
 {  
 dispose(); 
2  

 }  
 public void paint(Graphics g)  
{  
 g.drawString(text,50,100); 
 }  
}  

//App8.html  
<html>  
<body>  
<applet code=App8.class width=300 height=300>  
</applet>  
</body>  
</html>  

III. MODUL DE LUCRU 

1. Se foloseşte utilitarul instalat la primul laborator: Eclipse sau NetBeans sau oricare
altul! 2. Pe calculatorul personal este instalata o versiune functionala JDK, in
conformitate cu precizarile de la primul laborator.

IV. TEMĂ 

1. Se vor parcurge toate exemplele prezentate în platforma de laborator testându-se practic şi


explicând rezultatele obţinute. 
2. Scrieţi un applet Java care să conţină următoarele: o zonă de editare TextArea cu 5 linii si
10 coloane, un buton cu eticheta OK şi un grup de componente CheckBox. Setaţi textul
zonei de editare la un anume şir de caractere. Utilizaţi diverse culori şi font-uri. 
3. Scrieţi un applet Java care să conţină un grup de 2 componente CheckBox etichetate “red” şi
“blue”, şi un buton etichetat “Clear all”. Utilizatorul va bifa una din opţiunile “red” sau
“blue”. La efectuarea unui click cu mouse-ul pe suprafaţa aapplet-ului se va desena un cerc
colorat roşu sau albastru în funcţie de opţiunea aleasă. La apăsarea butonului “Clear all” se
vor şterge toate cercurile desenate până în acel moment. 
TEHNOLOGII JAVA 
LUCRARE DE LABORATOR 7  

Java Swing  
JFrame, JApplet, JPanel, Borders, Tabbed Panes, Scrolling
Panes,  Split Panes, Etichete, Butoane 
I. SCOPUL LUCRĂRII 

Lucrarea de faţă are rolul de a prezenta şi familiariza studentul cu modul de construire a 


unei interfeţe grafice utilizator folosind pachetul de clase java.swing. Se vor prezenta câteva 
componente vizuale utile, împreună cu modul de creare şi utilizare a acestora.  
La sfârşitul acestei lucrări, studentul va avea posibilitatea să scrie mini-aplicaţii Java în
care  să utilizeze noţiunile învăţate si să scrie interfete grafice Java in care sa integreze
componentele  invatate.  

II. NOŢIUNI TEORETICE 

 Observaţie: Vezi noţiunile prezentate în cursurile 6, 7 si 8.  


Swing este un subset JFC (Java Foundation Classes) şi constă dintr-o serie de
componente  vizuale care extind (îmbunătăţesc) componentele AWT, şi furnizează noi facilităţi
precum tabele  şi arbori. Structura de clase din Swing este asemănătoare cu cea din AWT, în
sensul că toate  componentele interfeţei grafice sunt derivate dintr-un singur părinte numit
JComponent (care  este derivat din clasa AWT Container).  
Pachetul de clase Swing reprezintă soluţia furnizată de Sun pentru crearea unor interfeţe 
utilizator grafice complet portabile pe orice platformă.  
În Swing, toate numele claselor încep cu litera J, şi atunci când este posibil, numele este 
acelaşi cu cel al clasei AWT pe care o înlocuieşte.  
La fel ca la AWT, punctul de plecare pentru un program bazat pe Swing, este clasa 
JFrame sau clasa JApplet.  

1. JFrame 
JFrame este o versiune extinsă a clasei Frame care adaugă suport pentru un
comportament  de desenare special. Adiţional, JFrame permite componentelor Swing MenuBars
să fie ataşate nu  numai în partea de sus a ferestrei dar oriunde în fereastră.  
Toate obiectele asociate unui JFrame sunt manipulate de o instanţă a clasei JRootPane, 
care este singura componentă-fiu a unei instanţe JFrame. JRootPane este un container simplu 
pentru alte câteva componente. Iată care este ierarhia de obiecte dintr-o instanţă JFrame:  

 JFrame  
JRootPane  
glassPane  
layeredPane 

 [menuBar]  
 contentPane  
O aplicaţie JFrame  
  
import java.awt.*;  
import javax.swing.*;  
class TestFrame extends JFrame  
{  
public TestFrame()  
{  
setTitle( "Test Application" );  
setSize( 100, 100 );  
setBackground( Color.gray );  
Panel topPanel = new Panel();  
topPanel.setLayout( new BorderLayout() );  
getContentPane().add( topPanel );  
Label labelHello = new Label( "Hello World!" );  
topPanel.add( labelHello, BorderLayout.NORTH );  
}  
public static void main( String args[] )  
{  
TestFrame mainFrame = new TestFrame();  
mainFrame.setVisible( true );  
}  
}  
  
Este posibil să se mixeze componentele AWT cu cele Swing, într-o aplicaţie Java
Swing,  dar în general se recomandă utilizarea exclusivă a componentelor Swing (un posibil
efect:  componentele AWT sunt desenate mai rapid undeva în colţul din stânga sus al frame-ului
înainte  de a fi corect poziţionate, rezultând un “flicker” neaşteptat în timpul operaţiilor de
redesenare a  ecranului).  
Codul din exemplul anterior este foarte simplu şi arată ca şi cum s-ar fi utilizat 
componente AWT, cu o singură excepţie:  
getContentPane().add( topPanel );   
O clasă JFrame prezintă o singură incompatibilitate în raport cu o clasă AWT. În AWT 
Frame se puteau adăuga componente direct la instanţa frame (pentru că clasa AWT Frame 
creează automat o instanţă Panel).  
frame.add( component );  
Pentru JFrame, trebuie să specificăm exact în care subcomponentă a lui JRootPane vom 
plasa componenta noastră. Cel mai adesea, componentele grafice se vor adăuga la contentPane. 
Trebuie utilizată următoarea sintaxă:  
myJFrame.getContentPane().add( component );  
Cea mai bună soluţie este de se crea un Panel, de a se adăuga acesta la ContentPane, şi de a se 
adăuga apoi toate componentele la Panel-ul nou creat.  
Similar, cînd se setează un “layout” pentru conţinutul unui JFrame , de obicei se setează
layout-ul pentru subcomponenta contentPane:  
myJFrame.getContentPane().setLayout(new FlowLayout());  
  
Variabile JFrame  
protected JRootPane rootPane - această variabilă conţine o instanţă a JRootPane-ului
asociat  frame-ului.  
Constructori JFrame  
JFrame()   
JFrame( String title ) 

- creează o nouă instanţă JFrame care iniţial este invizibilă.  

Metode importante JFrame  


public void setJMenuBar( JMenuBar menu );  

O caracteristică unică a clasei JFrame este abilitatea de a determina cum se va efectua 


operaţia de închidere a ferestrei. JFrame implementează metode set/get pentru valoarea
operaţiei  implicite de închidere.  
  
public void setDefaultCloseOperation(int operation);   
public int getDefaultCloseOperation();   
  
 “Layered pane” este un container invizibil plasat peste “root pane”. Poate fi accesat 
pentru a afişa peste conţinutul frame-ului obiecte dinamice (precum cursoarele).”Glass Pane” 
permite afişarea unor componente în faţa instanţei JFrame existente.  
  
protected JRootPane createRootPane();  
protected void setRootPane(JRootPane root);  
public JRootPane getRootPane();   
public Container getContentPane();  
public void setLayeredPane(JLayeredPane layered);  
public JLayeredPane getLayeredPane();   
public void setGlassPane(Component glass);   
public Component getGlassPane();  
  
2. JWindow  
  
JWindow este similară cu JFrame exceptând faltul că nu are no “title bar”, nu este 
redimensionabilă, minimizabilă, maximizabilă, şi nu se poate inchide (fără a scrie cod pentru 
acest lucru). Se utilizează în general pentru a mesaje temporare (“splash screen”).  

3. JApplet  
JApplet are structură similară cu JFrame. Permite adăugarea de componente MenuBars 
şi toolbars. Exemplu:  
  
import java.awt.*;  
import javax.swing.*;  
public class TestApplet  
extends JApplet  
{  
public TestApplet()  
{  
}  
public void init()  
{  
setSize( 100, 100 );  
setBackground( Color.gray );  
Panel topPanel = new Panel();  
topPanel.setLayout( new BorderLayout() );  
getContentPane().add( topPanel );  
Label labelHello = new Label( "Hello World!" ); 

topPanel.add( labelHello, BorderLayout.NORTH );  


}  
}  

 Constructori JApplet  
JApplet() -creează o nouă instanţă JApplet. 

Metode importante JApplet  

public void setJMenuBar( JMenuBar menu );  


public JMenuBar getJMenuBar();  
public void setContentPane(Container contentPane);  
public Container getContentPane();  
public void setLayeredPane(JLayeredPane layered);  
public JLayeredPane getLayeredPane();   
public void setGlassPane(Component glass);   
public Component getGlassPane();  
protected void setRootPane(JRootPane root);  
public JRootPane getRootPane();   
protected JRootPane createRootPane();  
  
  
4. JPanel  
  
Echivalentul Swing al clasei AWT Panel este JPanel. JPanel suportă toate tipurile de 
“layout manager” din AWT, plus cele noi din Swing.  
  
import java.awt.*;  
import javax.swing.*;  
class TestPanel extends JFrame  
{  
public TestPanel()  
{  
setSize( 200, 200 );  
setBackground( Color.gray );  
JPanel topPanel = new JPanel();  
topPanel.setLayout( new GridLayout( 3, 2 ) );  
getContentPane().add( topPanel );  
topPanel.setBackground( Color.lightGray );  
topPanel.add( new Button( "One" ) );  
topPanel.add( new Button( "Two" ) );  
topPanel.add( new Button( "Three" ) );  
topPanel.add( new Button( "Four" ) );  
topPanel.add( new Button( "Five" ) );  
}  
public static void main( String args[] )  
{  
TestPanel mainFrame = new TestPanel();  
mainFrame.setVisible( true );  
}  
}  
  
  
Clasa TestPanel este derivată din JFrame; creează o instanţă JPanel căreia i se aplică
“GridLayout manager”. Butoanele sunt adăugate instanţei JPanel, ci nu ferestrei principale.  O
instanţă JPanel este implicit “double buffered”, ceea ce reduce efectul de “flicker” în timpul
operaţiilor de redesenare a ecranului, pentru programele de animaţie. Dacă utilizăm  “double-
buffering” pentru o componentă, toţi fii acesteia vor utiliza de asemenea “double buffering”
(chiar daca nu este activat). JRootPane este componenta din vârful ierarhiei oricărei  ferestre
Swing, deci activând “double-buffering” pentru JRootPane, toate subcomponentele sale  vor fi
desenate utilizându-se tehnica “double-buffering”.  
  
Constructori JPanel  
JPanel( LayoutManager layout, boolean isDoubleBuffered )  
- creează o instanţă JPanel cu un “layout” specifcat, iar capacităţile de “double buffering” sunt 
controlate de variabila de tip boolean.  
JPanel( LayoutManager layout )  
- creează o instanţă JPanel cu un “layout” specifcat. 
JPanel( boolean isDoubleBuffered )  
- creează o instanţă JPanel cu un “layout” implicit de tipul FlowLayout, iar capacităţile de 
“double buffering” sunt controlate de variabila de tip boolean.  
JPanel()   
- creează o instanţă JPanel cu un “layout” implicit de tipul FlowLayout, iar capacităţile de 
“double buffering” sunt activate.  
  
5. Borders  
 
Pachetul border furnizează următoarele clase care por fi aplicate oricărei componente 
Swing:  
BevelBorder – o margine 3D cu o înfăţişare “ridicată” sau nu (respectiv “raised” sau 
“lowered”). 
CompoundBorder - o combinaţie de 2 alte tipuri de margini: o margine interioară şi o margine 
exterioară.  
EmptyBorder - o margine transparentă utilizată pentru a defini un spaţiu vid în jurul unei 
componente.  
EtchedBorder – o margine cu o linie gravată.  
LineBorder - o margine cu o grosime şi culoare specificate.  
MatteBorder - o margine constând fie dintr-o culoare, fie dintr-o imagine repetată (“tiled”). 
SoftBevelBorder –o margine 3D cu o înfăţişare “ridicată” sau nu, şi cu capetele rotunjite. 
TitledBorder – o margine care permite existenţa unui titlu într-o anume poziţie şi locaţie.    
Pentru a seta marginea unei componente Swing se apelează metoda setBorder() a 
JComponentei. Există de asemenea şi o clasă numită BorderFactory (în pachetul javax.swing), 
care conţine un grup de metode statice utilizate pentru contruirea rapidă de margini. De
exemplu:    
myComponent.setBorder(BorderFactory.createEtchedBorder());   
  
import java.awt.*;  
import javax.swing.*;  
import javax.swing.border.*;  
class BorderTest extends JFrame  
{  
public BorderTest() {  
setTitle("Border Test");  
setSize(450, 450);  
JPanel content = (JPanel) getContentPane();  
content.setLayout(new GridLayout(6,2));  
JPanel p = new JPanel();  
p.setBorder(new BevelBorder (BevelBorder.RAISED)); 
p.add(new JLabel("RAISED BevelBorder"));  
content.add(p);  
p = new JPanel();  
p.setBorder(new BevelBorder (BevelBorder.LOWERED));  
p.add(new JLabel("LOWERED BevelBorder"));  
content.add(p);  
p = new JPanel();  
p.setBorder(new LineBorder (Color.black, 5));  
p.add(new JLabel("Black LineBorder, thickness =
5"));  content.add(p);  
p = new JPanel();  
p.setBorder(new EmptyBorder (10,10,10,10));  
p.add(new JLabel("EmptyBorder with thickness of
10"));  content.add(p);  
p = new JPanel();  
p.setBorder(new EtchedBorder (EtchedBorder.RAISED));  
p.add(new JLabel("RAISED EtchedBorder"));  
content.add(p);  
p = new JPanel();  
p.setBorder(new EtchedBorder
(EtchedBorder.LOWERED));  p.add(new JLabel("LOWERED
EtchedBorder"));  
content.add(p);  
p = new JPanel();  
p.setBorder(new SoftBevelBorder
(SoftBevelBorder.RAISED));  p.add(new JLabel("RAISED
SoftBevelBorder"));  
content.add(p);  
p = new JPanel();  
p.setBorder(new SoftBevelBorder
(SoftBevelBorder.LOWERED));  p.add(new JLabel("LOWERED
SoftBevelBorder"));  
content.add(p);  
p = new JPanel();  
p.setBorder(new MatteBorder (new
ImageIcon("spiral.gif")));  p.add(new
JLabel("MatteBorder"));  
content.add(p);  
p = new JPanel();  
p.setBorder(new TitledBorder (  
new MatteBorder (new ImageIcon("spiral.gif")),"Title
String"));  p.add(new JLabel("TitledBorder using
MatteBorder"));  
content.add(p);  
p = new JPanel();  
p.setBorder(new TitledBorder (  
new LineBorder (Color.black, 5),"Title String"));  
p.add(new JLabel("TitledBorder using LineBorder"));  
content.add(p);  
p = new JPanel();  
p.setBorder(new TitledBorder (  
new EmptyBorder (10,10,10,10),"Title String"));  
p.add(new JLabel("TitledBorder using EmptyBorder"));  
content.add(p);  
setVisible(true);  
}  
public static void main(String args[]) {  
new BorderTest();  
}  
}  
  
Crearea unei margini definite de utilizator 

Se implementează interfaţa javax.swing.Border şi se definesc următoarele 3


metode:  void paintBorder(Component c, Graphics g)   
Insets getBorderInsets(Component c)  
boolean isBorderOpaque()  
  
Să considerăm următorul exemplu. Programul construieşte o margine
dreptunghiulară “ridicată” şi umbrită cu colţurile rotunjite. Variabilele instanţă:  
int m_w: valorile stanga şi dreapta  
int m_h: valorile sus şi jos  
Color m_topColor: culoarea non-shadow  
Color m_bottomColor: culoarea shadow.  
  
import java.awt.*;  
import javax.swing.*;  
import javax.swing.border.*;  
public class OvalBorder implements Border  
{  
protected int m_w=6;  
protected int m_h=6;  
protected Color m_topColor = Color.white;  
protected Color m_bottomColor = Color.gray;  
public OvalBorder() {  
m_w=6;  
m_h=6;  
}  
public OvalBorder(int w, int h) {  
m_w=w;  
m_h=h;  
}  
public OvalBorder(int w, int h, Color topColor,  
Color bottomColor) {  
m_w=w;  
m_h=h;  
m_topColor = topColor;  
m_bottomColor = bottomColor;  
}  
public Insets getBorderInsets(Component c) {  
return new Insets(m_h, m_w, m_h, m_w);  
}  
public boolean isBorderOpaque() { return true; }  
public void paintBorder(Component c, Graphics g,  
int x, int y, int w, int h) {  
w--;  
h--;  
g.setColor(m_topColor);  
g.drawLine(x, y+h-m_h, x, y+m_h);  
g.drawArc(x, y, 2*m_w, 2*m_h, 180, -90);  
g.drawLine(x+m_w, y, x+w-m_w, y);  
g.drawArc(x+w-2*m_w, y, 2*m_w, 2*m_h, 90, -90);  
g.setColor(m_bottomColor);  
g.drawLine(x+w, y+m_h, x+w, y+h-m_h);  
g.drawArc(x+w-2*m_w, y+h-2*m_h, 2*m_w, 2*m_h, 0,
-90);  g.drawLine(x+m_w, y+h, x+w-m_w, y+h);  
g.drawArc(x, y+h-2*m_h, 2*m_w, 2*m_h, -90, -90);  
}  
public static void main(String[] args) {  
JFrame frame = new JFrame("Custom Border:
OvalBorder");  JLabel label = new
JLabel("OvalBorder"); 
((JPanel) frame.getContentPane()).setBorder(new
CompoundBorder(  new EmptyBorder(10,10,10,10), new
OvalBorder(10,10)));  frame.getContentPane().add(label);  
frame.setBounds(0,0,300,150);  
frame.setVisible(true);  
}  
}  

6. Tipurile de Layout Manager specifice Java Swing  


  
BoxLayout - aranjează componentele de-a lungul axelor X, Y ale panel-ului. Încearcă
să   utilizeze lăţimea şi înălţimea preferate ale componentei.  
OverlayLayout – aranjează componentele unele peste altele, efectuând o aliniere
a   punctului de bază al fiecărei componente într-o singură locaţie. 
ScrollPaneLayout – specific pentru “scrolling panes”  
ViewportLayout – specific panel-urilor cu “scrolling panes”, aliniază de-a lungul axei
X    
Vom prezenta un exemplu pentru tipul BoxLayout (cel mai des utilizat). Acest layout 
manager organizează componentele de-a lungul axelor X, Y ale panel-ului care le deţine. 
Alinierea componentelor se poate face la stânga, la dreapta sau centru (implicit).    
import java.awt.*;  
import javax.swing.*;  
class TestFrame extends JFrame  
{  
public TestFrame()  
{  
setTitle( "BoxLayout Application" );  
JPanel topPanel = new JPanel();  
topPanel.setLayout( new BorderLayout() );  
getContentPane().add( topPanel );  
JPanel yAxisPanel = createYAxisPanel();  
topPanel.add( yAxisPanel, BorderLayout.CENTER );  
JPanel xAxisPanel = createXAxisPanel();  
topPanel.add( xAxisPanel, BorderLayout.SOUTH );  
}  
  
public JPanel createYAxisPanel()  
{  
JPanel panel = new JPanel();  
panel.setLayout( new BoxLayout( panel,
BoxLayout.Y_AXIS ) );  panel.setBackground( Color.lightGray
);  
panel.add( new JButton( "Button 1" ) );  
panel.add( new TextArea( "This is a text area" ) );  
panel.add( new JCheckBox( "Checkbox 1" ) );  
return panel;  
}  
  
public JPanel createXAxisPanel()  
{  
JPanel panel = new JPanel();  
panel.setLayout( new BoxLayout( panel,
BoxLayout.X_AXIS ) );  panel.setBackground( Color.gray );  
panel.add( new JButton( "Button 1" ) );  
panel.add( new TextArea( "This is a text area" ) );  
panel.add( new JCheckBox( "Checkbox 1" ) );  
return panel; 

}  
  
public static void main( String args[] )  
{  
TestFrame mainFrame = new TestFrame();  
mainFrame.pack();  
mainFrame.setVisible( true );  
}  
}  
  
Pentru a utiliza mai uşor BoxLayout manager, Swing furnizează şi o clasă numită Box 
care creează un container ce are aplicat BoxLayout manger. Se utlizează un cod similar cu:  
{  
…  
// Creeaza un container nou  
Box boxPanel = new Box(BoxLayout.Y_AXIS );  
// Adauga componente  
boxPanel.add( new JButton( "Button 1" ) );  
panel.add( new TextArea( "This is a text area" ) );  
panel.add( new JCheckBox( "Checkbox 1" ) );  
…  
}  
  
  
  
  
7. Tabbed Panes  
  
O componentă de tipul ”tabbed pane” permite gruparea mai multor pagini de informaţie 
într-un singur punct de referinţă. Se comportă ca orice altă componentă Swing: putem să îi 
adăugăm un panou (panel), să îi adăugăm componente de obicei sub formă de pagini. Fiecărei 
pagini îi putem asocia alte componente Java UI.  
  
Crearea unui “tabbed pane”  
import javax.swing.*;  
{  
. . .  
tabbedPanel = new JTabbedPane();  
topPanel.add( tabbedPanel, BorderLayout.CENTER );  
. . .  
}  
Adăugarea şi inserarea de pagini   
O pagină constă de obicei dintr-o instanţă JPanel conţinând componente
fiu.  import javax.swing.*;  
{  
. . .  
// Creeaza pagina (un “panel”)  
pagePanel = new JPanel();  
pagePanel.setLayout( new BorderLayout() );  
pagePanel.add( new JLabel( "Sample
Label" ),BorderLayout.NORTH );  pagePanel.add( new JTextArea( ""
),BorderLayout.CENTER );  pagePanel.add( new JButton( "Button 1"
),BorderLayout.SOUTH );    
// Adauga pagina la “tabbed pane”  
tabbedPanel.addTab( "Page 1", pagePanel );  
. . . 
}  
  
Se va utiliza cod similar pentru crearea fiecărei pagini. Dar o astfel de secvenţă de cod 
adaugă paginile secvenţial. Pentru a insera pagini oriunde într-o ierarhie de pagini se utilizează: 
// Insereaza pagina in “tabbed pane”  
tabbedPanel.insertTab( "Inserted Page",  
 new ImageIcon( "image.gif" ),   pagePanel,"My tooltip
text",iLocation );    
Variabila iLocation reprezintă index-ul (poziţia) paginii. Se observă de asemenea cum
se  ataşează o imagine.  
  
Ştergerea paginilor  
tabbedPanel.removeTabAt( iLocation );  
  
unde iLocation este index-ul paginii ce se va înlătura. Pentru a se şterge toate paginile, trebuie
să se ţină evidenţa numărului de pagini rămase, altfel Java VM va genera o excepţie. 
while( tabbedPanel.getTabCount() > 0 )  
 tabbedPanel.removeTabAt( 0 );  
  
Metoda getTabCount() returnează numărul total de pagini din panel.  
  
Selectarea paginilor  

Există 2 mecanisme pentru selectarea unei pagini. Cel mai simplu, utilizatorul va selecta 
cu un click pagina dorită, iar instanţa JTabbedPane va muta automat pagina selectată în faţă. 
Dar se poate scrie şi cod pentru aceasta. Se apelează metoda setSelectedIndex() cu indexul 
paginii care se doreşte să apară în faţă.  
tabbedPanel.setSelectedIndex( iLocation );  
  
O a doua metodă utilizează instanţa panel-ului care a fost referenţiat atunci când pagina
a  fost adăugată.  
tabbedPanel.setSelectedComponent( pagePanel );  
  
Iată un exemplu complet:  
  
import java.awt.*;  
import javax.swing.*;  
class TestTab extends JFrame  
{  
private JTabbedPane tabbedPane;  
private JPanel panel1;  
private JPanel panel2;  
private JPanel panel3;  
public TestTab()  
{  
setTitle( "Tabbed Pane Application" );  
setSize( 300, 200 );  
setBackground( Color.gray );  
JPanel topPanel = new JPanel();  
topPanel.setLayout( new BorderLayout() );  
getContentPane().add( topPanel );  
// Creeaza paginile  
createPage1();  
createPage2();  
createPage3(); 

// Creeaza un “tabbed pane”  


tabbedPane = new JTabbedPane();  
tabbedPane.addTab( "Page 1", panel1 );  
tabbedPane.addTab( "Page 2", panel2 );  
tabbedPane.addTab( "Page 3", panel3 );  
topPanel.add( tabbedPane, BorderLayout.CENTER );  
}  
public void createPage1()  
{  
panel1 = new JPanel();  
panel1.setLayout( null );  
JLabel label1 = new JLabel( "Username:" );  
label1.setBounds( 10, 15, 150, 20 );  
panel1.add( label1 );  
JTextField field = new JTextField();  
field.setBounds( 10, 35, 150, 20 );  
panel1.add( field );  
JLabel label2 = new JLabel( "Password:" );  
label2.setBounds( 10, 60, 150, 20 );  
panel1.add( label2 );  
JPasswordField fieldPass = new JPasswordField();  
fieldPass.setBounds( 10, 80, 150, 20 );  
panel1.add( fieldPass );  
}  
public void createPage2()  
{  
panel2 = new JPanel();  
panel2.setLayout( new BorderLayout() );  
panel2.add( new JButton( "North" ), BorderLayout.NORTH ); 
panel2.add( new JButton( "South" ), BorderLayout.SOUTH ); 
panel2.add( new JButton( "East" ), BorderLayout.EAST ); 
panel2.add( new JButton( "West" ), BorderLayout.WEST ); 
panel2.add( new JButton( "Center" ),
BorderLayout.CENTER );  }  
public void createPage3()  
{  
panel3 = new JPanel();  
panel3.setLayout( new GridLayout( 3, 2 ) );  
panel3.add( new JLabel( "Field 1:" ) );  
panel3.add( new TextArea() );  
panel3.add( new JLabel( "Field 2:" ) );  
panel3.add( new TextArea() );  
panel3.add( new JLabel( "Field 3:" ) );  
panel3.add( new TextArea() );  
}  
  
public static void main( String args[] )  
{  
TestTab mainFrame = new TestTab();  
mainFrame.setVisible( true );  
}  
}  
  
8. Scrolling panes  
  
În următorul exemplu vom crea un “scrolling pane”, şi îi vom adăuga o instanţă JLabel 
care arată o imagine foarte mare. Pentru că imaginea este prea mare ca să fie afişată întreagă, 
barele de navigare “scroll bars” vor apare automat.  
import java.awt.*;  
import javax.swing.*;  
  
class TestScroll extends JFrame  
{  
private JScrollPane scrollPane;  
public TestScroll()  
{  
setTitle( "Tabbed Pane Application" );  
setSize( 300, 200 );  
setBackground( Color.gray );  
JPanel topPanel = new JPanel();  
topPanel.setLayout( new BorderLayout() );  
getContentPane().add( topPanel );  
Icon image = new ImageIcon( "main.gif" );  
JLabel label = new JLabel( image );  
// Creeaza un “scroll pane”  
scrollPane = new JScrollPane();  
scrollPane.getViewport().add( label );  
topPanel.add( scrollPane, BorderLayout.CENTER );  
}  
public static void main( String args[] )  
{  
TestScroll mainFrame = new TestScroll();  
mainFrame.setVisible( true );  
}  
}  
  
9. Split panes  
  
Clasa JSplitPane este utilizată pentru a divide două componente, care prin intervenţia 
utilizatorului pot fi redimensionate interactiv. Divizarea se poate face în direcţia stânga-dreapta 
utilizând setarea JSplitPane.HORIZONTAL_SPLIT, sau în direcţia sus-jos utilizând 
JSplitPane.VERTICAL_SPLIT.  
JSplitPane va divide numai două componente. Dacă este nevoie de o interfaţă mai 
complexă, se poate imbrica o instanţă JSplitPane într-o altă instanţă JSplitPane. Astfel, se va 
putea intermixa şi divizarea orizontală cu cea verticală.  
Graniţa de diviziune poate fi ajustată de către utilizator cu mouse-ul, dar poate fi setată
şi  prin apelul metodei setDividerLocation(). Atunci când graniţa de diviziune este mutată cu 
mouse-ul de către utilizator, se vor utiliza setările dimensiunilor minime şi maxime ale 
componentelor, pentru a determina limitele deplasării graniţei. Astfel, dacă dimensiunea
minimă 
a două componente este mai mare decât dimensiunea containerului “split pane”, codul
JSplitPane  nu va permite redimensionarea frame-urilor separate de graniţa de diviziune. 
Exemplu:  
  
import java.awt.*;  
import javax.swing.*;  
class TestSplit extends JFrame  
{  
private JSplitPane splitPaneV;  
private JSplitPane splitPaneH;  
private JPanel panel1;  
private JPanel panel2;  
private JPanel panel3;  
  
public TestSplit() 
{  
setTitle( "Split Pane Application" );  
setBackground( Color.gray );  
JPanel topPanel = new JPanel();  
topPanel.setLayout( new BorderLayout() );  
getContentPane().add( topPanel );  
createPanel1();  
createPanel2();  
createPanel3();  
splitPaneV = new
JSplitPane( JSplitPane.VERTICAL_SPLIT ); 
topPanel.add( splitPaneV, BorderLayout.CENTER );  
splitPaneH = new
JSplitPane( JSplitPane.HORIZONTAL_SPLIT ); 
splitPaneH.setLeftComponent( panel1 );  
splitPaneH.setRightComponent( panel2 );  
splitPaneV.setLeftComponent( splitPaneH );  
splitPaneV.setRightComponent( panel3 );  
}  
public void createPanel1()  
{  
panel1 = new JPanel();  
panel1.setLayout( new BorderLayout() );  
panel1.add( new JButton( "North" ), BorderLayout.NORTH ); 
panel1.add( new JButton( "South" ), BorderLayout.SOUTH ); 
panel1.add( new JButton( "East" ), BorderLayout.EAST ); 
panel1.add( new JButton( "West" ), BorderLayout.WEST ); 
panel1.add( new JButton( "Center" ),
BorderLayout.CENTER );  }  
public void createPanel2()  
{  
panel2 = new JPanel();  
panel2.setLayout( new FlowLayout() );  
panel2.add( new JButton( "Button 1" ) );  
panel2.add( new JButton( "Button 2" ) );  
panel2.add( new JButton( "Button 3" ) );  
}  
public void createPanel3()  
{  
panel3 = new JPanel();  
panel3.setLayout( new BorderLayout() );  
panel3.setPreferredSize( new Dimension( 400,
100 ) );  panel3.setMinimumSize( new Dimension( 100,
50 ) );  
panel3.add( new JLabel( "Notes:" ),
BorderLayout.NORTH );  panel3.add( new JTextArea(),
BorderLayout.CENTER );  
}  
public static void main( String args[] )  
{  
TestSplit mainFrame = new TestSplit();  
mainFrame.pack();  
mainFrame.setVisible(true);  
}  
}  

10. Etichete (Labels)  

Etichetele sunt string-uri de text care se utilizează pentru a identifica alte componente.
Pot  avea propriul tip de font, propriile culori “foreground” (culoarea textului) şi “background” 
(culoarea de fundal), şi pot fi poziţionate oriunde în containerul căruia îi aparţin.  Exemplu de
utilizare a clasei JLabel: 
  
import java.awt.*;  
import javax.swing.*;  
  
class TestLabel extends JFrame  
{  
public TestLabel()  
{  
setTitle( "JLabel Application" );  
setSize( 300, 200 );  
setBackground( Color.gray );  
JPanel topPanel = new JPanel();  
topPanel.setLayout( new GridLayout( 2, 2 ) );  
getContentPane().add( topPanel );  
JLabel label1 = new JLabel();  
label1.setText( "Label1" );  
label1.setForeground( Color.yellow );  
topPanel.add( label1 );  
JLabel label2 = new JLabel( "Label2" );  
label2.setFont( new Font( "Helvetica", Font.BOLD,
18 ) );  topPanel.add( label2 );  
  
  
Icon image = new ImageIcon( "myimage.gif" );  
JLabel label3 = new JLabel( "Enabled",
image,SwingConstants.CENTER ); 
label3.setVerticalTextPosition( SwingConstants.TOP );  
topPanel.add( label3 );  
JLabel label4 = new
JLabel( "Label4",SwingConstants.RIGHT ); 
topPanel.add( label4 );  
}  
public static void main( String args[] )  
{  
TestLabel mainFrame = new TestLabel();  
mainFrame.setVisible( true );  
}  
}  
Să observăm că Label1 îşi schimbă culorile utilizate (metodele setForeground() şi 
setBackground()), Label2 efectuează o schimbare de font, iar Label3 include o imagine grafică. 
Dimensiunea imaginii determină dimensiunea minimă a etichetei.  
  
Alinierea textului   
  
Interfaţa SwingConstants conţine valori constante pentru toate clasele din biblioteca 
Swing. Cinci dintre aceste valori constante sunt aplicabile clasei JLabel pentru alinierea
textului.    
SwingConstants.LEFT - aliniere orizontală stânga  
SwingConstants.CENTER - aliniere orizontală centru sau aliniere
verticală SwingConstants.RIGHT - aliniere orizontală dreapta  
SwingConstants.TOP - aliniere verticală sus  
SwingConstants.BOTTOM - aliniere verticală jos  
  
label.setHorizontalAlignment( SwingConstants.RIGHT );  
label.setVerticalAlignment( SwingConstants.BOTTOM );  
Pentru etichetele care includ atât text cât şi imagine, textul poate fi aliniat independent
de  imagine:  
label.setHorizontalTextAlignment( SwingConstants.LEFT )

label.setVerticalTextAlignment( SwingConstants.TOP );   
Ataşarea unei imagini la o etichetă 

Exemplul anterior arată cum se setează imaginea în timpul construcţiei obiectului


JLabel.  Icon image = new ImageIcon( "myimage.gif" );  
JLabel label3 = new JLabel( "Label3", image,SwingConstants.CENTER );  Se
poate proceda şi altfel – imaginea să fie setată la orice moment.  
Icon image = new ImageIcon( "myimage.gif" );  
label2.setIcon( image );  
Imaginile nu sunt scalate pentru a se potrivi cu limitele dimensiunii etichetei, deci 
adăugarea unei imagini mari poate cauza efectul de “clipping”. Pentru a se înlătura o imagine a 
unei etichete se utilizează:  
label2.setIcon( null );  

11. Butoane  
  
Să ne amintim că toate clasele UI sunt derivate din JComponent.  
  

  
Nu se va utiliza direct clasa AbstractButton, dar în implementarea diferitelor aplicaţii
se  vor utiliza clasele-fiu ale acesteia. Clasa AbstractButton manipulează aproape toate 
funcţionalităţile celorlalte clase Swing Button, de aceea o vom studia in detaliu.    
Tratarea evenimentelor generate de butoane  
  
Cel mai frecvent se utilizează interfaţa ActionListener. Se poate proceda în două
moduri.  Se ceează o clasă independentă de clasa ce conţine instanţa butonului, iar această clasă
va  implementa interfaţa ActionListener (şi va furniza cod pentru metoda actionPerformed() ). 
Avantajul acestei abordări este că mai multe butoane din clase diferite ale unui proiect pot fi 
manipulate de o singură clasă. A doua abordare este de a implementa interfaţa ActionListener
în  clasa care deţine instanţa butonului. Exemplu:  
  
import java.awt.*;  
import java.awt.event.*;  
import javax.swing.*;  
class TestJBut extends JFrame implements
ActionListener  {  
private int iCounter = 0; // Keep track of button
presses  private JButton button = null;  
public TestJBut()  
{  
setTitle( "ActionListener Application" );  
setBackground( Color.gray );  
JPanel topPanel = new JPanel();  
topPanel.setLayout( new FlowLayout() );  
topPanel.setPreferredSize( new Dimension( 300, 200 ) ); 
getContentPane().add( topPanel );  
button = new JButton( "Press Me" );  
topPanel.add( button );  
button.addActionListener( this );  
}  
public void actionPerformed( ActionEvent event )  
{  
if( event.getSource() == button )  
{  
iCounter++;  
button.setText( "Pressed " + iCounter + " times" );  
System.out.println( "Click" );  
pack();  
}  
}  
public static void main( String args[] )  
{  
TestJBut mainFrame = new TestJBut();  
mainFrame.pack();  
mainFrame.setVisible( true );  
}  
}  
  
Ataşarea unei imagini pentru un buton   

Vom modifica exemplul anterior prin adăugarea la suprafaţa butonului a unei imagini
GIF  animate.  
  
import java.awt.*;  
import java.awt.event.*;  
import javax.swing.*;  
class JButImg extends JFrame implements
ActionListener  {  
private int iCounter = 0;  
private JButton button = null;  
public JButImg()  
{  
setTitle( "Animated Button Application" );  
setBackground( Color.gray );  
JPanel topPanel = new JPanel();  
topPanel.setLayout( new FlowLayout() );  
getContentPane().add( topPanel );  
ImageIcon image = new ImageIcon( "computers.gif" );  
button = new JButton( "Press Me", image );  
button.setPreferredSize( new Dimension( 250, 90 ) );  
ImageIcon image1 = new ImageIcon( "appleguy.gif" );  
button.setPressedIcon(image1);  
button.setMnemonic( 'P' );  
topPanel.add( button );  
button.addActionListener( this );  
JButton but1=new JButton(" OK ");  
but1.setEnabled( false );  
topPanel.add(but1);  
JButton but2=new JButton(" OK ");  
but2.setEnabled( true );  
topPanel.add(but2);  
}  
public void actionPerformed( ActionEvent event ) 
{  
if( event.getSource() == button )  
{  
iCounter++;  
button.setText( "Pressed " + iCounter + " times" );  
pack();  
}  
}  
public static void main( String args[] )  
{  
JButImg mainFrame = new JButImg ();  
mainFrame.pack();  
mainFrame.setVisible( true );  
}  
}  
Dacă un buton conţine o imagine, se pot asigna opţional imagini individuale pentru 
următoarele stări ale butonului: normal, selectat, apăsat, cursorul mouse-ului se află deasupra 
suprafeţei butonului, dezactivat. Se utilizează următoarele metode (vezi documentaţie clasa 
AbstractButton): setIcon(),setDisabledIcon(), setDisabledSelectedIcon(), setPressedIcon(), 
setRolloverIcon(), setRolloverSelectedIcon(), setSelectedIcon().  
  
Butoane activate şi dezactivate  
  
De exemplu, pentru aplicaţiile ce conţin formulare bazate pe ferestre de dialog, este util
să se dezactiveze butonul OK până când utilizatorul completează toate câmpurile obligatorii.
Pentru  a activa şi dezactiva un buton se utilizează codul:  
button.setEnabled( bState );  
unde bState este true (pentru activare) sau false (pentru dezactivare). Dacă butonul este 
dezactivat, va fi redesenat într-o nuanţă de gri şters.  
  
Adăugarea unei combinaţii de taste  

Se pot crea aplicaţii care să suporte operaţii fără mouse, numai prin utilizarea tastaturii. 
Swing aplică această capabilitate familiei sale de componente vizuale, permiţând asignarea unei 
combinaţii de taste (“keyboard mnemonic”) numită şi accelerator, pentru orice clasă-fiu a clasei 
părinte JComponent, inclusiv pentru butoane şi “check boxes”. Se utilizează codul:  
button.setMnemonic( 'R' );  
- asignează tasta R instanţei button. Pentru efectul de apăsare a butonului, în loc de a se utiliza
un  click cu mouse-ul, se poate utiliza combinaţia de taste Alt+R.  
Dacă litera se află în eticheta butonului, atunci va apare subliniată.  
  

11.1 Butoane “Toggle”  


  
Swing furnizează şi o clasă numită JToggleButton. Butoanele din această clasă au 
acelaşi aspect ca şi cele JButton, diferenţa constând în faptul că au 2 stări. Butoanele “Toggle” 
lucrează aşa cum lucrează tasta Caps Lock de pe tastatură, în timp ce butoanele JButton
operează în aceeaşi manieră ca tastele ce reprezintă litere sau cifre. Clasa JToggleButton
furnizează un  mecanism “press-and-hold”, deci sunt ideale pentru interfeţele utilizator care
necesită operaţii  modale.  
Mai multe butoane JToggleButton pot fi grupate în aceeaşi manieră ca şi butoanele de
tip  radio, utilizându-se clasa ButtonGroup. Exemplu:  
  
import java.awt.*;  
import java.awt.event.*; 
import javax.swing.*;  
class ToggleBut extends JFrame  
{  
public ToggleBut ()  
{  
setTitle( "ToggleButton Application" );  
setBackground( Color.gray );  
JPanel topPanel = new JPanel();  
topPanel.setLayout( new FlowLayout() );  
getContentPane().add( topPanel );  
JToggleButton button1 = new JToggleButton( "Button 1",
true );  topPanel.add( button1 );  
JToggleButton button2 = new JToggleButton( "Button 2",
false );  topPanel.add( button2 );  
JToggleButton button3 = new JToggleButton( "Button 3",
false );  topPanel.add( button3 );  
ButtonGroup buttonGroup = new ButtonGroup();  
buttonGroup.add( button1 );  
buttonGroup.add( button2 );  
buttonGroup.add( button3 );  
}  
public static void main( String args[] )  
{  
ToggleBut mainFrame = new ToggleBut ();  
mainFrame.pack();  
mainFrame.setVisible( true );  
}  
}  
  
11.2 Butoane “CheckBox”  

Swing furnizează o clasă, numită JCheckBox, care extinde JToggleButton pentru a 


implementa un control standard de tip “check box”. Un “check box” are 2 stări care pot fi setate 
de către utilizator cu ajutorul mouse-ului sau al unui accelerator al tastaturii, sau programatic 
utilizând codul:  
boolean bValue = checkbox.isSelected();  
sau:  
checkbox.setSelected( bValue ); unde bValue este true sau false.  
  
Cel mai eficient se utilizează în grup, pentru a arăta faptul că un obiect poate avea mai 
multe stări simultan, şi că utilizatorul poate modifica una din ele fără a le afecta pe celelalte. Se 
pot utiliza si izolat.  

Observaţie:  
BoxLayout manager simplifică afişarea componentelor JCheckBox în coloană (este 
valabil şi pentru componentele JRadioButton).  
Dacă se doreşte, de exemplu, intermixarea unui grup de “check boxes” cu câmpuri de 
editare ( text Fields), cea mai simplă abordare este de a crea pentru componentele JCheckBox
un  subpanel (utilizând JPanel) având manager-ul BoxLayout, şi de a îl adăuga apoi
containerului  principal în locaţia corectă. Exemplu:  
  
import java.awt.*;  
import java.awt.event.*;  
import javax.swing.*;  
import javax.swing.border.*;  
class TestCheckBox extends JFrame  

public TestCheckBox ()  
{  
setTitle( "BoxLayout Application" );  
setBackground( Color.gray );  
JPanel topPanel = new JPanel();  
topPanel.setLayout( new FlowLayout() );  
getContentPane().add( topPanel );  
JButton button1 = new JButton( "Button 1" );  
button1.setMaximumSize( new Dimension( 100, 25 ) );  
topPanel.add( button1 );  
JPanel innerPanel = new JPanel();  
innerPanel.setLayout(new
BoxLayout(innerPanel,BoxLayout.Y_AXIS)); 
innerPanel.setPreferredSize( new Dimension( 150, 120 ) ); 
innerPanel.setBorder(new TitledBorder(new EtchedBorder(),  
"Checkboxes"));  
topPanel.add( innerPanel );  
JCheckBox check1 = new JCheckBox( "Checkbox 1" );  
check1.setSelected(true);  
innerPanel.add( check1 );  
JCheckBox check2 = new JCheckBox( "Checkbox 2" );  
innerPanel.add( check2 );  
JCheckBox check3 = new JCheckBox( "Checkbox 3" );  
innerPanel.add( check3 );  
JCheckBox check4 = new JCheckBox( "Checkbox 4" );  
innerPanel.add( check4 );  
JPanel textPanel = new JPanel( new BorderLayout() );  
textPanel.setBorder(new TitledBorder(new
EtchedBorder(),"TextArea"));  JTextArea area = new JTextArea( "",
10, 30 );  
area.setPreferredSize( new Dimension( 170, 130 ) );  
textPanel.add( area );  
topPanel.add( textPanel );  
}  
public static void main( String args[] )  
{  
TestCheckBox mainFrame = new TestCheckBox ();  
mainFrame.pack();  
mainFrame.setVisible( true );  
}  
}  
  
11.3 Butoane Radio  
  
În Swing, butoanele Radio sunt implementate în clasa JRadioButton, şi sunt şiruri de 
butoane utilizate pentru a aplica stări mutual exclusive. În Swing, sunt întotdeauna asociate cu o 
instanţă ButtonGroup. Niciodată nu se utilizează izolat, ci numai într-un grup de stări mutual 
exclusive, permiţând utlizatorului selectarea la un moment dat numai a uneia dintre stări. 
Exemplu:  
  
import java.awt.*;  
import java.awt.event.*;  
import javax.swing.*;  
import javax.swing.border.*;  
class TestRadio extends JFrame implements
ActionListener  {  
JButton button1=null;  
String string1=" 1 ";  
String string2=" 2 ";  
String string3=" 3 "; 
public TestRadio ()  
{  
setTitle( "Radio Buttons Application" );  
setBackground( Color.gray );  
JPanel topPanel = new JPanel();  
topPanel.setLayout( new FlowLayout() );  
getContentPane().add( topPanel );  
  
button1 = new JButton( "Button 1" );  
button1.setMaximumSize( new Dimension( 100, 25 ) );  
topPanel.add( button1 );  
//creeaza un grup pentru butoanele radio  
ButtonGroup rgroup=new ButtonGroup();  
JRadioButton radio1 = new JRadioButton ( string1);  
radio1.setActionCommand(string1);  
rgroup.add( radio1 );  
JRadioButton radio2 = new JRadioButton (string2 );  
radio2.setActionCommand(string2);  
rgroup.add( radio2 );  
JRadioButton radio3 = new JRadioButton ( string3);  
radio3.setActionCommand(string3);  
rgroup.add( radio3 );  
//inregistreaza un listener pentru butoanele radio  
radio1.addActionListener(this);  
radio2.addActionListener(this);  
radio3.addActionListener(this);  
//plaseaza butoanele radio orizontal pe un JPanel  
JPanel radioPanel = new JPanel( );  
radioPanel.setLayout(new
BoxLayout(radioPanel,BoxLayout.X_AXIS)); 
radioPanel.setPreferredSize( new Dimension( 300, 50 ) ); 
radioPanel.setBorder(new TitledBorder(new EtchedBorder(),  
"Radio buttons"));  
radioPanel.add(radio1);  
radioPanel.add(radio2);  
radioPanel.add(radio3);  
topPanel.add(radioPanel);  
}  
public void actionPerformed(ActionEvent e)  
 {  
 button1.setText(e.getActionCommand());  
 pack();  
 }  
public static void main( String args[] )  
{  
TestRadio mainFrame = new TestRadio ();  
mainFrame.pack();  
mainFrame.setVisible( true );  
}  
}  

III. MODUL DE LUCRU  


  
Clasic:  
1. Se editează codul sursă al programului Java folosind un editor de text disponibil (de ex.,  se
poate utiliza Notepad).  
2. Se salvează fişierul cu extensia .java. 
3. Compilarea aplicaţiei Java se va face din linia de comandă:  
javac nume_fişier_sursă.java  
În cazul în care programul conţine erori acestea vor fi semnalate şi
afişate.  4. Pentru rularea aplicaţiei Java, se lansează interpretorul Java:  
java nume_clasă_care_conţine_main  
  
Se foloseşte utilitarul disponibil în laborator J2SDK Net Beans IDE.  
  
  
IV. TEMĂ 
  
1. Se vor parcurge toate exemplele prezentate în platforma de laborator testându-se practic şi 
explicând rezultatele obţinute.  
2. Scrieţi o aplicaţie Java utilizând componente Swing. Aplicaţia va conţine o etichetă, un 
buton ce are ataşată o imagine şi o combinaţie de taste, şi un grup de butoane radio.  Atunci
când se apasă butonul se va modifica imaginea ataşată acestuia. Când se selectează una din
opţiunile radio, se va modifica textul etichetei de pe ecran la textul ataşat acelei  opţiuni
curent selectată. 

TEHNOLOGII JAVA 
LUCRARE DE LABORATOR 10  

Fire de execuţie în Java 


I. SCOPUL LUCRĂRII 

Lucrarea de faţă are rolul de a prezenta şi familiariza studentul cu modul de construire şi 
utilizare a firelor de execuţie în Java.  
La sfârşitul acestei lucrări, studentul va avea posibilitatea să scrie programe Java în care să
utilizeze noţiunile învăţate.  

II. NOŢIUNI TEORETICE 


Crearea firelor de execuţie  

“Multithreading” înseamnă capacitatea unui program de a executa mai multe secvenţe


de  cod în acelaşi timp. O astfel de secvenţă de cod se numeşte fir de execuţie sau thread.
Limbajul  Java suportă multithreading prin clase disponibile în pachetul java.lang. În acest
pachet există 2  clase Thread şi ThreadGroup, şi interfaţa Runnable. Clasa Thread şi interfaţa
Runnable oferă 
suport pentru lucrul cu thread-uri ca entităţi separate, iar clasa ThreadGroup pentru crearea
unor  grupuri de thread-uri în vederea tratării acestora într-un mod unitar.  
Există 2 metode pentru crearea unui fir de execuţie: se creează o clasă derivată din clasa 
Thread, sau se creează o clasă care implementeză interfaţa Runnable.  

Crearea unui fir de execuţie prin extinderea clasei Thread  

Se urmează etapele:  
- se creează o clasă derivată din clasa Thread 
- se suprascrie metoda public void run() moştenită din clasa Thread 
- se instanţiază un obiect thread folosind new 
- se porneşte thread-ul instanţiat, prin apelul metodei start() moştenită din clasa Thread.
Apelul acestei metode face ca maşina virtuală Java să creeze contextul de program
necesar unui thread după care să apeleze metoda run(). 

Exemplu:  
public class Fir  
{  
 public static void main(String args[])  
 {  
 FirdeExecutie fir=new FirdeExecutie();  
 fir.start();  
 System.out.println("Revenim la main");  
 }  
}  

class FirdeExecutie extends Thread 


{  
 public void run()  
 {  
 for(int i=0;i<10;i++)  
 System.out.println("Pasul "+i);  
 System.out.println("Run s-a terminat");  
 }  
}  
  
Observaţie:  
Metoda main() are propriul fir de execuţie. Prin apelul start() se cere JVM crearea şi 
pornirea unui nou fir de execuţie. Din funcţia start() se va ieşi imediat. Firul de execuţie 
corespunzător metodei main() îşi va continua execuţia independent de noul fir de execuţie
creat.    
Să considerăm un alt exemplu simplu în care se vor crea două fire de execuţie ce rulează
concomitent. Metoda sleep() cere oprirea rulării firului de execuţie curent pentru un interval de 
timp specificat.  
  
public class Fir1  
{  
 public static void main(String args[])  
 {  
 FirdeExecutie fir1=new FirdeExecutie();  
 FirdeExecutie fir2=new FirdeExecutie();  
 fir1.start();  
 fir2.start();  
 System.out.println("Revenim la main");  
 }  
}  
  
class FirdeExecutie extends Thread  
{  
 public void run()  
 {  
 for(int i=0;i<10;i++)  
 {  
 System.out.println("Pasul "+i);  
 try{  
 sleep(500);//oprirea pt. 0,5 secunde a firului de executie   }  
 catch(InterruptedException e) {System.err.println("Eroare");}   }  
 System.out.println("Run s-a terminat");  
 }  
}  
Java defineşte 3 constante pentru selectarea priorităţilor firelor de
execuţie:  public final static int MAX_PRIORITY; // 10  
public final static int MIN_PRIORITY; // 1  
public final static int NORM_PRIORITY; // 5  
O metodă importantă în contextul utilizării priorităţilor este  
public static native void yield()  
care scoate procesul curent din execuţie şi îl pune în coada de aşteptare.  
Iată un exemplu simplu care demonstrează cum se lucrează cu priorităţile firelor de 
execuţie. Metoda getName() (moştenită din clasa Thread) returnează numele procesului
curent.    
public class Fir2  

 public static void main(String args[])  


 {  
 FirdeExecutie fir1=new FirdeExecutie("Fir 1");  
 FirdeExecutie fir2=new FirdeExecutie("Fir 2");  
 FirdeExecutie fir3=new FirdeExecutie("Fir 3");  
 fir1.setPriority(Thread.MIN_PRIORITY);  
 fir2.setPriority(Thread.MAX_PRIORITY);  
 fir3.setPriority(7);  
 fir1.start();  
 fir2.start();  
 fir3.start();  
 System.out.println("Revenim la main");  
 }  
}  
class FirdeExecutie extends Thread  
{  
 public FirdeExecutie(String s)  
 {  
 super(s);  
 }  
 public void run()  
 {  
 String numeFir=getName();  
 for(int i=0;i<5;i++)  
 {  
 //if(numeFir.compareTo("Fir 3")==0) yield();  
 System.out.println(numeFir+ " este la pasul "+i);  
try{  
 sleep(500);  
 }  
 catch(InterruptedException e) {System.err.println("Eroare");}   }  
 System.out.println(numeFir+ " s-a terminat");  
 }  
}  
  
Observaţie:  
Implementările Java depind de platformă. Un program Java care foloseşte fire de
execuţie  poate avea comportări diferite la execuţii diferite pentru aceleaşi date de intrare.
Platformele  Windows folosesc cuante de timp (firele de execuţie sunt administrate într-o
manieră Round Robin).  
  
  
Crearea unui fir de execuţie folosind interfaţa Runnable  
  
Este o modalitate extrem de utilă atunci când clasa de tip Thread care se doreşte a fi 
implementată moşteneşte o altă clasă (Java nu permite moştenirea multiplă). Interfaţa Runnable
descrie o singură metodă run().  
Se urmează etapele:  
- se creează o clasă care implementează interfaţa Runnable  
- se implemetează metoda run() din interfaţă  
- se instanţiază un obiect al clasei folosind new  
- se creează un obiect din clasa Thread folosind un constructor care are ca parametru un 
obiect de tip Runnable (un obiect al clasei ce implementează interfaţa)  
- se porneşte thread-ul creat la pasul anterior prin apelul metodei start().  
 Exemplu:  
  
public class Fir3  
{  
 public static void main(String args[])  
 {  
 FirdeExecutie fir=new FirdeExecutie();  
 Thread thread=new Thread(fir);  
 thread.start();  
 System.out.println("Revenim la main");  
 }  
}  
  
class A  
{  
 public void afis()  
 {  
 System.out.println("Este un exemplu simplu");  
 }  
}  
  
class FirdeExecutie extends A implements Runnable  
{  
 public void run()  
 {  
 for(int i=0;i<5;i++)  
 System.out.println("Pasul "+i);  
 afis();  
 System.out.println("Run s-a terminat");  
 }  
}  
  
Observaţii utile:  
Un fir de execuţie se poate afla la un moment dat în una din următoarele stări: running
(rulează), waiting (adormire, blocare, suspendare), ready (gata de execuţie, prezent în coada de 
aşteptare), dead (terminat). Fiecare fir de execuţie are o prioritate de execuţie. În general thread
ul cu prioritatea cea mai mare este cel care va accesa primul resursele sistem.  
O altă clasă aparte de thread-uri sunt cele Daemon care sunt thread-uri de serviciu
(aflate  în serviciul altor fire de execuţie). Când se pornesşte maşina virtuală Java, există un
singur fir de  execuţie care nu este de tip Daemon şi care apelează metoda main(). JVM rămâne
pornită cât  există activ un thread care să nu fie de tipul Daemon.  
  
Excludere mutuală şi sincronizare  

Presupunem că două fire de execuţie incrementează valoarea unui întreg partajat. Pot 
apare probleme în sensul că cele 2 fire de execuţie incrementează în acelaşi timp întregul, 
sărindu-se astfel peste valori ale acestuia. Problema se rezolvă dacă cel mult un fir de execuţie
are  acces la acea dată la un moment dat. Java implementează excluderea mutuală prin
specificarea  metodelor care partajează variabile ca fiind synchronized. Aceste metode trebuie
să fie din  aceeaşi clasă. Orice fir de execuţie care încearcă să acceseze o metodă synchronized
a unui  obiect atîta timp cât metoda este utilizată de un alt fir de execuţie, este blocat până când
primul fir  de execuţie părăseşte metoda. Iată un exemplu.  
  
import java.awt.*;  
import java.applet.*;  
import java.awt.event.*; 
public class DoiContori extends Applet implements ActionListener  {  
private Button start;  
private int contor=0;  
public void init()  
{  
start=new Button("Start");  
add(start);  
start.addActionListener(this);  
}  
public void actionPerformed(ActionEvent event)  
{  
 if(event.getSource()==start)  
 {  
 contor++;  
 Graphics g=getGraphics();  
 NumarPartajat numar=new NumarPartajat(g,contor);  
Contor1 contor1=new Contor1(numar);  
 Contor2 contor2=new Contor2(numar);  
 contor1.start();  
 contor2.start();  
 }  
}  
}  
  
class Contor1 extends Thread  
{  
 private NumarPartajat nr;  
 public Contor1(NumarPartajat nr)  
 {  
 this.nr=nr;  
 }  
 public void run()  
 {  
 for(int i=1;i<=10;i++)  
 nr.increment();  
 }  
}  
  
class Contor2 extends Thread  
{  
 private NumarPartajat nr;  
 public Contor2(NumarPartajat nr)  
 {  
 this.nr=nr;  
 }  
 public void run()  
 {  
 for(int i=1;i<=10;i++)  
 nr.increment();  
 }  
}  
  
class NumarPartajat  
{  
 private int n=0;  
 private Graphics g;  
 private int x=0;  
 private int contor;   
public NumarPartajat(Graphics g,int contor)  
{  
 this.g=g;  
 this.contor=contor;  
}  
public synchronized void increment()  
{  
 n=n+1;  
 g.drawString(n+", ",x*20,30+15*contor);  
 x++;  
}  
}  
  
Metodele wait() şi notify()  

Tot o problemă de excludere mutuală este exemplul producător-consumator.


Producătorul  furnizează date pe care consumatorul le utilizează mai departe. Ce se întâmplă
dacă vitezele de  producere şi consum diferă? În acest scop se utilizează metodele wait(),
notify() şi notifyAll() ale  clasei Object. Apelul lui wait() va trece obiectul apelat în starea
Blocked. El rămâne blocat până 
la apelul unei metode notify() sau notifyAll() pentu acelaşi obiect. Condiţia necesară pentru a
se  apela una dintre aceste metode este ca apelul lor să se facă în interiorul metodelor
synchronized.  Pentru metoda wait() se poate specifica o durată maximă de aşteptare. În acest
caz, firul de  execuţie râmâne blocat până când timpul expiră sau un alt fir de execuţie apelează
notify().  
Să considerăm următorul exemplu. Un program Java pentru simularea unei cafenele. O 
comandă se realizează prin apăsarea unui buton (burger, fries, cola). Comanda se afişează pe 
ecran şi apoi se introduce într-o coadă care de asemenea se afişează pe ecran. Şeful ia comnada 
din coadă în sistemul primul venit, primul servit. Chelnerul acceptă o comandă, o afişează şi o 
inserează în coadă.  
  
import java.awt.*;  
import java.applet.*;  
import java.awt.event.*;  
  
public class Cafe extends Applet implements
ActionListener  {  
private Button burger, fries, cola, cooked;  
private Order order, complete;  
  
public void init()  
{  
 Graphics g=getGraphics();  
 burger=new Button("Burger");  
 add(burger);  
 burger.addActionListener(this);  
 fries=new Button("Fries");  
 add(fries);  
 fries.addActionListener(this);  
 cola=new Button("Cola");  
 add(cola);  
 cola.addActionListener(this);  
 cooked=new Button("Cooked");  
 add(cooked);  
 cooked.addActionListener(this);  
 order=new Order();  
 Queue queue=new Queue(g);  
 complete=new Order(); 

 Waiter waiter=new Waiter(g,order,queue);  


 waiter.start();  
 Chef chef=new Chef(g,complete, queue);  
 chef.start();  
}  
  
public void actionPerformed(ActionEvent event)  
{  
 if(event.getSource()==burger)  
 order.notifyEvent("burger");  
 if(event.getSource()==fries)  
 order.notifyEvent("fries");  
 if(event.getSource()==cola)  
 order.notifyEvent("cola");  
 if(event.getSource()==cooked)  
 complete.notifyEvent("cooked");  
}  
}  
  
class Waiter extends Thread  
{  
 private Order order;  
 private Graphics g;  
 private Queue queue;  
  
public Waiter(Graphics g, Order order,Queue queue)  
{  
 this.g=g;  
 this.order=order;  
 this.queue=queue;  
}  
public void run()  
{  
 g.drawString("O noua comanda",10,50);  
 while(true)  
 {  
 String nouaComanda=order.waitForEvent();  
 g.clearRect(10,50,50,25);  
 g.drawString(nouaComanda,10,70);  
 try{  
 Thread.sleep(5000);  
 }  
 catch(InterruptedException e){  
 System.out.println("Exceptie waiter!");  
 }  
 if (! queue.isFull())  
 queue.enter(nouaComanda);  
 }  
}  
}  
  
class Order  
{  
 private String order="";  
  
 public synchronized void notifyEvent(String
nouaComanda)   {  
 order=nouaComanda;  
 notify(); 

 }  
 public synchronized String waitForEvent()  
 {  
 while (order.equals(""))  
 try{  
 wait();  
 }  
 catch(InterruptedException e) {  
 System.out.println("Exceptie order!");  
 }  
 String nouaComanda=order;  
 order="";  
 return nouaComanda;  
 }  
}  
  
class Queue  
{  
 private Graphics g;  
 private String[] queue=new String[20];  
 private int count=0;  
  
 public Queue(Graphics g)  
 {  
 this.g=g;  
 }  
 public synchronized void enter(String item)  
 {  
 queue[count]=item;  
 count++;  
 display();  
 notify();  
 }  
 public synchronized String remove()  
 {  
 while(count==0)  
 try{  
 wait();  
 }  
 catch(InterruptedException e) {  
 System.out.println("Exceptie queue!");  
 }  
 String item=queue[0];  
 count--;  
 for(int c=0;c<count;c++)  
 queue[c]=queue[c+1];  
 display();  
 return item;  
 }  
 public synchronized boolean isFull()  
 {  
 return count==queue.length;  
 }  
 private void display()  
 {  
 g.drawString("Coada",120,50);  
 g.clearRect(120,50,50,220);  
 for(int c=0;c<count;c++)  
 g.drawString(queue[c],120,70+c*20); 

 }  
}  
  
class Chef extends Thread  
{  
 private Graphics g;  
 private Order complete;  
 private Queue queue;  
  
 public Chef(Graphics g, Order complete, Queue
queue)   {  
 this.g=g;  
 this.complete=complete;  
 this.queue=queue;  
 }  
 public void run()  
 {  
 g.drawString("Cooking",200,50);  
 while(true)  
 {  
 String order=queue.remove();  
 g.clearRect(200,55,50,25);  
 g.drawString(order,200,70);  
 g.drawString(order,200,70);  
 String cookedInfo=complete.waitForEvent();  
 g.clearRect(200,55,50,25);  
 }  
 }  
}  

Exemple:  

1. Problema producatorului si a consumatorului  

Specificatia problemei:  

  
Producatorul produce mesaje care contin data si ora emiterii mesajului. Produsele sunt stocate 
intr-o coada. Consumatorul "consuma" mesajele din coada afisandu-le la terminal. Coada 
reprezinta o resursa critica, la care accesul trebuie sincronizat. Producatorul va bloca accesul la 
coada in momentul depunerii "produsului" in coada, si va elibera accesul dupa ce depunerea s-a 
terminat. Daca coada se umple, producatorul intra in asteptare. Daca coada se goleste, atunci 
consumatorul va intra in asteptare. 

  

Descrierea claselor: 
  
Sursa Java:  
import java.util.*;  
class Critical{  
  static final int MAXQUEUE = 5;  
  private Vector messages = new Vector();  
  public synchronized void putMessage() throws InterruptedException{  
  while( messages.size() == MAXQUEUE )  
  wait();   
  String message = new String( new java.util.Date().toString() );  
  System.out.println("Producator: "+message);  
  messages.addElement( message );  
  notify();   
  }  
  public synchronized String getMessage() throws InterruptedException{
notify();  
  while( messages.size() == 0 )  
  wait();   
  String message = (String) messages.firstElement();  
  messages.removeElement( message );  
  return message;  
  }  
}   
class Producer extends Thread{   
  private Critical res;   
  public Producer( String name, Critical res )  
  {  
  super(name);  
  this.res = res;  
  }  
  public void run()  
  {  
  try{   
  while( true ) {  
  res.putMessage();  
  sleep( 1000 );  
  }  
  }  
  catch( InterruptedException e ){}   
  }  
}   
class Consumer extends Thread{   
  private Critical res;   
  public Consumer( String name, Critical res )  
  {  
  super(name);  
  this.res = res;  
  }  
  public void run()  
  { 
  

 try{  
  while( true ) {  
  String message = res.getMessage();  
  System.out.println("Consumator: "+message);  
  sleep(2000);  
  }  
  }  
  catch( InterruptedException e ) {}   
  }  
}   
public class Control6{   
  public static void main( String args[])  
  {  
  Critical res = new Critical();  
  Producer p = new Producer( "Fir producator",res);  
  Consumer c = new Consumer( "Fir consumator",res);  
  p.start();  
  c.start();   
  }  
}   

2.  
Specificatie problema:  
Intr-un birou sunt 8 functionari care din cand in cand tiparesc la imprimanta documente, nu toti 
eleboreaza documentele in acelasi ritm. Fiindca au o singura imprimanta in birou, poate tipari 
doar o singura persoana la un moment dat. Sa se simuleze functionarea biroului.  

Descrierea claselor  
 
 
Sursa Java:  

Coada.java  
package Birou;  
import java.util.*;  
public class Coada{ 
  

 private Vector documente= new Vector();  


  private int MAX_COADA;  
  
  public Coada( int MAX_COADA ){  
  this.MAX_COADA=MAX_COADA;  
  }  
  public synchronized void adauga_document( String document )  
  throws InterruptedException{  
  while( documente.size() == MAX_COADA )  
  wait();   
  documente.addElement( document );  
  notifyAll();  
  }  
  public synchronized String sterge_document()  
  throws InterruptedException{  
  notifyAll();  
  while( documente.size() == 0 )  
  wait();   
  String document = ( String )documente.elementAt(0);  
  documente.removeElementAt( 0 );  
  return document ;  
  }  
}   

Functionar.java  
package Birou;  
public class Functionar extends Thread{  
  private Coada coada;  
  private int nr_document;   
  public Functionar ( String name, Coada coada ){  
  setName( name );  
  this.coada = coada;  
  nr_document = 0;  
  }  
  public void run(){  
  try{   
  while( true ){  
  nr_document++;  
  coada.adauga_document( getName()+"__"+Integer.toString(nr_document));  
sleep( (int) (Math.random() * 2000) );  
  }  
  }  
  catch( InterruptedException e ){  
  }  
  }  
}   

Imprimanta.java  
package Birou;  
public class Imprimanta extends Thread{ 
  

 private Coada coada;  


  public Imprimanta ( String name, Coada coada ){  
  setName( name );  
  this.coada = coada;  
  }  
  public void run(){  
  try{   
  while( true ){  
  System.out.println( "TIPARIRE: "+coada.sterge_document());  
  sleep( (int) (Math.random() * 500) );  
  }  
  }  
  catch( InterruptedException e ){  
  }  
  }  
}   

TestBirou.java  
import Birou.*;  
public class TestBirou{   
  public static void main( String args[] ){  
  int nr_functionari =4;  
  Coada c = new Coada( 10 );  
  Functionar f[] = new Functionar[5];  
  for( int i=0;i<nr_functionari; i++ ){  
  f[ i ] = new Functionar( Integer.toString(i+1), c);  
  f[ i ].start();  
  }  
  Imprimanta i = new Imprimanta( "Imprimanta" , c );  
  i.start();   
  }  
}   

3.  
Specificatie problema:  
Intr-o gara sunt 3 case de bilete. Calatorii se aseaza la coada la una dintre cozi ( de ex: la care e 
mai scurta ). Dar casieritele nu vand biletele in acelasi ritm. Simulati functionarea caselor de 
bilete.  
  
Descrierea claselor
Sursa Java:  

Calator.java  
package Gara;  
import java.util.*;  
public class Calator{   
  private long cID;  
  private Date tsosire;  
  private Date tplecare;  
  public Calator( long cID, Date tsosire, Date tplecare ){  
  this.cID = cID;  
  this.tsosire = tsosire;  
  this.tplecare = tplecare;   
  }  
  public long getCID(){   
  return cID;  
  }  
  public Date getTsosire(){  
  return tsosire;  
  }  
  public Date getTplecare(){   
  return tplecare;  
  }  
  public String toString(){  
  return ( Long.toString(cID)+" "+tsosire.toString()+" "+tplecare.toString());  
}   
}   

Casa.java  
package Gara;  
import java.util.*;  
public class Casa extends Thread{   
  private Vector calatori=new Vector(); 

 public Casa( String name ){  


  setName( name );  
  }  
  public void run(){  
  try{   
  while( true ){  
  sterge_calator();  
  sleep( (int) (Math.random()*4000) );  
  }  
  }  
  catch( InterruptedException e ){  
  System.out.println("Intrerupere");  
  System.out.println( e.toString());  
  }  
  }  
  public synchronized void adauga_calator( Calator c ) throws InterruptedException
{   
  calatori.addElement(c);  
  notifyAll();  
  }  
  public synchronized void sterge_calator() throws InterruptedException
{   
  while( calatori.size() == 0 )  
  wait();   
  Calator c = ( Calator )calatori.elementAt(0);  
  calatori.removeElementAt(0);  
  System.out.println(Long.toString( c.getCID())+" a fost deservit de casa "+getName());  
notifyAll();  
  }  
  public synchronized long lungime_coada() throws InterruptedException{
notifyAll();  
  long size = calatori.size();  
  return size;  
  }  
}   

Producator.java  
package Gara;  
import java.util.*;  
public class Producator extends Thread{  
  
  private Casa casa[];  
  private int nr_case;  
  static long ID =0;  
  private int nr_clienti;//Numar calatori care trebuie deserviti de catre casele de bilete
public Producator( int nr_case, Casa casa[], String name, int nr_clienti ){   setName(
name );   
  this.nr_case = nr_case;  
  this.casa = new Casa[ nr_case ];  
  this.nr_clienti = nr_clienti;  
  for( int i=0; i<nr_case; i++){  
  this.casa[ i ] =casa[ i ] ; 

 }   
  }  
  private int min_index (){   
  int index = 0;  
  try   
  {  
  long min = casa[0].lungime_coada();   
  for( int i=1; i<nr_case; i++){  
  long lung = casa[ i ].lungime_coada();  
  if ( lung < min ){  
  min = lung;   
  index = i;  
  }  
  }  
  }  
  catch( InterruptedException e ){  
  System.out.println( e.toString());  
  }  
  return index;  
  }  
  
  public void run(){  
  try   
  {  
  int i=0;  
  while( i<nr_clienti ){  
  i++;   
  Calator c = new Calator( ++ID, new Date(), new Date() );  
  int m = min_index();  
  System.out.println("Calator :" +Long.toString( ID )+" adaugat la CASA "+ 
Integer.toString(m));  
  casa[ m ].adauga_calator( c );  
  sleep( (int) (Math.random()*1000) );  
  }  
  }  
  catch( InterruptedException e ){  
  System.out.println( e.toString());  
  }  
  }  
}   

TestGara.java  
import Gara.*;  
public class TestGara{   
  public static void main( String args[] ){  
  int i;  
  int nr = 4;   
  Casa c[] = new Casa[ nr ];  
  for( i=0; i<nr; i++){  
  c[ i ] = new Casa("Casa "+Integer.toString( i ));  
  c[ i ].start();  
  } 

 Producator p = new Producator( nr , c, "Producator",30);  


p.start(); 

III. MODUL DE LUCRU 

1. Se foloseşte utilitarul instalat la primul laborator: Eclipse sau NetBeans sau oricare
altul! 2. Pe calculatorul personal este instalata o versiune functionala JDK, in
conformitate cu precizarile de la primul laborator.

IV. TEMĂ 
1. Se vor parcurge toate exemplele prezentate în platforma de laborator testându-se practic şi
explicând rezultatele obţinute. 
2. Scrieţi un program Java pentru simularea unui cronometru (utilizând fire de execuţie).
Acesta are două butoane, unul pentru start şi continuarea secvenţei de timp şi altul pentru
revenirea la poziţia iniţială. 
3. Scrieţi un program Java care generează două fire de execuţie pentru parcurgerea
unui String de la cele două capete. Folosiţi doi pointeri a căror valoarea se
incrementează, respectiv se decrementează într-o funcţie din memoria comună
(synchronized). În memoria comună se află String-ul. Firele de execuţie se întâlnesc la
„mijloc”. 

S-ar putea să vă placă și