Sunteți pe pagina 1din 231

************************

* Limbajul Java *
* ABC-doar *
************************

*********************************
* autor RUSU MIRCEA AUREL VALER *
*********************************

********************************************
* MOTTO: *
* *
* "That's one small step for a man, *
* one giant leap for mankind." *
* Neil Armstrong *
********************************************

De ce Java ?

Pentru ca este: simplu,robust si eficient,multitasking si


dinamic,este structurat modular exclusiv sub forma de obiecte,
este opensource si poate fi aplicat pe orice tip de dispozitiv
electronic (automatizari,comunicatii,imagistica etc.)
********************
* C O N T I N U T *
********************

Prezentare generala . . . . . . . . . . . . . . . . 1

Structura generala a programului . . . . . . . . . . 6

Elementele de limbaj . . . . . . . . . . . . . . . . 12

Clase si obiecte . . . . . . . . . . . . . . . . . . 16

Interfete grafice . . . . . . . . . . . . . . . . . . 19

Pachete . . . . . . . . . . . . . . . . . . . . . . . 22

Componentele vizuale (Swing si AWT) . . . . . . . . 26

Executia concurentiala . . . . . . . . . . . . . . . 57

Applet-uri Java . . . . . . . . . . . . . . . . . . . 79

Designul interfetei grafice (Layout Managers) . . . . 95

Tabele si baze de date . . . . . . . . . . . . . . . 109

Clase generice si colectii . . . . . . . . . . . . . 115

Grafica 2D . . . . . . . . . . . . . . . . . . . . . 130

Aplicatii audio . . . . . . . . . . . . . . . . . . 141

Java Management . . . . . . . . . . . . . . . . . . 161

Java networking (operatii in retea) . . . . . . . . 180

Securitatea aplicatiilor Java . . . . . . . . . . . 185

Finalizarea aplicatiilor . . . . . . . . . . . . . . 190


PREZENTARE GENERALA

Limbajul Java a fost proiectat si realizat initial ca o reactie la


limbajul C si C++,cu scopul de a asigura o cat mai buna portabilitate a
apliatiilor,pe orice platforma software si in orice mediu hardware.
Limbajul C,a fost creat initial pentru a structura mai eficient comu-
nicatiile dintr-o centrala telefonica.Urmasul sau,limbajul C++ a pastrat
toate filele header si structurile limbajului C,dar a adaugat si structuri
noi,denumite clase si obiecte.Rezultatul a fost un amalgam de functii de
nivel inferior si structuri de nivel superior,ce formau un mediu de ope-
rare complex si dificil de administrat.In plus,aplicatiile C++ erau strict
dependente de sistemul de operare si de o anumita configuratie hardware.
Obictele de tip DOS nu erau compatibile cu cele Windows iar aplicatiile nu
puteau fi rulate sub Linux,Solaris,OS2 sau alte sisteme de operare.Nu
existau obiecte ActiveX,astfel incat singura solutie era ca fiecare apli-
catie sa fie rescrisa,pentru fiecare context software/hardware.
In acest context,James Gosling de la firma Sun Microsystems a initiat
un proiect,prin care un limbaj structurat asemenator cu limbajul C++ sa
poata fi portabil pe orice tip de hardware si sub orice sistem de operare.
Pentru acest scop,a imaginat un cod intermediar organizat sub forma de
bytes si a creat doua instrumente de lucru independente: un compilator si
un interpretor.Comiplatorul converteste fila tip text la bytecode,iar
interpretorul converteste bytecode la limbaj masina (codul pt. procesor).
Prin acest mecanism simplu,o aplicatie poate fi creata in mediul Windows
si executata sub Linux sau DOS.In plus,fila de tip bytecode este complet
"inerta" fata de procesor si poate fi transmisa in orice tip de retea de
comunicatii,fara riscul de a fi corupta sau de a genera eventuale procese
"accidentale".Compilatorul si interpretorul sunt create special pentru
fiecare sistem de operare si pentru fiecare tip de hardware utilizat.
Firma Sun,ofera gratuit seturi intregi de astfel de instrumente speciali-
zate,pentru fiecare sistem de operare sau tip de dispozitiv electronic.
Pentru a crea o aplicatie Java este necesar un compilator si setul de
file header in care sunt arhivate clasele standard,la care se adauga toate
filele ce contin resurse,iar pentru a executa aplicatia este necesar un
interpretor si setul de file ce creaza mediul de operare necesar pentru
aplicatie.
Intre fila text editata de programator,si procesor,se interpune acest
cod simbolic si cele doua (sau mai multe) instrumente specializate in
prelucrarea lui.Acest mecanism a fost denumit generic "virtual machine"
si are semnificatia unui procesor virtual,creat sub forma de structura
software in care se executa exact aceleasi operatii ca si intr-un proce-
sor real.Acest procesor virtual poate fi creat pe orice tip de calculator,
sau dispozitiv electronic,cu conditia sa existe un tampon de memorie su-
ficient de mare.Ca rezultat,indiferent de tipul de procesor fizic instalat
Java va crea un procesor virtual in care va executa operatiile de conver-
sie a codului simbolic si apoi va accesa procesorul fizic in cod masina.
Firma Sun a publicat prima implementare de acest gen in 1995 sub numele
de Java 1.0 popularizata prin sloganul "Write Once,Run Anywhere".Apoi,
platforma Java a cunoscut o serie intreaga de actualizari si dezvoltari,
si este in continuare in plin proces de evolutie spre forme din ce in ce
mai perfectionate.

-2-
Acest mecanism inovativ,a produs o adevarata revolutie,atat pentru
tehnica de calcul,cat si pentru dispozitivele de automatizare si control.
Pentru prima data,se pot edita programe simple pe un calculator de birou
si apoi se pot transmite telefonic,pentru a fi implementate pe un robot,
sau orice alt tip de utilizator final.Exista o versiune de Java speciali-
zata pentru aplicatii de tip telefonie mobila.In prezent,exista nenumarate
solutii tehnologice similare,sau asemanatoare,dar Java este un mediu total
gratuit,este open source si este perfect compatibil,atat pentru scopuri
didactice,cat si pentru solutii prectice imediate.
Interpretorul de Java are 132 Kb.Ca rezultat,se poate crea un mediu
pentru executia aplicatiei Java in mai putin de 1 Mb de memorie (inclusiv
filele ce formeaza aplicatia).Ca rezultat,aplicatiile Java pot fi execu-
tate pe aproape orice tip de aparat electronic modern.
Limbajul Java nu este potivit pentru invatarea notiunilor elementare.
Este recomandabil sa utilizati alte limbaje pentru a invata ce este o
variabila sau o constanta,ce sunt instructiunile si comenzile,cum se
implementeaza functiile si procedurile sau ce este o clasa si un obiect.
Inainte de a incepe lucrul in Java,este bine sa cunoasteti cel putin un
limbaj de nivel superior,sa fiti familiarizati cu programarea orientata
spre obiect si cu modul de organizare al claselor de obiecte vizuale.In
plus,este bine sa aveti cel putin notiuni elementare despre reteaua Inter-
net si Web design (HTML,XML,XSL etc.).Principalele recomandari ar fi
limabjul C++ si Visual C++,limbajul Visual Basic sau Delphi.
In etapa de proiectare,limbajul Java a avut urmatoarele obiective:
1. -sa fie simplu,orientat spre obiect si familiar
2. -sa fie robust si sigur
3. -sa fie portabil si neutru fata de arhitectura intermediara
4. -sa fie cat mai performant (viteza/memorie consumata)
5. -sa fie dinamic,interpretat,multitasking (cu executie paralela)
Este bine sa aveti in vedere aceste obiective si pentru aplicatiile
create de d-voastra cu ajutorul platformei Java.
Spre deosebire de C++ si alte limbaje asemanatoare,Java ofera si alte
instrumente specializate de o importanta exceptionala.In primul rand,
trebuie mentionate instrumentele pentru gestiunea automata a memoriei
(Garbage collection) si cele pentru tratarea automata a eventualelor
erori de executie (Automated Exception Handling).Pe langa acestea,exista
un set intreg de instrumente (tools) auxiliare,ce permit conversia si
reconversia codurilor,arhivarea si dezarhivarea filelor,dezasamblarea
si asamblarea proiectelor,extragerea de documente Web cu comentariile
si referintele unui program etc.
Java este un mediu de programare suprastructurat.Toate datele trebuie
sa fie incluse in obiecte.Obiectele pot exista izolat,sau pot fi grupate
cu ajutorul unor obiecte de tip container.Fiecare obiect este creat cu
ajutorul unei clase (obiectul este o instanta a unei clase).Clasele pot
fi create si definite de catre programator,dar in principal se utilizeaza
clase standardizate,predefinite.Clasele predefinite sunt grupate in
pachete,incluse intr-o biblioteca denumita generic API.Spre deosebire de
alte limbaje vizuale,Java nu poate face apel la clasele incluse in Windows
sau in alte sisteme de operare.In schimb,Java contine un set complet de
clase proprii,ce inlocuiesc cu succes clasele API Windows si cele simi-
lare lor.

-3-
Platforma Java cuprinde un numar foarte mare de instrumente auxiliare,
editoare si programe de verificare si control.Ca rezultat,limbajul Java
se poate utiliza pentru foarte multe tipuri de aplicatii.Cele mai frec-
vente sunt: arhivarea si prelucrarea datelor,comunicatii in retea,actio-
nari si automatizari,prezentarea datelor in retea sub forma de interfete
grafice,componente auxiliare ale unei aplicatii Web (denumite applet-uri),
grafica si design,posta electronica etc.Acest manual,nu are decat titlul
de abecedar si se va axa mai ales pe aplicatiile de tip client,in care
se exploateaza o interfata grafica,formata din obiecte vizuale.Totusi se
vor prezenta succint si notiunile elementare ale limbajului,astfel incat
dupa terminarea acestui ciclu de instructie sa puteti migra spre oricare
dintre mijloacele de expresie ale limbajului Java.
Pentru inceput,trebuie sa va procurati setul de resurse software mini-
mal: setul cu instrumente de dezvoltare inclus intr-un pachet de tip JDK,
setul de instrumente pentru executie,inclus intr-un pachet de tip JRE,un
minim de documentatie tehnica (Exemplu: Java 2 SE 6 Documentation) si
eventual utilitarul NetBeans.Cel mai aimplu este sa descarcati de pe
Internet pachetul complet inclus in Java Standard Edition 6.0 (sau mai
recent).In plus,puteti cauta si descarca orice manuale,carti si tutoriale,
programe demonstrative sau exemple executabile,articole de specialitate,
comentarii si recenzii,etc.
Dupa instalarea programului,directorul Java va contine in folderul JDK
un set de subdirectoare: bin,db,demo,include,jre,lib,sample si src.Dintre
aceste,in aceasta etapa au importanta subdirectorul "bin" in care sunt
arhivate principalele utilitare si pachetul "src" in care sunt arhivate
pachetele de clase API (trebuie dezarhivat cu unzip sau cu JAR).
Daca deschideti "bin",puteti observa un set intreg de executabile mici,
si cateva file de tip DLL.Dintre acestea sunt esentiale: 1.cel denumit
"javac" (compilatorul) si 2. cel denumit "java" (interpretorul).Restul
de executabile implementeaza functii si operatii auxiliare:
javadoc -genereaza documentatie API
apt -instrument pentru addnotare
appletviewer -previzualizeaza un applet in web browser
jar -arhiveaza si dezarhiveaza filele
jdb -este programul debugger (depanator)
javah -genereaza file header de tip C++
javap -dezasambleaza filele .class
extcheck -detecteaza conflictele tip JAR (de arhivare)
Alte instrumente sunt specializate pentru securitatea aplicatiilor:
keytool -gestioneaza certificatele si setul de taste
jarsigner -genereaza sau verifica semnaturile JAR
policytool -administreaza filele de protocol (policy files)
Exista si un set experimental de instrumente destinate pentru depanare:
jinfo -prezinta informatii despre procesor sau despre server
jhat -permite verificarea stivei (din serverul Web)
jmap -prezinta o harta a memoriei (pentru un proces,o fila)
jsadebugd -ataseaza o fila destinata pentru depanarea server-ului
jstack -prezinta lista sirurilor de executie din proces
etc...
In etapa initiala,puteti sa eliminati instrumentele inutile.Este insa
obligatoriu sa pastrati compilatorul,interpretorul si filele DLL.

-4-
Trebuie remarcat de la prima vedere,ca intregul director "bin" nu ocupa
mai mult de 2Mb.Daca la alte platforme de programare toate utilitarele
sunt incluse intr-o interfata comuna (de obicei un meniu central cu seturi
de optiuni),Java a preferat sa ofere toate aceste utilitare separat.
Astfel,compilatorul java (javac) ocupa doar 25 Kb,iar interpretorul
(java) ocupa doar 132 Kb.Concluzia este evidenta: aplicatiile java se pot
crea si intr-un mediu foarte restrans de memorie (de exemplu pe un telefon
celular).Fiecare programator,are libertatea sa-si configureze mediul de
programare dupa bunul plac,sau dupa necesitatile de moment.Bineinteles ca
este recomandabil sa pastrati toate utilitarele din kit,la care puteti sa
adaugati orice alte instrumente de dezvoltare noi.
Pentru executia aplicatiilor Java,nu sunt suficiente doar utilitarele
din pachetul JDK,ci este strict necesar sa instalati si mediul de executie
denumit Java Runtime Enviroment,inclus in pachetul JRE.Acest pachet con-
tine procesorul virtual (Java virtual machine) si un set de biblioteci de
functii necesare pentru executie.Mediul de executie Java,este un mediu
complex,asemantor cu cel al sistemului de operare Windows,dar fara nici
un fel de interferenta cu acesta.In plus,sistemul de mesaje si controlul
evenimentelor sunt organizate complet diferit (nu are rost sa incercati sa
exploatati din Java mesajele de tip Windows).
Pentru a crea o fila executabila,sunt necesare urmatoarele etape:
1.-se editeaza o fila text ce contine codul in limbaj Java
2.-se salveaza fila cu extensia .java (numele filei trebuie sa corespunda
cu numele clasei implementate)
3.-se utilizeaza compilatorul javac pentru a converti fila in bytecode
(compilatorul genereaza o fila cu acelasi nume dar cu extensia .class)
4.-fila .class poate fi executata cu ajutorul interpretorului Java
La prima vedere,acest proces pare destul de complex si confuziv,dar cu
putin exercitiu,procesul de compilare si executie devine o rutina.Cei pre-
tentiosi,pot apela la un editor vizual,in care toate aceste operatii se
efectueaza automat.
Principalul avantaj il reprezinta faptul ca fila .class,generata in
cod simbolic (bytecode),este de dimensiuni mici,compacta,nu interfereaza
cu nici un sistem de operare,poate fi transmisa prin orice sistem de
comunicare (inclusiv telefonic) si poate fi executata pe orice dispozitiv
electronic dotat cu o masina virtuala Java si un interpretor.
Un alt avantaj major il reprezinta faptul ca intreaga platforma este
open source.Totul este la vedere,inclusiv bibliotecile de functii si
filele executabile.Mai mult decat atat,filele .class pot fi dezasamblate
pana la nivel de instructiuni de procesor,astfel incat profesionistii sa
poata verifica fiecare instructiune,registru sau operatie.
Nu in ultimul rand,Java este un limbaj cu un substantial potential de
dezvoltare viitoare,datorita faptului ca se poate adapta la aproape orice
tip de structura hardware.In etapa actuala,inca domina procesoarele cu
linie de executie seriala,bazata pe evenimente asincrone.Fiecare astfel
de eveniment,sau operatie,trebuie sa fie tratata la nivel de procesor
separat de restul evenimentelor.Chiar si procesarea de tip mutitasking,se
face tot serial: -se programaeaza mai multe fire de executie,apoi se
fragmenteaza aceste siruri de coduri si se executa pe rand cate un frag-
ment din fiecare sir (thread).Unele procese pot avea prioritate relativa
sau absoluta,in functie de un set de mark-eri.

-5-
Procesarea seriala a ajuns deja la limita fizica maxima,astfel incat
dezvoltarile viitoare nu se vor putea face decat utilizand metode de
procesare paralela,bazata pe evenimente sincrone.Exista deja calculatoare
de birou dotate cu procesoare duale,dar acest tip de solutie este rezervat
deocamdata doar pentru centralele mari si pentru supercalculatoare.Prin
dimensiunile mici si codul simbolic,Java este perfect compatibila si cu
aplicatiile in care se utilizeaza procese paralele (sistem distribuit).
Mai mult decat atat,Java este un mediu foarte interesant si pentru
iubitorii de hardware.Procesorul virtual ofera o platforma foarte simpla
si clara pentru verificare fizica a functionalitatii unui procesor.Cel
mai simplu exemplu il reprezinta verificarea registrilor cu ajutorul
celor din procesorul virtual (prin comparare).
In orice caz,Java nu este mediul cel mai potrivit pentru incepatori,
sau pentru amatori.Java este un limbaj modular,hiperstructurat sub forma
de clase,organizate arborescent.Clasa radacina este clasa Object.Toate
celelalte clase deriva din clasa Object si respectiv au clasa Object pe
post de superclasa(ancestor).Clasa Object este arhivata in pachetul
denumit "lang" si este implicita (intregul pachet "lang" este implicit).
Clasa Object are un constructor si un set de metode ce vor fi mostenite
de toate celelalte clase: clone(),equals(),finalize(),getClass(),hash-
Code(),notify(),notifyAll(),toString() si wait().Aceste metode pot fi
apelate din oricare dintre mostenitori.Restul claselor se dezvolta arbo-
rescent,spre clase din ce in ce mai specializate.Documentatia Java 2 SE 6
ofera pentru fiecare clasa prezentata si arborele genealogic:
EXEMPLU: java.lang.Object
|_ java.awt.Component
|_java.awt.Button
Urmarind arborele genealogic,puteti evalua toate proprietatile si meto-
dele mostenite de la ancestori.Mecanismul de mostenire este la fel ca si
cel al claselor C++,cu diferenta ca in Java nu exista mostenire multipla
(un obiect nu poate fi creat simultan din doua clase ancestoare).
In mod curent,aplicatiile Java nu vor contine o singura clasa,ci un
set intreg de clase,din care se vor crea obiecte ce interactioneaza prin
diverse apeluri reciproce.Din acest motiv,atunci cand se compileaza fila
sursa,este imperios necesar ca toate filele de resurse sa fie accesibile
pentru compilator.Inainte de a incepe procesul de compilare,trebuie sa
va asigurati ca directorul curent contine,sau are acces la toate pachetele
apelate si la toate filele de resurse incluse in aplicatie.
Si in mediul Java,este extrem de important cum gestionati conexiunile
dintre file si aplicatii (link-urile).Este recomandabil sa nu creati
link-uri spre file de resurse ce urmeaza sa fie actualizate,redenumite,
sau mutate la o alta adresa,deoarece riscati sa generati procese ce nu
pot fi executate prin lipsa unor resurse esentiale.
In linii mari,Java functioneaza la fel ca orice alt program orientat
spre obiect.In fiecare aplicatie se construieste un obiect,din clasa
principala si apoi se executa metodele obiectului.In cazul aplicatiilor
lipsite de obiecte vizuale,se implementeaza o functie principala (denu-
mita de obicei Main),cu ajutorul careia se organizeaza secventa de ope-
ratii,instructiuni si comenzi.Toate datele sunt incluse in obiecte (vizu-
ale sau nonvizuale),astfel incat programul este modular si incapsulat.
Daca a-ti inteles aceasta introducere,are rost sa cititi si restul cartii.

-6-
STRUCTURA GENERALA A PROGRAMULUI (Exemple)

Platforma Java si respectiv limbajul Java permit crearea unui numar


foarte mare de solutii software,pentru diverse tipuri de probleme si con-
figuratii hardware.Cea mai simpla aplicatie posibila,este o fila execu-
tabila.Mai multe astfel de file,impreuna cu un set de file continand alt
tip de resurse (grafice,audio etc.),se pot grupa pentru a forma un pro-
iect sau o aplicatie Java.Atunci cand aplicatia utilizeaza o interfata
grafica formata din obiecte vizuale,poarta numele de Aplicatie Desktop.
Atunci cand aplicatia este destinata exclusiv pentru Internet,poarta
numele de Aplicatie Web.In plus,Java se poate utiliza pentru a crea file
si biblioteci noi.In acest caz,se utilizeaza exclusiv clase derivate din
Object,la care se adauga diverse implementari noi.Atunci cand un grup
oarecare de obiecte urmeaza sa fie utilizate intotdeuna in aceeasi con-
figuratie,aspectul realizat poarta numele de interfata grafica.O inter-
fata nu este decat o conventie prin care programatorul se obliga sa
utilizeze aceeasi combinatie de obiecte,in aplicatii diferite.Aceste
interfete grafice,mai sunt denumite si sabloane,sau templates si sunt
frecvent aplicate pentru formularistica sau pentru a controla relatia
dintre utilizatori si program.Pentru a simplifica munca de programare,
clasele si interfetele se grupeaza in functie de functionalitatea lor,in
niste obiecte mai mari de tip container,denumite pachete.Programatorul va
avea libertatea sa incarce in memorie o singura clasa,sau intregul pachet,
in functie de necesitatile sale imediate.De obicei,atunci cand se utili-
zeaza mai multe clase din acelasi pachet,se incarca intregul pachet.
Pentru a simplifica procesele de eliberare a memoriei,Java incapsuleaza
toate datele in clase si obiecte.Alte programe,utilizeaza sisteme complexe
de tabele si pointeri prin care gestioneaza fiecare variabila si constanta
din program.Java include toate datele in clase si obiecte,astfel incat
aceste tabele se rezuma doar la obiectul respectiv.O data cu eliberarea
unui obiect,se elibereaza si tabela de pointeri,adica toate datele incluse
in obiectul respectiv,intr-o singura operatie.Acest gen de solutie,creste
viteza de executie si simplifica munca procesorului pentru gestionarea
operatiilor interne.Ca rezultat,fiecare fila Java trebuie sa contina cel
putin o clasa.Pentru a organiza executia programului,clasa principala din
program contine o functie,denumita Main(),ce urmeaza sa fie cautata si
invocata de Java Virtual Machine,in momentul executiei.In functia Main,
se grupeaza instructiuni izolate,sau blocuri de instructiuni,precum si
bucle si functii special destinate pentru controlul fluxului din program.
Cel mai simplu program Java,afiseaza pe ecran un text oarecare.
EXEMPLU:
class HelloWorldApp {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
-editati textul cu NotePad si salvati fila cu numele HelloWorldApp.java
in directorul BIN,la adresa la care este arhivat kit-ul JDK (sa fie in
acelasi director cu executabilul javac.exe).
Pentru a converti fila in cod binar,utilizati din butonul Start,optiu-
nea All Programs,alegeti Accessories si apoi Command Prompt.

-7-
Primul pas este sa deschideti directorul in care este arhivata fila nou
creata.Utilizati o comanda de genul:
cd C:\Program Files\Java\JDK1.6.0_03\BIN
Eventual,utilizati o comanda "dir" pentru a verifica daca sunt listate
toate filele din directorul BIN.
Pentru a compila fila nou creata utilizati o comanda:
javac HelloWorldApp.java
In mod normal se va genera o fila noua cu extensia .class.Verificati
cu "dir" daca fila HelloWorldApp.class apare in directorul BIN,apoi
puteti lansa fila in executie cu comanda:
java HelloWorld
Acesta este cel mai simplu exercitiu posibil.La inceput,este mai greu
sa va orientati in mediul DOS,dar va imaginati ca doriti sa transmiteti
un mesaj SMS,pe un telefon celular.
Exemplul este functional,deoarece utilizeaza stream-ul de iesire a
datelor System.out.La fel ca si in C++,stream-ul de iesire implicit este
un obiect gata creat si sta la dispozitie in orice moment.
In mod normal,clasele nu pot fi utilizate direct.Este necesar sa cre-
ati un obiect (o instanta a clasei respective),sa initializati obiectul
si abea apoi sa apelati una dintre metodele sale.
Mai observati si faptul ca nu trebuie inclusa nici o fila auxiliara.
Streamul System.out este inclus in pachetul System,care este inclus in
lang (pachetul lang este incarcat automat in orice aplicatie).Pentru o
imagine si mai clara,este bine sa deschideti fila de documentatie si sa
cautati in index pachetul System.Observati ca streamul "out" este inclus
in clasa System sub forma de camp de date static,conectat la clasa
PrintStream din pachetul java.io.Pentru scrierea propriu zisa a datelor
se va utiliza metoda println() a obiectului de tip PrintStream.Este bine
sa urmariti in pachetul de documentatie calea de executie pentru acest
exemplu simplu,pentru a putea intelege cum sunt apelate metodele unui
obiect in orice alta linie de comanda.
Pentru ca relatia dintre utilizator si program sa fie completa,este
necesar sa existe si o modalitate de a introduce date in program.Cea mai
simpla solutie este sa utilizati un stream (flux) de intrare a datelor.
Cel mai practic stream de intrare este inclus in clasa Scanner din pache-
tul denumit Util:
EXEMPLU:
import java.util.Scanner;
class Salut {
public static void main(String[] args) {
System.out.println("Hello World !");
System.out.println("Introduceti numele d-voastra:");
Scanner sc1=new Scanner(System.in);
String salut1 = sc1.next();
System.out.println("Hello: " + salut1 + " Wellcome to Java!");
}}
-salvati fila cu numele Salut.java
Apoi compilati fila (javac Salut.java) si executati fila (java Salut)
din Command Prompt.
Fata de exemplul precedent,am asociat stream-ului de intrare System.in
un obiect de tip Scanner (creat cu New) si apoi am apelat metoda next().
-8-
Pentru cei familiarizati cu C++,cele doua strem-uri sunt echivalente
cu "cin" si "cout".Acest gen de solutie este recomandabil doar pentru
aplicatii ce urmeaza sa ruleze sub DOS,intr-un mediu cu memorie extrem
de limitata.Pentru aplicatiile obisnuite,se recomanda fie crearea unei
interfete grafice cu obiecte vizuale,fie crearea unui applet,pentru o
fila de Web.
Pentru construirea interfetei grafice se utilizeaza un set de compo-
nente,asemantoare cu cele din mediul Windows,dar cu aspect putin diferit.
Trebuie remarcat faptul ca Java nu apeleaza resursele sistemului Windows
ci include un set separat de componente,incluse in pachetul denumit Swing.
EXEMPLU:
import javax.swing.*;
public class HelloWorldSwing {
public static void main(String[] args) {
JFrame frame = new JFrame("HelloWorldSwing");
frame.setDefaultCloseOperation(Jframe.EXIT_ON_CLOSE);

JLabel label = new JLabel("Hello World");


frame.getContentPane().add(label);

frame.pack();
frame.setVisible(true); }
}
-salvati fila cu numele HelloWorldSwing.java,apoi compilati si execu-
tati fila.
Daca sunteti familiarizati cu obiectele vizuale,acest exemplu este
relativ usor de urmarit.Functia main() construieste initial un obiect de
tip JFrame si apoi o eticheta de tip jLabel (cu new) .Interfata trebuie
sa contina neaparat un obiect container (frame sau window) in care se
pot include restul de componente (label,combobox,buttons etc.) cu ajutorul
metodei add().Observati ca in acest caz,compilatorul a creat si o fila
auxiliara,denumita HelloWorldSwing$1.class in care arhiveaza informatii
suplimentare,necesare pentru executie (ordinea proceselor de executie).
Acest exemplu,afiseaza deja un obiect grafic.Daca nu va place sa ope-
rati din DOS,puteti sa utilizati un instrument oarecare prin care sa
transformati fila .class in executabil de tip Windows,sau cel putin sa
puteti lansa fila in executie cu un dublu click de mouse.Cel mai simplu
program de acest gen,se numeste Java Runner,are 55 Kb si poate fi descar-
cat de pe Internet,prin bunavointa autorului (Kevin Kuang).Instalati
utilitarul,apoi conectati in Windows Explorer filele de tip .class cu
utilitarul jr.exe (vezi fila readme din program).In continuare,puteti
lansa in executie orice fila .class,cu un simplu click dublu de mouse,
cu conditia sa existe un interpretor de java instalat si un pachet JRE
(continand Java Virtual Machine).In continuare,programarea in Java incepe
sa semene cu cea din oricare alt program vizual.
Este bine sa verificati in Documentatie si obiectele JFrame si respec-
tiv JLabel utilizate in exemplul de mai sus.In general,pentru interfetele
grafice se prefera un alt tip de solutie : se creaza mai intai o interfata
de tip runnable,apoi se lanseaza in executie prin metoda Run().In acest
caz,functiile prin care se implementeaza interfata se declara de tip
private,pentru a nu putea interfera cu restul aplicatiei.
-9-
EXEMPLU:
import javax.swing.*;
public class HelloWorldSwing {
private static void createAndShowGUI() {
JFrame frame = new JFrame("HelloWorldSwing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

JLabel label = new JLabel("Hello World");


frame.getContentPane().add(label);

frame.pack();
frame.setVisible(true); }
public static void main(String[] args){
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() { createAndShowGUI(); }
} );
}
}
-salvati,compilati si executati fila (atentie cum inchideti paranteza
invokeLater() dupa ultima acolada din new Runnable() ).
Observati ca in acest caz,functia prin care se creaza obiectele este
privata si nu poate fi apelata din exteriorul filei.In schimb,functia
main() este publica,creaza o interfata de tip Runnable() cu ajutorul
functiei private si apoi apeleaza metoda Run(),pentru a pune interfata
in executie.Acest procedeu este mai complicat,dat asigura o mult mai
buna securitate a datelor (interfata nu poate fi corupta din exterior).
O alta modalitate pentru prezentarea datelor o reprezinta applet-urile.
Spre deosebire de aplicatiile simple,un aplet nu trebuie sa contina o
functie main(),deoarece va fi pus in executie de motorul intern al filei
HTML in care va fi exportat.Pentru a putea fi recunoscut de browser,este
necesar ca applet-ul sa fie inclus intr-o clasa de tip public,creata prin
derivarea clasei standard JApplet din pachetul javax.swing.
EXEMPLU:
import javax.swing.JApplet;
import java.awt.Graphics;
public class Hello extends JApplet {
public void paint(Graphics g) {
g.drawRect(0,0,getSize().width - 1,getSize().height - 1);
g.drawString("Hello world!",5,15); }
}
-salvati fila cu numele Hello.java,apoi compilati fila
Includeti applet-ul intr-o fila HTML astfel:
<html>
<title> Applet </title>
<h1> APPLET </h1>
<body>
<applet code="Hello.class" width=100 height=20 >
</applet>
</body>
</html>
-salvati fila cu numele Applet1.htm si deschideti cu Internet Explorer

-10-
Un applet poate fi previzualizat si cu instrumentul denumit appletviewer
atunci cand nu doriti sa lansati in executie browser-ul de web.In acest
caz se va utiliza o linie simpla de comanda in care se specifica utili-
tarul si fila HTML ce contine applet-ul:
EXEMPLU: appletviewer applet1.htm
va lansa in executie applet-ul creat anterior.Trebuie remarcat faptul
ca utilitarul appletviewer nu are un interpretor pentru HTML si nu poate
prezenta intreaga fila HTML si doar continutul applet-ului extras intr-o
fereastra tip Java.
Limbajul java permite si redactarea unor file asemanatoare cu applet-
urile,dar destinate pentru a seta sau imbunatati functionalitatea unui
server.Aceste file se numesc servlet-uri si nu vor fi prezentate in acest
manual,deoarece depasesc interesul programatorului amator.
O alta modalitate de structurare a datelor,este sub forma de proiecte
complete.In aceasta etapa,este prematur sa construiti proiecte,dar este
recomandabil sa lansati in executie cateva dintre proiectele demonstrative
impachetate in directorul Demo,din pachetul JDK.
De exemplu,deschideti directorul "applets",apoi "Animator" si alegeti
unul dintre cele patru exemple (click pe fila HTML).Daca studiati putin
proiectul,observati ca exista un set de file pentru resurse grafice si
audio,si respectiv cate o fila sursa.
Un exemplu ceva mai complex,este inclus in directorul GraphicsTest.
Puteti observa ca pentru un singur applet s-au editat 15 file de cod Java.
Probabil ca cel mai simplu exemplu,este cel inclus in directorul numit
JumpingBox.Eventual,puteti incerca sa completati acest exemplu: fie sa
colorati dreptunghiul aleator,fie sa adaugati un tip ordonat de miscare.
Pentru reprezentari grafice elementare,puteti transforma exemplul din
directorul SimpleGraph (de exemplu pentru a reprezenta grafic o functie).
Exemplul SortDemo ofera trei algoritmi diferiti pentru sortarea date-
lor (bubble sort,quick sort si bi-directional sort).
Pentru a va face o idee despre cum arata un proiect complet,dar si
pentru a va sensibiliza cu componentele Swing,deschideti directorul JFC
si alegeti proiectul SwingSet.Lansati fila HTML si testati toate optiunile
apoi deschideti directorul src si studiati filele sursa.
Un alt proiect complex este Java2Demo,in care sunt prezentate princi-
palele mijloace de exprimare grafica.
Daca doriti sa scrieti un editor de tip Notepad,in java,studiati cu
atentie proiectul Notepad.
In general,este bine sa executati toate programele demonstrative si
apoi sa studiati structura fiecarui proiect.Pentru un alt tip de orientare
in proiect,puteti sa instalati si programul NetBeans IDE si apoi sa des-
chideti proiectele exemplificative cu aceasta interfata de programare.
De exemplu,din meniul File alegeti Open project si selectati grupul de
aplicatii de tip Netbeans din directorul "nbproject".Alegeti jfc si apoi
Notepad si apasati butonul OpenProject.Interfata NetBeans va ofera avan-
tajul de a putea deschide si compila fiecare fila separat.In plus puteti
studia structura arborescenta a proiectului si filele de resurse.Observati
ca filele de cod sunt arhivate in directorul "default package" in timp ce
resursele grafice au un director separat.Pentru executia proiectului,
alegeti din meniul Run,optiunea Run Project.
Incercati sa construiti un proiect elementar,cu o fila simpla Java.

-11-
O alta platforma software destinata pentru crearea proiectelor si apli-
catiilor Java,poarta numele de Eclipse si poate fi descarcata gratuit de
la adresa http://www.eclipse.org.Platforma este freeware si open source
si formeaza un instrument de lucru extrem de util.Contine si cateva tuto-
riale,inclusiv cel pentru crearea unei aplicatii simple.Urmariti acest
tutorial si creati o aplicatie simpla de tip HelloWorld.Observati ca spre
deosebire de fila simpla tip text,platforma a generat un folder special
pentru aplicatie,in care sunt incluse:o fila proiect,o fila .classpath
un director denumit "bin" in care se includ filele .class si un director
denumit "src",in care se includ filele sursa.
Platforma nu este utila doar pentru organizarea si impachetarea filelor
ci asigura si un set intreg de facilitati si operatii suplimentare.Des-
crierea acestei platforme,depaseste scopul acestui manual,dar este reco-
mandabil sa descarcati aceasta platforma,daca nu aveti un alt instrument
de lucru preferat.
In general,java lucreaza cu module,organizate ierarhic.Cel mai mic
modul recunoscut de limbaj,poarta numele de token si este echivalentul
unui "atom" lexical (Exemple: identificator,cuvant cheie,operator etc.).
Mai multi tokeni se organizeaza lexical,pentru a forma o expresie (de
obicei o linie de cod) concretizata printr-o comanda sau o instructiune
de procesor.Mai multe astfel de expresii,se grupeaza in blocuri de date,
denumite functii,metode sau proceduri,in functie de particularitatile din
definitie.Pentru a grupa grupuri mai mari de date,expresii,functii si me-
tode,exista structuri mai complexe denumite obiecte si clase.Mai multe
clase formeaza o fila,iar mai multe file se pot grupa in directoare spe-
ciale,pentru a forma pachete.Pachetele sunt continute pe o unitate de
memorie.Unitatile de memorie,pot fi coordonate de o centrala,sau un ser-
ver,pentru a forma o retea locala de calculatoare,iar retelele locale se
poat interconecta pentru a forma o super-retea,denumita Internet.
Limbajul Java permite interventia la nivelul oricarui astfel de modul.
Java este un limbaj de nivel inalt,adica utilizeaza o serie intrega de
conventii,prin care programatorul poate exprima foarte exact ce anume
doreste sa implementeze.Pentru executie,este necesar ca fiecare astfel de
conventie sa fie recunoscuta si retranscrisa simbolic in limbaj masina.
Pentru acest scop,programul compilator face o comparatie intre fila sursa
si un tabel in care sunt reprezentate conventiile de limbaj.Orice grup de
caractere ce nu poate fi interpretat de catre aceasta tabela de comparatie
va fi tratat ca si cand ar fi un simplu sir de caractere.Din acest motiv,
este imperios necesar sa respectati cu strictete conventiile de limbaj.
Acest manual nu poate face o prezentare exhaustiva a acestui set de
conventii,ci va face doar o trecere sumara in revista si se va axa mai
mult pe exemple practice.Pentru a putea verifica si depana aplicatiile
d-voastra este insa obligatoriu sa detineti si o referinta completa a
limbajului (standardul de limbaj).O astfel de referinta poate fi descar-
cata de pe Internet cu numele de "langspec-3.0".
Este inerent ca in etapa de invatare sa faceti o serie intrega de gre-
seli,semnalate si amendate de compilator.Nu va descurajati.Corectati cu
rabdare fiecare greseala,apoi recompilati fila sursa,pana cand obtineti
rezultatul dorit.Si din acest motiv,este recomandabil sa utilizati o plat-
forma de dezvoltare a aplicatiilor (depanarea este mai usoara).

-12-
ELEMENTELE DE LIMBAJ

Cele mai mici elemente ale limbajului sunt caracterele,spatiile goale,


markerii,cifrele simple,caracterele speciale (gen CR si LF pentru termi-
narea unui rand) si operatorii.Urmeaza tokenii,valorile numerice,variabi-
lele si constantele,sirurile de caractere,functiile,clasele si obiectele
etc.
Comentariile se pot include astfel:
1. /* text */ -comentariul este cuprins intre /* si */
2. // text -comentariul este intre // si capatul randului
In Java,comentariile au o semnificatie speciala.Nu numai ca marcheaza
si explica un bloc de instructiuni,dar se pot utiliza pentru a genera un
fel de manual de referinta al aplicatiei.Astfel,utilitarul Javadoc extrage
toate comentariile din fila sursa si genereaza o fila de tip HTML in care
descrie toate clasele si interfetele,constructorii,metodele si campurile
de date (inregistrarile),impreuna cu comentariile care le marcheaza.In
procesul de depanare,programatorul nu trebuie sa mai urmareasca fiecare
modul,ci poate sa citeasca direct fila API astfel generata.
Nu este obligatoriu sa utilizati acest mecanism de lucru,dar este
recomandabil,mai ales in cazul aplicatiilor complexe ce se extind pe mai
multe file sursa.Pentru aplicatiile mici,sau evidente,este recomandabil
sa va rezumati la comentariile strict necesare.Exemplele oferite impreuna
cu setul de instrumente,contin si cate o licenta de utilizare inclusa tot
sub forma de comentariu.Daca doriti,puteti sa proceati in mod similar,
dupa ce creati un sablon cu textul dorit.In acest caz,la distributia
aplicatiilor,nu va mai fi necesar sa adaugati si o fila de licenta,aceasta
putand fi generata la nevoie cu javadoc.
Din punctul meu de vedere,acest procedeu incarca in mod inutil memoria
de operare utila,cu date inerte,dar aceasta solutie este foarte agreata
de cei care pun accentul pe "drepturile de autor".
Un identificator,este o secventa continua de litere si cifre,dintre
care prima trebuie sa fie o litera.Pentru a forma identificatori cat mai
discriminativi,se unesc mai multe cuvinte si se utilizeza cate o litera
mare la inceputul fiecarui cuvant:
EXEMPLE: PrimulDintreIdentificatori AlDoileaDintreIdentificatori
Se exclud cuvintele cheie,valorile booleene si cele nule,etc.
Nu se vor utiliza operatori si semne de punctuatie in formarea unui
identificator,pentru a nu genera erori de executie.Compilatorul face
distinctie intre majuscule si minuscule: "Unu" -nu este egal cu- "unu"
Limbajul Java accepta seturi diferite de caractere Unicode: litere latine,
grecesti,cyrilice etc. (vezi The Unicode Standard).
In limbajul java sunt rezervate urmatoarele cuvinte cheie:
abstract,assert,boolean,break,byte,case,catch,char,class,const,continue,
default,do,double,else,enum,extends,final,finally,float,for,if,goto,imple-
ments,import,instanceof,int,interface,long,native,new,package,private,pro-
tected,public,return,short,static,strictfp,super,switch,syncronized,this,
throw,throws,transient,try,void,volatile,while.
In orice context,cuvintele de mai sus vor fi interpretate a fi cuvinte
cheie si vor fi executate ca atare de catre compilator (cu exceptia celor
incluse in string-uri).Utilizarea lor in orice alt context,decat cel stan-
dardizat,genereaza o eroare de executie.

-13-
Pentru a forma clase si respectiv obiecte,Java recunoaste un set intreg
de tipuri de data,ce pot fi utilizate pentru a forma campuri de date,arii,
constante si variabile,etc.Principalele astfel de tipuri de data sunt:
ARRAY,BIGINT,BINARY,BIT,BLOB,BOOLEAN,CHAR,CLOB,DATALINK,DATE,DECIMAL,DIS-
TINCT,DOUBLE,FLOAT,INTEGER,JAVA OBJECT,LONGNVARCHAR,LONGVARBINARY,LONG-
VARCHAR,NCHAR,NCLOB,NULL,NUMERIC,NVARCHAR,OTHER,REAL,REF,ROWID,SMALLINT,
SQLXML,STRING,STRUCT,TIME,TIMESTAMP,TINYINT,VARBINARY,VARCHAR
(vezi clasa Types din sql)
Pentru a forma expresii,Java recunoaste urmatorii 37 de operatori:
= > < ! ~ ? ? :
== <= >= != && || ++ --
+ - * / & | ^ % << >> >>>
+= -= *= /= &= |= ^= %= <<= >>= >>>=
Urmatoarele caractere au rol de separatori:
( ) { } [ ] ; , .
VARIABILE: -limbajul Java este un limbaj puternic tipizat,astfel fiecare
variabila si fiecare expresie va corespunde unui anumit tip de data ce
poate fi recunoscut de catre compilator.Orice eroare in sintaxa sau in
semantica unei expresii va transforma expresia respectiva intr-un sir de
caractere fara semnificatie pentru compilator.Tipurile de data Java pot
fi impartite in tipuri primitive:boolean si numeric (byte,short,int,long,
char,float,double) si tipuri de data de tip pointer (arii,obiecte si
clase etc.).Exista si un tip special -tipul NULL.Datele de tip sir de
caractere sunt de obicei arhivate in obiecte de tip String.Diferenta intre
tipurile de data primitive si cele de tip pointer o reprezinta faptul ca
tipurile primitive sunt prezente in momentul compilarii,in timp ce tipu-
rile de data prin referinta (pointer) pot fi absente in momentul compi-
larii,pentru a fi prezente in momentul executiei,dupa ce au fost incarcate
filele si fisierele sursa.
Tipurile de data,se utilizeaza pentru a crea variabile,cu declaratii
de genul: int i= 7; sau long nr1 = 2.71352;
In Java,toate declaratiile se fac in interiorul unei clase.In functie
de modificatorul utilizat,o astfel de variabila poate fi statica,caz in
care este prezenta in toate obiectele create din clasa respectiva,sau
poate fi declarata sub forma de camp de date nonstatic (instance varia-
bile) atunci cand nu este declarata cu "static".Variabilele de tip instan-
ta (non-statice) au valori unice in fiecare instanta (obiect creat din
clasa respectiva).Daca variabilele sunt declarate in interiorul unei me-
tode,vor fi variabile locale (adica nu vor avea vizibilitate in afara
metodei respective).Variabilele pot avea si calitatea de parametru,atunci
cand se utilizeaza ca argumente ale unei functii,sau metode.
Aceste amanunte,au o semnificatie mai mica in etapa de compilare a
programului,dar pot avea o importanta majora in etapa de executie.Astfel,
o variabila locala,apelata dintr-un spatiu fara vizibilitate,va genera un
mesaj de eroare.
Tipurile primitive de data asigura si o valoare implicita (nu este
necesar sa fie initializate).Aceste valori implicite sunt: byte = 0,
short = 0,int = 0,long = 0L,float = 0.0f,double = 0.0d,char = '\u0000',
String = null,boolean = null,orice obiect = null.
Constantele (literals) sunt asemantoare cu variabilele,dar au valoare
fixa: boolean result = true; sau char capitalC = 'C';

-14-
Atat variabilele cat si constantele ce contin valori de tip numeric
de tip "int",pot utiliza sistemul numeral decial,cel octal sau cel hexa-
zecimal.Pentru valorile exprimate octal se adauga un zero in fata valorii
numerice iar pentru cele exprimate hexazecimal se adauga 0x.
EXEMPLU: int decimal1 = 26; //are valoarea 26
int octal = 032; //are tot valoarea 26
int hexa1 = 0x1a; //are tot valoarea 26
In cazul numerelor in virgula mobila,se pot utiliza atat scrierea
stiintifica (cu E sau e) cat si conventiile F si f(32-bit float literal)
si respectiv D si d(64-bit double literal)
EXEMPLU: float f1 = 123.4f;
float f2 = 1.234e2;
double d1 = 123.4;
Atat pentru numere cat si pentru stringuri se pot utiliza si urmatoarele
caractere speciale:
\b (backspace), \t(tab), \n(line feed), \f(form feed), \r(carriage return)
\"(double quote), \'(single quote) si \\(backslash).
Un tip special de variabile sunt cele de tip arie de date.O arie este
de fapt un container ce contine un anumit numar de elemente,ordonate in
functie de un numar de indexare.Fiecare element din arie poate fi apelat
prin numarul sau de indexare.Numarul de elemente din arie se declara in
momentul in care se declara variabila.O arie de date,poate contine orice
tip de date:
EXEMPLE: int[] Arie1; // declara o arie de integri
Arie1 = new int[10]; //aloca 10 elemente pentru Arie1
Arie1[0] = 100; //initializeaza primul element
Arie1[1] = 200; //initializeaza al doilea element
....etc.
Pentru alte tipuri de date,se vor utiliza constructii similare:
byte[] aria1; // creaza o arie de bytes
short[] aria2; // creaza o arie de short int
boolean[] aria3; // creaza o arie de valori booleene
String[] aria4; // creeaza o arie de siruri
Exista si functii specializate pentru lucrul cu arii de date.De exemplu,
clasa System contine metoda arraycopy() specializata pentru a copia datele
dintr-o arie in alta.
Datele pot fi convertite de la un tip de data la altul.Pentru tipurile
primitive de date,exista functii standardizate,iar pentru cele de tip
pointer trebuie sa scrieti functii specializate pentru fiecare tip de
conversie.
Prin combinarea variabilelor cu operatori si semne de punctuatie se
pot forma expresii.O expresie este o combinatie de identificatori,date,
semne de punctuatie si apeluri la functii sau metode,in care se respecta
conventiile de limbaj,astfel incat prin evaluarea expresiei sa rezulte
o valoare acceptata de standardul de limbaj.In urma evaluarii expresiei,
procesorul trebuie sa poata inlocui expresia prin valoarea rezultata.In
caz contrar,expresia va fi interpretata a fi un simplu sir de caractere.
EXEMPLU: if(value1==value2) System.out.println("value1==value2");
Expresia va putea fi evaluata astfel: daca cele doua valori sunt egale,
va rezulta un sir de caractere("value1==value2"),iar in caz contrar
va rezulta o valoare nula.

-15-
Evaluarea unei expresii se face in ordinea prioritatilor,sau daca toate
elementele au acceasi prioritate,se va face in ordinea in care apar in
expresie.In cazul operatorilor,prioritatile poarta numele de precedenta
si respecta urmatoarea ordine descrescatoare:
OPERATORI PRECEDENTA
postfix expr++ expr--
unari ++expr --expr +expr -expr ~ !
multiplicare * / %
aditivi + -
salt binar << >> >>>
relationali < > <= >= instanceof
egalitate == !=
bitwise AND &
bitwise exclusiv OR ^
bitwise inclusiv OR |
AND logic &&
OR logic ||
ternar ? :
atribuire = += -= *= /= %= &= ^= |= <<=
>>= >>>=
Daca intr-o expresie se utilizeaza mai multi operatori,acestia vor fi
executati in ordinea precedentei:
EXEMPLU: x+y/100 executa y/100 apoi adauga x
O astfel de expresie se numeste ambigua.Pentru a specifica exact ordinea
de executie se pot utiliza parantezele rotunde:
EXEMPLU (x + y) / 100 executa x+y,apoi imparte la 100.O astfel de
expresie nu este ambigua si nu se preteaza la nici un fel de erori.
Pe cat posibil,este preferabil sa impartiti expresiile mari in seturi de
expresii mai mici,din care sa eliminati orice ambiguitati.In acest mod,
se evita orice eroare,iar aplicatia este mult mai usor de depanat.
Un tip special de expresii sunt cele care poarta umele de instructiuni.
Instructiunile sunt unitati complete de executie cu o semnificatie spe-
ciala pentru compilator.Compilatorul urmeaza sa transforme instructiunea
intr-un set de operatii simple.Exemple: atribuirea de valori,apelul unor
functii si metode,crearea unor variabile sau obiecte,etc.Un tip secial de
instructiuni sunt cele utilizate pentru controlul fluxului de executie si
sunt formate din bucle de operatii iterative (repetitive).
Mai multe expresii si instructiuni se pot grupa in blocuri de executie
denumite functii,metode sau proceduri.Functia este un grup bloc de execu-
tie in care se evalueaza toate expresiile si se executa toate instructiu-
nile dupa care se returneaza valoarea rezultata.Evaluarea unei functii
trebuie intotdeauna sa returneze o valoare.Procedura este asemantoare cu
functia,dar nu returneaza valori,decat daca se sepcifica explicit in
cadrul procedurii.Metoda,este o functie sau o procedura declarata in ca-
drul unei clase.Metoda nu poate fi apelata decat dupa ce se creaza un
obiect din clasa respectiva.Pentru apelul unei metode,se va utiliza o
expresie in care se precizeaza numele obiectului si apoi numele metodei,
separate prin punct.
EXEMPLU: obiect1.metoda1
Atat functiile cat si procedurile sau ,metodele pot avea unul sau mai
multi parametri,caz in care se spune ca sunt "paramterizate".

-16-
CLASE SI OBIECTE
Clasa este modulul structural de baza,in orice program orientat spre
obiect,iar in Java este "piatra de temelie" pentru orice tip de program.
Practic,o clasa este exchivalenta cu un miniprogram complet.O clasa incap-
suleaza un set oarecare de date,numite campuri de date sau proprietati si
un set oarecare de functii executabile,denumite metode.Fiecare metoda
grupeaza un set oarecare de expresii,instructiuni si comenzi.Mai mult
decat atat,o clasa contine de obicei si o functie specializata pentru
operatiile de initializare (creaza un obiect),denumita constructor si
o functie specializata pentru eliberarea memoriei,denumita functie des-
tructor.Clasa ca atare nu este un modul de program functional ci este
doar un set de declaratii si definitii cu ajutorul carora functia cons-
structor poate crea un obiect din clasa respectiva.Cu alte cuvinte,clasa
este un fel de matrita,sau sablon ce se poate utiliza pentru a forma se-
turi de obiecte identice.Fiecare obiect generat,va contine setul de date
si setul de metode declarate in clasa de origine.
Practic,informatia este organizata in felul urmator:
-definitia clasei este arhivata in memorie la o adresa oarecare
-se creaza un pointer (o referinta) spre adresa de memorie la care este
arhivata clasa respectiva.In program,clasa este reprezentata doar prin
pointerul sau,adica prin adresa sa de memorie.
-atunci cand se creaza obiecte,se creaza niste tampoane de memorie in
care se copiaza datele de la adresa clasei si in plus se construiesc si
restul de structuri de memorie necesare:variabile si constante,tampoane,
arii de date etc.Astfel,daca definitia clasei se rezuma la declararea
tipurilor de data,obiectul trebuie sa expandeze memoria astfel incat sa
permita operatii asupra datelor continute.Ca rezultat,obiectul va ocupa
de multe ori mai multa memorie decat clasa de origine.Pentru fiecare
obiect generat,sa va crea cate un astfel de tampon de memorie.In general,
obiectele sunt plasate in memorie la alta locatie decat clasa de origine,
astfel incat sa fie cat mai usor de accesat in program.Datele incluse
in obiect sunt deja date reale,ce pot fi accesate,prezentate sau pot fi
incluse in operatii (in clase toate datele sunt virtuale,sau abstracte).
Declararea unei clase noi,este echivalenta cu crearea unui nou tip de
data.O clasa poate fi declarata si in interiorul unei alte clase,caz in
care se spune ca este o clasa intricata (nested class).Mai frecvent,o
clasa se poate crea modificand o alta clasa.In acest caz,se spune ca este
o clasa derivata din clasa de origine si mosteneste toate campurile de
date si metodele clasei ancestoare.Exista si clase create special pentru
a fi utilizate pe post de sablon pentru alte clase.Aceste clase nu contin
declaratia completa a tipurilor de date,ci doar un schelet general al
modulului si poarta numele de clase abstracte.Clasele abstracte nu pot
fi utilizate pentru a crea obiecte.Clasele abstracte trebuie sa fie deri-
vate in clase mastenitoare la nivelul carora sa se faca completarea decla-
ratiilor si definitiilor necesare.Clasele declarate cu modificatorul "pu-
blic" au vizibilitate si in afara filei in care sunt declarate,adica sunt
un fel de module ubiquitare.Mai multe clase se pot grupa pentru a forma o
interfata.Atunci cand intr-o clasa mostenitoare se declara o metoda noua,
cu nume identic cu cel al unei metode mostenite de la ancestori,fenomenul
poarta numele de supraincarcare (overloading).Obiectul derivat va contine
metoda cu definitia noua (cea mostenita va fi ignorata).

-17-
Cu alte cuvinte,o clasa este oarecum asemanatoare cu o biblioteca DLL,
iar un obiect este asemanator cu un mic program executabil,independent.
O aplicatie formata din obiecte,este asemenatoare cu una formata din mai
multe programe executabile mici.
De ce nu se arhiveaza in memorie direct definitia obiectelor ?
Clasele prezinta urmatoarele avantaje:
-ocupa mai putin loc in memorie
-nu pot fi executate si ca urmare nu pot fi corupte in timpul executiei
-nu se modifica in timpul executiei
-clasa poate utiliza functii automate pentru a genera serii de obiecte
-clasele pot fi derivate si transformate succesiv pentru a forma serii de
clase (din care se obtin serii de obiecte)
-clasele genereaza obiectele automat (cu ajutorul constructorului)
-clasa se poate utiliza pentru a verifica sau depana un obiect in timpul
executiei programului
-clasele se pot arhiva in file independente pentru a putea fi utilizate
simultan de catre un numar mare de aplicatii
-clasele permit si definitii abstracte (fara instante reale)
-clasele sunt arhivate la alte adrese de memorie decat obiectele si permit
depanarea automata a programului,prin intermediul unor functii specia-
lizate pentru tratarea erorilor
In concluzie,obiectele sunt module de program complet independente,ce
pot fi create cu ajutorul unor matrite,numite clase.
Tipurile de data incluse intr-o clasa poarta numele de membri.O clasa
poate contine urmatoarele tipuri de membri:
-membri mosteniti de la o eventuala interfata (ce contine clasa)
-membri mosteniti de la ancestori
-membrii proprii (cei declarati in interiorul clasei)
Atunci cand se vorbeste despre tipul unei clase,aceasta expresie se
refera la:
-tipul de data al argumentelor functiei sau metodei
-tipul de data returnat de membrul respectiv
-clauza de exceptie throw (tipul de data al exceptiei tratate)
Spre deosebire de clasele C++,clasele Java sunt dotate cu un asa numit
mecanism de depanare automata.In ce consta acest mecanism ? Atunci cand se
executa o metoda oarecare,este posibil ca in timpul executiei sa fie
generata o eroare de executie.De exemplu,prin evaluarea unei expresii,
poate sa rezulte un alt tip de data decat cel pe care trebuie sa-l retur-
neze expresia.In acest caz,procesorul intalneste o eroare de executie si
in mod normal intrerupe executia si afiseaza eroarea.Pentru a evita intre-
ruperea programului,metoda poate include si o functie speciala,destinata
pentru a "trata" eventuala eroare in timpul executiei.O astfel de functie
este clauza "throw",prin care metoda poate renunta la o anumita valoare,
atunci cand nu corespunde cu tipul de data asteptat in urma evaluarii
expresiei.In acest caz,daca o expresie returneaza un tip de data eronat,
aceasta va fi "aruncata",adica se va renunta la ea,in loc sa se intrerupa
executia programului.Eroarea este totusi inregistrata si urmeaza sa fie
afisata dupa terminarea executiei (fara a intrerupe programul).Acest
mecanism,pare greoi,dar permite o serie de solutii tehnice inaccesibile
in alte limbaje de programare (decat daca se implementeaza functii auxi-
liare).Rutinele pentru autodepanare sunt facultative.
-18-
Pentru a declara o metoda,formula generala este:
identificator ( lista de paramatrii);
La aceasta formula,se pot adauga modificatorii,tipul parametrilor,tipul
de data rezultat si clauza throw.
Acest manual nu poate include recomandari complete pentru modul de
definitie al unei clase noi.In principiu,trebuie sa organizati datele
de asa maniera incat obiectul rezultat sa fie un modul de program ce
executa un anumit set de operatii.Constructorul trebuie astfel conceput
incat sa creeze si sa initializeze obiectul,iar destructorul trebuie sa
elibereze complet memoria.Daca nu stiti sa creati astfel de clase,este
recomandabil sa utilizati doar clase standard,fie ca atare,fie persona-
lizate prin adaugarea unor metode si campuri noi.Clasele standardizate
(cele incluse in pachetele Java) prezinta urmatoarele avanataje:
-sunt sigure si performante
-sunt deja in memorie,nu trebuie decat sa le apelati
-sunt organizate ierarhic si au o documentatie completa
-pot fi verificate si depanate de orice alt programator
-nu pot genera nici un fel de erori "accidentale"
In toate situatiile trebuie sa tineti cont de urmatorul postulat:
-in program,clasa nu este decat o adresa de memorie,in timp ce obiectul
este un tampon de memorie real,in care se pot face operatii.
In prima etapa,trebuie sa va familiarizati sa lucrati cu utilitarul
Help si cu documentatia de care dispuneti.Java contine zeci de pachete,
cu sute si mii de clase,constante,functii,variabile etc.Nu pot fi reti-
nute si nici nu este util.Pentru orice obiect si orice metoda apelata,
trebuie sa verificati si documentatia,pentru a va asigura ca respectati
standardul de limbaj.Pentru a putea edita programe performante,este obli-
gatoriu sa puteti verifica si depana orice expresie din program.Nu incer-
cati sa faceti "colaje" cu fragmente de program extrase din alte programe,
deoarece rezultatele pot fi imprevizibile.Acest gen de solutie este po-
sibil doar atunci cand cunosteti exact fiecare modul utilizat,impreuna cu
toate extensiile,link-urile,adresele de memorie referite,resursele si
filele de comanda si control,mecanismele de eliberare a memoriei,precum
si masurile de securitate si control.Clasele pot fi utilizate ca atare,
in orice situatie,in timp ce fragmentele arbitrare de program pot fi in
relatie cu diverse alte structuri de memorie,ce tin de mediul de operare,
sau de resurse importate de la diverse alte adrese de memorie.Java permite
lucrul si cu resurse situate la diverse adrese de memorie din reteaua
Internet.Pentru a avea acces la aceste resurse,de multe ori sunt necesare
instrumente si programe speciale,parole si coduri de acces sau structuri
specializate de memorie,programe de conversie etc.Nu incercati sa depa-
nati sau sa transformati un program in care exista si fragmente de cod
pe care nu le intelegeti,sau nu le puteti controla cu resursele locale.
Pe langa pachetele de clase standard incluse in kit-ul de dezvoltare,
puteti descarca din retea o serie de alte pachete auxiliare,specializate
pentru un anumit tip de aplicatie.Este recomandabil ca pentru astfel de
pachete sa obtineti si documentatia completa.Incercati fiecare clasa si
metoda in exemple izolate,inainte de a le include in program.Nu este ru-
sinos sa apelati la Help,sau sa cautati cu Google solutia unei anumite
probleme-dimpotriva,este un test de maturitate ( cu cat sunteti mai bine
informati,cu atat munca d-voastra va fi mai performanta).
-19-
INTERFETE GRAFICE

In general,o interfata este o structura de date ce se interpune intre


program si utilizator.Cele mai frecvente interfete sunt cele grafice.
Intr-o interfata grafica se utilizeaza de obicei grupuri de obiecte vi-
zuale functionale,prin intermediul carora utilizatorul poate sa execute
diverse seturi de operatii,fara sa cunoasca codul aplicatiei si fara sa
fie programator.Cel mai simplu exemplu de interfata grafica il reprezinta
fereastra Desktop din Windows,cu bara de start si utilitarul My Computer.
Un alt exemplu simplu il reprezinta browserele pentru Internet.Orice
browser va deschide o fereastra cu un meniu: File,Edit,View,Tools si Help,
o bara de butoane cu Back,Forward,Stop,Refresh...etc. si o caseta de tip
text pentru adresa http:\\,urmata de butonul Go.Utilizatorii s-au obisnu-
it cu acest format,astfel incat orice browser nou va contine si aceste
instrumente vizuale,deja "clasice".
Cu alte cuvinte,o interfata grafica este un fel de contract,prin care
programatorul poate sa utilizeze in mai multe aplicatii acelasi grup de
obiecte,implementate la fel.Interfata este asemanatoare cu un sablon,sau
cu o clasa abstracta,in sensul ca nu face decat sa ordoneze structura
unui anumit grup de obiecte (de obicei grafice).
In Java,o interfata se declara prin cuvantul cheie Interface,la fel ca
si o clasa abstracta.In interiorul interfetei se vor declara toate clasele
necesare,constantele si variabilele,sau metodele proprii.In interfata nu
se include si definitia detaliata a calselor sau metodelor ci doar numele
si tipul lor.Ca rezultat o interfata nu poate fi utilizata pentru a crea
obiecte,ci doar pentru a implementa o clasa,sau pentru a extinde interfata
cu noi proprietati.
EXEMPLU: public interface Meniu1 {
// aici se declara constantele
// aici se declara variabilele
int metoda1(parametru1,parametru2);
long metoda2 (parametru3);
// ...etc.
}
In aceasta forma,interfata nu este decat o adresa de memorie spre care
s-a creat un pointer.Pentru a putea fi utilizata,interfata trebuie sa
fie implementata printr-o clasa,in care se vor completa declaratiile
tuturor metodelor.
EXEMPLU: public class MeniulDorit implements Meniul1 {
int x=7;int y=15;int z=23;
int metoda1(int a,int b) {
a=(x+y);
b=(a+z); }
long metoda2(long numar) {
numar=(a+b)/(a-b); }
}
Observati ca metodele au definitii complete.In continare,clasa Meniul-
Dorit poate fi utilizata pentru a crea instante ale interfetei.Interfetele
grafice se implementeaza similar,cu deosebirea ca fiecare metoda va fi
constructorul unui obiect vizual functional(buton,lista,caseta de dialog).
In sinteza,interfata contine doar o lista a componentelor utilizate.

-20-
Ce avantaje prezinta utilizarea interfetelor ? In primul rand,se pas-
treaza in memorie un sablon,astfel incat interfata cu utilizatorul va
avea intotdeauna acelasi aspect.In al doilea rand,dintr-o interfata se
pot implementa clase diferite,astfel incat chiar daca aspectul va fi
acelasi,functionalitatea va fi diferita.Concret,atunci cand se implemen-
teaza clasa din care se va deriva obiectul,definitia metodelor poate fi
diferita de la o clasa de implementare la alta.Ca rezultat se pot obtine
aplicatii diferite,in care interfata are acelasi aspect,cu acelasi numar
de butoane si componente,dar butoanele vor functiona diferit,sau vor uti-
liza o solutie diferita de rezolvare a problemei.Cu alte cuvinte,functio-
nalitatea unei interfete poate fi actualizata sau transformata foarte
usor.In plus,interfata poate fi utilizata ca punct de plecare pentru
depanarea unei aplicatii.
Mai mult decat atat,o interfata se poate crea prin extinderea unei alte
interfete,sau chiar prin combinarea a doua sau mai multe interfete.
EXEMPLU:
public interface Grup1 extends Interface1,Interface2,Interface3
{ //declaratia constantelor
//declaratia metodelor
// declaratia claselor incluse
// ...etc.
}
In exemplul de mai sus,interfata Grup1 se va forma prin combinarea
celor trei interfete,la care se adauga metodele si clasele din declaratie.
Acest mecanism de mostenire multipla,permite formarea de structuri com-
plexe,pornind de la grupuri mici de componente.Exemplul cel mai simplu il
reprezinta o pagina de ziar electronic,in care interfata grafica grupeaza
pe coloane mai multe interfete simple.
Interfetele pot fi publicate in retea,pentru a putea fi utilizate in
comun,de doi sau mai multi programatori.
O interfata o data arhivata si publicata,nu mai poate fi schimbata,
deoarece va afecta toate aplicatiile create cu ajutorui ei.Din acest
motiv,ori de cate ori este necesar sa actualizati sau sa modernizati o
interfata,este recomandabil sa o extindeti pentru a crea o interfata
noua.
In particular,interfetele de tip grafic ofera o serie intreaga de
avantaje.In primul rand izoleaza utilizatorul de codul aplicatiei.Utili-
zatorul nu trebuie sa stie unde este codul aplicatiei si nici nu are
nevoie de nici o notiune de programare pentru a utiliza programul.In
unele situatii,nici programatorii avansati nu pot avea acces la codul
sursa.Pe langa faptul ca asigura un mecanism mult mai comod de lucru,o
interfata grafica trebuie si sa asigure securitatea programului,astfel
incat codurile sa nu poata fi modificate,iar utilizatorul sa nu poata
introduce date ce pot deranja functionalitatea programului.Pentru acest
scop,fiecare obiect grafic va avea si o functie de control,sau un filtru
de executie,prin care va refuza,sau va "arunca" (throw) eventualele date
introduse gresit.
Pentru o functionalitate cat mai simpla,o interfata poate fi implemen-
tata si cu ajutorul unei functii simple (atunci cand nu este necesar sa
fie declarate metode noi).In acest caz,se vor putea utiliza doar metodele
implicite (standard).

-21-
Cea mai simpla interfata Java este inclusa in pachetul "lang" cu
numele de Runnable.Aceasta interfata are o singura metoda si anume metoda
Run().Aceasta interfata se utilizeaza ori de cate ori doriti sa utilizati
un thread (un fir de exectie) pentru a executa interfata.Thread-urile
(firele de executie) prezinta avantajul ca permit un mecanism serial de
multiprocesare a datelor,asemanator cu executia paralela.Concret,daca
doua sau mai multe interfete se implementeaza in thread-uri diferite,
acestea vor putea fi executate simultan (procesare multitasking).Cu alte
cuvinte,procesorul va putea executa simultan mai multe sarcini,ca si cand
ar exista mai multe procesoare,in paralel.De fapt,procesorul fragmenteaza
thread-urile in fragmente si apoi executa serial cate un fragment din
fiecare thread,pana cand epuizeaza toate operatiile.La viteza de lucru a
procesorului,se creza senzatia de executie paralela.
EXEMPLU:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class FrameDemo {


private static void creazaInterfata() {
JFrame frame = new JFrame("FrameDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

JLabel JLabel1 = new JLabel("Containerul de tip Frame");


Label1.setPreferredSize(new Dimension(375,100));
frame.getContentPane().add(Label1,BorderLayout.CENTER);

frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() { creazaInterfata(); }} );
}
}
-salvati fila cu numele FrameDemo.java si compilati fila
La executie,exemplul de mai sus va crea o fereastra de suport,denumita
FrameDemo,cu dimensiunile specificate,si cu eticheta amplasata in centrul
ferestrei.Fereastra de tip Frame este containerul de electie pentru orice
interfata grafica vizuala.Acest exemplu,poate reprezenta punctul de ple-
care spre orice interfata grafica de tip Swing.
Se remarca interfata Runnable() utilizata exclusiv pentru metoda Run().
Metoda invokeLater(),din SwingUtilities,are rostul de a apela metoda Run()
doar dupa ce au fost executate toate celelalte evenimente AWT.Cu alte
cuvinte,metoda asteapta pana cand sunt create toate obiectele si pana
cand se executa toate instructiunile de setare,initializare etc.Aceasta
metoda este recomandabila ori de cate ori se utilizeaza un thread,pentru
a implementa o interfata grafica,cu componente din pachetul Swing.
Daca a-ti inteles acest exemplu simplu,restul programarii cu componente
Java Swing este aproape o joaca de copil(se creaza obiecte,se seteaza pro-
prietatile,se organizeaza evenimentele,apoi se executa interfata).

-22-
PACHETE (packages)
Java contine deja sute de clase si limbajul este inca in continua dez-
voltare.Pentru a putea organiza aceste clase,dar mai ales pentru a evita
conflictele de identificator,clasele se grupeaza in containere mai mari,
fie sub forma de foldere,fie sub forma de baze de date.Organizarea in
foldere este mai usor de gestionat si executat de catre orice sistem de
operare,in timp ce organizarea in baze de date,permite operatii diverse
de sortare si selectie a claselor.
Clasele se grupeaza dupa un anumit criteriu,ales fie in functie de
functionalitatea clasei,fie in functie de modul de definitie.Un astfel
de grup de clase,poarta numele de pachet (package) si are rostul de a
asigura accesul la date si de a proteja datele (nu pot fi sterse automat).
Gruparea claselor in pachete,prezinta urmatoarele avantaje:
-programatorii pot observa cu usurinta clasele inrudite intre ele
-programatorii pot identifica usor fiecare tip de clase
-se elimina conflictele de identificator (pot exista mai multe clase cu
acelasi nume,cu conditia sa fie arhivate in alt pachet)
-se creaza un spatiu denumit suplimentar,ce poate fi utilizat pentru orga-
nizarea domeniilor de vizibilitate (Exemplu: clasele dintr-un pachet
oarecare pot avea acces la alte clase din pachet,dar nu si la clasele
arhivate in alt pachet).
Pentru a crea un pachet nou,trebuie sa alegeti un nume unic,diferit
de cele axistente.Numele trebuie sa fie cat mai sugestiv,usor de identi-
ficat si usor de inclus in aplicatii.Frecvent se utilizeaza denumiri
prescurtate,formate din initialele unor cuvinte.Pentru se deosebi de
numele claselor,se utilizeza de obieci doar litere mici.
Exemplu: awt este prescurtarea de la Abstract Window Toolkit
Un pachet,poate contine: interfete,clase,enumerari,exceptii,erori sau
tipuri adnotate.
Pentru fiecare clasa,se vor include in pachet cate doua file: fila
sursa cu extensia .java si fila compilata,cu extensia .class.In mod normal
nu se include decat o singura clasa,in fiecare fila.Fila sursa se va putea
utiliza pentru a dezvolta clasa spre o clasa mai complexa,sau pentru a
forma o clasa derivata (mostenitoare) iar fila compilata se va putea uti-
liza pentru a putea exploata clasa respectiva.
Java este un sistem de lucru "open source" in care totul trebuie sa fie
la vedere.Daca creati clase si pachete noi,trebuie sa oferiti si toate
datele necesare (fila sursa,explicatii si adnotatii,eventual un utilitar
de tip Help,etc.).Pentru a putea identifica pachetul din care face parte
fila sursa,se adauga pe primul rand numele pachetului:
EXEMPLU: package java.awt;
Daca este necesar,fila in care se defineste clasa poate importa alte
clase si pachete.In acest caz,ori de cate ori se va importa clasa res-
pectiva,se vor importa automat si restul de clase interdependente.
Dupa crearea si arhivarea unei clase intr-un pachet,clasa va putea fi
utilizata in programe in trei modalitati:
1.-se apeleaza clasa cu numele intreg (pachet.clasa)
2.-se importa clasa cu include
3.-se importa intregul pachet in care este arhivata clasa.
O clasa se importa prin: import java.numele pachetului.numele clasei
EXEMPLU: import.java.awt.peer.ButtonPeer;

-23-
Pentru a importa intregul pachet,se utilizeaza caracterul *;
EXEMPLU: import.awt.*;
Atentie,atunci cand pachetul respectiv contine la randul sau alte
pachete,acestea nu vor fi deschise automat cu .* ci trebuie sa utilizati
o instructiune import pentru fiecare pachet in parte.
EXEMPLU: import java.awt.*;
import java.awt.color.*;
Atunci cand pachetul contine clase,sau constante cu denumiri lungi,
pentru a nu trebui sa utilizati de fiecare data numele intreg,puteti
importa constanta respectiva cu modificatorul static;
EXEMPLU: pachetul java.Math include si constanta PI astfel
public static final double PI 3.141592653589793
in program se utilizeaza cu:
import java.lang.Math.*;
double numar = Math.PI;
daca PI se importa static,se va utiliza astfel:
import static java.lang.Math.PI;
double numar = PI;
In cazul pachetelor mici,filele sursa pot fi arhivate impreuna cu cele
compilate (in acelasi folder),dar in cazul pachetelor mari se obisnuieste
sa fie arhivate separat.Frecvent,pentru filele sursa se utilizeaza un
director denumit "src",pentru a permite motoarelor de cautare automata
sa identifice fila cat mai usor.
In general,pachetele trebuie arhivate in asa fel incat compilatorul sa
poata avea acces cat mai usor la fila sursa.
Atunci cand doriti sa recompilati o fila sursa,trebuie sa eliminati
eticheta din antet (linia cu instructiunea: package numele; ).
Pentru a asigura accesul cat mai usor la o anumita clasa,se poate
seta o variabila se sistem CLASSPATH:
EXEMPLU: in Windows - C:\> set CLASSPATH = C:\Program Files\bin\clasa1
in Unix - % CLASSPATH = /home/bin/clasa1; export CLASSPATH
Pentru scopuri temporare,sau pentru clase mici de uz restrans,se pot
utiliza file sursa in care nu includeti instructiunea package.In acest
caz,compilatorul va considera ca fila nu face parte din nici un pachet
(chiar daca fila este inclusa intr-un folder cu un nume oarecare).Acest
gen de solutie se poate aplica doar local,sau pentru aplicatii private.
Pentru pachetele oferite in retea,este obligatoriu ca pachetul ca fie
clar definit,printr-un identificator unic(sa fie un spatiu denumit unic).
Pentru a simplifica munca de cautare a unei clase,sau a unui anumit
membru,este bine ca fiecare pachet sa contina si o fila de indexare,in
care toate clasele si metodele sunt ordonate alfabetic.In plus,este bine
ca fiecare pachet sa contina si o nota explicativa: ce clase contine,cum
sunt implementate si pentru ce scop,cum se utilizeaza metodele specifice,
etc.Uneori,este util sa se includa si un arbore genealogic (atunci cand
clasele continute sunt inrudite).
In Java nu se obisnuieste sa se includa file de documentatie separate.
Toate explicatiile si comentariile sunt incluse in fila sursa,de unde
pot fi apoi extrase cu utilitarul special destinat.
Deschideti orice fila sursa.De exemplu: src/java/awt/Button.Observati
ca fila incepe cu un antet (comentariu) in care se specifica autorul.
Urmeaza instructiunea package si instructiunile de import.Apoi urmeaza

-24-
un lung sir de comentarii in care se explica scopul si modul de utilizare
al clasei respective.In continuare,intreaga fila este intesata cu nume-
roase comentarii pentru fiecare functionalitate implementata.
Acest gen de solutie permite altor programatori sa se orienteze cat
mai clar.Java este un minunat instrument didactic pentru programarea avan-
sata (este insa cam greoaie pentru incepatori).
Comentariile ocupa mai mult decat jumatate din fila.Daca urmeaza sa
utilizati fila intr-un mediu cu memorie restransa,puteti sa procedati la
optimizarea codului.Extrageti toata documentatia cu javadoc,arhivati o
copie de siguranta a filei originale,apoi puteti sa stergeti toate comen-
tariile din fila.Fila rezultata va avea aceeasi functionalitate dar va
ocupa mult mai putin spatiu.Puteti sa va personalizati instrumentele de
lucru,cu conditia sa nu alterati functionalitatea codurilor.
Structura pachetelor se rearanjeaza de la o versiune la alta.Pentru
kit-ul de dezvoltare oferit de Java Platform Standard Edition 6,principa-
lele pachete de clase standard sunt incluse in folderele:java si respectiv
javax din directorul "src".In pachetul documentar,gasiti referinte com-
plete in:Java 2 SE 6 Documentation/API (Aplication Proggraming Interface).
Folderul "java" contine urmatoarele pachete:
-applet = contine clasele necesare pentru a crea si utiliza un applet
-awt = contine clasele necesare pentru grafica si imagini si pentru
crearea de interfete
-beans = contine clase pentru aplicatii dezvoltate cu JavaBeans
-io = contine stream-ul de intrare si iesire (obiecte implicite)
-lang = contine clasele java fundamentale (este pachetul implicit)
-math = contine clase aritmetice (a nu se confunda cu lang.math)
-net = contine clase pentru aplicatiile de retea
-nio = contine tampoane,pe post de containere auxiliare pentru date
-rmi = contine pachetul Remote Method Invocation (pt.Virtual Machine)
-security= contine clase si interfete pentru masurile de securitate(acces)
-sql = contine clase ce permit exploatarea bazelor de date
-text = contine clase pentru prelucrare de text,numere,date si mesaje
-util = contine clase utile pt.timp,data,conventii internationale etc.
Folderul "javax" contine urmatoarele pachete:
-accessibility = clase pentru accesul la componentele din interfata
-activation = asigura operatiile de initializare (comenzi,adrese etc.)
-activity = contine exceptii aruncate in timpul pauzelor de executie
-annotatin = posibilele addnotari de constructie sau destructie
-crypto = clase pentru operatii cryptografice
-imageio = pachetul principal Java Image I/O API
-jws = clase pentru operatii Web Service
-lang.model = contine pachete de clase (class-use,element,Source-Ver-
sion,type,util) utile pentru modelarea limbajului Java
-management = contine clasele pentru Java Management Extensions
-naming = clase pentru accesul la servicii denumite
-net = clase pentru aplicatii de retea(altele decat java.net)
-print = clase pentru setarea operatiilor de imprimare
-rmi = contine pachete cu clase pentru aplicatii RMI-IIOP
-script = clase pentru Java Scripting Engine
-security = pachete pentru autorizari,certificate si autentificari
-sound = pachete pentru procesarea sunetelor (midi,sampled)

-25-
-sql = clase pentru accesul bazelor de date din server(server-side)
-swing = componente vizuale pentru interfete grafice
-tools = interfete pentru instrumentele invocate de un program
-transcation = exceptii eliberate in pauzele de executie
-xml = o clasa destinata pentru functionalitatea XML
Pe langa aceste pachete de date,puteti sa adaugati diverse alte pachete
cu clase specifice,create de d-voastra sau descarcate de pe Internet.In
cazul in care oferiti sau comercializati aplicatii scrise in Java,este
recomandabil sa utilizati pachetele standard,sau sa oferiti informatii
detaliate si complete despre pachetele "nonstandard".
Modul in care reusiti sa va orientati in documentatie,precum si modul
in care selectati si dezvoltati clasele si metodele cu care lucrati,este
si va fi definitoriu,pentru calitatea programelor generate de d-voastra.
Cu cat reusiti sa va documentati mai rapid si mai complet,cu atat pro-
gramele realizate vor fi mai clare si mai performante.Indiferent de
scopul propus,este probabil sa gasiti un obiect potrivit,sau cel putin
unul apropiat de cel necesar.Din acest motiv,este recomandabl sa studiati
cat mai amanuntit clasele standard,inainte de a trece la constructia de
clase noi.Daca nici una dintre clase nu va satisface,este bine sa creati
obiectul nou prin dezvoltarea obiectului radacina Object.In acest mod,
obiectul creat de d-voastra se va integra foarte bine cu restul de obiecte
din aplicatie si va puatea fi inclus in formulele automate de cautare,
realizate de asa numitii "roboti".Ca rezultat,aplicatia creata va putea
fi verificata si depanata automat,si va putea fi acceptata mult mai usor
pentru utilizare in sistem "shareware".Atunci cand creati clase noi,este
recomandabil sa le arhivati in pachete noi.Chiar daca o anumita clasa a
fost creata prin extinderea unei clase existente,daca includeti clasa nou
creata in acelasi pachet cu clasa ancestor si oferiti aplicatia in retea,
se vor crea confuzii intre pachetele cu acelasi nume.Din acest motiv,este
esential sa respectati structura pachetelor standard.In cazul in care
optimizati codul,pentru aplicatiile oferite in retea trebuie sa inlocuiti
pachetele "optimizate" cu cele standard.Pentru aplicatiile strict locale,
"optimizarea" poate merge chiar si mai departe.Puteti sa excludeti din
pachet clasele de care nu aveti nevoie,astfel incat sa nu includeti in
aplicatie (respectiv in memoria de executie),decat datele strict necesare.
Aceasta capacitate de modelare a resurselor in functie de memoria exis-
tenta,face din Java o tehnologie de varf,cu infinite posibilitati de
exprimare pentru micro-electronica si dispozitive de comanda si control.
O alta solutie,este sa utilizati pachete optimizate,dar sa le includeti
intr-un pachet nou,cu identificator unic.In acest caz,trebuie sa asigurati
si toata documentatia si sa specificati faptul ca aplicatia este indepen-
denta de pachetele standard.Pe cat posibil este bine sa oferiti si un
utilitar pentru instalarea automata a aplicatiei.
Exista si nenumarate situatii in care limbajul java va fi utilizat
doar pentru a completa o alta aplicatie.Cel mai clar exemplu il reprezinta
applet-urile.Si in acest caz,este recomandabil sa utilizati metoda "open
source" (majoritatea programatorilor si administratorilor de retea refuza
o aplicatie pe care nu o pot verifica si depana complet).
Nu incercati sa epatati prin formule complexe si alambicate.Calitatea
unui programator nu se evalueaza dupa aspectul codului,ci dupa modul de
rezovare a problemei propuse.Solutia cea mai simpla este cea mai buna.

-26-
COMPONENTELE VIZUALE (AWT si SWING)

Limbajul Java este un limbaj complex si permite o serie intreaga de


subtilitati de exprimare.Prezentarea lor exhaustiva formeaza un material
complex,greu de urmarit,si determina scaderea interesului fata de acest
limbaj.Din acest motiv,in acest manual nu se va face o prezentare completa
a notiunilor teoretice,ci se va trece direct la exemple practice.Urmeaza
sa va completati notiunile elementare,atat din capitolele urmatoare,cat
si prin studiu individual.
Programarea moderna a aplicatiilor de tip utilizator,se face aproape
exclusiv sub forma de interefete grafice cu utilizatorul.Clientii s-au
obisnuit sa apese un buton,care sa execute singur toate operatiile nece-
sare.Prin urmare,prima etapa fireasca in crearea unei aplicatii,o consti-
tue proiectarea interfetei grafice.Pentru acest scop,Java a rezervat mai
multe pachete de clase,grupate sub numele de JFC(Java Foundation Classes).
Principalele pachete de clase JFC sunt: AWT si SWING,iar principalele
functionalitati sunt:
-Swing GUI Components = obiecte vizuale pentru interfata grafica(butoane,
liste,meniuri,casete de dialog,evenimente,sortari,drag and drop)
-Pluggable Look-and-Feel support = este o tehnologie prin care obiectele
vizuale pot schimba aspectul,indiferent sa sistemul de operare.
Exemplu: sub Linux,sau sub Mac butoanele pot avea aspectul Windows
-Accessibility API = permit accesul unor tehnologii auxiliare la interfata
grafica.Exemplu: interfata poate fi citita in Braille
-Java 2D API = permite incorporarea de grafica si imagini 2D
-Internationalization = permite ca interfata grafica sa comunice cu uti-
lizatorul prin caracterele specifice fiecarei limbi (japoneza,coreeana,
chineza,greaca,rusa,araba,hindu etc.).
Componentele vizuale Swing se utilizeaza la fel ca orice alt tip de
obiecte vizuale: se importa fila sursa,se creaza obiectul apoi se seteaza
proprietatile.Daca nu aveti nici un editor specializat,toate aceste ope-
ratii trebuiesc realizate la nivel de cod.Daca doriti sa lucrati direct
cu obiectele vizuale,puteti utiliza platforma NetBeans.
Obiectele vizuale nu pot fi create direct in tamponul de memorie ci
trebuie sa fie incluse intr-un obiect de suport,de tip container.Acest
container poate fi de tip JFrame,JDialog sau JApplet.In capitolul intro-
ductiv a fost deja prezentat cel mai simplu exemplu pentru crearea unei
ferestre de tip JFrame.
In container,obiectele vizuale sunt organizate ierarhic in functie de
pozitia din arborele genealogic.Un obiect vizual nu poate fi continut
decat intr-un singur alt obiect container.Daca incercati sa introduceti
obiectul intr-un alt container,atunci obiectul va fi extras din primul
container si va fi transferat in cel de al doilea.Obiectul container
situat la radacina arborelui genealogic prezinta un panou,pe care vor fi
afisate toate obiectele continute,ca pe o panoplie.Optional,containerul
radacina poate include si un meniu.Meniul nu va fi inclus in panou,ci
este o conventie situata intre marginea superioara a ferestrei si panou.
Ca rezultat,optiunile din meniu nu vor putea fi accesate apeland la
metodele panoului,ci se vor apela doar prin metodele proprii.
In afara containerelor amintite,toate componentele Swing sunt derivate
din clasa de baza JComponent,adica mostenesc toate metodele JComponent.
-27-
Cele mai frecvente obiecte dintr-o interfata grafica,sunt butoanele.Un
buton simplu se creaza ca o instanta a clasei JButton.
EXEMPLU:
import java.awt.*;
import java.awt.event.*;
import java.swing.*;
public class Buton1 {
public static void main(String[] args) {
JFrame frame = new JFrame("Fereastra cu buton");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

JButton button = new JButton("Butonul meu");


frame.add(button);

frame.pack();
frame.SetVisible(true);
}
}
-salvati fila cu numele Buton1.java si apoi compilati se executati
fila
Observati principalele operatii: se creaza containerul de tip JFrame,
se seteaza destructorul (setDefaultCloseOperation) pentru a putea elibera
memoria la inchiderea ferestrei,se creaza butonul,se include butonul in
fereastra (cu add),se actualizeaza fereastra(cu pack) si apoi se seteaza
proprietatea setVisible,pentru a putea afisa fereastra (altfel va fi
activa dar in background).
Butonul creat insa nu este functional.Pentru ca butonul sa poata exe-
cuta ceva (operatii),trebuie sa existe o functie specializata,declansata
de apasarea butonului.Aici intervine cea mai radicala deosebire dintre
C++ si Java.Java nu exploateaza nimic din resursele sistemului de operare,
prin urmare nu poate utiliza nici sistemul de mesaje Windows.In locul
mesajelor Windows,Java utilizeaza un set propriu de mesaje.Aceste mesaje
nu sunt de fapt decat niste constante,incluse in fiecare obiect sub forma
de campuri de date.In momentul in care in aplicatie intervine un eveniment
oarecare,obiectul in care s-a petrecut evenimentul elibereaza in mediul
de operare un mesaj format din una dintre aceste constante.Pentru ca
acest mesaj sa poata fi interpretat,trebuie sa existe o functie speciali-
zata.Aceasta functie se numeste "functia de tratare a evenimentului" si
nu face decat sa verifice permanent daca in mediul de operare un anumit
mesaj este prezent,sau este nul.In momentul in care identifica mesajul,
functia executa un set oarecare de operatii,apoi sterge mesajul din mediul
de operare,pentru a evita operatiile redundante.Acest mecanism este mult
mai rapid si mai discriminativ decat cel din Windows ( in Windows,mai
multe evenimente pot elibera acelasi mesaj si respectiv acelasi mesaj
poate fi asteptat de mai multe functii).
Java contine un set intreg de structuri specializate pentru declan-
sarea si respectiv tratarea evenimentelor.Functiile(metodele) specializate
in "asteptarea" si respectiv "tratarea" evenimentelor poarta numele de
EventListeners("asculta" evenimentele) si pot fi de mai multe tipuri,in
functie de operatia ce a declansat evenimentul.Fiecare astfel de metoda
are un singur argument,format din tipul de data pe care il asteapta.
-28-
Evenimentele pot fi primare(low-level),cum sunt cele declansate prin
taste si dispozitivul mouse,sau pot fi evenimente semantice (toate cele-
lalte).Evenimentele primare sunt comune pentru toate componentele din
interfata,in timp ce cele semantice sunt specifice pentru fiecare obiect.
Cand se apasa un buton,se elibereaza un mesaj "actionPerformed" ce poate
declansa metoda EventListener(apartine unui obiect creat din clasa Event).
EXEMPLU:
import java.awt.*;
import javax.swing.*;
import java.awt.BorderLayout;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.util.*;
public class Data2 extends JPanel implements ActionListener {
JButton button;
public Data2() {
super(new BorderLayout());
button = new JButton("Click Me");
button.setPrefferedSize(new Dimension(400,100));
add(button,BorderLayout.CENTER);
button.addActionListener(this);
}
public void actionPerformed(ActionEvent e) {
button.setText("Data curenta: " + new Date());
}
public static void main(String[] args){
JFrame frame = new JFrame("Apasa butonul");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JComponent newContentPane = new Data2();
newContentPane.setOpaque(true);
frame.setContentPane(newContentPane);
frame.pack();
frame.setVisible(true);
}
}
-salvati fila cu numele Data2.java.Compilati si executati exemplul.
Observati ca pentru evaluarea evenimentului "click button" am utilizat:
o interfata ActionListener din care am implementat clasa Data2,un obiect
de tip ActionEvent necesar pentru identificarea mesajului si respectiv o
metoda (actionPerformed) declansata de aparitia mesajului.In plus,in
locul butonului clasic,am creat un component de tip JComponent,in care
am inclus un buton,am setat dimensiunile butonului si apoi am creat o
instanta a interfetei ActionListener (prin intermediul clasei Data2).
Acest exemplu,pare putin incurcat la prima vedere,dar include toate
etapele necesare pentru a exploata obiectele standard.Daca doriti,puteti
sa inlocuiti interfata ActionListener cu una creata de d-voastra,dar
exista riscul sa nu faceti conexiunea corecta dintre mesajul eliberat si
functia de tratare a evenimentului.In plus,trebuie sa codificati si un
timer,care sa citeasca permanent memoria.La orice eroare,fiecare apasare
de buton va crea in memorie diverse instante incomplete ale obiectelor
create,iar butonul va ramane nefunctional.

-29-
Daca doriti sa utilizati o interfata vizuala pentru generarea aplica-
tiei,puteti utiliza NetBeans IDE 6.5 astfel:
Din meniul File,alegeti New Project si alegeti un proiect Java de tip
Java Application,apoi alegeti numele proiectului si adresa de destinatie.
Deselectati optiunea Create main Class (controlul fluxului se va face
prin metoda main generata de obiectul container (JPanel).
Pentru a putea avea acces la paleta de componente vizuale,efectuati un
click drept de numele proiectului (JavaApplication1),alegeti New si apoi
JPanel Form (componentele trebuie incluse intr-un container).In continuare
se poate utiliza paleta de obiecte vizuale.Daca nu este afisata,alegeti
din meniul Window,optiunea Palette.Pentru a alterna intre fereastra de
cod si cea de design,puteti utiliza meniurile Source si Design.Alegeti
meniul Design,apoi deschideti fereastra Palette.Pentru a adauga un obiect
in fereastra de design,alegeti obiectul si trageti de el cu butonul mouse
apasat.De exemplu,trageti un buton OK in fereastra.Sa presupunem ca doriti
sa faceti un utilitar pentru conversia gradelor Celsius in Fahrenheit si
viceversa.Adaugati in fereastra si trei obiecte de tip TextField.In primul
se va introduce valoarea dorita,iar in celelalte doua se vor afisa cele
doua conversii posibile.Pentru a executa aceste operatii cu ajutorul
butonului OK,selectati butonul,executati un click drept,alegeti Events,
apoi Action si actionPerformed.Programul va crea automat functia necesara.
Completati functia astfel:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
double tempFahr = Double.parseDouble(jTextField1.getText())*1.8+32;
double tempCels =(Double.parseDouble(jTextField1.getText())-32)/1.8;
String y = Double.toString(tempFahr);
String z = Double.toString(tempCels);
jTextField2.setText(y);
jTextField3.setText(z);
}
In continuare,reveniti la meniul Design,asezati obiectele in fereastra
dupa bunul plac si apoi adaugati si cateva obiecte Label in care puteti
include explicatiile dorite.Daca doriti sa modificati fonturile si culo-
rile,utilizati din fereastra Palette proprietatile "font" si "background".
Pentru cele trei obiecte de tip TextField setati proprietatea Text la o
valoarea implicita oarecare,de exemplu zero.Schimbati si textul butonului.
Dupa ce fereastra are aspectul si dimensiunile dorite,executati aplicatia
cu Run Main Project.
Daca nu sunteti multumiti de aspect,faceti modificarile dorite.Apoi
puteti construi proiectul cu Clean and Build Main Project (apasand butonul
cu un ciocan si o matura).
Pentru a analiza proiectul in forma finala,deschideti directorul in
care a fost arhivat proiectul(cu Windows Commander).Proiectul va contine
urmatoarele foldere: build,dist,nbproject,src si test.Fila executabila
Windows se gaseste in directorul dist,cu extensia Executable Jar File,
iar fila tip java se gaseste in directorul "src".Fila de tip .class este
arhivata in "build/classes".Analizati structura intregului proiect.
Remarcati ca platforma NetBeans va permite sa realizati o interfata
grafica completa si eleganta,cu doar cateva ckick-uri de mouse si cateva
linii de cod.In continuare,incercati sa dezvoltati aplicatia adaugand
noi componente si functionalitati.

-30-
Fila .java,generata de NetBeans (din directorul src) nu poate fi uti-
lizata direct pentru a crea o fila de tip .class,deoarece nu contine
instructiunile pentru importul pachetelor de clase.Daca doriti sa dezvol-
tati acesata fila in afara platformei NetBeans,trebuie sa adaugati si
toate instructiunile de import.Platforma NetBeans are o tabela de pointeri
catre toate pachetele Java instalate si executa link-ul spre pachetele
necesare doar in momentul executiei (run time).Daca doriti sa executati
filele .class pe un calculator ce nu are instalata platforma NetBeans,fie
utilizati fila gata compilata (din classes),fie recompilati fila dupa ce
a-ti adaugat si pachetele necesare.
Intr-o interfata grafica,componentele pot executa secvente complexe de
operatii.Pentru a putea organiza aceste operatii,este necesar sa proiec-
tati si sa programati serii intregi de evenimente.Un singur component
poate raspunde la doua sau mai multe evenimente,iar acelasi eveniment
poate genera doua sau mai multe operatii simultane,sau consecutive.Cu
alte cuvinte,pentru acelasi obiect se pot conecta mai multe funcii de tip
EventListener si respectiv,pentru acelasi eveniment se pot utiliza mai
multe functii de tip EventHandler.
EXEMPLU: (pentru NetBeans)
-deschideti un nou proiect de tip Java Application (fara clasa Main)
-adaugati un component de tip JFrame Form.
-deschideti Palette si adaugati un buton de tip Button
-redimensionati butonul pentru a putea cuprinde un text mai lung
-click drept pe buton,alegeti Events -> Action -> actionPerformed
-completati metoda jButton1ActionPerformed() astfel:
jButton1.setText("Butonul a fost apasat");
-reveniti in fereastra de design
-click drept pe buton,alegeti Events -> Mouse -> mouseEntered
-completati metoda jButton1MouseEntered() astfel:
jButton1.setText("Mouse este deasupra butonului");
-reveniti in fereastra de design
-click drept pe buton,alegeti Events -> Mouse -> mouseExited
-completati metoda jButton1MouseExited() astfel:
jButton1.setText("Mouse a parasit butonul");
Executati exercitiul cu Run Main Project.Observati cum se modifica
textul in relatie cu miscarile indicatorului mouse pe obiect.
Pentru a conecta o functie noua de tratare a unui anumit eveniment,se
va completa lista Event Handler:
-in fereastra de design selectati butonul
-in fereastra Properties,alegeti Events,apoi apasati butonul cu trei
puncte situat la extremitatea optiunii actionPerformed
-se va deschide fereastra Handlers for actionPerformed in care este
deja inclusa metoda jButton1ActionPerformed
-pentru a adauga o metoda noua,apasati butonul Add,si completati numele
metodei dorite (Exemplu : Redimensionare)
-apoi deschideti fereastra Source si completati metoda astfel:
jButton1.setSize(300,200);
Executati exercitiul din nou.Observati ca la primul click pe buton se
va excuta prima metoda (jButton1ActionPerformed),iar la al doilea click
consecutiv (dublu click) se va executa si metoda a doua (Redimensionare).
Testati butonul cu click si cu dublu click.

-31-
Este foarte important cum alegeti evenimentele si ordinea in care
doriti sa fie executate.De exemplu: evenimentul actionPerformed si eveni-
mentul mouseClicked sunt declansate simultan in momentul in care butonul
este apasat cu un click de mouse.Cele doua evenimente utilizeaza un mesaj
diferit cu o functie Event Handler si o functie EventListener diferita.
Teoretic,cele doua functii se vor executa simultan.Intr-adevar,daca pro-
gramati cele doua evenimente simultan,nu se vor returna erori de compilare
sau de executie.Totusi executia celor doua metode nu se va face simultan
(decat daca utilizati thread-uri diferite).Pentru a evita executiile con-
fuzive,este preferabil sa evitati acest gen de solutii.Inainte de a incepe
programarea propriu zisa,este bine sa faceti o mica schema de executie,
in care sa stabiliti ce operatii doriti sa implementati,ordinea de execu-
tie si respectiv ordinea de prioritati.Apoi alegeti componentele cele mai
potrivite,selectati mesajele cele mai clare pentru fiecare component si
abea apoi incepeti sa introduceti codurile necesare.La un moment dat,
Internet-ul a fost inundat cu reclamatii de acest gen.Programul in sine
este foarte bun (chiar exceptional),dar se pot gasi solutii in care exe-
cutia sa fie confuziva (sau chiar imposibila),fara ca erorile sa fie
detectate in etapa de comiplare (daca sintaxa este corecta).Inainte de
a trece la interfete complexe,este bine sa faceti cat mai multe exercitii
cu obiecte simple si cu operatii simple,secventiale.Executia paralela si
multiprocesarea,vor fi abordate intr-o etapa de studiu mai avansata.
Daca analizati putin fila sursa pentru exemplul anterior,puteti observa
cum cele patru evenimente sunt organizate sub forma de metode.Doua dintre
evenimente sunt de tip ActionEvent si vor fi incluse intr-un obiect de
tip ActionListener,iar alte doua evenimente sunt declansate de catre
mouse si vor fi incluse intr-un obiect de tip MouseListener.
Intr-un program sunt posibile numeroase astfel de evenimente,dar numai
o parte dintre ele sunt utilizate frecvent in programare.Pentru cele mai
frecvente dintre ele,Java include cate o interfata specializata pentru
interceptarea ("ascultarea") evenimentului respectiv.Aceste interfete
standard sunt: ActionListener,AncestorListener,CaretListener,CellEditor-
Listener,ChangeListener,ComponentListener,ContainerListener,DocumentLis-
tener,ExceptionListener,FocusListener,HierarchyBoundsListener,Hierarchy-
Listener,HyperlinkListener,InputMethodListener,InternalFrameListener,
ItemListener,KeyListener,ListDataListener,ListSelectionListener,MenuDrag-
MouseListener,MenuKeyListener,MenuListener,MouseMotionListener,MouseListe-
ner,MouseMotionlistener,MouseWheelListener,PopupMenuListener,Property-
ChangeListener,TableColumnModeListener,TableModeListener,TreeExpansion-
Listener,TreeModeListener,TreeSelectionListener,TreeWillExpandListener,
UndoableEditListener,VetoableChangeListener,WindowFocusListener,Window-
Listener,WindowStatelistener.
Fiecare dintre aceste interfete,contine una sau mai multe metode spe-
cializate pentru evenimentul respectiv.Pentru o parte dintre aceste inter-
fete exista si clase de tip "adapter",create special pentru a implementa
o anumita functionalitate.Exemple: ComponentAdapter,ContainerAdapter,
FocusAdapter,KeyAdapter,MouseAdapter,WindowAdapter etc.Aceste clase contin
toate metodele necesare pentru "asteptarea" si inregistrarea unui anumit
tip de eveniment (Exemplu: evenimentele mouse pentru clasa MouseAdapter).
Clasele adaptoare pot fi apelate direct,interfetele necesita implementare.

-32-
Nu trebuie sa invatati pe de rost aceste interfete.Daca utilizati plat-
forma NetBeans,sau o alta interfata automata,toate obiectele si legaturile
vor fi create automat.Are rost sa intelegeti mecanismul lor,atunci cand
doriti sa depanati o aplicatie,sau atunci cand proiectati o functionali-
tate noua.In toate cazurile,trebuie sa va puteti orienta cat mai rapid in
sursa bibliografica.
Nu toate aceste interfete sunt utile pentru fiecare component.Interfe-
tele comune pentru toate componentele Swing sunt: ComponentListener,
FocusListener,KeyListener,MouseListener,MouseMotionListener,MouseWhell-
Listener,HierarchyListener si HierarchyBoundsListener.Restul pot fi apli-
cate doar pentru unul sau mai multe dintre componente.Pentru a va fami-
liariza cu toate tipurile de evenimente,este bine sa creati cel putin cate
un exemplu din fiecare tip (vezi si tutorialul oferit de firma Sun).
Pachetul Swing contine un obiect(o fereastra) special destinat pentru
selectarea si setarea culorilor preferate:
EXEMPLU:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.colorchooser.*;
public class ColorChooserDemo extends JPanel implements ChangeListener{
protected JColorChooser tcc;
protected JLabel banner;
public ColorChooserdemo(){
super(new Borderlayout());
banner = new JLabel("Obiectul ColorChooser",JLabel.CENTER);
banner.setForeground(Color.yellow);
banner.setBackground(Color.blue);
banner.setOpaque(true);
banner.setFont(new Font("SansSerif",Font.BOLD,24));
banner.setPrefferedSize(new Dimension(100,65));
JPanel bannerPanel = new JPanel(new BorderLayout());
bannerPanel.add(banner,BorderLayout.CENTER);
bannerPanel.setBorder(BorderFactory.createTitleBorder("Banner"));
tcc = new JColorChooser(banner.getForeground());
tcc.getSelectionModel().addChangeListener(this);
tcc.setBorder(BorderFactory.createTitleBorder("Alegeti culoarea"));
add(bannerPanel,BorderLayout.Center);
add(tcc,BorderLayout.PAGE_END); }
public void stateChanged(changeEvent e) {
Color newColor = tcc.getColor();
banner.setForeground(newColor); }
public static void main(String[] args) {
JFrame frame = new Jframe("ColorChooserDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JComponent newContentPane = new ColorChooserDemo();
newContentPane.setOpaque(true);
frame.setContentPane(newContentPane)
frame.pack();
frame.setVisible(true); } }

-33-
Salvati fila cu numele ColorChooserDemo.java.Compilati si executati.
Obiectul ColorChooser ofera mai multe metode de selectie pentru culoarea
sau nuanta dorita,precum si o fereastra Preview pentru previzualizare.
Oricat de riguros alegeti combinatia de culori pentru interfata gra-
fica creata de d-voastra,utilizatorul va dori alta combinatie de culori.
Cea mai simpla solutie este sa adaugati un astfel de obiect si apoi sa
conectati toate obiectele din interfata la obiectul ColorChooser (de
exemplu printr-o tasta de short-cut).
EXEMPLU: (pentru NetBeans)
-deschideti un nou proiect (fara functia main())
-adaugati o fereastra JFrame Form
-din Palette adaugati un obiect de tip Label
-setati dimensiunile,culorile si fonturile
-din Palette,alegeti Swing Windows si adaugati un ColorChooser
-selectati obiectul Label -> Events -> mouseClicked si adaugati metoda
Click1 astfel:
private void Click1(java.awt.event.MouseEvent evt) {
jLabel1.setText("Click de mouse");
jLabel1.setForeground(jColorChooser1.getColor()); }
Incercati sa conectati obiectul jColorChooser1 si la alte obiecte din
interfata.
Pentru a putea afisa sau ascunde obiectul jColorChooser1 se va putea
utiliza metoda setVisible(),mostenita de la ancestorul JComponent.
De exemplu,adaugati doua butoane denumite Deschide si Inchide.Pentru
butonul Deschide editati evenimentul actionPerformed:
jColorChooser1.setVisible(true);
iar pentru butonul Inchide editati evenimentul actionPerformed:
jColorChooser1.setVisible(false);
Cu un singur obiect ColorChooser,puteti permite utilizatorului sa
aleaga si sa seteze dupa bunul plac,intreaga paleta de culori din inter-
fata grafica.Eventual,puteti crea si o metoda prin care setarile alese
de utilizator sa ramana permanente (de exemplu,salvati setarile intr-o
fila independenta si rescrieti fila automat,ori de cate ori este necesar).
Obiectul are si un set de metode proprii,dar majoritatea metodelor sunt
cele mostenite de la JComponent.
Exista numeroase teorii si recomandari cu privire la modul de selectie
si combinare a culorilor dintr-o interfata.In principiu,este esential ca
sa asigurati un contrast cat mai bun intre culoarea de fond si cea rezer-
vata pentru text.Atunci cand interfata contine si imagini sau desene,este
recomandabil sa utilizati o culoare de fond cat mai mata,pentru a nu
estompa calitatea imaginilor.In general,culorile stralucitoare nu se vor
utiliza decat pentru elementele pe care doriti sa le evidentiati.Pentru
fond si pentru elementele mai putin importante,se aleg de obicei culori
pastelate,mai sterse.Este recomandabil sa nu utilizati mai mult de 4-5
culori/fereastra (pentru a nu obosi ochiul si simtul estetic).Daca doriti
sa atrageti neaparat atentia asupra unui element,puteti utiliza efecte de
clipire (blink) sau secvente animate,dar in general,aceste efecte nu numai
ca sunt obositoare,dar consuma inutil si din numarul de procese executate
de procesor/ciclu de operatii.Este recomandabil sa utilizati buclele de
repetitie doar pentru operatii utile: sortari,cautarea si selectia de
date,introducerea de date utile,setari automate,etc.

-34-
O alta operatie extrem de frecventa intr-o aplicatie,o reprezinta
identificarea si exploatarea unei file de resurse.In situatia in care
fila de resurse este fixa,se poate utiliza o cale directa de acces la
fila respectiva.In cazul in care doriti ca utilizatorul sa poata alege
singur fila din care extrage un anumit tip de date,trebuie creata o inter-
fata simpla pentru acces la fila.Java Swing include un obiect specializat
pentru aceasta operatie,cu numele de JFileChooser.Obiectul are un set
destul de bogat de metode proprii si un filtru,cu ajutorul caruia se poate
restrictiona accesul la un anumit tip de file.Obiectul are o interfata
vizuala si este foarte practic.De exemplu,pentru a deschide o fila de tip
text,puteti utiliza o aplicatie de genul:
EXEMPLU:
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.SwingUtilities;
import javax.swing.filechooser.*;

public class FileChooserDemo2 extends JPanel implements Action Listener{


static private final String newline = "\n";
JButton openButton;
JTextArea log;
JFileChooser fc;
public FileChooserDemo2() {
super(new BorderLayout());
log = new JTextArea(25,40);
log setMargin(new Insets(5,5,5,5));
log setEditable(false);
JScrollPane logScrollPane = new JScrollPane(log);
fc = new JFileChooser();
openButton = new JButton("Open a File...");
openButton.addActionListener(this);
JPanel buttonPanel = new JPanel();
buttonPanel.add(openButton);
add(buttonPanel,BorderLayout.PAGE_START);
add(logScrollPane,BorderLayout.CENTER);
}
public String nume;
public void actionPerformed(ActionEvent e){
if (e.getSource() == openButton) {
int returnVal = fc.showOpenDialog(FileChooserDemo2.this);
if (returnVal == JFileChooser.APPROVE_OPTION) {
File file = fc.getSelectedFile();
nume = file.getAbsolutePath();
String[] sir1 = null;
FileChooserDemo2.this.Scrie(sir1);
}
}
}
//codul continua pe pagina urmatoare

-35-
//metoda Scrie() este necesara doar daca preluati textul din fila deschisa

public void Scrie(String[] args) {


try {
FileReader is1 = new FileReader(nume);
char[] buffer1 = new char[32000];
int len;
while ((len = is1.read(buffer1)) != -1) {
String sir2 = new String(buffer1,0,len);
log.append(sir2);
};
is1.close();
}catch (IOException ex1) {
System.err.println("Eroare: " + ex1.getmessage());
}finally { }
};
public static void main(String[] args) {
JFrame frame = new JFrame("FileChooserDemo2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new FileChooserDemo2() );
frame.pack();
frame.setVisible(true);
}
}
-salvati fila cu numele FileChooserDemo2.java.Compilati si executati.
In acest exemplu simplu,puteti observa functionalitatea obiectului
FileChooser.In plus,exemplul contine si o metoda pentru citirea si scrie-
rea datelor citite caracter cu caracter.Observati ca pentru a apela o
metoda adaugata de d-voastra in clasa se va utiliza numele clasei,urmat
de pointerul "this" (pointerul indica instanta clasei,adica obiectul).
Exemplu: NumeleClasei.this.NumeleMetodei();
Acelasi exemplu,se poate realiza extrem de usor in NetBeans.
-deschideti un nou proiect
-adaugati JFrame Form
-adaugati cate un Text Area,un Button si un Label
-selectati pentru buton Events -> Action ->actionPerformed
-editati urmatoarea metoda:
public String nume;
private void JButton1ActionPerformed(java.awt.event.ActionEvent evt){
javax swing.JFileChooser fc = new javax.swing.JFileChooser();
int returnVal = fc.showOpenDialog(NewJFrame.this);
if (returnVal == Javax.swing.JFileChooser.APPROVE_OPTION){
java.io.File fila1 = fc.getSelectedFile();
jLabel1.setText(fila1.getAbsolutePath());
nume = fila1.getAbsolutePath();
String[] x = null;
NewJFrame.this.Scrie(x);
}
In principiu,este acelasi exemplu.Se observa insa ca trebuie sa speci-
ficati calea completa de acces la fiecare obiect nou creat (filele sursa
sunt importate doar in momentul executiei ) pentru a putea compila fila.

-36-
Aceleasi transformari sunt necesare si pentru metoda Scrie():
public void Scrie(String[] args) {
try {
java.io.FileReader is1 = new Java.io.Filereader(nume);
char[] buffer1 = new char[32000];
int len;
while ((len = is1.read(buffer1)) != -1) {
String sir2 = new String(buffer1,0,len);
jTextArea1.append(sir2);
};
is1.close();
}catch (java.io.IOException ex1) {
System.err.println("Eroare: " + ex1.getMessage());
}finally {}
};
Pentru a depana eventualele erori,executati un click drept pe numele
proiectului din fereastra Inspector si alegeti Test.Daca nu se returneaza
nici un mesaj de eroare,puteti executa cu Run Main Project,apoi construiti
proiectul cu butonul Clean and Build Main Project.
Pentru exercitii,puteti personaliza obiectul FileChooser dupa bunul
plac.De exemplu,daca doriti sa utilizati obiectul doar pentru a deschide
file cu o anumita extensie,puteti adauga un filtru.
EXEMPLU:
JFileChooser chooser = new JFileChooser();
FileNameExtensionFilter filter = new FileNameExtensionFilter("jpg");
chooser.setFileFilter(filter);
In acest caz,obiectul FileChooser nu va mai deschide decat filele cu
extensia .jpg (simplifica identificarea unei file).
Atentie.Obiectul FileChooser nu executa nici un fel de actiuni asupra
filelor.Daca doriti sa cititi date din fila,sau daca doriti sa puneti in
executie fila respectiva,trebuie sa editati o metoda speciala pe care sa
o atribuiti butonului Open.De exemplu,daca doriti sa deschideti o fila
de tip HTML in loc de o fila de tip text,inlocuiti obiectul TextArea cu
un obiect de tip JEditorPanel si modificati metoda butonului astfel:
public String nume;
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt){
javax.swing.JFileChooser fc = new javax.swing.jFileChooser();
int returnVal = fc.showOpenDialog(NewJFrame.this);
if( returnVal == javax.swing.JFileChooser.APPROVE_OPTION){
java.io.File fila1 = fc.getSelectedFile();
nume = fila1.getName();
jEditorPane1.setText(nume);
java.net.URL adresa = java.lang.ClassLoader.getSystemResource(nume);
try {
jEditorPane1.setPage(adresa);
} catch (java.io.IOException e) {
System.err.println("Eroare de preluare a filei:" + nume);
}
}
-metoda se va putea utiliza pentru file Web preluate din retea,sau
pentru file HTML locale,arhivate in acelasi director (src).
-37-
Exista foarte multe formate pentru datele de tip text.Incepand de la
seturile de caractere utilizate si pana la filele de text ce utilizeaza
un limbaj marcat de tip Hipertext,datele de tip text pot utiliza nenuma-
rate tipuri si stiluri de fonturi,culori,grafica si resurse audio-vizuale,
etc.Pentru a putea satisface toate gusturile,Java include un numar foarte
mare de obiecte,create special pentru a putea administra datele de tip
text.Astfel,doar pachetul swing,contine sase obiecte vizuale special des-
tinate(JTextField,JFormattedTextField,JPasswordField,JTextArea,JEditorPane
si JTextPane) precum si un pachet denumit "text",in care sunt arhivate
alte peste 120 de clase si interfete (Exemple: Caret,Document,EditorKit,
Element,html,NavigationFilter,Style,StyledDocument,TableView etc.).Este
imposibil de facut un ghid complet de utilizare a tuturor acestor resurse.
Este insa important sa stiti ca exista,pentru a putea alege atunci cand
este cazul,obiectul cel mai potrivit,sau cel mai usor de utilizat.
Dintre obiectele vizuale,cel mai simplu si probabil cel mai frecvent
utilizat este obiectul JTextField.Se creaza obiectul si se citesc datele
introduse de utilizator prin metoda getText().JPasswordField este destul
de asemanator cu JTextField dar a fost creat special pentru a solicita o
parola.Obiectul mascheaza caracterele introduse si preia parola cu aju-
torul metodei getPassword().Alt obiect simplu este JFormattedText,creat
pentru a lucra cu date in format tipizat.Acest obiect contine un conver-
tor automat pentru formatarea datelor,denumit "formatterFactory" ce per-
mite utilizarea directa a urmatoarelor tipuri de data: number,date,time,
percent,currency si mask.
Obiectul JTextArea este destinat pentru texte ample,iar JEditorPane si
JTextPane sunt create pentru a permite utilizarea textelor de tip hiper-
text.JEditorPane preia file intregi de tip HTML,in timp ce JTextPane
compune niste file asemenatoare cu cele HTML din siruri de caractere si
stiluri de prezentare,organizate sub forma de documente StyledDocument.
EXEMPLU:
-deschideti un proiect NetBeans,adaugati JForm si deschideti Design
-adaugati cate un obiect de tip JTextField,JPasswordField,JFormatted-
TextField,JTextArea,JEditorPane si JButton.
-pentru campul JFormattedTextField,alegeti din fereastra Properties
optiunea formatterFactory si selectati tipul de data cu care doriti sa
lucrati in obiectul respectiv.
-adaugati in proiect o fila HTML (Exemplu: Bv1.htm )
-selectati butonul,click drept -> Events -> Action -> actionPerformed
si editati urmatoarea metoda:
public String s1;
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt){
jTextArea1.append(jTextField1.getText() + "Parola= ");
jTextArea1.append(s1.valueof(jPasswordField1.getPassword()));
java.net.URL adresa = java.lang.ClassLoader.getSystemResource("Bv1.htm");
try {
jEditorPane1.setPage(adresa);
} catch (java.io.IOException e) {
System.err.println("Eroare de preluare a filei: " +"Bv1.htm");
}
}
Testati si apoi executati exemplul cu Run Project.
-38-
Obiectul JTextPane este putin mai greu de exploatat,deoarece nu are
metode executabile directe.Fila text se formeaza intr-un tampon de memo-
rie intermediar.Acest tampon intermediar se creaza cu ajutorul unui obiect
(document) de tip StyledDocument.In acest tampon se introduc sirurile de
tip text,cu ajutorul metodei insertString() ce permite ca fiecare sir de
caractere sa utilizeze un alt stil de prezentare (fonturi si culori dife-
rite etc.).Obiectul de tip StyledDocument ofera si un set propriu de meto-
de si proprietati.In plus,stilul de prezentare se poate compune cu aju-
torul unei functii speciale,in care se pot utiliza orice alt fel de clase
si obiecte de formatare a textului.Dupa ce documentul este complet redac-
tat (concatenat),acesta poate fi importat in obiectul de prezentare.
EXEMPLU:
-deschideti un nou proiect NetBeans
-adaugati JForm si deschideti fereastra de Design
-adaugati un obiect de tip JTextPane si un buton
-editati pentru buton urmatorul eveniment actionPerformed:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt){
java.swing.text.StyledDocument doc = jText1.getStyledDocument();
try {
doc.insertString(doc.getlength(),"text ",doc.getStyle("large"));
}catch (javax.swing.text.BadLocationException ble) {
System.err.println("Textul nu poate fi inserat !");
}
}
Pentru ca textul sa fie prezentat cu un stil oarecare,utilizati metoda
doc.getStyle() pentru fiecare sir in parte.
Pentru a simplifica munca de programare este bine sa aveti sabloane
gata pregatite pentru fiecare stil de prezentare dorit.Astfel in momentul
in care construiti documentul,nu va mai trebui decat sa importati textul
si respectiv sablonul de prezentare.
Obiectul ancestor pentru toate obiectele vizuale de tip text este
JTextComponent.Aceasta clasa radacina asigura urmatoarele functionalitati:
-un document pentru continutul obiectului
-o forma(fereastra) de afisare a obiectului pe ecran
-un kit de editare (citire/scriere) pentru operatiile I/O
-o bucla infinita pentru operatii tip "undo" si "redo"
-un cursor cu filtru de navigare si "caret change listener"
(ce vor fi mostentie in toate obiectele derivate).
Pentru a mosteni metode noi,sau pentru a personaliza aceste obiecte,
fie se pot deriva clase noi,fie se pot include obiectele standard in con-
tainere,ce pot contine si metode personalizate.Atunci cand se lucreaza
cu grupuri mari de astfel de obiecte,este chiar recomandabil sa separati
fiecare grup intr-un container.In acest mod,se creaza cate un spatiu
"namespace"(spatiu de vizibilitate),pentru fiecare grup.Prin aceasta me-
toda,obiectele de acelasi fel se izoleaza astfel incat sa se excluda orice
risc de corupere accidentala a datelor (buclele automate nu vor putea
citi decat obiectele incluse in acelasi container).Este bine ca fiecare
operatie sa fie controlata de un buton sau un meniu separat (pentru a fi
mai usor de verificat si depanat),dar este posibil ca un singur buton sa
execute operatii multiple,sau sa raspunda la mai multe tipuri de eveni-
mente posibile.

-39-
In exemplele precedente,metodele care contin cate o operatie de citire
a datelor contin si cate o bucla try-catch,destinata pentru identificarea
si tratarea exceptiilor.Acest mecanism face parte din mecanismul automat
prin care Java evita eventualele erori de citire a datelor.In general,o
exceptie este un eveniment ce intervine in momentul executiei si deter-
mina intreruperea fluxului de operatii (procesorul nu stie cum sa proce-
seze datele respective).Acest gen de situatii,nu pot fi depistate sau
depanate in etapa de compilare,ci trebuiesc anticipate si rezolvate cu
ajutorul unor functii speciale.Exemple: o exceptie intervine atunci cand
un obiect asteapta date de tip String iar utilizatorul introduce o data
calendaristica,sau atunci cand o variabila este de tip Integer si utili-
zatorul introduce o valoare in virgula mobila (float),etc.Acest gen de
situatii nu pot fi rezolvate de catre compilator si trebuiesc anticipate
si prevazute prin functii speciale.Si alte programe includ rutine pentru
depanarea automata,dar Java a ales sa includa aceste operatii in toate
functiile ce efectueaza operatii de tip I/O.Fie ca sunt Stream-uri,fie
ca sunt obiecte de tip File sau FileReader,toate operatiile de intrare/
iesire asteapta si o solutie de tratare a exceptiilor.Toate erorile si
exceptiile din Java au ca superclasa,clasa Throwable.Din aceasta clasa se
deriva cate o clasa mostenitoare,din care se formeaza obiecte.Fiecare
exceptie sau eroare posibila formeaza un astfel de obiect.Obiectele pot
fi recunoscute si apoi tratate in functie de specificatiile programato-
rului.Pentru fiecare functie,exista una sau mai multe astfel de exceptii
ce pot fi tratate in mod automat.Cele doua metode principlae de tratare a
exceptiilor sunt "catch" (capturarea exceptiei) si "throw" (eliminarea
exceptiei).Se utilizeaza metoda de capturare a exceptiei atunci cand se
considera ca datele respective sunt utile si trebuie sa fie prelucrate
prin alt mecanism.De exemplu,daca utilizatorul introduce datele intr-un
format gresit,metoda "catch" va prelua datele respective,va face operatia
de conversie necesara si va returna datele in formatul acceptat (adica va
corecta eroarea automat si eventual va afisa un mesaj de avertizare).Daca
datele respective nu sunt utile in program,pot fi eliberate fara nici o
altfel de prelucrare.In acest caz,se utilizeaza metoda "throw".Pentru
fiecare metoda I/O,documentatia contine si tipul de exceptii ce pot fi
tratate automat:
EXEMPLE: public int read() throws IOException
public void throwException() throws CharacterCodingException
Pentru a putea alege exceptia capturata sau eliminata in timpul unei
operatii de preluare a datelor,trebuie sa consultati documentatia Java,
sau sa utilizati depanatorul automat vizual.De exemplu,in NetBeans,in
momentul in care introduceti in cod numele unui obiect oarecare,apare o
fereastra interactiva in care sunt incluse toate constantele,variabilele,
proprietatile sau metodele obiectului (proprii sau mostenite).
In momentul in care apare in timpul executiei o eroare oarecare,Java
creaza un obiect specializat,denumit "exception object",in care include
informatii despre tipul de eroare si momentul din program in care a inter-
venit.Mecanismul prin care eroarea se transforma in obiect poarta numele
de "throwing an exception".Dupa ce eroarea a fost transformata in obiect,
procesorul asteapta indicatii asupra modului de prelucrare a obiectului.
Modul de prelucrare a obiectului poarta numele de "tratare a exceptiei".
Functiile si metodele specializate pentru tratarea exceptiilor pot fi

-40-
incluse in: functia care a generat eroarea,in functia main(),intr-o fun-
ctie specializata dar fara executie automata,sau intr-o functie speciali-
zata ce contine si o rutina automata denumita "exception handler"(tratarea
exceptiei).Procesorul verifica toate aceste variante.Daca exista o astfel
de functie,prelucreaza obiectul conform indicatiilor,iar in caz contrar,
obiectul este ignorat.Cu alte cuvinte,mecansimul "throw" este echivalent
cu cel de eliminare a datelor din program (acestea nu vor avea vizibili-
tate in program,dar nici nu vor intrerupe executia).Sau altfel spus,eroa-
rea se transforma intr-un obiect inert.
In Java,in cazul functiilor I/O,functia de tratare a exceptiei este
inclusa direct in functia ce a generat eroarea (functia contine si un
"exception handler").Ca rezultat,are prioritate absoluta si se executa
imediat.In alte limbaje,procesorul trebuie sa parcurga toate functiile
din program,pana cand identifica metoda specializata,cu un numar foarte
mare de operatii in plus,si cu o intarziere considerabila in cazul pro-
gramelor mari.
Pentru a edita o functie de tratare a exceptiilor,se utilizeaza de
obicei o bucla de tip try-catch.Primul bloc al acestei bucle il formeaza
blocul try { ...} in care se includ toate operatiile in care suspectati
ca utilizatorul poate introduce erori (toate operatiile ce pot genera o
exceptie).Cel de al doilea bloc,denumit "catch (tipul exceptiei nume){..}"
trebuie sa identifice exceptia si apoi sa utilizeze un set de operatii
pentru corectarea erorii.Daca nu puteti anticipa metoda cea mai buna de
corectare a erorii,atunci blocul catch trebuie sa contina cel putin un
mesaj de avertizare,prin care sa semnalizati tipul de eroare si momentul
in care a intervenit,astfel incat utilizatorul sa-si poata corecta singur
gresala.Exemplu de mesaj: "Atentie- introduceti o valoare de tip Integer".
Cu ajutorul acestor functii,se vor putea rezolva toate situatiile
anticipate de programator.Bineinteles ca exista si situatii ce nu pot fi
anticipate.Acest gen de situatii genereaza erori simple ce nu pot fi re-
zolvate in mod automat.Aceste erori vor intrerupe executia programului.
Erorile ce nu pot fi tratate automat,sunt fie erori de executie de tip
"runttime error" ce tin de o greseala de programare (ce nu a fost identi-
ficata de compilator),fie erori de executie generate de utilizator prin
operatii incorecte sau introducerea de date cu format incompatibil.Pro-
gramele ce contin astfel de erori iremediabile,poarta numele de programe
defective,"virusate",sau "buggs".Exista si o categorie de programatori
malitiosi,care cauta intentionat limitele de executie ale unui program
oarecare,tocmai cu scopul de a exploata aceste limite pentru a crea asa
numitii "virusi informatici".Acest gen de programatori poarta si numele
de "hack-eri".Hack-erii au si un rol pozitv: atrag atentia asupra limite-
lor sau viciilor de constructie si contribuie implicit la munca de dez-
voltare a platformelor software.Nu are rost sa incercati sa anticipati
toate exceptiile posibile,dar este bine sa tratati toate exceptiile ce
intervin frecvent in timpul executiei (apasarea unei taste gresite,apa-
sarea unui bloc de taste,click de mouse in zonele "inerte" etc.).Exista
un aforism prin care se postuleaza ca: oricat de ingenios si meticulos
este programatorul,"prostul" va gasi o modalitate prin care sa "sparga"
toate mijloacele de protectie a codului si sa "ocoleasca" toate proto-
coalele de securitate.Pentru situatiile exceptionale,puteti utiliza si
blocul "finally { }",ce se executa in cazul exceptiilor nescontate.

-41-
Pentru organizarea grupurilor de obiecte vizuale se pot utiliza diverse
obiecte de tip container.Pe langa fereastra JFrame,Swing ofera si urma-
toarele containere vizuale: Panel,Scroll Pane,Internal Frame,Tabbed Pane,
Tool Bar,Layered Pane,Split Pane si Desktop Pane iar pachetul AWT contine
containerele vizuale Panel,Canvas si Scroll Pane.In prima etapa,configu-
rati containerul de la baza.In mediul vizual,este suficient sa alegeti si
sa setati proprietatea potrivita iar in fila .java trebuie sa setati
fiecare proprietate printr-o linie de cod.
EXEMPLU:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class TopLevelDemo {


Public static void main(String[] args) {
JFrame frame = new JFrame("TopLevelDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

JMenuBar greenMenuBar = new JMenuBar();


greenMenuBar.setOpaque(true);
greenMenuBar.setBackground(new Color(50,100,50));
greenMenuBar.setPrefferedSize(new Dimension(800,40));

JLabel yellowLabel = new JLabel();


yellowLabel.setOpaque(true);
yellowLabel.setBackground(new Color(250,250,50));
yellowLabel.setPrefferedSize(new Dimension(800,360));
yellowLabel.setText("Aici se poate include textul dorit...");
frame.setMenuBar(greenMenuBar);
frame.getContentPane().add(yellowLabel,BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
}
-salvati fila cu numele TopLevelDemo.java.Compilati si executati.In
acest exemplu,se adauga in fereastra un meniu si un camp Label si apoi
se seteaza dimensiunile si culoarea de fond.
Pentru a imparti fereastra de suport in mai multe compartimente dis-
tincte,cea mai simpla solutie este sa utilizati un obiect de tip JTabbed-
Pane.Acest obiect permite sa creati mai multe palete de optiuni,in care
se pot include grupurile de obiecte dorite.Pentru a trece de la un grup
de obiecte la altul,este suficient sa schimbati paleta de optiuni.La
nevoie se pot utiliza mai multe astfel de obiecte,fiecare cu grupul sau
de optiuni.Cel mai frecvent,obiectele de tip JTabbedPane includ grupuri
de date de tip text si formeaza un fel de fisier cu file succesive.Filele
se pot organiza alfabetic,sau dupa orice alt criteriu.Se pot ajusta cu-
lorile si fonturile,asfel incat fiecare optiune sa prezinte datele intr-un
format diferit.Foarte frecvent se utilizeaza culori diferite,astfel incat
utilizatorul sa poata alege optiunea favorita in functie de culoarea de
fond.

-42-
EXEMPLU:
import javax.swing.*;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.KeyEvent;
public class TabbedPaneDemo extends JPanel {
public TabbedPaneDemo() {
super(new GridLayout(1,1);
JTabbedPane tabbedPane = new JTabbedPane();
JComponent panel1 = makeTextPanel("Paleta 1 - inactiva");
tabbedPane.addTab("Tab 1",panel1);
JComponent panel2 = makeTextPanel("Paleta 2 ");
tabbedPane.addTab("Tab 2",panel2);
JComponent panel3 = maketextPanel("Paleta 3 ");
tabbedPane.addTab("Tab 3",panel3);
JComponent panel4 = makeTextPanel("Paleta 4");
panel4.setPreferredSize(new Dimension(400,250));
tabbedPane.addTab("Tab 4",panel4);
add(tabbedPane);
tabbedPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
}
protected JComponent makeTextPanel(String text) {
JPanel panel = new JPanel(false);
JLabel filler = new JLabel(text);
filler.setHorizontalAlignement(JLabel.CENTER);
panel.setLayout(new GridLayout(1,1));
panel.add(filler);
return panel;
}
public static void main(String[] args) {
JFrame frame = new JFrame("TabbedPaneDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TabbedPaneDemo(),BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
}
-salvati fila cu numele TabbedPaneDemo.java.Compilati si executati.
Daca utilizati o platforma vizuala,cum este NetBeans,nu trebuie decat
sa adaugati obiectele si apoi sa setati proprietatile.Fereastra de design
nu numai ca permite o evaluare cat mai exacta a aspectului final,dar
ofera si un set de indicatori (coordonate axiale) pentru alinierea si
dimensionarea obiectelor.In plus,pentru a putea previzualiza si functio-
nalitatea obiectelor,puteti utiliza butonul Preview Design.In continuare
puteti sa adaugati obiecte in fiecare optiune: butoane,casete de dialog,
campuri de text de tip Text Area,etc.Nu este insa bine sa exagerati cu
numarul de optiuni.Fiecare astfel de optiune introduce in program un
spatiu denumit suplimentar si implicit un set intreg de operatii pentru
reglementarea domeniului de vizibilitate.Prea multe obiecte de acest gen
pot incetini sau chiar bloca executia (suprascriu memoria de operare).

-43-
Uneori,obiectul contatiner poate influenta activ comportamentul sau
aspectul obiectelor continute.De exemplu,daca mai multe butoane de tip
radio se includ intr-un obiect de tip ButtonGroup,atunci daor unul dintre
butoane va putea fi selectat,iar restul de butoane vor fi deselectate
automat.ButtonGroup este special destinat pentru a reglementa statutul
selectat/deselectat al obiectelor continute.Se pot include in ButtonGroup
orice tip de obiecte derivate din AbstractButton,dar nu are rost sa uti-
lizati acest container decat pentru: JRadioButton,JRadioButtonMenuItem si
JToggleButton.
EXEMPLU:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class RadioButtonDemo extends JPanel implements ActionListener {
JLabel picture;
public RadioButtonDemo() {
super(new BorderLayout());
JRadioButton Buton1 = new JRadioButton("Buton1");
Buton1.setSelected(true);
Buton1.setActionCommand("Buton1");
JRadioButton Buton2 = new JRadioButton("Buton2");
ButtonGroup group = new Buttongroup();
group.add(Buton1);
group.add(Bouton2);
Buton1.addActionListener(this);
Buton2.addActionListener(this);
picture = new JLabel("text initial");
JPanel radioPanel = new JLabel(new GridLayout(0,1));
radioPanel.add(Buton1);
radioPanel.add(Buton2);
add(radioPanel,BorderLayout.LINE_START);
add(picture,BorderLayout.CENTER);
}
public void actionPerformed(ActionEvent e) {
picture.setText(e.getActionCommand() );
}
public static void main(String[] args) {
JFrame frame = new JFrame("RadioButtonDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JComponent new ContentPane = new RadioButtonDemo();
newContentPane.setOpaque(true);
frame.setContentPane(newContentPane);
frame.pack();
frame.setVisible(true);
}
}
-salvati fila cu numele RadioButtonDemo.java.Compilati si executati.
Pentru ca bitoanele sa functioneze strict asincron,trebuie ca butoanele
sa fie incluse intr-un obiect de tip ButtonGroup,care sa fie inclus la
randul sau intr-un obiect de tip Panel,ce va fi inclus in containerul
de suport (in JFrame).

-44-
Daca analizati putin exercitiul anterior,puteti observa urmatoarea
ordine de operatii:
-intregul program este de fapt o clasa (RadioButtonDemo)
-clasa contine o functie main(),pe care o executa implicit
-functia main creaza fereastra de suport (new JFrame)
-se seteaza proprietatile containerului de suport
-se creaza un nou component de tip Pane utilizand functia RadioButtonDemo
-functia RadioButtonDemo() executa urmatoarele operatii:
-creaza un obiect JLabel
-creaza si seteaza doua obiecte JRadioButton
-creaza un obiect JButtonGroup
-include obiectele JRadioButton in JButtonGroup
-adauga cate un Listener la fiecare buton
-creaza un obiect de tip Panel
-include butoanele in panel
-defineste functia pentru tratarea evenimentului capturat (action)
-se seteaza proprietatile obiectului Panel
-se actualizeaza fereastra (pentru a crea toate obiectele si a actualiza
toate setarile)
-se afiseaza fereastra
Exercitiul contine obiecte structurate pe patru nivele diferite si
este putin confuz pentru incepatori.Pana cand va familiarizati cu acest
gen implementari,puteti incerca sa faceti scheme si diagrame,pe hartie,
inainte de a incepe codificarea instructiunilor.
Daca lucrati in mediul vizual,lucrurile se simplifica foarte mult:
EXEMPLU (pentru NetBeans):
-deschideti un proiect nou
-adaugati fereastra JFrame
-in fereastra de design adaugati un obiect de tip LayeredPane
-bifati pentru jLayeredPane1 proprietatea "opaque"
-alegeti o culoare de fond oarecare (cu proprietatea background)
-includeti in jLayeredPane1 doua obiecte RadioButton
-adaugati si un obiect de tip Label
-adaugati un obiect de tip ButtonGroup (Obiectul buttonGroup1 nu poate
fi vazut in fereastra de design,dar poate fi identificat in fereastra
Source,in blocul variabilelor declarate,sau in fereastra Navigator)
-pentru a include butoanele in ButtonGroup,selectati Frame,alegeti din
fereastra Properties optiunea Events,selectati windowOpen si adaugati
urmatoarea metoda Start:
private void Start(java.awt.event.WindowEvent evt){
buttonGroup1.add(jRadioButton1);
buttonGroup1.add(jRadioButton2);
}
-acum butoanele vor fi incluse automat in ButtonGroup in momentul in
care se deschide fereastra principala
-in continuare puteti adauga cate un eveniment actionPerformed pentru
fiecare dintre cele doua butoane:
private void jRadioButton1ActionPerformed(java.awt.event.ActionEvent evt){
jLabel1.setText("Butonul 1 a fost activat");
}
si respectiv...

-45-
private void jRadioButton2ActionPerformed(java.awt.event.ActionEvent evt){
jLabel1.setText("Butonul 2 a fost activat");
}
Din fereastra Design puteti previzualiza si apoi testati,sau executati cu
Run Main Project.
Esential este cum includeti obiectele in containere.Este indicat sa
utilizati unul dintre evenimentele automate de initializare a ferestrei.
Dupa ce identificati mecanismul de lucru,incercati sa includeti doua sau
mai multe astfel de grupuri de optiuni functionale.Pentru a personaliza
aspectul,puteti utiliza orice combinatie de fonturi si culori,etc.De
exemplu,incercati sa creati o aplicatie cu mai multe optiuni,prin care
sa puteti converti automat o valoare numerica introdusa de la tastatura,
in diverse monede de circulatie.
Exista situatii in care doriti sa faceti un schimb oarecare de infor-
matii intre program si utilizator,fara sa complicati interfata grafica cu
prea multe obiecte suplimentare.In aceste cazuri,cea mai simpla solutie
este sa adaugati o fereastra de dialog,adica o fereastra independenta in
care afisati sau preluati un anumit set de date simple.Cea mai simpla
fereastra de dialog,este fereastra de tip mesaj si se poate crea cu aju-
torul obiectului JOptionPane.
EXEMPLU:
import javax.swing.*;
public class Mesaj {
public static void main(String[] args) {
JOptionPane.showMessageDialog(null,"Mesajul dorit !"); }
}
-salvati fila fila cu numele Mesaj.java.Compilati si executati.
Obiectul JOptionPane este special conceput pentru urmatoarele tipuri
de ferestre de dialog:
1.Fereastra de confirmare,in care se asteapta un raspuns pozitiv la o anu-
mita intrebare.Se creaza cu: JOptionPane.showConfirmDialog().
2.Fereastra de input,in care utilizatorul trebuie sa introduca un anumit
tip de date.Se creaza cu: JOptionPane.showInputDialog().
3.Fereastra de tip mesaj,in care utilizatorul primeste un scurt mesaj in-
formativ.Se creaza cu: JOptionPane.showMessageDialog(). (vezi exemplul)
4.Fereastra de tip optiune,in care utilizatorul poate alege dintr-un set
de optiuni una singura.Se creaza cu: JoptionPane.showOptionDialog.
Toate aceste ferestre de dialog se creaza cu ajutorul unei ferestre
interne standard,de tip JInternalFrame.Optional se poate include si un
desen standard,sub forma de icon.Java include urmatoarele icons create
special pentru acest obiect: question,information,error,warning,custom.
Pentru a desemna tipul de mesaj si respectiv desenul afisat se pot utiliza
urmatoarele constante: JOptionPane.WARNING_MESSAGE,JOptionPane.ERROR_MESS-
AGE,JOptionPane.PLAIN_MESSAGE,JOptionPane.INFORMATION_MESSAGE si respectiv
JOptionPane.QUESTION_MESSAGE.
Asadar,obiectul JOptionPane are mai multi constructori.In functie de
constructorul apelat,se va crea o fereastra de dialog din tipul respectiv.
Daca doriti sa inlocuiti desenul standard cu un icon personalizat,trebuie
sa includeti numele icon-ului in locul constantei standard.
Pentru a nu complica prea mult programul,si pentru a fi cat mai usor
de depanat,ferestrele de dialog e bine sa fie cat mai simple.Este mai bine
-46-
sa utilizati mai multe ferestre de dialog succesive,decat sa incercati sa
aglomerati prea multe date intr-o singura fereastra.
EXEMPLU (recapitulativ):
import javax.swing.*;
public class Mesaj2 {
public static void main(String[] args){
JOptionPane.showMessageDialog(null,"Atentie!","Alerta",
JOptionPane.ERROR_MESSAGE);
JOptionPane.showConfirmDialog(null,
"Alegeti Yes sau No","Selectie",JOptionPane.YES_NO_OPTION);
Object[] optiuni = { "OK","CANCEL" };
JOptionPane.showOptionDialog(null,"Confirmati cu OK","Warning",
JOptionPane.DEFAULT_OPTION,JOptionPane.WARNING_MESSAGE,
null,optiuni,optiuni[0]);
String valoare1 = JOptionPane.showInputDialog("Introduceti o valoare:");
Object[] valori = {"Primul","Al doilea","Al treilea"};
Object selectedValue = JOptionPane.showInputDialog(null,
"Selectati optiunea:","Selectie",JOptionPane.INFORMATION_MESSAGE,
null,valori,valori[0];
}
}
-salvati fila cu numele Mesaj2.java.Compilati si executati.
Este bine sa faceti cat mai multe exercitii cu fiecare tip de fereastra
de dialog si apoi sa pastrati cate un sablon,pentru cele mai utile dintre
ele.Apoi,ori de cate ori este necesar,copiati sablonul si efectuati doar
modificarile necesare.
Daca lucrati intr-un mediu vizual,obiectul JOptionPane nu este vizual,
asa ca nu poate fi vizualizat in fereastra de Design,nu se pot atribui
evenimente (decat prin linii de cod scrise manual) si nu se poate utiliza
nici fereastra Properties.Pentru a utiliza acest obiect,este bine sa aveti
sabloane preformate,pe care le conectati la unul dintre obiectele vizuale.
EXEMPLU: (NetBeans)
-deschideti un proiect nou
-adaugati JFrame
-deschideti fereastra Design
-adaugati un buton
-selectati pentru buton evenimentul Action -> action Performed si adaugati
o metoda de genul:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt){
javax.swing.JOptionPane.showMessageDialog(this,"Mesajul dorit!");
}
-testati si executati cu Run Main project.
Ferestrele de dialog prezinta un avantaj major.Se creaza si se elibe-
reaza automat din memorie,imediat dupa executie.Astfel,memoria de operare
nu va mai fi incarcata cu un pointer inutil.Se utilizeaza foarte frecvent
pentru a semanliza eventualele erori de executie.Puteti utiliza aceasta
solutie pentru oricare dintre valorile capturate cu catch,pentru a semna-
liza daca o operatie a fost executata corect,sau eronat.Puteti utiliza
mesaje si pentru a crea un mic program "Help" interactiv,pentru a comu-
nica sau cere informatii suplimentare,sau pentru a descrie unele dintre
obiecte,sau o anumita functionalitate a programului,etc.
-47-
Atunci cand doriti sa includeti in program un numar mare de optiuni,cea
mai comoda solutie o ofera meniurile.Acelasi rezultat se poate obtine si
cu un grup de butoane radio,spinner,sau casete Listox si ComboBox,dar
meniurile ocupa mult mai putin spatiu,au un cod compact,usor de editat,
se executa mai usor si exclud orice fel de erori de executie.Spre deose-
bire de celelalte componente,meniurile nu se includ in interfata grafica,
ci sunt obiecte separate.Clasic se pot utiliza doua tipuri de meniuri:
bara de meniuri si meniul popup.O bara de meniu contine unul sau mai
multe meniuri,ce pot contine la rindul lor submeniuri.Pentru un meniu
complet se utilizeaza trei tipuri de obiecte Swing: JMenuBar,JMenu si
respectiv JMenuItem.Ca rezultat,datele sunt compartimentate modular si nu
exista riscul ca un anumit tip de data sa poata bloca intregul meniu.In
cazul in care intervine o eroare intr-un submeniu,restul meniului va fi
functional,astfel ca utilizatorul va putea avea o solutie de iesire din
impas.Meniurile se declara,se creaza,apoi se conecteaza la evenimente:
EXEMPLU:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class MenuLayoutDemo {
public JMenuBar createMenuBar() {
JMenuBar menuBar = new JMenuBar();
JMenuBar.setLayout(new BoxLayout(menuBar,BoxLayout.X_AXIS));
menuBar.add(createMenu("Meniu1");
menuBar.setBorder(BorderFactory.createMatteBorder(3,3,3,5,Color.RED));
return menuBar;
}
public JMenu createMenu(String title) {
JMenu m = new Jmenu(title);
m.add("Optiunea 1 din " + title);
m.add("Optiunea 2 din " + title);
m.add("Optiunea 3 din " + title);
JMenu submenu = new JMenu("Submenu");
submenu.add("Submeniu optiunea 1");
submenu.add("Submeniu optiunea 2");
m.add(submenu);
return m;
}
public satic void main(String[] args){
JFrame frame = new JFrame("Exemplu de meniu simplu");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MenuLayoutDemo demo = new MenuLayoutDemo();
Container contentPane = frame.getContentPane();
contentPane.setBackground(Color.WHITE);
contentPane.add(demo.createMenuBar(),BorderLayout.LINE_START);
frame.setSize(300,80);
frame.setVisible(true);
}
}
-salvati fila cu numele MenuLayoutDemo.java.Compilati si executati.
Exemplul contine o bara de meniu,un meniu,trei optiuni si un submeniu.

-48-
Meniurile sunt laborios de editat manual.Pentru a verifica fiecare
meniu si apoi pentru a conecta cate un eveniment la fiecare optiune din
meniu,sunt necesare o serie intreaga de operatii.Este mult mai usor,daca
utilizati un editor vizual.
EXEMPLU: (NetBeans)
-deschideti un proiect nou
-adaugati JFrame
-deschideti fereastra de design
-adaugati un obiect MenuBar
-adaugati un obiect Label
-pentru a adauga meniuri,click drept pe MenuBar si alegeti Add Menu
-pentru a adauga optiuni,click drept pe Meniu si alegeti Add From Palette
si apoi MenuItem ( sau MenuItem/RadioButton)
-pentru a adauga evenimente,click drept pe meniu,alegeti Events si apoi
evenimentul dorit
-editati metoda pentru tratarea evenimentului
JLabel1.setText("A fost activat meniul 1 ");
-testati si executati cu Run Main Project
Editorul vizual este extrem de usor de utilizat si foarte eficient.Nu
numai ca simplifica foarte mult munca de editare,dar permite sa visuali-
zati in permanenta aspectul interfetei.Alegeti culorile si fonturile
preferate,setati dimensiunile si incadrati fiecare obiect,adaugati bor-
duri,chenare sau linii de subliniere,short-cut-uri etc.
In cazul in care nu aveti un editor vizual,este bine sa lucreti cu
sabloane.Construiti un model simplu de meniu,la care conectati cate un
eveniment simplu si o metoda de tratare a evenimentului.Apoi,ori de cate
ori este necesar,nu va trebui decat sa schimbati numele optiunilor si sa
editati metodele de tratare a evenimentului.Eventual,puteti gasi pe In-
ternet seturi intregi de sabloane,pentru majoritatea tipurilor de apli-
catii posibile.Nu trebuie decat sa alegeti sablonul potrivit si apoi
sa implementati metodele dorite.Daca nu aveti preferinte gata formate,
puteti sa pastrati aspectul general si combinatia de culori din meniul
standard.Daca schimbati grafica,este bine sa existe un contrast cat mai
bun,dar fara sa utilizati culori stralucitoare (obosesc privirea).
Meniurile nu trebuie sa fie colorate ca un papagal.Rostul lor este sa
controleze cat mai simplu o anumita actiune.Meniurile cu derulare econo-
misesc foarte mult din spatiul rezervat pentru interfata grafica.Pentru
a obtine acelasi efect cu alte tipuri de obiecte,trebuie sa creati o
functie speciala prin care obiectele sa fie afisate doar atunci cand sunt
necesare,sau respectiv sa proiectati o fereastra externa destinata special
acestui scop.
Meniurile ofera si un alt avantaj major,prin faptul ca pot grupa seturi
de operatii secventiale,sau seturi de operatii asemenatoare,astfel incat
utilizatorul sa vada dintr-o singura privire intregul set de operatii.
Fiecare meniu si submeniu este un obiect separat.In cazul in care,
dintr-un motiv sau altul apar erori de executie la nivelul unui anumit
meniu,cea mai simpla metoda este sa inlocuiti obiectul cu totul.Pentru
programele complexe,este bine sa arhivati cate o copie de siguranta a
fiecarui obiect,astfel incat sa fie cat mai simplu sa depanati programul
modular (inlocuiti doar obiectul defect cu clona sa functionala).Este
bine sa nu exagerati totusi,cu numarul de optiuni dintr-un meniu.

-49-
Dupa ce a-ti setat containerul de baza si eventual a-ti adaugat un me-
niu de optiuni,puteti introduce in interfata obiectele vizuale dorite.Pe
langa etichete(Label),butoane si campuri de date (prezentate deja in
exemplele anterioare),un obiect vizual extrem de util il reprezinta JList.
JList este creat special pentru a putea prezenta grupuri de date,sub
forma de lista fixa,sau derulabila.Utilizatorul poate sa aleaga unul sau
mai multe elemente din lista,cu care sa execute apoi o serie oarecare de
operatii.Cea mai simpla lista se creaza cu ajutorul unei arii de siruri:
EXEMPLU:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class Lista extends JPanel {
public JList list;
String[] sir1 = {"Optiunea 1","Optiunea 2","Optiunea 3","Optiunea 4"};
public JList list;
list = new JList(sir1);
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
list.setSelectedIndex(0);
list.setVisibleRowCount(2);
JScrollPane s1 = new JScrollPane(list);
add(s1,BorderLayout.CENTER); };
public static void main(String[] args){
JFrame frame = new JFrame("Lista de optiuni");
frame.setDefaultCloseOperation(Jframe.EXIT_ON_CLOSE);
JComponent newContentPane = new Lista();
newContentPane.setOpaque(true);
frame.setContentPane(newContentPane);
frame.pack();
frame.setVisible(true);
}
}
-salvati fila cu numele Lista.java.Compilati si executati.
Puteti observa in exercitiu urmatoarele:
-pentru a crea lista am declarat si definit functia constructor Lista()
-elementele din lista se creaza cu ajutorul ariei de siruri
-lista a fost inclusa intr-un panou de derulare (ScrollPane)
In rest,depinde de modul in care doriti sa utilizati elementele din
lista.Daca doriti sa afisati permanent toate elementele,nu mai este nece-
sar sa adaugati un scroller (panou de derulare),dar lista va ocupa o mare
parte din interfata grafica cu elemente inerte.
Obiectul are un numar mare de metode si proprietati ce permit personali-
zarea aspectului sau a stilului de executie,si respectiv garnitura normala
de evenimente.Pentru a programa operatii,trebuie sa conectati evenimentul
ales la metoda dorita.Editarea sub forma de linii de cod este destul de
laborioasa,asa ca este preferabil sa utilizati un editor vizual.Acest
obiect prezinta un foarte mare avantaj: -optiunile prezentate in lista au
un format fix,ce exclude orice eroare de introducere a datelor.Aplicatia
nu va avea nevoie de nici un fel de filtru I/O,sau de functii pentru
tratarea erorilor de format.

-50-
Daca doriti sa lucrati modular,sau daca aveti deja un sablon anume
pentru lista dorita,obiectul poate fi creat si cu ajutorul unui model
preformat,sau utilizand un sablon:
EXEMPLU:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class Lista1 extends JPanel {
private JList list;
private DefaultListModel model1;
public Lista1() {
model1 = new DefaultListModel();
model1.addElement("Primul element din lista");
model1.addElement("Al doilea element din lista");
model1.addElement("Al treilea element din Lista");
list = new JList(model1)
list.setSelectionMode(ListselectionModel.SINGLE_SELECTION);
list.setSelectedIndex(0);
list.setVisibleRowCount(3);
add(list,BorderLayout.CENTER);
};
public static void main(String[] args) {
JFrame frame = new JFrame("Lista de optiuni");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JComponent newContentPane = new Lista1();
newContentPane(newContentPane);
frame.pack();
frame.setVisible(true);
}
}
-salvati fila cu numele Lista1.java.Compilati si executati.
Acest gen de solutie ofera urmatoarele avantaje:
-se pot crea mai multe liste cu ajutorul unui singur sablon
-sablonul poate fi configurat automat,pentru a genera liste diferite in
functie de un criteriu oarecare
-sablonul poate fi arhivat intr-o fila externa si utilizat in multiple
aplicatii
Pentru exercitiu,incercati sa creati o aplicatie in care lista se va
construi diferit,in functie de o parola oarecare introdusa de utilizator
inainte de initializarea interfetei grafice.
In mediu vizual,JLabel este mult mai usor de exploatat:
EXEMPLU: (NetBeans)
-deschideti un proiect nou si adaugati JFrame,deschideti Designer
-adaugati un obiect List si un obiect Label
-selectati jList1 si setati proprietatea model,apoi setati proprietatea
selectionMode = SINGLE_INTERVAL
-alegeti evenimentul ListSelection -> valueChanged si editati metoda:
jLabel1.setText("Selectie = " + jList1.getSelectedItem() );
-testati si executati exemplul cu Run Main Project
-incercati sa dezvoltati exemplul cu cateva metode suplimentare

-51-
Un obiect asemanator cu JList este JComboBox.Acest obiect este de fapt
o combinatie intre jList si un buton cu un camp de editare.Utilizatorul
poate alege o valoare predefinita din lista de derulare,sau poate edita
o valoare noua.Obiectul nu ridica probleme deosebite si nu necesita o
prezentare suplimentara.
Java contine insa si un obiect vizual mai particular,ce permite prezen-
tarea unor grupuri de siruri sau obiecte,sub forma de tabel bidimensional.
Nu este o grila pentru exploatarea bazelor de date,ci este un tabel simplu
creat cu date locale (sau preluate dintr-o fila sursa).Acest obiect nu se
intilneste in alte medii de programare,dar este foarte asemanator cu o
grila simpla.Obiectul poarta numele de JTable si are 7 constructori(adica
7 metode diferite de a crea un tabel).Cei sapte constructori recunosc
parametri diferiti.Astfel,cel mai simplu creaza un tabel pe baza unui
model standard implicit,iar cel mai complex creaza tabelul pe baza unui
set de obiecte de tip sablon.De exemplu,pentru a prezenta un set de siruri
de caractere sub forma de tabel,se va apela constuctorul ce are ca para-
metrii o arie bidimensionala de siruri si o arie simpla de siruri:
JTable(Object [] [] rowData,Object [] columnNames);
EXEMPLU:
import javax.swing.*;
import java.awt.Dimension;
import java.awt.GridLayout;
public class Tabel1 extends JPanel {
public Tabel1() {
super(new GridLayout(1,0));
String[] coloane={"Nume","Prenume","Adresa","Vechime(ani)","Confirmare");
Object [][] date = {
{"Barbu","Ion","Republicii nr.7",new Integer(5),new Boolean(false)},
{"Albu","Mihai","Primaverii nr.5",new Integer(3),new Boolean(true)},
{"Marin","Petre",B-dul Muncii nr.3",new Integer(2),new Boolean(true)},
{"Pop","Vasile","Piata Pacii nr.10",new Integer(7),new Boolean(false)},
};
final JTable table = new JTable(date,coloane);
table.setPrefferedScrollableViewportSize(new Dimension(500,100));
table.setFillsViewportHeight(true);
JScrollPane scrollPane = new JScrollPane(table);
add(scrollPane);
}
public static void main(String[] args) {
JFrame frame = new JFrame("Tabel simplu");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Tabel1 new ContentPane = new Tabel1();
newContentPane.setOpaque(true);
frame.setContentPane(newContentPane);
frame.pack();
frame.setVisible(true);
}
}
-salvati fila cu numele Tabel1.java.Compilati si executati fila.
Tableul contine: o arie de siruri pentru definitia titlurilor si o arie
bidimensionala de siruri in care sunt incluse datele propriu zise.

-52-
Atunci cand structura unui tabel urmeaza sa fie utilizata de mai multe
ori,fie in aceeasi aplicatie,fie in aplicatii diferite,este comod sa con-
struiti tabelul cu ajutorul unui sablon (model preformatat).Construiti
sablonul,apoi se pot utiliza rutine automate,pentru a crea seturi intregi
de obiecte,sau serii de obiecte ce mostenesc acelasi ancestor.
EXEMPLU:
import javax.swing.*;
import javax.swing.table.AbstractTableModel;
import java.awt.Dimension;
import java.awt.GridLayout;
public class Tabel2 extends JPanel {
public Tabel2() {
super(new GridLayout(1,0));
class TabelulModel extends AbstractTableModel {
String[] coloane={"Nume","Prenume","Adresa","Vechime(ani)","Confirmare");
Object [][] date = {
{"Barbu","Ion","Republicii nr.7",new Integer(5),new Boolean(false)},
{"Albu","Mihai","Primaverii nr.5",new Integer(3),new Boolean(true)},
{"Marin","Petre",B-dul Muncii nr.3",new Integer(2),new Boolean(true)},
{"Pop","Vasile","Piata Pacii nr.10",new Integer(7),new Boolean(false)},
};
public int getColumnCount() { return coloane.length; }
public int getRowCount() { return date.length; }
public String getColumnName(int col) { return coloane[col]; }
public Object getValueAt(int row,int col){ return date[row][col]; }
}
JTable table = new JTable(new TabelulModel());
table.setPrefferedScrollableViewportSize(new Dimension(500,100));
table.setFillsViewportHeight(true);
JScrollPane scrollPane = new JScrollPane(table);
add(scrollPane);
}
public static void main(String[] args) {
JFrame frame = new JFrame("Tabel simplu");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Tabel2 new ContentPane = new Tabel2();
newContentPane.setOpaque(true);
frame.setContentPane(newContentPane);
frame.pack();
frame.setVisible(true);
}
}
-salvati fila cu numele Tabel2.java.Compilati si executati.
Exercitiul este similar cu cel precedent,dar in locul celor doua obiecte
de tip arie de siruri,constructorul utilizeaza un tabel sablon creat cu
ajutorul clasei TabelulModel.Acest gen de solutie prezinta urmatorul avan-
taj: modelul poate contine si setarile dorite.Ori de cate ori doriti sa
clonati tabelul respectiv,acesta va fi gata setat (culori,fonturi,borduri,
stil de prezentare etc.).Exista si un constructor ce utilizeaza vectori
(adica arii de date ce pot creste progresiv).Acest constructor se va apela
atunci cand doriti sa adaugati periodic inregistrari noi.

-53-
Daca utilizati un editor vizual,etapa de design este mult mai simpla.
EXEMPLU:
-deschideti un proiect nou si adaugati JFrame.
-in fereastra Design,adaugati un obiect Table (din grupul Beans)
-selectati obiectul jTable1 si utilizati fereastra properties
-pentru a specifica sablonul tabelului utilizati proprietatea "model"
-alegeti fonturile,culorile,bordurile preferate
-adaugati si un obiect Label
-pentru a testa un eveniment oarecare,selectati din nou obiectul jTable1
-click drept pe tabel,alegeti Events -> Mouse si mouseClicked
-editati o metoda de genul:
private void jTableMouseClicked(java.awt.event.MouseEvent evt){
int x = 0 ;
int y = 0 ;
x = jTable1.getSelectedColumn() + 1;
y = jTable1.getSelectedRow() + 1;
jLabel1.setText("Selectie = coloana: " + x + " randul: " + y);
}
-testati si executati exemplul
Obiectul JTable are un set foarte bogat de metode,la care se pot adauga
si metode personalizate incluse in clasa utilizata ca sablon.Modul in care
combinati aceste metode pentru a obtine o anumita solutie,depinde atat de
necesitatile de moment,cat si de imaginatia d-voasta.Daca nu reusiti sa
obtineti o combinatie lucrativa,este bine sa consultati si oferta de pe
Internet.Exista o paleta foarte variata de sabloane si modele preformate
ce acopera aproape toate necesitatile uzuale de programare.Nu trebuie
decat sa descarcati un astfel de sablon si apoi sa-l transformati pentru
a corespunde cu cerintele aplicatiei curente.
O alta facilitate simpla si practica,oferita de Java este posibilitatea
de a formata sirurile de caractere cu ajutorul limbajului HTML.Majoritatea
componentelor Swing,utilizeaza si fragmente de text ca parte componenta a
inerfetei grafice.Pentru formatarea acestui text se pot utiliza proprie-
tatile obiectului:
EXEMPLU: label = new JLabel("textul dorit");
label.setFont(new Font("Serif",Font.PLAIN,14));
label.setForeground(new Color(0xffffdd));
sau se poate utiliza limbajul HTML:
EXEMPLU:
import javax.swing.*;
public static void main(String[] args) {
JFrame frame = new jFrame("Text redactat in limbaj HTML");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel label = new Jlabel
("<html><h1><font color=red> Text HTML </font></h1></html>");
frame.getContentPane().add(label);
frame.pack()
frame.setVisible(true);
}
}
-salvati fila cu numele TextHTML.java.Compilati si executati
Experimentati mai multe obiecte si formate de tip HTML.

-54-
Daca lucrati in mediu vizual,designul si formatul sunt mult mai usor
de ales.
EXEMPLU:
-deschideti un nou proiect si adaugati JFrame
-deschideti fereastra de Design
-adaugati doua butoane si un camp Label
-editati pentru primul buton evenimentul Action -> actionPerformed:
jLabel1.setText(
"<html><h1><font color=red> Text HTML </font></h1></html>");
-editati pentru cel de al doilea buton Action -> action{erformed:
jLabel1.setText("Text normal");
-testati si executati,apoi apasati alternativ cele doua butoane.
Acest tip de solutie,nu numai ca simplifica alegerea formatului,dar
permite si sa aveti niste sabloane prestabilite pentru format,editate in
limbaj HTML si importate dintr-o fila sursa.Daca doriti ca un numar oare-
care de file si obiecte sa respecte un format particular de text,este
suficient sa editati sablonul o singura data si apoi sa-l importati sub
forma de sir de caractere,pentru toate obiectele dorite.
Tot in paleta Swing se gaseste si controlul Tree,creat cu ajutorul
clasei JTree,pentru a putea organiza si prezenta datele ierarhic,sub forma
de arbore binar.Obiectul de tip Tree nu va contine datele propriu zise,ci
doar va prezenta ierarhia lor.Pentru a putea avea acces la date cu ajuto-
rul acestui obiect,va trebui sa creati o conexiune intre fiecare element
din arbore si fila sursa.Conexiunea se va activa automat in momentul in
care se va identifica evenimentul ales pentru crearea link-ului.
In obiectul de tip jTree,datele se vor prezenta pe verticala,incepand
cu elementul radacina.Fiecare rand din diagrama va reprezenta un nod.
Pentru fiecare nod se va utiliza un obiect de tip TreeNode ce se poate
construi relativ simplu cu ajutorul unui obiect de tip DefaultMutable-
TreeNode.
Se observa de la prima vedere,ca este vorba de fapt despre un grup de
obiecte,organizate modular.Fiecare data,este reprezentata cu ajutorul
unui obiect distinct.Ca rezultat,operatiile de sortare,cautare sau navi-
gare in cadrul grupului sunt mult mai usor de realizat (se utilizeaza
pointerii spre fiecare adresa).
Pentru economie de spatiu,fiecare nod poate fi expandat sau plisat
(collapsed) dupa necesitati.Atunci cand este expandat,afiseaza toti des-
cendentii,iar cand este plisat (colabat),afiseaza doar directorul parinte.
Toate aceste operatii,se pot executa si automat,prin functii specifice:
EXEMPLE: isRootVisible(),setRootVisible(),getVisibleRowCount() etc...
Fiecare nod din arbore poate fi identificat fie cu ajutorul unui obiect
special destinat de tip TreePath,fie prin textul afisat in dreptul sau (
sau o pictograma de tip icon).
Pentru a identifica si exploata evenimentele de la nivelul obiectului,
este necesar sa conectati cate o functie de tip Event Listenr pentru
fiecare dintre evenimentele urmarite,de genul:
if (node.isLeaf()) { functia pentru afisarea datelor }
else { functia alternativa }
Obiectele de tip Tree sunt greu de editat fara ajutorul unei interfete
vizuale,deoarece contin numeroase obiecte si functii de tip constructor,
sau metode pentru setarea obiectelor.

-55-
EXEMPLU:
import javax.swing.*;
import javax.swing.tree.*;
import javax.swing.event.*;
import java.awt.*;
public class Arbore extends JPanel {
public Arbore() {
DemoArea demoArea;
demoArea = new DemoArea();
add(demoArea); }
public class DemoArea extends JScrollPane {
Dimension minSize = new Dimension(100, 100);
JTree tree;
public DemoArea() {
TreeNode rootNode = createNodes();
tree = new JTree(rootNode);
setViewportView(tree); }
private TreeNode createNodes() {
DefaultMutableTreeNode root;
DefaultMutableTreeNode grandparent;
DefaultMutableTreeNode parent;
DefaultMutableTreeNode child;
root = new DefaultMutableTreeNode("Directorul radacina ");
grandparent = new DefaultMutableTreeNode("Primul nod");
root.add(grandparent);
parent = new DefaultMutableTreeNode("A doua ramificatie (parinte
1)");
grandparent.add(parent);
child = new DefaultMutableTreeNode("Primul descendent");
parent.add(child);
child = new DefaultMutableTreeNode("Al doilea descendent");
parent.add(child);
parent = new DefaultMutableTreeNode("A doua ramificatie (parinte
2)");
grandparent.add(parent);
child = new DefaultMutableTreeNode("Primul urmas");
parent.add(child);
child = new DefaultMutableTreeNode("Al doilea urmas");
parent.add(child);
return root;
}
}
public static void main(String[] args) {
JFrame frame = new JFrame("Arbore de directoare");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JComponent newContentPane = new Arbore();
newContentPane.setOpaque(true);
frame.setContentPane(newContentPane);
frame.pack();
frame.setVisible(true);
}
}
-salvati fila cu numele Arbore.java.Compilati si executati.
-56-
Daca analizati putin exemplul,observati ca nu este chiar atat de greu
cum pare la prima vedere.Obiectul Tree se formeaza din unul sau mai multe
obiecte de tip TreeNode,ce se creaza utilizand ca sablon un obiect de tip
DefaultMutableTreeNode.Se definesc constructorii,apoi se grupeaza obiecte-
le cu ajutorul metodei add().Totusi,editarea manuala este foarte laborioa-
sa in cazul arborilor cu structura complexa.Daca utilizati un editor vi-
zual,munca de programare se simplifica foarte mult:
EXEMPLU: (NetBeans)
-deschideti un proiect nou si adaugati JFrame
-deschideti fereastra de Design
-adaugati un obiect de tip Tree si un obiect de tip Label
-obiectul jTree1 va contine un model implicit format din trei directoare
si cateva subdirectoare.Pentru a schimba continutul arborelui,selectati
obiectul jTree1,deschideti fereastra Properties si alegeti "model".Se va
deschide fereastra jTree1 - model in care elementele sunt prezentate in
doua casete de dialog.Stergeti elementele din prima caseta si introduceti
datele dorite.In cea de a doua caseta se va afisa aspectul arborelui con-
struit.Pentru a crea subdirectoare,trebuie sa lasati spatii goale,cores-
punzator cu pozitia din arbore: fara nici un spatiu va fi director rada-
cina,cu un spatiu gol va fi subdirector...etc.Cand arborele are aspectul
dorit,confirmati cu OK.
-inchideti fereastra Properties
-selectati din nou obiectul jTree1,click drept de mouse si alegeti din
Events -> TreeSelection -> valueChanged si editati urmatoarea metoda:
private void jTree1ValueChanged(javax.swing.event.TreeSelectionEvent evt){
javax.swing.tree.DefaultMutableTreeNode node =
(javax.swing.tree.DefaultMutableTreeNode)
jTree1.getLastSelectedPathComponent();
Object nodeInfo = node.getUserObject();
jLabel1.setText(nodeInfo.toString());
}
-testati si executati exercitiul cu Run Main Project
Intr-o aplicatie reala,textul returnat in jLabel1 poate fi numele unei
file ce urmeaza sa fie deschisa cu ajutorul unui alt obiect,sau respectiv
o comanda executabila,sau un link etc.
Observati ca si in acest caz,fiecare element din arbore este tot un
obiect de tip TreeNode,construit cu un sablon de tip DefaultMutableTree-
Node.Pentru a putea lucra cu elementele din arbore,acestea trebuie sa fie
referite prin metodele obiectelor de rigoare.In exemplul de mai sus,pentru
a putea identifica nodul selectat de utilizator,am creat un obiect de tip
DefaultMutableTreeNode in care am preluat valoarea curenta a nodului se-
lectat.
Structura arborelui poate fi modificata si interactiv in timpul exe-
cutiei,fie cu ajutorul unui algoritm prestabilit,fie cu ajutorul unor
operatii de tip drag and drop.Acest gen de solutii,depasesc nivelul ele-
mentar la manualului,dar puteti sa incercati sa dezvoltati exercitii de
acest gen.In plus,arborele poate contine pictograme si imagini,sau o
combinatie de text si pictograme.
Pentru orice aplicatie,trebuie sa aveti in vedere clasele necesare
pentru constructia obiectului: JTree si DefaultMutableTreeNode si res-
pectiv interfata TreeNode (analizati proprietatile si metodele lor).
-57-
Paleta de componente Swing este mult mai bogata,dar nu este necesara
prezentarea fiecarui obiect.Pentru a putea evalua utilitatea fiecarui
astfel de obiect,este necesar putin studiu individual.Creati exemple
simple,asemanatoare cu cele precedente si apoi explorati metodele si pro-
prieatatile fiecarui obiect.La nevoie,studiati si exemplele oferite in
diversele tutoriale din reteaua Internet.

EXECUTIA CONCURENTIALA

Exemplele anterioare au prezentat doar cateva secvente elementare de


operatii,organizate intr-un obiect unic si controlate cu ajutorul unei
functii centrale,denumita functia main().In viata reala,aplicatiile de
tip software se deruleaza de multe ori intr-un mediu complex,format din
doua sau mai multe calculatoare,interconectate direct,sau prin intermediul
unor centrale de distributie.In acest mediu complex,un program simplu,sau
o aplicatie este echivalentul unui proces,adica un set oarecare de ope-
ratii,controlate cu ajutorul unei functii,sau a unui obiect.Un astfel de
proces,mai poarta si numele de "executabil",datorita faptului ca setul
respectiv de operatii poate fi executat in mod repetat cu ajutorul unei
singure comenzi.Un astfel de proces nu satisface intotdeauna necesitatile
de programare.Exista situatii in care sunt necesare mai multe astfel de
procesari succesive,pentru a putea obtine rezultatul dorit.Acest gen de
situatii,poarta numele de multiprocesare si se poate realiza prin mai
multe metode.In cazul in care exista o singura linie de transport a date-
lor ("bus") si un singur procesor,multiprocesarea nu se poate face decat
impartind fiecare proces in mai multe secvente si apoi executand cate o
secventa din fiecare proces,pana la epuizarea lor.Acest gen de solutie,
poarta si numele de multiprocesare "pe port serial" si creaza doar iluzia
unei executii simultane a proceselor.Aceasta este singura solutie posibila
in cazul calculatoarelor obisnuite de birou (de tip monopost) in cazul in
care nu sunt conectate la o retea de calculatoare.In cazul in care exista
mai multe linii de transport a datelor,si mai multe procesoare (sau un
procesor compartimentat de tip 5X86 6X86 etc) se creaza si posibilitatea
fizica de a executa mai multe procese simultan.In acest caz,fiecare pro-
ces sa va derula pe o magistrala de transport diferita si va fi deservit
de un procesor diferit,sau cel putin de un modul diferit dintr-un proce-
sor complex.Acest gen de solutie,poarta numele de multiprocesare "pe port
paralel" si asigura o viteza de executie mult mai mare.Exista si solutii
mixte,in care se utilizeaza mai multe procesoare,dar fiecare procesor va
executa seturi seriale de procese in partitie de timp.
Dupa cum se poate observa de la prima vedere,procesarea pe port serial,
nu numai ca dureaza mult mai mult,dar adauga si o serie de operatii supli-
mentare ce nu tin de programul executat.Astfel,fiecare proces trebuie
segmentat in secvente,apoi fiecare secventa trebuie mutata intr-un tampon
de asteptare,de unde va fi preluata cu un algoritm oarecare.Toate aceste
operatii,nu numai ca intarzie executia,dar adauga si un posibil factor de
eroare (suprascrierea datelor,segmentarea incorecta,preluarea gresita a
segmentelor etc.).Din acest motiv,ori de cate ori este posibil,se va
prefera o solutie pe port paralel.In practica insa,cele mai frecvente sunt
solutiile mixte,deoarece numarul de procese solicitate,depaseste intotdea-
una structura fizica de executie (centralele au un numar limitat de linii

-58-
de executie).Impartirea unui proces in segmente,nu se poate face oricum.
Pentru a nu crea situatii incompatibile,segmentele trebuie sa contina
blocuri executabile,pe cat posibil independente de restul segmentelor din
proces (aplicatie).Cu alte cuvinte,pentru ca un program complex sa poata
fi executat in regim de multiprocesare seriala,trebuie sa poata fi sub-
impartit in mai multe module executabile.Aceste segmente executabile
poarta numele de fire de executie (thread-uri) si se reglementeaza in
limbaj Java cu ajutorul unui obiect special destinat,cu numele de Thread.
Astfel,programul va fi impertit in mai multe module.Fiecare modul va fi
inclus intr-un obiect de tip Thread.Fiecare obiect de tip Thread contine
o interfata de tip Runnable si prin urmare poate avea o executie indepen-
denta de restul modulelor.
Obiectul Thread are opt constructori diferiti,adica exista opt solutii
diferite de a crea un fir de executie.Cea mai simpla solutie este sa cre-
ati un obiect de tip Thread,in care sa definiti metoda Run().In acest
caz,firul de executie va utiliza propria metoda Run() pentru executie,dar
apelul nu se va face prin metoda Run(),ci se va apela o metoda special
destinata,numita start().
EXEMPLU:
public class FirExecutabil extends Thread {
public void run() {
System.out.println("Mesajul returnat !");
}
public static void main(String[] args) {
(new FirExecutabil()).start();
}
}
-salvati fila cu numele FirExecutabil.java.Compilati si executati.
Clasa Thread este importata implicit o data cu pachetul lang.Obser-
vati ca in metoda main(),obiectul se creaza prin apelul recursiv al
constructorului (clasa isi autoapeleaza constructorul).
Daca doriti ca firul executabil creat sa contina metoda Run() definita
in alt obiect (adica sa importe pentru executie datele dintr-o alta clasa)
trebuie sa utilizati al doilea tip de constructor,in care obiectul se
creaza pe baza unei interfete de tip Runnable.
EXEMPLU:
public class HelloRunnable implements Runnable {
public void run() {
System.out.println("Hello from a thread !");
}
public static void main(String[] args) {
(new Thread(new HelloRunnable())).start();
}
}
-salvati fila cu numele HelloRunnable.java.Compilati si executati.
Cele doua metode sunt practic identice,dar utilizeaza constructori dife-
riti.Cea de a doua metoda se utilizeaza atunci cand exista deja o inter-
fata oarecare,creata cu ajutorul unei interfete de tip Runnable,pe care
doriti sa o includeti intr-un thread (pentru a putea fi executata apoi
concurential).Ceilati 6 constructori,permit denumirea firului de executie
si respectiv formarea de grupuri de astfel de fire executabile.

-59-
Imediat dupa crearea unui obiect de tip Thread,se pot seta proprieta-
tile,sau se pot apela metodele acestui obiect.De exemplu,pentru a deter-
mina o intirziere de executie a unui fir executabil,se poate apela metoda
sleep().
EXEMPLU:
public class FirExecutabil2 extends Thread {
public void run() {
System.out.println("Mesajul returnat !");
}
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
try {
(new FirExecutabil2()).sleep(2000);
} catch (InterruptedException e) {
return;
}
(new FirExecutabil2()).start();
}}}
-salvati fila cu numele FirExecutabil2.java.Compilati si executati.
Atunci cand un proces (o aplicatie) contine mai multe fire executabile,
procesorul va alege si executa aceste fire,in functie de o serie intreaga
de criterii.Daca nu evaluati corect aceste criterii,executia va parea
uneori absolut paradoxala.
EXEMPLU:
public class FirExecutabil3 extends Thread {
public void run() {
System.out.println("Mesajul returnat !");
}
public static void main(String[] args) {
FirExecutabil3 fir_1 = new FirExecutabil3();
fir_1.setName("Firul1");
FirExecutabil3 fir_2 = new FirExecutabil3();
fir_2.setName("Firul2");
try {
System.out.println(fir_1.getName());
fir_1.sleep(2000);
fir_1.start();
System.out.println(fir_2.getName());
fir_2.sleep(5000);
fir_2.start();
} catch (InterruptedException e) { return ; }
}
}
-salvati fila cu numele FirExecutabil3.java.Compilati si executati.
Pentru a putea reglementa ordinea de executie,fiecare Thread are si o
anumita prioritate de executie.Aceasta prioritate se poate seta prin
metoda setPriority si accepta valori de tip int cuprinse intre 1 si 10.
Valoarea implicita este 5 si este reglementata prin constanta NORM_PRIO-
RITY,minima este MIN_PRIORITY = 1 iar maxima este MAX_PRIORITY = 10.In
exemplul de mai sus,ambele fire de executie au acceasi prioritate(normala)
asa ca vor fi executate in ordinea aparitiei in program).

-60-
Daca prioritatile nu sunt egale,se va executa preferential cel cu
prioritatea mai mare.
EXEMPLU:
public class FirExecutabil4 extends Thread {
public void run() {
System.out.println("Firul curent este: " + Thread.currentThread());
System.out.println("Mesajul returnat !");
}
public static void main(String args[]){
FirExecutabil4 fir_1 = new FirExecutabil4();
fir_1.setName("Firul1");
FirExecutabil4 fir_2 = new FirExecutabil4();
fir_2.setName("Firul2");
try {
fir_1.setPriority(2);
fir_2.setPriority(7);
fir_1.sleep(5500);
fir_2.sleep(1500);
fir_2.start();
fir_1.start();

} catch (InterruptedException e) { return; }


}
}
-salvati fila cu numele FirExecutabil4.java.Compilati si executati.
Puteti observa ca metoda sleep() are prioritate.Primul fir executat
este firul fir_2 (cu prioritatea 7) urmat de fir_1 (cu prioritatea 2).
Aceste notiuni sunt deja suficiente,pentru a putea crea si organiza
grupuri mai mici sau mai mari de astfel de fire executabile,in care o
parte dintre ele se vor executa prioritar,iar altele vor fi ordonate in
stiva,pe linie de asteptare.Daca numarul de fire este foarte mare,exista
riscul ca o parte dintre fire sa nu poata fi executate niciodata,deoarece
in permanenta vor aparea alte fire cu prioritate mai mare.Din acest motiv
este bine sa existe o buna corelatie intre numarul de fire executabile si
numarul de operatii executate de procesor/secunda,astfel incat sa nu
ramana fragmente de cod neexecutate.
O alta problema extrem de importanta o reprezinta durata de viata a
fiecarui fir executabil.Fiecare fir are o proprietate denumita STATE.In
fiecare moment al executiei,firul nu poate avea decat un singur status,ce
poate fi: NEW,RUNNABLE,BLOCKED,WAITING,TIMED_WAITING, sau TERMINATED.
Un fir executabil normal este NEW imediat dupa creere,WAITING inainte
de a fi executat,RUNNABLE in timpul executiei si TERMINATED imediat ce
a fost executat.Cu alte cuvinte,imediat dupa executie firul isi schimba
statusul si nu mai poate fi reapelat pentru o noua executie.Se spune ca
firul respectiv "a murit".Exista si fire executabile nemuritoare.Aceste
fire executabile poarta numele de DAEMON si se creaza cu ajutorul metodei
setDaemon().In cazul firelor DAEMON,dupa terminarea executiei statusul
lor devine WAITING in loc de TERMINATED si pot fi reaplelate.Un astfel
de fir DAEMON ramane executabil atat timp cat mai exista in executie un
fir nedaemonic,adica pe tot parcursul aplicatiei,deoarece functia main
este la rindul sau un fir executabil nedaemonic.

-61-
EXEMPLU:
public class FirExecutabil5 extends Thread {
public void run() {
System.out.println("Mesajul returnat !");
try {
System.out.println("Metoda RUN-firul curent este: "
+ thread.currentThread());
while (true) {
try { Thread.sleep(1500);
} catch (InterruptedException x) { }
System.out.println("Firul DAEMON este activat din nou !");
System.out.println("Firul actual= " +Thread.currentThread());
}
} finally { System.out.println("Iesire din metoda RUN"); }
}
public static void main(String[] args) {
FirExecutabil5 fir_1 = new FirExecutabil5();
fir_1.setName("Firul1");
fir_1.setPriority(7);
FirExecutabil5 fir_2 = new FirExecutabil5();
fir_2.setName("Firul2");
fir_2.setPriority(1);
FirExecutabil5 fir_3 = new FirExecutabil5();
fir_3.setName("Firul3");
fir_3.setPriority(9);
fir_1.setDaemon(true);
fir_2.setDaemon(true);
fir_3.setDaemon(true);
fir_3.start();
fir_2.start();
fir_1.start()
System.out.println(" Status Firul1= " + fir_1.getState());
System.out.println(" Status Firul2= " + fir_2.getState());
System.out.println(" Status Firul3= " + fir_3.getState());
try { Thread.sleep(3000);
} catch (InterruptedException x) { } ;
System.out.println(" Status Firul1= " + fir_1.getState());
System.out.println(" Status Firul2= " + fir_2.getState());
System.out.println(" Status Firul3= " + fir_3.getState());
}
}
-salvati fila cu numele FirExecutabil5.java.Compilati si executati.
Observati cu atentie exercitiul.Ori de cate ori doriti sa depanati,
sau sa organizati ordinea de executie a thread-urilor este bine sa cititi
statusul pentru fiecare fir,in momentul respectiv.
ATENTIE ! -sirurile daemonice creaza foarte frecvent bucle de executie
infinite,fie direct,fie prin combinarea unui grup oarecare de circumstante
sau bucle de control.Ca rezultat,trebuie sa verificati cu maximum de aten-
tie toate variantele posibile de executie,inclusiv cele improbabile sau
cele care genereaza exceptii.Buclele infinite,blocheaza executia si sunt
extrem de stinjenitoare pentru "creditul" unui programator.

-62-
Atunci cand exista mai multe fire executabile,unul dintre ele ofera
suport pentru executia celorlalte.Firele executabile pot executa operatii
in background,sau pot crea interfete vizuale.De exemplu,o interfata vizu-
ala poate include mai multe module independente,fiecare modul fiind inclus
intr-un obiect de tip Thread.
EXEMPLU:
import javax.swing.*;
class Fir1 extends Thread {
public void run() {
JFrame frame = new JFrame("Fir1");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel label = new JLabel("Prima interfata grafica");
frame.setBounds(100,100,200,200);
frame.getContentPane().add(label);
frame.pack();
frame.setVisible(true);
}
}
class Fir2 extends Thread {
public void run() {
JFrame frame = new JFrame("Fir2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel label = new JLabel("A doua interfata grafica");
frame.setBounds(300,100,200,200);
frame.getContentPane().add(label);
frame.pack();
frame.setVisible(true);
}
}
public class FirExecutabil6 extends Thread {
public static void main(String[] args) {
(new Fir1()).start();
(new Fir2()).start();
}
}
-salvati fila cu numele FirExecutabil6.java.Compilati si executati.
Exemplul contine trei fire executabile.Cel din metoda main() se exe-
cuta in background si ofera suport pentru cele doua fire executabile ce
contin cate o interfata vizuala.Observati ca firele secundare sunt incluse
in clase simple (private) in timp ce firul implicit este inclus in clasa
declarata "public".In mod similar,se pot crea module complexe,cu executie
independenta.Aceste module sunt usor de importat in orice program si pre-
zinta avantajul ca nu ocupa memoria de operare decat in timpul executiei.
Un pachet importat,este prezent in mediul de memorie pe tot parcursul
executiei,in timp ce un fir executabil poate avea si o existenta efemera,
strict pe durata in care se executa firul respectiv.
Daca se aglomereaza prea multe fire executabile,se produce acelasi
fenomen ca si in cazul mesajelor Windows.Se produce fenomenul denumit si
"pool-ing",adica firele de executie se aduna in stiva (sau in tamponul)
de memorie) iar o parte dintre ele nu ajung sa fie executate decat la
inchiderea programului (cele cu prioritate minima).

-63-
Aceleasi criterii trebuiesc respectate si atunci cand editati programul
cu ajutorul unei interfete vizuale.
EXEMPLU: (NetBeans)
-deschideti un proiect nou si adaugati JFrame
-deschideti fereastra de Design
-adaugati doua butoane,alegeti pentru fiecare evenimentul Action si apoi
actionPerformed si editati metodele:
private void JButton1ActionPerformed(java.awt.event.ActionEvent evt){
class Fir1 extends Thread {
public void run() {
javax.swing.JFrame frame = new javax.swing.JFrame("Fir1");
frame.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
javax.swing.JLabel label = new javax.swing.JLabel("Prima interfata");
frame.setBounds(100,100,200,200);
frame.getContentPane().add(label);
frame.pack();
frame.setVisible(true);
}
}
(new Fir1()).start();
private void jButton2ActionPerformed(java.awt.event.ActionPerformed evt){
class Fir2 extends Thread {
public void run() {
javax.swing.JFrame frame = new javax.swing.JFrame("Fir2");
frame.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
javax.swing.JLabel label = new javax.swing.JLabel("A doua interfata");
frame.setBounds(300,100,200,200);
frame.getContentPane().add(label);
frame.pack();
frame.setVisible(true);
}
}
(new Fir2()).start();
-testati si executati exemplul.Este similar cu cel precedent,dar cu
deosebirea ca fiecare fir executabil este controlat cu ajutorul unui
buton.Nu mai este necesar un fir de suport.La fiecare apasare de buton,
firul respectiv va fi recreat si functional(butonul are un fir propriu).
Observati ca in ambele exemple,obiectul Thread a fost creat cu "new",
doar in momentul executiei.Acest gen de fire poarta si numele de fire
"dinamice",deoarece se pot adapta la un anumit context de memorie,spre
deosebire de cele statice (cum sunt cele daemonice) ce sunt prezente in
memorie pe toata durata de executie a programului (exemplu: firul ce
controleaza functia main).
Fiind obiecte,firele de executie pot interactiona cu toate celelalte
obiecte din acelasi spatiu de vizibilitate: -pot avea acces comun la date,
si la resurse,pot utiliza aceleasi variabile sau arii de memorie pentru
a organiza datele,pot parataja acelasi tampon de memorie pentru a executa
unele operatii etc.Mai mult decat atat,firele de executie se pot bloca si
debloca reciproc,isi pot schimba temporar prioritatile sau comenzile de
intirziere,se pot activa sau inactiva reciproc etc.Atunci cand sunt mai
multe,este bine sa fie organizate intr-un obiect de tip container.

-64-
EXEMPLU:
import javax.swing.*;
class Fir1 extends Thread {
public void run() {
JFrame frame = new JFrame("Fir1");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel label = new JLabel("Prima interfata grafica");
frame.setBounds(100,100,200,200);
frame.getContentPane().add(label);
frame.pack();
frame.setVisible(true);
String sir1 = "";
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) { return; };
FirExecutabil7.numar1 = FirExecutabil7.numar1 + 1 ;
label.setText(sir1.valueOf(FirExecutabil7.numar1));
}}}
class Fir2 extends Thread {
public void run() {
JFrame frame = new JFrame("Fir2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel label = new JLabel("A doua interfata grafica");
frame.setBounds(300,100,200,200);
frame.getContentPane().add(label);
frame.pack();
frame.setVisible(true);
String sir1 = "";
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) { return; };
FirExecutabil7.numar1 = FirExecutabil7.numar1 + 5;
label.setText(sir1.valueOf(Firexecutabil7.numar1));
}}}
public class FirExecutabil7 extends Thread {
public static int numar1 = 0;
public static void main(String args[]) {
(new Fir1()).start();
(new Fir2()).start();
}}
-salvati fila cu numele FirExecutabil7.java.Compilati si executati.
In exercitiul de mai sus,se pot observa urmatoarele:
-fiecare thread executa un set de operatii,dupa un algoritm propriu.
-ambele thread-uri modifica valoarea variabilei publice "numar1".
-actiunea unui thread influenteaza actiunea celuilat thread,sau altfel
spus,cele doua siruri prezinta fenomenul de inteferenta (thread interfe-
rence).Aceasta interferenta poate avea un rol pozitiv (adica cele doua
fire se potenteaza reciproc),sau poate avea un rol negativ (daca cele
doua fire se anuleaza reciproc).
-65-
Pentru a putea observa interferenta negativa,este suficient ca in
exemplul de mai sus sa fixati acelasi interval de timp pentru functia
sleep(),in ambele siruri.Apoi setati primul fir sa incrementeze cu unu
valoarea variabilei numar1,la fiecare bucla,si respectiv setati cel de
al doilea fir sa decrementeze cu unu valoarea variabilei numar1,la fiecare
bucla.La executie,puteti observa ca valoarea variabilei va oscila intre
1 si 0.
Un alt fenomen ce trebuie evitat,este fenomenul de "inconsistenta a
memoriei",adica situatiile in care datele preluate din memorie nu mai
sunt actuale in momentul interpretarii lor.Exemplu: daca se utilizeaza
un fir pentru a seta valoarea unei variabile,si un alt fir pentru citirea
valorii arhivate in variabila respectiva,exista posibilitatea ca intre
cele doua operatii sa se interpuna un al treilea fir de executie,cu prio-
ritate superioara,ce modifica valoarea variabilei respective.In acest caz,
chiar daca cele doua fire de executie sunt cuplate in aceeasi aplicatie,
exista riscul ca valoarea preluata sa fie "inconsistenta" cu valoarea
setata de primul fir.Rezultatul obtinut va fi eronat.
Pentru a evita acest gen de situatii,trebuie ca executia firelor sa se
ordoneze intr-un anumit fel,astfel incat sa nu se deranjeze reciproc.Cea
mai simpla solutie este sa intrerupeti firele de executie inutile si sa
lasati doar un singur fir,dar in acest caz,se vor pierde toate operatiile
executate de firele mai putin importante.Pentru reglementarea acestor
intreruperi,se poate utiliza metoda asociata cu bucla try-catch (pentru
InterruptedException).O modalitate mai eleganta de a ordona executia fire-
lor,va permite ca o parte dintre acestea sa fie doar intirziate,sau tre-
cute pe "linie de asteptare" si apoi sa fie reluate in ordinea prioritatii
pana cand se epuizeaza toate operatiile din program.Acest gen de solutie
poarta numele de sincronizare si se realizeaza cu ajutorul unor obiecte
denumite "monitoare".Un monitor se creaza cu ajutorul cuvintului cheie
"syncronized" si are proprietatea de a putea bloca sau debloca un fir de
executie.Pentru a simplifica lucrurile,Java Virtual machine recunoaste ca
monitor orice obiect derivat din clasa Object,adica orice obiect standard
din Java.Pentru a putea bloca si respectiv elibera firele de executie,se
vor aplea metodele wait() si respectiv notify() si notifyall().Asadar,
orice obiect care include aceste metode,poate fi utilizat si pe post de
monitor,pentru a putea organiza executia thread-urilor.De cele mai multe
ori,se utilizeaza un singur obiect,atat pentru a contine variabilele in
care se opereaza,cat si pentru a sincroniza executia.In exemplul de mai
sus,variabila "numar1" este inclusa in obiectul FirExecutabil7,care este
un obiect de tip Thread (derivat din Object) si poate fi utilizat si
pentru a sincroniza cele doua fire executabile.Este suficient sa apelati
metodele: FirExecutabil7.wait() sau respectiv FirExecutabil7.notify().
Pentru ca executia unei metode sa poata fi sincronizata,este necesar
ca metoda sa fie declarata utilizand si cuvantul cheie "SYNCHRONIZED".Nu
se pot sincroniza constructorii claselor si nici nu ar avea rost,deoarece
metodele de tip constructor nu pot fi accesate simultan de mai multe fire
de executie.Este bine insa sa utilizati metode sincronizate,ori de cate
ori un obiect este vizibil pentru doua sau mai multe fire de executie.In
acest caz,cuvantul cheie va asigura ca la un anumit moment dat,doar unul
singur dintre firele de executie va putea avea acces la obiectul respec-
tiv.Acest mecanism poarta numele de blocare intrinseca (intrinsec lock).
-66-
EXEMPLU:
import javax.swing.*;
class Fir1 extends Thread {
public synchronized void scrie() {
JFrame frame = new JFrame("Fir1");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel label = new JLabel("Prima interfata grafica");
frame.getContentPane().add(label);
frame.pack();
frame.setVisible(true);
String sir1 = "";
for (int i = 0;i < 10; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) { return; };
FirExecutabil8.numar1 = FirExecutabil8.numar1 + 1;
label.setText(sir1.valueOf(FirExecutabil8.numar1));
}}}
class Fir2 extends Thread {
public synchronized void scrie() {
JFrame frame = new JFrame("Fir2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel label = new JLabel("A doua interfata grafica");
frame.setBounds(300,100,200,200);
frame.getContentPane().add(label);
frame.pack();
frame.setVisible(true);
String sir1 = "";
try {
Thread.sleep(3000);
} catch (InterruptedException e) { return; };
FirExecutabil8.numar1 = FirExecutabil8.numar1 + 5;
label.setText(sir1.valueOf(FirExecutabil8.numar1));
}}
public class FirExecutabil8 extends Thread {
public static int numar1 = 0;
public static void main(String args[]) {
Fir1 FirNou1 = new Fir1();
Fir2 FirNou2 = new Fir2();
FirNou2.scrie();
try {
FirNou1.scrie();
if (numar1 < 10) { FirNou1.wait(); };
} catch (InterruptedException e) { return; };
if ( numar1 <10) { FirNou2.notifyAll(); };
}}
-salvati fila cu numele FirExecutabil8.java.Compilati si executati.
Observati ca FirExecutabil8,nu numai ca ofera firul executabil de
suport,pentru cele doua fire executabile,dar este si obiect de tip "mo-
nitor".Metoda wait() pune primul fir pe linie de asteptare,pana cand se
deruleaza cel de al doilea fir,dupa care se activeaza cu notifyAll().

-67-
Orice obiect de tip Thread este derivat din Object si poate fi utili-
zat pe post de monitor.Pentru a putea utiliza blocajul intrinsec,trebuie
ca firul de executie sa dobindeasca acces exclusiv la acel obiect.Accesul
exclusiv se obtine apeland metoda declarata cu "SYNCHRONIZED".In momentul
in care obiectul incepe sa execute metoda sincronizata,obiectul nu mai
poate fi accesat de alte fire de executie,adica este blocat intrinsec.
Imediat dupa terminarea executiei,obiectul este deblocat,tot automat,
adica va putea fi accesat de alte fire de executie.Din acest motiv,este
esential ca monitorul sa obtina accesul exclusiv la obiect,inainte de a
apela metoda wait() sau notify().Cu alte cuvinte,inainte sa incercati sa
blocati un fir de executie,trebuie sa apelati metoda sincronizata.In
plus,este bine ca metodele wait() si notify(),sa fie apelate cu ajutorul
unei conditii oarecare de tip boolean,pentru a evita mecanismele reintran-
te(daca se incearca reblocarea obiectului fara apelul metodei sincroniza-
te,se va returna un mesaj de eroare de tip IllegalMonitorStateException).
Acest concept este ceva mai greu de inteles la inceput,dar este esen-
tial pentru a putea sistematiza ordinea de executie a thread-urilor.Nu
numai ca pot avea prioritati diferite,ci se pot crea algoritmi prin care
firele de executie se asteapta unul pe altul,pana cand exista conditiile
necesare pentru a executa o anumita operatie.Exemplu: firul efector va
astepta pana cind un alt fir executabil va deschide o anumita adresa de
Internet si va prelua un anumit set de date.Operatiile in retea nu pot fi
temporizate,deoarece depind de o serie de factori variabili (cum este
de exemplu viteza de transfer).Este esential ca firele de executie sa
poata astepta atat timp cat este necesar,pentru preluarea datelor.
La fel ca si metodele sincronizate,se pot utiliza instructiunile sin-
cronizate.Diferenta consta in faptul ca metoda sincronizata poate fi
apelata din orice monitor,in timp ce instructiunea sincronizata trebuie
sa specifice exact obiectul ce obtine blocajul intrinsec (monitorul).
EXEMPLU: public void addName(String name) {
synchronized(this) { lastName = name;
nameCount ++ ; }
nameList.add(name);
}
va putea fi apelata astfel:
public class MsLunch {
private long c1 = 0;
private Object lock1 = new Object();
public void inc1() {
synchronized(lock1) { c1++; }
}
}
-observati ca metoda synchronized se apeleaza explicit pentru obiectul
lock1,creat special pentru a fi "monitor".
Atunci cand lucrati cu un numar mare de fire executabile,este recoman-
dabil sa nu va repeziti direct la buclele automate pentru crearea algo-
ritmilor.Mai bine,construiti algoritmul cu doua sau trei fire si doar
apoi extindeti algoritmul pentru toate firele.Altfel,riscati sa mascati
o serie de operatii nedorite,sau dimpotriva,sa pierdeti din vedere o
serie de etape importante din constructia algoritmului.Verificati atent
orice mesaj de eroare si metodele pentru tratarea exceptiilor.

-68-
Atunci cand se proiecteaza sincronizarea unui numar oarecare de fire
executabile,trebuie sa se tina cont de perioada in care un astfel de fir
este activ,sau "in viata"(liveness).Exista o serie de situatii ce trebuie
sa fie evitate.De exemplu,atunci cand doua fire executabile sunt blocate
simultan si fiecare dintre ele asteapta sa fie deblocat de catre celalalt
fir,se creaza un blocaj permanent,denumit "deadlock".O situate mai putin
dramatica se intilneste atunci cand un thread asteapta executia unui alt
thread,care la rindul sau asteapta un alt thread (uneori timp destul de
idelungat).Acest gen de situatie poarta numele de "Livelock",deoarece
blocul nu este definitiv,ci mai devreme sau mai tarziu,va fi totusi exe-
cutat.Prin intirzierea executiei unor astfel de fire,se pot crea si si-
tuatii in care o parte dintre firele executabile nu mai ajung sa fie
executate,deoarece apar in permanenta thread-uri noi,cu prioritate mai
mare in executie.Acest gen de situatie poarta si numele de infometare
(starvation).Pentru a grupa thread-urile cu prioritate egala in functie
de o anumita conditie,se pot crea blocuri protejate (guarded blocks),in
care firele de executie vor fi incluse intr-o bulca conditionala de tip
if sau while.
Pentru a limita la maximum erorile de executie,este recomandabil sa
utilizati doar obiecte constante (immutable).Un obiect este constant,
atunci cand nu-si modifica statusul in timpul executiei.Nu exista o regula
fixa pentru a crea astfel de obiecte,dar se pot formula cateva recomandari
generale: -nu incudeti in obiect metode de tip set() si get().
-declarati variabilele de tip "final" si "private".
-nu supraincarcati definitiile si operatorii.
-nu amestecati obiectele constante cu cele variabile.
Un obiect este variabil,atunci cand in timpul executiei isi modifica
statusul,proprietatile,sau chiar structura interna.Obiectele cu structura
variabila sunt foarte utile in aplicatiile mici si directe,dar in cazul
aplicatiilor complexe de tip multithreading,cresc riscul de a genera
situatii de incompatibilitate.Exemplu: un thread asteapta niste date
preluate de alt thread,dar intre timp,obiectul sursa a fost reformatat si
cererea formulata este inconsistenta cu datele actuale.Pentru a evita
aceste situatii,se recomanda pe cat posibil ca thread-urile sa execute
mai ales operatii simple si directe.Acest gen de operatii,poarta si numele
de operatii "atomice",adica nu pot fi subimpartite in seturi de operatii
subsidiare.
EXEMPLU: -un thread poate deschide o fila oarecare si poate citi primul
byte din fila intr-o variabila,sau poate crea un tampon special de memorie
in care citeste primul byte din fila,apoi executa o serie intreaga de
operatii de verificare si control,reformateaza data sub forma de sir de
caractere si abea apoi arhiveaza data intr-o variabila de tip String.
Evident ca se va prefera prima varianta.Astfel de simplificari nu sunt
intotdeauna posibile,dar asigura robustetea si siguranta executiei.
Pentru a organiza si simplifica solutiile de sincronizare a thread-
urilor,java contine un pachet de obiecte special destinate,denumit:
java.util.concurent.Acest pachet contine obiecte specializate de tip
"monitor" denumite "Locks",interfete pentru executie denumite "executors"
si containere pentru colectii de fire (ThreadPools),precum si un set de
variabile de tip "atomic".Toate aceste facilitati au scopul de a simpli-
fica munca de programare si depanare a thread-urilor.

-69-
EXEMPLU:
import javax.swing.*;
import java.util.concurrent.locks.*;
class Fir1 extends Thread {
public synchronized void run() {
JFrame frame = new JFrame("Fir1");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jLabel label = new JLabel("Interfata grafica");
frame.setBounds(100,100,300,300);
frame.getContentPane().add(label);
frame.pack();
frame.setVisible(true);
String sir1 = "";
final ReentrantLock blocaj1 = new ReentrantLock();
try { if(FirExecutabil9.numar1 < 1) {
Thread.sleep(2000);
blocaj1.tryLock();
label.setText(sir1.valueOf("Este blocat? =" +
blocaj1.isLocked()));
Thread.sleep(2000);
label.setText("de firul curent? =" +
sir1.valueOf(blocaj1.isHeldByCurrentThread())); };
FirExecutabil9.numar1 = 5;
} catch (InterruptedException e) {
return; } finally { blocaj1.unlock(); };
}}
public class FirExecutabil9 extends Thread {
public static int numar1 = 0;
public static void main(String args[]) {
(new Fir1()).start();
}}
-salvati cu numele FirExecutabil9.java.Compilati si executati.
In exemplul de mai sus am utilizat pe post de monitor un obiect de
tip ReentrantLock,deoarece are o serie intreaga de metode interesante.Nu
numai ca puteti verifica daca thread-ul a obtinut accesul exclusiv la
obiect(cu lock() sau tryLock()),dar puteti verifica daca exista si alte
thread-uri in stiva,pe linie de asteptare,cate sau cum se numesc,etc.
Exista si monitoare de tip ReentrantReadWriteLock.In acest caz,blocarea
si deblocarea trebuie sa se faca in tandem: daca este deblocat pentru
citire trebuie sa fie blocat pentru scriere si viceversa.Nu se va putea
scrie si citi simultan din obiect,ci operatiile se vor executa strict
secvential.Mai mult decat atat,obiectul ReentrantLock contine si o
metoda denumita newCondition() prin care se poate modifica in timpul
executiei conditia prin care s-a construit un blocul protejat (conditia
necesara pentru a obtine accesul exclusiv la obiect).Cu ajutorul acestei
metode,blocul poate fi adaptat interactiv la necesitatile de moment ale
utilizatorului.
Obiectele din acest pachet,nu numai ca simplifica munca de programare,
dar sunt sigure si robuste si evita o serie intreaga de posibile erori
de executie.In plus,aceste obiecte contribuie si la structura modulara
a programului,sau la rutinele de depanare si autodepanare rapida.

-70-
Pachetul Concurrent contine si alte clase extrem de utile,cum sunt cele
de tip container,cu ajutorul carora se pot organiza firele de executie,sau
orice alt fel de executabile(de exemplu intrefetele grafice).Acest tip de
obiecte este util atunci cand se lucreaza cu seturi mari de thread-uri,
cum este cazul serverelor de retea,sau al centralelor telefonice,etc.In
aceste situatii,pentru a organiza si stoca temporar modulele executabile
(firele de executie),se pot utiliza tampoane de memorie simple,dar este
mult mai eficient daca se utilizeaza obiecte special concepute.Obiectele
specializate sunt de doua tipuri: Executor Interfaces si Thread Pools.
Interfetele de tip Executor au rostul de a putea organiza seturi mari
de thread-uri create cu ajutorul unei interfete Runnable (adica thread-uri
ce implementeaza intefete grafice).
EXEMPLU:
import javax.swing.*;
import java.util.concurrent.Executor;
class Exe1 implements Runnable {
public void run() {
JFrame frame = new JFrame("Fir1");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel label = new Jlabel("Prima interfata grafica");
frame.setBounds(100,100,200,200);
frame.getContentPane().add(label);
frame.pack();
frame.setVisible(true);
}
}
class Exe2 implements Runnable {
public void run() {
JFrame frame = new JFrame("Fir2");
frame.setDefaultCloseOperation(Jframe.EXIT_ON_CLOSE);
JLabel label = new JLabel("A doua interfata grafica");
frame.setBounds(300,100,200,200);
frame.getContentPane().add(label);
frame.pack();
frame.setVisible(true);
}
}
class DirectExecutor implements Executor {
public void execute(Runnable r) {
r.run(); }
}
public class Executor2 {
public static void main(String[] args) {
DirectExecutor Executabil = new DirectExecutor();
Executabil.execute(new Exe1());
Executabil.execute(new Exe2());
}
}
-salvati fila cu numele Executor2.java.Compilati si executati.
Interfata de tip Executor,utilizeaza in loc de run(),sau start(),metoda
execute(),pe care am redefinit-o in clasa DirectExecutor.Se poate observa

-71-
cu usurinta ca obiectul "Executabil" poate lansa in executie cele doua
interfete runnable cu ajutorul metodei execute().Atunci cand numarul de
interfete este redus,acelasi rezultat se poate obtine si creand cate un
thread nou,pentru fiecare interfata:
(new Thread(new Exe1())).start();
(new Thread(new Exe2())).start();
etc...
Care este diferenta ? In cazul aplicatiilor mari,cu un numar foarte mare
de thread-uri,obiectul Executor nu numai ca incapsuleaza modulele intr-un
spatiu de vizibilitate mai restrans,in care limiteaza interferentele cu
restul aplicatiei,dar prezinta avantajul ca este gata construit.Daca se
construieste cate un thread nou,pentru fiecare punere in executie a unei
interfete runnable oarecare,exista riscul ca sistemul de operare sa nu
detina suficienti pointeri spre adresele de memorie (sistemul se poate
bloca prin suprasolicitare).Cu ajutorul obiectului Executor,aceeasi inter-
fata runnable poate fi pusa in executie ori de cate ori,fara a se crea
redundanta (firele de executie sunt "muritoare",iar la un nou apel vor
returna un mesaj de eroare).In exemplul de mai sus,puteti incerca sa
apelati cele doua interfete,in mod repetat,dupa un algoritm oarecare.
Daca in loc de Executor,utilizati o interfata de tip ExecutorService,
beneficiati si de setul complet de metode al acestei interfete.De exemplu,
pentru a inchide simultan toate executabilele din obiect,se va putea apela
metoda shutdown(),sau pentru a activa simultan o colectie intreaga de
executabile,se va putea apela metoda invokeAll().ExecutorService este
derivata din Executor si adauga un set intreg de metode utile pentru
controlul si monitorizarea executiei.Detaliile referitoare la acest
subiect nu fac obiectul acestui manual,dar este bine sa retineti faptul
ca aceste obiecte,va pot simplifica foarte mult problemele ridicate de
programarea multitasking in regim concurential.In plus,functionalitatea
interfetelor de tip Executor si ExecutorService poate fi extinsa cu aju-
torul metodelor clasei Executors( callable(),newCachedThreadPool(),new-
SingleThreadExecutor(),privilegedCallable(),defaultThreadfactory(),etc.).
De exemplu interfata ThreadFactory,sau metoda Executors.defaultThreadFac-
tory(),se pot utiliza atunci cand doriti sa creati in permanenta fire noi
de executie.Firele nou create vor fi toate in acelasi grup (ThreadGroup)
si vor putea fi organizate cu acelasi SecurityManager.In plus,firele de
executie create cu ThreadFactory nu mai apeleaza la poinerii sistemului
de operare,ci utilizeaza adrese de memorie oferite de obiectul construc-
tor.Ca rezultat se evita eventualele "erori de executie",ce nu pot fi
evidentiate decat in situatiile extreme ale mediului de memorie(cum este
cazul pointerilor spre memorie).
Obiectele de tip container compartimenteaza spatiul de memorie si sim-
plifica munca de depanare si control.Containerele de tip ThreadPool,dupa
cum le spune si numele,au rolul de a adaposti temporar thread-urile cu
prioritate mai redusa.In locul unei stive simple,se vor utiliza aceste
obiecte specializate,care simplifica operatiile de sortate a thread-urilor
aflate "pe linie de asteptare".Cu alte cuvinte,obiectele de tip Thread-
PoolExecutor ofera o serie intreaga de metode,prin care arhiveaza tempo-
rar,activeaza sau dezactiveaza thread-urile,ajusteaza dimensiunea stivei,
controleaza numarul de thread-uri din stiva,anticipeaza si rezolva even-
tualele suprasolicitari,etc.

-72-
EXEMPLU:
import javax.swing.*;
import java.util.concurrent.ThreadFactory;

class Exe1 implements Runnable {


public void run() {
JFrame frame = new JFrame("Fir1");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel label = new JLabel("Interfata grafica");
frame.setBounds(100,100,200,200);
frame.getContentPane().add(label);
frame.pack();
frame.setVisible(true);
}
}
class Fabrica implements ThreadFactory {
public Thread newThread(Runnable r) {
return new Thread(r);
}
}
public class NewThread1 {

public static void main)String args[]) {


for (int i=0;i<5;i++) {
(new Fabrica()).newThread(new Exe1()).start();
}
}
}
-salvati fila cu numele NewThread1.java.Compilati si executati.In
timpul executiei,puteti trage cu indicatorul mouse apasat,de fiecare
fereastra,pentru a separa cele 5 thread-uri suprapuse.Exemplul este
sugestiv pentru modul de utilizare al interfetei ThreadFactory.Remarcati
cu fiecare thread nou creat,utilizeaza constructorul ce are ca parametru
o interfata de tip Runnable.Acest parametru se poate exploata pentru a
seta prioritatea,numele si statusul thread-ului,sau pentru a implementa
un set oarecare de operatii,pe care doriti sa le execute fiecare thread
nou creat.ThreadFactory are o singura metoda: newThread(Runnable r).
Obiectele de tip ThreadPoolExecutor sunt ceva mai greu de utilizat,
deoarece constructorii au un set intreg de parametri,printre care si
stiva in care se vor arhiva thread-urile,mai exact o interfata de tip
BlockingQueue<Runnable>.Insa interfata BlockingQueue<E> este de tip
abstract si trebuie inlocuita cu una derivata si redefinita,adica cu un
obiect derivat din clasa ArrayBlockingQueue<E>,care detine un constructor
valabil.ArrayBlockingQueue<E> permite construirea oricarui tip de stiva,
adica parametrul <E> poate fi reprezentat prin orice tip de data.Insa,
in cazul interfetelor grafice,acest parametru va fi o interfata de tip
Runnable.Ca rezultat,fiecare obiect din stiva va fi o interfata(grafica).
Este bine ca obiectul de tip ThreadPoolExecutor sa fie construit cu
o bucla de tip try...catch,pentru a putea depista eventual,erorile de
initializare a stivei,cu ajutorul exceptiei de tip NullPointerException.
Apoi se pot apela metodele specifice obiectului ThreadPoolExecutor.

-73-
EXEMPLU:
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import.java.util.concurrent.TimeUnit;
import.java.util.concurrent.BlockingQueue;
import.javax.swing.*;
class Exe1 implements Runnable {
public void run() {
JFrame frame = new JFrame("Fir1");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jLabel label = new JLabel("Interfata grafica");
frame.setBounds(100,100,200,200);
frame.getContentPane().add(label);
frame.pack();
frame.setVisible(true);
try {
int x=0;
String sir1 = "";
ThreadPoolExecutor pool = new ThreadPoolExecutor (
10,20,60,TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(20));
x= pool.getMaximumPoolSize();
label.setText("max Stiva = " + sir1.valueOf(x));
} catch (NullPointerException n) { return; };
}
}
public class Test1 {

public static void main(String args[]) {


(new Thread(new Exe1())).start();
}
}
-salvati fila cu numele Test1.java.Compilati si executati.Exemplul
nu face decat sa creeze un obiect de tip ThreadPoolExecutor si apoi sa
verifice dimensiunea maxima a stivei.In continuare,puteti sa deschideti
un numar oarecare de thread-uri,sa verificati periodic cate thread-uri
sunt in stiva,sa cresteti sau sa micsorati stiva,dupa un algoritm oare-
care etc.Pentru a crea un program ce simuleaza o centrala automata,ar mai
trebui sa adaugati si un timer,cu care sa cronometrati intervalele de
timp la care apar threadurile noi si apoi sa programati un mic algoritm
prin care sa anticipati eventualele aglomerari si sa cresteti preventiv
dimensiunea stivei,sau sa eliberati din thread-urile prea vechi.In apli-
catiile practice,obiectul ThreadPoolExecutor este deservit de un thread
de executie,care introduce sau extrage threadurile in obiect (in stiva).
In exercitii,acest thread efector poate fi cel care executa functia main,
dar in aplicatiile reale,trebuie sa existe unul sau mai multe astfel de
thread-uri (preferabil demonice).Cu cat obiectul va fi deservit de mai
multe thread-uri efectoare,cu atat stiva se va putea degaja mai rapid si
se va evita riscul de a ramane threaduri neexecutate.Acest obiect nu este
doar "o complicatie suplimentara",ci are rostul de a organiza cat mai
eficient executia threadurilor (o mini centrala automata).

-74-
In cazul interfetelor grafice realizate cu ajutorul componentelor din
pachetul SWING,organizarea firelor de executie trebuie sa tina cont si de
alti factori.Astfel,pentru a actualiza datele dintr-un obiect(component),
este esential ca apelul sa se faca din interiorul thread-ului in care
este definit obiectul Event Listener,adica din firul executabil in care
se "asteapta" evenimentul respectiv.Firul de executie in care se fac toate
operatiile de actualizare,poarta numele de "fir pentru tratarea evenimente-
lor" (event dispatch thread) si contine toate obiectele vizuale,impreuna
cu functiile pentru tratarea evenimentelor.Fiecare thread este un obiect
separat si izoleaza un anumit spatiu de vizibilitate.Daca se incearca
actualizarea unui obiect dintr-un thread,cu ajutorul unui alt thread,este
posibil sa apara erori de executie ce nu pot fi depistate de compilator si
nici nu se manifesta decat in anumite circumstante ale mediului de memorie.
Aceste erori,se pot produce fie prin interferenta (thread interference),fie
prin inconsistenta (memory consistency errors).Din acest motiv,majoritatea
obiectelor din pachetul Swing sunt descrise ca "not thread safe".Exista
si un numar limitat de obiecte,specificate ca "thread safe".Acestea pot
fi apelate din orice thread si in orice moment al executiei.Pentru a
evita aceste situatii,este bine sa includeti toate operatiile de actuali-
zare,doar in firul "event dispatch thread",sau sa organizati toate ope-
ratiile de asa maniera incat sa excludeti orice interferenta asupra date-
lor publice.
O alta situatie ce trebuie evitata,este cea a interfetelor "inghetate".
Atunci cand se utilizeaza un singur fir de executie,daca programul trebuie
sa execute un sir de operatii mai complex (de exemplu sa copieze o anumita
fila sau un program din reteaua Internet),atunci intreaga interfata gra-
fica va fi blocata ("inghetata") pentru intregul interval de timp,pana
cand se epuizeaza lantul de operatii.Pentru a evita acest gen de situatii,
este recomandabil sa utilizati mai multe thread-uri,dintre care unul va
tine evidenta interfetei grafice (event dispatch thread),iar altul va
lucra independent in background si va executa sirul de operatii necesare.
Acest ultim fir de executie,poarta si numele de "fir de lucru" (worker).
In pachetul Swing este inclus si un obiect special destinat pentru aceste
operatii,cu numele de SwingWorker.
Pe langa aceste fire de executie,pot fi necesare si altele,cu functii,
sau cu atributii specifice,pe care doriti sa le separati spatial de restul
operatiilor din program.De exemplu,daca aplicatia d-voastra necesita si o
serie de operatii preliminare (formatare,conversia datelor,crearea unor
obiecte specializate,preluarea datelor de la o anumita adresa,etc),atunci
se poate utiliza un thread special pentru initializare (initial thread).
Atunci cand thread-urile nu au o pondere egala,este bine sa nu fie
create cu ajutorul obiectelor de tip ThreadFactory si sa nu fie incluse
in containere de tip ThreadPool,ci sa fie organizate temporal,astfel incat
fiecare thread sa exploateze eficient procesorul.Daca aplicatia este mai
complexa,intotdeauna este util sa desenati si o schema simpla de executie,
asemanatoare cu un circuit electric,pe care sa sistematizati ordinea de
executie.O parte dintre operatii trebuie sa poata fi executate simultan,
sau cel putin "aparent simultan",in timp ce alte operatii vor trebui sa
stea pe linie de asteptare,pana cand configuratia de memorie va putea
permite executarea lor.Spre deosebire de thread-urile simple,SwingWorker
detine si un set de metode proprii,ce pot fi eventual redefinite.
-75-
Pe langa constructor,obiectele de tip SwingWorker detin si medtode ca:
doInBackground(),done(),execute(),get(),process(),publish(),run() etc.
Un obiect de tip SwingWorker se pune in executie prin metoda execute().
Nu este obligatoriu ca SwingWorker sa execute doar operatii in back-
ground.SwingWorker poate fi utilizat ca si un thread obisnuit,pentru orice
fel de operatii.De exemplu,poate include obiectele vizuale,pentru a fi un
thread de tip "event dispatch thread".
EXEMPLU:
import javax.swing.*;
class Procese extends SwingWorker<String,Object> {
@Override
public String doInBackground(){
return "text";
}
@Override
public void done() {
try {
JFrame frame = new JFrame("Fir1");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel label = new JLabel("Interfata grafica");
frame.setBounds(100,100,300,300);
frame.getContentPane().add(label);
frame.pack();
frame.setVisible(true);
label.settext(get());
} catch (Exception ignore) {}
}}
public class FirExecutabil10 extends Thread {
public static void main(String args[]) {
(new Procese()).execute();
}}
-salvati fila cu numele FirExecutabil10.java.Compilati si executati.
In exemplul,de mai sus,se pot observa urmatoarele:
-thread-ul SwingWorker se initializeaza cu execute()
-thread-ul SwingWorker <T,V> are si urmatorii parametri:
T - este tipul de data returnat de metodele doInBackground si Get
V - este tipul de data intermediara (tamponul de memorie) pentru
metodele publish si process
-metodele clasei pot fi redefinite cu ajutorul operatorului @Override
-in exemplu,am redefinit metoda doInBackground(),pentru a returna un
anumit sir de caractere si am redefinit metoda done(),pentru a crea
o mica interfata grafica,in care sa afiseze textul returnat
-metoda done() este apelata automat in momentul in care se termina
executia metodei doInBackground.Prin redefinirea lor,se poate crea un
duplex,pentru organizarea unui set oarecare de operatii.
In exemplul de mai sus,cele doua metode se executa simultan.Pentru
a ilustra mai bine secventa de executie a celor doua metode,exemplul se
poate dezvolta,astfel incat metoda doInBackground se execute o serie de
operatii preliminare,necesare pentru initializarea aplicatiei (de tip
initialize thread),iar metoda done() sa lanseze interfata grafica si
apoi sa o actualizeze (ca un event dispatch thread).
-76-
EXEMPLU:
import javax.swing.*;

class Procese extends SwingWorker<String,Object> {


public String[] sir1 = FirExecutabil11.sir2;
@Override
public String doInBackground() {
String sir3 = "";
for (int i=0;i< sir1.length;i++) { sir3 = sir1[i]; }
return(sir3);
}
@Override
public void done() {
try {
JFrame frame = new JFrame("Fir1");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel label = new JLabel("Interfata grafica");
frame.setBounds(100,100,300,300);
frame.getContentPane().add(label);
frame.pack();
frame.setVisible(true);
label.setText(get());
} catch (Exception ignore) {}
}}
public class FirExecutabil11 extends Thread {
public static String[] sir2 = { "t1","t2","t3","text4" };
public static void main(String args[]) {
Procese proc1 = new Procese();
proc1.execute();
}}
-salvati exemplul cu numele FirExecutabil11.java.
Exemplul este similar cu cel precedent,dar in acest caz,metoda doIn-
Background preia datele din clasa FirExecutabil si le prelucreaza sub o
forma oarecare inainte de a le returna.Apoi se executa automat metoda
done(),pentru a exploata datele prelucrate.Incercati sa dezvoltati putin
exemplul,pentru a prelua date din retea,pe care sa le prelucrati intr-un
fel oarecare si apoi sa le prezentati intr-o interfata grafica.
Se observa ca thread-ul SwingWorker poate fi atat de initializare,cat
si de tip worker sau event dispatch.Aceasta multivalenta poate crea o
serie intreaga de confuzii,atunci cand se traduce litaratura de speciali-
tate.Nu exista thread-uri specializate.Tipul de thread este etichetat
doar in functuie de contextul in care este utilizat.Mai mult decat atat,
in timpul executiei,acelasi thread poate fi utilizat pentru scopuri
complexe.
Un duplex asemanator il realizeaza si metodele publish() si process().
In acest caz insa,trebuie sa existe un tampon de memorie intermediar,in
care sa fie stocate datele returnate de metoda publish().De obicei acest
tampon este o clasa oarecare,ce accepta tipul de data returnat.Cele doua
metode se folosesc in tandem,pentru a putea prelua rezultate intermediare
ale unui set mai complex de operatii.Exemplu:-rezultatele partiale ale
unui set de operatii matematice.

-77-
EXEMPLU:
import javax.swing.*;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.awt.event.ActionEvent;
import java.awt.BorderLayout;

public class FirExecutabil12 extends JFrame {


private Random rand = new Random();
private AbstractAction startAction = new AbstractAction("Start"){
public void actionPerformed(ActionEvent e) {
startClicked(); }}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() { new FirExecutabil12().setVisible(true);}}); }
public FirExecutabil12(){
super("SwingWorker Demo");
add(new JButton(startAction),BorderLayout.CENTER);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setLocationByPlatform(true); }
private void startClicked() {
startAction.setEnabled(false);
new DemoWorker().execute(); }
private class DemoWorker extends SwingWorker <String,String> {
protected String doInBackground() throws Exception {
for (int i = 0; i < 50; i++) {
publish(Integer.toString(i));
TimeUnit.MILLISECONDS.sleep(rand.nextInt(20)); }
return null; }
@Override
protected void process(List<String> chunks) {
System.out.println("process: " + chuncks) }
@Override
protected void done() {
System.out.println("Executia este terminata !");
startAction.setEnabled(true)
}}}
-salvati fila cu numele FirExecutabil12.java.Compilati si executati.
In acest exercitiu are rost sa studiati clasa DemoWorker,cu cele trei
metode apelate.La executie,apasati butonul Start de mai multe ori conse-
cutiv.Observati ca executia este fragmentata,in calupuri de dimensiuni
variabile,in functie de durata intreruperii prin sleep.In functie de
procesorul instalat in calculatorul d-voastra,modificati valoarea pentru
sleep (intre 10 si 50) pana cand evidentiati cat mai clar modul de lucru
al tandemului publish-process.
Studiati si restul de proprietati si metode.Eventual,incercati sa
dezvoltati un exemplu,pentru functia getProgress() sau pentru functia
firePropertyChange().Din pachetul SwingUtilities puteti apela functia
isEventDispatchThread().Returneaza true,daca threadul asteapta evenimente.

-78-
O situatie putin deosebita,este in cazul applet-urilor.In mod normal,
este recomandabil ca fiecare applet sa fie lansat in executie cu un thread
separat,destinat sa organizeze toate operatiile din applet.Nu se va lansa
in executie un applet din interiorul unui thread de tip event dispatch,
deoarece se pot crea interferente nedorite.Este de dorit ca fiecare applet
sa reprezinte un modul independent,fara legatura cu restul aplicatiei.Din
acest motiv,nu se vor utiliza functii I/O in interiorul unui applet,decat
pentru operatii ce se excuta local.
EXEMPLU:
import javax.swing.*;
import java.awt.*;

public class Applet1 extends JApplet {


public void init() {
JLabel label = new JLabel("Introduceti textul dorit:");
setLayout(new GridLayout(1,0));
add(label);
add(new JScrollPane(new JTextArea(3,20)));
}
}
-salvati fila cu numele Applet1.java.Compilati fila.
Pentru a utiliza applet-ul editati o fila HTML de genul:
<html>
<title> Applet </title>
<h1> Applet Thread </h1>
<body>
<applet code = "Applet1.class" width = 300 height = 200>
</applet>
</body>
</html>
-salvati fila cu numele AppletThread.htm
sau pentru a obtine un grup de applet-uri:
<html>
<title> Applet </title>
<h1> Serie de Applet-uri </h1>
<body>
<applet code = "Applet1.class" width = 300 height = 200 >
<applet code = "Applet1.class" width = 300 height = 200 >
<applet code = "Applet1.class" width = 300 height = 200 >
</body>
</html>
-salvati fila cu numele AppletSerie.htm
Chiar daca applet-ul contine un obiect de tip TextArea,este recomandabil
sa utilizati datele introduse de user,doar in interiorul applet-ului.Daca
incercati sa transmiteti datele de la un applet la altul,sau de la applet
la fila HTML,rezultatul poate fi imprevizibil (in functie de experienta
d-voastra).
Un exemplu foarte sugestiv pentru modul de utilizare al thread-urilor
il reprezinta aplicatia Task Manager din Windows (executati un click drept
pe ToolBar si alegeti optiunea Task Manager).Eventual,puteti incerca sa
realizati o aplicatie asemanatoare,pentru programele d-voastra din Java.

-79-
APPLET-URI JAVA

Posibilitatea de a crea applet-uri pentru aplicatiile Web reprezinta


unul dintre atu-urile majore ale platformei Java si merita o prezentare
ceva mai detaliata.Applet-urile Java sunt asemanatoare cu scripturile,ce
pot fi editate in JavaScript sau in VBScript,dar prezinta avantajul de a
fi independente de platforma de lucru.Un applet Java poate fi importat
din orice sistem de operare,fara nici o transformare,cu conditia se existe
instatlata o versiune de JRE (Java SE Runtime Enviroment).In mod normal,
un applet trebuie privit ca un modul independent de program,ce poate fi
inclus intr-o fila HTML,la fel ca un petec.Este posibil ca applet-ul sa
faca diverse schimburi de date cu alte module din program,dar acest lucru
nu este de dorit,deoarece se creaza o anumita dependenta fata de o serie
de factori de mediu.Un applet trebuie sa fie independent,atat fata de
sistemul de operare,cat si fata de restul modulelor din program.O posibila
exceptie,o reprezinta applet-urile ce executa diverse operatii asupra
unor date preluate din reteaua Internet.Un applet,trebuie sa fie astfel
conceput,incat sa poata fi importat cat mai usor,in orice fila HTML si in
orice aplicatie Web.Fiecare astfel de applet,va adauga cate o functiona-
litate in plus,prin care va simplifica munca programatorului.De exemplu,
un apllet va putea adauga un fundal sonor,altul va permite o serie de
aplicatii grafice,sau va prezenta un text,o reclama,un antet etc.Fiecare
programator,aduna seturi intregi de asfel de module,pe care le include
apoi in aplicatie,ca intr-un colaj.
Exista o mica diferenta intre applet-uri si aplicatii.Pentru a apli-
catie Java,trebuie sa existe cel putin o clasa,si o metoda main.Pentru un
applet,este necesara cel putin o clasa derivata din clasa de baza Applet,
si cel putin o functie de initializare (init()).Cu alte cuvinte,un applet
este un tip perfectionat de aplicatie independenta,in care nu se poate
utiliza orice fel de clasa,iar metoda main() este inlocuita prin metoda
init().Clasa derivata din Applet,si daca va avea un numar mai mare de me-
tode,executia programului va incepe intotdeauna cu metoda INIT.Clasa App-
let are si alte metode implicite :destroy(),stop(),getImage(),getLocale(),
getCodeBase(),isActive(),play(),showStatus()..etc.Toate aceste metode pot
fi apelate in forma implicita,sau pot fi redefinite in cadrul clasei,
pentru a obtine functionalitati noi.
Pe linga clasa Applet din pachetul java.applet exista si o clasa de
tip Applet special conceputa pentru obiectele de tip Swing.Aceasta clasa
este inclusa in pachetul javax.swing cu numele de JApplet si este derivata
din Applet,dar adauga si o serie de functionalitati noi.Atunci cand utili-
zati o interfata grafica cu obiecte de tip Swing,este bine sa extindeti
clasa JApplet din javax.swing,iar atunci cand applet-ul executa doar
niste operatii simple in background (cum ar fi implementarea calculelor
matematice),este preferabil sa utilizati clasa Applet (mai economica).
In rest,un applet se proiecteaza la fel ca si o aplicatie obisnuita,
cu diferenta ca nu mai este necesar sa includeti obiectele vizuale intr-o
fereastra,ci le puteti declara si construi direct (applet-ul urmeaza sa
fie importat intr-o fereastra gata construita).Exista si situatii in care
metoda init() poate fi inlocuita prin start() sau prin paint().Durata de
"viata" (existenta) a unui applet,este intre executia metodei init() si
executia destructorului stop() sau destroy().

-80-
Pentru ca obiectele vizuale sa fie interective,trebuie sa utilizati
evenimente si functii EventListener,la fel ca si incazul aplicatiilor
simple.Cel mai simplu buton functional se programeaza cam asa:
EXEMPLU:
import java.awt.BorderLayout;
import java.awt.event.*;
import javax.swing.*;
import java.applet.Applet;

public class ApptoAppl extends Applet implements ActionListener {


JLabel text;
JButton button;
Jpanel panel;
private boolean _clickMeMode = true;
public void Init() {
setLayout(new BorderLayout(1,2));
text = new JLabel("Buton functional !");
button = new JButton("Apasa");
button.addActionListener(this);
add("Center",text);
add("South",button);
}
public void actionPerformed(ActionEvent event) {
Object source = event.getSource();
if (_clickMeMode) {
text.setText("Apasa din nou !");
_ClickMeMode = false;
} else {
text.setText("Sunt un buton functional !");
button.settext("Apasa");
_clickMeMode = true;
}
}
}
-salvati fila cu numele ApptoAppl.java si compilati fila.
Pentru executie,editati o fila HTML simpla:
<html>
<title> Applet </title>
<h1> Buton simplu: </h1>
<body>
<applet code = "ApptoAppl.class" width = 300 height = 200>
</applet>
</body>
</html>
Observati ca pentru a asocia un eveniment oarecare cu o functie de
raspuns la eveniment,clasa trebuie sa implementeze un EventListenr.In
exemplul de mai sus,evenimentul este ActionEvent,iar functia este de tip
actionPerformed.Pentru ca obiectul de tip Applet sa fie mai performant
decat obiectul sursa,se pot redefini o parte dintre metodele sale.Pentru
a putea depana un astfel de obiect,cea mai simpla metoda este sa includeti
cate un mesaj oarecare in fiecare metoda redeclarata(cu sau fara valori).

-81-
EXEMPLU:
import java.awt.Graphics;
import javax.swing.*;

public class Simple extends JApplet {


StringBuffer buffer;
public void init(){
buffer = new StringBuffer();
addItem("initializing....");
}
public void start() {
JOptionPane.showConfirmDialog(null,"Start ?");
addItem("starting....");
}
public void stop() {
JOptionPane.showConfirmDialog(null,"Stop ?");
try {
(new Thread()).sleep(1000);
} catch (InterruptedException e) { return;}
}
public void destroy() {
JoptionPane.showConfirmDialog(null,"Destroy ?");
}
private void addItem(String newWord) {
buffer.append(newWord);
repaint();
}
public void paint(Graphics g) {
g.drawRect(0,0,getWidth()-1,getHeight()-1);
g.drawString(buffer.toString(),5,15);
}
}
-salvati fila cu numele Simple.java si compilati fila.
Pentru executie editati o fila html,astfel:
<!DOCTYPE HTML PUBLIC "-//w3C//DTD HTML 4.01 Transitional //RO">
<html>
<head><title>Applet</title></head>
<body>
<h1> Applet simplu </h1>
<br>
Link spre pagina <a href="ApptoAppl.htm"> ApptoAppl </a>
<applet code="Simple.class" height="200" width="300">
</applet>
</body>
</html>
-salvati fila cu numele Simple.htm si executati fila.
Metodele start(),stop() si destroy(),au fost astfel redefinite incat
sa afiseze un mesaj in momentul in care incepe executia metodei.Fila
html contine si un link spre fila HTML precedenta,pentru a putea pune in
evidenta metoda stop().Astfel de mesaje,se pot utiliza pentru a returna
valori partiale ale unor operatii,in cadrul procesului de depanare.

-82-
Executati exemplul si observati fiecare dintre metode.Metoda stop(),
apeleaza automat metoda destroy,astfel incat,desi are o intarziere de
o secunda,mesajul de avertizare nu poate fi vizualizat (desi apare),
deoarece se executa imediat metoda destroy().
In principiu,metoda init() contine codurile pe care in mod normal le
contine constructorul clasei.Se pot include in aceasta metoda si alte
operatii,dar este de dorit sa fie cat mai scurte si sa nu intarzie exe-
cutia aplicatiei.Pentru operatiile laborioase,este bine sa rezervati un
thread separat,ce se va executa in background-ul aplicatiei,fara sa afec-
teze etapa de constructie a obiectului.Metoda init(),apeleaza automat
metoda start().
In metoda start(),se includ operatiile principale ale applet-ului.
Daca exista seturi de operatii ce urmeaza sa fie executate in paralel,
atunci din metoda start() se vor lansa in executie mai multe thread-uri,
fiecare dintre ele cu setul sau de operatii: in background,sau vizuale.
Cand redefiniti metoda start(),este bine sa redefiniti si metoda stop().
In mod normal,metoda stop() se utilizeaza,fie pentru a intrerupe temporar
un set oarecare de operatii (un fel de pauza),fie pentru a defini des-
tructorul,inainte de a parasi applet-ul.Metoda stop(),se apeleaza atunci
cand executia paraseste applet-ul,de exemplu atunci cand se apeleaza un
link spre o alta fila.In momentul in care se revine la fila initiala,
appletul va fi reconstruit automat prin apelul functiei init().In exemplul
de mai sus,navigati de cateva ori intre cele doua file si observati
modul automat in care sunt apelate metodele applet-ului.
Metoda destroy() este destructorul applet-ului.In mod normal,nu este
bine sa redefiniti aceasta metoda.Se poate utiliza atunci cand doriti ca
destroy() sa elibereze din memorie si alte structuri de date,decat cele
eliberate implicit (adica sa fie destructor si pentru alte obiecte).
Clasa Applet,mosteneste o serie intreaga de facilitati de la superclasa
sa Container.Asfel sunt: metoda paint() sau processKeyEvent si process-
MouseEvent...etc.
Un applet se poate edita si cu ajutorul unei platforme vizuale.Daca
utilizati NetBeans,deschideti un proiect oarecare si apoi creati o fila
noua de tip JApplet,fie cu File->New File fie cu un click drept pe numele
proiectului,apoi alegeti New si JApplet.NetBeans va crea automat capul
de fila cu declaratia clasei si metoda init().Platforma vizuala prezinta
si o serie intreaga de avantaje.De exemplu,puteti compila si previzualiza
applet-ul fara sa fie necesara o fila HTML sau un browser.Pur si simplu,
executati un click drept pe numele filei (in Projects) si alegeti optiunea
Debug.Fila de tip applet se poate salva in interiorul proiectului,sau la
orice alta adresa.Compilarea filei nu genereaza automat fila .class,ci
doar verifica daca nu exista erori de sintaxa.Pentru a obtine fila de tip
.class,trebuie sa compilati fila prin procedeul obisnuit.Daca insa con-
struiti intregul proiect,fila .class pentru applet-ul respectiv va fi
creata automat in directorul build/classes din proiectul final.
Platforma vizuala este foarte practica atunci cand creati doua sau mai
multe applet-uri,sau atunci cand transformati un applet mai vechi,prin
adaugarea de noi functionalitati.In plus,daca utilizati optiunea Debug,
puteti apasa meniul Applet pentru a reseta unele dintre proprietati:
Http proxy server,Httpproxy port,Class access etc.In rest,toate etapele
de editare sunt identice,ca pentru editarea cu NotePad.

-83-
Pentru ca applet-ul sa raspunda la evenimente,la fel ca orice interfata
grafica,se va adauga un eventListener si functia sau functiile necesare
pentru tratarea evenimentului respectiv.De exemplu,pentru a exploata eve-
nimentele indicatorului mouse,se va adauga un MouseListener.
EXEMPLU:
import javax.swing.*;
import java.awt.*;
import.java.awt.event.MouseListener;
import java.awt.event.MouseEvent;

public class Eveniment1 extends JApplet implements MouseListener {


public void init() {
addMouseListener(this);
JLabel label = new JLabel("Start:");
setLayout(new GridLayout(1,0));
add(label);
}
public void mouseEntered(MouseEvent event) { }
public void mouseExited(MouseEvent event) {
JLabel label = new JLabel("Out !");
add(label);
repaint();
}
public void mousePressed(MouseEvent event){}
public void mouseReleased(MouseEvent event){}
public void mouseClicked(mouseEvent event) {
JLabel label2 = new JLabel("Click !");
add(label2);
repaint();
}
}
-salvati fila cu numele Eveniment1.java si compilati.
Includeti applet-ul intr-o fila HTML si executati cate un click de
mouse in exteriorul applet-ului,apoi in interior.Observati rezultatul.
Chiar daca nu se utilizeaza toate evenimentele mouse,acestea trebuie sa
fie redefinite(cu o functie nula).
Este recomandabil ca functiile pentru tratarea evenimentului sa con-
tina operatii cat mai simple,clare si discriminative,pentru a fi cat mai
usor de exploatat.
Se pot face diverse combinatii intre evenimentele si metodele din
applet si cele din documentul HTML,cu ajutorul unor script-uri.Aceste
combinatii insa nu sunt recomandabile,deoarece nu pot fi utile decat
pentru o singura fila HTML,cu un anumit context.In general,applet-urile
se vor concepe astfel incat sa fie editate o singura data si apoi sa poata
fi utilizate in orice fila HTML,ori de cate ori este nevoie (uneori de
mai multe ori in aceeasi fila).Cu alte cuvinte,applet-ul trebuie sa fie
independent de fila in care urmeaza sa fie importat.Este posibil insa ca
applet-ul sa fie conectat permanent la un set oarecare de file sursa,din
care extrage date,sau functionalitati.De exemplu,un aplet poate sa exploa-
teze un set oarecare de imagini grafice,un set oarecare de file audio,
un set de file tip text,etc.
-84-
In acest caz,este recomandabil ca filele sursa sa fie impachetate in
acelasi director cu applet-ul in care sunt exploatate.
EXEMPLU:
import javax.swing.*;
import java.awt.*;
import java.net.URL;
import java.awt.Graphics;

public class Imagine extends JApplet {


static String sir1 = "Turcoaze.jpg";
public void paint(Graphics g) {
Image poza = getImage(getURL(sir1));
g.drawImage(poza,20,20,400,400,this);
}
protected URL getURL(String filename) {
URL codeBase = this.getCodeBase();
URL url = null;
try {
url = new URL(codeBase,filename);
} catch (java.net.MalformedURLException e) {
return null; }
return url;
}
}
-salvati fila cu numele Imagine.java si compilati.
Includeti fila intr-o fila HTML,in care applet-ul trebuie sa fie astfel
dimensionat incat sa poata cuprinde imaginea importata.
EXEMPLU:
<applet code = "Imagine.class" width=800 height=500></applet>
In exemplul de mai sus,se pot exploata file de tip GIF,JPEG sau PNG,
arhivate local (in acelasi director cu applet-ul).Pentru acest scop,metoda
getURL,transforma adresa locala intr-o adresa de tip URL.Daca lucrati cu
file din reteaua Internet,se poate utiliza direct metoda getImage,impreuna
cu adresa URL.
Fiecare dintre cele doua situatii,prezinta avantaje si dezavanataje.
Filele din retea pot fi apelate de la orice adresa din retea,in orice
moment sau de catre mai multi utilizatori simultan.In schimb,durata pentru
download depinde de calitatea si viteza de lucru a conexiunii.In plus,
este posibil ca proprietarul site-ului sa stearga fila fara preaviz,sau
sa schimbe adresa site-ului etc.,caz in care referinta va ramane fara o
adresa valabila.Filele arhivate local,se executa mult mai rapid si mai
sigur,nu depind de nici un factor extern aplicatiei,pot fi gestionate mult
mai usor.In schimb,daca doriti sa oferiti pachetul de date unui numar mai
mare de utilizatori,este mai nepractic sa exportati intregul pachet de
date.In acest caz,este preferabil sa postati filele sursa intr-un server
si apoi sa exportati doar applet-ul,via e-mail.
In ambele situatii,applet-ul prezinta urmatorul avantaj: utilizatorul
va avea o fila html fixa,in care nu se va modifica decat pachetul de file
sursa.Astfel,datele pot fi actualizate zilinic,la fel ca intr-un ziar
electronic,fara ca utilizatorul sa faca nici o singura oparatie.Este sufi-
cient ca server-ul sa modifice pachetul de file sursa(sau applet-ul).
-85-
Obiectul de tip Image este insa destul de simplu si rudimentar.Atunci
cand doriti sa aflati informatii despre imaginea preluata,sau doriti sa
puteti efectua operatii asupra imaginii,este preferabil sa utilizati un
obiect de tip BufferedImage.BuferedImage este derivat din Image,dar adauga
un set foarte bogat de metode utile (copydata(),getData(),getProperty(),
getRaster(),getRGB(),getSource(),getSubimage(),getTile()...etc.).Si acest
obiect se apeleaza asemanator:
EXEMPLU:
import java.applet.*;
import java.awt.*;
import java.awt.image.*;
import java.io.*;
import java.net.URL;
import javax.imageio.*;

public class Imagine1 extends Applet {


private BufferedImage img;
public void init() {
try {
URL url = new URL(getCodeBase(),"strawberry.jpg");
img = ImageIO.read(url);
} catch (IOException e) {}
}
public void paint(Graphics g) {
g.drawImage(img,50,50,null);
}
}
-salvati fila cu numele Imagine1.java si compilati.Apoi incarcati
applet-ul intr-o fila HTML,in acelasi director cu "strawberry.jpg".
In afara imaginilor preluate de la o adresa fixa,sau din retea,applet-
urile se pot utiliza si pentru a crea grafice,sau desene animate in timpul
executie.Pentru acest scop se va utiliza clasa Graphics si metodele sale.
Nu mai este necesar sa creati un context pentru dispozitivul grafic,sau
sa creati o fereastra noua,deoarece applet-ul va utiliza fereastra in care
este deschisa fila HTML.Nu este nexesar nici sa utilizati un obiect de tip
Canvas,Panel sau Paint etc.Pur si simplu,se pot apela direct metodele
obiectului Graphics creat automat la declararea metodei paint(Graphics g).
Obiectul Graphics asigura toate informatiile necesare si atunci cand
doriti sa faceti proiectii ale imaginii respective (rendering).Pentru a
putea face proiectii,vor fi necesare urmatoarele informatii:
-obiectul sau componentul pe care se deseneaza
-punctul de pornire pentru proiectie
-culoarea curenta
-fontul curent
-fragmentul decupat pentru proiectie
-starea actuala pentru operatia XOR sau Paint
-culoarea alternativa pentru operatia XOR
Operatia de proiectie nu va interesa decat pixelii inclusi in aria
decupata pentru proiectie.Operatiile de proiectie sunt utile mai ales
pentru a realiza efecte de animatie.Nu sunt recomandabile pentru incepa-
tori,deoarece depanarea aplicatiei poate fi destul de dificila.

-86-
Cele mai simple operatii sunt cele prin care se deseneaza un cerc sau
un patrat,o linie sau un arc.La acestea se adauga operatiile de setare a
fonturilor si culorilor si cele pentru decuparea si copierea unui fragment
oarecare din imagine.
EXEMPLU:
import javax.swing.*;
import java.awt.*;

public class Imagine2 extends JApplet {


public void paint(Graphics g) {
g.drawString("Grafic:", 10, 15);
g.drawLine(10,40,10,200);
g.drawLine(10,200,210,200);
g.setColor(Color.red);
g.drawLine(10,200,100,50);
g.drawLine(100,50,130,80);import javax.swing.*;
g.drawLine(130,80,200,40);
g.setColor(Color.blue);
g.drawOval(300,100,50,50);
g.drawOval(400,100,50,50);
g.setColor(Color.green);
g.fillOval(322,122,20,20);
g.fillOval(412,122,20,20);
g.setColor(Color.magenta);
g.fillArc(350,125,40,100,0,360);
g.fillArc(320,250,100,20,0,180);
}
}
-salvati fila cu numele Imagine2.java si compilati.Verificati applet-ul.

Pentru a afisa un text personalizat,trebuie sa setati culorile si fontul.


EXEMPLU:

import javax.swing.*;
import java.awt.*;
import java.text.*;
import java.awt.font.TextAttribute;

public class Imagine3 extends JApplet {


public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
Font font = new Font("Arial", Font.BOLD, 48);
g2.setFont(font);
g2.setColor(new Color(250,20,100));
g2.drawString("Text personalizat !", 40, 80);
}
}
-salvati fila cu numele Imagine3.java si compilati.
Includeti applet-ul intr-o fila HTML si verificati cu browser-ul implicit.
Eventual,incercati sa utilizati mai multe fonturi,cu stiluri diferite.

-87-
Un efect special foarte usor de realizat se poate obtine cu ajutorul
clasei GradientPaint,din pachetul java.awt.GradientPaint.Se poate utiliza
pentru a umple orice poligon (inclusiv caracterele grafice) cu o culoare
ce se modifica in gradient pe o suprafata delimitata din cea grafica.
Obiectul are patru variante de constructori si se poate apela direct.
EXEMPLU:
import javax.swing.*;
import java.awt.*;
import java.text.*;
import java.awt.font.TextAttribute;

public class Imagine4 extends JApplet {


public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
Font font = new Font("Arial",Font.BOLD,48);
g2.setFont(font);
g2.setPaint(new GradientPaint(
0,0,Color.yellow,400,400,Color.red,false));
g2.drawString("Text personalizat !",40,80);
}
}
-salvati fila cu numele Imagine4.java si compilati.
Pentru a putea adauga un sunet,sau o melodie,se poate utiliza interfata
AudioClip din pachetul java.applet.
EXEMPLU:
import java.awt.BorderLayout;
import java.applet.*;
import javax.swing.*;
import java.awt.event.*;
import java.net.URL;

public class Sunet1 extends JApplet implements ActionListener {


Applet applet;
private AudioClip onceClip;
String sir1 = "bark.au";
JButton buton1;
public void init() {
setLayout(new BorderLayout(1,2));
buton1 = new JButton("SUNET");
buton1.addActionListener(this);
add(buton1);
try{
URL url = new URL(getCodeBase(),sir1);
onceClip = newAudioClip(url);
} catch (java.net.MalformedURLException e) {}
public void actionPerformed(ActionEvent event) {
onceClip.play();
}
}
-salvati fila cu numele Sunet1.java si compilati.Includeti applet-ul
intr-o fila HTML,in acelasi director cu fila sursa "bark.au".

-88-
Interfata grafica din Swing are o functionalitate destul de limitata.
Fiecare interfata de tip AudioClip,va putea reda la un anumit moment dat,
un singur sunet,preluat dintr-o fila sursa de tip Sun,cu extensia .au,in
care sunetele sunt codificate in format de 8 biti,pe un singur canal cu
o frecventa de 8000 Hz.Puteti crea aceste file,sau puteti converti orice
fel de file audio,cu ajutorul unui program specializat de conversie.Un
program de conversie foarte bun si gratuit,este de exemplu: Switch Sound
File Converter oferit de firma NCH Software (vezi adresa www.nch.com).
Aplicatiile pentru redarea sunetelor pot fi si extrem de complexe.Se
pot crea mai multe benzi de sunet,ce pot fi executate simultan,pot fi
mixate sau filtrate dupa un anumit algoritm etc.Pentru simplificarea
acestor operatii,exista si alte obiecte java specialiate,dar prezentarea
acestor obiecte va face obiectul unui alt capitol.Pentru applet-uri este
suficient sa puteti include una sau mai multe file de sunet,ce pot fi apoi
executate simultan sau serial.Nici nu este indicat sa creati o aplicatie
de tip media-player intr-un applet,deoarece o astfel de aplicatie ocupa
un volum mare de memorie,cu multe thread-uri si niveluri de intrerupere,
ce pot dreanja sau interfera cu operatiile de navigare de la o fila la
alta (fiecare incarcare va fi mult prelungita si exista riscul de a
epuiza memoria de operare,doar pentru aplicatia audio).
Din acelasi motiv,nu este recomandabil nici sa creati o baza prea
larga de file sursa,conectata la applet.Daca doriti sa existe totusi o
gama oarecare de optiuni,adaugati un folder cu file sursa si un obiect de
tip ComboBox,sau FileChooser in care se va selecta fila dorita.Cu cat
applet-ul va fi mai complex,cu atat va ocupa mai mult din memoria de ope-
rare rezervata pentru fila HTML gazda.Cu cat applet-urile sunt mai mici,
cu atat fila gazda va putea incarca si executa simultan mai multe astfel
de applet-uri.Din acest motiv,decat sa faceti o singura fila complexa,cu
foarte multe functionalitati,este mai bine sa realizati seturi intregi
de applet-uri simple,pe care sa le puteti apoi combina in configuratia
dorita.Este bine sa va construiti o mica arhiva de astfel de applet-uri.
Exista si unele situatii,in care doriti sa utilizati o fila locala de
tip text,ca sursa de date pentru applet.Fie doriti sa afisati un simplu
text,fie doriti sa preluati un set oarecare de valori numerice ce urmeaza
sa fie apoi procesate intr-un algoritm oarecare.In retea,applet-urile nu
au acces la filele locale,nici pentru server,nici pentru client.Aceasta
masura de securitate are rolul de a proteja fisierele importante ale
sistemului de operare de asa numitele "atacuri ale hack-erilor" din retea.
Cu alte cuvinte,face parte din politica de tip "antivirus".Restrictia de
acces nu se aplica si in cazul filelor locale.Cu alte cuvinte,nu puteti
edita un applet care sa citeasca filele de tip text din alt calculator,
dar puteti sa editati applet-uri care preiau date din filele de tip text
arhivate in propriul calculator.Tehnologia de lucru este la fel ca pentru
orice operatie de tip I/O.Se utilizeaza un stream pentru citirea datelor,
si o bucla de tip try...catch pentru interceptarea si tratarea exceptiilor
de tip I/O.In mod normal,este mai bine sa evitati acest gen de solutie,
cu exceptia cazurilor in care applet-ul este doar o extensie a unui pro-
gram mai vechi,creat prin acest mecanism.Este recomandabil sa utilizati
file sursa fixe,dar se poate utiliza si un obiect de tip FileDialog sau
JFileChooser,pentru a putea naviga prin arhiva locala.Este bine sa evitati
interfetele prea incarcate,cu prea multe evenimente si operatii.

-89-
EXEMPLU:
import java.applet.*;
import java.awt.*;
import java.io.*;
import java.net.*;

public class CitesteText extends Applet {


String fileToRead = "text.txt";
StringBuffer strBuff;
TextArea txtArea;
public void init() {
txtArea = new TextArea(100,100);
txtArea.setEditable(false);
add(txtArea,"center");
String prHtml = this.getParameter("fileToRead");
if (prHtml != null) fileToRead = new String(prHtml);
readFile();
}
public void readFile() {
String line;
URL url = null;
try {
url = new URL(getCodeBase(),fileToRead);
} catch (MalformedURLException e) {}
try {
InputStream in = url.openStream();
BufferedReader bf = new BufferedReader(new InputStreamReader(in));
strBuff = new StringBuffer();
while((line = bf.readLine()) != null) {
strBuff.append(line + "\n");
}
txtArea.append("Numele filei : " + fileToRead + "\n");
txtArea.append(strBuff.toString());
} catch (IOException e) {}
}
}
-salvati fila cu numele CitesteText.java si compilati.Includeti applet-ul
intr-o fila HTML,in acelasi director cu fila "text.text" din care doriti
sa preluati datele.
Acest gen de solutie se poate utiliza eventual si atunci cand doriti
sa includeti in fila HTML un mesaj ce urmeaza sa fie actualizat periodic.
In acest caz,in loc sa inlocuiti intregul applet,va fi suficient sa
actualizati continutul filei de tip text (de obieci cu un alt program mai
vechi,editat in C++ sau Visual Basic...etc.).Cu alte cuvinte,nu prea are
rost sa proiectati astfel de aplicatii noi,dar puteti utiliza aceasta
facilitate pentru a exploata programe mai vechi.Un exemplu tipic,este
in cazul in care un program oarecare preia periodic date din retea si
le arhiveaza intr-o fila locala de tip text.Pentru a verifica periodic
datele extrase automat,puteti utiliza si acest gen de solutie (desi
exista solutii mai elegante pentru prelucrarea datelor de tip text).
ATENTIE: applet-urile nu pot rescrie filele de tip sistem din retea !

-90-
Un applet poate fi utilizat si pentru a crea un modul de lucru intr-o
baza de date,dar aceasta functionalitate va fi prezentata intr-un capitol
separat.Trebui mentionat si faptul ca Applet si JApplet sunt doua clase
absolut obisnuite.Nu este obligatoriu sa fie incluse doar in aplicatii de
tip applet,ci se pot utiliza in aplicatiile obisnuite,la fel ca orice
clasa.Daca se utilizeaza insa intr-o aplicatie obisnuita,interfata grafica
trebui sa fie inclusa intr-o fereastra (Form).
In tutorialul firmei Sun se specifica si urmatoarele recomandari gene-
rale,inainte de a pune in circulatie un applet:
1.Inactivati toate rutinele de depanare.De exemplu,toate comenzile de gen
System.out.println("mesajul dorit") incluse in buclele try-catch.Aceste
comenzi sunt foarte utile in etapa de editare sau depanare a programu-
lui,dar nu au nici un rost in timpul executiei normale.Daca preluati
exemple gata facute,este bine sa inactivati aceste comenzi.In plus,
este bine sa verificati daca nu exista si alte date care incarca inutil
memoria de operare (variabile neutilizate,constante inutile,obiecte
inactive,link-uri nefunctionale etc.)
2.Verificati daca applet-ul este inactiv atunci cand fila HTML gazda este
nefunctionala.Cu alte cuvinte,atunci cand applet-ul lanseaza in executie
unul sau mai multe thread-uri,trebuie sa va asigurati ca fiecare thread
contine si o metoda stop() pentru intreruperea executiei.In caz contrar,
exista riscul ca thread-ul respectiv sa ramana functional in background
si sa consume inutil din resursele procesorului.
3.Atunci cand applet-ul executa o operatie oarecare iterativa: animatie,
un sunet repetat,un spot publicitar sau o reclama...etc,trebuie sa va
asigurati ca utilizatorul are posibilitatea de a intrerupe in orice
moment functionalitatea respectiva (pentru a nu deveni agasanta).
La fel ca si fielele de tip Web,applet-urile sunt niste module de pro-
gram destinate sa execute operatii,fie local,fie intr-o retea oarecare de
calculatoare.In cazul aplicatiilor locale,nu exista restrictii speciale,
diferite de cele impuse de standardul de limbaj.Insa,in cazul in care un
applet este introdus in retea,exista si o serie de restricti impuse de
masurile de securitate ale retelei respective.Politica si masurile de se-
curitate pot fi usor diferite de la o retea la alta,dar in principu se vor
aplica urmatoarele restrictii:
-un applet nu poate adauga in sistem biblioteci noi de functii ( le
poate utiliza doar pe cele existente) si nici nu poate adauga metode noi
apelabile din programele externe (metodele sunt valabile doar in applet).
-in mod normal,un applet nu poate citi sau scrie filele native ale
unitatii gazda (maxim poate exploata un set de file atasate applet-ului).
-un applet nu poate face conexiuni in retea,decat cu unitatea sursa
(cea in care este gazduit applet-ul din retea).
-un applet nu poate pune in executie programele unitatii gazda
-un applet nu poate citi proprietatile sistemului de operare (setari,
constante,coduri,parole de acces,optiuni preferentiale...etc.).
-daca applet-ul deschide o fereastra noua,aceasta va avea un aspect
diferit de cel al ferestrelor din unitatea gazda,pentru a se putea
face o distinctie cat mai clara intre sistemul de operare si modul.
La aceste masuri generale,se adauga si cele specifice pentru fiecare
browser utilizat si cele ale programelor de tip anti-virus instalate in
calculatorul gazda.

-91-
Aceste restrictii nu sunt aplicabile si pentru administratorii de retea.
Daca aveti o problema ce nu poate fi rezolvata decat ignorand una dintre
restrictii,este recomandabil sa luati legatura cu administratorul de
retea.Mai ales in cazul reteleor locale,se pot gasi solutii fiabile,pentru
orice astfel de problema.
In principiu,in cadrul unei retele de calculatoare exista doua tipuri
de aplicatii.Aplicatii de tip server,destinate unitatilor ce asigura
serviciile de comunicatie din retea si aplicatii de tip client,adica
cele destinate pentru utilizatori.Pentru informatii suplimentare despre
aplicatiile de tip net-work,va trebui insa sa consultati alte surse de
informatie.
JAVA LOOK AND FEEL
Arhitectura Swing din Java,permite ca interfata grafica sa-si schimbe
interactiv aspectul grafic.Prin "LOOK" se intelege in termeni generali
modul de prezentare a componentelor vizuale iar prin "FEEL" se va intelege
modul de reactie la evenimente.Pentru acest scop,java separa fiecare
component in doua subclase.Una dintre subclase va contine obiectul de tip
JComponent(respectiv descendentul sau) iar cea de a doua subclasa va
contine un obiect de tip ComponentUI.Cea de a doua subclasa,este prezenta
in literatura de specialitate si cu denumirile: UI,UI component,UI dele-
gate,look and feel delegate etc.In mod normal,programatorul nu are nici o
interactiune directa cu aceasta subclasa.Ea exsita doar pentru a permite
ca obiectul sa poata avea forme diferite de prezentare.Toate operatiile se
executa automat,in momentul compilarii.
Cu ajutorul acestui mecanism,este posibil ca interfata grafica creata
de d-voastra sa-si schimbe aspectul cameleonic,in functie de sistemul de
operare pe care ruleaza aplicatia,sau la o comanda oarecare data de un
buton.Exista cateva aspecte standard implicite,sau puteti sa creati un
sablon oarecare pe care sa-l aplicati apoi la doua sau mai multe interfete
grafice.Daca sunteti un programator profesionist,puteti sa utilizati
acelasi sablon,pentru toate programele create de d-voastra,pentru a va
crea un "stil propriu".Mai mult decat atat.Java poate imprumuta stilul de
prezentare instalat in momentul respectiv in calculatorul userului.De
exemplu,daca aplicatia d-voastra este o extensie a sistemului de operare
si doriti sa utilizatorul sa vada obiectele cu acelasi aspect ca si cele
din sistemul sau de operare,puteti alege aceasta optiune automata.
Resursele pentru "Look and Feel" sunt situate in doua pachete diferite.
In pachetul implicit javax.swing.plaf.metal se gasesc resursele necesare
pentru aspectul implicit al obiectelor Java,pentru cele care imprumuta
aspectul de la sistemul de operare si pentru cele definite explicit de
catre utilizator.Aceste aspecte implicite sunt:
1.-CrossPlatformLookAndFeel -este denumit si "Metal" si contine setarile
implicite.Acesta este aspectul utilizat,daca nu formulati nici o alta
cerere specifica.Acest aspect va fi utilizat implicit,indiferent de
sistemul de operare pe care va rula aplicatia Java.Cu alte cuvinte,o
aplicatie Java obisnuita va avea acelasi aspect grafic,atat sub Windows,
cat si sub Linux sau Solaris.
2.-SystemLookAndFeel -este setul de resurse prin care se imprumuta de
la sistemul de operare,modul de prezentare grafica.Valorile sunt preluate
in timpul executie,astfel incat interfata grafica va respecta setarile
actuale ale sistemului de operare.

-92-
3.-Synth -contine resursele necesare prin care aspectul grafic poate fi
importat dintr-o fila de tip XML (locala sau din retea).Cu o singura
astfel de fila,se poate asigura aspectul grafic pentru un set intreg de
aplicatii create de aceeasi firma.
4.-Multiplexing -contine resursele pentru ca intefata sa poata sa-si
modifice aspectul interactiv,in timpul executiei.Pentru acest scop,cea
de a doua subclasa functionaza ca un tampon de memorie in care se retine
definitia initial.Subclasa poate fi rescrisa ori de cate ori,astfel ca
intefata se poate modifica cameleonic,chiar si in timpul executiei.
Pe langa aceste variante implicite,firma Sun ofera si alte seturi de
resurse,dar acestea sunt arhivate in directorul "com/sun/java/swing/plaf"
Acest pachet este arhivat in directorul "src" in paralel cu pachetul
java obisnuit.Pentru a se face distinctie intre cele doua pachete "java",
trebuie sa utilizati calea completa de acces,ori de cate ori apelati
aceste resurse (adica trebuie sa includeti si "com/sun/java....").
Acest pachet auxiliar contine seturile GTK,Motif si Windows.Primele doua
sunt destinate pentru sistemele de operare Linux si UNIX iar ultimul
pentru Windows.
Pentru a seta apectul grafic se va utiliza un obiect derivat din clasa
UIManager si metoda setLookAndFeel().
EXEMPLU: -pentru ca interfata sa primeasca apectul de tip Windows:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.plaf.metal.*;

public class ButonSpecial1 {


public static void main(String[] args){
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame frame = new JFrame("FrameDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton button = new JButton("Butonul meu");
frame.add(button);
try {
UIManager.setLookAndFeel(
"com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch (ClassNotFoundException e) {
} catch (UnsupportedLookAndFeelException e) {
} catch (Exception e) {}
frame.pack();
frame.setVisible(true);
}
}
-salvati fila cu numele ButonSpecial1.java si compilati.
Exemplul contine un singur buton nefunctional,dar daca adaugati si alte
obiecte in interfata,acestea vor avea tot aspectul Windows de prezentare
(XP sau Vista).
Observati ca pentru metoda setLookAndFeel() trebuie sa puteti sa
preluati toate cele patru tipuri de execeptii posibile.Pentru acest scop,
trebuie sa adugati cate o bucla catch (){},chiar daca bucla va fi complet
inactiva (capteaza exceptia dar fara sa "trateze" eroarea ).

-93-
Pachetul de resurse implicit,permite schimbarea culorilor prin mai
multe mecanisme.In primul rand,exista trei seturi implicite denumite
"themes"(teme).Aceste seturi sunt: DefaultMetal,Ocean si Test si se pot
inlocui reciproc cu o singura comanda simpla:
EXEMPLU: MetalLookAndfeel.seturrentTheme(new OceanTheme());
Daca doriti sa utilizati un set de culori personalizate,trebuie sa
definiti o clasa in care sa specificati aceste seturi,sau sa asociati o
fila de tip XML in care sunt specificate toate setarile grafice.
EXEMPLU:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.plaf.metal.*;

public class ButonSpecial {


public static void main(String[] args){
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame frame = new JFrame("FrameDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton button = new JButton("Butonul meu");
frame.add(button);
try {
UIManager.setLookAndFeel(
"javax.swing.plaf.metal.metalLookAndFeel");
MetalLookAndFeel.setCurrentTheme(new CulorileMele());
} catch (ClassNotFoundException e) {
} catch (UnsupportedLookAndFeelException e) {
} catch (Exception e) {}
frame.pack();
frame.setVisible(true);
}
}
-salvati fila cu numele ButonSpecial.java si compilati.Apoi editati fila:
import javax.swing.plaf.*;
import javax.swing.plaf.metal.*;
import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
public class CulorileMele extends DefaultMetalTheme {
public String getName() { return "Mircea"; }
private final ColorUIResource primary1=new ColorUIResource(155,255,10);
private final ColorUIResource primary2=new ColorUIResource(255,155,105);
private final ColorUIResource primary3=new ColorUIResource(15,50,255);
protected ColorUIResource getPrimary1() { return primary1; }
protected ColorUIResource getPrimary2() ( return primary2; }
protected ColorUIResource getPrimary3() ( return primary3; }
}
-salvati fila cu numele CulorileMele.java si compilati fila in acelasi
director cu fila ButonSpecial.class.
In mod similar,se poate transforma oricare dintre cele trei teme stan-
dard,pentru a obtine un aspect "crossplatform" personalizat.
-94-
Pentru a prelua aspectul grafic dintr-o fila XML,se va utiliza metoda
lookAndFeel.load(URL).
EXEMPLU:
import java.awt.Component;
import javax.swing.*;
import javax.swing.plaf.synth.*;

public class FeelXML extends JFrame {


public FeelXML() {
JLabel label = new Jlabel("Vezi fila Sursa1.xml");
add(label);
pack();
setDefaultCloseOperation(WindowConstants.EXIT_ONCLOSE);
}
private static void initLookAnfFeel() {
SynthLookAndFeel lookAndFeel = new SynthLookAndFeel();
try {
lookAndFeel.load(
FeelXML.class.getResourceAsStream(
"Sursa1.xml"),FeelXML.class);
UIManager.setLookAndFeel(lookAndFeel);
}
catch (Exception e) {}
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
try {
initLookAndFeel();
JFrame.setDefaultLookAndFeelDecorated(true);
} catch (Exception ex) {}
new FeelXML().setVisible(true);
}});
}}
-salvati fila cu numele FeelXML.java si compilati
Apoi editati fila "Sursa1.xml" astfel:
<synth>
<style id = "backingStyle">
<opaque value="TRUE"/>
<state>
<font name ="Verdana" size="30"/>
<color value="YELLOW" type="BACKGROUND"/>
<color value="RED" type="FOREGROUND"/>
</state>
</style>
<bind style="backingStyle" type="region" key".*"/>
</synth>
Salvati fila .xml in acelasi director cu fila FeelXML.class si verifi-
cati exemplul.Pentru a schimba aspectul interfetei este suficient sa
inlocuiti fila .xml.O singura fila XML poate deservii mai multe aplicatii.
Eventual,editati cateva seturi personalizate de astfel de file .xml.
-95-
DESIGN-UL INTERFETEI GRAFICE (LAYOUT MANAGERS)

Interfata grafica este un modul complex,realizat cu ajutorul unui


grup oarecare de obiecte vizuale.Asezarea fiecarui component,spatierea,
sublinierea sau incardarea unor obiecte,alegerea culorilor si a fontu-
rilor,seletarea evenimentelor..etc,fac parte din procesul denumit design.
In cazul editoarelor vizuale,cum este de exemplu platforma NetBeans,exista
un modul special pentru operatiile de design.Platforma va adauga automat
toate obiectele si interfetele necesare,va seta automat toate proprieta-
tile si va crea automat toate link-urile necesare.Programatorul nu trebuie
decat sa evalueze si apoi sa previzualizeze rezultatul final.Este recom-
mandabil sa utilizati o astfel de solutie,pentru orice program sau apli-
catie moderna.Totusi,trebuie sa cunoasteti si sa intelegeti operatiile
pe care platforma le executa automat.In caz contrar,nu ve-ti putea inte-
lege si depana sau moderniza programele rezultate.Din acest motiv,este
recomandabil sa faceti cat mai multe exercitii de programare "manuala" a
elementelor de design,pana cand va miscati cu usurinta prin orice program,
inclusiv cele generate cu NetBeans.Aceasta etapa,este esentiala pentru
a putea separa programele in module,pentru a putea personaliza doar unul
dintre module etc.In majoritatea cazurilor,programele moderne nu se mai
creaza de la zero.Programatorii detin seturi intregi de module indepen-
dente,sau fragmenteaza programele in astfel de module si apoi grupeaza un
set oarecare de module pentru a obtine functionalitatea dorita.De multe
ori,modulele provin din platforme diferite si necesita unele mici trans-
formari.Pentru a putea executa aceste operatii,este esential sa intelegeti
si modul in care Java organizeaza design-ul interfetei grafice.
Spre deosebire de alte platforme software,Java introduce si notiunea
de "manager pentru design" (Layout Manager).In alte programe,interfata
grafica era controlata cu ajutorul unui tampon de memorie simplu ( o arie
de variabile) sau cu ajutorul unui tabel preformatat (tabela de pointeri).
Java utilizeaza un set intreg de obiecte si interfete special concepute,
fiecare dintre acestea oferind un anumit tip de avantaje.In functie de
scopul propus,urmeaza sa alegeti unul sau altul dintre managerii aflati
la dispozitie.Este posibil si sa organizati designul intefetei grafice
fara nici un astfel de manager (pozitionare absoluta a obiectelor),dar
in acest caz,trebuie sa specificati faptul ca obiectul container nu
contine nici nu manager:
EXEMPLU: frame.setLayout(null) //fereastra nu utilizeza LayoutManager
Tipurile standard de "design manager" sunt: BorderLayout,BoxLayout,
CardLayout,FlowLayout,GridBagLayout,GridLayout,GroupLayout,SpringLayout.
Fiecare astfel de manager este de fapt o clasa de obiecte cu constructor,
proprietati si metode.Cu alte cuvinte,se utilizeaza un obiect,pentru a
gestiona pozitionarea celorlalte obiecte din interfata.Obiectele de tip
manager,nu sunt obiecte vizuale si nici nu interactioneaza direct cu
obiectele vizuale,nici nu sunt destinate pentru a executa operatii de
orice fel.Totusi,daca doriti sa personalizati aceste obiecte,se pot crea
clase noi prin extinderea claselor standard.In acest caz,obiectul de tip
manager,va putea castiga functionalitati complexe: mesaje de avertizare,
rutine pentru autodepanare,filtre pentru operatiile I/O,rutine pentru
conversia sau reconversia datelor,conexiuni si link-uri spre alte adrese
sau file sursa,parole de acces...etc.

-96-
Din acest motiv,am preferat termenul de "manageri de design",chiar daca
in structura lor primara obiectele de tip Layout Manager nu asigura decat
pozitionarea componentelor intr-un container (layout = pozitionare).
Cea mai simpla pozitionare,se realizeaza fara nici un manager:
EXEMPLU:
import javax.swing.JButton;
import javax.swing.JFrame;

public class Design1 {


public static void main(String[] args) {
JFrame frame = new JFrame("Pozitionare absoluta:");
frame.setDefaultCloseoperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(null);
frame.setSize(150,200);
JButton b1 = new JButton("unu");
JButton b2 = new JButton("doi");
JButton b3 = new JButton("trei");
b1.setBounds(10,10,100,20);
b2.setBounds(10,40,100,20);
b3.setBounds(10,70,100,20);
frame.add(b1);
frame.add(b2);
frame.add(b3);
frame.setVisible(true);
}
}
-salvati fila cu numele Design1.java si compilati.
In exemplul de mai sus,este esentiala comanda "frame.setLayout(null)".
In rest,obiectele se pozitioneaza prin indicatii directe cu ajutorul
metodei setBounds() mestenita de la clasa Component.
Cel mai simplu dintre managerii specializati este BorderLayout.Acest
tip de manager este initializat automat in orice container de baza (cum
sunt ferestrele,applet-urile si ferestrele de dialog).Managerul de tip
Borderlayout imparte suprafata containerului in cinci arii distincte:sus,
jos,dreapta,stanga si centru.Un exemplu foarte sugestiv il reprezinta
barele de tip JToolBar create cu ajutorul unui manager de tip BorderLayout
pentru a putea deplasa bara,cu ajutorul unei operatii de tip Drag and Drop
fie pe marginea de sus,fie pe marginea de jos,fie pe una dintre lateralele
ecranului (ferestrei).
In fiecare dintre cele cinci arii,nu se poate amplasa decat un singur
obiect.Obiectele vor avea spatii de vizibilitate diferita.Ca rezultat se
pot crea cinci obiecte identice,cu acelasi identificator,fara a genera un
conflict de denumire,cu conditia ca fiecare dintre ele sa fie amplasat
intr-o arie diferita.In acest caz,obiectul trebuie sa fie definit complet
(inclusiv evenimentele),inainte de a fi amplasat in aria de destinatie,
deoarece nu va mai putea fi referit ulterior.
Managerul BorderLayout redimensioneaza automat obiectele amplasate,in
asa fel incat sa se incadreze in container.Pentru desemnarea celor cinci
arii se utilizeeaza constantele:NORTH,SOUTH,EAST,WEST,CENTER sau respectiv
cele relative: PAGE_START,PAGE_END,LINE_START si LINE_END.In plus se
poate utiliza si clasa ComponentOrientation pentru a schimba orientarea.

-97-
EXEMPLU:
import java.awt.BorderLayout;
import javax.swing.JButton;
import javax.swing.Jframe;
import java.awt.Dimension;
import java.awt.Contaniner;

public class Design2 {


public static void main(String[] args){

JFrame frame = new JFrame("Exemplu cu BorderLayout");


frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.setSize(500,300);

JButton button = new JButton("Butonul: (PAGE_START)");


frame.add(button,BorderLayout.PAGE_START);

button = new JButton("Butonul (CENTER)");


button.setPreferredSize(new Dimension(200,100));
frame.add(button,BorderLayout.CENTER);
frame.setVisible(true);
}
}
-salvati fila cu numele Design2.java si compilati.
In exemplul de mai sus,se poate observa ca ambele butoane se numesc
"button" ,dar sunt gestionate separat,fara nici un conflict de identi-
ficator.Acest gen de solutie se poate adopta atunci cand este important
sa economisiti fiecare variabila de memorie,dar in mod curent este bine
ca fiecare obiect sa fie identificat cu un nume distinct,pentru a putea
fi referit si actualizat prin operatii succesive.
BOXLAYOUT MANAGER
Un alt tip de Layout manager poarta numele de BoxLayout si permite
pozitinarea componentelor in container,fie in functie de axa verticala a
containerului,fie in functie de axa sa orizontala.Pentru grupuri mari de
componente,este recomandabil sa grupati obiectele in mai multe panouri de
tip JPanel si apoi sa aranjati panourile cu un BoxLayout manager.
Axa de orientare a componentelor trebuie specificata in constructorul
obiectului BoxLayout si poate fi: X_AXIS,Y_AXIS,LINE_AXIS sau PAGE_AXIS.
Daca exista setari specifice,BoxLayout respecta preferintele de dimensiune
iar daca nu exista setari,incearca sa redimensioneze toate componentele
la dimensiunea celui mai mare dintre ele.De exemplu,daca sunt aranjate in
functie de axa orizontala,va redimensiona obiectele fata de inaltimea
obiectului cel mai inalt din interfata.Daca se utilizeaza axa LINE_AXIS,
obiectele vor fi pozitionate la fel ca si cuvintele intr-un rand,iar daca
se utilizeaza axa PAGE_AXIS,obiectele vor putea fi pozitionate la fel ca
si randurile dintr-o pagina de text.Obiectul BoxLayout prezinta o serie
intreaga de metode utile :getAxis(),getTarget(),prefferedLayoutSize(),etc.
Pentru a extinde gama de metode accesibile,unii autori prefera sa utili-
zeze obiecte de tip Box.Obiectele de tip Box sunt containere simple ce
utilizeaza BoxLayout pe post de Layout Manager.

-98-
Daca se utilizeza Box,nu mai este necesar sa setati managerul cu o
comanda de tip setLayout().Daca se utilizeaza alt tip de container,este
obligatoriu sa setati managerul dorit.
EXEMPLU:
import javax.swing.JButton;
import javax.swing.JFrame;
import java.awt.Component;
import java.awt.Container;
import javax.swing.BoxLayout;
public class Design3 {
public frame = new JFrame("Exemplu cu BoxLayout");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500,300);
adaugaComponente(frame.getContentPane());
frame.setVisible(true);
}
public static void adaugaComponente(Container pane) {
pane.setLayout(new BoxLayout(pane,BoxLayout.Y_AXIS));
adaugaButon("Buton 1",pane);
adaugaButon("Buton 2",pane);
adaugaButon("Buton 3",pane);
adaugaButon("Buton 4 (text lung)",pane);
adaugaButon("5",pane);
}
private static void adaugaButon(String text,Container container) {
JButton button = new JButton(text);
button.SetAlignementX(Component.CENTER_ALIGNEMENT);
container.add(button);
}
}
-salvati fila cu numele Design3.java si compilati
In exercitiul de mai sus,trebuie observat ca s-a utilizat o functie
speciala pentru crearea fiecarui buton,cu doi parametri: textul dorit si
containerul tinta.Aceasta solutie este necesara,deoarece clasa BoxLayout
implementeaza o interfata de tip LayoutManager2 in loc de LayoutManager.
LayoutManager2 este o extensie a interfetei LayoutManager si se utili-
zeaza atunci cand programatorul doreste sa forteze utilizarea unui anumit
obiect tinta,sau a unui anumit obiect de tip manager (din acest motiv,
constructorul include si containerul tinta).
Pentru a simplifica utilizarea managerului de tip BoxLayout,este mult
mai simplu sa utilizati obiecte de tip Box.Grupati componentele in unul
sau mai multe obiecte de tip Box,apoi includeti obiectele Box intr-o
fereastra,sau in containerul dorit.Obiectul Box,ofera si o serie de faci-
litati suplimentare.Exemple:
-daca doriti ca obiectele sa nu poata fi redimensionate (sa fie "lipite"
de interfata) puteti utliza metoda createGlue()
-daca doriti ca spatiul dintre obiecte sa fie constant si dupa redimen-
sionare interactiva,puteti utiliza metoda createHorizontalStrut()
-daca doriti sa creati un component invizibil,dar care ocupa permanent
acelasi spatiu din interfata,puteti utiliza metoda createRidgidArea()
In plus,nu mai este necesar sa construiti un obiect de tip BoxLayout.

-99-
EXEMPLU:
import javax.swing.*;
import java.awt.Component;
import java.awt.Container;
public class Test4 {
public static void main(String[] args) {
JFrame frame = new JFrame("Exemplu cu Box");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500,300);
Box caseta1 = new Box(BoxLayout.Y_AXIS);
JButton b1 = new JButton("text1");
JButton b2 = new JButton("text2");
caseta1.add(b1);
caseta1.add(b2);
caseta1.setVisible(true);
frame.add(caseta1);
frame.setVisible(true);
}
}
-salvati fila cu numele Test4.java si compilati.
CARDLAYOUT MANAGER
Un alt tip de manager pentru design,este CardLayout manager.Acest tip
de obiect trateaza fiecare component din container ca si cand ar fi o
carte de joc,dintr-un pachet de carti.Primul obiect adaugat in container
va fi cel vizibil implicit,iar restul obiectelor adaugate se vor aseza
ca intr-un pachet,sub componentul implicit.La un anumit moment dat,nu se
poate vizualiza decat unul singur dintre componentele din container,asa
cum din pachetul de carti nu se poate vedea decat una singura.Ordinea in
care se vor afisa restul de componente se poate organiza prin diversi
algoritmi si combinatii de evenimente.
Acest tip de manager,este foarte util atunci cand doriti ca interfata
grafica sa poata fi modificata interactiv,in functie de un anumit criteriu
sau in functie de un anumit eveniment.Pentru acest scop,grupurile de
obiecte vizuale necesare se pot introduce in containere de tip JPanel,
iar containerele JPanel pot fi organizate cu ajutorul unui obiect de tip
CardLayout manager.
Exemple: -se pot crea doua sau mai multe variante de interfata grafica,
iar utilizatorul va putea avea acces la una dintre variante,in functie
de o parola,sau un cod de acces.
-se pot crea grupuri de componente,incluse in containere diferite
iar in timpul executiei,containerele vor fi afisate succesiv,pe masura
ce sunt necesare pentru a controla operatiile aflate in curs.
In esenta,se pot crea solutii grafice prin care se elimina din inter-
fata grafica toate obiectele inutile si se inlocuiesc cu butoane,sau
cu casete de dialog.In momentul in care este necesar,interfata grafica
se va reconfigura,astfel incat sa afisese controalele necesare in acel
moment.
Pentru a naviga printre componentele containerului,obiectul manager
ofera metode specializate ca: first(),next() si last() sau previous().
Alte metode organizeaza dimensiunea si pozitionarea containerului.

-100-
EXEMPLU:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Design4 implements ItemListener {
JPanel cards;
public void Componente(Container pane) {
JPanel comboBoxPane = new JPanel();
String comboBoxItems[] = { "Butoane","Textbox","Eticheta" };
JComboBox cb = new JComboBox(comboBoxItems);
cb.addItemListener(this);
comboBoxPane.add(cb);
JPanel card1 = new JPanel();
card1.add(new JButton("Buton 1"));
card1.add(new JButton("Buton 2"));
card1.add(new JButton("Buton 3"));
JPanel card2 = new JPanel();
card2.add(new JTextField("Introduceti datele: ",20));
JPanel card3 = new JPanel();
card3.add(new JLabel("Eticheta");
pane.add(comboBoxPane,BorderLayout.PAGE_START);
pane.add(cards,BorderLayout.CENTER);
}
public void itemStateChanged(ItemEvent evt) {
CardLayout cl = (CardLayout)(cards.getLayout());
cl.show(cards,(String)evt.getItem());
}
private static void Interfata() {
JFrame frame = new JFrame("CardLayoutDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Design4 demo = new Design4();
demo.Componente(frame.getContentPane());
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) { Interfata(); }
}
-salvati fila cu numele de Design4.java si compilati
In exemplul de mai sus,prelucrat dupa exemplul din tutorialul oferit de
firma Sun,se pot observa etapele de lucru:
-se creaza mai multe obiecte de tip JPanel
-in fiecare container JPanel se includ obiectele vizuale dorite
-se creaza un obiect tip ComboBox cu pointeri spre fiecare JPanel
-se creaza un container de tip JPanel administrat de un manager de tip
CardLayout [new JPanel(new CardLayout())] in care se includ apoi toate
obiectele de tip Jpanel ce contin componente
-se include obiectul ComboBox intr-un alt panel si apoi impreuna cu
containerul principal se includ in containerul de baza
-se conecteaza evenimentul itemStateChanged la pointerii din ComboBox
Executati exercitiul si utilizati caseta ComboBox,pentru a schimba
interactiv interfata grafica (schimbati obiectul JPanel afisat).

-101-
FLOWLAYOUT MANAGER
FlowLayout manager organizeaza componentele unui container in ordinea
declararii,ca si cuvintele dintr-o propozitie.Acest manager este asociat
automat cu obiectele de tip JPanel.Obiectele sunt adaugate in container
pe linie orizontala,pana la epuizarea spatiului disponibil,apoi se trece
la linia urmatoare,la fel ca si cuvintele dintr-un text.Alinierea este
determinata prin proprietatea ALIGN si poate avea urmatoarele valori:
LEFT,RIGHT,CENTER,LEADING sau TRAILING.Obiectul FlowLayout are trei con-
structori diferiti.Cel mai complex dintre acestia permite specificarea
spatiilor libere dintre componenete.Acest tip de manager este usor de
utilizat si pentru rutine automate.
EXEMPLU:
import javax.swing.*;
import java.awt.*;

public class Design5 {


public static void main(String[] args){
JFrame frame = new JFrame("Exemplu cu FlowLayout");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(600,500);
FlowLayout manager1 = new FlowLayout(FlowLayout.CENTER,50,100);
JPanel panou = new JPanel(manager1);
JButton b1 = new JButton("text1");
panou.add(b1);
for (int x=0;x<9;x++)
{
b1 = new JButton("Butonul:" + String.valueOf(x));
panou.add(b1);
}
frame.add(panou);
frame.setVisible(true);
}
}
-salvati fila cu numele Design5.java
Pentru ca obiectele sa fie adaugate dupa un sablon oarecare,am creat
un obiect de tip FlowLayout si apoi am construit un container de tip
JPanel ce utilizeaza acest manager.Apoi am adaugat butoanele cu o rutina
automata.Pentru a observa mai bine modul de lucru al managerului,puteti
schimba valorile din constructor,sau puteti schimba dimensiunile feres-
trei.Apoi recompilati si observati diferentele.
Pentru obiectele de tip JPanel nu este necesar sa definiti managerul
de tip FlowLayout,decat daca doriti sa setati un anumit sablon.In caz
contrar,puteti utiliza managerul implicit,cu valorile implicite.
Obiectele pot fi adaugate in cascada,cu ajutorul unor bucle automate,
dar este bine sa faceti o schita a interfetei inainte de a programa aceste
bucle automate.In plus,este esential sa creati si destructorul corespunza-
tor,astfel incat sa puteti elibera memoria la nevoie.In majoritatea cazu-
rilor,este mai prudent sa adaugati obiectele pe rand,cu declaratii spe-
cifice si cu identificatori distincti.In acest caz,fiecare obiect va putea
fi apelat separat,iar evenimentele din interfata vor fi mult mai usor de
gestionat.

-102-
GRIDBAGLAYOUT MANAGER
GridBagLayout manager organizeaza componentele unui container sub forma
unei grile,cu celule orizontale si verticale,asemanator cu un tabel de
date preformatate.Fiecare celula poate include un singur obiect,dar un
obiect oarecare se poate intinde si pe doua sau mai multe celule.Nu este
obligatoriu ca obiectele sa fie egale intre ele,sau simetrice.Pentru a
reglementa pozitia si caracteristicile fiecarei celule se utilizeaza un
obiect de tip GridBagConstraints in care se vor seta proprietatile:east,
center,fill,gridx,gridy,gridwidth,gridheight,weightx,wieghty...etc.
EXEMPLU:
import javax.swing.*;
import java.awt.*;

public class Design6 {


public static void main(String[] args) {
JFrame frame = new JFrame("Exemplu cu GridBagLayout");
frame.setDefaultCloseOperation(jframe.EXIT_ON_CLOSE);
frame.setSize(600,500);
JPanel pane = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
JButton button;
for (int x=0;x<6;x++)
{ button = new JButton("Buton: " + String.valueOf(x));
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = x;
c.gridy = 0;
pane.add(button,c);
}
for (int y=1;y<4;y++)
{ button = new JButton("Buton: " + String.valueOf(y+5));
c.fill = GridBagConstrains.HORIZONTAL;
c.gridx = 1;
c.gridy = y;
c.gridwidth = 4;
c.weightx = 0.5;
pane.add(button,c);
}
frame.add(pane);
frame.setVisible(true);
}
}
-salvati fila cu numele Design6.java si compilati
Managerul de tip GridBagLayout este destul de flexibil si poate fi
setat,atat din proprietatile obiectului GridBagConstraints cat si prin
setarea proprietatilor pentru fiecare obiect in parte.Obiectele din grila
se pot crea unul cate unul,in grupuri,sau prin diverse rutine automate.
Daca obiectele componente din container sunt redimensionabile,vor fi
redimensionate automat pana la dimensiunea maxima a fiecarei celule,iar
in caz contrar,se pot seta diverse solutii pentru modul de prezentare a
spatiului ramas liber in celula respectiva.In plus,se pot utiliza metodele
obiectului GridBagLayout pentru a personaliza in plus interfata obtinuta.
-103-
GRIDLAYOUT MANAGER
GridLayout manager este asemanator cu GridBagLayout,dar are un alt set
de metode si trei constructori diferiti.Si acest obiect utilizeaza o grila
pentru ordonarea si alinierea componentelor.Constructorul implicit creaza
o grila cu doua coloane,iar ceilalti doi constructori creaza grila cu
valorile specificate prin parametrii constructorului.
EXEMPLU:
import javax.swing.*;
import java.awt.*;

public class Design7 {


public static void main(String[] args) {
JFrame frame = new JFrame("Exemplu cu GridLayout");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(600,500);
frame.setLayout(new GridLayout(7,5,25,40));
for (int x=0;x<35;x++)
{
frame.add(new JButton("Buton"));
}
frame.setVisible(true);
}
}
-salvati fila cu numele Design7,java si compilati.
Acest manager este simplu si usor de utilizat.Managerul imparte toata
suprafata in compartimente egale.Acest manager este de preferat,atunci
cand doriti sa utilizati spatii egale,pentru toate obiectele din interfata
grafica.Se preteaza si la bucle automate.Pentru a schimba orientarea de
la dreapta spre stanga,se poate utiliza ComponentOrientation.

GROUPLAYOUT MANAGER
Acest obiect manager este ceva mai complex si permite organizarea unor
seturi mai largi de componente,atat izolat cat si in grupuri fixe.Cu acest
manager,obiectele din interfata vor fi organizate ierarhic si pot fi
grupate cu ajutorul unor obiecte de tip Group.Pentru spatierea obiectelor
se utilizeaza spatii goale (gaps).Aceste spatii,pot fi considerate ca si
cand ar fi niste obiecte distincte,ce trebuiesc intercalate intre obiecte-
le vizibile.
Pentru organizarea componentelor,acest manager utilizeaza cele doua
axe: orizontala si verticala.Pentru fiecare dintre cele doua axe,trebuie
declarata metoda specifica: setHorizontalGroup() si setVerticalGroup().
Fiecare obiect trebuie sa fie inclus in ambele metode,pentru ca managerul
sa poata evalua pozitia sa relativ la axa respectiva.In caz contrar,se va
returna un mesaj de eroare.Cu alte cuvinte,fiecare obiect va fi raportat
atat la cele doua axe,cat si la celelalte obiecte din acelasi grup.In
fiecare dintre cele doua metode,se vor grupa obiectele care urmeaza sa
fie aliniate orizontal,respectiv vertical.Este posibil ca in cele doua
functii,obiectul sa fie inclus in grupuri diferite (dupa cum doriti sa
fie aliniat),dar este esential sa fie declarat in ambele metode.Acest
manager a fost conceput mai ales pentru editoarele cu interfata vizuala,
(cum este NetBeans),dar poate fi utilizat cu succes si in cod direct.
-104-
EXEMPLU:
import javax.swing.*;
import java.awt.*;
import static javax.swing.GroupLayout.Alignment.*;
import java.awt.Component;
public class Design8 {
public static void main(String[] args) {
JLabel label = new JLabel("Open File:");
JTextField textField = new JTextField();
JButton findButton = new JButton("Find");
JButton cancelButton = new JButton("Cancel");
JFrame frame = new JFrame("Exemplu cu GroupLayout");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(600,500);
GroupLayout layout = new GroupLayout(frame.getContentPane());
frame.getContentPane().setLayout(layout);
layout.setAutoCreateGaps(true);
layout.setAutoCreateContainerGaps(true);
layout.setHorizontalGroup(layout.createSequentialGroup()
.addComponent(label)
.addComponent(textField)
.add(layout.createParallelGroup(LEADING)
.addComponent(findButton)
.addComponent(cancelButton))
);
layout.setVerticalGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(LEADING)
.addComponent(label)
.addComponent(textField)
.addComponent(findButton))
.addComponent(cancelButton)
);
frame.setVisible(true);
}
}
-salvati fila cu numele design8.java si compilati
In mod normal,nu are rost sa utilizati acest manager in programarea
manuala,linie cu linie,dar este esential sa intelegeti modul in care se
organizeaza componentele,pentru a putea moderniza sau depana o aplicatie
creata cu NetBeans in care se utilizeaza acest manager.Pornind de la
exemplul de mai sus,incercati sa adaugati progresiv obiecte izolate,apoi
grupuri de obiecte aliniate orizontal sau vertical,pana cand stapiniti
cu siguranta modul de lucru.
In exemplul de mai sus,se pot identifica usor constructorul si cele
doua metode : setHorizontalGroup() si setVerticalGroup().
Pentru construirea obiectelor de tip Group se pot utiliza cele doua
metode : createParallelGroup() si respectiv createSequentialGroup().
Atentie la modul de inchidere a parantezelor,pentru fiecare constructor.
Pentru ca spatiile goale sa fie create automat,este suficient sa setati
metoda setAutoCreateGaps(),daca nu doriti sa creati spatii personalizate
cu o anumita configuratie.

-105-
SPRINGLAYOUT MANAGER
SpringLayout manager,este destinat pentru a permite reconfigurarea unei
interfete grafice,atunci cand este redimensionata.Termenul de spring,vine
de la "elastic" sau "extensibil" si atrage atentia asupra faptului ca
permite o pozitinare mai laxa a obiectelor.Pentru acest scop,acest manager
permite ca obiectele sa fie pozitionate in functie de niste repere fixe
din interfata.Aceste repere pot fi marginile unui alt obiect din container
(obiectele se pozitioneaza unul fata de altul),sau marginile containerului
(obiectele se pozitioneaza fata de container).Ca rezultat,de exemplu,daca
obiectele se pozitioneaza fata de marginea inferioara a ferestrei,atunci
obiectele se vor deplasa impreuna cu marginea inferioara,atunci cand
fereastra este redimensionata.Pentru stabilirea acestor repere,se utili-
zeaza niste obiecte specializate de tip Spring.Fiecare reper este repre-
zentat printr-un astfel de obiect de tip Spring.Fiecare obiect de tip
Spring are proprietati prin care se seteaza dimensiunea minima,maxima sau
dimensiunea preferata.Prin combinarea acestor proprietati se va putea
determina si dimensiunea actuala a obiectului,salvata in proprietatea
"value".Pentru setarea obiectelor de tip String,managerul apeleaza la
metoda specializata denumita putConstrains().
EXEMPLU:
import javax.swing.*;
import java.awt.*;

public class Design9 {


public static void main(String[] args) {
JFrame frame = new JFrame("Exemplu cu SpringLayout");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(600,500);
Container componentPane = frame.getContentPane();
SpringLayout layout = new SpringLayout();
contentPane.setLayout(layout);
JLabel label = new JLabel("Introduceti in caseta textul dorit: ");
JTextField textField = new JtextField("Text: ",40);
content.add(label);
content.add(textField);
layout.putConstraint(SpringLayout.NORTH,textField,10,
SpringLayout.SOUTH,label);
layout.putConstraint(SpringLayout.SOUTH,textField,40,
SpringLayout.SOUTH,contentPane);
frame.setVisible(true);
}
}
-salvati fila cu numele Design9.java si compilati
In acest exemplu,se pot observa etapele de lucru:
-se declara fereastra (containerul de baza)
-se construieste managerul
-se asociaza managerul la container
-se declara obiectele
-se fixeaza conditiile (reperele) cu metoda putConstraint()
In exemplul de mai sus,obiectul de tip textField este pozitionat prin
raportare la obiectul label si prin raportare la container.

-106-
Ca rezultat,obiectul textField se va redimensiona o data cu fereastra,
dar va mentine o distanta fixa fata de obiectul JLabel.Daca obiectele se
pozitioneaza doar prin raportare unul fata de altul,nu se vor deplasa
o data cu containerul.
EXEMPLU:
import javax.swing.*;
import java.awt.*;

public class Design10 {


public static void main(String[] args) {
JFrame frame = new JFrame("Exemplu cu SpringLayout);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(600,100);
Container contentPane =frame.getContentPane();
SpringLayout layout = new SpringLayout();
contentPane.setLayout(layout);
JButton buton1 = new JButton("Buton1");
JButton buton2 = new JButton("Buton2");
JButton buton3 = new JButton("Buton3");
contentPane.add(buton1);
contebtPane.add(buton2);
contentPane.add(buton3);
layout.putConstraint(SpringLayout.EAST,buton3,250,
SpringLayout.WEST,buton2);
layout.putConstraint(SpringLayout.EAST,buton2,250,
SpringLayout.WEST,buton1);
frame.setVisible(true);
}
|
-salvati fila cu numele Design10.java si compilati
In exemplul de mai sus,cele trei butoane sunt pozitionate prin rapor-
tare unul fata de altul.Indiferent de dimensiunea ferestrei,cele trei
butoane vor avea o pozitie fixa.Pentru ca sa poata fi deplasabile,trebuie
sa adaugati si o raportare la una dintre marginile containerului.
EXEMPLU: adaugati la exercitiul de mai sus si urmatoarea linie de cod:
layout.putConstraint(SpringLayout.NORTH,buton2,-30,
SpringLayout.SOUTH,contentPane);
In acest caz,marginea de sus a celui de la doilea buton va fi in per-
manenta situata la 30 de pixeli deasupra marginii inferioare a ferestrei.
Daca redimensionati fereastra,cel de al doilea buton se va deplasa impre-
una cu marginea de jos a ferestrei (containerului),in timp ce celelalte
doua butoane raman fixe.
In mod similar,se pot proiecta orice fel de combinatii posibile.In
tutorialul oferit de firma Sun,gasiti un set de exemple in care managerul
de tip spring imita comportamentul altor manageri,dar adauga si flexibi-
litatea specifica pentru SpringLayout manager.Pentru acest scop,se poate
definii o clasa speciala,in care sa se reglementeze automat toate pozi-
tionarile posibile (vezi SpringUtilities.class din acest tutorial).
Si pentru SpringLayout manager este recomandabil sa utilizati un editor
vizual (NetBeans),dar este esential sa intelegeti modul in care se orga-
nizeaza si administreaza pozitionarea obiectelor din interfata.

-107-
MANAGER PERSONALIZAT
In mod normal,obiectele standard ofera o gama destul de larga de
optiuni,pentru a putea satisface majoritatea necesitatilor de programare
curenta.Exista insa situatii in care doriti sa utilizati un obiect per-
sonalizat pentru designul interfetei grafice.De exemplu,daca lucrati in
cadrul unei firme de software si doriti ca toate aplicatiile sa respecte
un anumit tipar.In acest caz,puteti crea o clasa noua de tip Layout Mana-
ger,in care setati toate caracteristicile principale.Un astfel de manager
personalizat ofera urmatoarele avantaje:
-clasa respectiva poate fi utilizata ori de cate ori este cazul
-utilizatorii nu pot modifica aspectul interfetei grafice,dacat daca
oferiti si fila sursa (se protejeaza codul managerului)
-managerul poate contine un set intreg de setari de tip design,nu doar
cele necesare pentru pozitionarea obiectelor
Cea mai simpla metoda pentru a crea un astfel de manager este sa
extindeti una dintre clasele standard,adaugand functionalitati noi.
EXEMPLU:
import java.awt.*;
import java.awt.Color;

class ManagerulMeu extends FlowLayout {


public final static Color prefer1 = new Color(77,177,77);
}
-salvati fila cu numele ManagerulMeu.java si compilati
In continuare,managerul nou creat va putea fi utilizat la fel ca si
cel standard din care este derivat.
EXEMPLU:
import javax.swing.*;
import java.awt.*;
public class Design12 {
public static void main(String[] args) {
JFrame frame = new JFrame("Exemplu cu FlowLayout");
frame.setDefaultCloseOperation("Exemplu cu FlowLayout");
frame.setSize(600,500);
ManagerulMeu manager1 = new ManagerulMeu();
JPanel panou = new JPanel(manager1);
JButton b1 = new JButton("text1");
panou.add(b1);
for (int x=0;x<9;x++)
{
b1 = new JButton("Butonul:" + String.valueOf(x));
b1.setBackground(ManagerulMeu.prefer1);
panou.add(b1);
}
frame.add(panou);
frame.setVisible(true);
}
}
-salvati fila cu numele Design12.java si compilati
Observati ca butoanele vor avea culoarea setata in manager.

-108-
Exista si posibilitatea de a crea un Layout manager complet nou,dar
aceasta solutie este mult mai laborioasa.In acest caz,este esential ca
managerul nou creat sa implementeze o interfata de tip LayoutManager,fie
direct,fie prin descendentul sau,LayoutManager2.In plus,pe langa construc-
tor si destructor,este obligatoriu ca noul mamager sa declare si sa defi-
neasca urmatoarele metode esentiale:
void addLayoutComponent(String,Component)
void removeLayoutComponent(component)
Dimension preferredLayoutSize(Container)
Dimension minimalLayoutSize(Container)
void layoutContainer(Container)
In cazul in care managerul d-voastra implementeaza o interfata de tip
LayoutManager2,se vor adauga si umatoarele cinci metode esentiale:
addLayoutComponent(Component,Object)
getLayoutAlignmentX(Container)
getLayoutAlignement(Container)
invalidateLayout(Container)
maximumLayoutSize(Container)
O etapa esentiala o constitue modul in care eliberati memoria.Din acest
motiv,destructorul va trebui sa fie testat pentru orice fel de situatie
posibila,pentru a elimina orice resturi de date sau thread-uri restante
in "background".Programarea unui astfel de destructor poate fi extrem de
dificila si nu se recomanda incepatorilor.Din acest motiv,este preferabil
sa programati managerul personalizat doar prin extinderea unei clase
standard,in care beneficiati atat de constructor si destructor autorizat,
cat si de metodele esentiale,predefinite.
Notiunile din acest capitol sunt aproape inutile daca lucrati cu
NetBeans,sau cu orice alt editor vizual integrat.Totusi,este esential sa
intelegeti modul in care se organizeaza si se administreaza obiectele
din interfata grafica.Acest sistem de organizare poate fi utilizat si
in alte scopuri.Nu este obligatoriu ca managerul sa administreze doar
obiecte vizuale,ci poate fi utilizat pentru orice alt tip de obiect.De
exemplu,interfata grafica poate contine si o serie intrega de obiecte
ce nu sunt afisate in timpul executiei,dar interactioneaza cu evenimente
din interfata grafica.Cel mai cunoscut exemplu il reprezinta jocurile
pentru calculator,in care se creaza adevarate retele de astfel de obiecte
invizibile,ce asteapta un anumit eveniment.In locul unei astfel de retele
se poate utiliza cu succes un obiect de tip GridLayout..etc.
In plus,este util sa intelegeti modul de evidenta al obiectelor din
interfata,pentru a putea crea aplicatii asemanatoare.De exemplu daca
doriti sa programati un sistem nou de operare,va trebui sa alegeti una
sau mai multe solutii pentru gestionarea unitatilor de lucru,pentru
gestionarea partitiilor de memorie etc.Practic,orice tip de operatie de
gestiune se poate face asemanator cu cea pentru pozitinarea obiectelor.
Din acest motiv,am preferat termenul de "design manager",in locul celui
de "gestionar de pozitie".
Nu se pot face recomandari generale referitoare la design,sau la
gestionarea operatiilor necesare pentru design.Fiecare utilizator va alege
solutia ce corespunde cel mai bine cu experienta sa personala,sau cu
necesitatile aplicatiei proiectate.Totusi,exista o recomandare utila:
-solutia cea mai buna,este intotdeauna solutia cea mai simpla !

-109-
TABELE SI BAZE DE DATE
Mediul Java nu a fost conceput pentru operatii cu baze de date,dar
prin adaugarea unor programe auxiliare,se pot face orice fel de operatii
cu tabele si baze de date,inclusiv in retea.Pentru a face conexiunea cu
un tabel sau o baza de date,este necesar un pachet special de clase si
componente API denumit JDBC (Java Database Connectivity).In plus,este
obligatoriu ca in unitatea de lucru sa fie instalat si un driver special
(driver = program destinat pentru functiile sistemului de operare).Daca
utilizati platforma NetBeans,beneficiati atat de pachetul JDBC,cat si de
driverele necesare (sunt instalate automat).
Cea mai simpla operatie posibila este cea prin care se creaza si apoi
se afiseaza un tabel.Pentru aceste operatii simple,nu este ncesar nici un
program auxiliar,ci se poate utiliza doar clasa JTable din javax.swing.
In locul bazei de date,se va crea o clasa ce extinde o interfata de tip
TableModel,apoi se va construi obiectul JTable pe baza acestui sablon.
EXEMPLU:
import javax.swing.*;
import javax.swing.table.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;

public class TabelDemo extends JFrame {


public TabelDemo() {
setSize(700,300);
setLayout(new FlowLayout());
JTable gradesTable = new JTable(new ModelTabel());
gradesTable.setFillsViewportHeight(true);
gradesTable.setRowHeight(24);
JLabel text1 = new JLabel("Numele Prenumele si notele obtinute");
add(text1);
add(gradesTable);
}
public static void main(final String[] args) {
new TabelDemo().setVisible(true); }
}
-salvati fila cu numele TabelDemo.java
Inainte de a putea compila fila,este necesar sa creati si clasa de
tip ModelTabel pe care constructorul pentru JTable o va utiliza pe post
de sablon.
Acest sablon,se poate crea prin implementarea unei interfete de tip
TableModel (din javax.swing).Pentru acest scop,va trebui sa redefiniti
toate metodele acestei interfete: addTableModeListener()
getColumnClass()
getColumnCount()
getColumnName()
getRowCount()
getValueAt()
isCellEditable()
removeTableModeListener()
si setValueAt()

-110-
EXEMPLU:
import javax.swing.table.*;
import javax.swing.event.*;
class ModelTabel implements TableModel {
private final Object[][] GRADES = {
{"Albu","Mihai",8,7,5,9},
{"Barbu","Emil",9,6,8,7},
{"Ionescu","Ion",6,5,8,9},
{"Popescu","Daniela",5,6,5,8},
{"Stanescu","Ronald",8,5,5,7}, };
public void setValueAt(Object aValue,int rowIndex,int columnIndex){}
public void addTableModeListener(TableModeListener l) {}
public void removeTableModeListener(TableModeListener l) {}
public boolean isCellEditable(int rowIndex,int columnIndex) {
return false; }
public Object getValueAt(int row,int col) {
switch(col) {
case 0:
case 1:
case 2:
case 3:
case 4:
case 5: return GRADES[row][col];
case 6:
case 7: int fin = 0;
fin += (Integer) GRADES [row][2];
fin += (Integer) GRADES [row][3];
fin += (Integer) GRADES [row][4];
fin += (Integer) GRADES [row][5];
fin = Math.round((fin / 4.0f));
if (col == 6 ) { return fin;
} else { return fin > 7; }
} throw new AssertionError("invalid column"); }
public Class<?> getColumnClass(int col) {
switch(col) {
case 0:
case 1: return String.class;
case 2:
case 3:
case 4:
case 5:
case 6: return Integer.class;
case 7: return Boolean.class;
} throw new AssertionError("invalid column"); }
public String getColumnName(int col) { return "text: " ; }
public int getRowCount(){ return GRADES.length; }
public int getColumnCount(){ return 8; }
}
-salvati fila cu numele ModelTabel si compilati,apoi compilati si
fila precedenta si executati exercitiul.
Eventual,incercati sa dezvoltati tabelul cu noi randuri si coloane.

-111-
Acest gen de solutie prezinta urmatoarele avantaje:
-nu necesita nici un driver sau pachet suplimentar
-baza de date este inlocuita de o arie bidimensionala
-se elimina operatiile necesare pentru realizarea conexiunii
-modulul poate fi si monobloc,cu executie mult mai rapida
-pentru actualizarea datelor se va actualiza doar clasa Model Tabel
Principalele dezavantaje sunt:
-este o solutie foarte laborioasa,mai ales atunci cand se lucreaza cu
volume mari de date
-conectarea datelor din tabel la componentele din interfata grafica este
dificila si laborioasa
-este dificil de lucrat cu date arhivate in retea (site-uri de Internet)
-este dificil de organizat si sistematizat atunci cand se lucreaza cu un
numar mare de tabele
-comenzile de tip SQL sunt mult mai greu de implementat decat atunci cand
se lucreaza cu editoare vizuale
-nu exista un control vizual al operatiilor efectuate,motiv pentru care
operatiile de design si/sau depanare sunt mult mai greoaie
In sinteza,acest gen de solutie directa,este recomandabil doar atunci
cand se lucreaza cu volume mici de date,ce urmeaza sa fie prezentate cu
o structura fixa,fara operatii de actualizare sau reorganizare a datelor.
Pentru orice gen de aplicatie complexa,se recomanda sa utilizati exclusiv
editoare moderne,cu interfata grafica vizuala,gen NetBeans.Teoretic este
posibil sa realizati toate operatiile necesare si prin comenzi editate
manual,dar acest gen de solutie implica un volum nerezonabil de munca si
se preteaza la numeroase erori de conceptie,sau editare.
In principiu,programele ce opereaza cu baze de date si tabele de date
preformatate se pot realiza doar in urmatoarele conditii:
-trebuie sa existe cel putin un driver specializat,adica un program ce
faciliteaza operatiile de tip I/O (citirea sau scrierea bazelor de date)
-trebuie sa existe un program specializat cu care se editeaza bazele de
date si tabelele
-trebuie sa existe o solutie pentru organizarea tabelelor (file de index-
are,tabele de adevar,obiect de tip manager etc.)
-trebuie sa existe o solutie pentru a crea o conexiune intre baza de date
si aplicatia utilizatorului
-trebuie sa existe o compatibilitate perfecta intre tabelul utilizat si
comenzile de tip SQL prin care se solicita citirea sau reorganizarea
datelor
-trebuie sa existe un obiect compatibil,in care sa poata fi afisate datele
preluate
Programele denumite "driver" au un rol esential,deoarece determina
limitarile "fizice" ale sistemului de operare.Aceste drivere se pot
descarca din reteaua Internet si pot fi clasificate in urmatoarele grupe
mari:
-Tipul 1 -sunt cele care depind de o anumita biblioteca,ce trebuie sa
fie preinstalata in unitatea de lucru.Programele sunt functionale,dar pot
aparea o serie intrega de incompatibilitati atunci cand sunt transferate
pe alta unitate de lucru (portabilitatea este mai redusa).
-Tipul 2 -sunt specifice pentru un anumit format al bazei de date si
sunt dependente de o biblioteca specializata pentru acel tip de date.

-112-
-Tipul 3 -sunt cele care realizeaza conexiunea la baza de date,exclusiv
prin intermediul unui server,utilizand un protocol independent de tipul
de baza de date.
-Tipul 4 -sunt cele care utilizeaza cate un protocol specific pentru
fiecare tip de baza de date si realizeaza conexiunea direct cu baza de
date respectiva.
Exista un numar mare de programe ce permit editarea bazelor de date.
Dintre acestea,cele mai frecvent utilizate sunt FoxPro,Visual Basic,Oracle
dBase sau NetBeans.Fiecare program va genera un anumit tip de baze de date
cu o extensie specifica: .dbf,.mdb etc.Programele driver asigura compati-
bilitatea dintre aceste tipuri diferite de baza de date.Fiecare driver
este insotit de o documentatie tehnica.Este esential sa cititi cu atentie
aceasta documentatie inainte de a alege driver-ul dorit,pentru a va asi-
gura ca va fi compatibil cu datele pe care doriti sa le exploatati.In
principiu,nu trebuie sa alegeti driver-ul cel mai "la moda",ci este bine
sa alegeti cel care este competibil cu programul editor cu care sunteti
familiarizati.Exemplu : daca detineti tabele in format .dbf,este uneori
indicat sa utilizati un driver de tip 1 sau 2,chiar daca sunt mai vechi
si nu mai sunt "actuale".
Daca nu aveti nici un fel de experienta anterioara si nu detineti nici
un fel de baze de date,este recomandabil sa utilizati exclusiv platforma
NetBeans.Platforma NetBeans,nu numai ca instaleaza automat cinci programe
driver,ce acopera majoritatea necesitatilor posibile,dar permite si edi-
tarea tabelelor si bazelor de date,comod si simplu.
EXEMPLU:
-deschideti platforma NetBeans
-deschideti fereasta Services si extindeti nodul Databases
-selectati nodul Java DB si executati un click drept
-alegeti optiunea CreateDatabase
-completati fereastra de dialog : nume,user si parola
-confirmati cu OK
-deschideti din nou fereastra Services si selectati baza de date nou
creata,apoi executati un click drept si alegeti optiunea Connect...
-extindeti nodul (apasand pe semnul +) si selectati folderul Tables
-executati un click drept pe Tables si alegeti Create Table
-completati numele tabelului,apoi introduceti datele
-pentru fiecare coloana,alegeti tipul de data si dimensiunea
-este esential sa existe o cheie de indexare a tabelului (cel putin
una dintre coloane va avea selectata si optiunea key)
-daca doriti sa indexati tabelul in functie de o anumita coloana
selectati si optiunea Index (nu are rost sa indexati tabelul decat
daca urmeaza sa executati operatii de actualizare si sortare)
-in final,confirmati cu OK
-extindeti nodul Tables pentru a vedea tabelul nou creat
-selectati tabelul,executati un click drept de mouse si alegeti
optiunea View Data
-tabelul va fi afisat in planseta de design
-pentru a introduce date,executati un click drept in tabel si apoi
alegeti optiunea Insert Record
-completati caseta de dialog si confirmati cu OK
-daca doriti,puteti reedita comanda SQL (din caseta suprajacenta)
-113-
In exemplul precedent,s-a creat o baza de date si un tabel indexat.In
continuare,puteti adauga alte tabele,sau puteti testa diferite formule
de prezentare a datelor si diverse comenzi SQL.
De exemplu,pentru a crea o selectie (view) selectati folderul View,apoi
executati un click drept si selectati optiunea Create View.Alegeti un
nume si editati comanda sql dorita.
EXEMPLU:
select * FROM (numele tabelului) ...WHERE ...conditia dorita
Daca doriti sa previzualizati,expandati nodul Views,selectati nodul
dorit,executati un click drept si alegeti optiunea View Data
In continuare,baza de date,tabelele si selectiile dorite pot fi utili-
zate in aplicatii.Cea mai simpla forma de implementare a lor,este prin
utilizarea unui proiect de tip Java Desktop Application.
EXEMPLU:
-din meniul File alegeti New Project si apoi Java Desktop Application
-apasati butonul Next
-in caseta Choose Application Shell alegeti Database Application
-apasati butonul Next
-in caseta Database Connection selectati baza de date dorita
-daca exista mai multe tabele,alegeti tabelul dorit
-apasati butonul Finish
Aplicatia generata va contine o bara de meniuri cu meniurile File si
Help,un obiect de tip JTable gata conectat la tabelul ales,un set de
obiecte de tip TextArea conectate la fiecare coloana din tabel (pentru
actualizarea datelor) si un set de butoane functionale,gata setate pentru
principalele operatii posibile :
New - adauga o inregistrare noua
Delete -sterge o inregistrare
Refresh - actualizeaza datele
Save -salveaza modificarile efectuate
Acest schelet minimal,este suficient pentru majoritatea situatiilor.
Daca doriti sa executati operatii mai complexe,adaugati componentele
dorite si apoi implementati algoritmii doriti.Pentru a crea o conexiune
intre un component Swing si tabel,este suficient sa selectati obiectul,
apoi sa executati un click drept si sa alegeti optiunea Bind,iar apoi sa
selectati tabelul sursa (binding Source) si respectiv coloana dorita
(binding Expression).Operatiile se vor putea controla cu butoane simple
si evenimente mouseClicked sau actionPerformed,keyPresed ...etc.
Daca doriti pur si simplu sa afisati un tabel,sau o anumita selectie
dintre cele realizate anterior (altul decat cel conectat implicit),este
suficient sa deschideti fereastra Services,sa selectati nodul dorit si
apoi sa trageti (cu butonul mouse apasat) nodul dorit,in fereastra apli-
catiei.
Daca doriti sa adaugati un driver oarecare,deschideti fereastra Servi-
ces,selectati Drivers,executati un click drept si alegeti New Driver.
Expandati nodul Drivers pentru a putea observa driverele instalate.Daca
doriti sa stabiliti o conexiune,utilizand un anumit driver,selectati
driver-ul respectiv,executati un click drept si alegeti Conect Using...
Este necesar sa utilizati un driver special,atunci cand doriti sa va
conectati la un anumit tip de baza de date (de exemplu de tip FoxPro).
Pentru operatiile uzuale se pot utiliza metodele obiectului JTable.
-114-
Pentru aplicatii elementare,nu este necezsar sa adaugati nici un fel
de operatii suplimentare.Pur si simplu,selectati butonul Clean and Build
Main Project si construiti proiectul,apoi executati cu Run Main Project.
Pentru exercitiu,adaugati noi inregistrati folosind butonul New si
apoi salvati datele cu Save.Daca apasati butonul Refresh,se vor reseta
datele initiale.Pentru ca datele introduse sa ramana definitive,apsati
Save si inchideti aplicatia.
Daca sunteti incepatori,este recomandabil sa nu incercati sa dezvol-
tati operatii noi,sau sa utilizati doar obiecte standard conectate la
tabel cu Bind si seturi de operatii elementare.
Daca sunteti avansati,puteti dezvolta aplicatia progresiv.Cea mai
buna solutie este sa utilizati aceasi tip de solutie ca si cel oferit
de wizard.Pentru acest scop,deschideti fereastra DesktopApplicationView
si alegeti optiunea Source (in loc de Design).Studiati metodele utilizate
pentru newRecord(),deleteRecord(),SaveTask()...etc.Este recomandabil ca
metodele nou implementate sa apeleze componentele interfetei in mod
asemanator.
Exista insa si o solutie mult mai simpla.Pentru operatii elementare,
este mult mai usor sa utilizati componente swing simple,conectate la
tabelul dorit (cu bind).Executati operatiile necesare in aceste compo-
nente si apoi salvati rezultatul cu butonul Save implicit.
EXEMPLU:
-daca tabelul conectat contine o coloana denumita VALOARE,in care sunt
arhivate date de tip Double.
-presupunem ca doriti sa adaugati un procent de 18 % la o parte dintre
valorile din aceasta coloana (un impozit)
-coloana va fi conectata in interfata grafica la un obiect JTextField,
denumit valoareField.
-pentru a executa operatia automat,adaugati un buton simplu.Click drept
pe buton si alegeti Events -> Action -> ActionPerformed
-editati urmatoarea metoda
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
java.lang.Double xxx = 0.00;
xxx = java.lang.Double.valueOf(valoareField.getText()) +
java.lang.Double.valueOf(valoareField.getText()) * 18/100;
valoareField.setText(java.lang.String.valueOf(xxx);
}
Acest gen de solutie este extrem de simpla si nu implica utilizarea
unor alte obiecte.Conexiunea cu tabelul este gata realizata si nu sunt
necesare comenzi de tip SQL,sau tranzactii de date.Combinand mai multe
obiecte vizuale,se pot obtine operatii destul de complexe.
Pentru operatii mai complexe insa,trebuie sa utilizati pachetul
javax.persistence si obiecte de tip entityManager (la fel ca si in
metodele implicite).
Un alt tip de abordare posibila,este prin utilizarea pachetului
java.sql si a obiectelor de tip Statement si preparedStatement.
Nu exista o solutie unica.Fiecare programator va alege metoda prefe-
rata,in functie de experienta sa anterioara,sau in functie de necesita-
tile de moment.In orice caz,pentru incepatori este recomandabil sa nu
utilizeze decat metodele implicite si combinatii de operatii simple,
realizate cu ajutorul componentelor swing.

-115-
CLASE GENERICE SI COLECTII

Programarea moderna presupune organizarea si structurarea unui numar


din ce in ce mai mare de structuri de date.O parte dintre acestea sunt
mai vechi si au fost ediate conform regulilor anterioare de organizare a
datelor,in timp ce altele sunt mai noi si cuprind structuri sau obiecte
necunoscute pentru versiunile mai vechi de program.JList,JComoBox sau
JTable sunt doar cateva dintre obiectele moderne.Nici bazele de date,nu
sunt altceva decat niste containere simple,in care se organizeaza obiecte
de tip tabel.Fiecare program editor,utilizeaza reguli diferite pentru
organizarea interna a tabelelor din baza de date,motiv pentru care fiecare
tip de baza de date are o extensie diferita.Pentru ca doua baze de date
editate cu programe diferite se fie compatibile,trebuie sa existe un pro-
gram intermediar,de conversie,care va prelua sau edita tabelele din baza
de date,indiferent de regula lor de ordonare interna.Pentru a putea crea
astfel de programe de conversie (drivere),dar si pentru alte scopuri,
exista o serie intreaga de structuri de date,proiectate special pentru a
putea organiza orice fel de grup de date de acelasi fel.Aceste structuri
poarta numele de colectii si sunt un fel de containere in care se pot
grupa orice fel de obiecte,identice sau neidentice.In plus,pentru a putea
asigura o flexibilitate si mai mare,limbajul Java accepta si un tip de
clase,denumite clase generice,in care tipul de data cu care se lucreaza
poate fi declarat doar in momentul in care se construieste un obiect din
clasa respectiva.Cu alte cuvinte,clasa este un sablon general ce poate fi
adaptat pentru orice tip de data,iar obiectul construit va fi limitat doar
la tipul de data din declaratie.Cu ajutorul unei astfel de clase,se pot
grupa si organiza (sorta,selecta,filtra etc.) obiecte ce contin tipuri
de data complet diferite.Acest gen de obiecte,nu numai ca ofera o alter-
nativa pentru bazele de date si tabele,dar pot asigura si compatibilitatea
dintre obiectele noi si obiecte de tip mai vechi,scoase din uz.De exemplu,
in cazul platformei Java colectiile de tip mai vechi erau: Vector,Array,
Hashtable si Enumeration.Pentru a putea alimenta un tabel de date nou,cu
date preluate dintr-o colectie de tip Vector,se va putea implementa o
colectie noua,ce asigura compatibilitatea si conecteaza colectia la tabel.
In mod curent,clasele si interfetele generice se utilizeaza mai ales in
cazul interfeteleor de tip "Collecttion",motiv pentru care este mai simplu
sa fie prezentate impreuna.
Clasele generice sunt clase ce pot fi declarate fara un parametru tipi-
zat.Pentru a putea fi recunoscute de compilator,aceste clase se declara cu
paranteze unghiulare in locul celor rotunde.
EXEMPLU: in loc de class Box(String s)... se va utiliza class Box<T>
Prin conventie,parametrul este specificat printr-o singura litera.Nu
exista o regula stricta (se poate utiliza orice litera doriti),dar in mod
curent aceasta litera are urmatoarea seminificatie:
E - Element
K - Key
N - Number
T - Type
V - Value
S,U,V... - 2nd,3rd,4th types...etc.
Cand se construieste obiectul,parametrul va contine tipul de data dorit.

-116-
Mai mult decat atat,tipul generic poate fi utilizat atat pentru decla-
rarea constructorului clasei,cat si pentru unele dintre metodele sale.Ca
rezultat,metoda respectiva va putea accepta tipuri diferite de data.
EXEMPLU:
public class Box<T> {
private T t;
public void sdd(T,t) { this.t = t; }
public T get() { return t; }
public <U> void inspect(U u) {
System.out.println("T: " + t.getClass().getName());
System.out.println("U: " + u.getClass().getName());
}
public static void main(String[] args) {
Box<Integer> integerBox = new Box<Integer>();
integerBox.add(new Integer(10));
integerBox.inspect("some text");
Box<Double> doubleBox = new Box<Double>();
doubleBox.add( new Double(3.1415));
doubleBox.inspect(2.71);
}
}
-salvati fila cu numele Box.java si compilati.Executati fila.
In exemplul de mai sus,se declara o clasa de tip generic,iar in functia
main se apeleaza constructorul,recursiv,pentru a crea doua obiecte,dintre
care primul va fi de tip Integer,iar cel de al doilea va fi de tip Double.
Apoi se utilizeaza metodele fiecarui obiect,pentru a putea evalua rezulta-
tul returnat,in contextul fiecarui tip de data.
Trebuie remarcat faptul ca in obiectele derivate dintr-o clasa generica
parametrul precizat la declarare poate fi orice tip de data,orice varia-
bila sau obiect,cu exceptia tipurilor primare (Exemplu: nu se pot utiliza
valori numerice directe).
In exemplul de mai sus,daca incercati o formula de genul"
integerBox.add(10) in loc de integerBox.add(new Integer(10)),se va
returna un mesaj de eroare in momentul compilarii.Cu alte cuvinte,para-
metrul precizat in momentul declaratiei trebuie sa fie un obiect.In cazul
variabilelor se construieste un obiect din tipul respectiv (colectia
trebuie sa contina obiecte,nu poate grupa valori directe).
Se observa cu usurinta avantajele claselor generice.Nu numai ca se
pot adapta la orice tip de data,dar pot decela inca din etapa de compilare
erorile de format,ce nu sunt depistate in mod curent decat in etapa
de executie.De exemplu,daca utilizati o clasa obisnuita,compilatorul nu
va putea evalua ca eroare,tentativa de a adauga in colectie un numar
direct.
In exemplul de mai sus,clasa generica este exploatata direct in functia
main(),dar in mod normal aceste clase se declara si se compileaza separat,
pentru a putea fi apelate si utilizate din cat mai multe aplicatii.
Nu este obligatoriu ca o clasa generica sa accepte orice tip de data.
Pentru a restrange valorile acceptate doar la un anumit subgrup de tipuri
de data,se poate utiliza un parametru limitat (bounded parameter),declarat
prin extends.
EXEMPLU: public <U extends Number> void inspect(U u) { ....

-117-
In acest caz,obiectele derivate din acest tip generic nu vor putea
avea ca parametru decat unul dintre tipurile de data derivate din Number,
adica: AtomicInteger,AtomicLong,BigDecimal,BigInteger,Byte,Double,Float,
Integer,Long,Short.Tentativa de a apela metoda cu un parametru de tip
Strig (de exemplu),va returna un mesaj de eroare.
Cu alte cuvinte,cu cat tipul declarat se afla in fruntea unei ierarhii
mai mari de subtipuri derivate,cu atat clasa generica respectiva,si meto-
dele sale,vor putea accepta mai multe tipuri de date(respectiv toate sub-
tipurile).Forma cea mai generala de clasa generica utilizeaza tipul Object
deoarece toate tipurile din java au acest ancestor comun.
Pentru declararea unui tip,se pot utiliza si caracterele cu sens gene-
ral (wildcards),cum sunt ?,*...etc.In acest caz,caracterul respectiv va
tine locul unei litere,oricarui caracter alfa-numeric...etc.
EXEMPLU: Box<? extends Number> box = .....
inseamna ca tipul clasei este necunoscut,dar ca este un subtip al
tipului Number,eventual chiar tipul Number.
Box<*> box =.....
inseamna ca tipul este complet necunoscut si urmeaza sa fie specificat
in momentul apelarii constructorului.
Dupa ce se creaza o instanta a unei clase generice,compilatorul face
o serie de conversii interne pentru a premite compatibilitatea cu diverse
alte structuri din program.Ca rezultat,nu se poate utiliza tipul clasei
generice pentru a crea obiecte sau instante ale unei interfete,deoarece
compilatorul a stres din memorie informatia despre tipul generic (Type
Erasure).Mai exact,a inlocuit informatia despre tipul de data cu o struc-
tura noua,ce nu poate fi apelata in timpul executiei.Din acest motiv,orice
tentativa de a apela tipul generic va returna un mesaj de eroare.
EXEMPLE: public class MyClass<E> {
public static void myMethod(Object item) {
if (item instanceof E) { -returneaza eroare !
.....
E item2 = new E(); -returneaza eroare !
E[] iArray = new E[10]; -returneaza eroare !
E obj = (E)new Object(); -returneaza eroare !
....etc.
Tipurile generice reprezinta piatra de temelie pentru structurile mai
complexe de tip colectie.Pentru o mai buna intelegere a acestor notiuni,
este utila si putina istorie.In epoca de pionierat a tehnicii de calcul,
toate datele se arhivau sub forma de stiva.Pentru ca sa poata fi incluse
in stive,datele trebuiau sa fie formatate intr-un anumit fel (de obicei
binar in format de 4,8,16,32 de biti etc.).Ca rezultat,pentru fiecare tip
de data,trebuia sa existe un anumit tip de stiva.La fel se facea si orga-
nizarea interna a datelor.Memoria de operare,era fragmentata in numeroase
astfel de stive (tampoane de memorie) in care erau arhivate datele tempo-
rare.Colectiile,nu sunt decat niste structuri asemanatoare,menite sa arhi-
veze datele temporar,dar spre deosebire de stive,au o structura interna
elastica,ce se "muleaza" pe tipul de data utilizat.Astfel,in loc sa existe
cate un tampon de memorie specializat pentru fiecare tip de data,cu aju-
torul tipurilor generice se pot crea tampoane de memorie capabile sa arhi-
veze orice tip de data (inclusiv obiecte mari sau interfete grafice).Se
face astfel economie de memorie si se reduce numarul de operatii/proces.

-118-
Colectiile sunt de fapt obiecte de tip container,proiectate sa poata
grupa si organiza mai multe structuri de date,intr-o singura unitate.Se
utilizeaza pentru a arhiva datele temporar,dar si pentru a executa o serie
intreaga de operatii de sortare si filtrare,sau agregare,etc.In mod tipic
se utilizeaza pentru a grupa date de acelasi fel,sau tipuri compatibile,
astfel incat sa se poata opera asupra lor prin metode globale.Sub o forma
sau alta,structurile de tip colectie exista in toate limbajele de progra-
mare (stive,arii de date,vectori,tabele de pointeri etc.),dar limbajul
Java implementeaza un numar foarte mare de astfel de structuri,cu functio-
nalitati complexe,menite sa simplifice orice tip de operatii posibile.In
Java,toate aceste structuri formeaza o arhitectura denumita "retea de
colectii" (collections frameworks),in care sunt incluse o serie intreaga
de interfete,clasele in care sunt implementate aceste interfete,precum si
o serie intreaga de algoritmi specifici.Interfetele sunt tipul abstract,
adica sablonul initial utilizat pentru a crea structurile necesare.Imple-
mentarile,sunt clasele in care au fost dezvoltate aceste interfete,iar
algoritmii sunt metodele prin care se executa operatiile de nivel inferior
(sortare,filtrare,agregare,eradicare etc.).
Colectiile nu numai ca simplifica munca de programare,dar au si rolul
de a compartimenta structurile din program in module distincte.Ca rezultat
orice eroare de executie sau operatie defectiva,va fi limitata la un anu-
mit modul,fara sa afecteze restul programului.Programele vor fi mult mai
usor de conceput (se programeaza fiecare modul separat) si de depanat.In
plus,structurile de tip colectie pot asigura compatibilitatea cu structuri
de date mai vechi (inclusiv cu stivele binare),pentru a permite utilizarea
unor arhive de date mai vechi,fara reformatarea datelor.
Pentru a facilita compatibilitatea dintre structuri,colectiile sunt
organizate si dezvoltate ierarhic,la fel ca si restul obiectelor din Java.
In capul listei,ancestorul absolut il reprezinta interfata Collection<E>
si respectiv obiectele ce implementeaza aceasta interfata: AbstractCollec-
tion,AbstractList,AbstractQueue,AbstractSequentialList,AbstractSet,Array-
BlockingQueue,ArrayDeque,ArrayList,AttributeList,BeanContextServices-
Support,ConcurrentLinkedQueue,ConcurentSkipListSet,CopyOnWriteArrayList,
CopyOnWriteArraySet,DelayQueue,EnumSet,HashSet,JobStateReasons,LinkedBlo-
ckingDeque,LinkedBlockingQueue,LinkedHashSet,LinkedList,PriorityBlocking-
Queue,PriorityQueue,RoleList,RoleUnresolvedList,Stack,SynchronousQueue,
TrySet,Vector.
Din interfata Collection au fost derivate urmatoarele sub-interfete:
BeanContext,BeanContextServices,BlockingQueue<E>,BlockingDeque<E>,Deque<E>
List<E>,NavigableSet<E>,Queue<E>,Set<E>,SortedSet<E>.
Fiecare dintre clasele de mai sus,implementeaza una sau mai multe
dintre aceste interfete,simultan.Ca rezultat,obiectele derivate din aceste
clase vor putea mosteni functionalitatea acestor interfete.In functie de
interfetele implementate,exista o serie de deosebiri de la un obiect la
altul: unele nu accepta decat obiecte unice,in timp ce altele accepta si
clone identice,unele nu permit operatii de sortare in timp ce altele sunt
concepute special pentru acest scop...etc.Nu se poate face o descriere
exhaustiva a tuturor acestor clase.Este insa esential sa intelegeti modul
in care sunt organizate,pentru a putea naviga cu usurinta prin documenta-
tia tehnica (vezi manualul Help).In mod curent,nu se utilizeaza decat
clasele in care interfetele au fost deja implementate.

-119-
Dintre interfetele de tip Collection,cele mai frecvent utilizate sunt:
Set si SortedSet,List si Queue.
Set este un tip de colectie ce nu accepta elemente duplicate si maxim
un singur element nul.Pe langa metodele mostenite de la Collection contine
si metode proprii pentru a introduce si extrage elemente,pentru a verifica
prezenta unui element oarecare si pentru a numara elementele continute.
Doua colectii de tip Set sunt egale,daca contin exact aceleasi elemente.
Se pot utiliza pentru a copia date de la o adresa la alta.Pentru simplifi-
carea implementarii,este recomandabil sa utilizati una dintre clasele ce
implementeaza aceasta interfata: EnumSet,HashSet,TreeSet...etc.
EXEMPLU:
import java.util.*;
public class Set1 {
public static void main(String[] args) {
Set<Integer> s = new HashSet<Integer>();
for (Integer x=0;x<20;x++)
s.add(new Integer(x));
System.out.println(s);
}
}
-salvati fila cu numele Set1.java.Compilati si executati.
In exemplul se mai sus,se construieste colectia,se introduc elemente,
apoi se afiseaza continutul colectiei.
Pentru a verifica daca un anumit element este continut in colectie se
poate utiliza un algoritm de genul:
EXEMPLU:
import java.util.*;
public class Cauta {
public static void main(String[] args) {
Set<Integer> s = new HashSet<Integer>();
for (Integer x=0;x<20;x++);
s.add(new Integer(x));
System.out.println(s.contains(new Integer(7)));
}
}
-salvati cu numele Cauta.java,compilati si executati exercitiul
Pentru a verifica daca un element oarecare este duplicat,se poate
exploata si parameterul String[] din functia main().
EXEMPLU:
import java.util.*;
public class Duplicate {
public static void main(String[] args) {
Set<String> s = new HashSet<String>();
for (String a : args)
if (!s.add(a))
System.out.println("Cuvantul: " + a + " este preexistent !");
System.out.println(s.size()+" cuvinte distincte: " + s);
}
}
-slavati fila cu numele Duplicate.java si compliati fila.
Executati fila cu comanda: java Duplicate am venit am vazut am invins

-120-
Exemplul de mai sus,speculeaza faptul ca Set nu accepta elemente iden-
tice si utilizeaza parametrul de tip String al functiei main(),pentru a
accepta valorile ce urmeaza sa fie incluse in colectie.Repetati exemplul
pentru orice propozitie sau grup de caractere,redundante sau unice.
Intr-o colectie,metodele pot fi subimpartite in trei grupe:
-operatii de baza cum sunt: isEmpty(),contains(),add() si remove()
-operatii brute (bulk): containsAll(),addAll(),removeAll(),retainAll()
-operatii asupra ariilor: toArray()
Operatiile de baza sunt cele obligatorii pentru orice colectie.Cele
brute sunt cele ce actioneaza global asupra tuturor elementelor din co-
lectie,iar cele de tip arie permit ca elementele unei colectii sa poata
fi transferate intr-o variabila de tip arie(pentru a asigura compatibi-
litatea cu datele editate in format mai vechi).
Pentru a putea executa operatii asupra unui element oarecare dintr-o
colectie,este important modul in care se navigheaza in interiorul unei
colectii.Nu exista o solutie unica,ci exista grupuri de solutii posibile.
Cea mai simpla solutie,utilizeaza o bucla de tip For...sau For...each.
EXEMPLU:
import java.util.*;
public class Set2 {
public static void main(String[] args) {
Set<Integer> s = new HashSet<Integer>();
for (Integer x=0;x<20;x++);
s.add(new Integer(x));
for (Object o: s)
System.out.println(o);
}
}
-salvati fila cu numele Set2.java.Compilati si executati.
Prima bucla FOR introduce datele in colectie,iar cea de a doua citeste
colectia element cu element.
Exista si o interfata specializata pentru navigarea prin colectii,cu
numele de Iterator<E>.Pentru comoditate,se poate utiliza una dintre cla-
sele ce implementeaza aceasta interfata,cum este de exemplu,clasa Scanner.
EXEMPLU:
import java.util.*;
public class Scaner {
public static void main(String[] args) {
String sir1 = "unu,doi,trei,patru,cinci,sase,sapte";
Scanner sc = new Scanner(sir1);
for (Integer x=0;x<6;x++)
System.out.println(sc.next());
}
}
-salvati fila cu numele Scaner.java.compilati si executati.
Interfata de tip Iterator contine metodele hasNext(),next() si remove()
iar clasa Scanner adauga si un set complet de metode pentru navigatie.In
exemplul de mai sus,am utilizat doar metoda next(),dar obiectul contine
un set intreg de metode ce permit solutii estrem de personalizate sau
discriminative de navigare in colectie.Este esential insa sa alegeti
metodele cele mai potrivite pentru tipul de data din colectie.

-121-
import java.util.*;

public class Set3 {


public static void main(String[] args) {
Set<Integer> s = new HashSet<Integer>();
for (Integer x=0;x<20;x++)
s.add(new Integer(x));
String sir1 = String.valueOf(s);
Scanner sc = new Scanner(sir1);
for (integer x=0;x<20;x++)
System.out.println(sc.next());
}
}
-salvati fila cu numele Set3.java.Compilati si executati.
Observati ca pentru a conecta obiectul Scanner la colectie,am utilizat
un String intermediar (am convertit toate valorile numerice la valori de
tip String).Aceasta solutie este foarte simpla atunci cand dorim doar sa
parcurgem si sa afisam colectia.In cazul in care datele trebuie analizate
prin formule complexe,sau trebuiesc filtrate,aceasta solutie nu mai este
adecvata,deoarece nu se va mai putea face distinctia dintre o valoare de
tip Integer,Float,Double sau String.
Din punct de vedere matematic,colectiile sunt niste simple multimi.Cu
ajutorul metodelor brute (addAll(),removeAll() si retainAll()) se pot
executa operatiile simple de sumatie,scadere sau intersectie.
EXEMPLU:
import java.util.*;

public class Set4 {


public static void main(String[] args) {
Set<Integer> s1 = new HashSet<Integer>();
for (Integer x=0;x<10;x++)
s1.add(new Integer(x));
Set<Integer> s2 = new HashSet<Integer>();
for (Integer x=7;x<17;x++)
s2.add(new Integer(x));
System.out.println("Prima colectie = " + s1);
System.out.println("A doua colectie = " + s2);
s1.removeAll(s2);
System.out.println("Scazut s2 din s1 = " + s1);
s1.addAll(s2);
System.out.println("Adaugat s2 la s1 = " + s1);
s1.retainAll(s2);
System.out.println("Extras s2 din s1 = " + s1);
}
}
-salvati fila cu numele Set4.Compilati si executati.
Exista numeroase situatii in care utilizeaza perechi de colectii,in
care se executa operatii diferite,apoi se apeleaza metodele brute pentru
a executa operatii cu colectiile in intregime.De exemplu,daca doriti sa
salvati si apoi sa interpretati toate comenzile introduse de la tastatura,
sau daca doriti sa analizati o astfel de comanda.
-122-
EXEMPLU:
import java.util.*;

public class Duplicate2 {


public static void main(String[] args) {
Set<String> unice = new HashSet<String>();
Set<String> duplicate = new HashSet<String>();
for (String a : args)
if(!unice.add(a))
duplicate.add(a);
unice.removeAll(duplicate);
System.out.println("Cuvinte unice: " + unice);
System.out.println(Duplicate: " + duplicate);
}
}
-salvati fila cu numele Duplicate2.java.Compilati si executati cu:
java Duplicate2 am venit am vazut am invins
In exemplul de mai sus,orice cuvant care se repeta va fi introdus in
colectia "duplicate".Inainte de a fi afisate,se extrag din colectia
"unice",toate elementele din colectia "duplicate".
Prin operatii multiple de acest gen,se pot realiza diversi algoritmi
pentru sortarea,filtrarea sau prelucrarea datelor.
Interfata Set se preteaza doar pentru organizarea unor "seturi" simple
de elemente nesortate.Pentru operatii mai complexe,se poate utiliza o
intefata de tip SortedSet,respectiv unul dintre obiectele ce implementeaza
aceasta interfata.Un astfel de obiect extrem de comod,este TreeSet,in care
sunt implementate cinci interfete: Serializeable,Iterable<E>,Collection<E>
NavigableSet<E>,Set<E> si SortedSet<E>.Fiecare interfata aduce un set nou
de metode,astfel ca obiectul este foarte maleabil.
EXEMPLU:
import java.util.*;

public class Set5 {


public static void main(String[] args) {
TreeSet<String> s1 = new TreeSet<String>();
s1.add(new String("text1"));
s1.add(new String("abcdefg"));
s1.add(new String("documentul1"));
s1.add(new String("valoare3"));
s1.add(new String("valoare1"));
System.out.println(s1);
System.out.println("Primul element este: "+s1.first());
System.out.println("Ultimul element este: "+s1.last());
System.out.println("Cel mai mare element,mai mic decat valoare1 este:");
System.out.println(s1.floor(new String("valoare")));
}
}
-salvati fila cu numele Set5.java.Compilati si executati.
Observati ca elementele din colectie sunt sortate automat,in functie de
ordinea lor naturala (alfabetic in cazul string-urilor).Pentru a schimba
criteriul de sortare,se poate declara un comparator (un obiect Collator).
-123-
Pentru sortarea elementelor in functie de criteriul natural,obiectul
de tip TreeSet va utiliza o interfata de tip Comparable<T>,iar pentru
sortarea elementelor cu ajutorul unui comparator,va utiliza un obiect
ce implementeaza o interfata de tip Comparator<T>.
In Java,fiecare obiect are un cod numeric intern,ce poate fi obtinut
cu ajutorul metodei Object.hashCode().Acest cod este utilizat in toate
secventele de ordonare si sortare a datelor.Pentru a schimba pozitia din
colectie,obiectul care executa operatia de sortare va modifica acest cod
intern,in functie de un algoritm oarecare.Pentru a intelege acest cod,
este bine sa faceti cateva exercitii ajutatoare,de genul:
EXEMPLU:
import java.util.*;

public class Set6 {


public static void main(String[] args) {
String s1 = new String("A");
System.out.println(s1.hashCode());
String s2 = new String("B");
System.out.println(s2.hashCode());
String s3 = new String("Z");
System.out.println(s3.hashCode());
String s4 = new String("a");
System.out.println(s4.hashCode());
String s5 = new String("0");
System.out.println(s5.hashCode());
String s6 = new String("1");
System.out.println(s6.hashCode());
String s7 = new String("10");
System.out.println(s7.hashCode());
String s8 = new String("100");
System.out.println(s8.hashCode());
}
}
-salvati fila cu numele Set6.java.Compilati si executati exercitiul.
Obiectele de tip String sunt cel mai usor de analizat.Incercati sa
inlocuiti literele prin cuvinte intregi sau propozitii si reanalizati
exemplul.Apoi,utilizati obiecte din ce in ce mai complexe,in locul celor
de tip string,si analizati codul numeric intern al fiecarui obiect.
Dupa ce aveti un model clar de lucru,puteti concepe algoritmi perso-
nalizati,prin care sa puteti executa orice tip de operatii asupra unui
obiect,sau grup de obiecte dintr-o colectie.
Nu are rost sa creati un comparator nou,decat atunci cand ordonarea
in functie de criteriul natural nu poate satisface necesitatile din pro-
gram.Crearea unui obiect de tip comparator prezinta insa avantajul ca
permite proiectarea unor tipuri de selectie ce nu pot fi realizate intr-o
baza de date cu ajutorul comenzilor de tip SQL.De exemplu,se pot programa
filtre complexe,ce intereseaza doar grupuri si subgrupuri de elemente din
colectie,sau poate organiza elementele unei colectii in functie de codul
numeric intern al unor obiecte din alta colectie (obiecte de alt tip),etc.
Pentru comoditatea in proiectare si depanare,este recomandabil ca
obiectul comparator sa fie in acelasi modul cu obiectul de tip colectie.

-124-
EXEMPLU:
import java.util.*;

public class Set7 {


public static void main(String[] args) {
String s = new String();
TreeSet<String> s1 = new TreeSet<String>(new Comparator1(s));
s1.add(new String("text1"));
s1.add(new String("abcdefg"));
s1.add(new String("documentul1"));
s1.add(new String("valoare3"));
s1.add(new String("valoare1"));
System.out.println(s1);
}
}

class Comparator1 implements Comparator<String> {


private final String sir1;
private final String sir2 = "control";
public Comparator1(String sir1) {
if (sir1 == null) throw new NullPointerException();
this.sir1 = sir1;
}
public int compare(String sir3,String sir4) {
return sir1.hasCode() - sir2.hashCode();
};
public boolean equals(Object o) {
return false;
};
}
-salvati fila cu numele Set7.java.Compilati si executati.
Comparati exemplul cu exercitiul Set5 si observati ordinea in care
sunt sortate elementele.Pentru a declara un comparator nou,se poate crea
o clasa noua,ce implementeaza o intefata de tip Comparator<T>,sau se
poate utiliza direct un obiect de tip Collator sau RuleBasedCollator.
In primul caz,trebuie redefinit constructorul si cele doua metode:
compare() si equals().In cel de al doilea caz,se pot utiliza direct
proprietatile si metodele obiectului de tip Collator.Obiectul Collator,
prezinta si urmatorul avantaj: -cu ajutorul metodei setStrength(),se
poate specifica gradul de discriminare pe care il va utiliza obiectul,
atunci cand va compara doua elemente din colectie.Acest grad de discrimi-
nare poate fi : PRIMARY (exemplu intre "e" si "f"),SECONDARY (exemplu
intre "e" si "e" cu accent),TERTIARY (exemplu intre "e" si "E") sau
IDENTICAL (exemplu intre "e" si "e").Prin acest mecanism,este posibil
ca obiectul sa nu faca distinctia dintre majuscule si minuscule,sau
chiar dintre caracterele accentuate si neaccentuate.
EXEMPLU: Collator.setStrenght(Collator.PRIMARY)
nu va mai putea face distinctia dintre "abc" si "ABC"
In plus,obiectul Collator poate fi comparat direct cu un alt obiect de
tip Collator,cu ajutorul metodei equals(Object that).Pentru o singura
colectie,se pot utiliza si mai multi comparatori,inlocuiti interactiv.

-125-
O alta interfata derivata din Collection<E>,este interfata List<E>.Nu
trebuie confundata cu clasa List din pachetul AWT,sau cu clasa JList din
pachetul Swing,chiar daca implementeaza metode destul de asemanatoare.
Interfata List<E> se utilizeaza pentru a implementa obiecte de tip
colectie in care elementele sunt arhivate intr-o lista ordonata.Fiecare
element este insotit de un numar de indexare,astfel incat sa poata fi
manipulat cu ajutorul acestui numar de indexare.Programatorul poate con-
trola cu precizie locatia la care va fi arhivat fiecare element din lista,
sau poate apela orice element,in functie de pozitia sa.Spre deosebire de
seturi,listele pot contine si elemente perfect identice (identificate doar
prin numarul de indexare).Deasemenea,listele pot contine un numar nelimi-
tat de elemente nule.Pentru navigare,interfata List ofera si un iterator
specializat,denumit ListIterator.
Exista mai multe clase ce implementeaza interfata List.Dintre acestea
cel mai comod se lucreaza cu clasa Vector.
EXEMPLU:
import java.util.*;

public class Vector1 {


public static void main(String[] args) {
String s=new String();
Vector<String> v1 = new Vector<String>();
v1.add(new String("text1"));
v1.add(new String("abcdefg"));
v1.add(new String("documentul1"));
v1.add(new String("valoare3");
v1.add(new String("valoare1"));
System.out.println(v1);
System.out.println("Al doilea element este: "+v1.elementAt(1));
}
}
-salvati fila cu numele Vector1.java.Compilati si executati.
Observati ca spre deosebire de SortedSet,interfata List nu sorteaza
automat elementele,in schimb permite accesul direct la oricare dintre
elemente,la fel ca si intr-o arie de date.De fapt,orice clasa in care se
implementeaza interfata List,este perfect compatibila cu datele de tip
Array.Se poate utiliza o arie de date,pentru a initializa o lista,pentru
a adauga sau extrage elemente in si din lista,sau pentru a face diverse
alte tipuri de operatii cu grupuri de elemente.
Clasa Vector,nu numai ca include toate metodele necesare,dar asigura
si compatibilitatea cu programele mai vechi.In plus,clasa vector imple-
menteaza inca alte cinci interfete: Serializable,Cloneable,Iterable<E>,
Collection<E> si RandomAccess,pentru a adauga si functionalitati noi.De
exemplu,RandomAccess permite ca orice element sa poata fi accesat aleator
(spre deosebire de stive,unde elementele trebuie incluse sau extrase in
ordine,unul cate unul).
Exista si o clasa derivata din Vector,in care se includ si metode
specifice pentru stive.Acesta clasa se numeste Stack si adauga metodelor
din Vector inca 5 metode specifice pentru stive: empty(),peek(),pop(),
push() si search(),necesare pentru operatii de tip LIFO(last-in-first-out)
Clasa Stack<E>,poate functiona atat ca vector,cat si ca stiva.

-126-
Asemanatoare cu Vector este si clasa ArrayList,care include cam ace-
leasi metode,dar nu este sincronizata (fenomenul de sincronizare are
importanta doar atunci cand obiectul primeste informatii simultane de la
mai multe thread-uri ce sunt procesate paralel).
Obiectele de acest gen,se pot utiliza pentru a arhiva temporar grupuri
mai mici sau mai mari de date.De exemplu,in procesul de depanare a unei
aplicatii,poate fi util sa cititi o fila de tip text,rand cu rand,pana
cand identificati sediul erorii.
EXEMPLU:
import java.util.*;
import java.io.*;

public class FileList {


public static void main(String[] args) {
final int assumedLineLength = 50;
File file = new File(args[0]);
List<String> fileList =
new ArrayList<String>((int)(File.length()/assumedLineLength)*2);
BufferedRead reader = null;
int lineCount = 0;
try {
reader = new Bufferedreader(new FileReader(file));
for (String line = reader.readLine(); line != null;
line = reader.readLine()) {
fileList.add(line);
lineCount++;
}
} catch (IOException e) {
System.err.format("Could not read %s: %s%n",file,e);
System.exit(1);
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e){}
}
}
int repeats = Integer.parseInt(args[1]);
for (int i=0; i<repeats;i++) {
System.out.format("%d: %s%n",i,fileList.get(i));
}
}
}
-salvati fila cu numele FileList.java.Compilati si executati.
Pentru a citi date dintr-o fila de tip text,trebuie sa includeti in
comanda numele filei si numarul de randuri.
EXEMPLU: java FileList FileList.java 5
va citi primele 5 randuri din fila sursa (FileList.java)
Puteti utiliza aceasta secventa,atunci cand scrieti un program de
analiza automata a filelor sursa (parser),sau atunci cand doriti sa pre-
luati doar titlul,sau fragmente limitate din filele sursa...etc.

-127-
O lista poate fi generata si cu ajutorul unei arii de date.De exemplu,
metoda asList() din clasa Arrays,genereaza o interfata de tip List<E>,in
care include automat elementele din aria specificata ca parametru.
EXEMPLU:
import java.util.*;

public class Sort {


public static void main(String[] args) {
List<String> list = Arrays.asList(args);
Collections.sort(list);
System.out.println(list);
} }
-salvati fila cu numele Sort.java.Compilati si executati cu comanda:
EXEMPLU: java Sort text ce urmeaza sa fie sortat alfabetic
Pentru sortarea elementelor,exercitiul utilizeaza metoda sort,din clasa
Collections.Aceasta clasa (nu trebuie confundata cu interfata Collection)
contine o serie intreaga de metode statice,destinate pentru operatii in
sau asupra colectiilor de date.Clasa Collections nu are constructor,asa
ca nu se pot construi obiecte din acest tip.Se pot utiliza doar metodele
sale,apelate cu Collections.numelemetodei.
Ultimul tip de interfete derivate din Collection,sunt cele destinate
pentru operatii cu stive: Queue si Deque.Pentru fiecare dintre ele,exista
mai multe clase in care sunt implementate.Operatiile specifice stivelor,
se executa prin introducerea si extragerea elementelor,in ordine,unul
cate unul,dupa regula LIFO (ultimul introdus este primul extras).Fiecare
clasa are un set propriu de metode.Majoritatea obiectelor nu mai sunt
limitate la functionalitatea de tip stiva,ce permit operatii cu acces
aleatoriu,asupra oricarui membru din colectie.Un mecanism tipic,implica
popularea stivei cu elemente si apoi extragerea progresiva a primului
element din stiva (capul stivei).
EXEMPLU:
import java.util.concurent.*;
public class Stiva1 {
public static void main(String[] args){
ArrayBlockingQueue<Integer> s = new ArrayBlockingQueue<Integer>(20);
for (Integer x=0;x<10;x++)
s.add(new Integer(x));
for (Integer x=0;x<10;x++)
System.out.println(s.remove());
}
}
-salvati fila cu numele Stiva1.java.Compilati si executati.
Acest exemplu,utilizeaza un obiect de tip ArrayBlockingQueue.Alte clase
utile sunt:ArrayDeque,DelayQueue,LinkedList,PriorityQueue,SynchronousQueue
etc.Majoritatea acestor clase,implementeaza doua sau mai multe interfete,
astfel incat sa combine functionalitatea stivei cu ce a unui obiect de
tip Set,sau de tip List.Se utilizeaza mai ales pentru compatibilitatea
dintre diverse tipuri de date.Exemple: datele din stive pot fi copiate
in liste sau seturi,seturile in liste,ariile de date in liste...etc.
Colectiile nu arhiveaza datele decat temporar,adica functioneaza pe
post de tampoane de memorie pentru memoria de operare.

-128-
Toate colectiile prezentate pana acum,au ca ancestor interfata Collec-
tion.Exista si un al doilea tip de colectii,denumite Map (map = a impere-
chea).Aceste colectii,au ca ancestor primordial Interfata Map si accepta
cate doi parametri interconectati intre ei.Primul parametru poarta numele
de cheie (Key) iar cel de al doilea poarta numele de valoare (Value).
Pentru fiecare cheie poate exista o singura valoare.Pot exista insa
mai multe chei,cu aceeasi valoare.Fiecare dintre cei doi parametrii este
de tip generic,astfel ca poate accepta orice tip de data.Ca rezultat,se
poate face conexiunea dintre orice tip de obiect,cu orice tip de data.
Din Map<K,V> au fost dezvoltate urmatoarele interfete specializate:
Bindings,ConcurrentMap<K,V>,ConcurrentNavigableMap<K,V>,LogicalMessage-
Context,MessageContext,NavigableMap<K,V>,SOAPMessageContext,SortedMap<K,V>
si urmatoarele clase,in care se implementeaza una sau mai multe dintre
interfete:AbstractMap,Attributes,AuthProvider,ConcurrentHashMap,Concurrent
SkipListMap,EnumMap,HashMap,HashTable,IdentityHashMap,LinkedHashMap,Prin-
terStateReasons,Properties,Provider,RenderingHints,SimpleBindings,Tabular-
DataSupport,TreeMap,UIDefaults,WeakHashMap.
Dintre acestea,cele mai uzitate sunt:HashMap,TreeMap si LinkedHashMap.
EXEMPLU:
import java.util.*;

public class Map1 {


public static void main(String[] args) {
Map<String,Integer> m = new HashMap<String,Integer>();
m.put("Numele:",1);
m.put("Mihai",2);
m.put("Stefan",3);
m.put("Mihai",4);
m.put("Victor",5);
System.out.println(m.size() + " cuvinte distincte: ");
System.out.println(m);
}
}
-salvati exercitiul cu numele Map1.java.Compilati si executati.
Observati ca pentru cheia "Mihai",valoarea a fost actualizata automat.
Pentru a accepta valori de la tastatura,modificati exercitiul astfel:
EXEMPLU:
import java.util.*;

public class Map2 {


public static void main(String[] args) {
Map<String,integer> m = new HashMap<String,Integer>();
for (String a : args) {
Integer freq = m.get(a);
m.put(a,(freq == null) ? 1 : freq + 1);
}
System.out.println(m.size() + " cuvinte distincte:");
System.out.println(m);
} }
-salvati fila cu numele Map2.java.Compilati si executati cu:
java Map2 am venit am vazut am invins

-129-
Daca doriti ca elementele din colectie sa fie sortate automat,inlocuiti
clasa HashMap prin TreeMap.Elementele vor fi sortate in functie de crite-
riul lor natural.Daca doriti sa utilizati un alt criteriu pentru sortarea
datelor,va trebui sa definiti un Comparator.Este insa mult mai simplu sa
alegeti pentru cheie tipul de data cel mai convenabil.De exmplu,pentru
a organiza un set de date in ordine numerica,puteti utiliza pe post de
cheie o valoare de tip Integer.
EXEMPLU:
import java.util.*;

public class Map3 {


public static void main(String[] args) {
Map<Integer,String> m = new TreeMap<Integer,String>{};
m.put(1,"Numele:");
m.put(5,"Mihai");
m.put(3,"Stefan");
m.put(2,"Mihai");
m.put(4,"Victor");
System.out.println(m.size() + " cuvinte distincte: ");
System.out.println(m);
}
}
-salvati fila cu numele Map3.java.Compilati si executati.
Observati sortarea automata,dar si faptul ca in acest caz pot exista
doua elemente cu valoarea "Mihai",conectate la alta cheie de indexare.
In continuare,studiati cu atentie fiecare obiect,pentru a evalua ce
interfete implementeaza si respectiv ce metode utilizeaza.La fel ca si
in cazul colectiilor simple,exista metode brute (bulk) ce opereaza simul-
tan asupra tuturor elementelor din colectie.Aceste metode se vor utiliza
pentru operatii cu multimi.
EXEMPLU : -pentru a afla cate elemente din colectia A se regasesc in
colectia B se poate utiliza metoda containsAll() .
In plus,fiecare clasa contine un set oarecare de metode destinate
pentru o anumita functionalitate.Cititi cu atentie documentatia fiecarei
clase,inainte de a deriva clase noi.Daca nici una dintre clasele standard
nu rezolva necesitatile d-voastra,alegeti clasa cea mai utila si apoi
extindeti aceasta clasa cu noi functionalitati.
Colectiile ofera o serie intreaga de avantaje :
-nu necesita o fila auxiliara si operatii de tip Intrare/Iesire (I/O)
-consuma un volum minim de memorie/operatie
-permit translatarea datelor intre structuri de date complet diferite
-nu necestia drivere,sau programe auxiliare
-pot executa automat,operatii complexe cu grupuri mari de date
-sunt extrem de utile pentru programele de tip parser (analiza datelor)
-sunt extrem de maleabile (se muleaza in functie de necesitati)
Dintre dezavantaje,cele mai importante sunt:
-nu arhiveaza datele decat temporar (se pot salva in file)
-nu pot fi exploatate din alte limbaje de programare
-nu permit conexiuni multiple intre elemente (decat cu filtre speciale)
Decizia intre colectii si baze de date,o va face fiecare programator,
in functie de numeroase criterii,sau in functie de experienta anterioara.

-130-
GRAFICA 2D
Mediul Java permite toate operatiile grafice posibile: desen,text,
preluare de imagini,filtrarea imaginilor,proiectii,imprimare etc.Pentru
a simplifica munca programatorului,Java include toate operatiile necesare
pentru identificarea dispozitivului grafic in clase speciale.Aceste clase
se gasesc in pachetul Abstract Windowing Toolkit(AWT),cu numele de:
Graphics si Graphics2D.
In general,grafica computerizata este ingreunata de urmatorul aspect:
fiecare dispozitiv grafic (imprimanta,monitor,scanner,aparat foto digital)
are un sistem diferit de reprezentare a imaginilor.Unele au un numar mai
mic sau mai mare de pixeli/cm patrat,altele organizeaza pixelii sub forma
de matrice,sau arii de date etc.Ca rezultat,atunci cand se vorbeste despre
spatiul grafic,se disting doua notiuni:
-spatiul clientului (user space) -este spatiul grafic utilizat de clientul
respectiv (este un spatiu logic format din coordonate logice)
-spatiul de dispozitiv(device space) -este spatiul grafic utilizat de dis-
pozitivul grafic (este spatiul real format din coordonate reale)
Nu intotdeauna exista o corespondenta perfecta intre modul in care
a fost programata o imagine si modul in care este reprezentata in dispo-
zitivul grafic periferic.Exemplu : imprimantele utilizeaza alt sistem de
organizare al pixelilor,decat monitoarele.Pentru ca imaginile sa poata fi
reprezentate,este necesar sa existe niste programe speciale in care se
face conversia datelor de la un format la altul.Aceste programe,poarta
numele de drivere si trebuie sa fie preinstalate(driver pentru imprimanta,
driver pentru camera foto,driver pentru monitor,etc.).
In majoritatea programelor anterioare,pentru a putea incepe o proiectie
grafica,era necesar sa fie precizat contextul de dispozitiv grafic.In Java
toate aceste operatii se executa automat.Clasele grafice identifica auto-
mat contextul de dispozitiv grafic corespunzator cu fereastra activa.Nu
mai este necesara nici o operatie pregatitoare.Este totusi necesar ca
proiectiile grafice sa fie facute intr-un spatiu compatibil : o fereastra
sau un alt obiect specializat.
In rest,grafica din Java este asemanatoare cu cea din orice alt limbaj
de programare.Trebuie remarcat insa faptul ca Java ofera un numar foarte
mare de interfete si clase specializate,astfel incat munca programatorului
se rezuma doar la alegerea clasei si a metodei dorite.
Nu exista o compatibilitate perfecta cu grafica din alte limbaje de
programare,decat in cazul componentelor de tip ActiveX,dar exista o
compatibilitate completa cu orice tip de resursa standardizata: file de
tip .bmp,.gif,.jpeg...etc.
Programatorul,utilizeaza spatiul de tip client (user space),pentru a
specifica operatiile dorite,cu ajutorul unui sistem de coordonate logice.
Acest sistem de coordonate,este independent de cel utilizat de fiecare
dispozitiv grafic.Pentru a realiza compatibilitatea cu orice tip de dis-
pozitiv,coordonalele logice,urmeaza sa fie proiectate in momentul execu-
tiei in spatiul de dispozitiv,pentru a forma coordonale reale,adica cele
utilizate efectiv.Din acest motiv,imaginea creata de programator va avea
un aspect diferit in functie de dispozitivul grafic utilizat pentru pre-
zentare (in functie de rezolutie,numar de culori si nuante,etc.).Pentru
a controla modul in care se face aceasta proiectie,Java utilizeaza o serie
de atribute: pen,fill,compositing,transform,clip,font etc.

-131-
Pentru reprezentarea imaginilor,trebuie utilizat un obiect de tip Gra-
phics,sau extensia sa Graphics2D.Obiectul Graphics ofera urmatoarele fa-
cilitati:
-detecteaza automat dispozitivul grafic
-are proprietati specifice pentru informatiile absolut necesare: obiectul
pe care se deseneaza,punctul de origine al translatiilor,culoarea curenta,
fontul,operatiile curente "pixel cu pixel" (gen XOR),daca exista operatii
de decupare (tip Clip),etc.
Clasa Graphics2D,este o extensie perfectionata ce permite un control
mult mai sofisticat al operatiilor de transformare a coordonatelor logice
in coordonate reale.Ori de cate ori este posibil,este preferabil sa utili-
zati aceasta clasa,atunci cand sunt necesare proiectii si operatii mai
complexe.Pentru reprezentarile foarte simple,este recomandabila clasa
Graphics (pentru a face economie de memorie).
Reprezentarea propriu zisa se face cu ajutorul unei metode paint().
Practic,se declara o fereastra,in care se include un obiect de tip Gra-
phics,apoi se apeleaza metodele acestui obiect si se prezinta cu paint().
EXEMPLU:
import java.awt.*;
import java.awt.event.*;
import java.awt.font.*;

public class Grafica1 {


public static void main(String[] args) {
Frame f = new Frame("Exercitii grafice") {
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
Font font = new Font("Arial",Font.BOLD,20);
g2d.setFont(fonst);
g2d.setColor(Color.RED);
g2d.drawString("Textul dorit",40,80);
g2d.draw3DRect(30,50,200,50,false);
}
};
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) { System.exit(0); } });
f.setSize(new Dimension(500,300));
f.setVisible(true);
}
}
-salvati fila cu numele Grafica1.java.Compilati si executati.
Analizati putin exercitiul.Practic se putea utiliza direct obiectul g,
dar se prefera declararea unui obiect nou,pentru a pastra obiectul g pe
post de sablon.Ori de cate ori este necesar un obiect implicit se va putea
crea direct din g.In rest,este foarte simplu:se declara fontul si culoarea
apoi se editeaza un text,sau o figura geometrica cu ajutorul metodelor
directe.Consultati lista de metode pentru obiectul de tip Graphics2D si
incercati sa implementati cat mai multe dintre ele,pentru a obtine efectul
dorit.
Incercati sa reprezentati un grafic de valori,fie cu linii,fie cu
figuri geometrice,sau chiar cu obiecte de tip img (cu drawImage()).
-132-
In majoritatea situatiilor din aplicatiile reale,valorile ce urmeaza
sa fie reprezentate grafic se obtin din diverse ecuatii matematice.In
aceste ecuatii,rezultatul obtinut este frecvent un numar fractionar.Pentru
a elimina operatiile necesare pentru conversia la numere intregi,Java
permite utilizarea numerelor de tip Float sau Double pentru specificarea
coordonatelor logice,daca se utilizeaza niste clase speciale,cum sunt:
Line2D.Float,Line2D.Double,QuadCurve2D.Float,QuadCurve2DDouble,Ellipse2D.
Float si Ellipse2D.Double...etc.
EXEMPLU:
import java.awt.*;
import java.awt.geom.Line2D.Double;
import java.awt.event.*;
public class Grafica2 {
public static void main(String[] args) {
Frame f = new Frame("Exercitii grafice"){
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.BLUE);
for (Integer x=1;x<30;x++) {
g2d.draw(new java.awt.geom.Line2D.Double(
55.3,73.77,17.7*x,400-x*10)); }
} };
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e){ System.exit(0); } } );
f.setSize(new Dimension(500,400));
f.setVisible(true);
} }
-salvati fila cu numele Grafica2.java.Compilati si executati.
EXEMPLU:
import java.awt.*;
import java.awt.geom.QuadCurve2D.Double;
import java.awt.event.*;
public class Grafica3 {
public static void main(String[] args) {
Frame f = new Frame("Exercitii grafice"){
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.RED);
for (Integer x=1;x<10;x++) {
g2d.draw(new java.awt.geom.QuadCurve2D.Double(
35.5,55.5*x,200.3,53.3*x,405.5,100.3)); }
} };
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e){ System.exit(0); } } );
f.setSize(new Dimension(500,400));
f.setVisible(true);
} }
-salvati fila cu numele Grafica3.java.Compilati si executati.
Puteti utiliza exercitii asemanatoare pentru a reprezenta valorile
oricarei functii matematice,liniare sau neliniare.Incercati sa creati un
exemplu asemanator,utilizand clasa CubicCurve2D.Double.
-133-
Pentru reprezentari grafice mai complexe,se pot utiliza obiecte de tip
container,in care se arhiveaza seturi de linii,sau reprezentari grafice,
diferite.Apoi,obiectul container se reprezinta cu draw().O astfel de clasa
este GeneralPath (din java.awt.geom).
EXEMPLU:
import java.awt.*;
import java.awt.geom.GeneralPath;
import java.awt.event.*;

public class Grafica4 {


public static void main(String[] args) {
Frame f = new Frame("Exercitii grafice") {
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.RED);
GeneralPath desen = new GeneralPath();
desen.moveTo(125.5,153.5);
desen.lineTo(250,250);
desen.quadTo(455.5,375.5,475.5,125.7);
desen.lineTo(270,250);
desen.lineTo(375.5,153.5);
g2d.draw(desen);
}};
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) { System.exit(0); } });
f.setSize(new Dimension(500,400));
f.setVisible(true);
}}
-salvati fila cu numele Grafica4.java.Compilati si executati
Liniile se introduc una cate una in GeneralPath,apoi se reprezinta.
Pentru a umple cu culoare se utilizeaza metodele fill si setPaint.
EXEMPLU:
import java.awt.*;
import java.awt.geom.Ellipse2D;
import java.awt.event.*;
public class Grafica5 {
public static void main(string[] args) {
Frame f = new Frame("Exercitii grafice") {
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
GradientPaint gradient1 = new GradientPaint(
0,0,Color.RED,350,0,Color.YELLOW);
g2d.setPaint(gradient1);
g2D.fill (new Ellipse2D.Double(50,50,400,300)); } };
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) { System.exit(0); }});
f.setSize(new Dimension(600,400));
f.setVisible(true);
}}
-salvati fila cu numele Grafica5.java.Compilati si executati.
Obiectul de tip GradientPaint permite gradiente de culoare personalizate.

-134-
Pentru a umple continutul unui poligon se poate utiliza si o textura
importata dintr-o fila de resurse,sau chiar dintr-o imagine.Pentru acest
scop,se va crea un obiect de tip TexturePaint,cu ajutorul unui tampon de
tip BufferedImage,apoi se va apela metoda setPaint(),cu acest obiect.
EXEMPLU: -desenati in Paint modelul.Salvati fila cu numele "Model1.gif".
import java.awt.*;
import java.awt.image.*;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.awt.event.*;
import java.io.*;
import javax.imageio.*;
public class Grafica6 {
public static void main(String[] args) {
Frame f = new Frame("Exercitii grafice"){
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
BufferedImage img = null;
try { img = OmageIO.read(new File("Model1.gif"));
} catch (IOException e) {}
TexturePaint t1 = new TexturePaint(
img,new Rectangle2D.Double(0,0,100,100));
g2d.setPaint(t1);
g2d.fill( new Ellipse2D.Double(50,50,400,300)); }};
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) { System.exit(0); }});
f.setSize(new Dimension(600,400));
f.setVisible(true); }}
-salvati fila cu numele Grafica6.java.Compilati si executati.
Puteti repeta exercitiul cu orice fila .jpg (fotografie,tablou,imagine).
Pentru a determina stilul penitei de desen se utilizeaza un obiect de
tip BasicStroke.
EXEMPLU:
import java.awt.*;
import java.awt.event.*;
public class Grafica7 {
public static void main(String[] args) {
Frame f = new Frame("Exercitii grafice"){
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
Float f1 = new Float(11.55);
BasicStroke bs1 = new BasicStroke(f1);
g2d.setStroke(bs1);
g2d.drawLine(70,70,150,250);
g2d.drawLine(150,250,220,70); }};
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) { System.exit(0); }});
f.setSize(new Dimension(600,400));
f.setVisible(true); }}
-salvati fila cu numele Grafica7.java.Compilati si executati.
In BasicStroke puteti seta atributele: caps,joins,dash sau miter limit.

-135-
Reprezentarile grafice pot fi inlocuite cu imagini digitale (fotografii
grafice,desene,imagini etc.) preluate dintr-o fila de resurse.Cea mai
simpla modalitate este sa creati o clasa derivata din Component in care
sa includeti imaginea.In continuare construiti un obiect din clasa respec-
tiva si utilizati obiectul ca pe un component oarecare.
EXEMPLU:
import java.awt.*;
import java.awt.event.*;
import java.awt.font.*;
import javax.swing.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;

public class Grafica8 implements ActionListener {


JButton buton1;
public static void main(String[] args) {
Grafica8 g8 = new Grafica8(); }
public Grafica8() {
JFrame frame = new JFrame("Design");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(null);
frame.setSize(500,300);
class Desen1 extends Component {
BufferedImage img;
public void paint(Graphics g) {
g.drawImage(img,0,0,null); }
public Desen1() {
try { img = ImageIO.read(new File("strawberry.jpg"));
} catch (IOException e) {}
} };
buton1 = new JButton("OK");
buton1.setBounds(10,10,100,20);
buton1.addActionListener(this);
Desen1 d1 = new Desen1();
d1.setBounds(10,50,100,100);
frame.add(buton1);
frame.add(d1);
frame.setVisible(true);
}
public void actionPerformed(ActionEvent event) {
this.buton1.setText("noul text"); } ;
}
-salvati fila cu numele Grafica8.java.Puteti sa inlocuiti fila .jpg cu
orice alta imagine.Compilati si executati.
Exercitiul contine un buton functional si clasa Desen1,creata special
pentru a gazdui o imagine oarecare.Obiectul d1,derivat din Desen1 poate
fi utilizat in interfata la fel ca orice alt component vizual.
Exercitiul poate fi un punct de pornire spre orice interfata grafica
(din acest motiv,majoritatea exercitiilor includ si parametrul String
in functia main()-pentru a putea fi exploatat in eventualele aplicatii).

-136-
Pentru operatii grafice mai complicate,se poate utiliza un obiect de
tip AffineTransform.Acest obiect permite transformarea unei imagini grafi-
ce,in alta imagine grafica cu alt sistem de coordonate.Obiectul actioneaza
asupra unui container de tip GeneralPath si translateaza fiecare punct,
dintr-un sistem de coordonate in altul.
EXEMPLU:
import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
public class Grafica9 {
public static void main(String[] args) {
JFrame frame = new JFrame("Design");
JPanel panel1 = new JPanel(){
GeneralPath makeBox(int x,int y) {
GeneralPath p = new GeneralPath();
p.moveTo(100,100);
p.lineTo(150,150);
p.lineTo(250,100);
p.lineTo(100,100);
p.closePath();
return p; }
public void paint(Graphics g) {
Dimension sz = getSize();
g.setColor(Color.red);
g.drawRect(10,10,sz.width-20,sz.height-20);
Graphics2D g2; g2=(Graphics2D) g;
GeneralPath p = makeBox(200,100);
p.setWindingRule(generalPath.WIND_EVEN_ODD);
AffineTransform tfm = new AffineTransform();
tfm.translate(175.5,27.5); g2.fill(p);
tfm = new AffineTransform();
p = makeBox(200,100);
tfm.translate(10.5,90.5); g2.setTransform(tfm);
g2.setColor(Color.green); g2.fill(p);
g2.draw();
Shape s = p.createTransformedShape(tfm);
tfm = new AffineTransform();
tfm.translate(75.7,150.5); tfm.rotate(-Math.PI/3);
g2.settransform(tfm);
g2.setColor(Color.red); g2.fill(s);
g2.draw(s);
}};
frame.setDefaultCloseOperation(Jframe.EXIT_ON_CLOSE);
frame.add(panel1);
frame.setSize(500,300);
frame.setVisible(true);
}}
-salvati fila cu numele Grafica9.java.Compilati si executati.
Practic,obiectul AffineTransform utilizeaza doua matrice tridimensio-
nale,si translateaza fiecare punct,dintr-o matrice in alta,apoi redese-
neaza obiectul.Desenul poate fi rotit,inversat,deplasat,deformat etc.

-137-
Pentru a decupa fragmente dintr-un desen,sau dintr-o imagine,se pot
utiliza metodele setClip() si Clip().Prin setClip() se specifica tipul
de suprafata utilizata pentru decuparea imaginii,iar prin clip() se exe-
cuta operatia propriu-zisa.
EXEMPLU:
import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;

public class Grafica10 {


public static void main(String[] args) {
JFrame frame = new JFrame("design");
class Desen1 extends Component {
BufferedImage img;
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setClip(0,0,50,50);
g2d.clip(new Rectangle(0,0,50,50));
g2d.drawImage(img,0,0,null);
}
public Desen1() {
try { img = ImageIO.read(new File("strawberry.jpg"));
} catch (IOException e) {}
} };
Desen1 d1 = new Desen1();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(d1);
frame.setSize(500,300);
frame.setVisible(true);
}}
-salvati fila cu numele Grafica10.java.Compilati si executati.
Pentru specificarea suprafetei decupate se poate utiliza orice forma
geometrica inclusa intr-un obiect de tip Shape,dar cele mai sigure rezul-
tate se obtin in cazul suprafetelor dreptunghiulare.Fragmentul decupat
intereseaza intreaga suprafata grafica,astfel ca metoda se poate utiliza
si pentru a decupa fragmente de text (gen coloana de ziar).
O alta facilitate oferita de Java,o reprezinta capacitatea de a supra-
pune doua imagini,pentru a obtine o imagine de sumatie.Pentru acest scop,
se poate utiliza clasa AlphaComposite,combinata cu metoda setComposite().
Clasa AlphaComposite reglementeaza modul in care vor fi tratati bitii din
fiecare dintre cele doua imagini suprapuse.Clasa contine un atribut spe-
cial denumit alpha,prin care se poate preciza gradul de opacitate al ima-
ginii suprapuse.Acest atribut,poate lua valori de tip Float,intre zero=
transparenta totala si 1= opacitate totala.In zonele in care cele doua
imagini se suprapun,imaginea de sumatie se va forma in functie de stilul
Porter Duff precizat prin obiectul AlphaComposite.In functie de stilul
ales,bitii suprapusi vor fi inclusi,exclusi sau sumati.Cele 12 situatii
posibile se precizeaza prin constantele: SRC,DST,DST_OUT,SRC_OUT...etc.

-138-
EXEMPLU:
import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;

public class Grafica11 {


public static void main(String[] args) {
JFrame frame = new JFrame("design");
class Desen1 extends Component {
BufferedImage img,img1;
public void paint(Graphics g){
Graphics2D g2d = (Graphics2D) g;
AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.SRC);
g2d.setComposite(ac);
g2d.drawImage(img1,0,0,null);
g2d.drawImage(img,0,0,null);
}
public Desen1() {
try { img = ImageIO.read(new File("strawberry.jpg"));
img1 = ImageIO.read(new File("Turcoaze.jpg"));
} catch (IOException e) {}
} };
Desen1 d1 = new Desen1();
frame.setDefaultCloseOperation(Jframe.EXIT_ON_CLOSE);
frame.add(d1);
frame.setSize(500,300);
frame.setVisible(true);
}}
-salvati fila cu numele Grafica11.java.Compilati si executati.
Puteti inlocui cele doua file de resurse cu orice alte imagini,dar cu
conditia ca fila salvata in tamponul img sa fie mai mica decat cea salvata
in tamponul img1.Pentru a intelege mai bine cele 12 reguli de sumatie,
puteti inlocui constanta SRC cu una dintre celelalte 11 variante posibile
si apoi repetati exercitiul.
Modul in care sunt tratate imaginile suprapuse,are o importanta spe-
ciala in cazul aplicatiilor ce contin grafica animata,desene animate,
imagini in miscare,video-clip-uri,etc.In cazul aplicatiilor complexe,nu
se lucreaza cu doua imagini,ci cu algoritmi automati ce prelucreaza
zeci sau sute de astfel de suprapuneri posibile.Acest procedeu tehnic a
fost utilizat pe larg si in cazul spoturilor publicitare.In general,este
recomandabil sa evitati grafica animata atunci cand nu este strict nece-
sara.Nu numai ca oboseste ochiul utilizatorului,dar consuma si un procent
destul de mare din resursele procesorului(sute si mii de operatii inutile)
sau interactioneaza cu dispozitivele utilizate pentru imprimarea datelor.
Atunci cand informatia poate fi prezentata prin grafica simpla,se va
prefera intotdeuna o interfata stabila in locul uneia animate.In cazul
in care este esential sa utilizati grafica animata,este mult mai simplu
si mai eficient sa creati clip-uri animate,de tip Gif-animat.

-139-
Pentru ca un obiect grafic sa poata fi redesenat interactiv,trebuie
creata o bucla,intre functia care trateaza evenimentul si cea care con-
struieste obiectul grafic,astfel incat sa poata fi apelata de fiecare
data metoda repaint().
EXEMPLU:
import java.awt.*;
import java.awt.geom.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class Grafica12 extends JApplet implements ChangeListener {
Desen desen1;
JSpinner sizes;
static int sizeChoice = 12;
public void init(){
JPanel panel1 = new JPanel();
panel1.add(new Jlabel("Schimbati coordonata y:"));
sizes = new JSpinner(new SpinnerNumberModel(50,10,300,10));
sizes.addChangeListener(this);
panel1.add(sizes);
desen1 = new Desen();
add(BorderLayout.NORTH,panel1);
add(BorderLayout.CENTER,desen1);
}
public void stateChanged(ChangeEvent e) {
try {
String size = sizes.getModel().getValue().toString();
sizeChoice = Integer.parseInt(size);
desen1.Actualizeaza();
} catch (NumberFormatException nfe) { }
}
public static void main(String args[]) {
JFrame f = new JFrame("Grafica interactiva");
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e){ System.exit(0); }});
JApplet grafica1 = new Grafica12();
f.add(grafica1,BorderLayout.CENTER);
grafica1.init();
f.pack();
f.setVisible(true);
}}
class Desen extends JComponent {
public Dimension getPreferredSize(){ return new Dimension(500,200); }
public void Actualizeaza() { repaint(); }
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.RED);
g.drawLine(10,10,300,Grafica12.sizeChoice);
Actualizeaza();
}}
-salvati fila cu numele Grafica12.java.Compilati si executati.

-140-
Daca analizati putin exercitiul de mai sus,puteti observa ca la orice
modificare a spinner-ului este apelata metoda Actualizeaza() prin care
se redeseneaza obiectul cu repaint().O alta metoda posibila construieste
un obiect nou la fiecare eveniment.Solutiile mai complexe,implica mai
multe thread-uri,cate unul pentru fiecare eveniment.
Acest manual nu poate epuiza toate mijloacele de exprimare grafica
din Java.Pentru o documentare suplimentara,este util sa studiati si
exemplele similare oferite pe Internet.Fiecare astfel de exemplu,poate
fi punctul de plecare pentru un anumit gen de aplicatie.In majoritatea
cazurilor,puteti gasi solutia directa pentru problema d-voastra,fara sa
mai fie necesar sa proiectati o aplicatie noua.
Daca activitatea d-voastra implica un numar mare de aplicatii grafice,
si este important sa gasiti in permanenta solutii noi,este recomandabil
sa va organizati putin.Extrageti din sursa bibliografica toate clasele
utile pentru aplicatiile grafice si construiti scheme,sau sabloane,in
functie de tipul de solutie.
EXEMPLU:
-daca din pachetul awt sunt necesare clasele: ActiveEvent,Canvas,Color,
Component,Container,Event,geom,Graphics2D,Image,LayoutManager,Paint,
MultipleGradientPaint si Transparency.
Extrageti din sursa de documentatie fiecare dintre clase,cu metodele
si constructorii (inclusiv cele mostenite) si apoi construiti o planse
in care afisati relatiile cele mai frecvente.In acest mod,in loc sa
navigati prin Help,va fi suficient sa aruncati o privire pe diagrama de
ansamblu.
O alta abordare posibila,este prin crearea unor module de tip schelet,
pentru fiecare tip de aplicatie grafica.Construiti fereastra de baza si
obiectele necesare pentru afisarea sau prelucrarea datelor,proiectati
si definiti evenimentele si conectati obiectele intre ele.De cele mai
multe ori,este practic sa preluati datele dintr-o fila sursa,sau dintr-o
clasa auxiliara externa (usor de actualizat).Cu alte cuvinte,creati seturi
de interfete grafice.In continuare,va fi suficient sa inlocuiti fila de
resurse sau sa actualizati clasa externa.Cele mai frecvente file de tip
resursa sunt tabelele si bazele de date,filele XML si filele de tip text.
Orice aplicatie noua,se va putea crea combinand doua sau mai multe
astfel de module,sau interfete.Java este un sistem "open-source".Cu alte
cuvinte,este permis si chiar recomandabil sa utilizati fragmente de cod
preluate din surse sigure,cu exceptia situatiilor in care aceste coduri
au fost protejate expres,prin drepturi de autor.La randul d-voastra,este
recomandabil sa insotiti aplicatiile create de codul sursa.In acest mod,
programele vor fi mult mai usor de verificat si depanat si vor putea fi
preluate fara rezerva de catre alti programatori.
In cazul in care combinati module realizate cu versiuni diferite de
Java,pot sa apara unele mici incompatibilitati.In aceste situatii,este
recomandabil sa modificati aplicatia spre versiunea cea mai recenta,adica
sa inlocuiti clasele vechi,prin cele moderne.Fiecare versiune a imbunata-
tit mijloacele de expresie,sau a rezolvat micile neajunsuri ale versiunii
precedente.Situatia este ceva mai complexa in cazul in care doriti sa
combinati module create cu platforme vizuale diferite (NetBeans,Eclipse,
etc.).In acest caz,este recomandabil sa aveti o experienta anterioara cu
fiecare dintre aceste platforme,inainte de a incerca sa le mixati.
-141-
APLICATII AUDIO
Aplicatiile moderne sunt de cele mai multe ori audio-vizuale.Cu alte
cuvinte,fiecare program nou contine o serie de file sursa,atat de tip
grafic cat si de tip audio,precum si un set de obiecte in care se proce-
seaza aceste date,pentru a obtine efecte vizuale sau sonore.Operatiile de
tip audio,implica urmatoarele etape:
1.-crearea unor file de resurse audio,sau stocarea informatiei in tampoane
de memorie temporare (streamuri,linii de date,etc.)
2.-arhivarea si sau transmiterea acestor file de la un calculator la
altul
3.-citirea filelor de resurse si decodificarea informatiei
4.-prelucrarea informatiei (filtre,analiza,transformari,insertii etc.)
5.-conversia datelor intr-un format acceptat de utilizatorul final
6.-distributia datelor la unitatea de executie (difuzor)
In majoritatea limbajelor de programare,toate aceste operatii se fac
automat.Exista obiecte specializate,iar codurile sursa sunt protejate sau
chiar secrete.Platforma Java,este insa creata in baza conceptului de "open
source" si ofera un acces nelimitat la informatia din filele audio.Pro-
gramatorii pot descompune semnalul,bit cu bit,pot executa orice tip de
operatie posibila,pot crea orice tip de aplicatie software posibila: audio
playere,mixere audio,filtre,dispozitive de supraveghere si control,pro-
grame de analiza automata a informatiei,programe pentru depanare automata,
motoare de cautare in retea,motoare de ditributie in retea...etc.Mai mult
decat atat,Java ofera un set foarte bogat de obiecte specializate si de
interfete grafice,ce contin numeroase metode predefinite.In esenta,toate
aceste obiecte si interfete sunt grupate in pachetul "javax.sound".
Pachetul "javax.sound" este subimpartit in doua pachete: "sampled" ce
contine obiectele si interfetele destinate sa actioneze asupra unor file
de resurse preexistente (file sursa in format audio) si pachetul "midi" ce
contine mijloacele necesare pentru a crea file sursa de tip audio,sinte-
tizatoare de sunet si operatii de tip "midi"(receiver,sequencer,synthe-
sizer,transmitter etc.).
Aplicatiile audio create vor putea fi de tip "applet",pentru a putea
fi incluse in file de tip HTML,sau vor putea fi aplicatii independente,
menite sa ruleze pe un calculator user.Alte aplicatii,vor putea inter-
actiona cu diverse structuri software (mixere,sintetizatoare,filtre,ana-
lizoare,distribuitoare etc.) sau hardware (keyboard digital,orga electro-
nica,instrumente muzicale cu comanda numerica,CD-playere,DVD-uri,video
si audioplayere,televizoare,telefoane mobile...etc.).Practic,platforma
Java ofera mijloace de expresie,pentru orice tip de aplicatie audio ima-
ginabila.
Exista si o serie de limitari.Pachetul original nu include toate for-
matele audio posibile.De exemplu,pentru a putea utiliza file in format
MP3,este necesar sa descarcati pachete auxiliare de pe Internet,sau sa
creati codurile necesare pentru decomprimarea datelor.Mai exact,Java
nu recunoaste implicit de tipurile necomprimate de format audio: AIFC,
AIFF,AU,SND si WAVE.Pentru toate celelalte tipuri,sunt necesare operatii
auxiliare de conversie a datelor.Exista doua solutii posibile:
-convertiti file la formatul .wav (cu ajutorul unui program de conversie)
-extindeti paleta de optiuni a platformei Java cu alte tipuri de format
(adaugand pachete suplimentare,obiecte si interfete specializate etc.).
-142-
Este necesara o prezentare putin mai ampla a notiunii de format audio.
Unda sonora este o vibratie (oscilatie),caracterizata prin frecventa,
amplitudine si intensitate sonora (volum sau energie purtatoare).Undele
sonore sunt cuprinse in gama de frecvente situata intre 16 si 16000 Hz.
Pentru a caracteriza complet si explicit o unda sonora se pot imagina
numeroase metode matematice: descrierea undei punct cu punct,aproximarea
undei prin linii de amplitudine diferita,descrierea undei in sistem grafic
de tip "pixel cu pixel",descrierea undei prin obiecte vizuale sau matema-
tice,arii de date,matrite,tabele de pointeri,baze de date etc.Pentru ca
toate aceste mijloace de expresie sa se incadreze intr-un sistem coherent
este necesar sa existe un standard comun,respectat cu strictete de toti
programatorii.Acest standard,poarta numele de format audio.Exista mai
multe solutii general acceptate,iar ca rezultat exista mai multe formate
de tip audio.Fila de format audio contine: un header (antetul cu infor-
matii generale),informatii utile referitoare la formatul utilizat(Exemplu:
1 = 8-bit G.711 u-law sau 5=32-bit linear PCM),informatii referitoare
la fila in ansamblu (autor,data,lungime,versiune,etc.) precum si o struc-
tura ce codifica si decodifica informatia bruta,cunoscuta sub numele de
audio codec.In general,fiecare format audio contine un anumit audio codec,
dar pot exista si formate audio ce recunosc mai multe astfel de structuri
(de exemplu filele de tip AVI).
Principalele tipuri de format audio sunt: WAV,AIFF,AU,FLAC,Monkey's
Audio,WavPack,Shorten,Tom's,Audio Kompressor,TTA,ATRAC,Apple Loosless,
WindowsMedia Audio(WMA),MP3,Vorbis,Musepack,ATRAC,AAC...etc.
Pentru a reprezenta cat mai fidel informatia,se utilizeaza sisteme
extensive,consumatoare de mari volume de memorie.Astfel,pentru a repre-
zenta sunetele bit-cu bit,se va utiliza cate un byte pentru fiecare Hz
(oscilatie).Astfel,un sunet de 16 Hz va putea fi reprezentat cu 16 bytes,
dar un sunet de 3000 Hz va fi reprezentat prin 3000 de Bytes.Fiecare
valoare de tip byte,va fi reprezentata prin valori numerice de tip SIGNED,
pentru a putea codifica amplitudinea.Rezulta ca pentru reprezentarea
sunetelor tamponul minim de memorie trebuie sa contina cel putin 16000
de bytes (16Kb).Dar aceasta codificare nu poate include toate informatiile
dorite.De exemplu,pentru a putea regla volumul sonor,cresteri sau scaderi
ale volumului,sau pentru a putea adauga diverse efecte speciale (forte,
dolce,stereo,quadro)este necesar ca fiecare oscilatie sa fie caracterizata
prin doi sau mai multi bytes.Sunetele percepute de urechea umana nu de-
pasesc freceventa de 12000 de Hz.Prin conventie,s-a stabilit ca sunt
suficienti cate 4 bytes de informatie pentru fiecare oscilatie,astfel ca
tamponul minimal de memorie este cel de 48 Kb (12000x4).In concluzie,
pentru ca aplicatia software si respectiv unitatea hardware sa poata
procesa sunete,este necesar sa poata citi calupuri de cel putin 48 kb
pentru fiecare sunet (chiar daca majoritatea sunetelor vor ocupa mai
putina memorie).
Formatele acceptate de Java sunt exclusiv cele necomprimate.Adica fila
sursa descrie complet fiecare sunet,inclusiv pauzele audio totale.Cu
alte cuvinte,o fila necomprimata va ocupa pentru un minut de muzica exact
acelasi spatiu de memorie ca si pentru un minut de liniste absoluta.
Practic,intr-o melodie exista mai multe pauze decat momente sonore.Ca
rezultat,filele necomprimate sunt incarcate cu volume foarte mari de
informatie inutila,sau dispensabila (dar cu pierderea calitatii).

-143-
In plus,exista situatii in care se poate renunta la codificarea pe
patru bytes a fiecarei oscilatii.In acest caz,se va utiliza cate un singur
bytes/oscilatie,reducand consumul de memorie de 4 ori.Filele rezultate
contin toate sunetele,dar pierd o serie intreaga de efecte speciale.Cali-
tatea inregistrarii va fi compromisa ireversibil.Din acest motiv,atunci
cand doriti calitate maxima,sau doriti sa analizati un fragment audio,
este esential sa utilizati formatul audio necomprimat.
Principalul format audio necomprimat poarta numele de PCM (Pulse-code
modulation) si reprezinta oscilatiile prin variatia amplitudinii,spre
deosebire de formatul PPM (pulse position modulation) in care oscilatiile
sunt diferentiate intre ele prin pozitia pe axa orizontala.
Majoritatea formatelor audio utilizeaza insa o formula oarecare de
compresie a datelor,astfel incat sa reduca cat mai mult din spatiul de
memorie consumat,dar sa pastreze o calitate audio acceptabila.Gradul de
compresie depinde de sunetul inregistrat,dar si de solutia tehnica imple-
mentata: stereofonie,quadrofonie...etc.In esenta,tipurile de formate cu
compresie se impart in doua categorii: lossy si lossless in functie de
volumul de informatie utila ce se pierde din inregistrare.Detaliile pentru
fiecare solutie de compresie nu fac obiectul acestui manual,dar principiul
general este acelasi: -toate spatiile din inregistrare in care sunetele
sunt absente,sau practic nesemnificative se exclud din inregistrare si
se inlocuiesc cu o valoare numerica,in care se specifica durata pauzei
respective.La redare,valoarea numerica va fi transformata in sunet minim
si va fi reinserata in tamponul de memorie inainte de a fi transmisa la
utilizator.Prin astfel de operatii,spatiul de memorie poate fi redus de
patru pana la zece ori.Solutiile matematice difera de la un format la
altul si sunt determinate de tipul inregistrarii: mono sau stereo...etc.
Exista formule extrem de complexe,prin care se poate face o aproximare
destul de exacta a informatiei codificate prescurtat.Puteti studia aceste
solutii,in literatura de specialitate.In principiu,nu este util sa creati
un format audio nou,decat daca aveti deja un numar destul de mare de uti-
lizatori si exista un scop precis (protejarea unor informatii valoroase).
Pentru restul situatiilor,sunt suficiente formatele deja existente,
dintre care cele mai reprezentative sunt:
FREE OPEN FORMATS:
wav -este formatul audio standard necomprimat de tip PCM.Calitatea audio
este maxima,dar ocupa foarte multa memorie (circa 10 Mb/minut).Filele
wav au o structura de tip RIFF si se utilizeaza mai ales pentru inre-
gistrarile facute in studio (CD-urile comerciale).
ogg -este un format comprimat,asemanator cu Mp3,dar mai putin popular
mpc -Musepack este un format comprimat,stereo,utilizat de Apple pentru Mac
raw -(raw=brut) poate contine orice codec audio,dar se utilizeza mai ales
pentru formate necomprimate (PCM).Se utilizeaza pentru testarea unor
aparate audio,sau pentru proiectarea formatelor audio comerciale.
au -este formatul standard utilizat de firma Sun pentru Java.Formatul au
poate contine datele necomprimate(PCM),sau comprimate cu un audio
codec de tip u-law,a-law sau G729.
mid -este standardul industrial utilizat pentru a permite compatibilitatea
dintre computere si instrumentele muzicale sau echipamentele de veri-
ficare,control si comunicatie.
Toate aceste formate respecta legislatia referitoare la free-ware.

-144-
OPEN FILE FORMATS:
gsm -este destinat pentru telefonie.Este utilizat in Europa si asigura un
raport destul de bun de compresie/calitate.Poate codifica file wav.
dct -este destinat pentru dictare.Contine un header,ce poate fi criptat,
pentru a garanta confidentialitatea inregistrarilor.
vox -contine un codec de tip ADPCM (Adaptive Differential Pulse Code
Modulation).Comprima formatele mai mari de 4 biti la 4 biti/oscilatie
si este asemanator cu wav,dar nu include nr.de canale si rata/sec.
aac -este un format comprimat,bazat pe standardele MPEG2 si MPEG4
mp4/m4a -este un format comprimat cu un codec MPEG-4
mmf -este un format audio utilizat de firma Samsung
Aceste formate sunt de tip Open file,adica permit accesul la date,dar nu
sunt gratuite.Achizitionarea lor se face contra cost.
PROPRIETARY FORMATS:
mp3 -este cel mai popular format pentru arhivarea melodiilor comerciale.
Este comprimat cu un codec MPEG-3 pentru o compresie de circa 10 ori
a filelor de tip Wav.Calitatea audio este rezonabila.Se utilizeaza
pentru muzica ascultata pe PC (exista numeroase arhive freeware).
ATENTIE: melodiile sunt freeware dar fromatul este cu drept de autor.
wma -este formatul Microsoft Windows.
atrac -este dezvoltat de firma Sony.Are intotdeauna si o extensie .wav.
ra -Real Audio este creat pentru transportul datelor via Internet.In
acest format se includ datele (pentru a fi protejate la acces).
ram -este o fila de tip text ce contine link-ul spre filele de tip .ra
dss -Digital Speech Standard este un format produs de firma Olympus
msv -este un format comprimat,produs de firma Sony pentru Memory Stick
dvf -este un format comprimat utilizat de firma Sony pentru dictafoane
IVS -este dezvoltat de 3D Solar UK pentru muzica si video playere
m4p -este dezvoltat de firma Apple pentru iTunes Music Store
iKlax -este un format de tip multi-track,dezvolatat de iKlax Media pentru
operatii complexe asupra datelor: mixaje,rearanjari,compozitie etc.
mxp4 -este un format dezvoltat de firma Musinaut.Permite redarea unei
melodii in mai multe versiuni (skins = inregistrari paralele).Acest
format permite scenarii interactive intre artist si utilizator.
Toate aceste formate sunt protejate prin drepturi de autor.Chair daca
majoritatea inregistrarilor oferite cu aceste formate sunt de tip free-
ware,formatul propriu-zis este protejat.Cu alte cuvinte,pentru a putea
prelua datele brute din acest format,este necesara obtinerea unei licente
si a codec-ului audio.Puteti utiliza aceste formate pentru a arhiva sau
reda inregistrarile,dar nu puteti transforma sau reinregistra filele.Daca
este imperios necesar sa "deparazitati" o melodie,convertiti datele in
format .wav,efectuati operatiile dorite si apoi reconvertiti filele la
formatul original.
Este esential sa intelegeti formatul audio,inainte de a incepe orice
fel de operatii asupra datelor.Pentru a putea lucra cu formate diferite,
este important sa detineti un program bun de conversie.Exista numeroase
astfel de programe.Pot fi descarcate gratuit,sau contra cost,din reteaua
Internet.Un astfel de program,gratuit este de exemplu: Switch Sound File
Converter.Acest program lucreaza cu file de tip: aac,aiff,aif,amr,ape,au,
flac,gsm,m3u,m4a,mp3,mpc,ogg,pls,raw,rss,spx,vox,wav,wma,wpl.Puteti insa
sa alegeti orice alt program,in functie de preferintele d-voastra.

-145-
Prima operatie esentiala inainte de a incepe orice operatie asupra
datelor,o reprezinta obtinerea de informatii despre formatul audio.Pentru
acest scop,exista o clasa special destinata,denumita AudioSystem.Clasa
AudioSystem pemite identificarea si accesarea mixerelor instalate,conver-
sia dintre diferite formate audio,includerea resurselor audio in tampoane
de memorie si stream-uri...etc.Pentru a obtine formatul audio,clasa con-
tine trei metode getAudioFileFormat() supraincarcate,astfel incat se poate
obtine formatul audio fie dintr-o fila locala,fie de la o adresa URL,fie
dintr-un stream.Formatul audio obtinut va fi o instanta a clasei Audio-
FileFormat si va contine informatii despre: tipul de format audio,lungimea
in bytes,numarul de masuri (frames),tipul de compresie,numarul de canale
audio (mono,stereo),numarul de masuri/secunda,lungimea fiecarei masuri.
EXEMPLU:
import java.applet.*;
import javax.swing.*;
import java.awt.event.*;
import java.net.URL;
import java.awt.FlowLayout;
import javax.sound.sampled.*;
import java.io.IOException;
public class Sunet2 extends JApplet implements ActionListener {
Applet applet;
private AudioClip onceClip;
String sir1 = "bark.au";
JLabel text1,text2;
JButton buton1;
AudioFileFormat fila1;
public void init() {
setLayout(new FlowLayout());
buton1 = new JButton("SUNET");
text1 = new JLabel("Textul initial");
buton1.addActionListener(this);
add(buton1);
add(text1);
try { URL url = new URL(getCodeBase(),sir1);
try { try{
fila1 = AudioSystem.getAudioFileFormat(url);
} catch (IOException e){}
} catch (UnsupportedAudioFileException e) {}
onceClip = newAudioClip(url);
} catch (java.net.malformedURLException e) {}
}
public void actionPerformed(ActionEvent event){
onceClip.play();
text1.setText(fila1.toString());
}
}
-salvati fila cu numele Sunet2.java si compilati.
Pentru executie,includeti applet-ul intr-o fila HTML.Acest exercitiu
utilizeaza pentru redarea sunetelor un obiect de tip AudioClip (din pache-
tul applet) si metoda AudioFileFormat.toString() pentru formatul audio.

-146-
Interfata AudioClip este simplista.Se recomanda doar pentru efecte
sonore,salvate in file de tip .au.Interfata permite repetarea sunetelor
cu ajutorul metodei loop() sau chiar mixarea a doua sau mai multe sunete.
EXEMPLU:
import java.applet.*;
import javax.swing.*;
import java.awt.event.*;
import java.net.URL;
import java.awt.FlowLayout;
import javax.sound.sampled.*;
import java.io.*;
public class Sunet4 extends JApplet implements ActionListener {
Applet applet; private AudioClip onceClip;
String sir1 = "bong.au"; JLabel text1,text2;
JButton buton1,buton2,buton3;
JTextField t1; AudioFileFormat fila1;
public void init() {
setLayout(new FlowLayout());
t1 = new JTextField("bong.au");
buton1 = new JButton("Start");
buton2 = new JButton("Stop");
buton3 = new JButton("Loop");
text1 = new JLabel("Textul initial");
buton1.addActionListener(this);
buton2.addActionListener(this);
buton3.addActionListener(this);
add(t1); add(buton1); add(buton2);
add(buton3); add(text1);
try{ URL url = new URL(getCodeBase(),sir1);
try{ try{
fila1 = AudioSystem.getAudioFileFormat(url);
} catch (IOException e) {}
} catch (UnsupportedAudioFileException e) {}
onceClip = newAudioClip(url);
} catch (java.net.MalformedURLException e) {} }
public void actionPerformed(ActionEvent event) {
String s1 = event.getActionCommand();
if (s1 == "Start") { sir1 = t1.getText();
try{ URL url = new URL(getCodeBase(),sir1);
try{ try{ fila1 = AudioSystem.getAudioFileFormat(url);
} catch (IOException e){}
} catch (UnsupportedAudioFileException e) {}
onceClip = newAudioClip(url);
} catch (java.net.MalformedURLException e) {}
onceClip.play(); }
if (s1 == "Stop") { onceClip.stop(); }
if (s1 == "Loop") { onceClip.loop(); }
text1.settext(fila1.toString());
}}
Salvati fila cu numele Sunet4.java si compilati.Includeti applet-ul intr-o
fila HTML si executati exercitiul.Puteti mixa doua sau mai multe file.

-147-
Interfata AudioClip este destinata doar pentru efecte sonore intr-o
fila de tip web.Pentru a putea asculta o fila muzicala de tip wav (ce
poate contine 30 - 300 Mb de informatie,codificata pe 8 sau 16 biti,este
necesar un player sau un mixer audio.O astfel de structura,contine mai
multe linii de date,alimentate de catre un stream specializat si obiecte
vizuale pentru operatii asupra datelor.Scheletul unei singure linii de
date,se poate configura ca in exemplul de mai jos.
EXEMPLU:
import java.io.File;
import java.io.IOException;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.swing.SwingUtilities;
import javax.swing.filechooser.*;
import javax.sound.sampled.*;

public class Audio1 extends JPanel implements ActionListener {


private static final int EXTERNAL_BUFFER_SIZE = 100000;
String strFilename = "Mel10.wav";
JButton openButton,Start1,Stop1;
JTextArea text1;
JFileChooser fc;
public Audio1() {
super(new BorderLayout());
JPanel panou1 = new JPanel();
panou1.setLayout(new FlowLayout());
openButton = new JButton("Open File");
openButton.addActionListener(this);
Start1 = new JButton("Start");
Start1.addActionListener(this);
Stop1 = new JButton("Stop");
Stop1.addActionListener(this);
panou1.add(openButton);
panou1.add(Start1);
panou1.add(Stop1);
fc = new JFileChooser();
text1 = new JTextArea(5,60);
text1.setEditable(false);
JScrollPane scroll1 = new JScrollPane(text1);
add(panou1.BorderLayout.PAGE_START);
add(scrol1,BorderLayout.CENTER); }
public static void main(String[] args) {
JFrame frame = new JFrame("Mixer audio");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout());
frame.add(new Audio1());
frame.setSize(300,200);
frame.pack();
frame.setVisible(true); }
-continuare pe pagina urmatoare

-148-
public void actionPerformed(ActionEvent event) {
if (event.getSource() == openButton) {
int returnVal = fc.showOpenDialog(Audio1.this);
if (returnVal == JFileChooser.APPROVE_OPTION) {
File file = fc.getSelectedFile();
strFilename = file.getAbsolutePath();
text1.append(strFileName);
text1.append("\n"); }}
File soundFile = new File(strFilename);
AudioInputStream audioInputStream = null;
try {
audioInputStream = AudioSystem.getAudioInputStream(soundFile);
} catch (Exception e) { e.printStackTrace() ;
System.exit(1);
}
AudioFormat audioFormat = audioInputStream.getFormat();
SourceDataLine line = null;
DataLine.Info info = new DataLine.Info(SourceDataLine.class,audioFormat);
try { line = (SourceDataLine) AudioSystem.getLine(info);
line.open(audioFormat);
} catch (LineUnavailableException e)
{ e.printStackTrace();
System.exit(1);
} catch (Exception e) { e.printStackTrace();
System.exit(1);
}
if (event.getSource() == Start1) {
text1.append(audioFormat.toString());
text1.append("\n");
line.start();
int nBytesRead = 0;
byte[] abData = new byte[EXTERNAL_BUFFER_SIZE];
while (nBytesRead != -1) {
try {
nBytesRead = audioInputStream.read(abData,0,abData.length);
} catch (IOException e) { e.printStackTrace(); }
if (nBytesRead >= 0)
{ int nBytesWritten = line.write(abData,0,nBytesRead); }
}
line.drain();
line.close(); }
}
if (event.getSource() == Stop1) {
line.stop();
line.close();
System.exit(0);
}
}}
-salvati fila cu numele Audio1.java.Compilati si executati.Apasati butonul
OpenFile si alegeti orice fila cu extensia .wav,apoi apasati butonul Start
pentru redare.Butonul Stop,este mai mult formal.

-149-
Exemplul de mai sus contine urmatoarele etape:
-designul pentru o interfata grafica minimala,cu cateva butoane
-un obiect JFileChoser pentru alegerea filei dorite
-continutul filei este copiat intr-un stream (audioInputStream)
-se citese formatul filei audio (in audioFormat)
-se creaza o linie de date de tip SourceDataLine
-se includ informatiile despre formatul filei audio
-se deschide linia de date (cu open())
-se copiaza datele din stream intr-un tampon intermediar de memorie (o
arie de bytes de dimensiunea tamponului de memorie- abData)
-eventual se executa operatiile dorite asupra datelor (filtre,insertii,
decupaje,selectii,resetari ...etc)
-se scriu datele din tamponul intermediar in linia de date
-se lanseaza linia in executie cu start()
Pentru a simplifica exercitiul,se poate renunta la stream si la tam-
ponul intermediar.In acest caz,datele se pot scrie direct din fila in
linia de date,pentru a fi executate cu start.In acest caz,insa,nu se va
putea face nici o operatie asupra datelor (player rudimentar).
Un player competitiv,sau un mixer,va trebui sa contina mai multe
astfel de linii de date,ce pot fi executate secvential sau simultan.
Pentru acest scop,este esential ca fiecare linie sa fie inclusa intr-un
thread separat.In exercitiul de mai sus,puteti observa ca melodia lansata
in executie nu poate fi intrerupta pana la citirea completa a datelor.
Pentru a remedia acest inconvenient,includeti intreaga linie de date
intr-un thread ce poate fi initializat sau oprit,ori de cate ori este
necesar.
Exista o oferta extrem de larga pentru mixere,playere,programe de
conversie a formatului,etc.Inainte de a proiecta o astfel de aplicatie,
este bine sa consultati oferta din reteaua Internet.Majoritatea progra-
melor sunt in regim shareware,sau chiar cu licenta,dar exista si o oferta
destul de bogata in regim freeware.De exemplu,un mixer functional si
destul de performat este oferit sub numele de Sound in Depth.Daca doriti
si codurile sursa,este bine sa verificati si oferta de la adresa:
http://svn.sourceforge.net
Are rost sa proiectati o aplicatie noua,doar daca sunteti extrem de
pasionati,sau daca aveti o conceptie radical diferita de cele existente.
Nu este suficient sa executati operatii matematice asupra sirului de
bytes.Pentru ca modificarile efectuate sa fie relevante,trebuie sa res-
pectati codec-ului fiecarui format audio.
Exemplu: sa presupunem ca este un format de 4 bytes/oscilatie.Daca este
vorba de un semnal stereo,cei patru bytes pot fi utilizati astfel: primul
pentru canalul LEFT,al doilea pentru canalul RIGHT,al treilea pentru
volum si al patrulea pentru timbru sau efecte speciale...etc.Nu se poate
ghici codul intern,ci trebuie sa cunoasteti exact aceste informatii,
pentru fiecare tip de format audio posibil (licenta codec-ului).
Nu exista reguli fixe.Puteti executa orice operatii matematice posi-
bile,cu conditia sa respectati toate reglementarile referitaore la for-
matul respectiv.In principiu,cele mai simple operatii sunt cele prin
care se extrag fragmente dintr-o inregistrare.Aceste fregmante,se pot
exclude (pentru a elimina "parazitii"),sau se pot salva in file izolate,
pentru efecte speciale : mixaje,waw-waw,polifonie etc.

-150-
EXEMPLU:
import java.io.*;
import java.io.IOException;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.SwingUtilities;
import javax.swing.filechooser.*;
import javax.sound.sampled.*;

public class Audio3 extends JPanel implements ActionListener {


String strFilename = "Mel10.wav";
JButton openButton,Start1,Stop1;
JTextField lungime,pornire,oprire;
JTextArea text1;
JFileChooser fc;
AudioFileFormat.Type tip1;
public Audio3() {
super(new BorderLayout());
JPanel panou1 = new JPanel();
panou1.setLayout(new FlowLayout());
lungime = new JTextField("040000000");
pornire = new JTextField("000000000");
oprire = new JTextField("000200000");
openButton = new JButton("Open File");
openButton.addActionListener(this);
Start1 = new JButton("Start");
Start1.addActionListener(this);
Stop1 = new JButton("Stop");
Stop1.addActionListener(this);
panou1.add(lungime);
panou1.add(openButton);
panou1.add(pornire);
panou1.add(Start1);
panou1.add(oprire);
panou1.add(Stop1);
fc = new JFileChooser();
text1 = new JtextArea(15,80);
text1.setEditable(false);
JScrollPane scroll1 = new JScrollPane(text1);
add(panou1,BorderLayout.PAGE_START);
add(scroll1,BorderLayout.CENTER); }
public static void main(String[] args) {
JFrame frame = new JFrame("Mixer audio");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout());
frame.add(new Audio3());
frame.setSize(300,200);
frame.pack();
frame.setVisible(true); }
-continuare pe pagina urmatoare
-151-
public void actionPerformed(ActionEvent event) {
int tampon = Integer.valueOf(lungime.getText());
int p1 = 0 ; int p2 = 200000;
p1 = Integer.valueOf(pornire.getText());
p2 = Integer.valueOf(oprire.getText());
if (event.getSource() == Stop1) { System.exit(0); }
if (event.getSource() == openButton) {
int returnVal = fc.showOpenDialog(Audio3.this);
if (returnVal == JFileChooser.APPROVE_OPTION) {
File file = fc.getSelectedFile();
strFilename = file.getAbsolutePath();
text1.append(strFilename);
text1.append("\n");
}}
File soundFile = new File(strFilename);
AudioInputStream audioInputStream = null;
try {
audioInputStream = AudioSystem.gatAudioInputStream(soundFile);
} catch (Exception e) { System.exit(1); }
try {
tip1 = AudioSystem.getAudioFileFormat(soundFile).getType();
} catch (UnsupportedAudioFileException e) {}
catch (IOException e1) {}
AudioFormat audioFormat = audioInputStream.getFormat();
SourceDataLine line = null;
DataLine.Info info = new DataLine.Info(SourceDataLine.class,audioFormat);
try { line = (SourceDataLine) AudioSystem.getLine(info);
line.open(audioFormat);
} catch (LineUnavailableException e) { System.exit(1) ; }
catch (Exception e) { System.exit(1); }

if (event.getSource() == Start1) {
line.start();
int nBytesRead = 0;
byte[] abData = new byte[tampon];
try {
nBytesRead = audioInputStream.read(abData,0,abData.length);
} catch (IOException e) {}
byte[] selectie = new byte[tampon];
for (int x = p1;x<p2;x++) {
selectie[x-p1] = abData[x];
}
int nBytesWritten = linie.write(abData,0,nBytesRead);
File salvare1 = new File("Salvare1.wav");
ByteArrayInputStream sursa1 = new ByteArrayInputStream(selectie);
AudioInputStream sursa2 = new AudioInputStream(sursa1,audioFormat,tampon);
try {
AudioSystem.write(sursa2,tip1,salvare1);
} catch (IOException e) {}
catch (IllegalArgumentException e1) {};
-continuare pe pagina urmatoare
-152-
text1.append(sursa1.toString());
text1.append("\n");
line.drain();
line.close();
}}}
-salvati exercitiul cu numele Audio3.java.Compilati si executati
Pentru a deschide fila dorita,utilizati butonul OpenFile.In prima
caseta JTextField (lungime) puteti seta lungimea fragmentului interpretat,
iar in urmatoarele doua: offset-ul de start si offset-ul final al frag-
mentului selectat.Apasand butonul,se va reda fragmentul cu lungimea setata
si se va salva in fila "Salvare1.wav",fragmentul cuprins intre: pornire
si oprire.
Un astfel de algoritm,reprezinta doar o mica parte dintr-un mixer.In
continuare,mixerul trebuie sa poata decupa mai multe astfel de fragmente
si apoi sa le alipeasca,sau sa le combine,pentru a rezulta un fragment
muzical nou.
Exista doua tipuri principale de operatii asupra datelor de tip audio:
-operatii asupra unor fragmente audio preinregistrate (selectare,mixare,
filtrare,transformare ...etc.)
-operatii asupra fenomenului fizic prin care se genereaza sunetele(modi-
ficarea frecventei,a amplitudinii,generarea de sunete noi...etc.).
Primul tip de operatii respecta formatul existent al datelor si lucrea-
za doar cu fragmente audio,ce pot fi salvate in file separate,sau in tam-
poane de memorie.
Cel de al doilea tip de operatii,necesita o pregatire speciala si no-
tiuni avansate despre structura semnalului audio.Fiecare sunet,este un
fenomen fizic complex,ce poate fi codificat doar cu ajutorul unui volum
destul de mare de date.Un sunet mediu,este format din sute sau mii de
oscilatii,cu amplitudine diferita.Rezultanta lor,este un singur sunet
scurt,dar descompunerea liniara a acestor oscilatii ofera o imagine destul
de realista a fenomenului de ansamblu.Se spune ca fiecare sunet are o
"amprenta",adica o anumita secventa logica,unica si repetabila.Aceasta
"amprenta" poate fi pusa in evidenta,fie prin valori numerice,fie sub
forma unei reprezentari grafice.Codificarea fiecarui sunet,nu se poate
face arbitrar,sau dupa reguli aleatorii.Din acest motiv,forul European de
specialitate,denumit European Broadcasting Union (EBU),a dezvoltat impre-
una cu Audio Engineering Society (AES),un standard pentru codificarea
semnalului audio,cunoscut sub numele de AES/EBU (AES3).Acest standard a
intrat in vigoare in anul 1985 si a fost actualizat in anul 1992 si 2003.
Inainte de a incerca orice operatii asupra semnalului audio,este bine sa
consultati si acest standard.In plus,trebuie sa cunoasteti algoritmul
exact al fiecarui codec audio,pentru a putea respecta formatul respectiv.
In principiu,este recomandabil sa uitlizati doar instrumente specia-
lizate (exista o gama foarte larga,oferita sub licenta freeware).Daca
totusi doriti sa faceti analize ale semnalului audio,puteti dezvolta
aplicatii in care prelucrati matematic valorile audio din stream-ul audio,
sau reprezentati grafic semnalul si apoi dezvoltati algoritmi pentru
analiza si interpretarea datelor obtinute.Trebuie insa sa tineti cont
de faptul ca doar unul dintre bytes contine informatia audio propriu zisa,
in timp ce restul sunt doar bytes "de masca",sau contin informatii auxi-
liare despre semnal.

-153-
EXEMPLU:
import java.io.File;
import java.io.IOException;
import java.awt.*;
import java.awt.Robot;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.Timer;
import.javax.swing.SwingUtilities;
import javax.swing.filechooser.*;
import javax.sound.sampled.*;
import java.awt.geom.Line2D.Double;

public class Audio6 extends JPanel implements ActionListener {


static int tampon = 9000100;
static int adresa = 0;
static int p1 = 0;
static int p2 = 80;
static int timp = 20;
static byte[] sunet;
String strFilename = "bark.wav";
JButton openButton,Start1;
JButton Stop1,Stop2;
JTextField lungime;
JtextField pornire;
JTextField oprire;
JTextField delay1;
JTextArea text1;
JFileChooser fc;
static Desen1 panou2;
static Timer timer1;
public Audio6() {
super(new BorderLayout());
sunet = new byte[tampon];
for (int x=0;x<800;x++) {
sunet[x] = 0; }
JPanel panou1 = new Jpanel();
panou1.setLayout(new FlowLayout());
lungime = new JTextField("009000000");
pornire = new JTextField("000000000");
oprire = new JTextField("000000080");
delay1 = new JTextField("0020");
openButton = new JButton("Open File");
openButton.addActionListener(this);
Start1 = new JButton("Start");
Start1 .addActionListener(this);
Stop1 = new JButton("Stop");
Stop1.addActionListener(this);
Stop2 = new JButton("StopAuto");
Stop2.addActionListener(this);
-continuare pe pagina urmatoare

-154-
JLabel et1 = new Jlabel("bytes: ");
JLabel et2 = new JLabel("offset1: ");
JLabel et3 = new JLabel("offset2: ");
JLabel et4 = new JLabel("delay:" );
panou1.add(et1);
panou1.add(lungime);
panou1.add(openButton);
panou1.add(et2);
panou1.add(pornire);
panou1.add(Start1);
panou1.add(et3);
panou1.add(oprire);
panou1.add(Stop1);
panou1.add(et4);
panou1.add(delay1);
panou1.add(Stop2);
fc = new JFileChooser();
text1 = new JTextArea(10,80);
text1.setEditable(false);
JScrollPane scrol1 = new JScrollPane(text1);
panou2 = new Desen1();
add(panou1,BorderLayout.PAGE_START);
add(scrol1,BorderLayout.CENTER);
add(panou2,BorderLayout.SOUTH);
}
public static void main(String[] args) {
JFrame frame = new JFrame("Mixer audio");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout());
frame.add(new Audio6());
frame.pack();
frame.setSize(1000,600);
frame.setVisible(true);
frame.repaint();
}
public void actionPerformed(ActionEvent event) {
tampon = Integer.valueOf(lungime.getText());
p1 = Integer.valueOf(pornire.getText());
p2 = Integer.valueOf(oprire.getText());
if(event.getSource() == Stop1) { System.exit(0); }
if(event.getSource() == Stop2) { timer1.stop(); }
if(event.getSource() == openButton) {
int (returnVal = fc.showOpenDialog(Audio6.this);
if (returnVal == JFileChooser.APPROVE_OPTION) {
File file = fc.getSelectedFile();
strFilename = file.getAbsolutePath();
text1.append(strFilename);
text1.append("\n");
}
}
-continuare pe pagina urmatoare

-155-
File soundFile = new File(strFilename);
AudioInputStream audioInputStream = null;
try {
audioInputStream = AudioSystem.getAudioInputStream(soundFile);
} catch (Exception e){ text1.append("Exceptie I/O ! \n"); }
AudioFormat audioFormat = audioInputStream.getFormat();
SourceDataLine line = null;
DataLine.Info info = new DataLine.Info(SourceDataLine.class,audioFormat);
try { line = (SourceDataLine) AudioSystem.getLine(info);
line.open(audioFormat);
} catch (LineUnavailableException e)
{ text1.append("Linia nu este accesibila ! \n");
} catch (Exception e){ text1.append("Format necunoscut ! \n");}
if(event.getSource() == Start1) {
line.start();
int nBytesRead = 0;
int nAdresa = 0;
byte[] abData = new byte[tampon];
try{ nBytesRead = audioInputStream.read(abData,0,tampon-1);
} catch (IOException e) {}
sunet = new byte[tampon];
for (int x=0;4*x<tampon-1;x++) {
sunet[4*x+3] = abData[4*x+3];
sunet[4*x+1] = 0;
sunet[4*x+2] = 0;
sunet[4*x] = 0;
}
int nBytesWritten = linie.write(abdata,0,nBytesRead);
for (int x = p1;x<p2;x++) {
text1.append(String.valueOf(abData[x]));
text1.append("|");
ActionListener ceas1 = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
if(Audio6.adresa < Audio6.tampon) {
Audio6.panou2.Actualizeaza(); }}};
timp = Integer.valueOf(delay1.getText());
timer1 = new Timer(timp,ceas1);
timer1.start();
};
line.drain();
line.close();
text1.append(audioFormat.toString());
text1.append(" \n");
}}}

class Desen1 extends JPanel {


public Dimension getPreferredSize () {
return new Dimension(500,350); }
public void Actualizeaza() { repaint(); }
public void paint(Graphics g) {
-continuare pe pagina urmatoare

-156-
Graphics2D g2d = (Graphics2D) g;
super.paintComponent(g);
g2d.setColor(Color.BLUE);
g2d.draw(new Rectangle(882,300));
g2D.setColor(Color.RED);
g2d.drawLine(0,150,850,150);
for int x=1;x<8800;x++) {
Audio6.adresa = Audio6.adresa + 1;
g2d.draw(new java.awt.geom.Line2D.Double(
x*0.1,150+0.1,x*0.1,150+Integer.valueOf(
Audio6.sunet[Audio6.adresa])+0.1)); };
g2d.drawString(String.valueOf(
Audio6.sunet[Audio6.adresa]),700,300);
g2d.drawString(String.valueOf(Audio6.adresa),600,300);
}}
-salvati fila cu numele Audio6.java.Compilati si executati.
In exercitiul de mai sus,puteti studia stream-ul audio,fie sub forma
de valori numerice,fie prin reprezentarea grafica (simplista) din Desen1.
Observati ca datele au fost copiate intr-un tampon separat,inainte de a
fi prelucrate grafic,sau matematic,pentru a evita orice tip de corupere
a datelor.
Exemplul de mai sus,ofera o reprezentare grafica cat de cat corecta,
doar in cazul formatului .wav cu patru bytes/frame.Observati ca la
copierea datelor am exclus primii trei bytes din fiecare frame si am
salvat valoarea numerica doar pentru cel de al patrulea byte.Aceasta
formula nu se poate aplica pentru restul formatelor ( nici pentru formatul
.wav cu 8 bytes/frame).
Exercitiul de mai sus,este foarte simplist,dar ofera o imagine destul
de intuitiva asupra modului de analiza a unui semnal audio.Pentru o abor-
dare profesionista,va trebui sa consultati literatura de specialitate.
Deoarece utilizeaza un singur thread,toate operatiile se executa secven-
tial.Astfel,reprezentarea grafica nu apare decat dupa redarea fragmentului
muzical.Pentru a putea executa mai multe operatii simultan,trebuie sa
organizati evenimentele din interfata sub forma de thread-uri separate si
apoi sa lansati in executie doua sau mai multe thread-uri simultan.
Pachetul javax.sound.sampled contine urmatoarele interfete: Clip,Line,
DataLine,LineListener,Mixer,Port,SourceDataLine,TargetDataLine si urma-
toarele clase: AudioFileFormat,AudioFileFormat.Type,AudioFormat,AudioFor-
mat.Encoding,AudioInputStream,AudioPermission,AudioSystem,BooleanControl,
BooleanControl.Type,CompoundControl,CompoundControlType,Control,Control.
Type,DataLine.Info,EnumControl,EnumControl.Type,FloatControl,FloatControl.
Type,Line.Info,LineEvent,LineEvent.Type,Mixer.Info,Port.Info,ReverbType.
Fiecare dintre ele ofera un set de metode specializate pentru un anumit
gen de operatii.O parte dintre aceste instrumente software sunt de tip
abstract,adica nu contin decat declaratia metodelor.Pentru a putea utili-
za aceste structuri,exista doua solutii:
1.-editati definitia pentru fiecare metoda abstracta
2.-importati de pe Internet implementari in care metodele abstracte au
fost redefinite pentru un anumit scop.
Exista si pachete suplimentare,complet noi,ce pot fi descarcate si
incluse in aplicatiile d-voastra.

-157-
Cel de al doilea pachet din javax.sound,poarta numele de "midi" si este
destinat pentru muzica electronica instrumentala (midi este prescurtarea
de la Musical Instrument Digital Interface).In termeni mai generali,prin
MIDI se intelege standardul industrial definit in anul 1982 de catre
Audio Engineering Society,pentru a asigura compatibilitatea dintre toate
instrumentele muzicale electronice si echipamentele de comanda si control
computerizate (pentru arhivarea,prelucrarea,redarea sau transmisia date-
lor in retea).Cu ajutorul acestui protocol,este posibil ca un fragment
muzical executat la o orga electronica din Europa sa poata fi inregistrat,
impachetat si transmis in Australia,pentru a fi redat pe un computer,sau
pe o alta orga electronica conectata la un calculator.
Aplicatiile de tip MIDI utilizeaza un sistem total diferit de codifi-
care a informatiilor.Prin urmare,atat structurile software,cat si cele
de tip hardware sunt complet diferite de cele de tip audio(incompatibile).
Informatiile MIDI sunt arhivate in file speciale,cu extensia .midi.
Exista trei tipuri posibile de file MIDI:
MIDI 0 - single track (cu o singura linie de date)
MIDI 1 - multiple tracks,synchronous (mai multe linii executate sincron)
MIDI 2 - multiple tracks,asynchronous(mai multe linii de date ce pot fi
redate fie sincron,fie asincron).
Fiecare fila MIDI contine un header,in care se specifica tipul filei,
dimensiunea header-ului,numarul de linii de date (tracks) si tactul/nota.
In continuare,datele sunt fragmentate in segmente (chunks).Fiecare linie
de date trebuie sa contina un header si unul sau mai multe segmente de
date (chunks).In segmente,informatiile sunt structurate sub forma de eve-
nimente MIDI.Fiecare byte,este un astfel de eveniment MIDI si contine de
fapt o anumita comanda.La executia filei MIDI,se va citi si interpreta
fiecare byte,apoi se va executa comanda respectiva.De exemplu,daca eveni-
mentul MIDI este "Note on" se va executa nota muzicala respectiva.
In format midi,sunetele sunt prearhivate si codificate cu un singur
byte/nota muzicala.Exista un tabel de corespondenta,cu ajutorul caruia
fiecare tasta poate fi transformata intr-o nota muzicala.Ca rezultat,un
sunet poate fi codificat cu un singur byte (fata de 48 kb in formatul
audio),dar posibilitatile de exprimare se rezuma doar suntele preinregis-
trate.Acest format nu este destinat pentru inregistrarile muzicale de
calitate,dar este extrem de util pentru scopuri didactice: editarea si
redarea unei partituri muzicale simple,abc-muzical ...etc.
Pentru a putea largi paleta de exprimare,sunetele preinregistrate se
arhiveaza sub forma de Instrumente.Fiecare instrument,va contine toata
gama de note muzicale acceptate.Ca rezultat,o anumita valoare numerica
(un Byte),va putea genera sunete diferite,in functie de Instrumentul
muzical in care este arhivat.Intr-o fila MIDI,se accepta pana la 16 linii
de date paralele,astfel ca un fragment muzical va putea cuprinde pana la
16 instrumente separate.Termenul de Instrument,nu implica neaparat un
instrument muzical,ci poate fi o voce umana,un cor,sau orice alt tip de
sunet (organizate sub forma de octave).De exemplu,un astfel de instrument
poate contine sunete sintetizate complet electronic (sunete care nu exista
in natura).Din acest motiv,obiectul software care genereaza sunetele este
denumit Synthesizer(sintetizator) iar cel care citeste secventele poarta
numele de Sequencer (secventiator).
Cel mai simplu MidiPlayer poate fi realizat astfel:

-158-
EXEMPLU:
import java.io.IOException;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.SwingUtilities;
import javax.swing.filechooser.*;
import javax.sound.midi.*;
public class MidiPlayer1 extends JPanel implements ActionListener {
private static Sequencer sm_sequencer = null;
private static Synthesizer sm_synthesizer = null;
String strFilename = "music.midi";
JButton openButton,Start1,Stop1;
JTextArea text1;
JFileChooser fc;
public MidiPlayer() {
super(new BorderLayout());
JPanel panou1 = new JPanel();
panou1.setLayout(new FlowLayout());
openButton = new JButton("Open File");
openButton.addActionListener(this);
Start1 = new JButton("Start");
Start1.addActionListener(this);
Stop1 = new JButton("Stop");
Stop1.addActionListener(this);
panou1.add(openButton);
panou1.add(Start1);
panou1.add(Stop1);
fc = new JFileChooser();
text1 = new JTextArea(5,60);
text1.setEditable(false);
JScrollPane scrol1 = new JScrollPane(text1);
add(panou1,BorderLayout.PAGE_START);
add(scrol1,BorderLayout.CENTER); }
public static void main(String[] args) {
JFrame frame = new JFrame("Midi Player");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout());
frame.add(new MidiPlayer1());
frame.setSize(300,200);
frame.pack();
frame.setVisible(true);
}
public void actionPerformed(ActionEvent event) {
if (event.getSource() == Stop1) { System.exit(0); };
if (event.getSource() == openButton) {
int returnVal = fc.showOpenDialog(MidiPlayer1.this);
if (returnVal == JFileChooser.APPROVE_OPTION) {
File file = fc.getSelectedFile();
-continuare pe pagina urmatoare

-159-
strFilename = file.getAbsolutePath();
text1.append(strFilename);
text1.append("\n"); }}
if (event.getSource() == Start1) {
File midiFile = new File(strFilename);
Sequence sequence = null;
try {
sequence = MidiSystem.getSequence(midiFile);
} catch (InvalidMidiDataException e)
{ text1.append("Exceptie Midi Data ! \n");}
catch (IOException e)
{ text1.append("Exceptie I/O ! \n"); }
try {
sm_sequencer = MidiSystem.getSequencer();
} catch (MidiUnavailableException e)
{ text1.append("Fila midi este inaccesibila ! \n"); }
if (sm_sequencer == null)
{ text1.append(" Nu exista Sequencer ! \n"); }
sm_sequencer.addMetaEventListener(new MetaEventListener() {
public void meta(MetaMessage event) {
if (event.getType() == 47) {
sm_sequencer.close();
if (sm_synthesizer != null) {
sm_synthesizer.close(); }
text1.append("Sfarsitul fragmentului ! \n"); }
}});
try { sm_sequencer.open();
} catch (MidiUnavailableException e)
{ text1,append("Fila midi nu a fost deschisa ! \n");}
try { sm_sequencer.setSequence(sequence);
} catch (InvalidMidiDataException e)
{ text1.append("Nu a fost setata secventa ! \n"); }
if ( ! (sm_sequencer instanceof Synthesizer)) {
try { sm_synthesizer = MidiSystem.getSynthesizer();
sm_synthesizer.open();
Receiver synthReceiver = sm_synthesizer.getReceiver();
Transmitter seqTransmitter = sm_sequencer.getTransmitter();
seqTransmitter.setReceiver(synthReceiver); }
catch (MidiUnavailableException e)
{ text1.append("Eroare de instanta ! \n"); }}
sm_sequencer.start(); }}
}
-salvati fila cu numele MidiPlayer1.java.Compilati si executati.Alegeti
orice fila in format .midi.
In exemplul de mai sus,se observa obiectele centrale : sequencer si
synthesizer,accesul la resurse cu ajutorul obiectelor JFileChooser si
respectiv MidiSystem,precum si cele doua obiecte necesare pentru trans-
portul si interpretarea datelor: Transmitter si Receiver.
Si acest exemplu este structurat intr-un singur thread.Intr-o aplicatie
reala,este de dorit ca fiecare eveniment sa detina un thread propriu,
pentru a permite multiprocesarea paralela.
-160-
Pachetul MIDI include urmatoarele interfete: ControllerEventListener,
MetaEventListener,MidiDevice,Receiver,Sequencer,Soundbank,Synthesizer si
Transmitter,precum si urmatoarele clase predefinite:Instrument,MetaMessage
MidiDevice.Info,MidiEvent,MidiFileFormat,MidiMessage,MidiSystem,Patch,
Sequence,Sequencer.SyncMode,ShortMessage,SoundbankResource,SysexMessage,
Track,VoiceStatus.
Pentru a exploata sau dezvolta aceste instrumente software,este bine
sa consultati si fila sursa (situata in src/javax/sound/midi).Daca doriti
sa proiectati mixere si filtre midi,va trebui sa studiati cu atentie
formatul de tip midi.In principiu,formatul include mai multe secvente,
structurate astfel: MIDI Header,Track Header,Track data si Track out.
Fragmentul muzical propriu zis,este inclus in segmentul Track data,sub
forma de evenimente MIDI.Fiecare eveniment MIDI este definit prin cate
patru bytes astfel: Byte1 = time-stamp (adica masoara tactul)
Byte2 = status-byte (exemplu W,X si Y = Note On)
Byte3 = note pitch (inaltimea notei)
Byte4 = volume (volumul notei respective)
EXEMPLU:
7F 90 3E 60 se traduce astfel: asteapta 7F unitati de timp,apoi
executa pe canalul 0,nota muzicala C,la volum de 60 de unitati.
Pentru status,se utilizeaza urmatoarele conventii: 8=Note Off,9=Note On,
A=AfterTouch(apasarea unei taste),B=Control Change,C=Program Change,
D=Channel Pressure,E=Pitch Wheel.
Cu alte cuvinte,programul d-voastra va trebui sa ruleze fiecare sec-
venta,sa extraga evenimentele MIDI si sa le interpreteze.Pentru a edita
fragmente muzicale,se procedeaza exact invers: se editeaza evenimentele
MIDI,se includ in Tracks si apoi in secvente si se salveaza in file de
tip MIDI.Pentru a putea edita fragmente muzicale,trebuie sa detineti si
un tabel de corespondenta intre nota muzicala si tasta ce defineste nota
respectiva(se poate descarca de pe Internet):
EXEMPLE:
Tasta numarul Codul octavei(englez) Codul octavei(german) Frecventa
-----------------------------------------------------------------------
88 C8 c5 4186.01 Hz
87 B7 h4 3951.07 Hz
86 A7/B7 ais4/b4 3729.31 Hz
85 A7 a4 3520.00 Hz
...............
3 B0 H2 30.8677 Hz
2 A0/B0 Ais2/B2 29.1353 Hz
1 A0 A2 27.5000 Hz
------------------------------------------------------------------------
Cele 9 octave sunt structurate astfel:
Englez: A0 A1 A2 A3 A4 A5 A6 A7 A8
German: A2 A1 A a a1 a2 a3 a4 a5
Frecventa: 27.5 55 110 220 440 880 1760 3520 7040
Exista si numeroase mixere si playere MIDI,cu licenta freeware ce pot
fi descarcate gratuit de pe Internet: MidiSwing,FruityLoops ...etc.
Formatul MIDI,ofera o calitate limitata pentru sunet,dar este extrem de
util pentru educatia muzicala primara: solfegii,compozitie,ritm si tact,
descifrarea unor partituri,backing instrumental,muzica techno...etc.
-161-
JAVA MANAGEMENT
In orice limbaj de programare,una dintre activitatile prioritare ale
programatorului este legata de gestionarea resurselor: unitati de memorie,
unitati de procesare,aplicatii,file de resurse...etc.Orice program sau
aplicatie,nu se poate dezvolta si nu poate rula decat intr-un anumit
context hardware/software,denumit generic "mediul de operare".Metodele
primitive,nu implica structuri specializate:
EXEMPLU:
import java.io.*;
import java.awt.*;
import java.awt.event;
import javax.swing.*;

public class Aplicatie1 extends JPanel implements ActionListener {


public static int numar = 0;
static JButton buton1;
public Aplicatie1() {
buton1 = new JButton("Apasa");
buton1.addActionListener(this);
add(buton1);
}
public static void main(String[] args) {
JFrame frame = new JFrame("Aplicatie");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Aplicatie1());
frame.setSize(300,200);
frame.pack();
frame.setVisible(true);
}
public void actionPerformed(ActionEvent) {
numar = numar + 1;
buton1.setText(String.valueOf(numar));
File fila1 = new File("FilaControl.txt");
try(
FileWritter agent1 = new FileWritter("FilaControl.txt");
agent1.write("Nr. de click-uri= " + String.valueOf(numar));
agent1.close();
} catch (IOException e) { buton1.setText("Eroare"); };
}}
-salvati fila cu numele Aplicatie1.java.Compilati si executati.
In exemplul de mai sus,pur si simplu se ataseaza la aplicatie o fila
simpla de tip text,in care se monitorizeza numarul de click-uri pentru
un anumit buton.Cu acest gen de solutie,se pot supraveghea si inregistra
o parte dintre evenimentele din aplicatie.Fie se inregistreaza toate eve-
nimentele intr-o singura fila de tip text,fie se utilizeaza mai multe
file de tip text in care evenimentele se grupeaza in functie de un anumit
criteriu (pentru a fi mai usor de sortat).Majoritatea sistemeleor de ope-
rare utilizeaza insa tabele si baze de date,in care se inregistreaza
automat toate evenimentele din aplicatie.Pentru analiza,se pot executa
apoi diverse operatii de sortare si filtrare in tabele.Toate aceste so-
lutii,se pot implementa fara obiecte software specializate.

-162-
Platforma Java,implementeaza insa un set destul de bogat de interfete
si clase specializate,concepute special pentru a permite adminstrarea
cat mai judicioasa a resurselor si aplicatiilor,inclusiv in cazul unei
retele de calculatoare interconectate.Initial,aceste resurse au fost
incluse in pachetul java.lang.management,iar apoi s-a adaugat si pachetul
javax.management.Impreuna,cele doua pachete sunt cunoscute sub numele de
JMX Technology (Java Management Extensions technology) si reprezinta un
standard pentru platforma Java,incepand cu versiunea 5.0.Scopul principal
al acestei tehnologii este cel de a simplifica operatiile de administrare
si gestionare a retelelor,cu ajutorul unui standard comun.Respectand
acest standard,cu o singura aplicatie de control se pot supraveghea si
gestiona toate aplicatiile de tip Java din retea (cu conditia sa contina
un modul specializat denumit MBean).
Pentru supravegherea operatiilor executate de Java Virtual Machine,
pachetul Java contine si un executabil specializat,denumit "jconsole".
Inainte de a explora cele doua pachete destinate pentru management,este
bine sa explorati putin acest utilitar.
EXEMPLU:
-lansati in executie orice aplicatie Java -de exemplu Aplicatie1
-executati un dublu click pe jconsole.exe
-se va deschide fereastra Java Monitoring & Management Console in care
este deschisa fereastra de dialog: JConsole: New Connection
-pentru a va conecta la aplicatia dorita,alegeti din lista Local Process
aplicatia dorita si apoi apasati butonul Connect
-in fereastra se va afisa o analiza grafica a principalelor elemente
de management: memoria de stiva,numarul de thread-uri active,numarul
de clase active (in tot computerul),procentul de activitate a proceso-
rului principal.
-cu ajutorul meniului,puteti explora in profunzime oricare dintre
optiuni.De exemplu,alegeti optiunea Threads
-se va afisa o analiza grafica,dar si lista completa a firelor aflate
in executie la un anumit moment dat.Executati un click pe oricare
dintre ele,pentru a afisa o descriere mai detailiata.
-o alta viziune de ansamblu o ofera aptiunea VM Summary,in care este
prezentata sintetic Java Virtual Machine actuala.
-ultima optiune,MBeans include interfetele specializate pentru manage-
ment.De exemplu,puteti sa alegeti aceasta optiune si apoi sa selectati
JMImplementation.Deschideti folderul pentru a gasi MBeanServerDelegat,
adica serverul dedicat operatiilor administrative de tip MBean.
-in continuare,explorati dupa bunul plac acest utilitar.
Este usor de observat ca "jconsole" poate fi utilizata cu succes pentru
a verifica oricare dintre aplicatiile realizate de d-voastra.Lansati in
executie aplicatia,apoi deschideti jconsole pentru a verifica cata memorie
consuma,ce volum de procesare solicita,cate thread-uri si clase sunt
active...etc.Mai mult decat ata,puteti lansa in executie mai multe apli-
catii in paralel,pentru a putea estima volumul total de memorie si randa-
mentul procesorului instalat.Acest utilitar este mai complex decat Task
Manager din Windows si ofera o imagine de ansamblu asupra tuturor opera-
tiilor din calculator (nu doar cele din mediul Java).In plus,acest utili-
tar va familiarizeaza cu principalele aspecte ce trebuiesc urmarite in
munca de administrare a sistemului,sau a unei retele locale.

-163-
Utilitarul jconsole este realizat cu tehnologia JMX.In principiu,prin
tehnologia JMX se poate face legatura dintre o anumita resursa locala si
o aplicatie de control,situata in acelasi calculator,sau la o locatie
oarecare din retea.Pentru acest scop,exista mai multe nivele de actiune:
-primul nivel este in unitatea de lucru ce contine resursa ce urmeaza sa
fie administrata (Exemplu: Unitatea de memorie C in care este arhivata
o anumita aplicatie).Pentru legatura cu aceasta resursa,se utilizeaza o
interfata specializata ce contine in numele sau si sufixul MBean.
-urmatorul nivel il reprezinta obiectul ce implementeaza aceasta inter-
fata.Acest obiect va purta numele de Managed Beans (administratorul de
elemente),sau pe scurt MBean.In acest obiect vor fi definite toate ope-
ratiile ce se pot executa asupra resursei administrate.
-urmatorul nivel este un server local de tip MBean,prin care obiectul de
tip MBean poate comunica cu restul retelei.Este esential ca obiectul de
tip MBean sa fie inregistrat in acest server (cu ajutorul unor functii
specializate).
-nivelul urmator este reprezentat prin conectoarele si protocoalele de
comunicatie specifice pentru reteaua respectiva (Exemple: protocolul de
tip SNMP-Simple Network Management Protocol,sau protocoale private)
-ultimul nivel este reprezentat prin aplicatia din retea cu ajutorul
careia se opereaza asupra resursei administrate (Exemplu: un utilitar de
genul "jconsole.exe").
In alti termeni,tehnologia JMX poate fi rezumata astfel:
1.Instrumentation (instrumentarea) -este reprezentata prin obiectele Java
ce fac conexiunea cu resursa administrata (interfata si clasa MBean).
2.JMX Agent (agentul administrator) -este reprezentat prin serverul local
si protocoalele de cominicatie ce asigura legatura intre obiectul MBean
si server.
3.Remote management(administrarea de la distanta) - este reprezentat prin
programul sau programele utilizate pentru a opera asupra resursei.Acest
program poate fi situat in acelasi calculator,sau undeva in retea.
Interventia propriu zisa asupra resursei se face cu ajutorul obiectului
MBean.Pentru acest scop,obiectul MBean poate sa contina:
-un set de atribute fixe sau reconfigurabile
-un set de operatii (functii predefinite)
-un set de informatii prin care obiectul se autodescrie (atribute,operatii
posibile,autor sau licenta,modul de utilizare etc.)
Pentru a realiza un obiect de tip MBean,se va defini o interfata MBean,
sau se va putea utiliza una dintre interfetele predefinite (DynamicMBean).
Aceasta interfata va contine toate atributele si operatiile ce vor fi
vizibile in aplicatia de control.In mod curent este mai usor sa definiti
o interfata simpla,dar daca doriti sa utilizati interfetele predefinite,
va trebui ca in clasa de implementare sa definiti toate metodele din
interfata sablon.
Prin conventie,numele intefetei MBean se formeaza prin adaugarea sufix-
ului MBean la numele clasei de implementare.
De exemplu: daca dorim sa transformam clasa Aplicatie1 intr-o clasa
de tip MBean,vom denumi aceasta aplicatie: Aplicatie2,iar interfata de
tip MBean se va numi Aplicatie2MBean.
Cu ajutorul unui modul de tip MBean,aplicatia va putea fi controlata
si de la distanta,de exemplu din "jconsole.exe".

-164-
EXEMPLU: interfata MBean poate fi urmatoarea:

public interface Aplicatie2MBean {


public String getName();
public void SetName(String sir1);
public void Salveaza2();
}
-salvati fila cu numele Aplicatie2MBean.java si compilati fila.
Obiectul de implementare va fi urmatorul:
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Aplicatie2 extends JPanel implements Aplicatie2MBean{


public static int numar = 0;
static JButton buton1;
public String name = "Java Management";
public String getName() { return this.name; }
public void SetName(String sir1){ this.name = sir1; };
public void Salveaza2() {
JPanel panou1 = new JPanel();
buton1 = new JButton("Apasa");
ActionListener actiune1 = new ActionListener() {
public void actionPerformed(ActionEvent evt){
numar = numar + 1;
buton1.setText(String.valueOf(numar));
File fila1 = new File("FilaControl.txt");
try{
FileWriter agent1 = new FileWriter("FilaControl.txt");
agent1.write("Nr. de click-uri= " + String.valueOf(numar));
agent1.close();
} catch (IOException e) { buton1.setText("Eroare"); };
}};
buton1.addActionListener(actiune1);
panou.add(buton1);
JFrame frame = new JFrame("Aplicatie");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panou1);
frame.setSize(300,200);
frame.pack();
frame.setVisible(true);
}
public Aplicatie2() { Salveaza2(); };
public static void main(String[] args) {
Aplicatie2 a1 = new Aplicatie2();
}}
-salvati fila cu numele Aplicatie2.java.Compilati fila.
Obiectul MBean este gata.Poate fi utilizat in continuare la fel ca si
Aplicatie1,dar pentru a putea fi utilizat in sistem "remote control" este
necesar sa fie inregistrat in serverul local MBean.

-165-
Prin conventie,server-ul local contabilizeaza clasele inregistrate cu
ajutorul unei clase specializate,denumita Main.Daca exsita aceasta clasa,
va trebui sa adaugati si inregistrarea noului obiect MBean,iar daca nu
exista,o puteti defini astfel:

import java.lang.management.ManagementFactory;
import java.util.Queue;
import java.util.concurent.ArrayBlockingQueue;
import javax.management.MBeanServer;
import javax.management.ObjectName;

public class Main {


public static void main(String[] args) throws Exception {
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
ObjectName mbeanName = new ObjectName("EXEMPLU:type=Aplicatie2");
Aplicatie2 mbean = new Aplicatie2();
mbs.registerMbean(mbean,mbeanName);
System.out.println("Se executa Aplictie2MBean...");
Thread.sleep(300000);
}
}
-salvati fila cu numele Main.java si compilati.
In continuare,aplicatia Aplicatie2 poate fi monitorizata si din
jconsole.
EXEMPLU: -lansati in executie clasa Main (cu java Main).
-lansati in executie jconsole.exe
-conectati jconsole la aplicatia Main
-alegeti din meniu optiunea MBeans
-deschideti folderul EXEMPLU
-expandati nodul Aplicatie2
-expandati cele doua noduri: Attributes si Operations
-selectati Name
Se va afisa valoarea atributului respectiv (Java Management)
-selectati SetName,completati un text in loc de String si apoi
apasati butonul SetName.
-selectati din nou Name,pentru a verifica operatia
-selectati operatia Salveaza2
-apasati de cateva ori butonul din fereastra Aplicatie,apoi
apasati butonul Salveaza2 (din jconsole).Observati ca fereastra
se reseteaza automat.
Cu alte cuvinte,din jconsole se poate avea acces la instanta activa a
clasei Aplicatie2,se pot prelua informatii,se pot seta atributele,sau
chiar se pot executa operatii complexe asupra resursei.
Urmatoarele obiecte MBean vor fi inregistrate in clasa Main in conti-
nuarea celor existente.Astfel,prin lansarea in executie a clasei Main,
se va putea avea acces la oricare dintre aplicatiile inregistrate.In
exemplul de mai sus,am utilizat pentru clasa Main un thread ce se inchide
automat dupa 5 minute.Daca doriti ca aplicatiile sa poata fi monitorizate
permanent,se va putea utiliza comanda Thread.sleep(Long.Max_VALUE),pentru
a realiza o bucla practic infinita.Inainte de a actualiza Clasa Main,este
bine sa va asigurati cu o copie de siguranta (pentru a putea reveni).

-166-
Pentru ca aplicatia sa poata fi deschisa cu jconsole de pe un alt
terminal din retea,este necesar ca serverul sa fie conectat la retea prin
un port de comunicatie.Serverul MBeans include conectorul JMX automat si
asculta solicitarile primite de la clienti.Pentru ca protocolul sa fie
complet este insa necesar ca in clasa Main sa fie inregistrat si autenti-
ficat portul de comunicatie prin care se va face schimbul de date.
Portul se poate inregistra de exemplu astfel:
java -Dcom.sun.management.jmxremote.port=9999 \
-Dcom.sun.management.jmxremote.authenticate=false \
-Dcom.sun.management.jmxremote.ssl=false \
Main
(-D seteaza respectiva proprietate a sistemului -vezi java.exe Options)
Cand doriti sa accesati o aplicatie situata pe alt calculator,lansati
jconsole,alegeti optiunea Remote Process si introduceti numele unitatii
de lucru si portul de cominicatie:
EXEMPLU: hostname:9999
Detaliile referitoare la comunicatiile din retea nu fac obiectul
acestui manual.Java contine un set de structuri software dedicate special
pentru operatiile in retea (Networking),dar nu este recomandabil sa inva-
tati aceste protocoale in sistem "autodidact".Pentru comunicatii in retea,
si aplicatii de retea,este recomandabil sa urmati un curs specializat,fie
prin Internet,fie intr-o unitate specializata.
Atunci cand datele cu care se opereaza in serverul MBean nu sunt din
tipurile standard (Exemplu: operati cu obiecte definite intr-o clasa lo-
cala),trebuie sa utilizati obiecte de tip MXBean.MXBean este un obiect
identic cu MBean,dar contine si o referinta (pointer) spre clasa locala
in care este definit tipul de date cu care se opereaza.
Exista si clase MBean dinamice,in care atributele si operatiile expuse
prin interfata MBean nu sunt fixe ci se pot modifica interactiv.In acest
caz,atributele si operatiile MBean vor fi definite cu ajutorul unor clase
locale,denumite "metadata classes".In serverul MBean se va inregistra
obiectul MBean,pentru a asigura conexiunea cu interfata MBean,dar conti-
nutul efectiv al acestei interfete va putea fi modificat dinamic prin
inlocuirea claselor locale (metadata classes).Nici acest mecanism nu face
obiectul acestui manual,deoarece necesita notiuni de programare cu clase
de tip generic,ce depasesc nivelul programatorului incepator.
Cele doua pachete contin clase si interfete ce permit automatizarea
operatiilor.De exemplu,clasa ManagementFactory poate genera automat seturi
de obiecte MXBean.Alte clase sunt destinate pentru administrarea memoriei
si a mediului de operare din Java Virtual Machine.Fiecare obiect MBean,
poate contine si un fel de utilitar "Help",in care sunt descrise principa-
lele caracteristici ale obiectului,incluse intr-un obiect de tip MBeanInfo
MBeanNotificationInfo,MBeanOperationInfo sau MBeanParameterInfo.
Nu se pot face recomandari referitor la modul de exploatare al acestor
resurse.Fiecare programator va apela la aceste clase,in functie de nece-
sitatile de moment,sau in functie de experienta sa personala.Este bine
sa studiati initial aplicatiile de tip management oferite in reteaua
Internet,apoi cautati clasele si metodele prin care se rezolva fiecare
dintre operatii.Cele mai frecvente aplicatii sunt cele care administreaza
sau supravegheaza memoria de operare (intrerup executia atunci cand apare
riscul de supraincarcare).

-167-
EXEMPLU:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Memorie1 extends JPanel {


static JLabel eticheta1,eticheta2;
static Timer timer1;
static String sir1,sir2;
static Long libera,maxima;
public static void main(String[] args) {
JFrame frame = new JFrame("Aplicatie");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout());
eticheta1 = new JLabel("text");
eticheta2 = new JLabel("text");
frame.add(eticheta1);
frame.add(eticheta2);
ActionListener ceas1 = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
libera = Runtime.getRuntime().freeMemory();
maxima = Runtime.getRuntime().maxMemory();
sir1 = String.valueOf(libera);
sir2 = String.valueOf(maxima);
eticheta1.setText("Memoria libera = " + sir1);
eticheta2.setText("Memoria maxima = " + sir2);
if ( Runtime.getRuntime().freeMemory() < 128000)
{ System.exit(0); }
}};
timer1 = new Timer(1000,ceas1);
timer1.start();
frame.setBounds(300,0,300,200);
frame.setVisible(true);
}}
-salvati fila cu numele Memorie1.Compilati si executati.
Exemplul de mai sus,utilizeaza un timer pentru a citi memoria libera
din secunda in secunda.Puteti utiliza un modul asemanator,atunci cand
doriti sa monitorizati memoria accesibila pentru o aplicatie oarecare.
Daca doriti doar sa eliberati automat memoria,atunci cand aceasta scade
sub o anumita limita critica,este suficient sa utilizati bucla if:
if (Runtime.getRuntime(),freeMemory() < limita) { Sysytem.exit(0); }
Nu intotdeauna este necesar sa inchideti complet aplicatia.Daca apli-
catia contine unul sau mai multe thread-uri,este suficient sa suspendati
temporar executia unui thread,pana cand memoria libera revine la valorile
optime pentru executie,apoi relansati automat thread-ul in executie.
In exemplul de mai sus,puteti observa ca memoria libera scade cu un
numar oarecare de bytes,la fiecare bucla de repetitie a timer-ului.Acest
fapt se datoreaza faptului ca la fiecare citire a memoriei,se creaza un
nou obiect.Acest obiect nou,ocupa un volum oarecare de memorie si apoi
ramane fara referinta pentru tot restul aplicatiei.Se spune ca acest gen
de solutie este nesigura ("unsave"),referitor la memoria de operare.

-168-
In orice alt limbaj de programare,acest tip de solutie ar fi necesitat
si o operatie oarecare de eliberare a memoriei.Limbajul Java,contine insa
o structura specializata tocmai pentru acest gen de operatii,denumita
Grabage Collection (colectorul de gunoi).Garbage Collection este procesul
prin care se elibereaza din memorie toate obiectele ramase fara referinta.
Pentru acest scop,Java Virtual Machine contine o serie de tampoane de
memorie cu ajutorul carora poate gestiona toate structurile de date din
program.Mai exact,memoria de operare este sub forma de stiva si este
impartita in trei sectiuni mari: Young Generation (datele recente),Old
Generation (datele vechi) si Permanent Generation (datele permanente).
Pentru datele recente,sectiunea Young generation este formata la randul
sau din trei stive mai mici: Eden Space (2 Mb),From Space (64 Kb) si res-
pectiv To Space(64 Kb).
Orice obiect nou creat,va fi salvat initial in Eden Space.Daca obiectul
urmeaza sa fie apelat din nou,este trecut in From si apoi in To Space,iar
daca urmeaza sa persiste in program,este trecut in stiva numita Old gene-
ration.Obiectele ce sunt necesare pe intreaga durata de executie a progra-
mului,vor fi pastrate in stiva denumita Permanent Space.
PREZENTARE SCHEMATICA:

________________________________________________________________
| Eden Space=2 Mb | From=64 Kb | To=64 Kb |
-----------------------------------------------------------------
|
_________________________________________________________________
| Old Generation = 5 Mb maxim 44 Mb |
-----------------------------------------------------------------
|
_________________________________________________________________
| Permanent Space = 4 Mb |
-----------------------------------------------------------------

In exemplul de mai sus,obiectele fara referinta se vor aduna in Eden


Space,pana cand Garbage Collector va efectua o operatie de eliberare a
memoriei.Acesta operatie are loc atunci cand se umple spatiul denumit
Eden Space,iar procesul poarta si numele de Scavenge Garbage Collector.
Toate clasele ramase fara referinta vor fi eliberate,iar celelalte vor
fi trecute in From.Din acest motiv,aceasta stiva mai poarta si numele de
Survivor Space.Atunci cand stivele From si To sunt pline,obiectele ce su-
pravietuiesc vor fi transferate in stiva denumita Old Generation.In stiva
denumita Permanent Generation sunt pastrate obiectele permanente rezultate
in etapa de compilare a programului.Cand se umple si aceasta stiva,Java
Virtual Machine incearca se elibereze memoria cu o operatie de Garbage
Collection pe toate stivele si daca nu reuseste se va elibera un mesaj de
eroare de tip "Out-of-Memory" si se intrerupe executia.
Asadar,eliberarea memoriei nu se face la intervale fixe de timp,ci
doar atunci cand tampoanele de memorie temporara devin suprasolicitate.
Se elibereaza din memorie prioritar obiectele noi create (daca nu mai
exista nici o referinta spre ele),si doar apoi se vor elibera cele mai
vechi.Pentru a executa o operatie de Garbage Collection pe toate tampoa-
nele,se poate apela si metoda : System.gc().

-169-
In exemplul precedent,incercati sa adaugati in bucla timer-ului si
comanda: Runtime.getRuntime.gc();
In acest mod,se va forta eliberarea memoriei la fiecare secunda.Acest
tip de solutie este sigur ("safe") in ceeea ce priveste memoria.Totusi
in aplicatiile reale nu are rost sa eliberati memoria pentru cativa bytes
ce vor fi oricum eliberati automat la nevoie,dar este practic se efectuati
o operatie de eliberare a memoriei inainte de a lansa un program nou,sau
inainte de a crea un set oarecare de obiecte.Pentru anumite tipuri de
aplicatii,exista si tendinta de a executa o operatie de Garbage Collection
inainte de a incepe executia propriu-zisa.
Trebuie mentionat faptul ca Java Virtual machine nu partajeaza spatiul
de memorie decat cu celelalte aplicatii Java.Are rost se eliberati memoria
doar daca exista si alte aplicatii Java ce ruleaza simultan.
Exista situatii in care doriti sa stiti exact cum este gestionata me-
moria intr-o aplicatie oarecare (De exemplu in aplicatiile editate de
d-voastra).Pentru acest scop,platforma Java va pune la dispozitie doua
utilitare extrem de valoroase: jps.exe si jstat.exe.
Primul dintre ele,jps.exe,detecteaza toate aplicatiile java aflate in
executie la un anumit moment dat si returneaza un cod numeric ce repre-
zinta identificatorul Virtual Machine pentru aplicatia respectiva (vmid).
EXEMPLU: lansati in executie exemplul precedent ( java Memorie1)
deschideti alta fereastra Command Prompt,setati calea de acces si
apoi lansati in executie jps.exe (jps).Se va returna o diagrama de genul:
304 Jps (304 este vmid pentru Jps)
1756 Memorie1 (1756 este vmid pentru Memorie1)
In continuare puteti obtine o schema completa a memorie cu ajutorul
utilitarului jstat (vezi si documentatia tehnica).
EXEMPLU: tastati: jstat -gcutil 1756 250 3
unde: 1756 este codul vmid (utilizati codul returnat de Jps)
250 este intervalul intre doua citiri in milisecunde
3 este numarul de citiri
Se vor afisa urmatoarele tampoane de memorie:
S0 - Survivor space zero (procent din spatiul total)
S1 - Survivor space 1 (procent din spatiul total)
E - Eden space (procent din spatiul total)
O - Old space (procent din total)
P -Permanent space (procent din total)
YGC - numarul de evenimente Garbage Colection in Young generation
YGCCT -timpul ultimei operatii Garbage Collection
FGC - numarul de operatii GC complete (toate tampoanele)
FGCT - timpul/operatie GC completa
GCT - timpul total pentru Grabage Collection
Optiunea gcutil este cea mai frecvent utilizata,dar jstat ofera o
paleta mult mai larga de optiuni: class,compiler,gc,gccapacity,gccause,
gcnew,gcnewcapacity,gcold,gcoldcapacity,gcpermcapacity,printcompilation
si gcutil.Fiecare dintre ele ofera o configuratie diferita de date.
EXEMPLU: jstat -class 1756 1000 5
va returna: Loaded - numarul total de clase active,Bytes - numarul total
de Kbytes incarcati,Unloaded - numarul de clase descarcate,Bytes-numarul
total de Kbytes descarcati si Time-timpul necesar pentru toate aceste
operatii.
-170-
Cele doua utilitare pot fi extrem de utile in etapa de proiectare si
in cea de depanare a programelor.Compilati programul,lansati programul in
executie,detectati codul vmid cu jps.exe,apoi lansati jstat cu un numar
mare de repetitii,la un interval oarecare.Executati in program operatiile
cele mai critice si studiati aspectul tampoanelor de memorie.Atunci cand
memoria consumata se apropie de limita critica,este bine sa inserati in
program si cate o operatie de eliberare a memoriei.
Limita critica va fi stabilita in functie de destinatia programului.
Daca programul urmeaza sa ruleze strict independent,nu este necesar sa
faceti nici un fel de operatii asupra memoriei.Java va elibera automat
tampoanele atunci cand este cazul.Insa,in cazul aplicatiilor ce urmeaza
sa fie executate concurential,aceasta limita critica va trebui sa fie
astfel aleasa incat toate programele sa poata rula concomitent.
O solutie alternativa este sa construiti fiecare aplicatie sub forma
de thread-uri.Fiecare thread va citi automat memoria libera si va executa
o pauza,atunci cand memoria libera este deficitara.Cu un astfel de algo-
ritm,programul d-voastra se va putea adapta la situatia de moment,fara
interventia programatorului.
Se pot imagina numaroase scenarii.Are rost sa implementati solutii
spaciale pentru administrarea memoriei,doar in situatiile in care stiti
sigur ca programul d-voastra va rula intr-un mediu multiprocesare concu-
rentiala in care exista riscul de a supraincarca memoria de operare.In
acest caz,vor trebui selectate procesele prioritare,fata de cele cu im-
portanta secundara.Solutia ce mai simpla este sa pastrati activ un singur
thread,cel ce administreaza executia celorlalte thread-uri.In acest thread
cititi periodic memoria libera si implementati secventa de prioritati.Pe
masura ce memoria se elibereaza,thread-ul administrator va putea lansa in
executie noi si noi thread-uri.
Pentru a crea aplicatii personalizate de administrare a memoriei se
pot utiliza metodele claselor din cele doua pachete de management.
Pachetul java.long.management contine urmatoarele clase: LockInfo,Monitor-
Info,ManagementFactory,MemoryNotificationInfo,MemoryUsage,ManagementPer-
mision si ThreadInfo,iar la acestea se adauga si urmatoarele interfete:
ClassLoadingMXBean,CompilationMXBean,MemoryManagerMXBean,GarbageCollector-
MXBean,MemoryMXBean,MemoryPoolMXBean,OperatingSystemMXBean,RuntimeMXBean,
RuntimeMXBean,ThreadMXBean.
Nici una dintre aceste clase nu contine metode cu acces direct la
memorie.Din acest motiv,pentru a putea beneficia de avantajele oferite
de aceste structuri software,trebuie sa cititi cu foarte mare atentie
documentatia tehnica (sau tutoriale specializate) si apoi sa combinati
cate doua sau mai multe clase si interfete.
De exemplu: -interfata MemoryMXBean administreaza toata memoria din
Java Virtual Machine.Ca urmare,permite prin metodele sale detectarea
memoriei de stiva,a memoriei non stiva,activarea rutinei de Garbage
Colector sau detectarea numarului de obiecte aflate inca in stare de
asteptare (referite dar neprocesate).Prin metodele getHeapMemoryUsage() si
getNonHeapMemoryUsage() se poate obtine un obiect de tip MemoryUsage,din
care se pot determina: memoria alocata (cu getComitted() ),memoria maxima
alocabila (cu getMax() ),memoria utilizata actual (cu getUsed())...etc.
Pentru acest scop se va edita cate o functie specializata in care un
obiect de tip MemoryUsage returneaza valoarea de tip long dorita.
-171-
Pentru a obtine o instanta a interfetei MemoryMXBean se poate utiliza
metoda ManagementFactory.getMemoryMXBean().
EXEMPLU:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;

public class Memorie2 extends Jpanel {


static JLabel eticheta1,eticheta2;
static String sir1,sir2;

public static void main(String[] args){


JFrame frame = new JFrame("Aplicatie");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout());
eticheta1 = new JLabel("text");
eticheta2 = new JLabel ("text");
frame.add(eticheta1);
frame.add(eticheta2);
MemoryMXBean memory = ManagementFactory.getMemoryMXBean();
sir1 = String.valueOf(reportStatus(memory));
sir2 = String.valueOf(reportUsed(memory));
eticheta1.setText("Memoria alocata = " + sir1);
eticheta2.setText("Memoria utilizata = " + sir2);
frame.setBounds(300,0,300,200);
frame.setVisible(true);
}
private static Long reportStatus(MemoryMXBean memory) {
Long m1 = memory.getHeapMemoryUsage().getCommited();
return m1; }
private static Long reportUsed(MemoryMXBean memory) {
Long m2 = memory.getHeapMemoryUsage().getUsed();
return m2; }
}
-salvati fila cu numele Memorie2.java.Compilati si executati.
Un astfel de modul poate fi extrem de util in etapa de proiectare si
programare a unei aplicatii.Pur si simplu includeti un astfel de modul in
punctele cheie ale executiei,pentru a verifica memoria consumata pana la
operatia respectiva.In functie de rezultat,puteti reajusta obiectele in
asa fel incat sa optimizati consumul de memorie.Solutia cea mai simpla
este sa impartiti executia in mai multe thread-uri.Apoi utilizati un
astfel de modul de memorie,pentru a echilibra pe cat posibil thread-urile
intre ele.In final,stabiliti ordinea de prioritati pentru executia thread-
urilor astfel incat programul sa ruleze cat mai lin si sa lase cat mai
multa memorie de operare pentru alte aplicatii Java ce ruleaza in paralel.
Exista si programe specializate ce executa si raporteaza toate aceste
operatii in mod automat.Aceste programe,fac "apanajul" analistilor-progra-
matori si vor decide daca aplicatia d-voastra va fi acceptata pentru uzul
general,sau va ramane doar de interes restrans.

-172-
In mod similar,se poate utiliza interfata MemoryPoolMXBean,pentru a
putea analiza tampoanele de memorie din Java Virtual Machine.
EXEMPLU:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.lang.management.*;
import java.util.*;

public class Memorie3 extends JPanel {


static JTextArea text1;
static String sir1,sir2;
public static void main(String[] args) {
JFrame frame = new JFrame("Aplicatie");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout());
text1 = new JTextArea(40,75);
text1.setEditable(false);
JScrollPane scrol1 = new JScrollPane(text1);
frame.add(scrol1);
InfoMemorie();
frame.setBounds(0,0,900,700);
frame.setVisible(true);
}
public static void InfoMemorie()
{ try {
text1.append("Memory Pools (tampoane de memorie): ");
java.util.List<memoryPoolMXBean> tampoane =
ManagementFactory.getMemoryPoolMXBeans();
for ( MemoryPoolMXBean tampon : tampoane)
{
text1.append( "\n Nume: " + tampon.getName() + "\n");
text1.append("Memorie consumata: "+ tampon.getUsage()+ "\n");
text1.append
("Utilizata din container: "+tampon.getCollectionUsage()+"\n");
text1.append
("Maxim utilizata: "+tampon.getPeakUsage()+"\n");
text1.append("Tip memorie: " + tampon.getType()+"\n");
text1.append("Numele managerului: ");
String[] numeManager = tampon.getMemoryManagerNames();
for (int i=0; i< numeManager.length;i++)
{ text1.append("\n" + numeManager[i] + "\n"); }
}}
catch( Exception e )
{ text1.append("Eroare la citirea tampoanelor ! "); }
}}
-salvati fila cu numele Memorie3.java.Compilati si executati.
In aplicatii,puteti insera temporar un astfel de modul,pentru a veri-
fica tampoanele de memorie intr-un anumit moment al executiei,sau puteti
conecta modulul la un buton,pentru a putea verfica memoria in orice
moment al executiei.

-173-
Cel de al doilea pachet administrativ,denumit javax.management,contine
un alt set de interfete si clase,destinate mai ales pentru schimb de date
intre doua instante de Java Virtual Machine,respectiv intre doua calcula-
toare diferite.Acest pachet depaseste nivelul de interes al incepatorilor
si este destinat mai ales adminstratorilor de retea.Totusi,daca doriti
sa instalati aplicatii Java pe mai multe calculatoare din retea si apoi
sa le monitorizati cu un program unic,este recomandabil sa studiati si
acest pachet.Descrierea exhaustiva se gaseste in documentul editat de
firma Sun,cu numele "Java Management Extensions (JMX) Remote API 1.0 Spe-
cification".Principalele clase si interfete se gasesc in pachetul javax.-
management.remote si definesc impreuna un standard de comunicatie ce are
urmatoarele caracteristici: flexibilitate,securitate,transparenta si
interoperabilitate:
-este flexibil,pentru ca permite adaugarea de noi protocoale si de solutii
pentru implementarea acestor protocoale noi
-este securizat prin urmatoarele standarde de securitate: Java Secure
Socket Extension (JSSE),Simple Authentification,Security Layer(SASL) si
Java Authentification and Authorization Service
-este transparent,deoarece expune catre client o interfata aproape iden-
tica cu cea arhivata in server-ul ce asigura comunicatia
-este interoperabil,deoarece clientul poate comunica cu server-ul prin
protocoale diferite,cu conditia sa respecte acest standard (clientul si
serverul pot utiliza implementari ale unor protocoale diferite)
In esenta,sistemul este format dintr-un server,unul sau mai multi
clienti si conectoarele dintre server si clienti.Aceste structuri se
gasesc atat la nivel de hardware (calculatoare si cabluri),cat si la
nivel de software (tampoane de memorie in care se organizeaza clasele si
interfetele ce administreaza operatiile dorite).Conexiunile fizice din
sistem (cele hardware) sunt permanente,in timp ce conexiunile software
se organizeaza prin algoritmii doriti (se deschid si se inchid atunci
cand este necesar).Exista un conector server si un conector client.In
fiecare dintre conectoare,se vor include clasele si interfetele necesare
pentru setul de operatii dorit.Ca rezultat al unei conexiuni,trebuie ca
terminalul de tip client sa expuna pentru operatii o interfata identica
cu cea arhivata in serverul MBean.Evident ca sistemul opereaza doar cu
clase de tip MBean.Protocolul definit pentru acest standard poarta numele
de Remote Method Invocation (RMI).
Comunicatia dintre server si client se face in sesiuni (sessions).O
sesiune este creata in momentul in care se defineste conectorul de tip
client.Sesiunea este prezenta si atunci cand conectorul software este
inchis.Astfel,in timpul unei sesiuni,conectorul poate fi deschis si apoi
inchis de mai multe ori,pentru a realiza conexiuni software repetate.O
conexiune este deschisa,atunci cand conectorul client a accesat serverul
pe unul dintre porturile de comunicatie posibile (portul de comunicatie
solicitat trebuie sa existe si sa fie liber).
EXEMPLU: connect "service:jmx:rmi://host:9876"
Dupa ce este creat,serverul software poate fi deschis,pentru a astepta
conexiunile de tip client.Daca serverul este deschis si se creaza un co-
nector de tip client pe care se realizeaza o conexiune,se deschide o noua
sesiune de comunicatie.Pentru a semnaliza aceste operatii,serverul MBean
poate adauga si Remote Listeners ( cu addNotificationListener).

-174-
Asadar,pentru un sistem complet sunt necesare urmatoarele programe:
o interfata MBean,o clasa MBean,un server MBean si un program client.
EXEMPLU: INTERFATA MBEAN

public inteface SampleMBean { public String getHello(); }


-salvati fila cu numele SampleMBean.java si apoi compilati fila

CLASA MBEAN

import javax.management.*;
public class Sample implements SampleMBean {
private String hello = "Hello World(s)!";
public Sample() {}
public String getHello() { return hello; }
}
-salvati fila cu numele Sample.java si compilati fila

SERVERUL MBEAN (Agentul pentru administrare)

import javax.management.MbeanServer;
import java.lang.management.ManagementFactory;
import javax.management.ObjectName;
import javax.management.remote.*;

public class SimpleAgent {


public static JMXConnectorServer server;
public static void main(String[] args) throws Exception {
String host = "127.0.0.1";
int port = 9998;
String urlPath = "";
MbeanServer mbs = ManagementFactory.getPlatformMBeanServer();
mbs.registerMBean(new Sample(),new ObjectName(":type=Sample"));
server = JMXConnectorServerFactory.newJMXConnectorServer
(new JMXServiceURL("rmi",host,port,urlPath),null,mbs);
server.start();
System.out.println("Serverul este pornit cu: " +
server.getAddress() + " \n Asteapta conexiuni ....");
Thread.sleep(5000);
server.stop();
}}
-salvati fila cu numele SimpleAgent.java.Compilati si executati.
In cele trei exemple de mai sus,am creat o interfata MBean ce expune
o singura metoda,apoi o clasa MBean in care este implementata aceasta
interfata.Metoda din clasa MBean,returneaza un string ce contine un anumit
mesaj (un mesaj de salut in acest caz).Agentul de management este serverul
MBean.In exemplul de mai sus,serverul este deschis,asteapta conexiuni timp
de 5 secunde,apoi se inchide automat.In mod normal,un astfel de server va
sta deschis pentru perioade de timp mult mai lungi,sau chiar permanent,
pentru a putea fi accesat de catre aplicatiile client.
In mediul de operare real,va trebui sa cunoasteti exact adresele URL,
atat pentru serverul accesat,cat si pentru client.

-175-
Aplicatia client,ruleaza pe unul sau mai multe terminale din retea,de
obicei altele decat cel pe care ruleaza aplicatia server.Pentru a exem-
plifica insa modul de lucru,in exempul urmator vom include atat serverul
cat si clientul in acelasi exemplu (pentru a garanta conexiunea software).
APLICATIA CLIENT
import javax.naming.*;
import javax.management.*;
import java.lang.management.ManagementFactory;
import javax.management.remote.*;
import java.util.*;
import java.io.IOException;

public class SimpleClient {


public static JMXConnector connector;
public static JMXConnectorServer server;
public static void main(String[] args) throws Exception {
int port = 9998;
String host = "SimpleAgent";
String urlPath = "";
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
mbs.registerMBean(new Sample(),new ObjectName(":type=Sample"));
server = JMXConnectorServerFactory.newJMXConnectorServer
(new JMXServiceURL("rmi",host,port,urlPath),null,mbs);
server.start();
System.out.println("Serverul este pornit...");
try { connector = server.toJMXConnector(null);
connector.connect();
} catch (IOException e) { System.out.println("Eroare !"); }
System.out.println("Conexiunea este deschisa...");
MBeanServerConnection connection = connector.getMBeanServerConnection();
ObjectName mbeanName = new ObjectName(":type=Sample");
String value = (String) connection.getAttribute(mbeanname,"Hello");
System.out.println("Datele receptionate= ..." + value);
connector.close();
System.out.println("Conexiunea este inchisa !");
server.stop();
System.out.println("Serverul este oprit !");
Thread.sleep(5000);
}}
-salvati fila cu numele SimpleClient.java.Compilati si executati
In exemplul de mai sus,clientul apeleaza serverul pentru a receptiona
datele din clasa MBean inregistrata in server.Acest gen de solutie se
poate utiliza cu succes,atunci cand doriti sa monitorizati mai multe
aplicatii Java ce ruleaza in paralel pe acelasi calculator.Observati ca
pentru conectorul client am utilizat direct adresa serverului.
In mediul real,lucrurile se complica foarte mult.Pe langa protocoalele
de securitate din standard,se adauga toate protocoalele de securitate din
reteaua respectiva (filtre,parole,autentificare,protocolul de comunicatie,
verificarea gazdei,a portului solicitat...etc.).In mediul de retea,este
o adevarata "arta" sa obti o conexiune buna,in timp cat mai scurt.Timpul
cel mai bun,pare sa fie realizat prin socket-uri si protocol TCP.

-176-
Pachetul javax.management include si un mecanism complex de anunturi,
prin care orice modificari ale atributelor din clasa MBean pot fi tran-
smise automat catre aplicatia de comanda.Acest gen de anunturi poarta
numele de notificari si necesita un set intreg de clase si interfete.
Astfel,pentru a putea crea anunturi,clasa MBean trebuie sa implementeze
si o interfata de tip NotificationEmitter sau NotificationBroadcasterSup-
port,iar pentru a putea transmite aceste anunturi trebuie sa includa si
un obiect de tip Notification.La randul sau,aplicatia ce primeste aceste
anunturi,trebuie sa contina un obiect de tip Listener special creat pentru
a receptiona aceste anunturi.
EXEMPLU: INTERFATA MBEAN
public interface HelloMBean {
public int getCacheSize();
public void setCacheSize(int size);
}
-salvati fila cu numele HelloMBean.java si compilati fila.

CLASA MBEAN
import javax.management.*;

public class Hello extends NotificationBroadcasterSupport


implements HelloMBean {
public int getCacheSize() { return this.cacheSize; }
public synchronized void setCacheSize(int size) {
int oldSize = this.cacheSize;
this.cacheSize = size;
System.out.println("Valoarea actuala CacheSize: " + this.cacheSize);
Notification n = new AttributeChangeNotification(this,sequenceNumer++,
System.currentTimeMillis(),"CacheSize changed","CacheSize","int",
oldSize,this.cacheSize);
sendNotification(n);
}
@Override
public MBeanNotificationInfo[] getNotificationInfo() {
String[] types = new String[] {
AttributeChangeNotification.ATTRIBUTE_CHANGE };
String name = AttributeChangeNotification.class.getName();
String description = "Unul dintre atributele MBean a fost schimbat!";
MBeanNotificationInfo info =
new MbeanNotificationInfo(types,name,description);
return new MBeanNotificationInfo[] { info } ;
}
private final String name = "Textul dorit";
private int cacheSize = DEFAULT_CACHE_SIZE;
private static final int DEFAULT_CACHE_SIZE = 200;
private long sequenceNumber = 1;
}
-salvati fila cu numele Hello.java si compilati fila.
Cele doua file de mai sus alcatuiesc clasa MBean ce este capabila sa
anunte orice modificare a atributului sau cacheSize,catre un listener
specializat din aplicatia de control.

-177-
APLICATIA DE CONTROL (managerul clasei MBean)
import java.util.*;
import java.io.IOException;
import javax.management.*;
import javax.management.remote.*;
import javax.naming.*;
import java.lang.management.ManagementFactory;

public class Monitor1 {


public static JMXConnector jmxc;
public static JMXConnectorServer server;
public static class ClientListener implements NotificationListener {
public void handleNotification(Notification notification,Object handback){
echo("\n Notificarea receptionata este: ");
echo("\t ClassName: " + notification.getClass().getName());
echo("\t Source: " + notification.getSource());
echo("\t Type: " + notification.getType());
echo("\t Message: " + notification.getMessage());
if (notification instanceof AttributeChangeNotification) {
AttributeChangeNotification acn =
( AttributeChangeNotification) notification;
echo("\t AttributeName: " + acn.getAttributeName());
echo("\t AttributeType: " + acn.getAttributeType());
echo("\t NewValue: " + acn.getNewValue());
echo("\t OldValue: " + acn.getOldValue());
}}}
public static void main(String[] args) throws Exception {
int port = 9998;
String host = "SimpleAgent";
String urlPath = "";
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
mbs.registerMBean(new Hello(),new ObjectName(":type=Hello"));
server = JMXServiceURL("rmi",host,port,urlPath),null,mbs);
server.start();
System.out.println("Serverul este pornit...");
try { jmxc = server.toJMXConnector(null);
jmxc.connect();
} catch (IOException e) { System.out.println("Eroare !"); }
System.out.println("Conexiunea este deschisa...");
ClientListener listener = new ClientListener();
waitForEnterPressed();
MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();
MbeanServerConnection connection = jmxc.getMBeanServerConnection();
echo("\n Se executa operatii asupra obiectului MBean...");
ObjectName mbeanName = new ObjectName(":type=Hello");
HelloMBean mbeanProxy =
JMX.newMBeanProxy(mbsc,mbeanName,HelloMBean.class,true);
mbsc.addNotificationListener(mbeanName,listener,null,null);
echo("\n CacheSize initial= " + mbeanProxy.getCacheSize());
mbeanProxy.setCacheSize(600);
-continuare pe pagina urmatoare

-178-
echo("\n Se asteapta notificarea....");
try {
Thread.sleep(2000);
} catch (InterruptedException e){};
waitForEnterPressed();
echo("\n Se inchide conexiunea cu serverul...");
jmxc.close();
server.stop();
echo("\n Bye! Bye!");
waitForEnterPressed();
}
private static void echo(String msg) {
System.out.println(msg);
}
private static void waitForEnterPressed() {
try {
echo("\n Press <Enter> to continue...");
System.in.read();
} catch (IOException e) {}
}
-salvati fila cu numele Monitor1.java.Compilati si executati.
In exemplul de mai sus,executia este fragmentata in mai multe etape,
cu ajutorul functiei waitForEnterPressed.Puteti verifica modul in care
se executa anunturile (notificarile) in mai multe moduri:
1. rulati exercitiul pana la capat.Valoarea pentru cacheSize va fi rese-
tata in cadrul exercitiului si dupa o usoara intarziere va veni si
notificarea emisa de clasa MBean
2. porniti in executie Monitor1,pana la pornirea serverului si stabilirea
conexiunii.Apoi,deschideti in alta fereastra aplicatia JConsole si
faceti conexiunea cu Monitor1.Alegeti MBeans,apoi DefaultDomain si
din nodul Hello alegeti Attributes,apoi CacheSize.Modificati de cateva
ori valoarea si confirmati cu butonul Refresh.Observati in Monitor1
anuntul inregistrat.Eventual studiati si nodul Notifications.
3. Creati o clasa noua in care construiti un obiect de tip Hello si un
algoritm pentru resetarea valorii cacheSize.Lansati in executie in
ferestre diferite,noua clasa si clasa Monitor1.Resetati valoarea pentru
cacheSize in noua clasa si observati notificarile din calsa Monitor1.
La prima vedere acest mecanism pare destul de greoi,dar cu putin exerci-
tiu anunturile vor fi din ce in ce mai usor de controlat.Prin acest meca-
nism simplu se pot realiza algoritmi pentru diverse operatii automate,
roboti,motoare de cautare,sisteme de avertizare si control,rutine pentru
actualizare automata,aplicatii pentru automatizarea unor procese,manage-
ment de tip "remote control"...etc.Cu alte cuvinte,numarul de aplicatii
posibile este foarte mare si ofera o intreaga paleta de operatii greu de
realizat in alte limbaje de programare.
Pentru a controla si mai strict modul in care se fac anunturile,se
pot utiliza obiecte de tip Monitor.Aceste obiecte monitorizeaza un anumit
atribut si nu trimit notificarile decat in situatia in care se indepli-
neste o anumita conditie (actioneaza ca un fel de filtru software,prin
care se limiteaza notificarile,doar la situatiile semnificative).Exista
trei tipuri de monitoare : numarator(int),contor(int),comparator de text.
-179-
Pachetul javax.management.monitor contine trei astfel de monitoare
specializate: CounterMonitor,GaugeMonitor si StringMonitor.Aceste clase
sunt insa mai putin recomandabile,din urmatoarele motive:
-nu au o interfata grafica facila
-este necesar cate un obiect separat pentru fiecare atribut MBeans
-mecanismul de setare este greoi si ineficient
-consuma nejustificat de multa memorie de operare
Acelasi rezultat poate fi obtinut cu o simpla bucla IF...si o notifi-
care simpla.
EXEMPLU: in exemplul precedent,modificati in clasa Hello,functia prin
care se seteaza valoarea atributului astfel:
public synchronized void setCacheSize(int size) {
this.cacheSize = size;
System.out.println("Valoarea actuala CacheSize: "+this.cacheSize);
Notification n = new Notification("Notificare: ",this,
sequenceNumber,"CacheSize a depasit valoarea limita !");
if (this.cacheSize > 400) {
sendNotification(n);
try { Thread.sleep(2000) } catch (InterruptedException e){};
}}
Cu ajutorul unor astfel de algoritmi simpli,un singur obiect poate
monitoriza mai multe atribute simultan,sau poate utiliza mai multe seturi
succesive de filtrare a datelor.In majoritatea situatiilor,este mai comod
sa programati obiectelele necesare pentru monitorizare,decat sa utilizati
cele trei clase predefinite.
Pentru ca mecanismul sa fie complet,trebuie ca la receptia unei astfel
de notificari sa fie declansata o functie oarecare de raspuns la notifi-
care.Astfel,notificarea nu va fi emisa decat daca atributul urmarit inde-
plineste o anumita conditie,iar in momentul in care o astfel de notificare
a fost receptionata in aplicatia client,trebuie sa fie decalansata o ruti-
na automata prin care sa fie corectata situatia creata.De exemplu,se poate
declansa o functie prin care atributul este resetat automat la o valoare
acceptabila,se poate declansa un sistem de alarma,sau se poate pune in
actiune un set oarecare de operatii de raspuns la notificare.
Nu este necesar sa programati singuri toate rutinele necesare pentru
monitorizarea aplicatiilor java sau pentru supravegherea Virtual Machine.
Exista sute de astfel de aplicatii,oferite in sistem freeware sau share-
ware.Puteti alege oricare dintre acestea,in functie de necesitati sau in
functie de bugetul disponibil.De exemplu,in locul utilitarului jconsole,
se poate utiliza cu succes aplicatia denumita VisualVM 1.1.1.Aceasta este
realizata cu NetBeans si ofera o interfata grafica pentru monitorizarea
parametrilor Java VM,a sistemului de operare instalat,a memoriei de ope-
rare sau a thread-urilor active din sistem.Programul este oferit in regim
freeware si este ideal pentru verificarea aplicatiilor create cu NetBeans.
In general,este recomandabil sa utilizati un astfel de program,inainte
de a pune in circulatie programele realizate de d-voastra.Prima operatie
simpla,este controlul memoriei consumate.Lansati in executie aplicatia
creata de d-voastra,apoi executati toate operatiile posibile si urmariti
consumul de memorie/operatie.Este recomandabil ca memoria consumata,sa nu
depaseasca niciodata mai mult de 50 din cea accesibila.Restul de operatii
de control depind de complexitatea aplicatiei verificate.
-180-
JAVA NETWORKING (operatii in retea)

Unul dintre avantajele majore oferite de platforma Java,este generat de


posibilitatea de a crea programe si aplicatii ce interactioneaza direct
cu resursele din reteaua Internet,sau cu cele din World Wide Web.Fie ca
se preiau si se exploateaza diferite tipuri de date,preluate din site-uri
de web,fie ca se transporta sau se prelucreaza datele cu ajutorul unor
applet-uri,acest gen de aplicatii utilizeaza si exploateaza structura
hardware si software a retelei Internet.
Reteaua Internet este comuna pentru sute de milioane de utilizatori.
Orice aplicatie ce executa operatii in reteaua Internet trebuie creata si
verificata cu un grad crescut de responsabilitate,pentru a nu deranja
munca sau interesele celorlalti utilizatori din retea.Nu este necesar sa
cunoasteti toate amanuntele legate de operarea in retea,pentru a putea
crea un applet,sau o aplicatie simpla,dar este esential sa intelegeti
exact ceea ce faceti.Daca in cazul aplicatiilor de tip monopost puteti
sa utilizati fragmente de cod copiate sau preluate din alte programe,in
cazul aplicatiilor pentru retea este esential sa verificati cu atentie
fiecare linie de cod.Orice greseala,cat de mica,se poate transforma in
"virus informatic" si poate deranja un numar oarecare de utilizatori ce
partajeaza aceleasi resurse.Atentia trebuie sa fie maxima,in cazul pro-
gramelor si aplicatiilor ce editeaza date,sau suprascriu resursele deja
existente.Din acest motiv,este recomandabil ca exercitiile de programare
de acest tip sa se faca in retele izolate de tip intranet,ce mimeaza doar
mediul real de executie.
Nu toate browserele de web accepta script-urile si applet-urile Java,
sau exista o optiune prin care acestea pot fi inactivate.In principiu,Java
este un mediu de programare de tip "open source",in care totul este la
vedere.Ca rezultat,programele si aplicatiile sunt usor de verificat si
depanat.Exista insa si programatori si utilizatori rau intentionati,sau
cu diverse tulburari psihice,ce deranjeaza intentionat activitatea altor
persoane,prin programe si aplicatii ce contin coduri vicioase,sau date
defective,informatii false...etc.In principiu,aceste persoane sunt iden-
tificate si excluse "fizic" din reteaua Internet,dar,daca suspectati ca
in mediul d-voastra exista astfel de persoane,puteti alege sa inactivati
toata activitatea de tip Java din calcualtorul d-voastra.In acelasi timp
insa,daca programele realizate de d-voastra deranjeaza munca altor persoa-
ne,chiar daca erorile au fost "accidentale",se va considera ca au fost
produse cu rea credinta.Daca nu aveti certitudinea ca programele respecta
toate standardele de calitate,este bine sa consultati personalul speciali-
zat,inainte de a le pune in circulatie.
In reteaua Internet,fiecare unitate de lucru se identifica printr-un
cod oarecare si fiecare aplicatie se identifica printr-o adresa.Din acest
motiv,una dintre clasele esentiale pentru operatii in retea este clasa URL
(Uniform Resource Locator),cea utilizata pentru identificarea resurselor
din retea.Pentru a putea realiza conexiunea dintre doua calculatoare se
utilizeaza o serie de programe software,denumite protocoale de comunicatie
si tranfer.Exista numeroase astfel ce protocoale,dar cele mai frecvent
utilizate sunt TCP (Transmission Control Protocol) si UDP (User Datagram
Protocol).Ambele protocoale sunt la fel de performante,dar exista o serie
de mici deosebiri de ordin tehnic.

-181-
Protocolul de tip TCP realizeaza o conexiune de tip telefonic,in care
ambele unitati trebuie sa fie prezente si active,pentru a putea realiza o
conexiune.Acest protocol este rapid,sigur si eficient,dar nu poate trans-
mite date spre o unitate inactiva.
Protocolul UDP,este asemanator cu sistemul postal.Transmite datele
spre o adresa oarecare,unde acestea vor fi plasate pe o linie de asteptare
pana cand se poate realiza conexiunea neceasara.In acest caz,nu se garan-
teaza ordinea si rapiditatea transferului,dar pachetul de date poate fi
transmis chiar daca unitatea de destinatie este inactiva.
Clasele din pachetul java.net sunt independente de protocolul de comu-
nicatie,asa ca nu este necesar sa analizati prea amanuntit acest aspect.
Fiecare calculator conectat la retea are o singura conexiune fizica,dar
poate comunica simultan cu doua sau mai multe calculatoare din retea.
Pentru a putea realiza acest tip de comunicatie multipla,intre conexiunea
fizica si unitatea de lucru se interpun un numar oarecare de tampoane de
memorie,denumite "porturi de comunicatie".Fiecare astfel de port,poate
sa organizeze comunicatia dintre o anumita aplicatie si o anumita resursa
din retea.Astfel,fiecare calcualtor sa va identifica printr-o adresa de
tip IP (de 32 de biti) si un numar de porturi (codificate cu 16 biti).
Daca mai multe porturi sunt activate simultan,datele primite sau emise
vor fi transmise succesiv (serial).Practic,portul este utilizat pentru a
mentine datele pe "linie de asteptare",pana cand se poate efectua trans-
ferul.Exista 65535 de astfel de porturi programabile,dintre care primele
1024 (de la 0 la 1023) sunt rezervate pentru serviciile HTTP si FTP.
Din reteaua Internet,cea mai frecvent accesata de marele public este
reteaua Web ce utilizeaza protocolul de transfer denumit HTTP (Hipertext
Transfer Protocol).In aceasta retea,se exploateaza predominent file edi-
tate in format hipertext de tip HTML si XML.Fiecare protocol de comunica-
tie utilizeaza un anumit sablon pentru adresa resurselor din retea.
Adresa resursei poarta numele de URL (Uniform Resource Locator) iar
clasa java utilizata pentru identificarea unei astfel de adrese poarta
acelasi nume.O astfel de adresa se formeaza din doua parti:
1. identificatorul pentru protocol
2. numele resursei
EXEMPLU: http://java.sun.com unde:
http -este identificatorul tipului de protocol
//java.sun.com -este numele resursei
La randul sau,numele resursei se poate forma din:
1.Host Name - numele unitatii de lucru ce arhiveaza resursa
2.Filename - calea software spre fila ce contine resursa
3.Port Number - numarul portului utilizat pentru conexiune
4.Reference - un pointer spre adresa resursei in cadrul filei
In majoritatea protocoalelor sunt necesare doar primele doua (unitatea
si calea software spre resursa) in timp ce ultimele doua sunt optionale
(portul si pointerul spre memorie).
Pentru a crea o astfel de adresa URL,se va apela constructorul clasei
URL in care adresa propriu zisa se reprezinta sub forma de String.
EXEMPLU: pentru adresa http://www.gamelan.com
se va utiliza o linie de cod de genul:
URL gamelan = new URL("http://www.gamelan.com/");
(Site-ul gamelan.com contine informatii utile pentru programatorii Java.)

-182-
Clasa URL detine 6 constructori diferiti,ce permit diferite solutii de
formare a unei adrese de tip URL.Standardul de sintaxa pentru adresele URL,
este continut in documentele: RFC 2396 si respectiv 2732.
EXEMPLU: pentru a include in adresa si portul de comunicatie,se poate
utiliza un constructor de tipul:
URL(String protocol,String host,int port,String file);
EXEMPLU: URL url = new URL("http","gamelan.com",80,"game.html");
Este posibil chiar ca adresa sa fie creata prin referire la o adresa
relativa creata anterior:
EXEMPLU: adresa http://www.gamelan.com/pages/Gamelan.game.html
se poate crea si astfel:
URL gamelan = new URL("http://www.gamelan.com/pages/");
URL gamelanGames = new URL(gamelan,"Gamelan.game.html");
In acest caz,s-a apelat constructorul de tip:
URL(String context,String spec);
Exista si situatii in care adresa URL contine caractere speciale.In
acest caz,este necesar ca aceste caractere sa fie recodificate conform cu
standardul din RFC 2396.Pentru a simplifica acest proces,este recomandabil
sa utilizati clasa URI (Uniform Resource Identifier),special creata pentru
acest scop.
EXEMPLU: adresa: http://foo.com/hello world/
contine un spatiu gol ce trebuie recodificat (adaugand %20).Adresa se
va putea crea astfel:
URL url = new URL("http://foo.com/hello%20world");
sau se va putea apela clasa URI astfel:
URI uri = new URI("http","foo.com","/hello world/","");
URL url = uri.toURL();
Clasa URI are la randul sau 5 constructori diferiti si metode speciali-
zate pentru a putea compune sau decompune si analiza orice adresa.
Toti constructorii elibereaza o exeptie de tip MalformedURLException in
cazul in care a intervenit o eroare de sintaxa.Aceasta exceptie va putea
fi exploatata pentru functiile de depanare automata.
Analiza unei adrese URL se poate face cu ajutorul metodelor speciali-
zate: getProtocol,getAuthority,getHost,getPort,getPath,getQuery,getFile,
getRef...etc.
Exista o serie intreaga de obiecte Java ale caror metode solicita o
adresa de tip URL,chiar si in cazul in care resursele apelate sunt arhi-
vate local.In paginile anterioare au fost deja prezentate cateva exemple
de acest fel.
Dupa crearea unei adrese URL,aceasta poate fi utilizata pentru ope-
ratii de tip I/O.Clasic se va utiliza un stream specializat in care se
vor citi datele cu un BufferedReader (un tampon de memorie dedicat).
Dupa deschiderea streamului,datele pot fi preluate in tamponul de memorie,
fie integrale,fie filtrate cu ajutorul unor obiecte speciale sau al unor
algoritmi special realizati.Cu un astfel de mecanism elementar se poate
crea un browser simplu de Internet,sau se pot crea utilitare simple ce
extrag doar un anumit tip de data,dintr-o pagina de tip HTML.
Datele preluate pot fi prelucrate direct in aplicatii,sau pot fi uti-
lizate pentru a crea alte file de tip HTML,sau pentru a declansa o serie
de rutine de comanda automata...etc.Cel mai simplu exemplu,extrage pur si
simplu toate datele dintr-o pagina de web.

-183-
EXEMPLU:
import java.net.*;
import java.io.*;

public class URLReader {


public static void main(String[] args) throws Exception {
URL yahoo = new URL("http://www.yahooo.com/");
Bufferedreader in = new BufferedReader(new InputStreamReader(
yahoo.openStream()));
String inputLine;
while((inputLine = in.readLine()) != null)
System.out.println(inputLine);
in.close();
}
}
Salvati fila cu numele URLReader.java si compilati exemplul.
La executie,daca exista o conexiune functionala la Internet,se va
emula intregul continut al filei HTML de la adresa yahoo.com.Pentru ca
acest exercitiu sa fie transformat intr-un browser complet,este necesar
ca datele sa fie salvate intr-o fila de tip HTML ce va fi apoi deschisa
local.Pentru a filtra datele se pot include diverse seturi de conditii,
iar pentru a anliza datele se pot crea algoritmi speciali.
In exemplul de mai sus,datele preluate din resursa apelata nu repre-
zinta decat o singura instanta a filei respective.In cazul in care fila
respectiva este actualizata permanent,poate fi util sa preluati datele
periodic,pentru a obtine aceste valori actualizate.In acest caz,se poate
deschide o conexiune permanenta cu resursa respectiva,cu ajutorul careia
se poate face un schimb activ de date,permanent.
Pentru a putea scrie sau actualiza datele din resursa apelata,trebuie
sa fiti autorizati in scris de catre proprietarul de drept al resursei
respective.
EXEMPLU: nu incercati sa scrieti date in fila yahoo.com,decat daca
sunteti pregatiti pentru a plati o amenda considerabila.
Pentru a exersa aceste operatii,este recomandabil sa deschideti un
site propriu,special destinat pentru exercitii de acest gen,sau sa utili-
zati unul dintre site-urile oferite special pentru instructie.
O confuzie foarte frecventa se face intre cele doua clase URL si URI.
URI este identificatorul unic al unei resurse,in timp ce URL este obiectul
ce asigura localizarea acestei resurse.Astfel,orice URL contine si un
obiect de tip URI,dar nu orice URI este un URL.Adica un obiect de tip URL
contine si un set de informatii suplimentare,necesare pentru a putea
localiza adresa ce se identifica prin URI.Pentru a transforma adresa URI
intr-un obiect de tip URL se poate apela la metoda toURL(),sau pentru a
transforma adresa URI intr-un sir de caractere ASCII,se poate apela metoda
toASCIIString().
Exista si un set de clase auxiliare ce completeaza operatiile ce se
pot executa asupra unei adrese de internet:
URISyntaxException,URLClassLoader,URLConnection,URLDecoder,URLEncoder,
URLStreamHandler,URLStreamHandlerFactory,JarURLConnection et.
Pentru o imagine de ansamblu,este bine sa studiati documentatia tehnica
si pentru aceste clase suplimentare.

-184-
Pentru a realiza o conexiune permanenta intre doua calculatoare din
retea se utilizeaza obiecte specializate.Cea mai simpla conexiune se poate
realiza cu ajutorul unui obiuect de tip URLConnection:
EXEMPLU:
try {
URL yahoo = new URL("http://yahoo.com/");
URLConnection yahooConnection = yahoo.openConnection();
yahooConnection.connect();
} catch (MalformedURLException e) {}
catch (IOException e) {}
In cazul protoculului TCP/IP,obiectele pentru conexiune poarta numele
de socket-uri.In cazul unitatilor de tip server,obiectele utilizate pentru
conexiune poarta numele de ServerSocket.
Clasa Socket are 9 constructori diferiti.In principiu,obiectul Socket
face conexiunea software dintre cele doua calculatoare (fata de conexiunea
fizica realizata prin cabluri sau dispozitive wireless).La apelarea unuia
dintre constructori se va preciza explicit adresa unitatii in retea,sau
adresa resursei cautate si portul de comunicatie dorit,iar pentru Server-
Socket poate fi suficient doar numarul portului de comunicatie:
EXEMPLU:
try{
Socket socket1 = new Socket("Unitatea1",2221);
Socket socket2 = new Socket(127.0.0.1,2222);
ServerSocket socket3 = new ServerSocket(4444);
} catch (UnknownHostException e1) { ...}
catch (SecurityException e2) { ...}
catch (IOException e3) { ... }
In cazul in care se lucreaza cu un numar foarte mare de conexiuni ce
trebuiesc formate si inchise automat,in mod dinamic,se pot utiliza clasele
SocketFactory si ServerSocketFactory din pachetul javax.net.
In mod normal,nu trebuie sa va complicati viata cu aceste obiecte.Orice
browser de Internet va crea si/sau inchide automat socket-urile sau
obiectele necesare pentru realizarea conexiunii.Are rost sa utilizati
aceste obiecte,doar atunci cand doriti sa creati aplicatii independente,ce
se pot conecta la retea fara intermediul unui browser,sau atunci cand
doriti sa programati un browser nou.Platforma Java nu include obiecte
vizuale de tip Socket,dar puteti consulta oferta de pe Internet,pentru
astfel de pachete auxiliare.
In cazul protocolului UDP,obiectele pentru conexiune sunt:DatagramSocket
DatagramPacket si MulticastSocket.Si aceste obiecte au un numar destul de
mare de constructori,pentru a permite formule destul de personalizate de
conectare la retea.Detaliile referitoare la modul de conectare si la ope-
ratiile I/O din retea,nu fac obiectul acestui manual,deoarece autorul nu
poate sa-si asume raspunderea pentru eventualele solutii oferite.Politica
locala pentru operatiile din retea,poata sa fie diferita de la o retea la
alta,sau chiar de la o luna la alta.Pentru detalii suplimentare este bine
sa va consultati si cu administratorul de retea.
In principiu,protocolul TCP/IP este de preferat in cazul unui schimb
activ de date,intre doua unitati (date transmise + date receptionate) in
timp ce protocolul UDP este de preferat atunci cand doriti doar sa trimi-
teti date,catre mai multi receptori(fara sa asteptati un raspuns imediat).

-185-
SECURITATEA APLICATIILOR JAVA

Java este un mediu de operare de tip "open source".Totul este la vedere:


file sursa,clase,pachete si resurse...etc.Pachetele pot fi despachetate,
filele compilate pot fi decompilate iar programele de management al memo-
riei ofera o imagine de ansamblu al tuturor proceselor aflate in executie,
sau al mecanismului intern de gestionare a memoriei.Ca rezultat,programele
java sunt foarte usor de verificat si depanat de catre orice programator
avizat.In mod normal,programele si aplicatiile Java nu necesita nici un
fel de masuri speciale pentru securizarea datelor.Sunt suficiente cele
asigurate de catre sistemul de operare.Totusi,exista si situatii in care
programatorii,sau utilizatorii doresc sa-si protejeze datele prin parole,
criptarea sau conversia datelor,semnaturi digitale,cetrificate de autenti-
ficare sau garantie...etc.In plus,exista o serie de masuri standardizate,
menite sa protejeze reteaua Internet de eventualele atacuri malvolente
(exemplu restrictiile impuse pentru applet-uri).
Personal,am fobie fata de parole,certificate si polite de asigurare...
Din acest motiv,acest capitol nu va include decat notiunile strict utile
la nivel de incepator.Cititorii,vor putea aprofunda acest capitol din sur-
se mai avizate.In plus,exista un numar foarte mare de aplicatii si instru-
mente software ce asigura si granateaza aceste servicii.Mai mult decat
atat,exista firme si institute specializate in securizarea datelor.Daca
detineti date cu caracter secret,este recomandabil sa apelati la o astfel
de firma,in loc sa incercati sa va "protejati" singuri.
Masurile de securitate Java,intereseaza: applet-urile,aplicatiile si
programele,parolele si certificatele de acces,semnaturile digitale,codu-
rile si conversiile pentru criptarea si decriptarea datelor,compresia si
decompresia,respectiv impachetarea si despachetarea datelor,restriciile
pentru unele dintre operatiile I/O (mai ales read/write)...etc.
Masurile de securitate pot fi structurate pe mai multe nivele,dupa
gradul de interes si responsabilitate:
-utilizatori casnici
-utilizatori avizati (firme si societati comerciale)
-unitati economice
-programatori si manageri de sistem
-administratori de retea
-etc.
Singurele masuri de securitate ce intereseaza toate aceste categorii,
sunt cele referitoare la applet-uri.In mod normal,applet-urile nu pot
executa o serie intreaga de operatii in calculatorul gazda:
EXEMPLE: -nu pot edita filele locale
-nu pot citi informatii legate de sistemul de operare
-nu pot actualiza fisiere locale
-nu pot prelua si transmite date in retea
Exista insa situatii in care doriti totusi sa utilizati o parte dintre
aceste operatii,strict in calculatorul d-voastra,pe proprie raspundere.In
acest caz,puteti crea o fila speciala de certificare,denumita "policy",
prin care garantati dreptul aplicatiei applet de a executa o anumita ope-
ratie.Aceasta certificare nu va avea efect decat in calculatorul ce inclu-
de o astfel de fila.In plus,applet-ul nu va putea fi lansat cu un browser,
ci doar cu utilitarul appletviewer (sau un shortcut).

-186-
EXEMPLU:
import java.awt.*;
import java.io.*;
import java.lang.*;
import java.applet.*;

public class WriteFile extends Applet {


String myFile = "writetest";
File f = new File(myFile);
DataOutputStream dos;
public void init() {
String osname = System.getProperty("os.name");
}
public void paint(Graphics g){
try {
dos = new DataOutputStream(new BufferedOutputStream(
new FileOutputStream(myFile),128));
dos.writeChars("Textul inclus in fila locala ! \n");
dos.flush();
g.drawString("Fila writetest a fost editata ! ",10,10);
} catch (SecurityException e) {
g.drawString("Exceptie de securitate = " + e,10,10); }
catch (IOException ioe) {
g.drawString("Exceptie IO ",10,10); }
}
}
-salvati fila cu numele WriteFile.java si apoi compilati fila.
Pentru a include applet-ul,editati o fila HTML de genul:
<html>
<title> Applet </title>
<h1> APPLET </h1>
<body>
<applet code = "WriteFile.class" width = 800 height = 20 >
</applet>
</body>
</html>
-salvati fila cu numele Security1.html
Daca lansati in executie fila Security1 se va afisa un mesaj de eroare,
declansat de exceptia de tip SecurityException.Pentru a putea evita acest
mesaj,trebuie sa completati un certificat prin care sa garantati accesul
la fila dorita.Pentru acest scop,puteti sa utilizati o fila de tip text,
dar este recomandabil sa utilizati utilitarul local,denumit "policytool".
Pentru acest scop,deschideti Command Prompt in directorul in care sunt
arhivate utilitarele java (bin) si editati comanda: policytool
Se va deschide fereastra Policy Tool.Alegeti optiunea: Add Policy Entry.
Se va deschide fereastra Policy Entry.Apasati butonul AddPermision.In
fereastra Permissions,alegeti pentru Permission optiunea FilePermission.
Apoi,completati in caseta Target Name numele filei : writetest iar in
caseta Actions alegeti optiunea : write.Confirmati cu OK.Apasati din nou
butonul Add Permission si alegeti : Permission = SecurityPermission si
Target Name = writetest.Confirmati cu OK.

-187-
Pentru verificare,fereastra Policy Entry trebuie sa contina urmatorul
text: java.io.FilePermission writetest,"write"
java.security.SecurityPermission writetest
Confirmati cu butonul Done.Pentru a salva fila,alegeti in fereastra
Policy Tool meniul File,apoi Save As si navigati in browser.In mod normal
filele de tip policy se vor arhiva in directorul jre/lib/security
EXEMPLU:
C:\Program Files\Java\jre1.6.0_03\lib\security\AppletSecurity1Policy
Pentru ca applet-ul sa poata fi lansat,este necesar ca la prima lansare
sa specificati si numele filei de tip policy ce garanteaza operatiile.
Pentru acest scop,editati in Command Prompt o comanda de genul:
appletviewer -J-Djava.security.policy=AppletSecurity1Policy Security1.html
Acum applet-ul este executat.Puteti verifica fila locala writetest.
In continuare,fila HTML va putea fi executata cu o comanda simpla:
appletviewer Security1.html
Macanismul pare destul de complicat,dar permite utilizarea unui applet,
pentru a putea actualiza de exemplu,o fila locala,cu date preluate dintr-o
fila Web arhivata in reteaua Internet.
Daca descarcati din reteaua Internet aplicatii Java,puteti sa intalniti
programe sau aplicatii ce utilizeaza astfel de applet-uri si este bine sa
stiti cum sa editati certificatul pentru garantarea accesului.O astfel de
aplicatie,prezinta urmatorul avantaj: puteti utiliza applet-ul in mediul
din retea,fara ca alt utilizator din retea sa poata copia sau utiliza
fila HTML ce contine applet-ul.Cu alte cuvinte,un alt utilizator din
retea nu va putea avea acces la filele locale din calculatorul d-voastra.
In exemplul de mai sus,am omis o serie intreaga de etape.Astfel,in
fereastra Policy Entry puteti utiliza caseta CodeBase pentru a garanta
doar applet-urile ce provin de la o anumita adresa din retea,sau puteti
utiliza caseta SignedBy,pentru a garanta doar applet-urile ce poarta
semnatura digitala a autorului respectiv.Daca lasati ambele casete necom-
pletate,polita va avea efect,indiferent de locatia applet-ului si fara sa
se mai verifice semnatura digitala.
Daca doriti,puteti deschide fila policy cu un editor de text,pentru
a verifica ce contine.Eventual,puteti chiar sa editati astfel de file
manual.
Masurile de securitate pentru applet-uri sunt utile si bine gandite.
Nu are rost sa evitati aceste masuri,decat in situatii exceptionale,si
doar pentru aplicatii destinate uzului personal.Garantarea accesului la
operatii de tip read/write reprezinta un hazard pe care vi-l asumati pe
risc propriu.Un utilizator banal nu va putea abuza de applet-ul d-voastra,
dar un "hacker" experimentat va putea obtine o cale de acces spre sistemul
d-voastra de operare.In plus,in cazul in care doriti sa oferiti aplicatia
d-voastra si pentru alti utilizatori,determinati expunerea lor al aceeasi
tip de hazard.
Toate operatiile executate cu ajutorul applet-urilor pot fi programate
si cu obiecte de tip API.Nu exista situatii care sa impuna utilizarea
de applet-uri.Applet-urile sunt extrem de apreciate pentru portabilitatea
lor (pot fi preluate facil in orice site de web),dar tocmai aceasta cali-
tate,reprezinta un impediment in cazul operatiilor ce prezinta un risc
oarecare pentru securitatea sistemului.Opinia autorului este sa nu apelati
la acest gen de solutii,decat in situatii evaluate foarte atent.

-188-
Aceleasi reguli se pot extrapola si in cazul aplicatiilor simple.In
mod normal (implicit),aplicatiile simple nu sunt supuse la nici un fel de
restrictii de executie.Pentru a introduce un set oarecare de astfel de
restrictii,trebuie ca aplicatia sa fie executata intr-un anumit context
de memorie,impreuna cu o fila denumita "security manager",prin care sa
fie explicitate restrictiile dorite.Fila de tip security manager,va deter-
mina citirea unei file de tip "policy",in care sunt specificate drepturile
garantate pentru aplicatia respectiva.De exemplu,pentru a utiliza in cazul
unei aplicatii simple aceleasi restrictii ca si in cazul applet-urilor,se
poate utiliza managerul de securitate implicit si fila policy implicita
din pachetul: jre1.6.0_03\lib\security (java.security si java.policy)
EXEMPLU: Lansati aplicatia cu o comanda de genul:
java -Djava.security.manager NumeleAplicatiei
in continuare se procedeaza exact la fel ca in cazul applet-urilor.Se
editeaza cate o fila de tip policy,in care se garanteaza drepturile de
acces.Fiecare client,va putea avea o astfel de fila policy personalizata,
astfel incat sa utilizeze din aplicatie doar atat cat este strict necesar.
Cu acest gen de solutie,se poate personaliza dreptul de acces la o anumita
fila,la o anumita proprietate a sistemului de operare sau la o anumita
resursa din retea.
O alta modalitate de abordare,o reprezinta semnaturile digitale.Exista
situatii in care doriti ca un anumit client sa poata verifica identitatea
unei anumite surse de informatii,inainte de a avea acces la date.Daca
datele provin de la o anumita sursa,clientul va putea citi datele,iar in
caz contrar se va aplica o anumita masura de securitate.Acest gen de so-
lutie se poate crea si cu ajutorul unor parole simple,dar este mult mai
eficient daca se utilizeaza obiecte complexe.O parola de tip string,poate
fi decodificata de un program performant in cateva secunde,in timp ce un
obiect complex este practic imposibil de decodificat.Pentru situatiile
obisnuite,obiectul contine tot o parola de tip String,dar asociaza la
acest sir de caractere si un cod unic,ce identifica o anumita masina din
retea,sau o anumita instanta a programului ce a creat obiectul.In acest
mod,doua obiecte similare,create pe calculatoare diferite,sau cu instante
diferite ale aceluiasi program,vor fi diferite.
Semnatura digitala,este de fapt un obiect de sine statator.Pentru a
autentifica originea unui anumit pachet de date,este necesar ca in acest
pachet sa existe si obiectul utilizat ca semnatura.Acest obiect poate fi
creat de d-voastra,sau puteti utiliza unul dintre obiectele standardizate
oferite de pachetul java.security,sau respectiv javax.security.
EXEMPLU:
import javax.security.auth.AuthPermission;

class Sursa1 {
public static AuthPermission Semnatura = new AuthPermission("Parola");
public static String Date = new String("Datele din sursa1...");
}
-salvati fila cu numele Sursa1.java si apoi compilati fila.
In acest exemplu,semnatura digitala este reprezentata de obiectul de
tip AuthPermission,iar datele propriu zise sunt incluse in string-ul Date.
Fila Sursa1.class poate fi expediata unui client oarecare,ce va putea
verifica semnatura,cu o aplicatie de genul:
-189-
import javax.security.auth.AuthPermission;

class VerificaSemnatura {
public static void main(String[] args) {
AuthPermission Semnatura2 = new AuthPermission("Parola");
if(new Sursa1().Semnatura.getName() == Semnatura2.getName())
{
System.out.println("Se citeste sursa...");
System.out.println(new Sursa1().Date);
}
else
{ System.out.println("Semnatura este incorecta !"); }
System.out.println(" ...s-au citit datele solicitate !");
}}
-salvati fila cu numele VerificaSemnatura.java si compilati fila.
Pentru a citi datele din Sursa1.class,executati fila VerificaSemnatura.
La prima vedere,obiectul Semnatura este identic cu un String obisnuit.
Insa,daca incercati sa utilizati un string simplu,fila nu va fi recunos-
cuta ca valabila.Mai mult decat atat.Presupunand ca stiti parola si in-
cercati sa creati un obiect ce contine semnatura digitala pe un alt cal-
culator decat cel sursa,semnatura nu va fi validata.
Pentru a intelege acest mecanism,deschideti fila sursa pentru obiectul
AuthPermission (din pachetul src/javax/security/auth).Observati ca in
constructorul clasei se include si un cod denumit serialVersionUID.Acest
cod identifica originea semnaturii digitale.Exista cate un astfel de cod,
pentru fiecare obiect standard din java.security,astfel ca semnaturile
digitale sunt foarte greu de falsificat.
Mecanismele standard pentru java.security sunt mult mai complexe decat
atat.In mod curent se utilizeaza seturi intregi de obiecte ce interactio-
neaza dupa un algoritm oarecare.In locul unei simple semnaturi,se creaza
cate un obiect complex,de tip Subject,pentru fiecare client.In acest
obiect de tip Subject,se includ toate datele de identificare ale fiecarui
client,precum si restrictiile sau drepturile garantate.
Mai mult decat atat,in obiectul Subject clientul poate sa figureze cu
mai multe nume,sau denumiri generice de tip alias.Pentru fiecare astfel
de nume,va avea o interfata de tip Principal.Astfel,un singur client poate
avea mai multe seturi de depturi de acces,in functie de numele utilizat
pentru conectare (logg-are).Drepturile de acces,se vor putea reglementa
fie prin file de tip policy,fie prin algoritmi special conceputi.
Acest gen de solutii software,fac obiectul firmelor specializate in
securizarea datelor.Atunci cand aveti nevoie de o astfel de solutie,este
preferabil sa apelati la o astfel de firma.Nu trebuie uitat ca in ultima
instanta,comutatia se executa fizic,intr-o centrala din retea.
Nu puteti implementa nici un fel de masura de securitate,care sa elimine
complet responsabilitatea administratorului de retea.Obiectele din cele
doua pachete "security",nu fac decat sa simplifice operatiile de comutatie
automata (sau manuala).Nici una dintre masurile de securitate software nu
poate avea eficienta,decat daca este implementata si prin hardware.
In concluzie,pentru situatiile simple este recomandabil sa utilizati
solutii cat mai simple,iar pentru situatiile complexe este mai bine sa
apelati la (sau sa colaborati cu ) firme specializate.
-190-
FINALIZAREA APLICATIILOR

Notiunile prezentate pana in prezent,sunt suficiente pentru a putea


crea o aplicatie simpla.Acest manual introductiv nu epuizeaza resursele
platformei Java.In exemplele de pana acum,au fost utilizate doar o parte
dintre obiectele incluse in pachetele java si javax.Platforma cuprinde
insa si alte pachete,cum sunt: com,org,launcher si sunw.Aceste pachete
contin clase si interfete destinate pentru operatii mai complexe,sau
pentru interactiunea cu alte limbaje de programare (Exemplu: w3c si xml).
Pentru a va completa cunostiintele de programare in Java,este necesar sa
studiati si alte carti,tutoriale sau manuale,in functie de domeniul de
interes.
Finalizarea unei aplicatii nu este insa chiar atat de usoara cum pare
la prima vedere.Din momentul in care programul lucreaza corect,mai sunt
inca o serie intreaga de etape,pana la finalizarea proiectului.In linii
mari,acestea pot fi structurate astfel: 1.Organizarea datelor 2.Depanare
3.Optimizare 4.Actualizare sau modernizare 5.Verificare si control de
calitate 6.Analiza 7.Legalizare 8.Impachetare si distributie.Fiecare
dintre aceste etape,este diferita in functie de nivelul profesional al
echipei de lucru,dar in linii mari cuprind urmatoarele operatii:
1.Organizarea datelor
Dupa ce programul functioneaza la nivel de cod,urmeaza etapele prin
care se obtine structura optima a programului.Se aleg obiectele cele mai
eficiente pentru operatia propusa.In cazul in care programul este destinat
pentru alti utilizatori decat d-voastra,este recomandabil sa proiectati o
interfata grafica.In principiu,grupurile de operatii se vor structura in
module separate,controlate de thread-uri separate.Fiecare astfel de modul,
va putea fi conectat la interfata grafica cu ajutorul unui obiect vizual.
In general,utilizatorii doresc sa obtina cat mai mult,cu un singur click
de mouse.Din acest motiv,se prefera butoanele si meniurile,ori de cate
ori este posibil.Operatiile trebuie sa fie simple si clare,sau sa fie
insotite de explicatii cat mai detailate.Nu scontati ca utilizatorul va
sti ce trebuie facut.Daca este cazul,adaugati si un sistem de mesaje
automate,ce conduc utilizatorul pas cu pas (un fel de wizard) pana la
indeplinirea scopului propus.Este bine ca programul sa-si gestioneze
singur atat resursele,cat si memoria consumata.Filele de resurse este
bine sa fie grupate in directoare specializate,pentru a fi cat mai usor
de depanat sau actualizat.In toate cazurile este recomandabil sa utilizati
resurse locale in locul celor din retea.Daca este absolut necesar sa uti-
lizati si date sau resurse preluate din retea,este bine sa proiectati un
modul separat ce identifica resursa si copiaza datele la o adresa locala.
Acest modul va fi lansat inaintea aplicatiei,urmand ca aplicatia propriu
zisa sa utilizeze doar resursa locala.In acest mod,evitati toate erorile
generate de conexiune,calea de acces,versiunea resursei...etc.Tot in etapa
de organizare,trebuie sa va hotarati si asupra mijloacelor de securizare
a datelor,sau a eventualelor metode de protejare a "dreptului de autor".
In principiu,Java este un sistem "open source",dar asta nu inseamna ca nu
poate fi utilizat si in scop comercial.Daca alegeti solutia comerciala,
trebuie sa va organizati juridic,sa inregistrati aplicatia si sa obtineti
"timbrul legal"...etc.In acest caz,adaugati la resurse si fila in care
specificati drepturile si responsabilitatile ambelor parti.

-191-
Daca alegeti varianta "open source",este recomandabil sa adaugati si
filele sursa (.java) si indicatii minimale pentru depanare si control.
In mod normal,codul vorbeste de la sine si este suficient sa adaugati o
fila in care precizati ca programul este distribuit in regim "freeware".
Chiar daca programul este "open source",nu inseamna ca sunteti degrevati
de orice responsabilitate (chiar daca adaugati o fila prin care declarati
ca nu va asumati nici o raspundere).Daca aveti cele mai mici dubii refe-
ritor la calitatea programului,este mai bina sa nu-l puneti in circulatie.
2.Depanare
Primele operatii de depanare sunt efectuate de catre compilator.La
acestea se poate adauga si utilitarul specializat (debugg-er).Daca apli-
catia este functionala si compilatorul nu identifica nici o eroare,nu
inseamna insa ca programul este perfect.Pot exista o serie intreaga de
situatii limita,ce vor genera erori de executie,sau chiar vor bloca exe-
cutia programului,dar numai in momentul in care se indeplinesc anumite
conditii.Cele mai frecvente situatii de acest gen sunt:
-se depaseste capacitatea unui tampon de memorie
-se apeleaza un tip de data incompatibil
-se depaseste domeniul de valori al unei anumite variabile
-se introduc date eronate,incomplete,defective,nule...etc
-se apeleaza actioneaza concurential asupra unei resurse determinand modi-
ficarea datelor sau a tipului de data prezentat
-se pierde sau se modifica pointerul spre o resursa
-se pierde sau se degradeaza conexiunea (link-ul) cu una dintre resurse
-se declanseaza o bucla de control infinita (fara conditie de stop)
-se depaseste capacitatea de lucru a procesorului,sau a sistemului de
operare
-se declanseaza seturi de operatii ce se anuleaza reciproc
-se cauta la infinit o resursa apelata grasit (sau relocata)
-se comuta executia intr-un spatiu de vizibilitate gresit
-se supraincarca memoria de operare
Toate aceste situatii nu pot fi identificate de compilator si nu se vor
exprima decat in conditii extreme.Pentru a elimina orice situatie de acest
gen,este bine sa testati programul utilizand valorile maximale.Pentru
situatiile ce se pot preta la confuzii,este recomandabil sa utilizati
bucle conditionale.Exemplu: programul asteapta date de tip numeric,dar
utilizatorul introduce din greseala date de tip text.In mod normal in
acest caz,se va declansa o eroare de tip si programul se va intrerupe.Cu
o bucla conditionala,introducerea textului va declansa doar un mesaj de
avertizare catre client.
Daca este vorba despre un program important,este bine sa-l oferiti
pentru testare spre cat mai multi utilizatori neavizati,sau chiar sa
apelati la o firma specializata in testarea si depanarea aplicatiilor.
3.Optimizare
Dupa primele doua etape,programul este functional si corect.Nu inseamna
insa ca este finalizat.In etapa urmatoare,se pot face o serie intreaga de
modificari,astfel incat executia sa fie mai rapida,memoria consumata sa
fie mai redusa si sa fie eliberata mai frecvent,expresiile sa fie mai
clare si mai precise,codurile sa fie mai condensate,modulele sa fie mai
performante...etc.Optimizarile pot interesa module intregi,sau se pot
aplica doar la nivel de linie de cod,sau expresie.

-192-
Primele modificari se pot face la nivel de expresie si implica utili-
zarea unor cuvinte cheie,denumite modificatori.Cu ajutorul acestora se
va putea determina modul in care obiectul generat se va comporta in unele
situatii mai speciale: datele sunt apelate dintr-o clasa externa,executia
se face concurential,in sistem multi-threading,se lucreaza cu serii de
obiecte...etc.
In general,modificatorii sunt cuvinte cheie prin care compilatorul
primeste informatii suplimentare despre coduri,sau obiecte si clase.
O parte dintre modificatori reglementeaza accesul la date: public,private
si protected,in timp ce alti modificatori descriu un anumit atribut sau
o anumita caracteristica: final,abstract,static,native,transient,volatile,
synchronized.
Modificatorii de acces (public,private si protected) reglementeaza
vizibilitatea datelor fata de restul spatiilor de memorie.Au aceeasi sem-
nificatie ca si in celelalte limbaje de programare:
-public : clasele,variabilele si metodele de acest fel pot fi utilizate
de catre orice program Java,fara restrictii.Metodele main() se declara
public,pentru a putea fi apelate din orice mediu Java.
-private : clasele principale nu pot fi declarate private.Variabilele si
metodele declarate private nu pot fi apelate decat din clasa respectiva.
-protected : nu se poate utiliza pentru clase.Metodele si variabilele de-
clarate protected sunt vizibile pentru toate clasele din acelasi pachet.
Mai mult decat atat,sun vizibile si pentru sub-clasele derivate din acea
clasa,chiar daca sunt declarate in alte pachete.In acest caz insa,datele
de tip protected nu pot fi utilizate decat in urmatoarele situatii:
-clasa descendenta poate redefini metoda de tip protected
-clasa descendenta poate scrie si citi datele protected din instanta
respectiva,dar nu poate scrie sau citi datele protected dintr-o alta
instanta a clasei respective
-clasa descendenta poate apela datele protected mostenite,in cadrul
clasei,dar nu poate apela datele protected din alta instanta a clasei
Acest mecanism,genereaza foarte frecvent nelamuriri,sau erori de exe-
cutie.Este bine sa nu apelati datele protected,decat din interiorul
clasei,la fel ca pe cele private.
Modificatorii de atribut au urmatoarea seminificatie:
-final : insemana ca datele respective nu mai pot fi schimbate.Se poate
utiliza atat pentru clase,cat si pentru metode si variabile.Datele
rezultate vor fi de tip constanta.De exemplu,o clasa declarata final,
nu mai poate fi extinsa sau redefinita,sau o variabila declarat final
nu mai poate schimba valoarea alocata.
-abstract : se utilizeaza pentru clase si metode la care nu se specifica
si definitia.Clasele abstracte nu pot crea instante (obiecte),decat
dupa ce au fost extinse cu definitiile necesare.Daca o clasa contine o
singura metoda abstracta,compilatorul va solicita sa fie declarata tot
abstracta.Clasele abstracte sunt destinate exclusiv ca sablon.
-static : se aplica pentru metode si variabile,atunci cand doriti sa
precizati ca apartin unei anumite clase,indiferent de instanta din care
vor fi apleate.Pentru o anumita clasa,exista o singura variabila sau
metoda de tip static,indifernt cate obiecte se vor deriva din clasa
respectiva.Atunci cand se apeleaza din instante diferite,datele se vor
suprascrie in aceeasi variabila.

-193-
EXEMPLU: class Clasa1 { static int = 0;
Clasa1(){x++;};
}
apoi in alt program....
Clasa1 c1 = new Clasa1();
Clasa1 c2 = new Clasa1();
c1.x = 100;
c2.x = 200;
int numar = c1.x;
...............
Valoarea pentru numar,va fi 200,deoarece exista o singura variabila x
si ambele instante suprascriu aceeasi variabila.
Metodele declarate static nu pot fi apelate cu this.Este esential sa
fie apelate specificand si instanta (obiectul).In mod similar,atunci cand
o metoda statica trebuie sa apeleze o variabila nonstatica,este necesar
sa se specifice si instanta variabilei respective.Si acest mecanism poate
genera numeroase erori de executie (instanta neprecizata).
In ce priveste importul din alta fila: datele private nu pot fi impor-
tate static,cele protected pot fi importate doar in acelasi pachet,iar
cele publice pot fi importate static si din alt pachet.
-native : se poate utiliza doar pentru metode.Este asemantor cu abstract
si specifica faptul ca definitia metodei se gaseste in alta parte,intr-o
biblioteca externa de Java Virtual Machine.Se utilizeaza pentru coduri
scrise in alt limbaj decat Java (de obicei C si C++).
EXEMPLU: class NativeExample {
native void doSomethingLocal(int i);
static { System.loadLibrary("MyNativeLib"); }
}
-transient : se aplica numai pentru variabile,in cazul obiectelor ce
au persistenta in cadrul seriilor(Serializable objects).O variabila
de tip transient nu va fi arhivata in statusul obiectului persistent.
(vezi mecanismul de eliberare a memoriei Garbage Recycle Bin)
-volatile : se aplica doar pentru variabile si indica faptul ca pot fi
modificate asincron.Se utilizeaza doar in cazul mediilor de operare
cu mai multe procesoare ce opereaza asincron (uz limitat).
-synchronized : se utilizeaza pentru a controla modul de acces la unele
secvente critice de cod,in cazul programelor cu thread-uri concurente.

Optimizarea unei expresii nu se face doar prin modificatori.Exista si


alte situatii ce pot optimiza executia.De exemplu,in cazul functiilor sau
metodelor parametrizate,se pot simplifica sau se pot exclude o parte
dintre parametrii inutili.
Exemplu: Metoda are ca parametru o lista de tip generic,dar lucreaza doar
cu valori numerice simple.Parametrul poate fi inlocuit printr-o variabila
simpla de tip numeric.
Metoda contine parametrii ce nu vor fi utilizati niciodata.Acest
gen de situatii este destul de frecvent atunci cand se importa cate un
modul intreg,pentru a rezolva o anmita functionalitate.Conectarea si
restructurarea acestor module implica o analiza atenta a tipurilor de
data cu care se opereaza.Solutia cea mai simpla este sa renuntati la
parametrii inutili.

-194-
Expresiile pot fi simplificate si in cazul in care contin formule
matematice si calcule complexe.Pentru a evita erorile generate de pre-
cedenta operatorilor,sau de incompatibilitatea tampoanelor de memorie,
este recomandabil sa impartiti orice expresie complexa in expresii mai
mici,ce se executa succesiv.In acest caz,nu numai ca va creste viteza de
procesare,dar puteti extrage si valori intermediare,pentru verificarea pe
etape a rezultatului obtinut.
Atentie la unitatile de masura.Daca cuplati module preluate din pro-
grame diferite,este posibil ca unele sa utilizeze m si Kg,iar altele sa
lucreze cu pounds si iarzi.
O alta etapa de optimizare se refera la modul de editare al codului
propriu zis.Se pot elimina variabilele inutile,se pot elimima spatiile
goale inutile,iar codurile se pot aglomera in spatii mai restranse.Daca
in cazul programelor educative este bine sa lucrati cat mai aerisit,sa
explicati fiecare etapa si operatie si sa includeti in cod toata documen-
tatia necesara,in cazul programelor de lucru,este recomandabil sa limitati
comentariile la minimum necesar.Preferabil sa nu includeti decat datele
strict necesare pentru depanare,verificare si control.
In orice program mai mare,este recomadabil sa lucrati cu thread-uri.
Thread-urile vor fi astfel proiectate incat sa fie cat mai echilibrate.
Verificati cu atentie inchiderea fiecarui thread,asfel incat sa nu existe
fire de executie trenante,ce raman active in background fara sa mai exe-
cute nici o operatie.Astfel de thread-uri,blocheaza o parte din memoria
de operare cu referinte inutile.In mod similar,este bine sa eliberati din
memorie toate obiectele si resursele ce nu mai sunt utile pentru desfasu-
rarea programului.Cu cat exista mai putini pointeri spre memorie,cu atat
procesorul va executa orice operatie mai rapid.
In cazul in care utilizati seturi mai mari de evenimente si ascultatori,
este recomandabil sa alegeti cu atentie evenimentele,astfel incat sa se
evite orice confuzie.Exemplu: daca utilizati mai multe butoane,evenimentul
Click este discriminativ pentru fiecare dintre ele,dar daca utilizati
pentru un singur buton atat evenimentul MouseClick cat si MouseMove,pot
apare si situatii confuzive.
O atentie deosebita trebuie acordata containerelor,colectiilor si
seriilor de date (arii,liste,tabele etc.).In toate aceste situatii,in mod
curent se lucreaza cu rutine automate pentru crearea,sortarea,actualizarea
si eliberarea obiectelor.Orice eroare,poate afecta sute sau mii de obiecte
cu implicatii majore asupra executiei programului.
Nu in ultimul rand,trebuiesc verificate cu atentie buclele de control.
Atunci cand parametrul ce controleaza inchiderea ciclului nu este destul
de clar si discriminativ,este bine sa implementati doua sau mai multe
solutii alternative de iesire din ciclu (pentru a evita buclele cu exe-
cutie infinita).
Nu ezitati sa consultati manuale si articole de specialitate,sau sa va
consultati cu alti programatori.Pentru fiecare tip de problema,exista deja
seturi standardizate de solutii.Nu trebuie decat sa alegeti solutia cea
mai buna pentru aplicatia d-voastra.O serie de tutoriale,sfaturi utile si
solutii concrete puteti gasi la adresele: www.java-tips.org si respectiv
www.1001javatips.com.Mai mult decat atat,puteti apela online la sfatul
expertilor Java,apeland site-ul: www.LivePerson.com.Intotdeauna este bine
sa cereti si o opinie externa,obiectiva ("second opinion").

-195-
4. Modernizare
Platforma Java se modernizeaza in permanenta.La intervale mai mici sau
mai mari,apare o versiune noua,un pachet nou,sau instrumente de lucru noi
(tools).Cele cateva sute de milioane de utilizatori,produc in permaneta
ceva nou.Spre deosebire de alte limbaje de programare,Java este inca in
permanenta dezvoltare.Daca programul d-voastra este conceput modular,este
destul de usor sa actualizati cate un astfel de modul,fie cu un modul
gata editat,preluat din retea,fie cu un modul rescris de d-voastra.Daca
a aparut o versiune noua de Java,verificati daca nu exista incompatibili-
tati.In mod normal,versiunile noi accepta orice solutie anterioara,dar
ofera si solutii noi,mai performante.Acelasi mecanism,trebuie sa fie apli-
cabil si pentru programele d-voastra.Pe masura ce introduceti module sau
resurse noi,programul d-voastra va upgrada spre o versiune superioara,dar
versiunile initiale trebuie sa ramana functionale,chiar daca vor avea o
functionalitate mai limitata(atat timp cat mai exista utilizatori activi).
5.Verificare
Etapa de verificare a programului,este mai complexa decat pare la prima
vedere.In cazul in care programul este strict pentru uz personal,nu este
necesar sa adaugati nici un fel de masuri suplimentare.Insa,in cazul in
care programul este destinat unor clienti necunoscuti,trebuie sa va asi-
gurati ca programul va fi suficient de robust incat sa reziste la orice
ce fel de operatii gresite,accidentale sau voluntare.Pentru acest scop,
trebuie sa implementati cate o solutie de depanare automata a oricarei
situatii de acest gen.Exemplu: utilizatorul altereaza accidental conti-
nutul unei file de resurse.In momentul in care programul apeleaza resursa
respectiva,in loc sa se blocheze,va trebui sa afiseze un mesaj de eroare
si sa revina la etapa anterioara de lucru (executia trebuie sa poata con-
tinua,pentru a putea inchide programul).
Pe cat posibil,programul va executa automat toate operatiile de iden-
tificare si incarcare a resurselor,astfel incat clientul sa execute doar
cateva click-uri de mouse.Exista insa si situatii in care este indispensa-
bil ca utilizatorul sa execute singur unele dintre operatii.In toate
aceste cazuri se vor utiliza bucle de tip TRY....CATCH si metode de prelu-
crare si tratare automata a erorii.In acest manual nu au fost prezentate
decat mesajele de eroare receptionate si afisate de bucla CATCH.Insa,in
situatiile reale,bucla de tratare a erorii va contine codul necesar,fie
pentru corectare erorii,fie pentru revenirea la o etapa anteroara din
program,fie pentru inchiderea automata a programului in conditii de sigu-
ranta.Nu se pot preintampina chiar toate tentativele de fraudare sau for-
tare a programului,dar se pot prevedea toate erorile ce pot intervenii
accidental (se apasa o tasta gresita,se executa un click de mouse in alt
loc decat cel dorit,se executa click-uri accidentale,se introduc date
gresite,se copiaza o resursa gresita,se solicita o adresa gresita,se exe-
cuta concomitent rutine ce anuleaza o parte din date...etc.).
In mod normal,este bine ca verificarea sa fie facuta de alta persoana,
sau alt colectiv,decat cel care a editat programul.Daca exista o eroare
oarecare,este probabil ca programatorul initial sa o repete,fie pentru ca
are tabiet-uri gresite,fie pentru ca nu este sensibilizat sa o observe.
Verificarea se poate face manual,sau cu ajutorul unor programe speciali-
zate.In cazul programelor comerciale,este recomandabil sa apelati la firme
specializate.

-196-
6.Analiza finala
Dupa ce programul a trecut prin toate etapele de verificare,se poate
face o analiza finala(viteza de executie,memorie consumata,intarziere/ope-
ratie,volum de date prelucrate,numar de operatii executate,procese sau
thread-uri active,metode apelate,numar de click-uri sau taste apasate,
numar de obiecte utilizate,date rescrise sau actualizate...etc.).Pentru
acest gen de analiza,fie se introduc in program module specializate ce
semnalizeaza automat toate aceste date,fie se utilizeaza concomitent
programe ce analizeaza automat aplicatia aflata in executie ( cum este
de exemplu jconsole).
Exista cateva solutii ce pot grabi executia programului:
-resursele pot fi impachetate intr-o singura clasa (pentru acces facil)
-thread-urile pot fi grupate in "pools" (pentru control facil)
-filele pot fi comprimate in file JAR executabile
Daca doriti o analiza amanuntita a mediului de executie,puteti utiliza
optiunea Xprof a comenzii java.Pur si simplu,executati aplicatia cu o
astfel de optiune:
EXEMPLU: java -Xrunhprof Memorie1
Aplicatia se va executa normal,dar se va afisa si textul:
Dumping Java heap...allocation sites....done
Pentru a vedea rezultatul analizei,deschideti directorul curent al apli-
catiei si observati fila generata cu numele java.hprof.Fila are circa 3 Mb
si contine toate clasele si obiectele,sau locusurile (sites) alocate.In
plus,o descrie statistica a executiei la nivel de CPU si Monitor.
Exista o serie intreaga de programe,specializate pentru analiza si
managementul memoriei,al claselor si obiectelor,al thread-urilor sau
chiar al codurilor masina de la nivel de procesor.Descrierea acestor
programe nu face obiectul acestui manual,dar este bine sa stiti ca exista.
In situatii critice,sau litigioase,este recomandabil sa apelati la firme
specializate (nu incercati sa va faceti "dreptate" singuri).
7.Legalizare
Pentru a putea obtine "drepturi de autor" trebuie sa va organizati
legal sub forma de societate comerciala,inscrisa la Registrul Comertului.
Apoi,inregistrati fiecare program la OSIM si obtineti timbrul legal ce
trebuie anexat la fiecare copie vanduta.In mod normal,se apeleaza la
firme specializate,care se ocupa de distributie si de asigurarea dreptu-
rilor aferente (puteti cauta o astfel de firma prin reteaua Internet).
Pentru masurile de securizare a programului,este recomandabil sa va
adresati la o firma specializata.In acest fel,va puneti la adapost de
eventualele litigii,generate de masurile de securizare a programelor (cele
mai multe situatii litigioase sunt generate de "drepturile de acces").
Trebuie sa fiti sensibilizati ca raspundeti material si moral,pentru
orice program pus in circulatie,fie ca este comercial,fie ca este in
regim freeware.Totusi,programele oferite in regim "open source",au fost
expuse la litigii doar in ocazii extrem de rare,in majoritatea cazurilor
doar prin acuzatii de "furt intelectual ?".
Acest manual se adreseaza exclusiv incepatorilor.Pentru primele pro-
grame editate de d-voastra,este recomandabil sa nu va lansati la varianta
comerciala,decat daca va asociati cu persoane mai experimentate,sau cu
firme specializate.Indiferent de valoarea programului,se vor gasi clienti
si utilizatori abili,capabili sa va solicite diverse tipuri de "daune".

-197-
8.Impachetare
Pentru arhivarea corecta,dar si pentru operatiile de upload si down-
load din retea,este recomandabil ca aplicatiile sa fie cat mai compacte.
Se poate utiliza si un director simplu,dar este recomandabil sa compri-
mati toate filele intr-o fila de tip JAR.O astfel de fila,nu numai ca este
mult mai usor de manevrat,dar poate fi si functionala.Pentru a crea o
astfel de fila se utilizeaza comanda JAR.Pentru a consulta optiunile este
suficient sa introduceti comanda JAR.Pentru a crea o fila noua,se va uti-
liza optiunea c,la care se pot adauga optional si alte optiuni.Toate
filele ce trebuiesc incluse in pachet,se vor adauga in lista,intr-o singura
linie de comanda.
EXEMPLU: -daca doriti sa impachetati filele necesare pentru exemplul de
applet
Cele trei file sunt: applet1.html,Applet1.class.Applet1.java
in fereastra Command Prompt (in directorul filelor) se va utilza comanda:
jar cvf Applet1.jar applet1.htm Applet1.class Applet1.java
Se va crea automat fila Applet1.jar.Observati ca am impachetat trei
tipuri diferite cu aceeasi comanda.Daca pachetul contine mai multe file
de tip .class,acestea pot fi impachetate simultan cu o comanda generica
de tip /*.class.
Pentru despachetarea filelor din fila JAR se va utiliza o comanda ce
include optiunile x si f.De exemplu,pentru a despacheta fila Applet1.jar
se va utiliza o comanda : jar xf Applet1.jar
In continuare,filele JAR pot fi comprimate cu utilitarul pack200,pentru
a crea o fila extrem de mica.In exemplul de mai sus,se poate utiliza o
comanda de genul: pack200 arhiva.pack.gz Applet1.jar
Se va crea automat o arhiva de tip WinRAR (la fel ca si cu WinZipp).
Pentru a despacheta arhiva,se va putea utiliza utilitarul unpack200 cu o
comanda : unpack200 arhiva.pack.gz Applet2.jar
Am utilizat un alt nume pentru fila JAR,pentru a putea observa fila nou
creata.
Impachetarea filelor nu numai ca va creste foarte mult viteza pentru
transferul in retea,dar asigura si un grad crescut de securitate.Un astfel
de pachet nu poate fi "atacat" accidental",si nu exista riscul de a pierde
file in cursul operatiilor de transfer (prin supraincarcarea tamponului
de memorie).Fila comprimata,inlocuieste zeci sau sute de pointeri prin
unul singur.
Cu aceste recomandari se incheie si acest manual.Platforma Java are
insa o arie de acoperire mult mai mare si in continua dezvoltare.Pentru
a stapani acest domeniu,este necesar un efort permanet de instruire si
reactualizare sau restructurare a notiunilor.Cand proiectati o aplicatie
Java sau JavaCE,este bine sa aveti in vedere si proverbul:

"Tot ce este foarte bun,este prea mic...sau prea putin ! "

***********
* SFARSIT *
***********

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