0% au considerat acest document util (0 voturi)
209 vizualizări

Java

Documentul prezintă principalele concepte ale programării orientate obiect și limbajul Java. Sunt descrise elementele de bază ale limbajului Java, inclusiv variabile, expresii și excepții, precum și metodele de dezvoltare a aplicațiilor în stil orientat obiect.

Încărcat de

adasdfsdfas
Drepturi de autor
© © All Rights Reserved
Respectăm cu strictețe drepturile privind conținutul. Dacă suspectați că acesta este conținutul dumneavoastră, reclamați-l aici.
Formate disponibile
Descărcați ca DOCX, PDF, TXT sau citiți online pe Scribd
0% au considerat acest document util (0 voturi)
209 vizualizări

Java

Documentul prezintă principalele concepte ale programării orientate obiect și limbajul Java. Sunt descrise elementele de bază ale limbajului Java, inclusiv variabile, expresii și excepții, precum și metodele de dezvoltare a aplicațiilor în stil orientat obiect.

Încărcat de

adasdfsdfas
Drepturi de autor
© © All Rights Reserved
Respectăm cu strictețe drepturile privind conținutul. Dacă suspectați că acesta este conținutul dumneavoastră, reclamați-l aici.
Formate disponibile
Descărcați ca DOCX, PDF, TXT sau citiți online pe Scribd
Sunteți pe pagina 1/ 219

Material didactic realizat in anul 2000 de lector Antal Margit, Universitatea

"Petru Maior"
Teorie
1. Introducere. Dezvoltarea aplicatiilor in stil OO. Limbajul Java.
2. Conceptele programarii orientate obiect.
3. Modelare cu obiecte
4. Vizibilitatea membrilor clasei si protectia acestora
5. Crearea interfetelor grafice.Pachetul java.awt.
6. Fire de executie
7. Tratarea evenimentelor
8. Facilitati de I/E. Streamuri.
9. Programare in retea. Socluri.
10. Accesul bazelor de date din Java. JDBC.
11. Java Webserver si servleturi.
12. Apleturi
13. Pachetul swing
14. Clase de baza
15. Serializare
16. Mecanismul de reflectie
17. Mecanismul de securitate
18. Programarea distribuita
19. Internationalizare
20. Colectii

Introducere
1. Limbaje orientate obiect - Dezvoltarea aplicatiilor in stil OO
2. Limbajul Java
2.1. Generalitati
2.1.1. Caracteristici
2.1.2. Scrierea aplicatiilor Java
2.1.3. Pachete Java
2.2. Elementele limbajului
2.2.1. Variablie
2.2.1.1. Tipuri primitive
2.2.1.2. Tipul referinta
2.2.1.3. Tablouri
2.2.1.3.1. Alocarea memoriei pentru tablouri
2.2.1.3.2. Lungimea tablourilor
2.2.1.3.3. Initializarea tablourilor
2.2.1.3.4. Eliberarea memoriei alocate dinamic
2.2.2. Expresii
2.2.3. Exceptii
2.2.3.1. Exceptii si tratarea acestora
2.2.3.2. Aruncarea exceptiilor
2.2.3.3. Aspecte legate de performanta utilizarii exceptiilor
2.3. Tipuri de programe Java

1. Limbaje OO
Limbaj

Dezvoltare

Anul de
aparitie

C++

AT&T Bell Laboratories;


Bjarne Stroustrup

inceputul
anilor 1980

Java

SUN JavaSoft; James


Gosling

inceputul
anilor 1990
inceputul
anilor 1970
inceputul
anilor 1980

Smalltalk XEROX PARC


Eiffel

Bertrand Meyer

Pascal

Apple Computer, Niklaus


Wirth

1986

Variante
Borland C++; Microsoft C++; Watcom
C++;
GNU C++
Sun JDK; Symantec Visual Cafe;
Microsoft Visual Java; Borland JBuilder
Smalltalk V.; Smalltalk-80; IBM
Smalltalk

Borland Turbo Pascal; Borland Delphi

Dezvoltarea aplicatiilor in stil OO


Pasii in dezvoltarea unei aplicatii indiferent de stilul de dezvoltare utilizat sunt:
1.
2.
3.
4.

analiza
proiectarea
implementarea
testarea.

Dupa aceea apare si o faza de intretinere a produsului, prin care se intelege corectarea
unor mici erori care apar cu timpul si adaugarea de noi facilitati (mai mici)
produsului. Cateodata la produse neproiectate in mod corespunzator faza de
intretinere poate fi mai costisitoare decat faza realizarii produsului. De aceea este
foarte important ca aplicatia sa fie proiectata modular astfel incat modulele
independente sa se poata intretine si separat.
Analiza: Este facuta de catre un analist, care colaborand cu beneficiarul produsului
identifica obiectele principale ale aplicatiei. De exemplu in cazul unui sistem
informatic pentru banci, obiectele principale ar fi: Client, Factura, Tranzactie,
Angajat_Bancar etc. Rezultatul acestei faze se va concretiza intr-un model realizat de
catre analist. In aceasta faza se determina CE trebuie facut, dar nu si CUM trebuie
facut. Detaliile de implementare apartin altor faze. Se vor identifica subsistemele
principale ale produsului si se va realiza un dictionar de date continand descrierea
principalelor obiecte. In ultima faza a analizei se identifica resursele necesare pentru
sistem (hardver si software).
Proiectarea: Sarcina acestei faze este de a detalia modelul obiect rezultat din faza de
analiza. Proiectantul va determina sarcina exacta a obiectelor si structurile de date
respectiv algoritmii necesari pentru faza de implementare. Tot in aceasta faza se
construiesc diagrame de clase si de obiecte precum si diagrame de colaborare intre
obiecte.
Implementare, testare: Se implementeaza clasele pe baza diagramelor de clase. Daca
proiectul este bine pus la punct atunci munca din aceasta faza este doar munca de
rutina. Tot in acesta faza se incearca utilizarea componentelor gata facute astfel
reutilizand codul existent. Prima data se testeaza componente mai mici, dupa aceea
modulele si in ultima faza se testeaza produsul intreg.
Metode si instrumente de dezvoltare

Metode:
In faza de proiectare a produsului ( si nu numai in aceasta ) ne ajuta produsele CASE
(Computer Aided Systems Engineering ). Unele dintre aceste produse CASE stiu sa
genereze si cod intr-un anumit limbaj sau in mai multe limbaje.
OMT (Object Modeling Technique) 1991, James Rumbaugh
Metoda Booch, 1991, Grady Booch
OOSE (Object Oriented Systems Engineering) 1992, Ivar Jacobson
UML (Unified Modeling Language ) 1997, Rational Corporation, Santa Clara
California. Grady Booch, James Rumbaugh, Ivar Jacobson
UML este un standard, versiunile se gasesc la adresa http://www.rational.rose
Instrumente:

Denumire
Rational Rose (Rational Corporation)
OMTolol (General Electric Research and
Development Center )
Objectory (Objective Systems)
With Class (MicroGold Software Inc. )

Metode
OMT, Booch,
OOSE, UML

Generare cod
C++, Smalltalk, Visual Basic,
Java, Modula

OMT

C++

OOSE
OMT, Booch,
OOSE, UML

C++, Pascal, Eiffel, Smalltalk

2. Limbajul Java
Limbajul Java are radacinile in C. Java este asemanator cu C++, dar este mai flexibil,
mai portabil si mai simplu de invatat. Parintele limbajului a fost James Gosling,
autorul celebrului editor de text emacs. Java incearca sa ramana un limbaj simplu, s-a
preluat partea buna a limbajului C++ si au fost eliminate partile derutante cum ar fi
supraincarcarea operatorilor si mostenirea multipla. Limbajul este independent de
arhitectura calculatorului pe care lucreaza (portabil). Nu genereaza cod nativ pentru o
platforma sau alta ci genereaza o secventa de instructiuni pentru o masina virtuala,
numita si Masina Virtuala Java (JVM). Aplicatiile Java vor fi interpretate. Deci Java
este un limbaj compilat si interpretat. Dezavantajul principal al limbajelor interpretate
este viteza de executie.
2.1.1. Caracteristici:

orientat obiect

distribuit (are biblioteci pentru scrierea aplicatiilor ce lucreaza in retea:


TCP/IP, URL)
securitate ridicata (facilitati de protectie a obiectelor )
permite lucrul cu mai multe fire de executie

2.1.2. Scrierea aplicatiilor Java


Scrierea unei aplicatii Java presupune existenta a amai multe faze. In prima faza se
face editarea programului sursa. Putem utiliza orice editor care stie sa salveze in
format text sau putem utiliza medii care genereaza cod. Rezultatul acestei faze este
unul sau mai multe fisiere sursa Java. Dupa faza de editare urmeaza faza de
compilare. Prin compilare se obtine unul sau mai multe fisiere bytescode (.class) cate
unul pentru fiecare clasa, clasa fiind unitatea de compilare. Dupa faza de compilare
urmeaza faza de executie.
Faza de editare:
Fiser sursa: Aplicatie.java

// Un program care isi afiseaza argumentele primite la linia de comanda


public class Aplicatie{
public static void main( String args[] ){
for( int i=0; i<args.length; i++)
System.out.println(args[i]);
}
}

Faza de compilare:
javac Aplicatie.java

-------> Aplicatie.class

Faza de interpretare:
java Aplicatie argument1 argument2 argument3 ...

In faza de interpretare se va crea un proces care contine in zona cod codul


interpretorului, iar in zona de date codul interpretat (BYTESCODE). Interpretorul este
mic si poate fi implementat usor pentru diferite platforme.
Unitatea de compilare este clasa. Clasele sunt componentele unei aplicatii care contin

date si cod. Clasele sunt incarcate in mod dinamic de catre o aplicatie Java. Ele sunt
incarcate in momentul in care sunt efectiv utilizate. Java contine si cateva clase
fundamentale care contin metode dependente de arhitectura. Aceste metode native
sunt implementate intr-un limbaj nativ platformei si permit accesul la sistemul de
fisiere, sistemul de ferestre si retea. Restul limbajului este scris in Java si este portabil.
Aici sunt incluse aplicatiile ca: compilatorul Java, browserul HotJava de la Sun etc.
2.1.3. Pachete Java
Pachetele Java sunt grupe formate din clase si interfete Java. Principalele pachete sunt:

Contine clasa Applet si clase pentru comunicarea intre


aplet si contextul acestuia
Contine clase pentru crearea interfetelor grafice cat
java.awt
si pentru desenare si lucrul cu imagini
java.awt.color
Permite lucrul cu culori
Clase si interfete pentru transferul datelor intre
java.awt.datatransfer
aplicatii
java.awt.dnd
Clase si interfete pentru operatia drag and drop
Clase si interfete pentru evenimente generate de
java.awt.event
componente AWT
Clase si interfete pentru lucrul cu diferite tipuri de
java.awt.font
fonturi
Clase si interfete pentru crearea si modificarea
java.awt.image
imaginilor
java.awt.print
Clase si interfete pentru tiparire
java.beans
Clase si interfete pentru Java Beans
Clase si interfete pentru intrare/iesire cu fluxuri de
java.io
date
java.lang
Clase fundamentale Java
Clase pentru efectuarea operatiilor aritmetice de
java.math
precizie oarecare
java.net
Clase pentru implementarea aplicatiilor de retea
java.rmi
Pachetul Remote Method Invocation
java.sql
Pachetul pentru JDBC
Clase utilitare ( Vector, Random, StringTokenizer,
java.util
Date)
javax.swing
Clase pentru componente lightwight
java.applet

2.2. Descrierea limbajul Java


2.2.1. Variabile

Toate variabilelel Java sunt initializate. Fiecare tip are o valoare implicita cu care se
initializeaza variabilele de tipul respectiv.
Declaratie: tip nume_variabila [ = expresie ];

2.2.1.1. Tipuri primitive


logic - boolean
caracter - char
intregi - byte, short, int, long
flotante - float, double

Tipul boolean are ca valori true si false. Variabilele boolean neinitializate explicit vor
avea valorarea implicita false.
Tipul caracter are ca valori coduri UNICODE reprezentate pe doi octeti, astfel
permitand reprezentarea tuturor caracterelor limbilor existente. Valoarea implicita este
caracterul null cu codul '\u0000'.
Tipul byte este un tip intreg cu semn avand valorile intre -128 ..127. Valoarea
implicita pentru variabilele de tip intreg este 0. Celelalte tipuri intregi sunt
reprezentate pe 16, 32 respectiv 64 biti.
Tipurile flotante sunt reprezentate pe 32 de biti, respectiv 64 de biti. Valoarea
implicita pentru variabilele flotante este 0.0f.
Reali speciali definiti de standardul IEEE
NaN - Not a Number. Este rezultatul unei impartiri cu 0. Ex. 0.0/0.0
Clasa java.lang.Float defineste aceasta constanta precum si altele cum ar
fi: POSITIVE_INFINITY, NEGATIVE_INFINITY
2.2.1.2. Tipul referinta
In C standard se pot defini tipuri noi, complexe cu ajutorul structurilor. In Java sau
alte limbaje OO se utilizeaza clase in locul structurilor. Clasa defineste un tip nou.
Referinta este similara cu notiunea de pointer din C cu exceptia ca referinta este un
pointer sigur ("safe-pointer"). Referinta este un fel de alias, un alt nume pentru un
obiect. Se utilizeaza in definitia claselor pentru a referi un obiect din interiorul unui alt
obiect.
Exemplu:
String s1 = "Un sir"; // Se aloca memorie pentru referinta s1 si pentru sirul constant
"Un sir". Se initializeaza referinta s1 cu adresa sirului constant
String s2 = s1; // Se aloca memorie pentru referinta s2 care este initializat
cu referinta s1

String s3; // Se aloca memorie pentru referinta s3


In exemplele precedente am creat trei referinte toate de tipul String. Primul a fost
initializat cu un sir constant, al doilea cu o alta referinta, iar al treilea nu a fost deloc
initializat. Valoarea implicita pentru variabile de tip referinta este null (referinta
neinitializata). La crearea referintelor nu se aloca memorie pentru obiectul referit, ci
doar pentru referinta. Alocarea de memorie se face in mod dinamic cu cuvantul
cheie new.
2.2.1.3. Tablouri
2.2.1.3.1. Alocarea dinamica a tablourilor

Tablourile sunt referinte speciale. Numele tabloului este o referinta cu ajutorul careia
ne putem referi la elementele tabloului.
Exemplu de referinta la un tablou de intregi:
int ti[];

Cu constructia de mai sus se creaza o referinta la un tablou de inregi. Nu se aloca


memorie pentru inregii din tablou, practic in acest moment nici nu se cunoaste
dimensiunea acestuia. Alocarea de memorie pentru acest tablou se va face cu
urmatoarea constructie:
ti = new int[10];

Declaratia se poate face si mai compact: int ti[]= new int[10];


Initializarea tablourilor unidimensionale
int ti[]={1, 2, 3, 4, 5};
Tablourile bidimensionale sunt practic tablouri unidimensionale de referinte
int ti[][]=new int[5][]; // Se creaza un tablou de cinci referinte
ti[0]= new int[2]; // Se initializeaza prima referinta din tabloul ti,
ti[0]
ti[1]= new int[3];// Se initializeaza a doua referinta din tabloul ti,
ti[1]

2.2.1.3.2. Lungimea tablorilor

In Java tablourile sunt alocate dinamic, ele isi pot schimba dimensiunile pe parcurul
executiei. Practic la alocarea unui tablou se creaza un nou obiect instantiat dintr-o
clasa ce permite stocarea a mai multor elemente de acelasi tip. Astfel avem la
dispozitie variabila de clasa length ce ne furnizeaza lungimea tabloului. Pentru
exemplul precedent obtinem urmatoarele valori:
int dim_ti = ti.length; // se va obtine 5
int dim_ti_0 = ti[0].length; // se va obtine 2
int dim_ti_1 = ti[1].length; // se va obtine 3

2.2.1.3.3. Initializarea unui tablou bidimensional.

Varianta 1. Se initializeaza un tablou cu doua linii, fiecare linie avand acelasi numar
de elemente.
int t[][] = new int[2][3];
int i,j;
for( i =0; i<t.length; i++)
{
for( j=0; j<t[i].length; j++){
t[i][j] = i*3+j;
System.out.print(t[i][j]);
System.out.print(" ");
}
System.out.println();
}
Rezultatul executiei:
0 1 2
3 4 5

Varianta 2. Se initializeaza un tablou cu doua linii, liniile avand lungime diferita.


int t[][] = new int[2][];

int i,j, c=0;


for( i =0; i<t.length; i++)
{
t[i] = new int[(i+1)*2];
for( j=0; j<t[i].length; j++){
t[i][j] = c++;
System.out.print(t[i][j]);
System.out.print(" ");
}
System.out.println();
}
Rezultatul executiei:
0 1
2 3 4 5
2.2.1.3.4. Eliberarea memoriei alocate dinamic

Eliberarea memoriei alocate dinamic se face automat in Java. Zonele de memorie


nerefeite de nici o referinta sunt colectate de asa zisa "colectorul de gunoi", care se
ruleaza pe un fir de executie de tip demon (cu prioritate mica). Colectorul de gunoi se
poate invoca si explicit prin: System.gc(); Dereferentierea unei variabile se poate
face in urmatoarele moduri:
int x[] = new int[10];
...
x= null; sau x = new int[20];

2.2.2. Expresii
Expresia are un tip si o valoare. Valoarea se obtine prin evaluarea expresiei. Tipul
expresiei se cunoaste inca din faza de compilare. Valoarea expresiei poate fi de un
anumit tip primitiv (rezultatul unei expresii numerice 20+3-6) sau poate fi o referinta (
new OClasa() ) sau poate fi tipul void, ca rezultatul unei metode (functii) ce
returneaza acest tip.
Operatori - Diferente fata de C standard
Java nu suporta operatorii de adresare directa & si cel de adresare indirecta *.
Operatorul de secventiere "," nu este suportat de Java. Nici sizeof nu este suportat.
In schimb avem operatori noi cum ar fiinstanceofsi operatorul + se poate utiliza si la
obiecte de tip String.
String s1 = new String("Un sir de caractere");
String s2 = "Un alt sir de caractere";
boolean b1= (s1 instanceof String);// true
b1 = ( s2 instanceof Object);// true
b1 = ( s1 instanceof Integer );// false

Toate clasele deriva din clasa Object. Aceasta este superclasa tuturor claselor Java.
Operatorul instanceof verifica daca un obiect apartine unei clase. Orice obiect din
subclasa unei clase apartine si superclasei. (Clasa String este subclasa clasei Object,

clasa Object este superclasa clasei String).


2.2.3. Exceptii
Cand vorbim despre exceptii trebuie sa facem diferenta intre instructiunea de generare
(aruncare) a exceptiilor ( throw) respectiv de instructiunea de tratarea acestora (trycatch-finally).
2.2.3.1. Exceptii si tratarea acestora

Proiectul Java a pornit cu scopul declarat de a dezvolta un software performant pentru


aparatele electronice de larg consum. Aceste echipamente se definesc ca mici,
portabile, distribuite si lucrand in timp real. Pentru controlul acestor echipamente era
absolut necesar ca erorile de tip software sa fie adecvat tratate. Nu se admite ca un
telefon sa nu functioneze din cauza unei erori software. Erorile software nu pot fi
eliminate, dar putem identifica secventele de cod care pot cauza acestea si le putem
trata. In limbajul C standard cade in responsabilitatea programatorului tratarea acestor
erori. Functiile returneaza de obicei -1 in caz ca a aparut vreo eroare. De exemplu la
deschiderea unui fisier inexistent pentru citire.
Java ofera o solutie eleganta pentru aceste probleme prin mecanismul de tratarea
exceptiilor. In cazul aparitiei acestor exceptii controlul executiei programului se
transfera la o sectiune de cod, scris in special pentru tratarea unei exceptii. Metodele
Java sunt declarate specificand tipurile de exceptii ce pot fi generate de acestea.
Exceptiile sunt instante (obiecte) ale clasei java.lang.Exception si ale sublcaselor
acesteia. Subclasele clasei Exception pot contine informatii speciale despre un anumit
tip de exceptie si un comportament adecvat. Exceptia cea mai importanta este definita
de clasa java.lang.IOException cu subclase speciale pentru diferite probleme
I/O cum ar fi FileNotFoundException respectiv SocketException.
Un obiect Exception este creat de catre cod in momentul cand au aparut conditiile
pentru o eroare. Obiectul de tip exceptie este transmis impreuna cu controlul executiei
catre codul de tratare a exceptiei.
In continuare vom prezenta exceptiile di cadrul pachetului java.lang impreuna cu
ierarhia de clase din care fac parte. In general avem doua tipuri de exceptii si acestea
sunt repezentate de subclasele claseiThrowable Exception si Error.Cele de tip Error si
RuntimeException sunt generate de mediul de executie. Ecxeptiile de tip Error sunt
generate de asemenea de catre mediul de executie, dar acestea nu pot fi prinse de
program. De exemplu masina virtuala Java nu are memorie suficienta.
java.lang.Exception
1. Object
1.1. Throwable

1.1.1. Exception
1.1.1.1. ClassNotFoundException
1.1.1.2. CloneNotSupportedException
1.1.1.3. IllegalAccessException
1.1.1.4. InstantiationException
1.1.1.5. InterruptedException
1.1.1.6. NoSuchMethodException
1.1.1.7. RuntimeException
1.1.1.7.1. ArithmeticException
1.1.1.7.2. ArrayStoreException
1.1.1.7.3. ClassCastException
1.1.1.7.4. IllegalArgumentException
1.1.1.7.4.1. IllegalThreadStateException
1.1.1.7.4.2. NumberFormatException
1.1.1.7.5. IllegalMonitorStateException
1.1.1.7.6. IllegalStateException
1.1.1.7.7. IndexOutOfBoundsException
1.1.1.7.7.1. ArrayIndexOutOfBoundsException
1.1.1.7.7.2. StringIndexOutOfBoundsException
1.1.1.7.8. NegativeArraySizeException
1.1.1.7.9. NullPointerException
1.1.1.7.10. SecurityException
java.lang.Error
1. Object
1.1. Throwable
1.1.1 Error
1.1.1.1. LinkageError
1.1.1.1.1. ClassCircularityError
1.1.1.1.2. ClassFormatError
1.1.1.1.3. ExceptionInitializerError
1.1.1.1.4. IncompatibleClassChangeError
1.1.1.1.4.1. AbstractMethodError
1.1.1.1.4.2. IllegalAccessError
1.1.1.1.4.3. InstantiationError
1.1.1.1.4.4. NoSuchFieldError
1.1.1.1.4.5. NoSuchMethodError
1.1.1.1.5. NoClassDefFoundError
1.1.1.1.6. UnsatisfiedLinkError
1.1.1.1.7. VerifyError
1.1.1.2. ThreadDeath
1.1.1.3. VirtulaMachineError

Sintaxa instructiunii:
try{
//bloc de instructiuni care pot cauza exceptii
}
catch( TipExceptie1 obiect1 ){
// codul de tratare a exceptiei TipExceptie1
}
catch( TipExceptie2 obiect2 ){
// codul de tratare a exceptiei TipExceptie2
}
finally{
//bloc de instructiuni care se executa intotdeauna
}

Exemplu:

public class fin{


public static void main( String args[] )
{
int i =0;
try{
i = Integer.parseInt( args[ 0 ] );
}
catch( ArrayIndexOutOfBoundsException e1 )
{
System.out.println(e1.toString() );
i=10;
}
catch( NumberFormatException e2 ){
System.out.println( e2.toString() );
i = 20;
}
finally{
i++;
}
System.out.println(i);
}
}

Exemple de executii: ( se compileaza javac fin.java ---> fin.class )


1. java fin
java.lang.ArrayIndexOutOfBoundsException
11

2.java fin 4
5

3. java fin qwerty


java.lang.NumberFormatException
21

Daca exceptia generata nu este prinsa de catre program atunci aceasta va fi prinsa de
catre mediul de executie Java care de obicei suspenda executia programului afisand
exceptia din cauza caruia s-a oprit programul. Daca se trateaza exceptia atunci
controlul executiei programului se transfera la codul de tratare dupa care daca exista
si clauza finally se executa instructiunile de aici, dupa care se continua cu prima
instructiune de dupa blocul try-catch-finally. Daca intr-un bloc try avem mai multe
clauze catch atunci se va cauta secvential intre aceste clauze si numai primul potrivit
va fi executat.
Exemplu:
try{
//cod sursa exceptie de tip IOException
}
catch( Exception e1 ){
// cod de tratare 1

}
catch( IOException e1 ){
// cod de tratare 2
}

In exemplul precedent in cazul generarii exceptiilor intotdeauna se va executa codul


de tratare 1, deoarece orice exceptie este implicit si de tip Exception, aceasta clasa
fiind superclasa tuturor exceptiilor. Concluzia de aici este ca trebuie sa fim foarte
atenti la ordinea in care sunt plasate clauzele catch.
2.2.3.2. Aruncarea exceptiilor

fara a crea o clasa noua de exceptii: prin constructia throw new Exception("S-a
intamplat ceva rau"); Se creaza un obiect de tip Exception si controlul se
transfera blocului de tratate a exceptiei cel mai apropiat.
prin extinderea clasei Exception
class MyException extends Exception{
MyException(){
super(); // Apel constructor superclasa
}
MyException( String text ){
super( text ); // Apel constructor superclasa
}
}

Utilizarea exceptiei:
try{
// operatii ce pot genera MyException
}
catch( MyException e ){
// tratare
}
catch( IOException e ){
//cod de tratare
}

2.2.3.3. Aspecte legate de performanta utilizarii tratarii exceptiilor

Exceptiile trebuie generate doar in imprejurari exceptionale. De exemplu la scrierea


unui ciclu se recomanda efectuarea unui test mic la fiecare reluare a ciclului, decat
generarea unei exceptii, care conduce inevitabil la marirea timpului de executie
datorita faptului ca trebuie gasit contextul cel mai apropiat de try-catch, dupa care
trebuie transferat controlul executiei si revenit dupa aceea.

2.3. Tipuri de programe scrise in Java


Java permite scrierea a doua tipuri de programe:

apleturi care se ruleaza in interiorul paginilor Web, incarcate de navigatoare. In


acest caz navigatorul are si un interpretor Java si interpreteaza codul octeti.

public class UnAplet extends java.awt.Applet{


public void paint( java.awt.Graphics g ){
g.drawString("Un aplet demonstrativ",10,10);
}
}

Fisierul HTML in care se incadreaza apletul:


<html>
<applet code="UnAplet.class" width=300 height=300>
</applet>
</html>

aplicatii care vor fi interpretate de catre interpretorul Java

Exemplu de aplicatie Java: Un program care isi afiseaza argumentele primite la linia
de comanda
public class OAplicatie{
public static void main( String args[] ){
int i;
for( i=0; i<args.length; i++)
System.out.println(args[i]);
}
}

Conceptele programarii orientate obiect


1.
2.
3.
4.
5.
6.
7.

Caracterizarea obiectului
Starea obiectului
Identificarea obiectului
Clasa, instanta
Starile unui obiect
Proprietatea de incapsulare;Ascunderea informatiei
Exemplu: Stiva deintregi

1. Caracterizarea obiectului

Obiectul stocheaza informatie si executa anumite sarcini la cerere. Un obiect este


format din date (atribute) si metode (operatii).

Obiect=Date+Cod
Metodele de fapt sunt rutine care lucreaza cu datele obiectului. Siacum sa consideram
obiectul Om. Un om poate fi caracterizat de nume, dedata nasterii, de inaltime, adresa.
Sunt si alte caracteristici ale omului,dar pentru a rezolva problema noastra e de ajuns
sa le consideram doarpe acestea. Acum discutam cateva metode prin care se manifesta
obiectul nostru. De exemplu oamenii se muta din cand in cand. Odata cu mutarea seva
schimba si adresa omului. Omul poate sa creasca in inaltime pana lao anumita varsta.
Deci obiectul om poate fi caracterizat prin:

Date: nume, data nasterii, inaltime, adresa


Metode: se_muta( adresa noua ), creste( inaltime_noua )

Pana acum am descris o abstractizare a omului, care va fi un tip nou. Acum sa


consideram un exemplu concret, adica un obiect de tip om.

Un alt exemplu. Vom incerca sa caracterizam ferestrele de pe ecran. Unobiect de tip


fereastra poate fi caracterizat prin urmatoarele date simetode:
Date:
x0,y0: coordonatele coltului stanga-sus, intregi
latime, inaltime: intregi
Metode:
afisare()
ascundere()
stergere()

2. Starea obiectului
Este formata din valorile actuale ale datelor. Dupa apelul anumitor metode (ale celor
care modifica campurile de date) starea obiectului se poatemodifica. Doua obiecte se
afla in aceeasi stare daca valorile campurilorde date coincid.

Exemplu:
Om Om("Ioan",32) si
3. Identificarea obiectului
Doua obiecte pot fi in aceeasi stare, dar ele nu pot fi identice, deoarece adresa lor in
memorie difera. Obiectele sunt identificate prin referinte. Doua referinte pot referi
acelasi obiect.
Exemple:
String s1 ="Un sir de caractere";
String s2 = s1;
// Doua referinte la un singur obiect
Om o1 = new Om("Pop Ioan",1960,182,"Tg-Mures");
Om o2 = o1;

Obiectul "Un sir de caractere" exista intr-un singur exemplar si avemdoua referinte s1
si s2 prin care obiectul poate fi accesat.
4. Clasa, instanta
Clasa unui obiect este un tip de data pe baza caruia se pot crea instante din clasa
respectiva. Aceste instante sunt obiecte.

Daca doua obiecte sunt in aceaasi stare atunci la aceaasi cerere reactioneaza la fel.
Cererile se realizeaza prin trimiterea anumitor mesaje obiectului. Mesajele au forma
urmatoare:
referinta_obiect.nume_metoda()

Pentru fiecare obiect se aloca memorie pentru datele obiectului, darmetodele sunt
utilizeaza in comun de catre diferite instante.
Un obiect poate sa ceara de la un alt obiect realizarea unei sarcini.Mesajele sunt de
fapt apeluri de metode publice ale claselor. Metodelepublice sunt metode accesibile de
catre celelalte obiecte. Un obiect poatesa contina si metode private, metode care nu
sunt accesibile din afara.In cazul clasei Fereastra metodele afiseaza() si sterge()
trebuie sa fiemetode publice, iar daca am dori desenarea unui chenar in jurul
ferestreiaceasta am putea-o defini ca o metoda privata.
Obiectele comunica prin mesaje si rolurile sunt distribuite in modulurmator:

client: cel care cere realizarea unei sarcini ( cel care trimitemesajul )
server: cel care executa sarcina (cel care receptioneaza mesajul)
Acelasi obiect poate fi odata client, iar dupa aceea server. Existatotusi obiecte tipice

client cum ar fi obiectele de tip control si obiectetipice server, obiecte de tip baza de
date. In literatura de specialitateputem sa intalnim si denumirile:
ACTOR: care cere numai
AGENT: care cere si executa
Mesajele au rolul de a activa obiecte si realizeaza schimb de informatieintre
obiecte. Raspunsul la un anumit mesaj se obtine prin valoareareturnata de catre
metoda sau prin parametrii transmisi ca referint
Pentru fiecare clasa utilizata in aplicatia noastra se creaza un obiectde
tip Class(java.lang.Class) care tine evidenta obiectelor instantiate din clasele
respective. Un obiect poate sa spuna din ce clasa este instantiata. Exemplu:
String s="Un sir de caractere";
Class c=s.getClass();
//getClass() - Returneazaun obiect de tip Class
System.out.println( c.getName()); //getName() - Returneaza un obiectde tip
String

5. Starile unui obiect


Ca si variabile, obiectele au un ciclu de viata. Se nasc, sunt initializate, dupa care pot
fi inactive sau pot fi activate si dupa aceea mor. Numelemetodei care initializeaza
obiectul difera de la un mediu de programarela altul:
C++, Java: constructor,o metoda cu numele clasei cu o lista de parametri si fara
tipreturnat. Constructorul are sarcina de a aloca memorie pentru campurilede date si
de a le initializa acestea.
Turbo Pascal: Init()
Delphi: Create()
Un constructor de tip Java pentru o fereastra ar avea forma:
Fereastra( int Fx, int Fy, int FLatime, int FInaltime )
{
x0 = Fx; y0 = Fy;
Latime = FLatime; Inaltime = FInaltime;
}

Caracteristicile metodei constructor:

poarta numele clasei


nu returneaza nici un tip de date
poate avea o lista de parametri
o clasa poate avea mai multi constructori

De multe ori la distrugerea obiectelor avem nevoie de dezalocarea resurselor alocate


pentru obiect. In C++ dezalocarile sunt facute de catre o metoda speciala numita si
destructor. In Java dezalocarea memoriei (alocata cu new) se face de catre Garbage
Colector dupa ce nu mai exista nici o referinta a respectivul obiect. Exista insa si
metode native pentru care alocarea memoriei nu s-a facut cu metoda new si in afara
de memorie exista si alte resurse alocabile obiectelor: fisiere, conexiuni retea. Pentru
dezalocarea acestor resurse Java pune la dispozitie metoda finalize, mostenita din
clasa Object si care are urmatoarea signatura:
protected void finalize() throws Throwable{}

Aceasta metoda este apelata de runtime system inainte ca memoria alocata obiectului
respectiv sa fie dezalocata de Garbage Colector. Colectorul de gunoi de ruleaza pe un
fir de executie demon si nu se stie de dinainte cand va fi planificat pentru executie. Se
stie ca metoda finalize se apeleaza inainte ca zona de memorie sa fie reutilizata.
Clasa System insa are o metoda gc() care forteaza executia Garbage Collector si se
foloseste impreuna cu runFinalization(). Aceasta metoda forteaza executia metodelor
finalize() a obiectelor care nu mai sunt referintiate, dar inca n-au fost finalizate. Cu
ajutorul unei alte metode runFinalizerOnExit() putem seta flag-ul care indica masinii
virtuale daca sa execute sau nu metodele finalize la exit, adica la terminarea executiei
masinii virtuale.
public static void gc()
public static void runFinalization()
public static void runFinalizerOnExit()

6. Proprietateade incapsulare. Ascunderea informatiei


Incapsularea inseamna ca datele se definesc impreuna cu codul care actioneaza asupra
lor.

Ascunderea informatiei inseamna ca obiectul isi ascunde problemele interne.Datele


din interiorul obiectelor sunt accesibile doar prin metode publice.Astfel cei
neautorizati nu pot patrunde in interiorul obiectului.

7. Exemplu
Sa se scrie o aplicatie care defineste o clasa stiva si instantieaza obiecte din aceasta
clasa.
Diagrama de obiecte:

Diagrama de clase:

Sursa Java:
public class TControl{
public TControl(){
TStiva s1, s2;
int i;
s1 = new TStiva( 10 );
s2 = new TStiva( );
for( i=0; i<10; i++)
s1.push( i );
while( ! s1.empty() )
System.out.println( Integer.toString( s1.pop()));
for( i=10;i<15;i++){
s2.push( i );
System.out.println( Integer.toString( s2.top()));
}
}
public static void main(String args[] ){
TControl contro = new TControl();
}
}
class TStiva{
int st[];
int sp;
int dim;
public TStiva( int pdim){
dim = pdim;
st = new int[ dim ];
sp = -1;
}
public TStiva( ){
dim = 100;
st = new int[ dim ];

sp = -1;
}
public void push( inte ){
sp++;
st[ sp ] = e;
}
public int pop(){
sp--;
return st[ sp+1 ];
}
public int top(){
return st[ sp ];
}
public boolean empty(){
return sp==-1;
}
}

Modelare cu obiecte
1.
2.
3.
4.

Legatura dintre obiecte, diagrame de obiecte


Diagrama de clase
Mostenire. Legare statica.
Exemple

1. Legatura dintre obiecte, diagrame de obiecte


Obiectele pot conlucra doar daca exista legaturi intre ele. Legaturiledintre obiecte sunt
de doua feluri:

de cunoastere (aquaintance relationship)


de continere(aggregation relationship)

Doua obiecte sunt in legatura de cunoastere, daca existaindependent si cel putin unul
cunoaste pe celalalt.
Doua obiecte sunt in legatura de continere, daca unul dintreele contine fizic pe
celalalt. (intreg+parte)
Exemple de legaturi de cunoastere:

Relatia de continere:
Daca se distruge obiectul container atunci automat se distrug si obiectele continute.
Relatia de continere este o relatie mai puternica decat relatia de cunoastere. Relatia de
continere poate fi o relatie de continere slaba sau una puternica. In cazul relatiei de
continere slaba, intregul isi cunoaste partile, dar poate exista independent de partea
continuta. Ca exemplu vom considera un obiect Cutie, care poate sa contina un cadou.
Cutia existasi fara cadou. Pentru acest tip de relatie se utilizeaza un romb neumplutpe
partea intregului.

In cazul relatiei de continere puternica utilizam un romb umplut tot pepartea


intregului, dar in acest caz intregul nu exista independent de partilelui. Ca exemplu
consideram obiectele TCaine, TCap, TCorp, TPicior si diagramaurmatoare pentru
relatia de continere puternica.

Diagramele de mai sus se numesc diagrame de obiecte.

2. Diagrame de clase

Lagaturile de pe diagramele de mai sus sunt de doua tipuri


1. legaturi obligatorii (intre tara si captala), nu exista tara fara capitala si invers
2. legaturi optionale cum ar fi legatura de casnicie intre barbat si femeie
Legaturile dintre clase pot fi clasificate si dupa gradul legaturilor.Aici putem avea
urmatioarele situatii:

legatura unu la unu (one to one association)


legatura unu la mai multe (one to many association)
lagatura mai multe la mai multe(many to many association)

Exemplele de mai sus au fost din prima categorie, adica legaturi unu launu.
Exemple de legaturi unu la mai multe:

Exemple de legaturi "mai multe la mai multe"

In cazul diagramei de mai sus * inseamna ca numarul cursurilor poate fioricat de


mare, iar cursurile se fac doar daca avem cel putin 10 cursanti.Capaciatatea salilor
fiind limitata, cursurile se tin maximum pentru 100de studenti. In cazul celei de-a
doua diagrame avem o legatura de cunoasterecu semnificatia ca orice student poate sa
cunoasca orice alt student.
Realizarea legaturilor
Obiectul de tip client intotdeauna trebuie sa cunoasca obiectul de tipserver. Cel care
initiaza cererea trebuie sa cunoasca pe cel caruia adreseazacererea. In cazul scrierii
aplicatiilor acest lucru se realizeaza cu ajutorulunei referinte. Exemplu:
class TClient{

TServer server;
...
}
class TServer
...
}

Scrierea unei aplicatii OO


Pas. 1. Specificarea detaliata a problemei astfel incat programul safie realizabil
Pas. 2. Faza de proiectare+implementare

Proiectare:
o
Diagrame de obiecte
o
Diagrame de clase
Implementare:

Implementarea claselor intr-unlimbaj


Pas. 3. Testare

Mostenire
Prima data definim doua concepte: specializarea si generalizarea.
Specializarea este procesul prin care se adauga noi caracteristiciunui obiect existent.
Generalizarea este procesul prin care din descrierea mai multorobiecte scoatem in
evidenta cele comune.

In exemplul de mai sus rombul, dreptunghiul si patratul sunt paralelogramespeciale.


De exemplu dreptunghiul este un paralelogram cu un unghi dreptunghic.

Mostenirea este procesul de specializare. Clasa care se extinde senumeste clasa


parinte, iar clasa derivata se numeste clasa copil.

Prin mostenire se adauga noi proprietati unei clase existente si se potredefini anumite
caracteristici ai clasei existente.
Notatia UML pentru mostenire:

In exemplul de mai sus clasa TOm are doua campuri de date, numele si anul nasterii,
respectiv doua metode invata() si vorbeste(). Din aceasta clasa de baza derivam doua
alte clase noi, clasa TStudent respectiv clasa TProfesor. Aceste clase noi adauga alte
campuri de date si metode respectiv specializeaza anumite metode ale clasei de baza.
Astfel clasa TStudent va avea cinci campuri de date: nume, anul nasterii, numar
matricol, an de studii, medie si doua metode inavata() si vorbeste(). Metoda invata() a
fost specializata (redefinita) deoarece un student invata altfel decat un om obisnuit.
Probabil ca invata mai mult si invata in anumite perioade ale anului. In cazul clasei
TProfesor apar doua date in plus fata de clasa parinte. Apare catedra la care apartine si
salariul pe care primeste pentru activitatea desfasurata. Clasa defineste o noua metoda
preda(),care caracterizeaza numai obiectele de tip TProfesor si redefineste

metodevorbeste() deoarece un profesor ar trebui sa vorbeasca mai clar si maicoerent


decat un om obisnuit. In concluzie prin mostenire putem face urmatoarele:

se adauga campuri de date noi


se adauga metode noi
se redefinesc anumite metode ale clasei parinte

Observatie: Daca se adauga campuri de date noi, atunci trebuie adaugatesi metode noi
care realizeaza accesul la aceste date.
Exista limbaje de programare care permit si mostenirea multipla cumar fi C++, iar
altele care permit doar derivarea de la o singura clasaparinte: Java, Smalltalk, Delphi.

Apelul constructorilor in cazul mostenirii


Consideram exemplul urmator:
class A{
A(){
System.out.println("Constructorul clasei A");
}
}
class B extends A{
B(){
System.out.println("Constructorul clasei B");

}
}
public class p4{
public static void main( String args[] )
{
B b = new B();
}
}

Rezultatul executiei va fi:


Constructorul clasei A
Constructorul clasei B

Deci putem afirma ca constructorul suprclasei se apeleaza intotdeauna automat, daca


aceasta are un constructor fara argumente. In caz contrar trebuie apelat explicit
furnizandu-i parametrii corespunztori. Exemplul urmator ilustreaza acest lucru:
class A{
A( String a){
System.out.println("Constructorul clasei A "+a);
}
}
class B extends A{
B( String b){
super( b );
System.out.println("Constructorul clasei B "+b);
}
}
public class p5{
public static void main( String args[] )
{
B b = new B("Hi");
}
}

Legare statica
Legare statica inseamna ca adresa metodei se cunoaste inca din timpul compilarii.
Deci in cazul unei constructii nume_obiect.metoda() compilatorul stie exact care
metoda va fi executata. Daca clasa careia apartine obiectul nu areo asemenea metoda
atunci compilatorul cauta metoda in ierarhia declase. Se va apela metoda din clasa

cea mai apropiata cu acelasi nume Aceasta cautare este facuta in faza compilarii si
acest tip de legare senumeste legare statica.
Exemplu 1: Sa se scrie o aplicatie care afiseaza pe ecran treiferestre cu titlurile: Unu,
Doi, Trei si cu dimensiunile 100x100.
Diagrama de clase:

Diagrama de colaborare:

Codul sursa Java:


//Source file: Aplicatie.java
import java.awt.Frame;
public class Aplicatie
{
public Frame Frames[];
public Aplicatie()
{
int i;
String titles[]={"Unu", "Doi","Trei"};
Frames = new Frame[ 3 ];
for(i=0;i<3;i++)
{
Frames[i ] = new Frame(titles[ i ]);
Frames[i ].setBounds(100*i,100*i,100,100);
Frames[i ].setVisible( true );
}

}
public static void main(String[] args)
{
Aplicatie a = new Aplicatie();
}
}

Exemplu 2: Sa se scrie o aplicatie care se ruleaza intr-o fereastra.Fereastra va contine


o eticheta si doua butoane.

Sursa Java:
import java.awt.Frame;
import java.awt.Button;
import java.awt.Label;
public class MyFrame extends Frame
{
private Button buttons[];
private Label label;
public MyFrame()
{
// Crearea butoanelor si adaugarea lor la container
buttons = new Button[ 2 ];
buttons[ 0 ]= new Button("Buton 1");
add( buttons[ 0 ], "North" );
buttons[ 1 ]= new Button("Buton 2");
add( buttons[ 1 ],"South" );
// Crearea etichetei si adaugarea ei la container

label = new Label("Eticheta");


add( label, "Center" );
}
public static void main(String[] args)
{
MyFrame f = new MyFrame();
f.setBounds(10,10, 300, 300 );
f.setVisible( true );
}
}

Exemplu 3: Sa se scrie o aplicatie care afiseaza cinci ferestrede tip MyFrame astfel
incat sa nu se suprapuna.

Sursa Java:
//Source file: MyFrames.java

public class MyFrames


{
public MyFrame Frames[];
public MyFrames()
{
int i;
Frames = new MyFrame[5];
for( i=0; i<5; i++)
{
Frames[ i ] = new MyFrame(Integer.toString( i ));

Frames[ i ].setBounds(i*100,i*100,50,50);
Frames[ i ].setVisible( true );
}
}

public static void main(String[] args)


{
MyFrames f = new MyFrames();
}
}

Vizibilitatea membrilor clasei si protectia acestora


1.
2.
3.
4.
5.

Interfete, pachete, utilitarul jar, clase incuibate


Modificatori de acces
Polimorfism
Modificatori de tip
Instantele predefinite this si super

1. Interfete, pachete
O interfata este o declaratie de tip care defineste de obicei un comportament. Este
formata dintr-o serie de constante si metode pentru care nu se specifica nici un fel de
implementare. In Java se utilizeazainterfete pentru a suplini lipsa mostenirii multiple.
Si interfetele potavea modificatori. Din punctul de vedere al accesului la ele pot fi
publice(publicinterface .. ), accesibile si din alte pachete decat din cel care odefineste.
Pot avea atasat si modificatorul de tip abstract ( abstractinterface... ).
interface Scalabil{
static final MARE = 2, MEDIU = 1, MIC =0;
void scalare( int marime );
}
class Cutie implements Scalabil{
public void scalare( int marime ){
switch ( marime ){
case MARE :{ ...; break; }.
case MEDIU:{ ...; break; }
case MIC
:{ ...; break; }
}
}
}

Deoarece interfata defineste un tip nou de aceea oriunde se pot utiliza clase se pot
utiliza si interfte. De exemplu in cazul exemplului de maisus putem avea urmatorul
cod:
Scalabil s; // s-a declarat o referinta la interfata Scalabil
s = new Cutie(); // s-a instantiat un obiect din clasa Cutiecu care s-a initializat
referinta s
Exemplu 1. Declaraea unei interfete si utilizarea acestuia
interface Scalabil{
static final int MARE =
static final int MEDIU =
static final int MIC
=
void scalare( int marime
}

2;
1;
0;
);

class Cutie implements Scalabil{


public void scalare( int marime ){
switch ( marime ){
case MARE :System.out.println("MARE"); break;
case MEDIU:System.out.println("MEDIU"); break;
case MIC :System.out.println("MIC"); break;
}
}
}
public class p_4_1{
public static void main( String args[] )
{
Cutie c = newCutie();
c.scalare(1);
Scalabil s = newCutie();
s.scalare( 2 );
}
}

Exemplu 2. Utilizarea interfetei List


Exemplul urmator afiseaza argumentelor liniei de comanda intr-o ordine aleatoare
import java.util.*;
public class Shuffle {
public static void main(String args[]) {
// l este o referintala o interfata List si poate fi initializata
//cu orice obiect instantiat dintr-o implementarea a interfetei

List l = Arrays.asList(args);
Collections.shuffle(l);
System.out.println(l);
}
}

Crearea pachetelor
Un pachet este format dintr-un grup de clase si interfete. Clasele pe care le utilizam in
aplicatiile noastre trebuie sa fie cunoscute si de catrecompilator, respectiv de catre
interpretor.
Codul sursa al unei clase Java se numeste unitate de compilare.O unitate de
compilare in mod normal este format dintr-un singur fisiercontinand definitia unei
singure clase (poate fi formata si din mai multeclase dar numai una singura poate fi
publica) si fisierul poarta numeleclasei. Clasa MyClass se defineste in
fisierul MyClass.java.Fiecare clasa Java apartine unui pachet. Daca nu se declara carui
pachetii apartine clasa, atunci va apartine pachetului implicit, altfel
pachetuluispecificat.
Variabila mediului de executie CLASSPATH este utilizat atat de compilator cat si de
interpretor pentru localizarea unei resurse. Contine caile incare se afla pachetele Java.
O cale poate specifica un catalog sau un fisierdintr-un catalog dat. Pachetele pot fi
arhivate si incarcatorul de claseva extrage din arhive clasele necesare. Formatele de
arhivare suportatede catre mediul de executie Java sunt JAR (Java Archive)
si ZIP.Fisierele JAR sunt create cu utilitarul jar care face partedin JDK. Intr-o arhiva
JAR se poate pune absolut orice tip de fisier. Decitoate clasele apartinand unei
aplicatii pot fi impachetate intr-un singurfisier JAR, care se adauga pe urma la
CLASSPATH.
Utilizarea utilitarului jar (Similar cu utilitarul tar de sub UNIX):

Comanda

Semnificatie

jar -cvf <nume_arhiva> <catalog1>


<catalog2> ...

Se creaza arhiva cu numele specificat si care va


contine continutul cataloagelor specificate

jar -tvf

Afiseaza continutul arhivei

<nume_arhiva>

jar -xvf <nume_arhiva> <catalog1>


<catalog2> ...

c-create - creare arhiva


t-tell -afisare continut arhiva

Extrage continutul arhivei, eventual doar


continuturile cataloagelor specificate.

x-extract - extragere din arhiva


v-verbose -cu mai multe informatii despre operatia curenta
f-file -primul argument este numele arhivei
$jar -cvf

Curs4.jar Curs4

added manifest
adding: Curs4/ (in=0) (out=0) (stored 0%)
adding:
adding:
adding:
adding:
adding:
adding:
40%)

Curs4/Person.class (in=669) (out=372) (deflated 44%)


Curs4/ppelda.java (in=665) (out=189) (deflated 71%)
Curs4/classes/ (in=0) (out=0) (stored 0%)
Curs4/classes/MyPackage/ (in=0) (out=0) (stored 0%)
Curs4/classes/MyPackage/Person.class (in=692) (out=384)(deflated 44%)
Curs4/classes/MyPackage/Student.class (in=488) (out=290)(deflated

adding:
adding:
adding:
adding:
adding:
adding:

Curs4/classes/Test.class (in=888) (out=519) (deflated 41%)


Curs4/Person.java (in=861) (out=300) (deflated 65%)
Curs4/Test.java (in=587) (out=293) (deflated 50%)
Curs4/Test.class (in=675) (out=405) (deflated 40%)
Curs4/Curs4.jar (in=340) (out=183) (deflated 46%)
Curs4/Student.java (in=522) (out=220) (deflated 57%)

$jar -xvf
created:
extracted:
created:
extracted:
extracted:
created:
created:
extracted:
extracted:
extracted:
extracted:
extracted:
extracted:
extracted:
extracted:

Curs4.jar
META-INF/
META-INF/MANIFEST.MF
Curs4/
Curs4/Person.class
Curs4/ppelda.java
Curs4/classes/
Curs4/classes/MyPackage/
Curs4/classes/MyPackage/Person.class
Curs4/classes/MyPackage/Student.class
Curs4/classes/Test.class
Curs4/Person.java
Curs4/Test.java
Curs4/Test.class
Curs4/Curs4.jar
Curs4/Student.java

$jar -tvf Curs4.jar


0 Tue Mar 21 15:01:24 EET 2000 META-INF/
66 Tue Mar 21 15:01:24 EET 2000 META-INF/MANIFEST.MF
0 Thu Feb 10 13:18:26 EET 2000 Curs4/
669 Mon Mar 20 21:15:04 EET 2000 Curs4/Person.class
665 Mon Mar 20 20:51:52 EET 2000 Curs4/ppelda.java
0 Tue Mar 21 08:01:02 EET 2000 Curs4/classes/
0 Tue Mar 21 09:17:10 EET 2000 Curs4/classes/MyPackage/
692 Tue Mar 21 12:57:50 EET 2000 Curs4/classes/MyPackage/Person.class

488 Tue Mar 21 13:15:22 EET 2000 Curs4/classes/MyPackage/Student.class


888 Tue Mar 21 13:23:40 EET 2000 Curs4/classes/Test.class
861 Tue Mar 21 13:26:28 EET 2000 Curs4/Person.java
587 Tue Mar 21 13:25:22 EET 2000 Curs4/Test.java
675 Tue Mar 21 13:20:58 EET 2000 Curs4/Test.class
340 Tue Mar 21 15:00:52 EET 2000 Curs4/Curs4.jar
522 Tue Mar 21 13:38:18 EET 2000 Curs4/Student.java

Exemplu:
Fisierul: MyBaseClass.java
package MyPackage;
public class MyBaseClass{
..
}
Fisierul: MyDerivedClass.java
package MyPackage;
public class MyDerivedClass extends MyBaseClass{
..
}

Exemplul precedent este format din doua unitati de compilare care apartin aceluiasi
pachet. Pentru compilarea acestor fisiere se vor utiliza liniile de comanda:
1. mkdir classes
//Se creaza catalogulclasses pentru fisierele .class
2. javac -d .\classes MyBaseClass.java
//Se compileaza unitatea
//MyBaseClass.java, fisierul
//rezultat se va pune in directorul
//specificat dupa
//optiunea -d

Rezultatul: ---classes----MyPackage----MyBaseClass.class
3. javac -d .\classes -classpath .\classes;c:\jdk1.2\lib MyDerivedClass.java
//Se compileaza unitatea MyDerivedClass.java, rezultatul se stocheaza tot
//in directorul classes, iar pentru incarcarea claselor se utilizeaza
caile
//specificate
//dupa optiunea -classpath. Aici s-au specificat doua cai de cautare:
//subdirectorul classes al directorului curent si subdirectorul lib al
//catalogului in
//care s-a instalat JDK

Rezultatul: ---classes----MyPackage--------MyBaseClass.class
|

|-------MyDerivedClass.class
Utilizarea pachetelor
Pentru a utiliza clase dintr-un pachet putem sa alegem din 3 variante:
1. Se prefixeaza numele clasei cu numele pachetului
Exemple:
java.awt.Button b;
MyPackage.MyBaseClass ob;
MyPackage.MyDerivedClass od;

2. Se importa clasele de care are nevoie aplicatia:


import java.awt.Button;
import MyPackage.MyBaseClass;
import MyPackage.MyDerivedClass

3. Se importa pachete intregi


import java.awt.*;
import MyPackage.*;

Exemplu complet:

// Se creaza catalogul classes


//
//
va
//
//

Compilare: javac -d .\classes Person.java


In catalogul classes se creaza un subcatalog al acestuiaMyPackage si aici
fi
pus si
rezultatul compilarii, fisierul Person.class

package MyPackage;
public class Person{
protected String name;
protected int age;
public Person( Stringname, int age){
this.name = name;

this.age = age;
}
public String getName(){
return name;
}
public int getAge(){
return age;
}
public void setName(String name ){
this.name = name;
}
public void setAge( intage ){
this.age = age;
}
}

//Compilare: javac -d ./classes -classpath c:\jdk1.2\lib;./classes


package MyPackage;
public class Student extends MyPackage.Person{
protected String faculty;
public

Student(String name, int age, String faculty){


super( name, age );
this.faculty = faculty;

}
public String getFaculty(){
return faculty;
}
public void setFaculty(String faculty ){
this.faculty = faculty;
}
}

// Compilare: javac -d .\classes -classpath c:\jdk1.2\lib;.\classes Test.java


// Interpretare: java -classpath c:\jdk1.2\lib;.\classes Test
import MyPackage.Student;
import MyPackage.Person;
public class Test{
public static void main(String args[] ){
Person p1 = new Person("Peter",20);
System.out.println("Name:"+p1.getName());
Student s1 = new Student("Paul",24,"Engeneering");

System.out.println("Name: "+s1.getName()+" Faculty:


"+s1.getFaculty());

}
}

Clase incuibate
Incepand cu versiunea 1.1 se pot declara clase in interiorull altorclase. In acest caz,
obiecte din clasa incuibata se pot declara doar inclasa care le contine. Se pot declara
chiar si clase incuibate anonime.
Clase incuibate anonieme si instantierea acestora:
{
...
addWindowListener( new WindowAdapter(){
public void windowClosing( WindowEvent e ){
{
System.exit( 0 );
}
}
);
...
}

Clase incuibate si instantierea acestora


class A{
A(){}
class B{
B(){}
public void doIt(){
System.out.println("Hello");
}
};
}
public class p2{
public static void main( String args[] )
{
A a = new A();
A.B b = a. new B();
b.doIt();
}
}

Clase incuibate statice

class A{
A(){}
static class B{
B(){}
public static void doIt(){
System.out.println("Hello");
}
};
}
public class p3{
public static void main( String args[] )
{
A.B.doIt();
}
}

Observatii:
1. Clasele incuibate nu pot contine metode statice, exceptie formand clasele incuibate
statice
2. Clasele incuibate nestatice apartin claselor exterioare, de aceea instantierea
obiectelor din aceste clase este precedata de instantierea obiectelor din clasele
exterioare.
In exemplul urmator vom utiliza interfata Enumeration:
//Interfata java.util.Enumeration
public interface Enumeration{
boolean hasMoreElements();
Object nextElement();
}

Un enumerator se utilizeaza pentru parcurgerea elementelor dintr-ostructura de date.


In exemplul urmator vom declara o lista de studentisi in interiorul acesteia o clasa care

implementeaza interfata Enumeration.

2. Modificatori de acces
O clasa gata facuta se poate utiliza in doua moduri:

prin crearea de noi instante din clasa respectiva


prin mostenire, derivarea de noi clase din clasa de baza

Accesul datelor din afara obiectului nu trebuie permis. De obicei clasatrebuia sa puna
la dispozitia celor care o utilizeaza o serie de metodepublice care permit manipularea
acestor date. Exista si metode care suntmetode ajutatoare si nu trebuie sa fie accesibile
din afara. Pentru a putearealiza protectia membrilor clasei vom utiliza asa zisele
modificatoride acces. Modificatorii pot fi atasati atat claselor cat si membrilor

acestora.Prima data ne ocupam de modificatorii membrilor clasei (date+metode).


InJava avem urmatoarele tipuri de modificatori pentru membrii clasei:

private -private
public -publice
protected -protejate
prietenosi

Membrii privati ai clasei nu sunt accesibili din afara clasei. Ei pot fiutilizati doar de
catre celelalte metode ale clasei.
Membrii publici sunt accesibili din afara clasei. Ei pot fi utilizatisi in clasele derivate.
Nu exista nici o restrictie in utilizarea acestora.
Membrii protejati sunt accesibili doar prin metodele clasei si ei vorfi accesibili si in
clasele derivate.
Membrii prietenosi sunt declarate fara nici un fel de cuvant cheiesi ei vor fi accesibili
din toate clasele din pachetul caruia apartineclasa.
In continuare vizibilitatea datelor va fi notata in modul urmator:
+ ----> membru public
- ----> membru privat
# ----> membru protejat

In cazul mostenirii membrii privati ai clasei vor exista si in clasa derivata, dar acestia
nu vor fi accesibili.
Din punctul de vedere al accesului la clasa avem doar doua tipuri declase:

clase publice
clase nepublice.

Clasele publice sunt accesibile pentru toate celelalte clase, iar celenepublice doar
pentru clasele care fac parte din acelasi pachet. Cele nepublicese declara normal fara

vreun modificator, iar cele publice se declara cumodificatorul public. (public class ...).

3. Polimorfism
Supraincarcarea metodelor (Methods overloading) inseamnadefinirea a doua sau a
mai multe metode in cadrul unei clase care diferaprin lista parametrilor si eventual
prin tipul returnat. De exemplu inJava putem avea oricati constructori pentru o clasa.
Toti constructorii poarta numele clasei (au acelasi nume) ei difera doar prin parametrii
lor (Constructorii nu returneaza nici o valoare). Pentru exemplificare consideram clasa
String din pachetul java.lang si cativa din constructorii clasei:
String()- creaza un obiect de tip string vid
String( String) - creaza un obiect de tip string initializand cu un alt obiectde
tip string (se copiaza continutul parametrului)
String( char []) - creaza un obiect de tip string initializand cu un tablou
decaractere
String( char s[],int indice_start, int numar_caractere
) -creaza un obiect de tipstring initializand acesta cu un subtablou
In afara de constructor putem defini si alte metode cu acelasi nume.De exemplu:
int max( int, int);
float max( float,float );
Compilatorul poate decide despre care metoda este vorba din tipul sinumarul
parametrilor. Deci adresa acestor metode se cunoaste inca din fazade compilare.
Redefinirea metodelor (Methods overriding) inseamna caclasele derivate pot redefini
metodele claselor parinte utilizand aceasisintaxa ( tip returnat nume_metoda( lista
parametrilor)). Un exemplu:

Metodele supraincarcate sunt legate in mod static, adica adresa lor secunoaste inca din
faza compilarii. Metodele redefinite sunt legate in moddinamic in timpul executiei.
Acest lucru duce imediat la scaderea vitezeide executie a programelor. In Java toate
metodele pot fi redefinite, iardaca dorim interzicerea redefinirii atunci putem utiliza
modificatorulfinal (modificator de tip). Modificatorul final face ca un membru sa
fieprivit constant. Modificatorul se mai poate utiliza pentru campuri de date si pentru
clase. Dintr-o clasa definita cu modificatorul final nu putemderiva alte subclase.

4. Modificatori de tip
Acesti modificatori se pot defini pentru clase, metode si variabilele clasei.
Modificatori pentru clase:

final
abstract

O clasa se poate declara abstract sau final. Clasele finale nu potfi superclase pentru
alte clase. Clasele abstracte sunt clase care servescca superclase pentru clasele
concrete care se vor deriva din aceasta. Dintr-o clasa abstracta nu se pot crea instante.
Modificatori pentru metode:

static
abstract
final
native
synchronized

Metodele statice apartin claselor (metode de tip clasa) si nu instantelor.Ele pot fi


invocate fara existenta instantelor, deci nu trebuie createobiecte din clasa respectiva ca
se le putem utiliza aceste metode. Metodelede conversie de la un tip de data la un alt
tip de data sunt implementateca metode statice ale unor clase. Exemplu:
clasa Integer are o metodatoString(int ) care este definita ca o metoda statica. Aceste
metode se apeleazain modul urmator:
nume_clasa.nume_metoda(listaparametrilor actuali)
Exemplu concret:
int i;
System.out.println(Integer.toString(i));
Metodele statice pot utiliza doar membrii statici ai clasei, ei nupot apela metode
nestatice si nu pot utiliza variabile nestatice. Dacaam dori sa contorizam numarul de
instante create dintr-o anumita clasaam putea avea urmatoarea declaratie:
class OClasa {
static final numar_instante=0;
public static incrementare(){
numar_instante++;
}
public static get_numar_instante(){
return numar_instante;
}
public OClasa(){
incrementare();
}
}
public class Control{
public static void main( String args[]){
System.out.println("Nr.instante:
"+Integer.toString(OClasa.get_numar_instante()));
OClasa v[]= new OClasa[5];
for( int i=0; i<5; i++){
v[i]=new OClasa();
System.out.println("Nr. instante:"
+Integer.toString(OClasa.get_numar_instante()));

}
}
}

Metodele abstracte in Java sunt metode fara corp de implementare.Ele sunt declarate
pentru a forta subclasele care vor sa aiba instantesa implementeze metodele
respective. Metodele abstracte se declara doarin clase abstracte. Clasele derivate din
clase abstracte care nu sunt declarateabstracte trebuie sa implementeze metodele
abstracte ale superclaselor.Metodele statice nu pot fi declarate si abstracte, deoarece o
metoda staticaeste si implicit metoda finala si nu poate fi rescrisa.
Metodele finale sunt metode care nu pot fi redefinite in subclaseleclasei in care au fost
declarate. Declararea metodelor cu clauza finaleste utila in primul rand pentru
compilator, care poate sa faca legarestatica in cazul acestor metode astfel crescand
viteza de executie a programelorJava.
Metodele native sunt metode implementate intr-un alt limbaj deprogramare de obicei
intr-un limaj nativ al platformei (C, C++ sau asamblare).Metodele native nu au corp
de implementare, ele fiind implementate intr-unalt limbaj de programare. Aceste
metode se comporta la fel ca toate celelaltemetode Java, pot fi mostenite, redefinite
etc.
Metodele sincronizate sunt utilizate pentru accesul unor resursecritice. In momentul
apelarii unei asemenea metode, resursei i se alocaun monitor, care blocheaza accesul
altor metode la aceea resursa. Dupaterminarea apelului se elibereaza monitorul acesta
putand fi ocupat dealte metode sincronizate.
Modificatori pentru variabile

static
final
transient
volatile

Modificatorul static specifica ca variabila respectiva apartineclasei si nu ale


instantelor si exista intr-un singur exemplar. Toate instantele lucreaza cu aceeasi
valoare. Daca o instanta modifica valoarea variabilei statice, atunci aceasta modificare
este vazuta si de celelalte instante.Variabilele statice sunt initializate la incarcarea
clasei si vor fi utilizatede catre metodele statice ale clasei. Vezi exemplul de la metode
statice.

Modificatorul final se utilizeaza pentru declararea unor constante,deci variabile ale


caror valori nu se modifica pe parcursul executiei.Tocmai din aceasta cauza
variabilele finale se initializeaza la declarare:finalint numar = 10;
Modificatorul transient se utilizeaza in cazul obiectelor persistente pentru a marca
datele care nu trebuie sa se piarda la terminarea programului.
Modificatorul volatile specifica faptul ca variabila respectivapoate fi modificata
asincron cu rularea aplicatiei. Prin acest modificatorfortam masina vituala Java ca
dupa modificarea variabilei sa scrie valoareainapoi in memorie si operatie de citire se
face tot din memorie., adicavariabila nu se poate stoca in cache sau in registrii masinii
virtuale.Singura problema cu acest modificator este ca in versiunea actuala incanu este
implementata, deci daca dorim sa protejam valoarea unei variabilela care au acces mai
multe fire de executie, atunci utilizam mecanismulde sincronizare.

5. Instantele predefinitethissi super


this este o referinta catre instanta curenta
super este o referinta la superclasa
Un exemplu de utilizare:
class Unu{
String sir;
public Unu( String sir ){
this.sir = sir;
}
}
class Doi extends Unu{
int val;
public Doi( String sir, int val ){
super(sir); //apel constructor superclasa
this.val = val;
}
public Doi( String sir, String altsir){
super(sir);
this.val = ( new Integer(altsir ) ).intValue();
}
}

Crearea interfetelor grafice. Pachetul


java.awt

1.
2.
3.
4.
5.
6.
7.

Introducere
Componente grafice
Ierarhia claselor pentru componente
Obiecte peer
Conceptul Model/View/Controller (MVC)
Afisarea componentelor
Organizarea componentelor

Introducere
Acest pachet ne ofera o coletie de clase pentru crearea interfetelor grafice. Aceste
clase permit lucrul cu ferestre, desenari, lucrul cu imagini si utilizarea componentelor
ca butoane, liste, meniuri intr-un mod independent de platforma. Pachetul java.awt
contine clasele AWT (Abstract Window Toolkit) GUI iar java.awt.image ne ofera
niste facilitati in plus pentru lucrul cu imagini. Dupa cum numele sugereaza AWT este
o abstractie. Clasele si functionalitatile oferite sunt aceleasi pentru orice implementare
Java. Pentru a obtine independenta de platforma AWT utilizeaza toolkituri
interschimbabile care actioneaza cu sistemul de ferestre pe care se ruleaza aplicatia.
De exemplu sa presupunem ca aplicatia noastra creaza un buton. Cand se ruleaza
aplicatia, toolkitul specific platformei afiseaza butonul conform platformei. Daca
aplicatia se ruleaza sub Windows vom obtine un buton de tip Windows, iar daca se
ruleaza sub Unix se va afisa un buton de tip X Windows.
Utilizarea componentelor din acest pachet este relativ usoara, pe cand toolkiturile
GUI sunt foarte complexe, dar aceasta este treaba celor care vor sa implementeze
AWT-ul pe o noua platforma.
Realitatea este ca cele mai multe probleme despre Java se ridica la folosirea acestui
pachet. Implementarea toolkiturilor pentru acest pachet contin cele mai multe buguri
Java. Tocmai din aceasta cauza JavaSoft a introdus Swing care reprezinta noua
generatie de componentele grafice si fac parte din JFC (Java Foundation Classes).
Componente grafice
Componentele sunt elementele care se utilizeaza la crearea unei interfete grafice.
Componentele sunt incluse in containere, care la randul lor sunt componente speciale.
Anumite componente pot fi containere pentru alte componente: de exemplu o
fereastra cu doua panouri. In acest caz fereastra este containerul, iar panelele sunt
componentele continute. Daca adaugam elemente ca butoane, liste, etichete, casete
text etc. in cele doua panouri atunci panoul va fi containerul iar elementele adaugate
vor fi componentele.

Ierarhia claselor pentru componente

Pentru simplitate impartim functionalitatea clasei Component in doua


categorii: modul de afisare si comportament. Aceasta clasa contine metode si
variabile care controleaza modul de afisare general al componentei. Aici sunt incluse
atributele pentru vizibilitate, marime, pozitie si atribute ca culoarea si fontul. Clasa
contine metode abstracte, care sunt implementate de subclasele pentru diferite tipuri
de componente, si care determina imaginea grafica a componentei. Prin
comportamentul componentei intelegem actiunile componentei la evenimentele
primite de la utilizator. In momentul cand utilizatorul actiuneaza asupra unei
componente (de exemplu apsa butonul mouse-ului) un fir de executie AWT

informeaza toti receptorii (componentele care vor sa primeasca acest eveniment)


despre evenimentul produs. De exemplu la apasarea unui buton se genereaza
evenimentul ActionEvent. Cei care vor sa primeasca acest eveniment trebuie sa fie
inregistrati, aceasta insemnand ca trebuie sa fie obiecte care respecta
interfata ActionListener.
Evenimentele sunt receptionate de catre obiecte de tip Listener, care la primirea
evenimentului apeleaza o metoda de tratare a evenimetului. Obiectele care doresc sa
primeasca evenimente trebuie sa implementeze interfetele pentru tipurile de
evenimente pe care doresc sa le primeasca. De exemplu evenimentele de tip
MouseEvents sunt primite de catre obiectele care respecta interfata MouseListener.
Evenimentele reprezinta un mecanism de comunicare intre obiecte (nu numai obiecte
grafice). Evenimentele sunt importante mai alesin cazul beanurilor Java.
Containerele rezolva tratarea evenimentelor pentru toate componentele continute.
De obicei containerul se inregistreaza la sursa de evenimente pentru a primi
evenimentele necesare pentru o anumita componenta.
Peer
In sectiunea precedenta tocmai am descris functionarea acestor componente si
evenimentele cu ajutorul carora aceste componente comunica intre ele. Asa sunt
privite componentele de Java, dar nu si in lumea reala, adica pe platforma pe care vor
fi efectiv afisate componentele. Lumea reala este caracterizata de o anumita
arhitectura si de dispozitive fizice. La un anumit nivel obiectele noastre vor comunica
cu obiecte care contin metode native pentru mediul in caare componentele trebuie sa
interactioneze. Pentru a tine aceasta interactiune sub control Java utilizeaza
interfetele peer. Aceasta interfata peer face posibila ca o componenta AWT Java sa
utilizeze componenta corespunzatoare din lumea reala - obiectul peer din mediul
nativ. Programele noastre vor lucra cu obiectele AWT Java, restul, partea grea este
rezolvata de clasa Component.

Este important sa intelegem aceasta arhitectura deoarece astfel putem intelege cam
ce putem realiza cu componentele. In figura preceedenta se poate vedea ce se intampla
la crearea unui buton. Toolkitul este de fapt o "fabrica de componente" native. Java
utilizeaza aceasta fabrica pentru a separa funtionalitatea componentelor de
modalitatea de implementare pe un sistem de afisare nativ. Obiectul Toolkit contine
metode pentru crearea tuturor tipurilor de componente grafice. Daca nu ne place acest
Toolkit oferit de mediul Java, putem sa scriem toolkitul nostru propriu.
Pachetul java.awt.peer contine o interfata pentru fiecare tip de componenta grafica.
In acest pachet clasa de baza este ComponentPeer de la care se deriva aproape toate
celelalte clase. De exemplu clasei Button ii corespunde clasa ButtonPeer. Apelul
metodei setLabel() determina apelul metodei corespunzatoare al obiectului nativ.

Conceptul Model/View/Controller (MVC)


MVC este o metoda pentru producerea componentelor reutilizabile care sunt
caracterizate prin structura, reprezentare si comportament. MVC a fost introdus ca
standard in primul rand pentru componentele grafice, dar ideile de baza pot fi aplicate
si la alte tipuri de componente. Ideea fundamentala este separarea modelului de
reprezentare. Pentru un singur model de date exista mai multe reprezentari diferite. De
exemplu datelor dintr-un spreadsheet putem atasa diferite tipuri de grafice. In cazul
unei componente de tip Button modelul de date ar fi o valoare logica pentru a
reprezenta starea butonului, reprezentareaeste modul de afisare, aspectul grafic al
butonului, iar evenimentele reprezinta partea de control.
Comunicarea intre componentele grafice AWT respecta MVC. Receptorii
evenimentelor sunt Observatori iar sursele evenimentelor Observabili. In momentul
cand un obiect Observabil isi modifica starea informeaza toti observatorii despre
aceasta modificare.
Conceptul "fabrica de componente" utilizat de catre obiectul Toolkit respecta tot
MVC. Aceste "fabrici" utilizeaza interfetele Java pentru a separa implementarea

obiectelor grafice de comportamentul acestora. Componetele native trebuie sa


respecte doar anumite interfete, nu trebuie sa se incadreze intr-o ierarhie de clase.
Singurul lucru pe care trebuie sa-l faca este implementarea metodelor din interfata.
Afisarea componentelor
Componetele pot fi rugate sa se autoafiseze. De exemplu daca fereastra care contine
componentele este acoperita de o alta fereastra, in momentul revenirii la fereastra
initiala aceasta trebuie reafisata cel putin partial. Cand AWT roaga componenta sa se
autoafiseze, aceasta apeleaza metoda paint(). Metoda update() are aceasi
functionalitae, dar aceasta prima data sterge suprafata componentei si dupa aceea
apeleaz metoda paint(). Componentele nu vor apela direct update(), aceasta metoda
fiind apelata de catre repaint(). Aceasta metoda roaga AWT sa programeze
componenta in cauza pentru improspatare. Atat paint() cat si update() au un parametru
de tip Graphics care reprezinta contextul grafic a componentei in cauza. Corespunde
suprafetei ecran pe care componenta poate desena. Acesta este mecanismul utilizat de
componente pentru autoafisare. Noi vom utiliza aceste metode doar in cazul
containerelor speciale, adica in cazul obiectelor de tip Panel, Canvas si Applet.
Organizarea componentelor
Un organizator al componentelor este un obiect care stabileste marimea si pozitia
componentelor in cadrul unui container. Fiecare container are un organizator implicit
care in caz de necesitate poate fi modificat. Containerele principale sunt diferitele
tipuri de ferestre, apleturi, panele etc. In cazul ferestrelor organizatorul implicit este
un obiect de tip BorderLayout, iar in cazul apleturilor si ale panourilor unul de tip
FlowLayout. Clasele principale organizatori de componente sunt: FlowLayot,
GridLayout,CardLayout, BorderLayout si GridBagLayout.

FlowLayout organizeaza componentele de la stanga la dreapta si daca se umple


randul curent atunci componetul urmator va fi plasat in randul urmator. Inaltimea
randului este data de componenta de cea mai mare inaltime pe randul respectiv.
FlowLayout fLayout = new FlowLayout();
setLayout( fLayout );
Button butonOk = new Button("Ok");
add(butonOk);
Button butonCancel = new Button("Cancel");
add(butonCancel);

sau scris mai compact:


setLayout( new FlowLayout());
add( new Button("Ok"));
add( new Button("Cancel"));

Organizatorul centreaza componentele adaugate, dar acest tip de aliniere poate fi


schimbata prin metoda setAlignment(). Metoda primeste ca parametru tipul alinierii.
Tipurile de aliniere posibile sunt definite ca constante in clasa FlowLayout (LEFT,
RIGHT, CENTER) si se utilizeaza in modul urmator:
FlowLayout fLayout = new FlowLayout();
fLayout.setAlignment(FlowLayout.LEFT)
setLayout( fLayout );

BorderLayout aranjeaza componentele in cinci regiuni: Nord, Sud, Vest, Est si


Centru. La adaugarea componentelor utilizand acest organizator trebuie specificat pe
langa componenta adaugata si regiunea la care se adauga. Atat BorderLayout cat si
CardLayout permite specificarea spatiului intre componente indicand numarul de
pixeli pe orizontala respectiv pe verticala.
setLayout( new BorderLayout(), 10,6);
add( new Button("Unu"),"North");
add( new Button("Doi"),"East");
add( new Button("Trei"),"South");
add( new Button("Patru"),"West");

CardLayout (teanc de carti) se utilizeaza la organizarea componentelor care nu incap


pe o anumita suprafata. Componentele sunt organizate pe aceste carti dintre care unul
singurul se va vedea pe ecran. Visual Caffe introduce ferestrele cu mai multe pagini
care pot inlocui acest organizator.
GridLayout imparte suprafata in randuri si coloane permitand aranjarea
componentelor in aceste celule de dimensiuni egale. Componentele sunt plasate in
celule incepand cu primul rand dupa aceea urmatorul rand si asa mai departe.
GridBagLayout este organizatorul cel mai avansat. Lucreaza asemanator ca
GridLayout. Principala diferenta fata de acesta este ca in caul acestui organizator o
componenta poate ocupa mai mult decat o singura celula.
Un container poate sa contina la randul lui alte containere si fiecare dinntre aceste
containere avand propriul organizator. De exemplu o fereastra continand mai multe
panele.

Fire de executie
Ce sunt firele de excutie si de ce avem nevoie de fire de
executie?
Utilizarea firelor de executie in Java
1. Creare si lansare
2. Legarea firelor de executie

3.
4.
5.
6.
7.
8.
9.

Fire de executie demon


Grupe de fire de executie
Starile unui fir de executie
Prioritatea firelor de executie
Sincronizarea firelor de executie
Problema producatorului si a consumatorului
Exemple

Ce sunt firele de executie?


O aplicatie Java ruleaza in interiorul unui proces al sistemului de operare. Procesul
consta in segmente de cod si segmente de date mapate intr-un spatiu virtual de
adresare. Fiecare proces detine un numar de resurse alocate de catre sistemul de
operare, cum ar fi fisiere deschise, zone de memorie alocate dinamic sau fire de
executie. Resursele alocate procesului sunt eliberate la terminarea executiei
procesului.
Un fir de executie este unitatea de executie a unui proces. Fiecarui fir de executie i se
asociaza o secventa de instructiuni, un set de registri CPU si o stiva. Procesul nu
executa instructiuni, este un spatiu de adresare comun pentru unul sau mai multe fire
de executie. Firele de executie sunt cele care executa instructiunile.
Firele de executie seamana cu procesele, pot fi la fel planificate pentru executie.
Principala diferenta este ca firul se executa in spatiul de adresare al procesului caruia
apartine si poate modifica valori care sunt vazute si de celelalte fire care apartin
aceluiasi proces. Din aceasta cauza apare necesitatea ca firele sa comunice intre ele,
adica trebuie sincronizat accesul la datele utilizate in comun. Sincronizarea asigura
siguranta datelor, adica prin sincronizare se previn situatile ca un fir sa modifice o
variabila care este tocmai utilazata de catre un alt fir de executie.

Fir de executie = Secventa de instructiuni + un set de registi


CPU + o stiva
Java fiind un limbaj interpretat, procesul detine codul interpretorului, iar codul binar
Java (bytecode) este tratat ca o zona de date de catre interpretor. Deci firele de excutie
sunt create de fapt de catre interpretorul Java. La lansarea in executie a unei aplicatii
Java este creat si automat un prim fir de executie, numit firul principal. Acesta poate
sa creeze alte fire de executie, care la randul lor pot crea alte fire, si asa mai departe.
De ce avem nevoie de fire de executie?

Aplicatiile care utilizeaza mai multe fire de executie pot executa in paralel mai multe
sarcini. De exemplu o aplicatie care realizeaza o animatie intr-o fereastra, iar intr-o
alta fereastra afiseaza rezultatul unei interogari de baza de date.
Un program de navigare realizeaza cel putin doua lucruri in paralel: aduce date din
retea si paralel afiseaza aceste date. Firele de executie faciliteaza ca programarea sa
fie mai apropiata de gandirea umana. Omul de obicei se ocupa de mai multe lucruri in
acelasi timp. Un profesor in timp ce preda trebuie sa fie atent si la studentii care il
asculta.
Firele de executie Java ofera o serie de facilitati programatorilor, dar exista si o serie
de diferente fata de alte pachete pentru fire de executie. Comparand cu aceste pachete
putem considera ca ne ofera mai putin, dar au si un avantaj, simplitatea. Exista si un
standard POSIX P10033.4a un pachet de fire de excutie, care poate fi implementat in
orice sistem de operare.
Orice pachet Java (de la Sun) este "Thread safe", adica este asigurat ca metodele
continute in pachet pot fi apelate simultan de mai multe fire de executie.

Utilizarea firelor de executie in Java


1. Creare si lansare
In Java avem doua posibilitati de a crea un fir de executie:
Prin definirea unei clase care mosteneste de la clasa predefinita Thread (deriva din
clasa Thread)
Prin implementarea interfetei Runnable
Clasa Thread este definita in pachetul java.lang avand o serie de metode. Principala
metoda este metoda run(). Aceasta trebuie sa contina toate activitatile pe care firul
trebuie sa le execute.
public class Thread extends Object implements Runnable

Clasa Thread este o clasa care are ca si superclasa clasa Object si implementeaza
interfata Runnable. Interfata Runnable declara o singura metoda run() si clasa Thread
implementeaza aceasta. Masina virtuala Java permite unei aplicatii sa ruleze mai
multe fire de executie in paralel. Fiecare fir de executie are o prioritate si fiecare fir
poate fi marcat ca si fir demon. In momentul crearii unui fir de executie se seteaza si
proprietatile acestea, adica firul nou creat va avea aceasi prioritate ca si firul parinte si
va fi de tip demon numai daca firul parinte este demon.
Cand se interpreteaza codul octeti al unei aplicatii, masina virtuala Java creaza un

prim fir de executie care ruleaza metoda main. Masina virtuala Java continua sa
execute acest fir sau alte fire noi create pana cand toate firele de executie nedemon
sunt distruse.

Thread
start()
run()
sleep()
interrupt()
join()
getName()
setName()
destroy()
isinterrupted()

Metoda start() este utilizata pentru lansarea in executie a unui fir nou creat. Metoda
start() se utilizeaza o singura data in ciclul de viata al unui fir . Firul se distruge cu
metoda destroy(), si aceasta putand fi apelat o singura data. Metoda sleep() se
apeleaza cu un argument care reprezinta timpul in milisecunde in care firul de
executie asteapta(adoarme). sleep() este o metoda statica se apeleaza prefixat cu
numele clasei. In caz ca firul este intrerupt se genereaza
exceptia InterruptedException. Deci apelul metodei trebuie facut intr-un context de
tratarea acestei exceptii.
try{
Thread.sleep( 1000 )
}
catch ( InterruptedException e ){
//Codul de tratarea a exceptiei
}

Firul poate fi scos din starea de adormire prin apelul metodei interrupt(). Metoda se
mai apeleaza pentru a intrerupe executia unui fir care este blocat in asteptarea unei
operatii lungi de intrare/iesire. Metodajoin() se utilizeza pentru legarea firelor de
executie. Prin getName() si setName() putem obtine sau sa setam numele firului.
Diagrama de clase:

Diagrama de colaborare:

Figura precedenta prezinta proiectul unei aplicatii, care creaza doua fire de executie si
le starteaza, neasteptand terminarea acestora. Firele vor afisa numele lor pana cand
sunt oprite. Firele pot fi oprite cu combinatia de taste Ctrl-C.
Crearea unui obiect din clasa MyThread nu inseamna si inceperea executiei firului
creat. Firul poate fi lansat in executie prin apelul metodei start().
Metoda start() apeleaza metoda run(), care executa instructiunile proprii firului.
Sursa Java pentru exemplul precedent:
//Source file: MyThread.java
public class MyThread extends Thread
{
public MyThread()
{
}
public void run()
{
while( true )
try{

System.out.println(" Se ruleaza "+getName());


sleep( 1000 );
}
catch( InterruptedException e ){}
}
public MyThread(String name)
{
super( name );
}
}
//Source file: Control.java
public class Control
{
public MyThread threads[];
public Control()
{
threads = new MyThread[ 2 ];
threads[ 0 ] = new MyThread( "Fir 1");
threads[ 1 ] = new MyThread( "Fir 2");
threads[ 0 ].start();
threads[ 1 ].start();
}
public static void main(String[] args)
{
Control c = new Control();
}
}

A doua modalitate de crearea unui fir de executie se utilizeaza cand clasa noua creata
trebuie sa mosteneasca de la doua clase. Deoarece Java nu permite mostenire multipla,
se incearca simularea acestuia prin interfete. Interfata este o declaratie care contine o
serie de metode abstracte care trebuie implementate de catre clasa care implementeaza
interfata.
Interfata Runnable este:
public interface Runnable{
public abstract void run();
}

In acest caz, clasa noua nu mosteneste metodele clasei Thread (start(), stop() etc. )
deci crearea firului se va face prin crearea unui obiect de tip Thread care primeste ca
parametru un obiect de tip Runnable. (Clasa Thread are si un asemenea constructor).
Diagrama de clase:

Diagrama de colaborare:

Sursa Java:
//Source file: Control.java
public class Control
{
public MyRunnable objects[];
public Thread threads[];
public Control()
{
objects = new MyRunnable[ 2 ];
objects[ 0 ] = new MyRunnable();
objects[ 1 ] = new MyRunnable();
threads = new Thread[ 2 ];
threads[ 0 ] = new Thread(objects[ 0 ]);
threads[ 1 ] = new Thread(objects[ 1 ]);
threads[ 0 ].start( );
threads[ 1 ].start( );
}

public static void main(String[] args)


{
Control c = new Control();
}
}

//Source file: MyRunnable.java

public class MyRunnable implements Runnable


{
public MyRunnable()
{
}
public void run()
{
while( true )
{
System.out.println( "Se ruleaza "+(Thread.currentThread()).getName() );
try{
Thread.sleep( 1000 );
}
catch( InterruptedException e ){}
}
}
}

2. Legarea firelor de executie


Legarea firelor de executie permite unui fir sa astepte ca un alt fir sa-si termine
executia. De exemplu un fir trebuie sa utilizeze date care sunt calculate de un alt fir de
executie, atunci in momentul cand are nevoie de aceste date isi intrerupe executia
asteptand firul care ii va furniza acestea. Pentru legarea firelor se utilizeaza metoda
join(). Metoda are doua forma de apel:

parametrul reprezinta timpul de asteptare (in


milisecunde), adica cat se asteapta pentru terminarea firului,
join() se asteapta terminarea firului indiferent cat trebuie asteptat
join( int timp )

Exemplul urmator creaza doua fire de excutie. Unul dintre fire afiseaza un text si
asteapta 500 de milisecunde de cinci ori. Celalalt fir isi afiseaza numele dupa care
asteapta pe celalalt fir ca acesta sa-si termine executia.

Diagrama de secventiere:

Sursa Java:
//Source file: MyThread1.java
public class MyThread1 extends Thread
{
public MyThread1(String name)
{
super( name);
}
public void run()
{
System.out.println(getName() + "is running");
for(int i=0;i<5;i++){
try{
sleep( 500 )

}
catch( InterruptedException e ){}
System.out.println(getName()+" writes "+Integer.toString(i));
}
}
}
//Source file: MyThread2.java
public class MyThread2 extends Thread
{
public MyThread1 waitedThread;

public MyThread2(String name, MyThread1 waitedThread)


{
super( name );
this.waitedThread = waitedThread;
}
public void run()
{
System.out.println(getName()+" waits for Thread
"+waitedThread.getName());
try{
waitedThread.join();
}

catch( InterruptedException e ){}


System.out.println(waitedThread.getName()+" has been finished");
System.out.println(getName()+" has been finished");
}
}
//Source file: Control.java
public class Control
{
public static void main(java.lang.String args[])
{
MyThread1 thread1 = new MyThread1("First Thread");
MyThread2 thread2 = new MyThread2("Second Thread",thread1);
thread1.start();
thread2.start();
}
}

3. Fire de executie demoni


Caracteristici:
Sunt fire speciale similare cu procesele demoni.
Realizeaza anumite activitati in fundal (background)
Se distrug automat la terminarea celorlaltor fire de executie.
Au prioritate de executie redusa, fiind planificate la CPU cand acesta nu ruleaza
alte fire
Colectarea gunoiul in Java se relueza pe un fir demon. Firul poate fi transformat in fir
demon prin apelul metodei setDaemon().
Exemplul urmator ar trebui sa ne arate ca firele demoni sunt planificate pentru
executie mai rar decat cele normale.
class MyThread extends Thread{
public MyThread( String name, boolean is_Daemon ){
super(name);
setDaemon(is_Daemon);
}
public void run(){
for(int i=0;i<5;i++){
try{
sleep( 500 ) ;

}
catch( InterruptedException e ){}
System.out.println(getName() + "se ruleaza");
}
}
}
public class Control{
public static void main( String args[] )
{
MyThread t1,t2;
t1 = new MyThread("Normal", false );
t2 = new MyThread("Demon ", true

);

t1.start();
t2.start();
}
}

4. Grupe de fire de executie


La crearea unui fir nou de executie, firul nou creat putem sa-l adaugam la un grup de
fire de executie existent, sau putem lasa in seama interpretorului Java la care grup sa-l
adauge.
In exemplul demonstrativ vom utiliza metoda yield() pentru a ceda unitatea centrala
altui fir de executie ( astfel firul care cedeaza trece in coada de asteptarea a firelor gata
de executie ).
class MyThread extends Thread{
MyThread( String nume ){
super( nume );
}
public void run(){
while( true ){
if (isInterrupted() )
break;
yield();
}
}
}

public class Control{


static public void main( String args[] ){
MyThread a, b, c;
ThreadGroup group;
// Obtinerea unei referinte la grup
group = Thread.currentThread().getThreadGroup();
System.out.println(" Nume grup: "+group.getName());
System.out.println(" Nr. fire active: "+group.activeCount());
a = new MyThread("Fir 1 ");
b = new MyThread("Fir 2 ");
c = new MyThread("Fir 3 ");
a.start(); b.start(); c.start();
System.out.println(" Nr. fire active: "+group.activeCount());
a.interrupt();
b.interrupt();
c.interrupt();
}
}

5. Starile unui fir de executie

Fir "rulabil" (Runnable): se ajunge in aceasta stare prin apelul metodei start(). Firul
trece in stare de "nerulabil" (Not Runnable) prin apelul metodei sleep() , wait() sau
daca firul se blocheaza intr-o operatie de citire. Dupa terminarea asteptarii firul revine
in starea "rulabil".

Firul ajunge in starea "mort", dupa ce se termina executia metodei run() sau daca se
apeleaza metoda destroy().
Firele sunt planificate pentru executie la fel ca si procesele, utilizand un algoritm
adecvat pentru planificarea lor. Daca masina virtuala se ruleaza pe un sistem de oprare
care lucreaza cu fire de executie, atunci s-ar putea ca fiecare fir de executie creat de
catre masina virtuala Java sa fie executat pe un fir nativ.
6. Prioritatea firelor de executie
Masina virtuala Java utilizeaza prioritatile firelor in planificarea firelor pentru
executie. In Java sunt 10 niveluri de prioritate. Avem si trei constante in clasa Thread
ce pot fi utilizate:
Thread.MIN_PRIORITY avand valoarea 1
Thread.MAX_PRIORITY avand valoarea 10
Thread.NORM_PRIORITY avand valoarea 5
Prioritatea firului se seteaza cu metoda setPriority()
7. Sincronizarea firelor de executie.
Fiecare fir de executie are o viata proprie si nu este interesat de ceea ce fac celelalte
fire de executie. Daca calculatorul este dotat cu mai multe procesoare, atunci diferitele
fire de executie ale aceluiasi proces pot fi planificate pentru executie pe diferite
procesoare. Pentru cel care proiecteaza aplicatia, acest lucru este nesemnificativ,
deoarece toate aceste lucruri cad in sarcina masinii virtuale si nu in sarcina
programatorului. Totusi apare o problema in cazul aplicatiilor care se ruleaza pe mai
multe fire si anume accesul resurselor comune. Ca sa nu apara probleme, accesul la
resursele utilizate in comun trebuie sincronizat. Sincronizarea se bazeaza pe conceptul
de monitor introdus de catre C.A. Hoare. Un monitor este de fapt un lacat atasat unei
resurse pentru a preveni utilizarea resursei in paralel.
Un fir de executie ocupa un monitor daca apeleaza o metoda sincronizata. Daca un
fir ocupa un monitor, un alt fir care incearca ocuparea aceluiasi monitor, este blocat si
asteapta pana la eliberarea monitorului.
Oricare obiect, care contine unul sau mai multe metode sincronizate, are si un monitor
atasat. Metodele sincronizate se definesc in modul urmator:
public synchronized void my_method() {...}

Orice clasa Java are un monitor atasat. Acest monitor se deosebeste de monitoarele
atasate obiectelor, se utilizeaza cand se apeleaza metodele statice sincronizate ale
clasei.
public static synchronized void my_static_method() {...}

wait() si notify()
Cu ajutorul cuvantului-cheie synchronized putem serializa executia anumitor
metode. Metodele wait() si notify() ale clasei Object extind aceasta
capabilitate. Utilizand wait() si notify(), un fir de executie poate elibera
monitorul ocupat, asteptand un semnal pentru reocuparea acestuia. Metodele pot fi
utilizate doar in metode sincronizate sau in blocuri de instructiuni sincronizate.
Executandwait() intr-un bloc sincronizat, firul elibereaza monitorul si adoarme. De
obicei firul recurge la aceasta posibilitate cand trebuie sa astepte aparitia unui
eveniment intr-o alta parte a aplicatiei. Mai tarziu, cand apare evenimentul, firul, in
care a aparut evenimentul, apeleaza notify() pentru a trezi firul adormit. Firul
trezit ocupa din nou monitorul si isi continua activitatea din punctul de intrerupere.
class MyClass{
public synchronized void method1(){}
public synchronized void method2(){}
public static synchronized void method3(){}
}
...
MyClass object1 = new MyClass(); // Se ataseaza un monitor obiect pentru
sincronizarea accesului la metodele method1() si method2() pentru firele de
executie al obiectului object1
MyClass object2 = new MyClass(); // Se ataseaza un monitor obiect pentru
sincronizarea accesului la metodele method1() si method2() pentru firele de
executie al obiectului object2

Pentru exemplul precedent se vor crea trei monitoare. Un monitor de clasa, care este
responsabil pentru sincronizarea accesului la metoda statica ( metoda clasei)
method3() si doua monitoare obiect, cate unul pentru fiecare obiect declarat pentru
sincronizarea accesului la method1(0 si method2()
Metoda notify() anunta intotdeauna un singur fir de executie care asteapta pentru a
accesa monitorul. Exista si o alta metoda notifyAll() care se utilizeaza atunci cand mai
multe fire de executie concureaza pentru acelasi monitor. In acest caz fiecare fir este
instiintat si ele vor concura pentru obtinerea monitorului.
Metodele wait(), notify() si notifyAll() se utilizeaza doar in metode sincronizate, altfel

mediul de executi arunca exceptia IllegalMonitorStateException. Exemplul urmator se


compileaza fara erori, dar se arunca aceasta exceptie pe parcursul executiei.
public class test{
public test(){
try{
wait();
}
catch( InterruptedException e ){}
}
public static void main( String args[] ){
test t = new test();
}
}

8. Problema producatorului si a consumatorului


Specificatia problemei
Intr-un birou lucreaza mai multi functionari, fiecare elaborand documente pe cate un
calculator legate intr-o retea. La aceeasi retea sunt legate si cateva imprimante, fiecare
avand acces la toate imprimantele conectate. Sa se simuleze functionarea biroului
stiind ca nu toti functionarii elaboreaza documentele in acelasi ritm si functionarii
selecteaza aleator imprimantele pe care vor tipari documentele.
Rezolvarea problemei
Perspectiva conceptuala

Se vede clar ca problema se reduce la celebra problema a producatorului si a


consumatorului, in acest caz avand mai multi
producatori si mai multi consumatori. Fiecare functionar poate fi privit ca un
producator si fiecare imprimanta ca un consumator.
Fiecare imprimanta are atasat o coada de asteptare (buffer) unde sunt gestionate
documentele inainte de a fi tiparite.
Trecem la identificarea obiectelor (claselor). Principalele clase vor fi urmatoarele:

Producer (Functionar)
Consumer (Imprimanta)

Buffer (Coada de asteptare a imprimantei)

Pentru a simula paralelismul vom lucra cu fire de executie, adica fiecare functionar si
imprimanta va fi implementat ca un fir de
executie. Evident apare si problema sincronizarii la cozile de asteptare atasate
imprimantelor.

Figura de mai sus este diagrama de clasa din perspectiva conceptuala.


Clasele Producer si Consumer sunt derivate din clasa Thread (fir de executie).
Intre Producer si Buffer avem o asociere unidirectionala, numai Producer cunoaste
Buffer si multiplicitatea asocierii este 1:n,
adica un obiect producator cunoaste n cozi de asteptare.
Intre Consumer si Buffer exista tot o asociere unidirectionala, imprimanta cunascand
coada de asteptare, dar aici multiplicitatea
asocierii este 1:1 insemnand ca o imprimanta are atasata o singura coada de asteptare.
Perspectiva specificatiei

Continuam cu descrierea acestor clase, adica a atributelor si metodelor principale ale


acestora.
Clasa Buffer
Atribute: Aceasta clasa trebuie sa aiba un atribut dimensiune prin care specificam
dimensiunea maxima a unui buffer si inca un
alt atribut de tip colectie pentru a permite stocarea produselor.
Metode: Avem nevoie de doua metode, una care adauga un produs la sfarsitul cozii de
asteptare si inca una care scoate
primul produs din coada de asteptare.
Clasa Producer
In cazul acestei clase nu avem nevoie de atribute, doar de cele care se nasc in urma
asocierilor. Clasa va avea un constructor
care initializeaza numele firului de executie (atribut mostenit de la clasa parinte
Thread) si atributul theBuffer creat in urma
asocierii cu clasa Buffer. Acest atribut este unul de tip array. Ca sa putem initializa
acest atribut, trebuie sa avem create in
prealabil obiectele de tip Buffer.

Clasa Consumer
Clasa va avea un constructor care initializeaza numele firului de executie (atribut
mostenit de la clasa parinte Thread) si atributul
theBuffer creat in urma asocierii cu clasa Buffer. Acest atribut este un atribut simplu,
dar ca sa-l putem initializa, trebuie sa avem
create in prealabil obiectele de tip Buffer si atunci fiecarui obiect Buffer ii corespunde
un obiect de tip Consumer.
Introducem si o clasa Product pentru identificarea documentelor produse. Fiecare
document va avea un nume, deci clasa
trebuie sa aiba un atribut tip sir de caractere reprezentand numele produsului. Acest
atribut va fi initializat cu constructorul clasei
si adaugam o metoda de tip query pentru returnarea acestui atribut.
Pentru numerotarea documentelor vom introduce si o clasa Counter. La pornirea
aplicatiei se creaza o singura instanta din
aceasta clasa si toti producatorii o vor folosi. Clasa va avea un atribut value de tip
intreg lung si o operatie next, pentru
returnarea urmatoarei valori a numaratorului.

Perspectiva de implementare
La diagrama din sectiunea precedenta vom adauga inca o clasa Control. Aceasta clasa
va avea cate o asociere cu calsele
Producer, Consumer si Buffer. Multiplicitatea acestor asocieri se vede pe diagrama
alaturata. Constructorul clasei face
instantierile obiectelor Buffer, Producer, Consumer. Fiecare asociere are
multiplicitatea 1:n, un singur obiect de tip control si
mai multi bufferi, producatori si consumatori. Trebuie sa vaem grija ca numarul
bufferelor sa corespunda cu numarul
imprimantelor.

Codul final:
//Source file: Control.java

public class Control


{
private Producer theProducer[];
private Consumer theConsumer[];
private Buffer theBuffer[];
public Control()
{
}
public Control(int np, int nc)
{
int i;
theProducer = new Producer[ np ];
theBuffer
= new Buffer [ nc ];
theConsumer = new Consumer[ nc ];

for( i=0; i<nc; i++ )


theBuffer[ i ] = new Buffer( 3 );
for( i=0; i<np; i++ ){
theProducer[ i ] = new Producer( theBuffer , "Producer.
"+Integer.toString( i+1 ));
theProducer[ i ].start();
}
for( i=0; i<nc; i++ ){
theConsumer[ i ] = new Consumer( theBuffer[ i ], "Consumer. "+
Integer.toString( i+1 ));
theConsumer[ i ].start();
}
}
public static void main(String[] args)
{
Control c = new Control(4,3);
}
}

//Source file: Producer.java

public class Producer extends Thread


{
private Buffer theBuffer[];

public void run()


{
try{
while( true ) {
Product p = new Product( Long.toString(Counter.next()) );
// Choose a buffer
int nr = ( int )Math.round( Math.random() * theBuffer.length );
if( nr >= theBuffer.length ) nr = theBuffer.length -nr;
System.out.println( getName() +":
"+p.getName()+"...."+Integer.toString( nr ));
theBuffer[ nr ].put( p );
sleep( Math.round( Math.random()*1000 ));

}
}
catch( InterruptedException e ){}
}

public Producer(Buffer[] buffer, String name)


{
super( name );
theBuffer = buffer;
}
}
//Source file: C:\Manyi\TempRose\Consumer.java

public class Consumer extends Thread


{
private Buffer theBuffer;
public Consumer()
{
}

public void run()


{
try{
while( true ) {
Product p= theBuffer.get();
System.out.println( getName()+" "+p.getName());
sleep(2000);
}
}
catch( InterruptedException e ) {}
}

public Consumer(Buffer buffer, String name)


{
super( name );
theBuffer = buffer;

}
}
//Source file: C:\Manyi\TempRose\Buffer.java
import java.util.Vector;
public class Buffer
{
private int maxBuffer;
private Vector buffer = new Vector();
public Buffer()
{
}
public synchronized void put(Product p) throws InterruptedException
{
while( buffer.size() == maxBuffer )
wait();
buffer.addElement( p );
notify();
}

public synchronized Product get() throws InterruptedException


{
while( buffer.size() == 0 )
wait();
Product p

= (Product) buffer.firstElement();

buffer.removeElement( p );
notify();
return p;
}
public Buffer(int maxBuffer)
{
this.maxBuffer = maxBuffer;
}
}

//Source file: Counter.java

public class Counter


{
private static long value = 0;
public Counter()
{
}
public static long next()
{
return value++;
}
}
//Source file: Product.java
public class Product
{
private String name;
public Product()
{
}
public Product(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
}

9. Exemple
9.1. 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 elibereaza biletele in acelasi ritm. Simulati
functionarea caselor de bilete.
Diagrama de clase
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
Integer.toString(m));

CASA "+

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();
}
}

Tratarea evenimentelor
1. Evenimente

2.
3.
4.
5.
6.
7.
8.

Receptorii evenimentelor, interfete Listener


Sursele evenimentelor
Livrarea evenimentelor
Evenimente AWT
java.awt.event.InputEvent
Clase Adapter
Exemple

1. Evenimente
Daca dorim sa scriem aplicatii bazate pe evenimente in Java trebuie sa utilizam
mecanismul de evenimente al limbajul. In Java componentele GUI comunica intre ele
cu ajutorul evenimentelor. Un eveniment este trimiterea unui mesaj. De exemplu un
buton informeaza aplicatia ca utilizatorul l-a apasat. Aceasta informare se realizeaza
cu ajutorul unui eveniment. Mesajele sosesc de la surse de evenimente iar destinatarii
acestor evenimente sunt receptionarii evenimentelor. La receptia evenimentului, in
obiectul receptor se executa o metoda. Evenimentul insusi este un obiect care contine
informatii in legatura cu evenimentul produs. De exemplu daca dorim sa cream
evenimente noi atunci va trebui sa extindem clasa java.util.EventObject. Toate tipurile
de evenimente create de catre utilizatori trebuie sa fie subclasele acestei clase.
public class KeyboardEvent extends java.util.EventObject{
private char key;
KeyboardEvent ( java.awt.Component source, char key){
super( source );
this.key = key;
}
}

Evenimentele sunt trimise de la o singura sursa si pot fi receptionate de mai multi


destinatari. Destinatarul (obiectul receptor) trebuie sa implementeze metode de
tratarea tuturor tipurilor de evenimente ai caror receptor poate fi.
Exemple de tipuri de evenimnete:
ActionEvent se genereaza la apasarea butoanelor, selectia din meniuri, terminarea
editarii unei casete text (apasarea tastei Enter in caseta).
MouseEvent se genereaza la operarea cu mouseul pe suprafata componenetei. Un
eveniment de tip ActionEvenet contine numele actiunii, iar un eveniment de tip
MouseEvent descrie pozitia mousului respectiv starea butoanelor.

2. Receptorii evenimentelor, interfete Listener

Un eveniment se livreaza destianatarului prin transmiterea ca parametru unei metode


de tratare a evenimentelor. Evenimentele de tip ActionEvent sunt livrate
metodelor actionPerformed() cu urmatoarea sintaxa:
//Receiver
public void actionPerformed(ActionEvent e){
...
}

Pentru fiecare tip de eveniment exista o interfata care trebuie implementata de catre
toti cei care doresc sa primeasca acel tip de eveniment. Orice obiect care doreste sa
primeasca evenimente de tip ActionEvent trebuie sa implementeze interfata
ActionListener.
public interface ActionListener extends java.util.EventListener{
public void actionPerformed( ActionEvent e );
}

Toate interfetele de tip "listener" sunt subinterfetele lui java.util.EventListener.


Aceasta din urma este o interfata vida. Interfetele ajuta la identificarea obiectelor
capabile de o primi anumite tipuri de evenimente. Interfata MouseListener descrie
metodele necesare primirii evenimentelor MouseEvent ( intrarea mouseului intr-o
zana sau iesirea dintr-o zona, apasarea sau eliberarea unui butom al mouseului.
MouseMotionListener este o interfata pentru a identifica evenimentele de tip
miscarea(move) sau tarairea (drag) mouseului.

3. Sursele evenimentelor
In sectiunea precedenta am descris mecanismul de primire a evenimentelor in partea
receptorului. In aceasta sectiune vom descrie cum atentioneaza receptorul sursele de
evenimente ca acestia sa porneasca trimiterea evenimentelor daca acestia apar. Pentru
a primi un eveniment un obiect receptor trebuie sa se inregistreze la sursa de
evenimente transmitand acestuia o referinta catre el. De exemplu clasa AWT Button
este o sursa de evenimente ActionEvent. Pentru a fi recptor al acestui eveniment codul
trebuie sa arate in modul urmator:
//sursa de eveniment de tip ActionEvent
Button buton = new Button("Ok");
//receptor de ActionEvenet
class Receptor implements ActionListener{

setupReceiver(){
...
buton.addActionLisener( this );
}
public void actionPerformed( ActionEvent e ){
// Ce sa se faca la apasarea butonului
}
}

Sursa de eveniment trebuie sa gestioneze toti receptorii, pentru acesta trebuie sa


implementeze doua metode:
//sursa de ActionEvent
public void addActionListener( Actionlistener listener ){
...
}
public void removeActionListener( ActionListener listener ){
...
}

Metoda a doua removeActionListenner() se utilizeaza in cazul cand un receptor actual


nu mai necesita serviciile oferite de sursa si in continuare nu mai doreste sa primeasca
evenimente.

4. Livrarea evenimentelor
Evenimentele AWT sunt difuzate, adica evenimentul are o singura sursa dar poate sa
aiba mai multi receptori. Evenimentele sunt difuzate utilizand modelul
observator/observabil. In momentul inregistrarii unui receptor la o sursa de
evenimente, sursa adauga referinta primita la o lista. Cand apare un eveniment
obiectul generat va fi livrat tuturor obiectelor din lista.

Nu se stie care dintre acesti receptori va fi primul caruia se livreaza evenimentul. De


altfel nu se ofera nici o garantie pentru cazurile in care un obiect receptor se
inregistreaza de mai multe ori.

5. Evenimente AWT
Toate evenimentele utilizate de componentele GUI al paachetului AWT sunt subclase
ale clasei java.awt.AWTEvent. Ierarhia acestor evenimente se prezinta in figura
urmatoare:

ComponentEvent este clasa de baza. Aceasta clasa include evenimente de tip


notificare in caz ca o componenta isi schimba dimensiunea sau vizibilitatea sau daca
se intampla evenimente cu mouseul sau tastatura care afecteaza componenta
respectiva. Apar evenimente ContainerEvent daca se adauga respectiv se sterg
componente dintr-un container.
Evenimente pentru componente si containere AWT

Eveniment

Cine produce?

Interfete Listener

ComponentEvent

Toate componentele

ComponentListener

Metode de tratare
componentResized()
componentMoved()
componentShown()
componentHidden()

FocusEvent

Toate componentele

FocusListener

KeyEvent

Toate componentele

KeyListener
MouseListener

MouseEvent

Toate componentele
MouseMotionListener

ContainerEvent

Toti containerii

ContainerListener

focusGained()
focusLost()
keyTyped()
keyPressed()
keyReleased()
mouseClicked()
mousePressed()
mouseReleased()
mouseEntered()
mouseExited()
mouseDragged()
mouseMoved()
componentAdded()
componentRemoved()

Evenimente specifice componentelor AWT

Eveniment
ActionEvent

ItemEvent

AdjustmentEvent
TextEvent

WindowEvent

Cine produce?
TextField
MenuItem
List
Button
List
CheckBox
Choice
CheckboxMenuItem
ScrollPane
Scrollbar
TextArea
TextField

Frame
Dialog

Interfete Listener

Metode de tratare

ActionListener

actionPerformed()

ItemListener

itemStateChanged()

AdjustmentListener

adjustmentValueChanged()

TextListener

textValueChanged()

WindowListener

windowOpened()
windowClosing()
windowClosed()
windowIconified()
windowDeiconified()
windowActivated()
windowDeactivated()

6. java.awt.event.InputEvent
MouseEvent si Keyevent sunt evenimente de tip InputEvent. Daca utilizatorul misca
mouseul sau apasa o tasta se genereaza evenimente de acest tip avand ca sursa

componenta pe suprafata caruia a avut loc evenimentul. Aceste evenimente si alte


cateva evenimente AWT sunt plasate intr-o coada de evenimente gestionata de catre
AWT. Deci AWT gestioneaza aceste evenimente si tot AWT este responsabil pentru
livrarea acestora catre receptori.
Clasa InputEvent defineste o serie de constante pentru a putea determina alte
informatii despre evenimentul produs. De exemplu daca este un eveniment cu
tastatura ne intereseaza daca concomitent cu o anumita tasta obisnuita s-a mai apasat
si o tasta de control Ctrl sau Alt, iar in cazul evenimentelor cu mouseul s-ar putea sa
ne intereseze si alte detalii, care dintre butoanele mouseului a fost apasat.
Lista constantelor definitae:
SHIFT_MASK
CTRL_MASK
META_MASK
ALT_MASK
BUTTON1_MASK
BUTTON2_MASK
BUTTON#_MASK

Pentru a verifica aceste lucruri se va utiliza metoda getModifiers() a


clasei InputEvent:

public void mousePressed( MouseEvent e){


int mods = e.getModifiers();
if( ( mods & InputEvent.SHIFT_MASK) != 0 ){
// SHIFT apasat
...
}
}

Evenimentele produse pot fi putin modificate inainte ca acestea sa ajunga la


receptorii lor. De exemplu caracterul apsat de utilizator poate fi schimbat cu una
dintre metodele: setKeyChar(), setKeyCode() sau setKeyModifiers(). Schimband
caracterul in evenument putem obtine ca pe ecran sa apara deja caracterul schimbat.
De exemplu in caz ca dorim ca in campuri text sa apara doar majuscule indiferent de
ce introduce utilizatorul atunci se aplica aceasta metoda.

7. Clase Adapter

Nu este o idee prea buna ca componentele unei aplicatii sa primeasca evenimentele in


direct. Cateodata nici nu este posibil. Consideram exemplul urmator pentru simularea
unui automat de bauturi. Automatul ne ofera trei sortimente: cafea, ceai si suc.
Proiectam pentru aceasta aplicatie o interfata grafica formata din trei butoane, cate un
buton pentru fiecare tip de bautura. In prima implementare obiectul nostru de
Bauturi_Adapter primeste evenimentele direct de la butoane. Problema este ca
obiectul trebuie sa stie mai mult decat servirea bauturilor, stie si faptul ca este utilizat
de trei butoane. Deci partea de GUI se suprapune cu logica aplicatiei.

O metoda mai buna este de a separa partea de GUI impreuna cu tratarea


evenimentelor de logica aplicatiei. Pentru a realiza aceasta separare vom utiliza clase
de tip adapter intre sursa si receptor . Un adaptor este un obiect care in functie de un
eveniment sosit apeleaza o anumita metoda. Implementarea primului adaptor ar fi:

class BauturiAdapter1 implements ActionListener{


Bauturi b;
BauturiAdapter1 ( Bauturi b ){
this.b =

b;

}
public void actionPerformed( ActionEvent e ){
b.Bautura_Cafea();

}
}

Clasa care implementeza interfata grafica ar trebui sa contina:

Bauturi b = ...;
Button buton_ceai, buton_cafea, buton_suc;
...
buton_ceai.addActionListener( new BauturiAdapter1(b));
buton_cafea.addActionListener( new BauturiAdapter2(b));
buton_suc.addActionListener( new BauturiAdapter3(b));

Astfel am separat logica aplicatiei de interfata la care este legata.

Multe din interfetele de tip Listener contin mai multe metode de tratarea
evenimentelor. Din nefericire acesta inseamna ca, clasa care este interesata in aceste
tipuri de evenimente trebuie sa implementeze toate metodele declarate in interfata.
Spre ajutorul programatorilor au fost create niste clase de tip Adapter care

implementeaza aceste metode. Deci daca avem nevoie de o anumita interfata, vom
deriva din aceasta clasa de tip Adapter implementat special pentru interfata dorita de
tip Listener. DE exemplu pentru evenimentele cu mouseul exista
clasa MouseAdapter care implementeza interfata MouseListener.
public void mouseClicked( MouseEvent e ) {};
public void mousePressed( MouseEvent e ){};
public void mouseReleased( MouseEvent e ) {};
public void mouseEntered( MouseEvent e ){};
public void mouseExited( MouseEvent e ) {};

Exemplu de utilizare:
oComponenta.addMouseListener( new MouseAdapter(){
public void MousePressed( MouseEvent e
){
obiect.show();
...
}
}
);

In constructia de mai sus am utilizat o clasa incuibata.

8. Exemple
Exemplu 1. Sa se scrie o aplicatie care afiseaza o fereastra avand o caseta text si trei
butoane avand etichetele 1,2,3. La apasarea butoanelor in caseta text sa apara eticheta
butonului apasat.
Diagrama de clasa:

import
import
import
import
import

java.awt.Frame;
java.awt.event.ActionListener;
java.awt.Button;
java.awt.TextField;
java.awt.event.ActionEvent;

public class MyFrame extends Frame implements ActionListener


{
private Button butoane[];
private TextField tf;
public MyFrame()
{
setLayout( new java.awt.FlowLayout());
tf = new TextField( 10 );
add( tf );
butoane = new Button[ 3 ];
for( int i = 0; i< butoane.length; i++ )
{
butoane[ i ] = new Button( Integer.toString( i ));
butoane[ i ].addActionListener( this );
add( butoane[ i ] );
}
// Tratarea evenimentelor cu fereastra
addWindowListener( new java.awt.event.WindowAdapter()
{
public void windowClosing( java.awt.event.WindowEvent
e ){
setVisible( false );
System.exit( 0 );

}
});
}
public void actionPerformed(ActionEvent arg0)
{
String s = arg0.getActionCommand();
tf.setText( s );
}
public static void main(String[] args)
{
MyFrame f = new MyFrame();
f.setBounds(1,1,200,100);
f.setVisible( true );
}
}

Exemplu 2. Sa se scrie o aplicatie care se ruleaza intr-o fereastra si la apasarea


mouseului in zona ferestrei sa apara o eticheta care sa contina coordonatele apasarii
mouseului.
Diagrama de clasa:

Sursa Java:
import java.awt.Frame;
import java.awt.Label;
public class MyFrame extends Frame
{
private Label label;

public MyFrame()
{
setLayout( new java.awt.FlowLayout() );
label = new Label(" ");
add( label );
// Inregistrarea ferestrei ca si receptor pentru evenimentele cu
mouse-ul
addMouseListener( new java.awt.event.MouseAdapter(){
public void mouseClicked( java.awt.event.MouseEvent e )
{
label.setText("("+Integer.toString(e.getX())+","+Integer.toSt
ring(e.getY())+")");
}
});
// Inregistrarea ferestrei ca si receptor pentru evenimnetele cu
fereastra
addWindowListener( new java.awt.event.WindowAdapter(){
public void windowClosing( java.awt.event.WindowEvent e ){
setVisible( false );
System.exit( 0 );
}
});
}
public static void main(String[] args)
{
MyFrame f = new MyFrame();
f.setBounds(1,1,300,300);
f.setVisible( true );
}
}

Exemplu 3. Sa se scrie o aplicatie care defineste o clasa Numarator care la


schimbarea valorii numaratorul genereaza un eveniment CounterEvent. Acest
eveniment va fi receptat de o clasa Receptor care la aparitia evenimentelor afiseaza
valoarea numaratorului.
Pentru orice eveniment nou se creaza o clasa derivata din clasa EventObject, iar
interfetele pentru receptionarea evenimentelor trebuie sa extinda clasa EventListener
din pachetul java.util. Clasa Counter este un numarator care se ruleaza pe un fir de
executie propriu si este capabil de gestionarea obiectelor de tip listener. Aceste

obiecte listener sunt stocate intr-un vector (java.util.Vector ) si la modificarea


numaratorului sunt anuntati. (notifyCounterChange).
Diagrama de clase:

Sursa Java:

class CounterEvent extends EventObject{


private int count;
CounterEvent ( Object source, int count ){
super( source );
this.count = count;
}
public int getCount(){
return count;
}
}

interface CounterChangeListener extends EventListener{


void counterChange( CounterEvent e );
}
class Counter extends Thread{
private int count = 0;
private Vector listeners = new Vector();
public Counter( string name, int count ){
super( name );
this.count = count;
}
public Counter( int count ){
this.count = count;
}
public Counter(){
this( 0 );
}
public void run(){
while( true ){
try{
sleep( ( int ) Math.round( Math.random()*3000));
}
catch( InterruptedException e ){}
count++;
notifyCounterChange( count );
}
}
public void startCounting(){
this.start();
}
public notifyCounterChange( int count ){
Vector tmpList;
CounterEvent ce = new CounterEvent( this , count );
synchronized( this ){
tmpList = (Vector ) listeners.clone();
}
for( int i=0; i<tmpList.size(); i++){
((CounterChangeListener )
tmpList.elementAt(i)).counterChange( ce );
}
}

public synchronized void addCounterChangeListener( CounterChangeListener


ccl ){
listeners.addElement( ccl );
}
public synchronized void removeCounterChangeListener(
CounterChangeListener ccl ){
listeners.removeElement( ccl );
}
}
public class CounterControl implements CounterChangeListener
{
public CounterControl()
{
Counter c = new Counter();
c.addCounterChangeListener(this);
c.startCounting();
}
public static void main(String[] args)
{
CounterControl cc = new CounterControl();
}
public void counterChange(CounterEvent e)
{
System.out.println("Counter value has changed: " +
e.getCount());
}
}

Facilitati I/E
1.
2.
3.
4.

Generalitati
I/E pe terminal
Filtre
Fisiere
o Implementarea comenzii cat din UNIX
o Copiere de fisiere

1. Conducte

1. Generalitati
In vederea tratarii unitare a interfetelor de comunicare intre entitatile unui sistem
informatic( entitati software+entitati hardware) se introduce conceptul de stream.

Autorul acestui concept este Dennis Ritchie care in 1984 implementeaza primul
sistem I/O pe baza de stream in cadrul s.o. Unix. Ideea de stream are la baza creara
unui canal de comunicatie intre doua entitati. Una dintre entitati este sursa, iar cealalta
destinatia. Sursa scrie informatii in canal, iar destinatia poata sa le citeasca aceste
date.Canalul permite trecerea unui flux de date intr-o singura directie.Datorita faptului
ca exista doua directii de comunicare, exista doua tipuri mari de streamuri pentru orice
nod de comunicatie: input stream si output stream. Tastatura ar fi un exemplu de
input stream, iar monitorul un output stream. Sursa si destinatia nu trebuie sa fie
neaparat periferice, ele pot fi si module soft. Un alt mare avantaj al streamurilor este
posibilitatea conectarii acestora, obtinand astfel un mecanism pipe-line de comunicare
interprocese.
Fluxurile de date sunt de doua tipuri fluxuri de octeti si fluxuri de caractere. Fluxurile
de caractere au fost introduse de versiunea 1.1. . Java API defineste o ierarhie intreaga
de clase si interfete pentru fluxuri.

InputStream/OutputStream

Sunt clase abstracte care definesc functionalitatile de baza pentru citirea respectiv
scrierea unui bloc de octeti. Toate celelalte tipuri de streamuri pentru octeti se deriva
din aceste doua.
Reader/Writer

Sunt clase abstracte care definesc functionalitatile de baza pentru citirea respectiv
scrierea unui bloc de caractere. Toate celelalte tipuri de streamuri pentru caractere se
deriva din aceste doua. Au fost introduse de Java 1.1
InputStreamReader/InputStreamWriter

Sunt clase utilizate pentru conversia blocurilor de caractere la blocuri de octeti.


DataInputStream/DataOutputStream

Sunt clase de tip filtre care se pun peste clasele InputStream/OutputStream si permit
citirea/scrierea a diferitelor tipuri de date (logice, intregi, reale, siruri de caractere etc.
).
ObjectInputStream/ObjectOutputStream

Se utilizeaza pentru scrierea obiectelor serializabile respectiv reconstructia lor dupa


citire.
BufferedInputStream/BufferedOutputStream/BufferedReader/BufferedWriter

Clase care realizeaza operatiile de citire scriere cu zone tampon pentru a mari
eficienta acestor operatii.
PrintWriter

Un stream special de caractere care permite scrierea textelor. System.out este de acest
tip.
PipedInputStream/PipedOutputStream/PipedReader/PipedWriter

Clase pentru realizarea mecanismului conducta (pipe).


FileInputStream/FileOutputStream/FileReader/FileWriter

Clase care ofera facilitati pentru accesul fisierelor din sistemul local de fisiere.

2. I/E pe terminal
Asemanator cu C standard si Java ne ofera facilitati pentru a lucra cu intrarea/iesirea
respectiv eroarea standard. Clasa Systemdin pachetul java.lang contine trei
referinte statice de urmatoarele tipuri:
InputStream

in

PrintWriter
PrintWriter

out
err

Aceste trei streamuri nu trebuie deschise, ele se deschid automat inaintea executiei
aplicatiei. Celelalte streamuri se deschid in momentul crearii lor prin apelul
constructorului clasei corespunzatoare. Streamurile se inchid cu apelul metodei
close(). Streamurile in, out si err nu trebuie inchise.
Citirea si scrierea din si in aceste streamuri se realizeaza cu ajutorul metodelor read()
si write() care au mai multe forme supraincarcate. In cazul streamurilor de octeti
metoda read() are urmatoarele trei forme:
int read() throws IOException;
int read( byte b[])throws IOException;
int read( byte b[], int offset, int length ) throws IOException;

Prima forma citeste un octet dar returneaza rezultatul sub forma unui intreg. In caz de
eroare se genereaza exceptia IOException, deci orice apel de metoda read obligatoriu

trebuie inclus intr-un context de tratarea exceptiilor. La sfarsitul fluxului read()


returneaza -1.
try{
int val = System.in.read();
...
}
catch (IOException e ){
// Tratarea exceptiei
}

Prin a doua si a treia forma se pot citi deodata un bloc intreg de octeti. Octetii cititi
vor fi stocati intr-un tablou de octeti primit ca parametru. Aceste doua metode
returneaza numarul octetilor efectiv cititi.
byte b[1024];
try{
int bytesread=System.in.read( b );
}
catch( IOException e ){...}

Clasa InputStream defineste si o metoda available() care returneaza numarul


octetiilor disponibili din flux.
try{
int disponibili = System.in.available();
if( disponibili > 0){
byte b[] = new byte[ disponibili ];
System.in.read( b );
}
}
catch( IOException e ){ ... }

Exemplul urmator copiaza intrarea standard la iesirea standard.


import java.io.*;
public class Copiere{
public static void copiere ( InputStream sin, OutputStream sout) throws
IOException{
int b;
while(( b =sin.read()) != -1) sout.write(b);
sout.flush();
}

public static void main( String args[]){


try{
copiere(System.in, System.out );
}
catch( IOException e ){
System.out.println("Eroare de copiere");
}
}
}

Functia skip( int ) se utilizeaza pentru a muta pozitia citirii peste un numar de
octeti specificat prin parametru. Toate metodele de citire blocheaza firul de executie
care doreste sa faca operatiile I/O pana cand toate datele sunt disponibile, s-a ajuns la
sfarsitul fluxului de date sau a aparut o exceptie.
Metodele mark() si reset() se folosesc impreuna oferind posibilitatea reluarii citirii
din stream. Prin metoda mark( int readLimit ) se memoreaza pozitia curenta in
stream si se creaza o zona tampon de dimensiunea specificata prin readLimit.
Prin reset() se repozitioneaza indicatorul in stream la pozitia marcata prin mark().
Aceste doua metode pot fi folosite doar in cazul in care streamul suporta marcare.
Verificarea acestui lucru se poate face prin markSupported().

3. Filtre
Exista clase in pachetul java.io care nu sunt utilizate pentru operatiile efective de
citire si scriere, ci ne ofera o serie de metode pentru a scrie si citi diferite tipuri de
date. Aceste clase alcatuiesc un nivel superior si intotdeauna se combina cu cate o
clasa care creaza canalul de comunicatie . Clasele DataInputStream respectiv
DataOutputStream sunt clase care definesc o serie de astfel de metode. De exemplu
clasa DataInputStream contine si urmatoarele metode:
short readShort();
int readInt();
long

readLong();

float readFloat();
double readDouble();

4. Fisiere
Clasele FileInputStream, FileOutputStream, FileReader, FileWriter
La capetele unui canal de comunicatie putem sa avem si fisiere. In acest caz operatiile
I/E vor afecta fisierele. Daca dorim sa citim din fisiere atunci in functie de tipul
fisierului vom utiliza clasele FileInputStream respectiv FileReader (fisier binar sau
fisier text). Pentru scriere se vor utiliza clasele FileOutputStream respectiv
FileWriter. Pentru a deschide un fisier pentru scriere sau citire se creaza un nou obiect
din clasele amintite mai in sus. La crearea obiectului se va apela unul din constructorii
clasei corespunzatoare. Acest constructor poate sa primeasca ca parametru numele
fisierului sau un obiect de tip File sau unul de tip FileDescriptor.
Exemplul urmator afiseaza continutul unui fisier text pe terminal. utilizand un obiect
de tip FileReader. Numele fisiereului de listat se primeste de la linia de comanda.
import java.io.*;
public class Cat{
public static void main( String args[]){
FileReader fr = null;
int b = 0;
if( args.length !=1 ){
System.out.println("Utilizare: java Cat <nume_fisier_text>");
System.exit(1);
}
try{
fr = new FileReader( args[0] );
while( ( b =fr.read()) != -1 )
System.out.print( (char) b );
}
catch( FileNotFoundException e ){

System.out.println("Fisier inexistent");
System.exit(2);
}
catch( IOException e ){
System.out.println("Eroare de citire");
System.exit(3);
}
}
}

Daca dorim sa citim linii intregi din fisier in loc de caractere va trebui sa utilizam
clasa BufferedReader care defineste metoda readLine(). Constructorul clasei
BufferedReader primeste ca parametru un obiect de tip FileReader, care in prealabil
trebuie creat.
try{
fr = new FileReader( args[0] );
BufferedReader br = new BufferedReader( fr );
String line;
while( ( line =br.readLine()) != null )
System.out.println( line );
}
catch( FileNotFoundException e ){
System.out.println("Fisier inexistent");
System.exit(2);
}
catch( IOException e ){
System.out.println("Eroare de ccitire");
System.exit(3);
}
}
}

Generalizare:
Modificam exemplul precedent a.i. daca nu primeste nici un argument de la linia de
comanda atunci copieaza intrarea standard la iesirea standard, iar daca primeste mai
multe argumente, le afiseaza pe toate.
import java.io.*;

public class cat{


String files[];
// Constructor pentru cazul cand programului se transmit
// argumente de la linia de comanda
public cat( String files[] ){
int i;
this.files = files;
for(i=0; i<files.length; i++)
{
try
{
BufferedReader br = new BufferedReader( new
FileReader(files[ i ] ));
print( br );
br.close();
}
catch( IOException e )
{
System.out.println("Error opening file: "+files[ i ]
);
}
}
}
// Constructor pentru cazul cand nu primeste nici un argument
public cat(){
try{
BufferedReader br = new BufferedReader(
new InputStreamReader( System.in ) );
print( br );
br.close();
}
catch( IOException e )
{
System.out.println("Error " );
}
}

public void print( BufferedReader br ) throws IOException {


String line;
while( ( line = br.readLine() ) != null )
System.out.println( line );
}
public static void main( String args[] ){
if( args.length == 0 ){
System.out.println(" Copiing standard imput to
standard output");
cat c = new cat();
}
else
{
System.out.println(" Copiing files to standard output
");
cat c = new cat( args );
}
}
}

Forme de utilizare:
1. java cat
2. java cat fisier1 fisier2 ...
Copiere de fisiere:

import java.io.*;
public class CopiereFisiere{
static FileInputStream fis;
static FileOutputStream fos;
public static void copiere ( InputStream sin, OutputStream sout) throws
IOException{
byte b[]= new byte[1024];
int bytesRead;
while(( bytesRead =sin.read(b)) >0) sout.write(b);
sout.flush();
}

public static void main( String args[]){


if( args.length !=2 ){
System.out.println("Utilizare java CopiereFisiere sursa destinatie");
System.exit(1);
}
try{
fis = new FileInputStream( args[0]);
fos = new FileOutputStream( args[1] );
copiere(fis, fos );
}
catch( FileNotFoundException e ){
System.out.println("Fisier inexistent "+args[0]);
System.exit(1);
}
catch( IOException e ){
System.out.println("Eroare de copiere");
}
}
}

Clasa File
Clasa File contine informatii despre fisiere si directoare si defineste o serie de metode
pentru a obtine respectiv a modifica aceste informatii.. Principalele metode sunt
urmatoarele:

Metoda
Tipul returnat
Descriere
canRead()
boolean
Are permisiunea de citire?
canWrite()
boolean
Are permisiunea de scriere?
delete()
boolean
Stergere
exists()
boolean
Exista fisierul?
getAbsolutePath() String
Calea completa spre fisier
getCanonicalPath() String
Calea completa spre fisier
getName()
String
Numele fisierului
getParent()
String
Numele catalogului parinte
getPath()
String
Calea spre fisier
isAbsolute()
boolean
Este un nume absolut?

isDirectory()
isFile()
lastModified()
length()
list()
mkdir()
mkdirs()

boolean
boolean
long
long
String[]
booolean
boolean

Este un director?
Este un fisier ordinar?
Data ultimei modificari
Lungimea fisierului
Lista fisierelor din director
Crearea de director
Crearea tuturor directoarelor

Programul urmator primeste de la linia de comanda un nume. Daca numele reprezinta


numele unui director atunci se listeaza continutul acestuia, altfel daca este fisier,
atunci se afiseaza fisierul pe terminal..
import java.io.*;
public class Listare {
public static void main( String args[] )
{
File file;
if( args.length != 1 ){
System.out.println("Utilizare: java Listare <nume> ");
return;
}
try{
file = new File( args[0]);
}
catch( Exception e ){
System.out.println(" Fisier inexistent ");
return;
}
if( ! file.exists() || !file.canRead() ){
System.out.println("Eroare de citire fisier: "+ args[0]);
return;
}
if( file.isDirectory() ){
String files[] = file.list();
for( int i =0; i<files.length; i++)
System.out.println( files[i] );
}
else{
try{

FileReader fr = new FileReader( file );


BufferedReader in = new BufferedReader( fr );
String line;
while( (line = in.readLine()) != null )
System.out.println(line);
}
catch( FileNotFoundException e ){
System.out.println("eroare la deschiderea fisierului");
}
catch( IOException e ){
System.out.println("eroare de citire");
}
}
}
}

Clasa RandomAccessFile
Aceasta clasa implementeaza atat interfata DataInput cat si interfata DataOutput astfel
permitand citirea si scrierea datelor primitive Java cat si a sirurilor de caractere. Clasa
permite accesul direct al fisierului. Clasele cu care am lucrat pana acum au permis
doar accesul secvential. Crearea unui obiect de tip RandomAccessFile se face in
modul urmator:
try{
RandomaccessFile file = new randomAccessFile("unfisier","rw");
...
}
catch( IOException e){
}

Primul parametru al constructorului poate fi un sir de caractere care reprezinta calea si


numele fisierului sau un obiect de tip File, iar al doilea parametru reprezinta modul de
access ( r-citire, w-scriere). Si aceasta clasa defineste metode de citire si scriere, dar
pe langa aceste metode contine si una care permite accesul direct: seek( long pozitie).
Exemplu:
Se creaza un fisier cu valori de tip double generate aleator si se afiseaza fisierul pe
terminal. Dupa aceea se modifica continutul aleator, modificand doar cateva elemente
si se afiseaza inca o data fisierul pe terminal.
import java.io.*;
import java.util.*;

public class FisierAccesDirect{


RandomAccessFile f;
String
long

name;
dim;

public FisierAccesDirect( String name, long dim ) throws IOException


{
this.name = name;
this.dim

= dim;

f = new RandomAccessFile( name, "rw");


Random r = new Random( 10000 );
for( int i=0; i< dim; i++ )
{
double d = r.nextDouble();
f.writeDouble( d );
System.out.print( d+"\t");
}
f.close();
f = new RandomAccessFile( name, "rw");
}

public double getDouble( long poz ) throws IOException


{
f.seek( poz * 8 );
return( f.readDouble());
}
public void putDouble( long poz, double d ) throws IOException
{
f.seek( poz * 8);
f.writeDouble( d );
}
public long getDim()
{
return dim;
}

public static void main( String args[] )


{
try
{
FisierAccesDirect c = new
FisierAccesDirect("doublefile",10);
Random r = new Random();
long n = c.getDim();
long i;
System.out.println("Dimension : "+n);
for( i=0; i<5; i++ ){
long poz = r.nextLong();
if (poz<0) poz = -poz;
poz = poz % n;
System.out.println("Poz: "+poz);
c.putDouble( poz, 1.0 );
}
System.out.println("Fisierul modificat: ");
for( i=0; i< n; i++ )
{
System.out.print(c.getDouble(i)+"\t");
}

}
catch( IOException e ){
System.out.println("Eroare IO ");
}
}
}

5. Conducte
In mod normal aplicatia utilizeaza un stream de scriere sau una de citire la un moment
dat. Clasele PipedInputStream si PipedOutputStream (respectiv PipedReader si
PipedWriter) ne ajuta la crearea mecanismului de conducta care se poate utiliza de
catre o aplicatie care se ruleaza pe mai multe fire de executie. Firele de executie
comunica intre ele cu ajutorul acestui mecanism. Exemplul urmator va fi o aplicatie
care se ruleaza pe doua fire de executie. Primul fir produce mesaje pe care le scrie
intr-o conducta, in cazul nostru mesajul va fi format din data si ora curenta a

producerii mesajului, iar celalalt fir de executie consuma mesajele, afisandu-le pe


terminal. Pentru a crea o conducta trebuie sa utilizam doua obiecte, unul pentru
capatul de scriere al conductei, iar celalalt pentru capatul de citire al
conductei. Crearea se face in modul urmator:
PipedInputStream pin = new PipedInputStream();
PipedOutputStream pout = new PipedOutputStream( pin );

sau invers
PipedOutputStream pout = new PipedOutputStream();
PipedInputStream pin = new PipedInputStream( pout );
Exemplu pentru utilizarea conductelor:
Diagrama de colaborare:

Diagrama de clase:

Sursa Java:
//Source file: Control.java

public class Control


{
public Control()
{
}
public static void main(String[] args)
{
ThreadA ta = new ThreadA("Pipe Writer Thread");
ThreadB tb = new ThreadB("Pipe Reader Thread", ta.piperead );
ta.start();
tb.start();
}
}
//Source file: ThreadA.java

import java.io.PipedWriter;
import java.io.PipedReader;
public class ThreadA extends Thread
{
public PipedWriter pipewrite;
public PipedReader piperead;

public ThreadA(String name)


{
super( name );
try{
pipewrite = new PipedWriter();
piperead

= new PipedReader( pipewrite );

}
catch( java.io.IOException e ) {}
}
public void run()
{
java.io.PrintWriter ptw = new java.io.PrintWriter( pipewrite );
while( true ){
String s = ( new java.util.Date().toString());
ptw.println( s );
System.out.println(getName()+" "+s+": has been written in
pipe");
try{
sleep(1000);
}
catch( InterruptedException e ){}
}
}
}
//Source file: ThreadB.java
import java.io.PipedReader;
public class ThreadB extends Thread
{
public PipedReader piperead;

public ThreadB(String name, PipedReader pr)


{
super( name );
piperead = pr;
}
public void run()
{
String s=null;
java.io.BufferedReader br = new java.io.BufferedReader ( piperead );
while( true ){
try{
s = br.readLine();
}
catch( java.io.IOException e ){
System.out.println("Error reading from pipe");
}
System.out.println(getName()+": "+s+" read from pipe");
try{
sleep(1000);
}
catch( InterruptedException e ){}
}
}
}

Aplicatii de retea. Socluri. URL.


1. Protocoale si porturi. Modelul client server.
2. Modelul de comunicatie orientat pe conexiune. Clasele Socket si ServerSocket
3. Modelul de comunicatie neorientat pe conexiune. Clasele DatagaramSocket
si DatagramPacket
4. URL
Clasele din pachetul java.net se impart in doua categorii, clase pentru socluri si clase
care lucreaza cu URL (Uniform Resource Locators). Soclurile Java faciliteaza accesul
la protocoalele standard utilizate in comunicarea intre calculatoarele gazda de pe
Interent.

1. Protocoale si porturi. Modelul client server.


Protocoale
Inainte sa intram in detaliile posibilitatilor oferite de limbajul Java pentru scrierea
aplicatiilor de retea trebuie sa cunoastem niste lucruri despre reteaua Internet.
Internetul functioneaza pe un sistem de protocoale numit TCP/IP (Transport Control
Protocol/Internet protocol)

Aceste protocoale stabilesc regulile cu ajutorul carora doua calculatoare comunica


intre ele. Protocoalele sunt standarde de care se ocupa IETF ( Internet Engineering
Task Force). Java implementeaza protocoalele de nivel superior al stivei de protocoale
TCP/IP. Astfel faciliteaza utilizarea protocoalelor HTTP (HyperText Transfer
Protocol) si FTP( File Transfer Protocol). Astfel programatorul va utiliza niste clase si
interfete predefinite, fara a cunoaste detaliile de implementare a acestora. Nu trebuie
sa cunoastem structurile de date utilizate de acest sistem de protocoale, nici metodele
utilizate pentru transmiterea si receptionarea secventelor de octeti.
Modelul client server
Serverul este o aplicatie care ofera servicii clientilor sositi prin retea. Serverele ofera o
gama variata de servicii. Serverul cel mai cunoscut este serverul Web, care furnizeaza
documentele cerute de catre clienti. Un alt serviciu cunoscut este posta electronica,
care utilizeaza protocoalele SMPT (Simple Mail Transfer Protocol) si IMAP4
(Internet Mail Access Protocol). Pe principiul client-server funnctioneaza si
protocoalele NFS (Network File Service) si FTP sau serviciul de nume de
domenii DNS (Domain Name Service) si serviciul de informatii despre retea NIS

(Network Information Services). Trebuie sa amintim si serviciul care permite logarea


la un calculator aflat la distanta: TELNET si RLOGIN. Putem trage concluzia ca
arhitectura client-server este instrumentul de baza in dezvoltarea aplicatiilor de retea.
Clientul este o aplicatie care utilizeaza serviciile oferite de catre un server. Pentru a
putea realiza acest lucru, clientul trebuie sa cunoasca unde se afla serverul in retea si
cum trebuie comunicat cu acesta si ce servicii ofera. Deci daca un client doreste o
comunicare cu serverul, trebuie sa cunosca trei lucruri:

adresa server
portul server utilizat pentru comunicare
protocolul de comunicatie utilizat de server

Daca aceste date ne stau la dispozitie, putem realiza comunicatia cu serverul.


Porturi si socluri
Porturile si soclurile reprezinta mecanismul prin care se realizeaza legatura cu un
server. Porturile reprezinta o poarta la care sunt primiti clientii pentru un anumit
serviciu. De exemplu la aceeasi adresa se pot oferi diferite servicii, acestea oferinduse la porturi diferite. Acelasi calculator (cu o singura adresa IP) poate sa ne ofere
oricate servicii doreste. Clientii care apeleaza la serviciile acestui calculator vor utiliza
aceeasi adresa, indiferent la care serviciu apeleaza, si toti clientii care doresc utilizarea
unui anumit serviciu vor utiliza acelasi port. Un numar de port este un numar inreg din
intervalul 1-9999. IETF defineste serviciile oferite pe porturile 1-1024. De obicei
serviciile HTTP sunt oferite la portul 80, cele de FTP la portul 21, Telnet la 23 etc.
Un soclu este de fapt un nod abstract de comunicatie. Soclurile reprezinta o interfata
de nivel scazut pentru comunicarea in retea. Soclurile permit comunicarea intre
procese aflate pe acelasi calculator sau pe calculatoare diferite din retea. Mecanismul
de socluri a fost definit prima data in BSD UNIX. Java suporta trei tipuri de socluri.
Clasa Socket utilizeaza un protocol orientat pe conexiune (TCP),
clasaDatagramSocket utilizeaza protocolul UDP la nivelul transport, care este un
protocol neorientat pe conexiune. O alta varianta a DatagramSocket
este MulticastSocket utilizat pentru a trimite date deodata la mai multi receptori.
Soclurile utilizeaza fluxuri de date (streamuri) pentru a trimite si a receptiona mesaje.

2. Modelul de comunicatie orientat pe conexiune.


Clasele Socket si ServerSocket
Acest model se bazeaza pe protocolul TCP. Intr-o aplicatie retea intotdeauna avem
doua parti: o parte client care initializeaza conversatia si trimite cereri, si o

parte server care primeste cererile si raspunde la acestea. Clientul intotdeauna creaza
un soclu pentru a initia conversatia si trebuie sa cunoasca serverul caruia adreseaza
cererea, iar serverul trebuie sa fie pregatit pentru a receptiona aceste cereri. In
momentul receptionarii mesajului creaza un soclu pe partea serverului, soclu care va
facilita deservirea clientului. Atat pe partea de client cat si pe partea de server se
utilizeaza cate un obiect de tip Socketpentru comunicare. Pe partea de server mai
trebuie sa cream un obiect de tip ServerSocket, care are sarcina primirii conexiunilor
si acceptarea acestora.

Clientul trebuie sa cunoasca doua lucruri despre server: numele serverului (utilizat
pentru determinarea adresei IP al serverului) si numarul portului la care acesta asculta
cererile clientilor. Acelasi calculator gazda poate oferi mai multe servicii, deci poate
gazdui mai multe procese de tip server. De exemplu poate fi server Mail, server FTP,
server HTTP, dar aceste aplicatii lucreaza cu diferite porturi, deci cererile adresate
acestor serveri vor fi receptionate pe diferite porturi.
Privind modalitatea de deservire a clientilor serverul prin constructie poate fi server
paralel (concurent) si server secvential.

Serverul concurent permite deservirea in paralel a mai multor clienti. Aceasta


paralelitate se poate realiza prin crearea a mai multor procese fiu, cate unul pentru
fiecare client sau prin crearea de fire de executie pentru deservirea fiecarui clienti In
Java noi vom utiliza cea de a doua modalitate. De obicei utilizam server cu arhitectura
paralela pentru servicii la care deservirea unui client dureaza in timp.
In general o aplicatie server trebuie sa execute urmatorii pasi:
1. Serverul aloca
cunoscut de catre
2. Cat timp ( mai
{
stabilire
deservire
iesire )
eliberare
}

un port de comunicare care va fi


clienti
sunt clienti la port )
conexiune cu client ( creare soclu )
client ( flux de intrare, flux de
conexiune ( eliberare soclu )

O aplicatie client executa urmatoarele:


1. Aloca un port de comunicare
2. Se conecteaza la server la portul cunoscut de dinainte
3. Se stabileste o conexiune prin care se trimit si se
citesc date (soclu + fluxuri)
Clasa Socket
Constructori:
Socket(InetAddress address, int port)

Creaza un soclu si care se conecteaza la adresa IP specificat prin obiectul


InetAddress si portul specificat prin parametrul port.
Socket(InetAddress address, int port, InetAddress localAddr, int
localPort)

Creaza un soclu si care se conecteaza la adresa IP specificat prin obiectul InetAddress


si portul specificat prin parametrul port. Ultimii doi parametri reprezinta adresa
clientului si portul pe care acesta comunica .
Socket(String host, int port)
Creaza un soclu si care se conecteaza la calculatorul host pe portul
specificat prin parametrul port.
Socket(String host, int port, InetAddress localAddr,
int localPort)
Creaza un soclu si care se conecteaza la calculatorul host pe portul
specificat prin parametrul port. Ultimii doi parametri reprezinta adresa clientului si
portul pe care acesta comunica
Metode principale:
void close()
Inchide soclul.
InetAddress getInetAddress()
Returneaza adresa la care soclul este conectat
InputStream getInputStream()
Returneaza un stream de intrare pentru soclu.
InetAddress getLocalAddress()
Returneaza adresa pe care soclul este creat.
int getLocalPort()
Returneaza numarul portului local.
OutputStream getOutputStream()
Returneza un stream de iesire pentru soclu.
int getPort()
Returneaza portul la care soclul este conectat.
Clasa ServerSocket
Constructori:

ServerSocket(int port)
Creaza un soclu server pe portul specificat.
ServerSocket(int port, int backlog)
Creaza un soclu server pe portul specificat. Al doilea parametru indica
lungimea cozii de asteptare.
Metode principale:
Socket accept()
Asculta conexiunile si le accepta.
void close()
Inchide soclul.
InetAddress getInetAddress()
Returneaza adresa locala al soclului server.
int getLocalPort()
Returneaza portul la care serverul asteapta conexiunile.
Exemplu 1.
Urmatoarea aplicatie este formata dintr-o parte client si una server. Clientul va trimite
un sir de caractere serverului, iar serverul il va trimite inapoi convertit in majuscule.
Pentru rezolvarea acestei probleme construim doua pachete:

Incepen cu descrierea serverului. Serverul are o structura paralela, permite deservirea


a mai multor clienti. Pentru fiecare client se va crea un obiect de tip ClientHanedle, un

obiect care se ruleaza pe un fir de executie separat si realizeaza deservirea clientului.

//Source file: c:\Rose\ClientServer\ServerPackage\Server.java


package ServerPackage;

public class Server


{
public static void main(String[] args)
{
int port;
if( args.length <1 )
{
System.out.println( "Usage Server <portnumber>");
System.exit( 1 );
}
try{
port = Integer.parseInt( args[ 0 ] );
}
catch( NumberFormatException e )
{
port = 1024;
}
try{
java.net.ServerSocket ss = new java.net.ServerSocket( port );
while( true )
( new ClientHandle( ss.accept() )).start();
}
catch( java.io.IOException e )

{
System.out.println( "Server error ");
}
}
}
//Source file: c:\Rose\ClientServer\ServerPackage\ClientHandle.java
package ServerPackage;
import java.net.Socket;
import java.net.SocketException;
public class ClientHandle extends Thread
{
Socket client;
public ClientHandle(Socket client) throws SocketException
{
this.client = client;
}
public void run()
{
try{
java.io.InputStream

in

= client.getInputStream();

java.io.OutputStream out = client.getOutputStream();


java.io.BufferedReader myin

= new java.io.BufferedReader(
new java.io.InputStreamReader( in));

java.io.PrintWriter

myout = new java.io.PrintWriter( new


java.io.OutputStreamWriter( out ));

String request = myin.readLine();


System.out.println( "Request: "+request);
myout.println( request.toUpperCase());
myout.flush();
myin.close();
myout.close();
client.close();
}
catch( java.io.IOException e )
{
System.out.println("I/O error "+e );
}

}
}

Partea de client:

//Source file: c:\Rose\ClientServer\ClientPackage\Client.java


package ClientPackage;
public class Client
{
private String hostname;
private int hostport;
private String message;
public Client(String hostname, int hostport, String message)
{
this.hostname = hostname;
this.hostport = hostport;
this.message = message;
doIt();
}
public void doIt()
{
try{
java.net.Socket s = new java.net.Socket( hostname, hostport );
java.io.BufferedReader

in = new java.io.BufferedReader( new

java.io.InputStreamReader(s.getInputStream()));
java.io.PrintWriter
out = new java.io.PrintWriter(
s.getOutputStream() );
out.println( message ); out.flush();
System.out.println("Answer from the server: "+in.readLine() );
s.close();
}

catch( java.io.IOException

e )

{
System.out.println( "I/O error "+e );
}
}

public static void main(String[] args)


{
String hostname, message;
int hostport;
if( args.length < 3 )
{
System.out.println("Usage Client <hostname> <hostport> <message>");
System.exit( 1 );
}
hostname = args[ 0 ];
message

= args[ 2 ];

try{
hostport =Integer.parseInt( args[ 1 ] );
}
catch( NumberFormatException e )
{
hostport = 1024;
}
Client c = new Client( hostname, hostport, message );
}
}

Exemplu 2
Urmatoarea aplicatie va fi un server web. Aplicatia se va rula pe un fir de executie cu
prioritatea mai mica decat cea normala si va rezolva cererile HTTP. Vom proiecta
aplicatia a.i. sa aiba o arhitectura paralela si sa rezolve cererile de tip GET
nume_fisier.Arhitectura paralela permite deservirea concomitenta a mai multor
clienti.
import java.io.*;
import java.net.*;
import java.util.*;

public class TinyHttpd{


public static void main ( String args[] ) throws IOException
{
ServerSocket ss = new ServerSocket( Integer.parseInt( args[0]));
while( true )
{
Socket s = ss.accept();
TinyHttpdConnection t = new TinyHttpdConnection( s );
t.start();
}
}
}

class TinyHttpdConnection extends Thread{


Socket client;
TinyHttpdConnection ( Socket client) throws SocketException{
this.client = client;
setPriority(NORM_PRIORITY -1);
}
public void run(){
try{
BufferedReader in = new BufferedReader(
new InputStreamReader(client.getInputStream(),"8859_1"));
OutputStream out = client.getOutputStream();
PrintWriter pout = new PrintWriter(
new OutputStreamWriter(out,"8859_1"),true);
String request = in.readLine();
System.out.println("Request: "+request);
StringTokenizer st = new StringTokenizer( request );
if( (st.countTokens()>=2) && st.nextToken().equals("GET"))
{
if( (request = st.nextToken()).startsWith("/"))
request=request.substring( 1 );
if( request.endsWith("/") || request.equals(""))
request=request+"index.html";
try{
FileInputStream fis = new FileInputStream( request );
byte[] data = new byte[ fis.available()];
fis.read(data);

out.write(data);
out.flush();
}
catch( FileNotFoundException e ){
pout.println(e.toString());
}
}
else{
pout.println("400 Bad request");
}
client.close();
}
catch( IOException e )
{
System.out.println(e.toString());
}
}
}

Utilizarea aplicatiei:
Aplicatia de mai sus se utilizeaza in modul urmator. Prima data se compileaza si dupa
aceea se executa cu comanda:
java TinyHttpd 1234.
Numarul 1234 reprezinta portul la care serverul asteapta cererile. Dupa ce serverul
este lansat in executie, dintr-un program de navigare (browser) se formuleaza o cerere
de forma:http://127.0.0.1:1234/Index.html, daca exista in catalogul aplicatiei
TyniHttpd fisierul Index.html si daca clientul si serverul se ruleaza pe acelasi
calculator. 127.0.0.1 este adresa IP al localhost-ului. Daca aplicatia se ruleaza pe un
calculator cu numele unu.doi.com atunci in locul adresei 127.0.0.1 se pune
unu.doi.com.
Descrierea aplicatiei:
Aplicatia defineste doua clase. O clasa care rezolva o cerere pe un fir de executie,
TinyHttpdConnection si o clasa TinyHttpd care creaza soclul server si intra in
asteptarea clientilor. In momentul aparitiei unui client ( accept()) se creaza un nou fir
de executie caruia se transmite referinta la soclul returnat de catre accept(). Aceasta
referinta la soclu permite firului de executie sa extraga de aici fluxurile de intrare si de
iesire prin care se realizeaza comunicarea efectiva. Firul de executie extrage din flux
cu ajurorul unor operatii pe siruri de caractere, numele fisierului cerut. Daca exista

fisierul, acesta se deschide pentru citire si datele citite vor fi scrise in soclu pentru
a putea fi extrase si de catre client.

3. Modelul de comunicatie neorientat pe conexiune. Clasele


DatagaramSocket si DatagramPacket
Trimiterea unei datagrame este similara cu trimiterea unei scrisori prin serviciul
postal. In cazul trimiterii unei scrisori avem nevoie de un plic pe care scriem adresa
destinatarului si dupa aceea punem scrisoarea in plic si o aruncam intr-o cutie postala.
Analog la trimiterea unei datagrame trebuie sa cunoasten adresa si portul
calculatorului caruia ii este adresata datagrama, dupa care putem sa punem datele in
datagrama si sa le trimitem. Datagramele utilizeaza la nivelul transportului protocolul
UDP. Acest protocol este unul nesigur, neorientat pe conexiune. Nu se face
confirmare in cazul receptionarii acestor datagrame. Nici calea urmata de aceste
datagrame nu se cunoaste de dinainte. De aceea daca trimitem la acelasi destinatar mai
multe datagrame, unul dupa altul, nu putem fi siguri nici in ordinea primirii acestor
datagrame. Din cauza ca protocolul nu necesita confirmarea sosirii datagramelor este
un protocol rapid si se utilizeaza in cazul serviciilor unde nu este nici o nenorocire
daca se pierde un pachet-doua (DNS utilizeaza UDP).
Descrierea claselor principale:
Clasa DatagramPacket:
Constructori:
DatagramPacket(byte[] buf, int length)
Construieste un obiect de tip DatagramPacket pentru primirea unui pachet de
lungime length
DatagramPacket(byte[] buf, int length, InetAddress
address, int port)
Construieste un obiect de tip DatagramPacket pentru trimiterea unui pachet de
lungime length pe un port specificat, la un host specificat
DatagramPacket(byte[] buf, int offset, int length)
Construieste un obiect de tip DatagramPacket pentru primirea unui pachet de
lungime length, specificand un offset in buffer

DatagramPacket(byte[] buf, int offset, int length,


InetAddress address, int port)
Construieste un obiect de tip DatagramPacket pentru trimiterea unui pachet de
lungime length pe un port specificat, la un host specificat, specificand si un offset
Metode:
InetAddress getAddress()
Returneaza adresa IP al calculatorului de la care se primiste sau la care se trimite
datagrama
byte[] getData()
Returneaza sirul de octeti care se trimite sau care se primeste
int getLength()
Returneaza lungimea datelor care se trimit sau care se primesc
int getOffset()
Returneaza offsetul datelor care se trimit sau care se primesc
int getPort()
Returneaza numarul portului calculatorului la distanta la care se trimit datele sau de la
care se primesc datele
void setAddress(InetAddress iaddr)
void
void
void
void

Seteaza adresa.
setData(byte[] buf)
Seteaza bufferul pentru pachet
setData(byte[] buf, int offset, int length)
Seteaza bufferyl pentru pachet
setLength(int length)
Seteaza lungimea pachetului.
setPort(int iport)
Seteaza portul..

Clasa DatagramSocket
Constructori:
DatagramSocket()
Construieste un soclu si leaga la un port liber pe calculatorul local.
DatagramSocket(int port)
Construieste un soclu si leaga la un portul specificat pe calculatorul local.

DatagramSocket(int port, InetAddress laddr)


Construieste un soclu si leaga la adresa si portul specificat
Metode:
void close()
Inchide soclul.
void connect(InetAddress address, int port)
Conecteaza soclul la o adresa si port la distanta.
void disconnect()
Deconecteaza soclul.
InetAddrress getInetAddress()
Returneaza adresa la distanta la care soclul este conectat.
InetAddress getLocalAddress()
Returneaza adresa locala la care soclul este conectat.
int getLocalPort()
Returneaza portul local la care soclul este legat.
int getPort()
Returneaza portul la distanta la care soclul este legat.
void receive(DatagramPacket p)
Primire de datagrama prin acest soclu.
void send(DatagramPacket p)
Trimitere de datagrama prin acest soclu
.
Exemplu:
Exemplul urmator va fi format pe partea clientului dintr-un aplet, care instiinteaza
aplicatia server ori de cate ori este pornit. Apletul se include intotdeauna intr-o pagina
HTML si programul navigator este cel care incarca si ruleaza apletul. Astfel daca
pagina HTML reprezinta un homepage vom putea contoriza numarul vizitatorilor la
pagina respectiva.

Aplicatia este formata dintr-o parte client si una server. Clientul este un aplet, iar
serverul o aplicatie.

Partea de client:

//Source file: c:\Rose\curs9\exemplu2\ClientPackage\MessageApplet.java


package ClientPackage;
import java.applet.Applet;
public class MessageApplet extends Applet
{
private String myHost;
private int myPort;
public void init()
{
myHost = getCodeBase().getHost();
myPort = Integer.parseInt( getParameter("PORT"));
}

public void sendMessage(String message)


{
try{
byte data[] =message.getBytes();
java.net.InetAddress addr = java.net.InetAddress.getByName( myHost );
java.net.DatagramPacket packet = new java.net.DatagramPacket(
data, data.length, addr, myPort );
java.net.DatagramSocket ds = new java.net.DatagramSocket();
ds.send( packet );
ds.close();
}
catch( java.io.IOException e ){
System.out.println(e );
}
}

public void start()


{
sendMessage("Pagina incarcata");
}
}

Fisierul HTML:
<applet HEIGHT=10 WIDTH=10 CODE=MessageApplet.class>
<param NAME="PORT" VALUE="1234"></applet>

Apletul utilizeaza metoda getCodeBase() si getHost() pentru aflarea numelui host-ului


care il gazduieste, iar numarul portului se citeste din fisierul HTML. Astfel vor fi
initializate datele obiectului MessageApplet, myHost si myPort.
Metodele start() si stop() respectiv init() sunt metode publice care vor fi utilizate de
catre navigator. init() se apeleaza o singura data la incarcarea paginii, iar start() ori de
cate ori se revine la pagina respectiva. Metoda init() initializeaza datele obiectului, iar
start() si stop() apeleaza metoda sendMessage() pentru trimiterea datagramei. Prima
data se creaza un obiect InetAddress, care este incarcat cu adresa hostului, dupa care
se va crea un obiect de tip DatagramPacket car va contine atat adresa cat mesajul de
trimis.
byte data[] =message.getBytes();
//conversie String --> sir de octeti
InetAddress addr = InetAddress.getByName( myHost );
//obtinerea adresei IP al hostului

DatagramPacket packet = new DatagramPacket( data, data.length, addr, myPort


);
//crearea pachetului

Dupa ce avem pachetul gata, pregatit pentru trimitere, mai trebuie sa cream un soclu
prin care sa se trimita si putem expedia pachetul cu metoda send(). Dupa epedierea
pachetului se va inchide soclul.
DatagramSocket ds = new DatagramSocket();
//Crearea soclu
ds.send( packet );
//Trimitere pachet
ds. close();
//Inchidere soclu

Partea server:
import java.net.*;
import java.io.*;

public class AppletServer{


public static void main( String args[]) throws IOException{
DatagramSocket s = new DatagramSocket(
Integer.parseInt(args[0]));
while( true ){
byte data[] = new byte[1024];
DatagramPacket packet = new DatagramPacket( data,1024);
s.receive( packet );
String message = new String( packet.getData());
System.out.println("Hostname:
"+packet.getAddress().getHostName()+" "+message);
}
}
}

Partea de server:

//Source file: c:\Rose\curs9\exemplu2\ServerPackage\AppletServer.java


package ServerPackage;

public class AppletServer


{
public static void main(String[] args)
{
try
{
java.net.DatagramSocket s = new java.net.DatagramSocket(
Integer.parseInt(args[0]));
while( true ){
//Serverul se pregateste pentru primirea unui pachet
byte data[] = new byte[1024];
java.net.DatagramPacket packet = new java.net.DatagramPacket(
data,1024);
//Serverul asteapta primirea unui pachet
s.receive( packet );
//Se scot datele din pachet si se afiseaza la iesirea standard
String message = new String( packet.getData());
System.out.println("Hostname: "+
packet.getAddress().getHostName()+" "+message);
}
}
catch( java.io.IOException e ){}
}
}

Aplicatia server creaza un soclu de tip DatagramSocket si intra in asteptarea clientilor


pe un port. Numarul portului se primeste de la linia de comanda, fiind de tip String la
primire se va converti la intreg prin apelul metodei Integer.parseInt(args[0]). Dupa
crearea soclului se creaza un pachet gol pentru receptionarea datagramelor sosite.
Acest pachet este un obiect de tip DatagramPacket care are si o variabila de tip sir de
octeti, care se utilizeaza pentru stocarea datelor sosite, insa acesta trebuie alocat
inaintea sosirii datelor. Dupa ce s-au creat aceste doua obiecte, soclul apeleaza
metoda receive() si intra in astepatarea datagramelor. In momentul sosirii unei
datagrame, se extrage din aceasta mesajul si se va afisa pe terminal.

4. URL
URL (Uniform Resource Locator) identifica o resursa(obiect) pe Internet. In mod
uzual este format din trei sau patru parti:
protocol://hostname/nume_resursa sau
protocol://hostname:port/nume_resursa

protocol: poate fi http, ftp, gopher etc.


hostname: numele calculatorului pe care se afla resursa, putem specifica si adresa
IP, daca o stim in loc de nume host
port: trebuie specificat doar daca serviciul este oferit pe un port nestandard.
nume_resursa: calea si numele resursei
Java ne ofera mai multi constructori pentru crearea unui obiect URL care pot genera
exceptia MalformedURLException in caz ca lipseste ceva din specificatia URL. In
momentul construirii obiectului nu se verifica existenta resursei, deci exceptia se
genereaza daca un parametru este transmis incorect.
URL(String spec)
URL(String protocol, String host, int port, String file)
URL(String protocol, String host, String file)

Exemplu de utilizare:
try{
URL url = new URL("http","www.uttgm.ro",3128, "index.html");
System.out.println( url.toString());
}
catch( MalformedException e ){
//Se trateaza exceptia
}

Un aplet poate comunica doar cu calculatorul pe care este stocat codul lui. Cu
ajutorul metodei getDocumentBase() a clasei Applet putem afla numele acestui
calculator si dupa acea putem cere accesul la o resursa de pe acel calculator:
try{
URL url = new URL("http",getDocumentBase(),"index.html");
System.out.println( url.toString());
}
catch( MalformedException e ){
//Se trateaza exceptia
}

Daca dorim sa aducem datele asociate unui URL trebuie sa cerem obiectului URL
referinta la un stream atasat acestuia. Referinta se obtine prin apelul
metodei openStream(). Exemplul urmator afiseaza pe terminal continutul unui fisier
HTML.
try{
URL url = new URL("http://www.uttgm.ro/index.html");
BufferedReader bin = new BufferedReader( new
InputStreamReader(url.openStream()));

String line;
while( ( line = bin.readLine()) != null )
System.out.println( line );
}
catch (Exception e ){}

Exemplu cu URL:
Sa se scrie un aplet care permite utilizatorilor vizualizarea produselor unei firme. Din
cauza ca preturile sunt in continua schimbare acestea se stocheaza intr-un
fisier "preturi.dat", aflat in acelasi catalog cu codul apletului, precum si cu fisierul
HTML. In caz ca se schimba preturile produselor, apletul ramane neschimat, doar
fisierul "preturi.dat" se va modifica.
Cand clientul viziteaza pagina Web, browserul incarca prima data fisierul HTML, pe
urma codul apletului. Apletul este rulat pe calculatorul clientului, acesta incarcand
fisierul "preturi.dat". Pentru a incarca fisierul "preturi.dat", apletul creaza un URL:
try{
URL url = new URL( getDocumentBase(),"preturi.dat");
}
catch( Exception e ){}

Lista de preturi este formatat a.i sa fie ptrivit pentru a fi incarcat intr-un
obiect Properties:
Mere=7000
Pere=10000
Struguri=25000
Basnana=27000

Incarcarea fisierului intr-un obiect Properties se va realiza prin:


Properties preturi = new Properties();
try{
preturi.load( url.openStream());
}
catch( Exception e ){}

Interfata apletului:

Diagrama de clasa:

Diagrama de secventiere:

Codul sursa:
//Source file: Linie_de_comanda.java
public class Linie_de_comanda
{
private String nume;
private int cantitate;
private double pretunitar;
public Linie_de_comanda(String nume, int cantitate, double pretunitar)
{
this.nume= nume;
this.cantitate = cantitate;
this.pretunitar = pretunitar;
}
public String toString()
{
String s2 = Integer.toString( cantitate );
String s3 = Double.toString( pretunitar );
return nume+" : "+s2+" : "+s3;
}
}
//Source file: CanvasComanda.java

import java.awt.Canvas;
import java.util.Vector;
import java.awt.Graphics;
public class CanvasComanda extends Canvas
{
private Vector a;
public void redraw(java.util.Vector a)
{
this.a =a;
repaint();
}
public void paint(Graphics g)
{
int i;
int x=80, y=0;
java.awt.Font f = new java.awt.Font("Monospaced",java.awt.Font.PLAIN, 12
);
g.setFont( f );
java.awt.FontMetrics fm = g.getFontMetrics( f );
int height = fm.getHeight();
y+=height;
g.drawString("Your order: ",x,y);
for( i = 0; i<a.size(); i++ )
{
y+=height;
g.drawString( a.elementAt(i).toString(), x, y );
}
}
}
//Source file: ApletComanda.java
import java.applet.Applet;
import java.awt.event.ActionListener;
import java.awt.Choice;
import java.awt.TextField;
import java.awt.Button;
import java.util.Properties;
import java.util.Vector;
import java.awt.event.ActionEvent;

public class ApletComanda extends Applet implements ActionListener


{
private Vector a = new java.util.Vector();
public CanvasComanda comanda;
public Choice nume;
public TextField cantitate;
public Button adaugare;
public Button gata;
public Properties preturi;
public void init()
{
setLayout( new java.awt.BorderLayout() );
java.awt.Panel p = new java.awt.Panel();
p.setLayout( new java.awt.FlowLayout());
nume = new Choice();
preturi = new java.util.Properties();
try{
java.net.URL url= new java.net.URL( getDocumentBase(),"preturi.dat");
preturi.load( url.openStream());
}
catch( Exception e ){}
java.util.Enumeration e = preturi.propertyNames();
while( e.hasMoreElements())
nume.addItem( ( String ) e.nextElement());
p.add( nume );
cantitate = new TextField( 5);
p.add( cantitate );
adaugare = new Button("Adaugare");
p.add( adaugare );
adaugare.addActionListener( this );
gata = new Button( "Gata");
p.add(gata );
gata.addActionListener( this );
add( p, "North");

comanda = new CanvasComanda();


add( comanda,"Center");
comanda.setSize(250,150);
comanda.redraw( a );
}
public void actionPerformed(ActionEvent arg0)
{
String command = arg0.getActionCommand();
if( command.equals("Adaugare")){
String itemName = nume.getSelectedItem();
int cant = 0;
double pret = 0.0;
try{
cant = Integer.parseInt( cantitate.getText());
pret = (new Double( preturi.getProperty( itemName ))).doubleValue();
}
catch( NumberFormatException e ){}
a.addElement( new Linie_de_comanda(itemName, cant, pret ));
comanda.redraw( a );
}
}
}

Accesul bazelor de date din Java.


JDBC-Java Database Connectivity
1. Limbajul Java, SQL, CLI
2. Arhitectura JDBC
3. Drivere si manageri de drivere
4. Utilizare JDBC-Exemple
5. Anatomia unei aplicatii JDBC
6. Relatia dintre tipuri SQL si tipuri Java
7. O aplicatie JDBC pe trei nivele
8. Instructiuni preparate
9. Tratarea campurilor speciale
10. Exemple

1. Limbajul Java, SQL si CLI

JDBC este bazat pe doua standarde: SQL (Structured Query Language) si CLI
(X/Open Call Level Interface). CLI este implementat in interfata Microsoft ODBC.
ODBC a fost implementat in limbajul C, deci nu se putea utiliza direct din Java
deoarece s-ar fi stricat portabilitatea acestor aplicatii. O alta problema cu ODBC era
ca fiind scris intr-un limbaj procedural in care caramida de constructie este functia era
mai greu atasarea la Java, care este un limbaj obiectual. Multe functii C din
ODBC returneaza si pointeri void care violeaza caracteristica fundamentala a
limbajului Java, siguranta tipului.

2. Arhitectura JDBC
Interfetele si clasele pentru JDBC se gasesc in pachetul java.sql. Clasele si interfetele
utilizate intr-o aplicatie ce utilizeaza JDBC se gasesc pe figura urmatoare:

O aplicatie JDBC utilizeaza unul sau mai multe drivere din pachetul java.sql care sunt
utilizate de catre clasa DriverManager. Driverele sunt specifice bazelor de date, deci
pentru fiecare tip de baza de date se utilizeaza un driver special. In aceeasi aplicatie
putem lucra cu baze de date diferite, deci implicit si cu mai multe drivere. Putem avea

nevoie de un driver care comunica cu o baza de date Oracle aflata la distanta si de un


altul care reprezinta legatura spre driverul ODBC local si comunica cu un server SQL.
In aplicatii comunicatia cu o baza de date necesita urmatorii pasi:
1. Se apeleaza la DriverManager cerand un driver specific pentru baza de date
2. Driverul specific creaza legatura cu baza de date si returneaza un obiect de tip
Connection
3. Cu ajutorul obiectului de tip Connection se creaza un obiect Statement care
contine si o cerere SQL catre baza de date
4. Obiectul Statement returneaza rezultatele intr-un obiect ResultSet

3. Drivere si manageri de drivere

4. Utilizare JDBC-Exemple

Exemplul urmator ilustreaza structura tipica a unei aplicatii JDBC.


In primul exemplu vom lucru cu o baza de date Access. Numele bazei de date va fi
Inventory, la fel si numele singurei tabele continuta in baza de date.
Structura tabelei Inventory:

Nume_camp Tip_camp Lungime_camp


NAME
Text
40
NumericQUANTITY
20
Real

Sursa Java:
import java.sql.*;
public class SimpleJDBC{
public static void main( String args[]){
try{
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
String databaseName = "jdbc:odbc:Inventory";
Connection
con

=DriverManager.getConnection(databaseName,"username","password");
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("select * from

Inventory");
while( rs.next()){
System.out.println(rs.getString(1)+":"+rs.get
Float(2));
}
}
catch( Exception e ){
e.printStackTrace();
}
}
}

Inainte sa executam programul precedent trebuie sa informam ODBC despre existenta


unei surse de date care va fi Inventory.mdb. Sursa de date o vom denumi tot
Inventory. Dupa ce s-a creat si s-a indexat baza de date se selecteaza din Control
Panel--ODBC32. De aici se trece la pagina System DSN unde se introduce in caseta
Data Source Name "Inventory". Dupa executarea acestor pasi tabela de date va fi
atasata driverului permitand operatii cu aceasta. ODBC este un protocol care asigura

accesul la baze de date utilizate sub s.o. Windows. In exemplul precedent aplicatia
noastra acceseaza direct baza de date. Asemenea aplicatii se numesc aplicatii cu doua
nivele. Intr-o abordare eleganta aplicatiile sunt proiectate pe trei nivele. In cazul
acestor aplicatii clientul lucreaza cu un server care reprezinta un nivel intermediar
intre client si baza de date.
Urmatorul exemplu va lucra cu o baza de date Access continand doua tabele.
Nume baza de date: Universitate.mdb
Nume tabel 1: Catedre
Structura:
CODCATEDRA

Long

DENUMIRE

Text

Indexari: CODCATEDRA

(cheie primara)

Nume tabel 2: Profesori


Structura:
CODPROFESOR

Long

NUME

Text

CODCATEDRA

Long

Indexari: CODPROFESOR

(cheie primara); CODCATEDRA

import java.sql.*;
public class SimpleJDBC{
public static void main( String args[]){
try{
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
String databaseName = "jdbc:odbc:Universitate";
Connection con =
DriverManager.getConnection(databaseName,"username","password");
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("select
Profesori.codprofesor,Profesori.nume,Profesori.codcatedra,Catedre.nume from
Catedre,Profesori where Catedre.codcatedra=Profesori.codcatedra order by
catedre.nume");
while( rs.next()){
System.out.println(rs.getLong(1)+":"+rs.getSt
ring(2)+":"+rs.getLong(3)+":"+rs.getString(4));
}
}
catch( Exception e ){

e.printStackTrace();
}
}
}

5. Anatomia unei aplicatii JDBC

a. Instalarea unui driver


Primul lucru pe care trebuie sa faca o aplicatie care lucreaza cu baze de date este
instalarea unui driver specific bazei de date. Exemple:
Class.forName("com.sybase.jdbc.SybDriver");
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");

Prin apelul acestor metode se va incarca un driver JDBC. In clasa specifica driverului
esista o metoda statica care va inregistra existenta sa cu DriverManager. Dupa
incarcarea driverului trebuie creata legatura cu baza de date. Se ridica o serie de
probleme:

unde se gaseste pe Internet calculatorul caruia apartine baza de date.?


pe ce numar de port asculta RDBMS-ul cererile?

Internetul a rezolvat deja aceasta problema prin introducerea URL-urilor (Uniform


resource Locator) care este format din: protocol//nume_host:port//cale. Pentru JDBC
s-a adaptat aceasta specificatie. Un URL pentru o baza de date ar avea
forma: jdbc:<protocol_secundar>:<nume_secundar>//nume_host:port//nume_baza_
de_date.
b.Crearea conexiunii
La crearea conexiunii pe langa numele bazei de date se vor transmite si numele
utilizatorului precum si parola acestuia. Daca sunt incarcate mai multe drivere pentru
lucrul cu diferite baze de date, atunci se pune problema cum se alege driverul pentru
conexiunea curenta. Clasa DriverManager este responsabila pentru acesta intreband
fiecare driver daca poate realiza legatura cu baza de date specificata prin url. De
exemplu un driver Oracle ar observa imediat ca in exemplul prezentat se lucreaza cu
un alt tip de baza de date si ar refuza cererea. La realizarea conexiunii se creaza un
obiect de tip Connection. De fapt Connection este o interfata, care asigura
transmiterea datelor spre baza de date si obtinerea datelor din baza de date. Interfata
furnizeza metode pentru a obtine informatii despre baza de date, inchid conexiunea cu

baza de date si asculta mesajele sosite de la baza de date.


c. Accesul la baza de date
Interfata Connection contine si metoda createStatement() care ne va furniza un obiect
Statement printr-un apel de urmatoarea forma:
Statement stmt = con.createStatement();

Metodele cele mai importante ale interfetei Statement sunt


urmatoarele: executeQuery(String), executeUpdate(String), execute(String). Aceste
metode se utilizeaza pentru executia codului SQL. MetodaexecuteQuery() executa
comanda SQL si returneaza un obiect de tip ResultSet si se utilizeaza pentru executia
comenziilor SQL de interogare SELECT. Metoda executeUpdate() executa comanda
SQL primita ca parametru si returneaza numarul randurilor tabelei modificate (update
count). Se utilizeaza pentru comenzile SQL de manipularea datelor: INSERT,
UPDATE, DELETE si pentru comenzi de definire a datelor CREATE/DROP TABLE.
In cazul comenzilor de definirea datelor valoarea returnata este 0. Ultima metoda
execute() poate fi privita ca fiind generalizarea celorlaltor doua metode. Se utilizeaza
daca comanda SQL poate returna deodata mai multe rezultate sau nu se cunoaste
rezultatul executiei.
ResultSet rs = stmt.executeQuery("select * from Inventory");

d. Prelucrarea rezultatelor
ResultSet este tot o interfata. Obiectul ResultSet contine rezultatul interogarii bazei de
date, insa pointerul atasat acestei tabele puncteaza inaintea primului rand din tabela.
Acest lucru ne este comod fiindca cu un singur ciclu while putem parcurge rezultatele
obtinute:
while( rs.next()){
System.out.println( rs.getString(1)+":"+rs.getFloat(2));
}

Singurul pericol in asemenea constructii poate fi ca rezultatul interogarii nu produce


nici o linie iar noi avem ceva asemanator cu constructia de mai jos:
ResultSet rs = stmt.executeQuery("A Query...");
int i = rs.getInt(1);

Daca rezultatul interogarii este vid atunci constructia de mai sus va genera
exceptie SQLException.
ResultSet contine metode pentru accesul datelor din rezultat. Astfel
metodele getXXX(int) si getXXX(String) returneaza valoarea dintr-o coloana
specificata prin parametru si linia curenta. In locul XXX se pune un tip predfinit Java
(tip primitiv-ex. int sau clasa de baza-ex. String).

6. Relatia dintre tipuri SQL si tipuri Java

Tip SQL
CHAR
VARCHAR
LONGVARCHAR
NUMERIC
DECIMAL
BIT
TINYINT
SMALLINT
INTEGER
BIGINT
REAL
DOUBLE
BINARY
VARBINARY
LONGVARBINARY
DATE
TIME
TIMESTAMP

Tip JAVA
String
String
String
java.math.BigDecimal
java.math.BigDecimal
boolean
byte
short
int
lonng
float
double
byte[]
byte[]
byte[]
java.sql.Date
java.sql.Time
java.sql.Timestamp

Metoda
getString()
getString()
getString()
getBigDecimal()
getBigDecimal()
getBoolean()
getByte()
getShort()
getInt()
getLong()
getFloat()
getDouble()
getBytes()
getBytes()
getBytes()
getDate()
getTime()
getTimestamp()

7. O aplicatie JDBC pe trei nivele


In exemplele precedente aplicatiile noastre contineau si codul SQL. Vom rescrie
primul exemplu cu baza de date inventory astfel incat vom crea clase speciale pentru
toate operatiile posibile cu acesta tabela. Aplicatiile care au nevoie de operatii cu
aceasta tabela vor utiliza clasele speciale, astfel aceste clase realizand un nivel
intermediar intre baza de date si aplicatia propriu zisa care lucreaza cu datele din
tabela. Aceste clase incapsuleaza logica aplicatiei.

Clasa InventoryItem lucreaza cu o inregistrare din tabela Inventory. Contine exact


doua campuri, tipul acestor campuri coincide cu tipul campurilor din tabela si contine
metode de tip setXXX() care permit modificarea acestor campuri precum si metode de
tip getXXX() pentru returnarea valorilor din aceste campuri.
Clasa InventoryManager va fi cea care contine logica aplicatiei. Constructorul clasei
incarca driverul pentru a realiza legatura cu baza de date, iar celelalte metode permit
operatiile necesare aplicatiilor si anume: ce cantitate exista dintr-un anumit material,
modificarea cantitatii dintr-o materie si verificarea daca dintr-o anumita materie exista
peste o anumita cantitate.
Diagrama de clase:

Sursa Java a aplicatiei:


Fisierul InventoryItem.java:

public class InventoryItem {


String item;
float amount;
public InventoryItem() {
item = "";
amount = 0;
}
public InventoryItem(String s, float a) {
item = s;
amount =a ;
}
public void setAmount(float a) {
amount = a;
}
public float getAmount() {
return amount;
}
public void setItem(String s) {
item = s;
}
public String getItem() {
return item;
}
}
Fisierul InventoryManager.java:
import java.sql.*;
import java.util.Vector;
import java.util.Enumeration;
public class InventoryManager {
Statement stmt;
String databaseName = "jdbc:odbc:Inventory";
public InventoryManager() {
try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
}
catch( Exception e ) {
e.printStackTrace();
}
}

//Verifica daca din materia ingredient avem peste cantitatea amount


public boolean checkInventory(String ingredient, float amount){
try {
Connection con = DriverManager.getConnection(databaseName, "", "");
stmt = con.createStatement();
ResultSet rs = stmt.executeQuery(
"SELECT Quantity FROM Inventory WHERE Ingredient = '"
+ ingredient +"'");
rs.next();
if (amount > rs.getFloat(1))
return false;
else
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}

public boolean checkInventory(Vector ingredients) {


try {
Connection con = DriverManager.getConnection(databaseName, "", "");
stmt = con.createStatement();
Enumeration e = ingredients.elements();
while (e.hasMoreElements()) {
InventoryItem i = (InventoryItem) e.nextElement();
ResultSet rs = stmt.executeQuery(
"SELECT Quantity FROM Inventory WHERE Ingredient = '"
+ i.item + "'");
rs.next();
if (i.amount > rs.getFloat(1))
return false;
}
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}

//Returneaza cantitatea din materia primita ca parametru


public float quantityOnHand(String ingredient)
throws SQLException {
Connection con =DriverManager.getConnection(databaseName, "", "");
stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT Quantity FROM Inventory WHERE
Ingredient = '"
+ ingredient +"'");
rs.next();
return rs.getFloat(1);
}
//Actualizeaza cantitatea din materia ingredient la cantitatea quantity
public void replenish(String ingredient, float quantity)
throws SQLException {
Connection con =
DriverManager.getConnection(databaseName, "", "");
stmt = con.createStatement();
ResultSet rs = stmt.executeQuery(
"SELECT Quantity FROM Inventory WHERE Ingredient = '"
+ ingredient +"'");
rs.next();
stmt.executeUpdate(
"UPDATE Inventory SET Quantity = " +
(rs.getFloat(1) + quantity) +
" WHERE Ingredient = '" + ingredient +"'");
}
}
Fisierul InventoryMain.java:
public class InventoryMain {
public static void main(String args[]){
InventoryManager im = new InventoryManager();
try {
System.out.println("Este cantitatea de zahar mai mare decat 90: " +
im.checkInventory("zahar", 90f));
System.out.println("Cantitatea de zahar este:" +
im.quantityOnHand("zahar"));
im.replenish("zahar", 100f);
System.out.println("Cantitatea de zahar este:" +
im.quantityOnHand("zahar"));

} catch (Exception e) {
e.printStackTrace();
}
}
}

8. Instructiuni preparate
In cazul aplicatiilor care lucreaza cu baze de date este foarte frecventa utilizarea
aceluiasi cod SQL de mai multe ori. RDBMS-urile faciliteaza crearea instructiunilor
preparate, care trebuie create, analizte si optimizate o singura data in baza de date si
dupa aceea pot fi utilizate in aplicatii. JDBC faciliteaza utilizarea instructiunilor
preparate prin clasa PreparedStatement. Aceasta clasa este subclasa clasei
Statement. Clasa PreparedStatement are un constructor care primeste ca parametru un
string reprezentand instructiunea SQL.
PreparedStatement pstmt = con.preparedStatement("SELECT
quantity FROM Inventory WHERE ingredient=?";
Se poate observa ca instructiunea SQL contine si semne de intrebare. Aceste semne de
intrebari reprezinta parametrii interogarii. Inainte de executia propriu-zisa a codului
acesti parametrii pot fi setati. In exemplul precedent am utilizat o
metoda checkInventory( Vector ingredients ) pentru a afla daca din fiecare materie
prima avem cantitatile dorite.
Enumeration e =ingredients.elements();
while( e.hasMoreElements()){
InventoryItem i = (InventoryItem) e.nextElement();
ResultSet rs = stmt.executeQuery( "SELECT quantity FROM Inventory WHERE
ingredient =' " + i.item+" ' ");
rs.next();
if( rs.getFloat(1) < i.amount )
return false;
}
return true;

In acest exemplu pentru fiecare materie prima din vectorul ingredients s-a executat
cate o instructiune SQL, timpul de executie astfel devenind foarte mare. Vom rescrie
aceasta metoda utilizand un obiect de tip PreparedStatement facand ca aplicatia sa
devina mai eficienta.
PreparedStatement pStmt = con.prepareStatement("SELECT Quantity FROM
Inventory WHERE Ingredient =?");
Enumeration e =ingredients.elements();

while( e.hasMoreElements()){
InventoryItem i = (InventoryItem) e.nextElement();
pStmt.setString(1,i.item);
ResultSet rs = stmt.executeQuery();
rs.next();
if( rs.getFloat(1) < i.amount )
return false;
}
return true;

Astfel codul SQL se compileaza o singura data pe partea de baza de date si la fiecare
apel executeQuery() se va executa acel cod precompilat cu parametrii
inlocuiti.Parametrii interogarii sunt setati de catre metodele setXXX() ale
clasei ResultSet. Primul parametru al acestor metode este numarul de ordine al
parametrului din secventa SQL care se inlocuieste, iar al doilea parametru este
valoarea cu care se inlocuieste.
9. Conversie SQL-Java

Tip Java
Java.math.BigDecimal
boolean
byte
short
int
long
float
double
byte[]
java.sql.Date
java.sql.Time
java.sql.Timestamp
String

Tip SQL
NUMERIC
BIT
TINYINT
SMALLINT
INTEGER
BIGINT
REAL
DOUBLE
VARBINARY sau LONGVARBINARY
DATE
TIME
TIMESTAMP
VARCHAR sau LONGVARCHAR

Metoda
setBigDecimal()
setBoolean()
setByte()
setShort()
setInt()
setLong()
setFloat()
setDouble()
setBytes()
setDate()
setTime()
setTIMESTAMP()
setString()

10. Tratarea campurilor speciale


Multe SGBD-uri faciliteaza folosirea campurilor de obicete speciale ( binary large
object - BLOB ). Aceste campuri sunt utilizate pentru stocarea datelor de lungime
variabila care pot fi documente, foi de calcul, imagini, pagini Web etc. JDBC
faciliteaza utilizarea acestor campuri de date. Exemplul urmator va scrie un asemenea

camp de date intr-o baza de date, iar dupa aceea va citi un alt camp de date salvand
rezultatul intr-un fisier. Exemplul nostru va stoca imagini de tip .gif. Ca prim pas vom
crea cu Microsoft Access o baza de date cu urnatoarea structura:
Imagini.mdb cu tabela imagini:
Nume_Camp
COD
NUME
IMAGINE

Tip_Camp
Numeric(10)
Text(30)
OLE Object

Dupa crearea bazei de date sursa de date trebuie sa fie facuta public prin intermediul
ODBC.
Datele in aceasta tabela vor fi introduse de catre program.
Nume clasa: JDBCImages
Date:
-databaseName: String
-con: Connection
-pictures: String[5]
-pStmt1, pStmt2: PreparedStatement
Metode:
+JDBCImages()
+writeRecord( int cod )
+readRecord( int cod, String fileName)
Sursa Java:
import java.io.*;
import java.sql.*;
public class JDBCImages{
String databaseName = "jdbc:odbc:Imagini";
Connection con = null;
String pictures[]={"curs2_fig1.gif","curs2_fig2.gif",
"curs2_fig3.gif","curs2_fig4.gif", "curs2_fig5.gif"};
PreparedStatement pStmt1 = null;
PreparedStatement pStmt2 = null;
public JDBCImages(){
// Incarcare driver - Creare conexiune
try{

Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
con = DriverManager.getConnection(databaseName,"","");
pStmt1 = con.prepareStatement("INSERT INTO imagini
(cod,nume,imagine) VALUES

(?,?,?)");

pStmt2 = con.prepareStatement("SELECT
imagini WHERE cod=?");

imagine

FROM

}
catch( Exception e ){
System.out.println("Eroare constructor");
e.printStackTrace();
}
}
public void writeRecord( int cod )
{
try{
File inFile = new File( pictures[ cod ] );
int flength = (int) inFile.length();
FileInputStream in = new FileInputStream( inFile );
pStmt1.setInt(1,cod);
pStmt1.setString(2,pictures[cod]);
pStmt1.setBinaryStream(3,in,flength);
pStmt1.executeUpdate();
}
catch( Exception e ){
System.out.println("Eroare INSERT");
e.printStackTrace();
}
}
public void readRecord( int cod, String fileName )
{
byte [] picture = new byte[ 1024 ];
try{
pStmt2.setInt(1,cod);
File outFile = new File(fileName);
FileOutputStream out = new FileOutputStream( outFile );
ResultSet rs = pStmt2.executeQuery();
rs.next();

InputStream ins = rs.getBinaryStream(1);


int n;
int s =0;
while( (n=ins.read(picture))>0)
{
out.write( picture,0,n);
s+=n;
}
System.out.println("Total bytes read:
"+Integer.toString(s));
out.close();
}
catch( Exception e ){
System.out.println("eroare SELECT");
e.printStackTrace();
}
}
public static void main( String args[]){
int i;
JDBCImages o = new JDBCImages();
o.writeRecord( 1 );
o.readRecord( 1, "picture1.gif");
}
}

In exemplul precedent constructorul incarca driverul pentru baza de date si realizeaza


conexiunea cu aceasta, dupa care creaza doua instructiuni preparate: una pentru a
insera o inregistrare in baza de date si una pentru a obtine campul imagine din baza de
date. Prima instructiune preparata va fi utilizata de catre metoda writeRecord( int ),
care primind indicele unui element din tabloul pictures insereaza in baza de date o
inregistrare. A doua instructiune preparata este folosita de catre readRecord( int,
String ). Aici primul parametru indica codul inregistrarii care trebuie selectata, iar al
doilea parametru va fi utilizat pentru numele fisierului in care se salveaza datele
obtinute din baza de date.Pentru a scrie intr-un asemenea camp sau a citi din aceasta
se vor utiliza metodele setBinaryStream() respectiv getBinaryStream()ale
clasei ResultSet.
Noutati aduse de JDBC 2.0:

ResultSet-uri derulabile

Daca dorim sa lucram cu ResultSet-uri derulabile trebuie sa utilizam doi


parametri in metodele clasei
Connection, createStatement respectiv prepareStatement:
Statement stmt = con.createStatement(
ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_READ_ONLY);

Intr-un ResultSet derulabil putem utiliza metodele:

Metoda
boolean
boolean
boolean
boolean
boolean
boolean
)

Rezultat
first()
Pozitionarea indicatorului pe prima linie
previous()
Pozitionarea indicatorului pe linia precedenta
next()
Pozitionarea indicatorului pe prima urmatoare
last()
Pozitionarea indicatorului pe ultima linie
absolute( int poz )
Pozitionarea indicatorului pe poztia indicata
relative ( int pozitie_relativa Pozitionarea indicatorului relativ la pozitia
curenta

Toate actualizarile, inserarile si stergerile pot fi facute printr-o singura operatie


cu baza de date utilizand comenzile de tip batch.

Pentru a realiza operatile de ti batch se va utiliza metoda clasei Statement


addBatch. Exemplu de utilizare:
//Creare Statement
Statement stmt = con.CreateStatement();
//Adaugare comenzi
stmt.addBatch("INSERT INTO Catedre (CodCatedra, Denumire) VALUES (5,'Stiinte
Economice')");
stmt.addBatch("INSERT INTO Profesori (CodProfesor, Codcatedra, Nume ) VALUES
(10,2,'Pop Ioan')");
//Executarea comenzilor
int [] updateCounts = stmt.executeBatch();

Metoda executeBatch() returneaza un tablou de elemente, continand randurile care au


fost afectate prin comanda data. Comenzile dintr-un batch se executa in ordinea in
care au fost asezate in batch. Daca vreo comanda este incorecta atunci se genereaza
exceptia BatchUpdateException si se opreste executarea comenzilor din batch.
Batch-urile pot fi utilizate si in cazul instructiunilor preparate.

PreparedStatement pstmt = con.prepareStatement("DELETE FROM Catedre WHERE


Denumire=?");
Enumeration e =v.elements();
while( e.hasMoreElements()){
pstmt.setString( 1, {String) e.nextElement());
pstmt.addBatch();
}
int [] updateCounts = pstmt.executeBatch();

Tipuri de date SQL 3.0. Obiectele Java pot fi stocate in baze de date.

11. Exemple:
1. Sa scrie o aplicatie care sa permita interogarea oricarei baze de date. Rezultatele
selectiei se vor afisa intr-un element de control TextArea. Interfata aplicatiei sa aiba
urmatoarea forma:

Sursa Java:
import java.awt.*;
import java.awt.event.*;
import java.sql.*;

public class TestJdbc extends Frame implements ActionListener{


String Driver=null;
String DataBase = null;
String UserName = null;
String Password
String SQL= null;

= null;

TextField tfDriver;
TextField tfDataBase;
TextField tfUserName;
TextField tfPassword;
TextField tfSQL;
Button b;
TextArea

ta;

// Constructorul creaza interfata aplicatiei si inregistreaza


receptorii
// evenimentelor la sursele acestora
public TestJdbc(){
setTitle("Jdbc Application");
setLayout( new FlowLayout());
Label l1 = new Label("Driver");
add( l1 );
tfDriver
=new TextField(60);
add(tfDriver);
Label l2 = new Label("DataBase URL");
add( l2 );
tfDataBase =new TextField(60);
add(tfDataBase);
Label l3 = new Label("User name:");
add( l3 );
tfUserName =new TextField(60);
add(tfUserName);
Label l4 = new Label("Password:");
add( l4 );
tfPassword =new TextField(60);
add(tfPassword);

Label l5 = new Label("SQL:");


add( l5 );
tfSQL

=new TextField(60);

add(tfSQL);
b= new Button( "Executa");

add(b);
b.addActionListener( this);
ta= new TextArea( 10,60);
add(ta);
addWindowListener( new MyWindowAdapter());
}
//Prelucrarea datelor din formularul prezentat in interfata
aplicatiei
private void processData(){
Driver = tfDriver.getText();
if( Driver.equals(""))
Driver="sun.jdbc.odbc.JdbcOdbcDriver";
DataBase =tfDataBase.getText();
if( DataBase.equals(""))
DataBase="jdbc:odbc:Demo";
UserName = tfUserName.getText();
Password = tfPassword.getText();
SQL = tfSQL.getText();
if ( SQL.equals(""))
SQL="Select * From Catedre";
}

// Tratarea evenimentului generat prin apasarea butonului "Executa"


// Se incarca driverul pt. baza de date
// Se creaza conexiunea cu baza de date
// Se creaza obiectul de tip Statement, care va executa codul SQL
//
public void actionPerformed( ActionEvent e ){
ta.setText("");
processData();
try{
Class.forName( Driver );
Connection con =
DriverManager.getConnection(DataBase,UserName,Pas
sword);
Statement

stmt= con.createStatement();

// Se obtin rezultatele selectiei


ResultSet

rs = stmt.executeQuery( SQL );

// Informatii (metadatele) despre selectie


// Se poate obtine atat numarul coloanelor
// din selectie, cat si tipurile acestor
// coloane
ResultSetMetaData rsmd = rs.getMetaData();
// Prelucrarea rezultatelor
int numCols = rsmd.getColumnCount();
while( rs.next() )
{
String record="";
for (int i=1; i<=numCols; i++)
{
int dataType = rsmd.getColumnType( i );
record=record+getField(rs,dataType, i)+" ";
}
ta.append( record+"\n" );
}
}
catch( SQLException ex1 ){
System.out.println(ex1.toString());
}
catch( ClassNotFoundException ex2 ){
System.out.println(ex2.toString());
}
}

private String getField(ResultSet rs, int dataType, int col)


throws SQLException
{
switch(dataType) {
case Types.DATE:
java.sql.Date date = rs.getDate(col);
return date.toString();

case Types.TIME:
java.sql.Time time = rs.getTime(col);
return time.toString();
case Types.TIMESTAMP:
java.sql.Timestamp timestamp = rs.getTimestamp(col);
return timestamp.toString();
case Types.CHAR:
case Types.VARCHAR:
case Types.LONGVARCHAR:
String str = rs.getString(col);
return str;
case Types.NUMERIC:
case Types.DECIMAL:
java.math.BigDecimal numeric = rs.getBigDecimal(col, 10);
return numeric.toString();
case Types.BIT:
boolean bit = rs.getBoolean(col);
return (new Boolean(bit)).toString();
case Types.TINYINT:
byte tinyint = rs.getByte(col);
return (new Integer(tinyint)).toString();
case Types.SMALLINT:
short smallint = rs.getShort(col);
return (new Integer(smallint)).toString();
case Types.INTEGER:
int integer = rs.getInt(col);
return (new Integer(integer)).toString();
case Types.BIGINT:
long bigint = rs.getLong(col);
return (new Long(bigint)).toString();
case Types.REAL:
float real = rs.getFloat(col);
return (new Float(real)).toString();
case Types.FLOAT:
case Types.DOUBLE:

double longreal = rs.getDouble(col);


return (new Double(longreal)).toString();
case Types.BINARY:
case Types.VARBINARY:
case Types.LONGVARBINARY:
byte[] binary = rs.getBytes(col);
return new String(binary);
}
return "";
}

// Pt. tratarea evenimentului WindowClosing


class MyWindowAdapter extends WindowAdapter{
public void windowClosing( WindowEvent e ){
System.exit(0);
}
}

public static void main( String args[]){


TestJdbc frame = new TestJdbc();
frame.setBounds(1,1,300,300);
frame.setVisible( true );
}
}

Servleturi si Java Webserver

1.
2.
3.
4.
5.

Introducere
Anatomia unui servlet HTTP
Instalarea servletului in WebServer
Arhitectura pachetelor javax.servlet si javax.servlet.http
Exemple

1. Introducere
Webul a trecut printr-o transformare rapida. Paginile statice HTML au fost schimbate
cu pagini generate in mod dinamic. Avantajul acestor pagini este ca informatia
continuta in ele poate reflecta de exemplu continutul unei magazii cu stocul in
continua schimbare. Crearea acestor pagini necesita insa multa munca de programare.
Java cu ajutorul apleturilor ajuta la crearea aplicatiilor pe partea clientilor. Pe partea
serverelor s-au introdus servleturile. Servletul este un mecanism de generarea acestor
pagini dinamice HTML, oferind deservirea rapida si eficienta a clientilor.
Inaintea servleturilor partea de server a aplicatiilor client/server era ajutata de
scripturi CGI (Common Gateway Interface). CGI permitea si evaluarea formularelor
trimise de catre clienti.
Comparatie CGI - Servlet
Scripturile CGI sunt mai putin eficiente decat servleturile. In cazul utilizarii CGI
pentru deservirea unui client se creaza un proces nou in care se executa scriptul CGI.
Scriptul genereaza pagina HTML si trimite clientului. Crearea unui proces nou este o
operatie costisitoare din punctul de vedere al sistemului de opearare.
Servletul face acelasi lucru ca un script CGI, insa servletul se ruleaza pe un fir de
executie separat al procesului webserver. Crearea unui fir de executie este mult mai
eficienta decat crearea unui proces nou. Pe langa eficienta servleturile mai au o
caracteristica impotantanta, securitatea. Firele de executie sunt create de catre masina
virtuala Java si poseda toate facilitatiile oferite de aceasta din punctul de vedere al
securitatii.
Exemplul urmator de servlet:genereaza in mod dinamic o pagina HTML care contine
data si ora serverului si un text aleator.

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.Date;
import java.lang.Math;
public class PhraseServlet extends HttpServlet {
String [] adjective = {"fericit",
"nefericit",
"suparat",
"nervos",
"indurerat"};
String [] adverbe = {"foarte",
"usor",
"putin",
"total"};
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
Date now = new Date();
res.setContentType("text/html");
PrintWriter out = res.getWriter();
out.println("<HTML><HEAD><TITLE>Phrase Servlet</TITLE></HEAD>");
out.println("<BODY BGCOLOR=#FFFFFF><CENTER><P>");
out.println("Astazi ");
out.println(now.toString());

out.println(" acest webserver se simte

");

out.println(adverbe[(int) (Math.random() * adverbe.length)] + " " );


out.println(adjective[(int) (Math.random() * adjective.length)] + ".");
out.println("</P></CENTER></BODY></HTML>");
out.flush();
out.close();
}
}

2. Anatomia unui servlet HTTP


Pachetul javax.servlet ne ofera un cadru generic pentru crearea serverelor. Contine
API-uri pentru prelucrarea cererilor si deservirea clientilor. Un alt pachet,
javax.servlet.http contine implementarea servleturilor utilizate in cazul webserverelor
pentru generarea paginilor HTML.

Un servlet HTTP pentru a putea realiza o anumita sarcina trebuie sa redefineasca


metoda doGet(). Metoda este apelata de catre webserver ori de cate ori serverului ii
este adresata o cerere HTTP care contine un GET <url>. Metoda este definita in clasa
HttpServlet pe langa metodele: doDelete(), doOptions(), doPost(), doTrace(). De
acum incolo ne vom referi la aceste metode in mod generic prin doXXX(). Aceste
metode au doi parametri, unul de tip ServletRequest si unul de tip ServletResponse.
Cele doua clase contin metode si variabile care permit comunicare servletului cu
webserverul si pot genera exceptiile ServletException si IOException:

public void doGet( HttpServletRequest req,


HttpServletResponse res) throws ServletException,
IOException{...}
Clasa ServletRequest contine toate informatiile necesare servletului pentru a intelege
cererea si a putea raspunde la aceasta. Contine informatii referitoare la calculatorul
caruia trebuie sa raspunda.
Clasa ServletResponse contine metode care permit crearea si trimiterea raspunsului.
Astfel cu ajutorul metodei setContentType( String) se stabileste tipul datelor care se
trimit inapoi. Dintre tipurile posibile amintim: text/html, text/plain. O alta metoda
importanta este getWriter(). Metoda returneaza o referinta de tip PrintWriter, care
este un flux de iesire prin care se trimite raspunsul. Aceasta metoda se utilizeaza daca
servletul trebuie sa trimita un continut de tip text si metoda getOutputStream() se
utilizeaza daca se trimit date binare.

3. Instalarea servletului in WebServer


Servletul trebuie instalat intr-un server care permite lucrul cu servleturi. Java
Webserver de la Sun ne ofera aceasta facilitate. Servletul poate fi instalat si fara
repornirea serverului. In general un servlet poate fi incarcat din trei surse:
din CLASSPATH
din catalogul servlets
dintr-un URL
Pentru a putea instala servletul PhraseServlet va trebui sa copiem fisierul
PhraseServlet.class in catalogul servlets al softului JavaWebserver.
In JavaWebserver avem la dispozitie o serie de apleturi de administrare care se vor
utiliza la instalarea servletului nostru. Aceste apleturi se gasesc la
adresa http://<nume_host>:9090/. La accesarea acestui URL apare apletul admin:

Aici vom introduce atat la nume cat si la parola cuvantul "admin". Dupa logare apare
urmatoarea pagina:

Din lista se alege "Web Service" si se apasa butonul "Manage". Dupa alegerea acestui
buton apare urmatoarea pagina:

In aceasta pagina se completeaza casetele Description si Class Name asa cum se vede
pe figura de dinainte. Alegand optiunea Load at Startup servletul se va incarca la
fiecare pornire al webserverului. Dupa completarea casetelor se alege butonul Save
pentru a salva optiunile selectate. Dupa aceste reglaje servletul nostru poate accesat la
adresa: http://<nume_calculator>:<port>/servlet/PhraseServlet.
Putem atasa si aliasuri servletului nostru. Aliasul se ataseaza prin alegerea
butonului Setup din bara de instrumente. Apare pagina urmatoare:
Completand casetele Alias si Servlet Invoked si salvand optiunile vom putea accesa
servletul nostru la adresa: http://<nume_calculator>:<port>/PhraseServlet.html.
Daca serverul rezolva concomitent doua cereri de acelasi tip, atunci trebuie apelat
acelasi servlet. Servleturile sunt rulate pe fire de executie diferite, fiecare avand cate o
copie de ServletRequest si ServletResponse, astfel neputand amesteca parametrii I/E.
Serverele pot avea o arhitectura secventiala sau una paralela. Daca dorim sa
implementam una cu arhitectura secventiala atunci servletul trebuie definit a.i. sa
implementeze interfata SingleThreadModel.
public class MyServlet extends HttpServlet implements SingleThreadModel{
}

Java Webserver este un server de capacitate medie, deci se poate utiliza in cazul
serverelor care nu sunt prea frecvent utilizate. Exista si alte webservere care lucreaza
cu servleturi: Netscape Enterprise Server, Microsoft IIS, Apache Web Server

4. Arhitectura pachetelor javax.servlet si javax.servlet.http


Pachetul javax.servlet ne ofera clase si interfete pentru scrierea servleturilor.
Principala interfata definita in acest pachet este interfata Servlet. Toate servleturile
implementeaza aceasta interfata, cel mai des prin extinderea clasei HttpServlet.
Interfata Servlet declara metode care gestioneaza comunicarile cu toti clientii. In
momentul cand un servlet accepta conexiunea cu un client, primeste si doua obiecte:

Un obiect ServletRequest, care este responsabil pentru comunicarea


client--->server
Un obiect ServletResponse, care este responsabil pentru comunicarea inversa
server---> client

Interfata ServletRequest permite servletului urmatoarele:

Informatii despre parametrii primiti de la client, protocolul utilizat de catre


client, numele hostului de la care s-a acceptat cererea.
Un flux de intrarea ServletInputStream. Servletul utilizeaza acest flux de intrare
pentru citirea datelor de la clienti . Clientii utilizeaza metode ca PUT si POST
ale protocolului HTTP.

Interfata ServletResponse declara metode prin care servletul poate trimite raspunsuri
la cererile clientilor.

Permite stabilirea lungimii raspunsului precum si tipul MIME al acestuia.


Un flux de iesire ServletOutputStream si unul Writer prin care servletul va
trimite raspunsul la cerere.

Interactiuni cu clientii
Un servlet HTTP trateaza cererile clientilor cu ajutorul metodei service(). Metoda
service() este cea care apeleaza metoda doGet() pentru prelucrarea cererii.

Cereri si raspunsuri
Tratarea cererilor GET si POST se face cu ajutorul urmatoarelor metode:
doGet, pentru tratarea cererilor GET, GET conditionat si HEAD
doPost, pentru tratarea cererilor POST
doPut, pentru tratarea cererilor PUT
doDelete, pentru tratarea cererilor DELETE
Implicit aceste metode returneaza eroarea BAD_REQUEST (400) afisata de catre
aplicatia client (programul de navigare).
Deservirea clientilor
Servleturile sunt capabile pentru deservirea clientilor in mod concurent. Daca
deservirea clientilor necesita accesul unor resurse partajate atunci accesul acestor
resurse trebuie sincronizate.
Daca dorim deservirea unui singur client la un moment dat, atunci servletul nostru
trebuie sa implementeze interfata SingleThreadModel pe langa extinderea
clasei HttpServlet. Implementarea acestei interfete nu necesita scrierea unor metode
suplimentare, asigura deservirea unui singur client la un moment dat.
public class MyServlet extends HttpServlet
implements SingleThreadModel {
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
...
}
...
}

Prelucrarea cererii
Metode clasei HttpServletRequest

Enumeration getParameterNames(),

returneaza numele tuturor parametrilor

continute in pagina
Exemplu:
void doGet (HttpServletRequest req, HttpServletResponse res){
String nume, valoare;
String[] params = req.getParameterNames();
while (params.hasMoreElements()) {
nume

= (String) params.nextElement();

valoare = req.getParameter(nume);
//Prelucrarea parametrului
}
//
}

String getParameter( String nume ),

returneaza valoarea parametrului cu

numele specificat
Exemplu:
<INPUT NAME="Nume" SIZE=30></INPUT>, defineste un camp text care
permite introducerea unui text de lungime maxima 30. Obtinerea valorii introduse in
acest camp text se poate obtine prin req.getParameter("Nume").
.

String [] getParameterValues( String

nume),

daca parametrul poate avea

mai multe valori

BufferedReader getReader(),

ServletInputStream getInputStream(),

pentru a obtine date de tip text de la client


pentru a obtine date binare de la client

Observatie:
In prelucrarea unei cereri nu se poate utiliza concomitent metodele de tip
getParameter si metodele getReader si getInputStream.
Trimiterea raspunsului
Un obiect HttpServletResponse pune la dispozitie doua cai pentru trimiterea
datelor catre client:

Writer getWriter()
ServletOutputStream getOutputStream()

Odata cu inchiderea fluxului de date se trimit datele scrise in flux clientului.


Inainte de a scrie date in fluxul de iesire trebuie setat tipul de date pentru trimitere prin
metoda setContentType(String).
Exemplu:
res.setContentType("text/html");
Ciclul de viata al unui servlet

Servleturi de baza
Java Webserver este implementat cu ajutorul servleturilor de baza. In primul
exemplu fara sa stim am utilizat deja servletul de baza invoker la incaracarea
servletului PhraseServlet. Un alt servlet de baza este ssinclude. Acest tip de servlet se
utilizeaza pentru pagini HTML cu includeri pe partea serverului (.shtml).
Urmatorul exemplu servlet primeste intrarea dintr-o pagina HTML care contine
si un formular si utlizeaza aceste date pentru generarea raspunsului. Raspunsul va fi
tot o pagina HTML.
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class FormServlet extends HttpServlet
{
public void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException
{
PrintWriter out = null;
try {
res.setContentType("text/html");
out = res.getWriter();
out.println(
"<HTML><HEAD><TITLE>FormServlet output</TITLE></HEAD>");
out.println("<BODY BGCOLOR=#FFFFFF><P>");

// Se prelucreaza parametrul starea emotionala


String [] emot = req.getParameterValues("emotion");
if (emot != null && emot[0].length() != 0) {
out.println("Astazi va simtiti " + emot[0] + ".");
} else {
out.println("N-ati scris nimic. Va simtiti bine?");
}
out.println("<BR><BR>");
// Se verifica care dintre zile
// a fost bifat in formular
String [] days = req.getParameterValues("days");
if (days != null) {
out.println("De obicei va simtiti bine in urmatoarele
zile:<BR><UL>");
for (int i = 0 ; i < days.length; i++) {
out.println("<LI>" + days[i] + "</LI>");
}
out.println("</UL>");
} else {
out.println("N-ati ales nici o zi. Sunteti nefericita?");
}
} catch(Exception e) {
e.printStackTrace();
out.println(e);
}
out.println("</BODY></HTML>");
out.flush();
out.close();
}
}

Pentru prelucrarea parametrilor primiti de la client se utilizeaza


metodele: getParameterNames() si getParameterValues( String ). A doua metoda
returneaza un tablou de tip String astfel putand trata parametrii cu o singura valoare
returnata cat si parametrii cu mai multe valori returnate
Formularul pe care prelucreaza servletul arata in modul urmator:

Exemplul precedent trebuie facut public in Java Webserver, iar dupa aceea vom scrie
un mic fisier HTML care sa contina formularul si la apasarea butonului sa trimita
rezultatele din formular servletului.
<HEAD>
<TITLE>sURVEY</TITLE>
</HEAD>
<BODY>
<FORM method=POST ACTION="/servlet/FormServlet" >
<BR><BR>Cum va simtiti astazi?<BR>
<BR><input type=text name=emotion>
<BR><BR>In care dintre urmatoarele zile sunteti fericit?<BR>
<BR>Luni<INPUT TYPE=checkbox NAME=days VALUE=Luni>
<BR>Marti<INPUT TYPE=checkbox NAME=days VALUE=Marti>
<BR>Miercuri<INPUT TYPE=checkbox NAME=days VALUE=Miercuri>
<BR>Joi<INPUT TYPE=checkbox NAME=days VALUE=Joi>
<BR>Vineri<INPUT TYPE=checkbox NAME=days VALUE=Vineri>
<BR>Sambata<INPUT TYPE=checkbox NAME=days VALUE=Sambata>
<BR>Duminica<INPUT TYPE=checkbox NAME=days VALUE=Duminica>
<BR><BR><INPUT TYPE=submit><INPUT TYPE=reset>
</FORM>
</BODY>
</HTML>

Apleturi
1.
2.
3.
4.
5.

Crearea apleturilor si executia acestora


Structura clasei Applet. Tag-ul htmlAPPLET
Comunicarea intre aplet si cadrul de executie al acestuia
Mecanismul desecuritate Java referitor la apleturi
Lucrul cu imagini si sunete

1. Creare si executie
Un apleteste un program mic care nu se executa sinestatator ci este nevoie de o
altaaplicatie pentru a-l executa. In general apleturile sunt executatede
catrenavigatoare. Clasa Applet este definita in pachetul java.applet impreuna
cualte interfete necesare pentru a realiza comunicatia intre aplet simediul sau de
executie. Un aplet este de fapt o fereastra cu o serie de metodeutilizate de catre
contextul apletului pentru a initializa,a starta respectiva opri apletul.
Contextul(cadrul) apletului este o aplicatie responsabila pentru a incarca si a rula
apletul. De exemplu un navigator poate fi un cadru de executie pentruun
aplet. Ierarhia de clase din care face parte clasaApplet este redatain figura urmatoare.
Totodata pe figura apare si clasa pentru primul nostruaplet, HelloWeb:

Pasii necesari pentru crearea unui aplet:


1. Editarea codului sursa
//Sursa: HelloWeb.java
public class HelloWeb extends java.applet.Applet{
public void paint( java.awt.Graphics gc ){
gc.drawString("HelloWeb!", 125, 95 );
}
}

2. Compilarea codului sursa


javac HelloWeb.java

Compilarea produce fisierul HelloWeb.class. Pentru a-l executa avem nevoie de un


fisier HTML care sa contina tagul APPLET cu valoareaHelloWeb.class.
3. Executia apletului
3.1 Se creaza fisierul HTML HelloWeb.html
<html>
<body>
<applet code=HelloWeb width=300 height=200></applet>
</body?
</html>

3.2 Se incarca intr-un navigator fisierul HelloWeb.html

2. Structura claseiApplet
void

destroy()

-Se apeleaza de catre programul care executa apletul pentru a distruge toate resursele
alocate pentru executia acestuia.
AppletContext getAppletContext()

-Returneaza o referinta la cadrul de executie, dandu-i posibilitatea apletului de a


interoga si a afecta cadrul de executie
String

getAppletInfo()

-Returneaza informatii despre aplet


URL

getCodeBase()

-Returneaza adresa la care se gaseste codul apletului (fisierul .class)


URL

getDocumentBase()

-Returneaza adresa la care se gaseste fisierul HTML in care este inclus codul
apletului
String

getParameter(String name)

-Returneaza valoarea parametrului cu numele name


void

init()

-Navigatorul apeleaza imediat dupa incarcarea codului apletului. Deobicei in aceasta


metoda se adauga componentele grafice pe suprafata apletului.
boolean isActive()

-Determina daca apletul este sau nu activ


void

resize(Dimension d)

-Cere de la navigator redimensionarea suprafetei apletului


void

resize(int width, int height)

-Cere de la navigator redimensionarea suprafetei apletului

void

showStatus(String msg)

-Cere de la navigator afisarea unui text in bara de stare


void

start()

-Este apelat de catre navigator imediat dupa init() pentru startarea apletului, respectiv
ori de cate ori se revine la pagina in navigator.Metoda este folosita si pentru pornirea
firului de executie propriu apletului.
void

stop()

-Este apelat de catre browser pentru oprirea executiei apletului. Se apeleaza ori de cate
ori se trece la o alta pagina HTML in navigator sause iconifica fereastra navigatorului.
Pe langa atributele CODE, WIDTH si HEIGHT tag-ul APPLET poate sacontina o
serie de alte atribute:
< APPLET
[ CODEBASE = codebaseURL ]
CODE = appletFile
[ ARCHIVE = archivesList ]
[ ALT = alternateText

[ NAME = appletInstanceName ]
WIDTH = pixels
HEIGHT = pixels
[ ALIGN = alignment ]
[ VSPACE = pixels ]
[ HSPACE =pixels ]
>
[<PARAM NAME = appletParameter1 VALUE = value >]
[<PARAM NAME = appletParameter1 VALUE = value >]
...
</APPLET>

CODEBASE: permite includerea unui aplet aflat intr-un alt catalog decatcel in care se
afla fisierul HTML respectiv a unui aplet aflat pe un althost
ARCHIVE: Permite utilizrea fisierelor comprimate. Inainte de executia apletului,
navigatorul aduce codul apletului. Daca pe parcursul executiei apletului este nevoie si
de alte clase de pe server, atunci se vor incarca si acestea astfel incetinind executia
apletului. Pentru a evita acest lucru se poate utiliza un singur fisier comprimat care sa
contina toate clasele de care este nevoie. In acest caz inaintea incarcarii apletului JVM
aduce arhiva si numai dupa aceea se trece la executia programului. Pentru arhivarea
claselor se poate utiliza utilitarul jar

ALT: Prin acest atribut se poate specifica un text pe care browserul sa-l afiseze in
cazul in care navigatorul nu este compatibil Java
NAME: Prin acest atribut se poate atribui un nume apletului
ALIGN, VSPACE, HSPACE: Sunt atribute pentru dispunerea apletului inpagina
HTML
PARAM: Se utilizeaza pentru transmiterea argumentelor apletului. Sunt similare cu
argumentele liniei de comanda.
Exemple:
<PARAM NAME=nume VALUE=valoare>
<PARAM NAME="dimensiune" VALUE="10">

3. Comunicarea intre aplet si cadrul de executie al acestuia


Apletul comunica cu browserul prin:
-parametrii apletului:

definirea acestora se face prin tagul HTML


<PARAM NAME="parametru" VALUE="valoare">
citirea de catre aplet se face prin metoda getParameter(String

name )

-transmiterea unor mesaje browserului


Aici avem doua categorii de mesaje, cele definite in clasa Applet si celedefinite in
interfata AppletContext

Prin metoda showStatus( String status), cere de la browser afisareaunui


mesaj in fereastra de stare a browserului.
Exemplu: showStatus("Un mesaj in bara de stare");

Metoda getCodeBase()returneaza locatia la care segaseste apletul, iar


metoda getDocumentBase()returneaza adresa paginiiin care se afla apletul.

Metoda showDocument( URL url ) cere browserului incarcarea unei noi pagini
in pagina curenta, iar metoda showDocument( URL url,Stringname ) specifica si
cadrul de afisaj. Parametrul name poate aveaunadin urmatoarele valori:
"self":

afisaeaza documentul in frame-ul curent

"_parent":

afiseza documentul in frame-ul parinte

"_top":

afiseaza documentul in frame-ul cel mai curent

"_blank":

afiseaza documentul intr-o fereastra noua

Navigatorul poate sa ignore atat showStatus() cat si showDocument().


Exemple pentru apelul metodei showDocument( URLurl ):
getAppletContext().showDocument("http://www.uttgm.ro") ;
getAppletContext().showDocument(getCodeBase(),"Demo.html");
getAppletContext().showDocument(getDocumentBase(),"AltDemo.html");

Exemple pentru apelul metodei showDocument( URL url , name):


getAppletContext().showDocument("http://www.uttgm.ro","self")

getAppletContext().showDocument("http://www.uttgm.ro","_blank")

Primul exemplu afiseaza o pagina HTML specificat printr-un URL absolut, al doilea
afiseaza un document HTML aflat in acelasi catalog cu sursa apletului, iar al treilea
exemplu incearca afisarea unei pagini HTML aflat in acelasi catalog cu pagina care
contine apletul
Urmatoarele doua metode se utilizeaza pentru comunicarea intre apleturile unei
aceleasi pagini HTML. Comunicarea intre apleturi se realizeaza la fel ca si
comunicarea intre oricare tipuri de obiecte. Dupa ce un aplet obtine referinta unui alt
aplet, poate sa trimita mesaje acelui aplet.

Metoda getApplets() returneaza o colectie detip Enumeration care contine


toate apleturile disponibiledin pagina in carese afla apletul curent. Astfel
apleturile din cadrul aceleasi pagini pot comunica.
Metoda getApplet( String name ) returneaza o referinta la apletul cu numele
name.

Exemplu de comunicare intre apleturi:


Construim o pagina HTML in care avem doua apleturi. Primul aplet asteapta
introducerea unui text intr-o caseta text si in momentul apasarii butonului Send trimite
celui de al doilea aplet din pagina.

Diagrama de clasa:

Sursa Java:
//Source file: Applet1.java
import java.applet.Applet;
import java.awt.event.ActionListener;
import java.awt.TextField;
import java.awt.Button;
import java.awt.event.ActionEvent;
public class Applet1 extends Applet implements ActionListener
{
public TextField tf;
public Applet2 a;
public Button b;
public Applet1()
{
}
public void init()
{
tf = new TextField( 30 );

add( tf );
b = new Button("Send");
add( b );
b.addActionListener( this );
a = (Applet2)getAppletContext().getApplet("APPLET2");
}
public void actionPerformed(ActionEvent arg0)
{
a.write( tf.getText());
}
}
//Source file: Applet2.java
import java.applet.Applet;
import java.awt.Graphics;
public class Applet2 extends Applet
{
private String string = null;
public Applet2()
{
}
public void paint(Graphics g)
{
if( string != null )
g.drawString(string, 10, 10 );
}
public void write(String s)
{
string = s;
repaint();
}
}

4. Mecanismulde securitate Java referitor la apleturi


Ce nu poate sa faca un aplet:
1. nu poate citi sau scrie fisiere de pe masina pe care se executa
2. nu poate sterge sau modifica fisiere de pe masina pe care se executa

3.
4.
5.
6.

nu poate citi anumite proprietati sistem


nu poate executa programe pe masina pe care se executa
nu poate deschide o conexiune de retea decat cu masina depe care a fost adus
nu poate incarca biblioteci sau metode native

Fiecare browser are un SecurityManager care implementeaza politica de securitate, iar


in momentul in care se incearca violarea drepturilor, acest SecurityManager arunca o
exceptie SecurityException

5. Lucrul cu imagini si sunete


Lucrul cu fisiere de tip sunet:
Pentru a incarca un fisier de tip sunet, apletul apeleaza metoda getAudioClip( URL
url), unde fisierul sunet este specificat prin parametrul URL.Metoda returneaza o
referinta la clasa AudiClip din pachetul java.applet.
AudioClip sound = getAudioClip( getDocumentBase(),"spacemusic.au");

Clasa AudiClip contine trei metode:


play(): executa clipul audio
loop(): executa clipul audio intr-un ciclu infinit
stop(): opreste executia clipului audio
Lucrul cu imagini:
Incarcarea unui fisier imagine se face cu unul dintre urmatoarele metode:
public Image getImage(URL url);

Returneaza un obiect de tip imagine. Parametrul url trebuie sa reprezinte unul absolut.
public Image getImage(URL url, String name);

Returneaza un obiect de tip imagine specificat printr-un URL absolut si numele unei
resurse realativ la url-ul specificat.
Exemplu demonstrativ:
In exemplul urmator veti putea utiliza la urmatoarele:

afisarea unui text in bara de stare: se introduce mesajul in textbox si se


selecteaza din lista showStatus

afisarea unui alt document HTML: se introduce URL-ul in textbox si se


selecteaza din lista showDocument
desenarea pe o tabla de desen ( cea cu culoarea verde)si stergerea acestuia cu
butonul Clear. Desenarea se face cu mouse-ul sieste "freehand".

Desenarea se realizeaza tratand doua tipuri de evenimente cu mouse-ul, MousePressed


si MouseDragged. Apletul este format din doua clase, o clasa pentru apletul propriuzis DemoApplet si o clasa pentru tabla de desenare DrawPad . Clasa DemoApplet
trateaza evenimentele de tip ActinEvent, adica cele cu butoanele, iar DrawPad-ul, care
este de fapt un container derivat din Canvas, trateaza evenimentele cu mouse-ul. In
clasa DrawPad se definesc dou clase incuibate, dar publice, de tip adaptor, pentru
tratarea evenimentelor. Inregistrarea receptorilor se face in modul urmator:
dp = new DrawPad();
panel.add("Center", dp );
dp.addMouseMotionListener( dp.new MyMouseMotionAdapter() );
dp.addMouseListener( dp.new MyMouseAdapter() );

Sursa Java:
//Source file:DrawPad.java

import java.awt.event.MouseMotionAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseAdapter;
import java.awt.Canvas;
import java.awt.Graphics;
import java.awt.Image;
public class DrawPad extends Canvas
{
private int xpos;
private int ypos;
private int oxpos;
private int oypos;
private Graphics drawGr;
private Image drawImg;
public DrawPad()
{
setBackground( java.awt.Color.green );
}

public void paint(Graphics g)


{
if( drawImg == null )
{
drawImg = createImage( getWidth(),getHeight() );
drawGr = drawImg.getGraphics();
}
g.drawImage(drawImg, 0, 0 , null );
}
public void update(Graphics g)
{
paint( g );
}
public void clear()
{
drawGr.clearRect(0,0, getWidth(), getHeight());
repaint();
}

public class MyMouseAdapter extends MouseAdapter


{
public MyMouseAdapter()
{
}
/**
@roseuid 3A5C0B1D02A8
*/
public void mousePressed(MouseEvent e)
{
oxpos= e.getX();
oypos= e.getY();
}
}
public class MyMouseMotionAdapter extends MouseMotionAdapter
{
public MyMouseMotionAdapter()
{
}
public void mouseDragged(MouseEvent e)
{
xpos = e.getX();
ypos = e.getY();
if( drawGr != null )
{
drawGr.drawLine(oxpos, oypos, oxpos=xpos, oypos=ypos);
repaint();
}
}
}
}
//Source file: DemoApplet.java
import java.applet.Applet;
import java.awt.event.ActionListener;
import java.awt.Choice;

import java.awt.TextField;
import java.awt.Button;
import java.awt.Panel;
import java.awt.event.ActionEvent;
public class DemoApplet extends Applet implements ActionListener
{
public Choice operation;
public TextField parameter;
public Button doIt;
public Button audioButton;
public Panel panel;
public Button clearButton;
public Panel p;
public DrawPad dp;

public void init()


{
String oplist[]={"showStatus", "showDocument"};
setLayout( new java.awt.GridLayout( 2, 1 ));
p = new Panel ();
add( p );
p.setLayout( new java.awt.FlowLayout());
operation = new Choice();
for(int i=0; i<oplist.length; i++ )
operation.add( oplist[ i ] );
p.add( operation );
parameter = new TextField(50);
p.add( parameter);
doIt = new Button("Do It");
p.add( doIt );
doIt.addActionListener( this );
audioButton = new Button("Play Audio");
p.add( audioButton );
audioButton.addActionListener( this );
panel = new Panel();
panel.setLayout( new java.awt.BorderLayout());
add( panel );
dp = new DrawPad();
panel.add("Center", dp );
dp.addMouseMotionListener( dp.new MyMouseMotionAdapter() );

dp.addMouseListener( dp.new MyMouseAdapter() );


clearButton = new Button("Clear");
clearButton.addActionListener ( this );
panel.add( "South",clearButton );
}
public void actionPerformed(ActionEvent arg0)
{
String command = arg0.getActionCommand();
if( command.equalsIgnoreCase("Do It"))
{
String op

= operation.getSelectedItem();

String par = parameter.getText();


if( op == null )
showStatus("Please select an operation and enter the proper
parameter for it");
else
{
showStatus("Parameter: "+op+" "+"Option: "+par);
if( op.equals("showStatus") )
showStatus(parameter.getText());
else
if( op.equals("showDocument"))
{
java.applet.AppletContext ctx = getAppletContext();
try{
ctx.showDocument( new java.net.URL(par));
}
catch( Exception e )
{
showStatus("The requested document doesn't exists");
}
}
}
}
else
if( command.equalsIgnoreCase("Play Audio"))
{
java.applet.AudioClip sound = getAudioClip(
getDocumentBase(),"spacemusic.au");

sound.play();
}
else
if( command.equalsIgnoreCase("Clear") )
dp.clear();
}
}

Crearea interfetelor grafice cu pachetul


swing
1. Introducere
2. Arhitectura Model-View-Controller(MVC)
3. Look and Feel
4. Utilizarea componentelor Swing
5. JLabel
6. JButton
7. JTextComponent
8. JPasswordField
9. JScrollBar
10. JSlider
11. JProgressBar
12. JComboBox
13. JList
14. Timer

Introducere
Daca ati incercat sa creati componente proprii in AWT, probabil ca ati extins clasa
Canvas sau Panel. Aceasta metoda functioneaza insa ridica cateva probleme si anume
atat Canvas cat si Panel sunt componente netransparente si daca o componenta contine
prea multe componente native atat scade viteza de executie a programului. De
exemplu sa consideram un checkbox, ori de cate ori modificam starea acestuia, acest
obiect comunica cu un obiect checkbox nativ si cele doua obiecte trebuie sa fie
ibtotdeauna in aceasi stare, adica starile lor se modifica in mod sincron. Acesasta
soncronizare incetineste viteza de executie a aplicatiei. O alta problema cu
componentele AWT este ca modul de afisare a acestora depinde de platforma pe care
se ruleaza aplicatia. Deci cum arata ele nu depinde de programator ci de componentele
native. Pentru aceste neajunsuri JavaSoft introduce componentele "lightweight".
Aceste componente sunt scrise 100% in Java si modul de afisare astfel depinde doar

de programator. In primele versiuni Java clasele Component si Container erau clase


finale, adica nu se puteau extinde. Incepand cu versiunea JDK 1.1 aceste clase nu mai
sunt finale, devenind posibila extinderea lor. Aceste componente nu vor acea perechea
lor nativa, astfel nefiind necesara comunicarea acestora cu perechile lor native si toate
acestea conducand la programe mai rapide, iar ele arata pe orice platforma la fel. Intro aplicatie se poate combina utilizarea componentelor AWT cu cele "lightweight"
(desi nu se recomanda), dar trebuie tinut cont de faptul ca componentele AWT sunt
netransparente, ele vor fi intotdeauna in prim plan, acoperind cele "lightweight".
Exemplul urmator prezinta o componenta ligtweight, care este de fapt un Button, care
arata ca si harta statului Texas. Pentru implementarea acestei componente am utilizat
doua clase. O clasa Texas care contine doar doua variabile statice de tip tablou cu
intregi si contin coordonatele punctelor pentru desenarea unui poligon si o alta clasa
care implementeaza componenta. exista si o atreia clasa care afiseaza o fereastra cu
trei asemenea butoane. La apasarea acestor butoane se afiseaza informatii despre
buton la iesirea standard.
public class Texas {
static int X[] = {
150, 150, 150, 149, 149, 149, 150, 151, 152, 151,
151, 151, 151, 151, 152, 152, 153, 153, 152, 152, 151, 151, 151, 151,
150,
149, 150, 149, 147, 147, 147, 147, 145, 144, 143, 142,
142, 141, 141, 140, 135, 134, 133, 131, 130, 129, 127, 125, 124, 123,
121,
120, 120, 120, 119, 119, 118, 117, 117, 116, 115, 115, 115, 114, 114,
114,
114, 113, 112, 111, 109, 108, 108, 106, 106, 105, 104, 104, 101, 101, 99,
99, 98, 98, 97, 96, 93, 93, 93, 93, 92, 91, 90, 88, 88, 86, 86, 84, 85,
55,
54, 50, 12, 11, 12, 12, 11, 12, 12, 14, 14, 15, 17, 23, 28, 28, 29, 29,
29,
30, 30, 30, 32, 39, 45, 46, 47, 48, 49, 51, 52, 53, 55, 55, 56, 56, 57,
58,
61, 62, 64, 64, 67, 67, 68, 68, 68, 69, 71, 73, 74, 74, 77, 78, 81, 82,
84,
85, 86, 86, 86, 87, 87, 88, 90, 91, 92, 94, 97, 100, 105, 106, 109, 110,
111,
112, 113, 113, 112, 112, 111, 109, 108, 110, 109, 109, 109, 109, 109,
109,
110, 111, 111, 110, 111, 112, 114, 114, 114, 114, 114, 115, 115, 116,
117,
117, 117, 117, 117, 118, 118, 119, 121, 121, 122, 121, 120, 120, 122,
123,

124, 124, 124, 124, 124, 125, 129, 135, 135, 138, 139, 137, 138, 139,
140,
140, 140, 142, 143, 147};
static int Y[] = {
98, 98, 98, 97, 96, 96, 95, 94, 91, 90,
89, 89, 88, 86, 86, 85, 82, 81, 79, 78, 77, 76, 76, 75, 74,
74, 73, 71, 69, 68, 56, 49, 48, 49, 49, 48,
48, 48, 47, 47, 44, 45, 45, 45, 45, 45, 45, 46, 46, 47, 46, 46, 45, 45,
45,
46, 46, 45, 44, 44, 45, 46, 47, 47, 46, 45, 45, 45, 46, 46, 44, 44, 45,
45,
44, 43, 42, 42, 42, 42, 42, 41, 41, 41, 41, 41, 40, 40, 39, 39, 38, 37,
38,
38, 38, 36, 36, 35, 11, 9, 9, 66, 63, 63, 63, 64, 64, 65, 66, 67, 68, 70,
71,
78, 82, 83, 84, 85, 86, 87, 91, 93, 96, 101, 104, 105, 104, 103, 102, 97,
95,
95, 95, 95, 95, 94, 94, 95, 95, 96, 96, 96, 97, 98, 99, 99, 99, 100, 102,
104,
105, 106, 114, 116, 120, 121, 123, 124, 125, 126, 128, 129, 132, 133,
138,
140, 140, 141, 142, 144, 145, 145, 147, 147, 146, 146, 146, 145, 144,
144,
143, 137, 134, 131, 130, 129, 129, 129, 129, 129, 128, 124, 124, 122,
121,
122, 121, 119, 118, 118, 118, 118, 117, 118, 118, 118, 117, 116, 115,
115,
115, 116, 115, 115, 114, 114, 113, 113, 112, 111, 111, 111, 112, 112,
112,
112, 111, 107, 105, 102, 102, 100, 99, 98, 98, 99, 100, 100, 100, 98};
}
import java.awt.*;
import java.awt.event.*;
public class texasButton extends Component {
boolean inPoly = false;
boolean mouseDown = false;
ActionListener listener;
Polygon poly = new Polygon(Texas.X, Texas.Y, Texas.X.length);
public texasButton() {
enableEvents(AWTEvent.MOUSE_EVENT_MASK |
AWTEvent.MOUSE_MOTION_EVENT_MASK);

setBackground(Color.blue);
}
public synchronized void addActionListener(ActionListener l) {
listener = AWTEventMulticaster.add(listener, l);
}
public synchronized void removeActionListener(ActionListener l) {
listener = AWTEventMulticaster.remove(listener, l);
}
public void paint(Graphics g) {
if (inPoly && mouseDown)
g.setColor(getBackground().darker().darker());
else
g.setColor(getBackground());
g.fillPolygon(poly);
}
public void processMouseMotionEvent(MouseEvent e) {
if (poly.contains(e.getPoint())) {
if (!inPoly && mouseDown)
repaint();
inPoly = true;
}
else {
if (inPoly && mouseDown)
repaint();
inPoly = false;
}
}
public void processMouseEvent(MouseEvent e) {
switch (e.getID()) {
case MouseEvent.MOUSE_PRESSED :
if (inPoly) {
mouseDown = true;
repaint();
}
break;

case MouseEvent.MOUSE_RELEASED :
if (inPoly == true && mouseDown == true) {
if (listener != null)
listener.actionPerformed(new ActionEvent(this,
ActionEvent.ACTION_PERFORMED, ""));
repaint();
}
mouseDown = false;
break;
}
super.processMouseEvent(e);
}
public Dimension getPreferredSize() {
return getMinimumSize();
}
public Dimension getMinimumSize() {
return new Dimension(160,150);
}
}
import java.awt.*;
import java.awt.event.*;
public class texasTest extends Frame implements ActionListener {
public static void main(String args[]) {
texasTest t = new texasTest();
}
public void actionPerformed(ActionEvent ae) {
System.out.println(ae.getSource());
}
public texasTest() {
setBackground(Color.lightGray);
setLayout( new GridLayout(1, 3));
texasButton cb[] = new texasButton[ 3 ];
for( int i =0; i<cb.length; i++)
{
cb[ i ] = new texasButton();
cb[ i ].addActionListener(this);

add(cb[ i ]);
}
addWindowListener( new WindowAdapter(){
public void windowClosing( WindowEvent e ){
setVisible( false );
System.exit( 0 );
}
});
setBounds(1,1,500,200);
setVisible( true );
}
}

Arhitectura Model-View-Controller(MVC)
Clasele din pachetul Swing sunt bazate pe arhitectura MVC. Intr-o interfata grafica
MVC intotdeauna exista trei obiecte model, view si controller (structura, reprezentare
si comportament). Modelul este reprezentarea logica, view-ul este reprezentarea
vizuala si controller-ul specifica comportamentul. Separarea acestor elemente permite
urmatoarele:

Putem avea mai multe view-uri asociate aceluiasi model. De exemplu putem
vizualiza aceleasi date sub forma de tabel sau sub forma de grafic. Modificand
datele se modifica ambele reprezentari.
Modelul nespecificand reprezenarea, putem modifica view-ul fara sa-l afectam
modelul atasat

Pentru modelul unui buton putem avea o variabila intreaga cu doua valori 0 si 1, sau o
variabila logica cu valorile false si true.

Look and Feel


In AWT fiecare componenta grafica are o clasa nativa ( clasa peer) care comunica cu
componenta nativa a sistemul de operare. De aceea un obiect Button apare ca si un
buton Win95, daca este rulat sub Win95, iar daca este rulat pe Solaris atunci arata ca
un buton Motif. Componentele din pachetul Swing nu mai au aceste clase peer, si pot
arata in mod diferit pe aceasi platforma din cauza ca respecta arhitectura MVC.

Pentru a schimba modul de afisare a componentelor swing se utilizeaza


metoda setLookAndFeel() a clasei UIManager.
try {
UIManager.setLookAndFeel(
"javax.swing.plaf.metal.MetalLookAndFeel");
}
catch (Exception e) {
System.err.println("Couldn't use the metal "+
"look and feel: " + e);
}

Utilizarea componentelor Swing


Pachetul swing contine doua tipuri de componente:

containere (JFrame, JApplet, JWindow, JDialog)


componente "lightweight" (JButton, JPanel, JList etc. )

Containerele reprezinta cadrul in care aceste componente pot exista. Imaginea


urmatoare prezinta ierarhia componentelor unei aplicatii cu o fereastra, doua butoane,
o caseta text si o lista.

Obiectul contentpane din figura precedenta este un obiect Container obisnuit si este
sub containerul swing.
Codul pentru crearea suprafetei grafice:
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
panel.add(textField);
panel.add(list);
Container contentPane = this.getContentPane();
contentPane.setLayout(new FlowLayout());
contentPane.add(button1);
contentPane.add(button2);
contentPane.add(panel);

Observatie: Nu se pot adauga componentele direct la containerul swing.


Figura urmatoare contine cateva componente impreuna cu ierarhia de clase in care se
incadreaza:

JLabel
Un JLabel este similar cu o eticehta java.awt.Label, avand o serie de functionalitati in
plus:

permite atasarea unei iconite


permite pozitionarea verticala si orizontala a textului fata de iconita
permite pozitionarea relativa a continutului in cadrul componentei

Exemplul urmator utilizeaza interfata Icon:


public interface Icon{
void paintIcon( Component c, Graphics g, int x, int y );
int getIconWidth();
int getIconHeight();
}

Clasa ImageIcon este o implementare a clasei Icon, care creaza o iconita dintr-un
obiect de tip Image.
Icon iconPicture = new ImageIcon("Apple.gif");

Un exemplu:

Sursa:
import javax.swing.*;
import java.awt.*;
public class SwingPanel extends JPanel
{
public SwingPanel()
{
setLayout( new GridLayout( 3, 1 ));
JLabel simplelabel = new JLabel("This is a simple label");
add( simplelabel );
JLabel iconlabel = new JLabel("This is a fancy label");
Icon icon = new ImageIcon("icon.gif");
iconlabel.setIcon( icon );
Font font = new Font("Serif",Font.BOLD|Font.ITALIC,30);
iconlabel.setFont( font );
add( iconlabel );
JLabel myiconlabel = new JLabel("This is my icon label");
Icon myicon = new RedOval();
myiconlabel.setIcon( myicon );
add( myiconlabel );
}

}
import javax.swing.JFrame;
public class SwingFrame extends JFrame
{
private SwingPanel p;
public SwingFrame()
{
p = new SwingPanel();
getContentPane().add( p );
}
public static void main( String args[] )
{
SwingFrame f = new SwingFrame();
f.addWindowListener( new java.awt.event.WindowAdapter(){
public void windowClosing( java.awt.event.WindowEvent e )
{
System.exit( 0 );
}
});
f.setBounds(1,1,400,300);
f.setVisible( true );
}
}

In toate exemplele demonstrative pentru componente se vor utiliza doua clase. O clasa
care extinde clasa JPanel si care contine componenta specifica si una de tip container
care extinde clasa JFrame si afiseaza panelul cu componentele specifice. De aceea in
cazul urmatoarelor exemple vom descrie doar constructorul clasei SwingPanel.
JButton
Un buton JButton se instantieaza analog ca si un butom java.awt.Button. Evenimentul
care se produce la apasarea acestuia este tot un ActionEvent si evenimentul se livreaza
tuturor receptorilor inregistrati.Culoarea butonului este identic cu culoarea
containerului, deci trebuie modificat la SystemColor.control.
setLayout( new FlowLayout() );
JButton simplebutton = new JButton("Simple");
add( simplebutton );
simplebutton.setBackground(SystemColor.control);
Icon icon = new ImageIcon("icon.gif");
JButton iconbutton = new JButton("Icon", icon );
iconbutton.setBackground(SystemColor.control);
add( iconbutton );

JTextComponent

JTextComponent este o clasa generala cu toate functiunile unui editor de text simplu.
Metodele cele mai utilizate:

copy()
cut()
paste()
getSelectedText()
setSelectionStart()
setSelectionEnd()selectAll()
replaceSelection()
getText()
setText()
setEditable()
setCaretPosition()

Subclasele clasei JTextComponent sunt: JTextField, JTextArea, JTextPane.


setLayout( new BorderLayout());
JTextPane tp = new JTextPane();
MutableAttributeSet attr = new SimpleAttributeSet();
StyleConstants.setFontFamily(attr,"Serif");
StyleConstants.setFontSize(attr,18);
StyleConstants.setBold(attr,true);
tp.setCharacterAttributes( attr, false );
add( tp, BorderLayout.CENTER );

JPasswordField
Este subclasa clasei JTextField. Cu metoda setEchoChar() se poate specifica
caracterul care se afiseaza in locul caracterelor introduse. Implicit este '*'.
setLayout( new FlowLayout() );
JPasswordField pf = new JPasswordField(20);
pf.setEchoChar('*');
add(pf );

JScrollBar
Este varianta "lightweight" a componentei java.awt.Scrollbar.
setLayout( new BorderLayout() );
JScrollBar vertical = new JScrollBar(JScrollBar.VERTICAL,0,5,0,100);
add(vertical, BorderLayout.EAST );
JScrollBar horizontal = new JScrollBar(JScrollBar.HORIZONTAL,0,5,0,100);
add(horizontal, BorderLayout.SOUTH );

JSlider
JSlider este similar cu JScrollBar, dar permite afisarea marcjelor minore respectiv a
celor majore precum si desenarea unui chenar Border in jurul componentei.

setLayout( new BorderLayout() );


JSlider s1 = new JSlider( JSlider.VERTICAL, 0, 100, 50 );
s1.setPaintTicks( true );
s1.setMajorTickSpacing(10);
s1.setMinorTickSpacing(2);
add( s1, BorderLayout.EAST);
JSlider s2 = new JSlider( JSlider.VERTICAL, 0, 100, 50 );
s2.setPaintTicks( true );
s2.setMinorTickSpacing(5);
add( s2, BorderLayout.WEST);
JSlider s3 = new JSlider( JSlider.HORIZONTAL, 0, 100, 50 );
s3.setPaintTicks( true );
s3.setMajorTickSpacing(10);
add( s3, BorderLayout.SOUTH);
JSlider s4 = new JSlider( JSlider.HORIZONTAL, 0, 100, 50 );
s4.setPaintTicks( true );
s4.setBorder( LineBorder.createBlackLineBorder());
add( s4, BorderLayout.NORTH);

JProgressBar
Se utilizeaza pentru vizualizarea evolutiei unei operatii Pentru a lucra cu o asemenea
componenta prima data trebuie s-o intializam
JProgressBar p = new JProgressBar();
p.setMinimum( 0 );
setMaximum( numar_operatii );

iar dupa aceea intr-un ciclu sa modificam starea componentei


p.setValue( p.getMinimum());
for( int i=0; i<numar_operatii; i++)

{
//se executa o operatie
p.setValue( i );
}

Exemplu:
import javax.swing.JFrame;
public class SwingFrame extends JFrame
{
private SwingPanel p;
public SwingFrame()
{
p = new SwingPanel();
getContentPane().add( p );
Thread t = new Thread( p );
t.start();
}
public static void main( String args[] )
{
SwingFrame f = new SwingFrame();
f.addWindowListener( new java.awt.event.WindowAdapter(){
public void windowClosing( java.awt.event.WindowEvent
e )
{
System.exit( 0 );
}
}
);
f.setBounds(1,1,400,300);
f.setVisible( true );
}
}
import javax.swing.*;
import java.awt.*;
public class SwingPanel extends JPanel implements Runnable
{
JProgressBar pb;
public SwingPanel()
{
setLayout( new FlowLayout() );
pb = new JProgressBar();
pb.setMinimum(0);
pb.setMaximum(100);
pb.setValue( pb.getMinimum());
add( pb );
}
public void run()
{

for( int i=0; i<pb.getMaximum(); i++ )


{
pb.setValue( i );
try{
Thread.sleep( 100 );
}
catch( InterruptedException e ){}
}
}
}

JComboBox
Componenta este asemanatoare cu Choice din AWT, dar permite si editarea, adica
introducerea unei valori care nu exista in lista.
Exemplu de utilizare:

Sursa:
import javax.swing.*;
import java.awt.*;
public class SwingPanel extends JPanel
{
String elements[] ={"One","Two","Three","Four","Five"};
public SwingPanel()
{

setLayout( new FlowLayout() );


JComboBox c1 = new JComboBox();
JComboBox c2 = new JComboBox();
for( int i =0; i< elements.length; i++ )
{
c1.addItem( elements[ i ] );
c2.addItem( elements[ i ] );
}
c1.setEditable( false );
c2.setEditable( true );
add( c1 );
add( c2 );
}
}

JList
Componenta are doua implementari, una care respecta arhitectura MVC si una care
nu, se comporta la fel ca si o lista AWT. Totusi si aceasta implementare mai simpla sa imbunatatit. Putem adauga elementele prin contructor transmitandu-i un tablou de
stringuri. JList nu suporta scroll, adica daca dorim aceasta facilitate atunci trebuie s-o
punem intr-un ScrollPane.
import javax.swing.*;
import java.awt.*;
public class SwingPanel extends JPanel
{
String elements[] =
{"Orange","Lemon","Strawberry","Raspberry","Apple","Banana"};
public SwingPanel()
{
setLayout( new BorderLayout() );
JList list = new JList(elements);
ScrollPane pane = new ScrollPane();
pane.add( list );
add( pane, BorderLayout.CENTER );
}
}

Timer
Pe langa componente grafice, pachetul swing vine si cu o serie de utilitare. Un astfel
de utilitar este clasa Timer. Exemplul urmator este o fereastra cu trei butoane si cu trei
obiecte de tip Timer. Fiecare obiect Timer controleaza un buton, adica la trecerea
intervalului specific fiecarui timer se incrementeaza numarul de pe butonul

corespunzator. La crearea obiectelor de tip Timer specificam intervalul de timp la


care actioneaza respectiv si obiectul listener, adica componenta care este notificata.
Timerul trimite mesajul actionPerformed() dupa trecerea intervalului de
timp.Obiectul Timer trebuie pornit cu metodastart().
Diagrama de clasa

Diagrama de secventiere

Sursa

import
import
import
import
import

javax.swing.JFrame;
java.awt.event.ActionListener;
javax.swing.JButton;
javax.swing.Timer;
java.awt.event.ActionEvent;

public class MyWindow extends JFrame implements ActionListener


{
private JButton b[];
private Timer t[];
public MyWindow()
{
final int n = 3;
int i;
getContentPane().setLayout( new java.awt.FlowLayout() );
b = new JButton[ n ];
for(i=0;i<n;i++)
{
b[i] = new JButton(Integer.toString( i ));
getContentPane().add( b[ i ] );
}
addWindowListener( new java.awt.event.WindowAdapter(){
public void windowClosing( java.awt.event.WindowEvent
e )
{
setVisible( false );
System.exit( 0 );
}
});
t = new Timer[ n ];
for(i=0;i<n;i++)
{
t[ i ] = new Timer( (i+1)*100, this );
t[ i ].start();
}
}
/**
@roseuid 3A72EE9202F8
*/
public static void main(String[] args)
{
MyWindow w = new MyWindow();
w.setBounds(1,1,400,300);
w.setVisible( true );
}
/**
@roseuid 3A72F8A50122
*/
public void actionPerformed(ActionEvent arg0)
{
if( arg0.getSource() == t[0] )
{
System.out.println( "Button: "+0);

b[0].setLabel( Integer.toString(
Integer.parseInt(b[0].getLabel())+1 ));
}
else
if( arg0.getSource() == t[1] )
{
System.out.println( "Button: "+1);
b[1].setLabel( Integer.toString(
Integer.parseInt(b[1].getLabel())+1 ));
}
else
if( arg0.getSource() == t[2] )
{
System.out.println( "Button: "+2);
b[2].setLabel( Integer.toString(
Integer.parseInt(b[2].getLabel())+1 ));
}
}
}

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