Documente Academic
Documente Profesional
Documente Cultură
DEPARTAMENTUL DE INFORMATICĂ
LUCRARE DE LABORATOR 1
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.
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.
//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:
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)
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]);
}
}
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.
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.
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{
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);
}
}
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);
}
}
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ă.
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] .
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.
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];
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ă
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;
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++;
2. Care din următoarele expresii sunt legale? (Alegeţi una sau mai multe.)
3. Care dintre următoarele expresii rezultă într-o expresie pozitivă a lui x? (Alegeţi una.)
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. 0
B. 1
C. 2
D. 3
int x=1;
String []names={“Fred”,”Jim”,”Sheila”};
names[--x]+=”.”;
for(int i=0;i<names.length;i++)
System.out.println(names[i]);
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;
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;
TEHNOLOGII JAVA
LUCRARE DE LABORATOR 2
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.
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);
}
}
}
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);
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--);
}
}
}
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);
}
}
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);
}
{
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);
}
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
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]);
}
}
}
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. int j=2;
2. switch(j) {
3. case 2:
5. Care dintre următoarele construcţii de ciclare sunt legale? (Alegeţi una sau mai multe.)
0
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);
TEHNOLOGII JAVA
LUCRARE DE LABORATOR 3
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.
1. Crearea obiectelor
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
Exemplul 2:
public class Floare
{
public String denumire;
public int nrPetale;
public String zonaClima="-";
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ă
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"); }
}
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ă).
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.
Test.modificaY();
t.modificaY(2);
System.out.println(y);
x=1;
t.modificaX(2);
System.out.println(x);
}
4. Moştenirea
Să considerăm următorul exemplu (programul Vehicule.java):
class Vehicul
{
public String denumire;
public int nrRoti;
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.
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.
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.
int getAnFabricatie()
{
return an_fabricatie;
}
int getDiagonala()
{
return diagonala;
}
}
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
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").
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;
}
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" }
}
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ă:
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:
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ă:
2. Metodele abstracte sunt metode care nu au corp de implementare. Ele sunt declarate
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
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.
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:
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
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)
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 ();
/*
* Client
*/
import java . net .*;
import java .io .*;
∙ 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.
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().
∙ 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
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();
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).
TEHNOLOGII JAVA
LUCRARE DE LABORATOR 5
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.
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:
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
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)
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.
/*
* 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 ();
/*
* Client
*/
∙ 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.
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().
∙ 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
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();
IV. TEMĂ
Se vor parcurge toate exemplele prezentate în platforma de laborator testându-se practic (acolo
unde este cazul).
TEHNOLOGII JAVA
LUCRARE DE LABORATOR 6
I. SCOPUL LUCRĂRII
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.
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.*;
// 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.
//App2.java
import java.applet.Applet;
import java.awt.*;
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().
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 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;
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;
//App6.html
<html>
<body>
<applet code=App6.class width=500 height=500>
</applet>
</body>
</html>
0
//App7.java
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
//App7.html
<html>
<body>
<applet code=App7.class width=200 height=300>
1
</applet>
</body>
</html>
//App8.java
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
//App8.html
<html>
<body>
<applet code=App8.class width=300 height=300>
</applet>
</body>
</html>
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Ă
Java Swing
JFrame, JApplet, JPanel, Borders, Tabbed Panes, Scrolling
Panes, Split Panes, Etichete, Butoane
I. SCOPUL LUCRĂRII
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 )
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!" );
Constructori JApplet
JApplet() -creează o nouă instanţă JApplet.
}
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();
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ă
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ă.
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 );
}
}
TEHNOLOGII JAVA
LUCRARE DE LABORATOR 10
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.
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");
}
}
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()
}
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:
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{
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{
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();
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();
}
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”.