Sunteți pe pagina 1din 183

CURS I 1.

Introducere in Java
1.1. Introducere Limbajul Java a fost lansat public pentru prima dat n noiembrie 1995 de firma Sun Microsystems. Era vorba de un limbaj de programare care putea rula ntr-o pagin WWW, fcndu-i un nume printre imagini, text, audio i omniprezentele semne n construcie. Java este un limbaj de programare adecvat pentru proiectarea de software dedicat lucrului n Internet, modelat dup limbajul de programare C++. Este deci un limbaj de programare orientat obiect, care folosete o metodologie ce devine din ce n ce mai folositoare n lumea proiectrii de software. n plus, este un limbaj independent de platform (crossplatform), ceea ce nseamn c programele pot fi proiectate s ruleze n acelai fel pe Microsoft Windows, Apple Macintosh i majoritatea versiunilor de UNIX. Java se extinde i dincolo de calculatoarele de birou, putnd fi executat pe dispozitive cum ar fi televizoare , ceasuri de mn sau telefoane celulare, JavaStation, staia de reea dedicat a firmei Sun, folosete ca sistem de operare JavaOS i este optimizat pentru acest limbaj. Java se aseamn mai mult cu limbajele de programare populare, cum ar fi C, C++, Visual Basic sau Delphi, dect cu limbajele de descriere a paginilor, cum este HTML, sau cu limbaje pentru scripturi, cum este JavaScript . Ceea ce a fcut att de popular acest limbj este n special faptul c faciliteaz utilizarea graficii interactive i a altor efecte speciale ntr-o pagin WWW. Ca orice limbaj de programare, Java permite scrierea de programe. Anumite programe Java, denumite applets, sunt executate n cadrul unei pagini Web, cu o capacitate asemntoare oricrui program tradiional. n plus, atunci cnd rulai un applet Java, serverul aflat la distan l transmite ctre browser prin Internet. Primul browser care a acceptat appleturile Java a fost HotJava, n prezent aproape toate browserele accept appleturile. De exemplu, Netscape Navigator accept appleturile de la versiunea 2.0. Appleturile sunt nglobate ntr-o pagin Web ntr-un mod asemntor unei imagini. Spre deosebire de imagini, appleturile pot fi interactive preiau intrrile utilizatorului, rspund la ele i prezint un coninut dinamic, la schimbare . Appleturile sunt ncarcate din WWW ca pagini HTML, imagini sau alte elemente ale unui site Web. Pe un browser, appletul va ncepe s ruleze imediat ce se termin de ncrcat . Appleturile sunt scrise n limbajul Java, compilate ntr-o form ce poate rula ca program i plasate pe serverul Web. Majoritatea serverelor pot livra fiiere Java fr nici o alt modificare n configuraia lor. Java este un limbaj de programare tnr , cu posibiliti de perfecionare att n privina limbajului ct i n privina instrumentelor utilizate pentru dezvoltare. Pentru o foarte succint caracterizare a limbajului, ni se pare potrivit s reproducem descrierea fcut de firma Sun, n The Java Language: A White Paper: Java: un limbaj simplu, orientat obiect, distribuit, interpretabil, robust, sigur, independent de arhitectur, portabil, de nalt performan, cu faciliti multithreading i dinamic.

Java este un limbaj simplu Nu este foarte clar, n general, ce nseamn simplu. n cazul de fa, un cunosctor al limbajului C, eventual al lui C++, poate s nvee Java foarte uor. Vis a vis de limbajele C i C++, Java aduce o serie de simplificri. Iat cteva dintre cele mai importante. Nu exist instruciunea goto, n schimb instruciunile break i continue sunt extinse, ele putnd fi folosite cu etichete spre a prsi/reitera nu numai cel mai interior ciclu. Java nu admite n textul surs faciliti de preprocesor (linii ce ncep cu #) i nu are fiiere header (linii #include). Construciile struct i union sunt eliminate. De asemenea, din facilitile obiectuale ale lui C++ au fost eliminate dou faciliti relativ controversate: motenirea multipl i suprancrcarea operatorilor. Poate c cea mai important simplificare este aceea c Java nu utilizeaz pointeri i implicit nu utilizeaz aritmetica de pointeri. Programatorii C / C++ tiu c aceasta este o surs important de erori. Toate obiectele Java sunt alocate dinamic, transparent fa de programator. De asemenea, programatorul nu trebuie s se ocupe de eliberarea memoriei, aceasta fcndu-se automat, prin intermediul unui mecanism de garbage collection (mecanismul de colectare i eliberare a zonelor de memorie nefolosite). Java este orientat pe obiecte Programarea orientat obiect Object Oriented Programming sau OOP este o modalitate de a modela un program drept un set de obiecte aflate n interaciune. Pentru unii reprezint chiar o modalitate de a organiza programele ; astfel, orice limbaj poate fi folosit pentru a crea programe orientate obiect . Java este un limbaj de programare orientat pe obiect, ceea ce nseamn c putei utiliza Java pentru a dezvolta programele voaste cu date i metode (funcii) care opereaz asupra datelor. n Java , o clas este o colecie de date i metode care descriu un obiect cu care programul opereaz. Concepei un obiect ca pe un lucru, cum ar fi o imagine grafic, o caset de dialog sau un fiier. Appleturile Java pot organiza clasele n ordine ierarhic, ceea ce nseamn c putei construi noi clase pornind de la clasele existente, optimiznd sau extinznd caracteristicile clasei existente. Cu excepia ctorva tipuri simple, cum ar fi numerele, caracterele i tipurile booleene, orice altceva este obiect. Java deine un cuprinztor set de clase pe care le putei utiliza n programele voastre. De fapt, un applet Java este el nsui o clas Java. Java este un limbaj distribuit Java este proiectat s suporte aplicaii n reea; suportnd diferite nivele de conectivitate n reea prin intermediul pachetului java.net. De exemplu, clasa URL permite aplicaiilor Java s deschid i s acceseze obiecte indeprtate n Internet. Cu Java, este la fel de uor s se deschid un fiier indeprtat ca i unul local. Java suport de asemenea att conectivitate fiabil (TCP) cu clasa Socket ct i conectivitate nefiabil (UDP) prin clasele Datagram*.

Java este un limbaj interpretabil Compilatorul Java genereaz, pentru fiecare entitate compilat, un cod echivalent, ntr-o form care se preteaz prelucrrii prin tehnica interpretrii. Ca i reprezentare intern, codul generat este format dintr-un ir de octei. Limbajul interpretativ este unul UNIVERSAL, NU un cod nativ al unei anumite maini. Pentru a executa un program Java are nevoie de un interpretor care s prelucreze octeii generai de compilator. Forma de generare a codului de octei este independent (neutr) fa de o anumit main. De aceea, codul poate fi executat pe orice main care dispune de un interpretor Java adic o main virtual, numit JVM (Java Virtual Machine). Pentru fixarea terminologiei, codul generat de compilator l vom numi cod JVM.

Java este un limbaj robust Atunci cnd se spune despre un cod c este robust , se face referire la fiabilitatea sa. Dei Java nu a eliminat codul nesigur, a reuit s fac mai accesibil scrierea unui cod de nalt calitate. Pentru nceput, Java elimin multe dintre problemele de memorie care sunt obinuite n limbaje precum C i C++. Java nu accept accesul direct la pointeri de memorie. Ca urmare, un applet nu poate altera memoria calculatorului. De asemenea Java efectueaz verificri n timpul execuiei pentru a se asigura c toate referirile la tablouri i iruri de caractere se afl ntre limitele fiecrui element. n alte limbaje de programare, multe dintre erorile logice(bugs) apar din cauz c programele nu elibereaz memoria pe care ar trebui s o elibereze sau elibereaz aceeai memorie de mai multe ori. Java, pe de alt parte, efectueaz o curenie automat, evitnd necesitatea ca programul s elibereze memoria neutilizat. Apoi, Java este mult mai puternic orientat pe tipuri dect C++ i solicit declaraii de metod explicite, ceea ce reduce posibilitatea erorilor de nepotrivire de tip. n sfrit, Java instituie o metod de detectare a erorilor cunoscut ca tratarea excepiilor (exception handling). Atunci cnd apare o eroare de program, java semnaleaz o excepie, ceea ce permite programului s treac de eroare i avertizeaz utilizatorul c exist ceva care provoac euarea unei anumite operaii. Java este un limbaj sigur Se poate ntlni un virus n Internet, dac se descarc i ruleaz un program. Din pcate, n cazul appleturilor Java, serverul aflat la distan descarc appletul ctre un browser al sistemului vostru, care ruleaz apoi appletul. La prima vedere, aceast descrcare a appleturilor Java este modalitatea ideal de creare a viruilor. Din fericire, proiectanii limbajului Java au avut n vedere lucrul n reea. De aceea, Java are ncorporate mai multe mijloace de securiate, care reduc capacitatea crerii unui virus prin Java. n primul rnd, appleturile Java nu pot citi sau scrie fiiere locale de pe discul calculatoarelor voastre. n acest fel, un applet nu poate s stocheze virusul pe discul calculatorului sau s-l ataeze unui fiier. Pur si simplu, appletul nu poate efectua operaii de intrare sau de ieire pe disc. n al doilea rnd, appleturile Java sunt oarbe n raport

cu configurarea memoriei calculatorului. Mai precis, appleturile Java nu au pointeri la memorie, astfel c programatorii nu pot utiliza aceast tradiional u de serviciu ctre calculatorul vostru. n al treilea rnd, Java nu poate altera memoria din afara propriului su spaiu de memorie. nglobnd aceste precauii n nsui limbajul Java, proiectanii si au reuit s impiedice n mare msur utilizarea sa la crearea i transmiterea viruilor. Java este independent de platform
Interpretor Java (Pentium) Bytecode Java (independent de platforma)
_______ ____ ______ _______ _______ _______ ____ ______ _______ _______

Cod Java
_______ ____ ______ _______ _______

Interpretor Java (PowerPC)


_______ ____ ______ _______ _______

Compilator Java

Interpretor Java (SPARC)


_______ ____ ______ _______ _______

Independena de platform posibilitatea ca un acelai program s ruleze pe diferite platforme sau SO este unul dintre cele mai semnificative avantaje pe care Java le are asupra altor limbaje de programare . Atunci cnd scriei i compilai un appplet Java, vei obine n final un fiier independent de platform numit cod de octei (bytecode) spre deosebire de majoriatea limbajelor la care prin compilare rezult un fiier n cod main instruciuni specifice procesorului pe care l folosete calculatorul vostru. Programele Java i dobndesc aceast independen folosind o main virtual un fel de calculator ntr-un alt calculator. Maina virtual preia programele Java compilate i le convertete instruciunile n comenzi inteligibile pentru sistemul de operare. Acelai program compilat care exist ntr-un format bytecode, poate rula pe orice platform i sistem de operare care posed o main virtual Java. Maina virtual mai este cunoscut i ca interpretor Java sau executor (runtime) Java. Java este independent de platform la nivel surs. Sursa, denumit i cod surs, reprezint un set de instruciuni de programare pe care un programator le introduce cu ajutorul unui editor de texte, atunci cnd creeaz un program. Codul surs este compilat n bytecode, aa nct poate fi rulat pe o main virtual Java. Bytecode-ul este asemntor codului main produs de alte limbaje, ns nu este specific nici unui procesor. Aceasta mai introduce un nivel ntre surs i codul main, aa cum se poate vedea n figura 1. Aceast main virtual se poate gsi n mai multe locuri. Pentru appleturi, maina virtual este fie nglobat ntr-un browser care suport Java, fie instalat separat, pentru a fi folosit de browser. Aplicaiile Java, pe de alt parte, pot rula doar ntr-un sistem unde a fost instalat maina virtual Java corespunztoare.

Apare aici intrebarea : ce impact are asupra performanei faptul c ntre sursa programului i codul main compilat se interpune bytecode-ul . Rspunsul este c programele Java se execut mai lent dect limbajele compilate dependente de platform, cum ar fi C, iar aceast diferen de vitez este principalul dezavantaj al Java. Pentru majoritatea programelor simple Java, viteza s-ar putea s nu reprezinte o problem. Dac dorii s scriei programe ce necesit o vitez mai mare de execuie dect poate oferi maina virtul, exist cteva soluii disponibile : - folosii n programul Java apeluri ctre codul main specific sistemului, ceea ce va face ca programul rezultat s fie dependent de platform - folosii compilatoare rapide (just-in-time), care convertesc bytecode-ul Java n cod specific mainii Java este un limbaj portabil Neutralitatea fa de arhitectur este numai unul dintre aspectele portabilitii. Un altul este acela ca limbajul s nu permit aspecte dependente de implementare (vezi spre exemplu reprezentarea diferit a int pe la diverse implementri C). n acest scop, Java specific lungimea n octei a fiecrui tip de date ca i o mrime aritmetic obinuit. Mediul Java este portabil pe noile sisteme de operare, deoarece compilatorul Java este scris tot n Java, n timp ce executabilul (run time system) este scris n ANSI C, cu respectarea specificaiilor POSIX. Java este un limbaj de nalt performan Robusteea limbajului este asigurat de o serie de mecanisme de nalt performan, cum ar fi verificarea timpurie a programelor pentru posibile probleme, verificarea dinamic trzie (runtime), i forarea programatorului s elimine situaiile care sunt presupuse c ar putea genera probleme la rulare. Unul dintre avantajele limbajelor puternic tipizate (cum ar fi C++) este c asigur un puternic suport pentru verificarea programelor n timpul compilrii n ideea de a elimina un numr ct mai mare de erori, din pcate limbajul C++ motenete o serie de probleme la verificarea n timpul compilrii tocmai din C, i acesta doar pentru a pstra compatibilitatea n jos. Deoarece Java nu are ce compatibilitate n jos s menin, nu este nevoit s suporte consecinele unor implementri sau specificaii vechi proaste sau incomplet fcute. Un exemplu, declaraiile, pe cnd n C++, se permit declaraii implicite ale variabilelor, funciilor sau procedurilor (tocmai motenite din C), Java este foarte sever n declararea exact a lor. Chiar i linkeditorul mai repet aceleai verificri pentru a fi sigur c nu apar probleme de incompatibiliti ntre tipuri de date folosite. Java este un limbaj cu faciliti multithreading ntr-o aplicaie de reea bazat pe GUI (de exemplu utilizarea unui browser Web) sunt uor de imaginat medii multitasking: procesorul se ocup simultan de controlul animaiei, calcule, gestiunea memoriei etc. Java ofer acest gen de servicii. Astfel,

pachetul java.lang ofer clasa Thread, care suport creare, oprire, execuie, control i sincronizare thread. Sincronizarea se bazeaz pe conceptul de monitor. Este cunoscut faptul c operarea cu multithreading d mult btaie de cap programatorilor C i C++. Programatorii trebuie s-i implementeze mecanisme proprii de blocare a unor seciuni critice i de partajare a unor resurse critice. Primitivele furnizate de Java reduc esenial acest efort. Java este dinamic Bibliotecile de clase n Java pot fi reutilizate cu foarte mare uurin. Cunoscuta problem a fragilitii superclasei este rezolvat mai bine dect n C++. Acolo, dac o superclas este modificat, trebuie recompilate toate subclasele acesteia pentru c obiectele au o alt structur n memorie. n Java aceast problem este rezolvat prin legarea trzie a variabilelor, doar la execuie. Regsirea variabilelor se face prin nume i nu printr-un deplasament fix. Dac superclasa nu a ters o parte dintre vechile variabile i metode, ea va putea fi refolosit fr s fie necesar recompilarea subclaselor acesteia. Se elimin astfel necesitatea actualizrii aplicaiilor, generat de apariia unei noi versiuni de bibliotec aa cum se ntmpl, de exemplu, cu MFC-ul Microsoft (i toate celelalte ierarhii C++).

1.2. Instalarea pachetului Java Development Kit (JDK) sub Windows Kitul de dezvoltare Java (JDK) este o colecie de software de la firma Sun care cuprinde tot ce este nevoie pentru crearea aplicaiilor standalone i appleturilor Java . Astfel , JDK conine compilatorul Java , depanatorul i un vizualizator de appleturi cu ajutorul cruia appleturile pot rula n afara unui browser , precum i documentaie i exemple de appleturi . Pachetul JDK poate fi transferat , pentru diferite platforme , de pe situl Web al firmei Sun de la adresa http://java.sun.com . nainte de a instala JDK pe sistemul dumneavoastr , trebuie s v asigurai c nu sunt instalate alte instrumente de dezvoltare Java . Dac exist mai multe instrumente de dezvoltare Java , acest lucru va duce , probabil ,, la probleme de configurare , atunci cnd vei ncerca s folosii JDK . Pentru a instala JDK sub Windows , executai dublu clic pe fiierul care conine arhiva de instalare sau folosii comanda Start|Run din bara de programe a Windows , pentru a gsi i a executa fiierul . Dup ce vei vedea o caset de dialog care v ntreab dac dorii s instalai JDK , va fi afiat asistentul JDK Setup Wizard . Putei folosi aceast fereastr pentru a configura modul n care JDK se instaleaz pe sistemul vostru . Parametrii predefinii ai acestui asistent ar trebui s fie buni pentru majoritatea utilizatorilor . JDK este instalat ntr-un nou folder , care primete un nume bazat pe versiunea pe care ai transferat-o (cum ar fi \jdk1.6.0_07) ; dac dorii s selectai un alt director din sistem , folosii butonul Browse . 1.3. Testarea instalrii

Utilizatorii Windows pot testa instalarea JDK folosind comanda MS-DOS Prompt . Aceasta va avea ca rezultat afiarea unei ferestre unde se pot tasta comenzi MS-DOS . Se introduce urmatoarea comand la prompt-ul de comand pentru a testa dac sistemul vostru gsete instalat versiunea corect de JDK : java -version Dac folosii JDK 1.6.0_07 ar trebui s obtinei ca rspuns urmtorul mesaj : java version 1.6.0_07 Dac obtinei ca rspuns un alt numr de versiune sau eroarea Bad command or file name , nseamn c sistemul vostru nu poate gsi versiunea corect a fiierului java.exe . fiierul care ruleaz programele Java . Acest lucru trebuie corectat nainte de a ncepe scrierea programelor Java . 1.4. Setarea variabilelor PATH i CLASSPATH Utilizatorii Windows trebuie s-i seteze variabilele Java . Variabila PATH trebuie s conin calea spre directorul BIN al pachetului JDK . De obicei aceast cale este C:\Program Files\Java\jdk1.6.0_07\bin pentru versiunea 1.6.0_07. Variabila CLASSPATH trebuie s conin calea spre biblioteci sau spre clasele folosite n programe . Pachetul JDK ofer o bibliotec tools.jar care se gsete n directorul LIB . n cazul n care variabila CLASSPATH nu exist ea trebuie creat . Setarea acestor variabile difer n funcie de versiunea de Windows folosit . Pentru Windows Millenium se poate obine acces la aceste variabile prin : Start Programs Accessories SystemTools System Information . Se deschide astfel fereastra de Help and Support i din meniul Tools se alege System Configuration Utility , iar la Environment se editeaz variabilele PATH i CLASSPATH i li se modific valorile . Pentru Windows XP, Vista la proprietile calculatorului exist Advanced Environment Variabiles . 1.5. Primele aplicaii Java Aa cum se obinuiete la prima prezentare a unui limbaj, vom prezenta cel mai simplu program Java posibil: afiarea unui ir de caractere. Specificul Java ofer ns dou tipuri de programe: aplicaii de sine stttoare, numite n terminologia Java standalone; programe activabile prin intermediul navigatoarelor Web, numite appleturi. 1.5.1.Programul standalone Salut 1.5.1.1. Sursa programului Fiierul surs poart numele Salut.java i este prezentat n programul1. public class Salut{ public static void main(String a[]) { System.out.println("Salut"); }//Salut.main

}//Salut Programul 1 Textul surs Salut.java Mai nti cteva precizri, care reprezint de fapt i primele reguli Java. Unele dintre amnunte vor fi explicate pe larg mai trziu. Un program Java const din definirea i instanierea unei clase. Numele textului surs este format din numele clasei urmat de sufixul .java. Unele programe pot conine n acelai text surs mai multe clase, dar atunci numai una dintre ele va fi vizibil n exterior, celelalte fiind numai de uz intern. Un program standalone trebuie s conin metoda static main. Ea are ca parametru un tablou avnd ca i elemente iruri de caractere. Fiecare element al tabloului conine un argument transmis n linia de comand ce lanseaz programul n execuie. Tiprirea este executat de ctre metoda println a obiectului out din clasa System. 1.5.1.2.Compilarea i rularea programului Compilatorul Java poart numele de javac. Lansarea compilrii programului se face cu comanda: javac Salut.java Compilatorul JDK nu afieaz nici un mesaj dac programul se compileaz cu succes . Dac programul s-a compilat fr erori , n directorul care conine fiierul Salut.java va aprea nc un fiier (Rezultatul compilrii) cu numele Salut.class, care conine codul JVM echivalent. Interpretorul standard Java poart numele java. El preia codul JVM din Salut.class i-l execut (interpretativ). Execuia interpretativ se lanseaz prin comanda: java Salut Ca efect, pe ecran se va afia, pe linie nou: Salut 1.5.2. Appletul SalutAp 1.5.2.1. Sursa appletului Exemplul din seciunea precedent, scris ca un applet, este prezentat n programul 2. import java.applet.*; import java.awt.*; public class SalutAp extends Applet { public void paint(Graphics g) { g.drawString("Salut",10,50); }//SalutAp.paint }//SalutAp Programul 2 Textul surs al appletului SalutAp.java

Mai nti se declar folosirea de metode ale pachetelor applet i awt. Apoi se indic faptul c clasa SalutAp extinde (este o subclas) clasa Applet. Scrierea textului se face prin intermediul metodei paint. Aceasta realizeaz rescrierea metodei paint din java.awt.Component, avnd rolul de a "picta" un obiect grafic g. Concret, este vorba de scrierea unui string ncepnd de la pozitia (x= 10 pixeli spre dreapta, y = 50 pixeli n jos). Compilarea sursei se face folosind aceeai comand de compilare: javac SalutAp.java care genereaz codul de octei echivalent sursei n fiierul SalutAp.class. Pentru lansarea n execuie a acestui applet este nevoie de un navigator Web, cum ar fi de exemplu Netscape, Mozilla, Konqueror, InternetExplorer. Pachetul Java ofer pentru testarea appleturilor, interpretorul appletviewer care este, de fapt, un navigator Web specializat. n textul surs HTML transmis navigatorului Web trebuie inserat sursa din programul 3. <APPLET code="SalutAp.class" width="500" height="100"> </APPLET> Programul 3. Textul surs SalutAp.html Numele fiierului .java trebuie s coincid cu numele clasei, ns numele fiierului HTML poate fi diferit (eu l-am luat acelai din comoditate). Prin acest text, care este un tag HTML, se cere navigatorului s-i ncarce codul JVM din fiierul SalutAp.class i s-l execute (interpretativ). Dac se dorete utilizarea interpretorului standard Java appletviewer, se va lansa comanda: appletviewer SalutAp.html 1.5.3.Un program ce poate rula alternativ standalone sau applet Pare cel puin interesant s vedem un program care s poat rula, dup preferin, ori ca aplicaie standalone ori ca applet. Unul dintre cele mai simple programe de acest tip este programul urmator : import java.awt.*; import java.applet.*; import java.awt.event.*; public class PrimCompus extends Applet { public static void main(String a[]) { WindowListener l=new WindowAdapter() { public void windowClosing(WindowEvent e){System.exit(0);} }; PrimCompus oPrimCompus = new PrimCompus();
9

Frame oFrame = new Frame("Fereastra standalone"); oFrame.addWindowListener(l); oFrame.setSize(250,350); oFrame.add("Center", oPrimCompus); oFrame.show(); oPrimCompus.init(); }//PrimCompus.main public void init() { }//PrimCompus.init public void paint(Graphics g) { g.drawString("Un sir in fereastra",50,60); }//PrimCompus.paint }//PrimCompus Sursa PrimCompus.java Clasa PrimCompus extinde clasa Applet spre a se putea comporta ca i un applet. De asemenea, n cadrul ei se definete metoda main, care este invocata la lansarea ca i aplicaie standalone. S urmrim mai nti comportarea ca i applet. In momentul lansrii dintr-un navigator, acesta (navigatorul) caut metoda init pe care o lanseaz n execuie. In exemplul nostru metoda init este vid. In continuare (dup cum am artat i la exemplul SalutAp), dac n cadrul clasei este definit metoda paint, atunci se lanseaz n execuie aceasta. In cazul nostru va afia un string n fereastr. Pentru lansarea din navigator, este suficient ca documentul html s aib coninutul : <html> <title>Fereastra applet </title> <Applet code="PrimCompus.class" width=250 height=350> </Applet> </html> Sursa PrimCompus.html Spre a se deosebi de aplicaia standalone, am precizat i titlul ferestrei. Execuia programului este:

10

Pentru ca programul s poat fi rulat, cu (aproape) acelai efect, n cadrul metodei main trebuie executate cteva aciuni, de altfel specifice interfeelor grafice de tip standalone. Mai nti am definit i construit obiectul oPrimCompus de tipul clasei. Apoi am definit un obiect oFrame de tip Frame (tipul clasic de fereastr din pachetul awt). Am fixat titlul acestei ferestre i dimensiunile ei (n pixeli). Am adugat n poziia central obiectului oFrame obiectul oPrimCompus i am cerut ferestrei s devin vizibil. In sfrit, am lansat metoda init a obiectului oPrimCompus, dup care comportarea va fi ca i la applet: va cuta metoda paint i va afia stringul n fereastr. 1.5.3. Scrierea programelor folosind mediul NetBeans 6.1 Mediu NetBeans 6.1. poate fi descarcat gratuit de pe situl Web al firmei de la adresa si apoi instalat in mod normal ca si majoritatea aplicatiilor pe calculatorul personal. Vom realiza in continuare rescrierea programelor folosind mediul NetBeans6.1. 1.5.3.1.Programul standalone Salut 1.5.3.1.1. Sursa programului Se lanseaza aplicatia NetBeans 6.1. Din meniul pop-up File se alege New Project. La primul pas la categorie se alege Java, iar la proiect Java Application. In pasul al doilea se da un nume la proiect (ex: lab1a) si o locatie (ex: E:\My Documents\goldis\anul 20082009\teh avns\sapt1), iar la numele clasei se pune lab1a.Salut. Si astfel se finalizeaza crearea proiectului.

11

Dupa creare se deschide automat fisierul Salut.java care contine in prima faza urmatoarele: /* * To change this template, choose Tools | Templates * and open the template in the editor. */ package lab1a; /** * * @author user */ public class Salut { /** * @param args the command line arguments */ public static void main(String[] args) { // TODO code application logic here } } Se modifica fisierul astfel incat sa realizam afisarea mesajului de salut: /* * To change this template, choose Tools | Templates * and open the template in the editor. */ package lab1a; /** * * @author user */ public class Salut { /** * @param args the command line arguments */ public static void main(String[] args) { System.out.println("Salut"); } }

12

1.5.3.1.2.Compilarea i rularea programului Compilarea se poate realiza din meniul Run->Run File->Debug Salut.java, iar rularea Run->Run File-> Run Salut.java. Ca efect, in fereastra output se va afia: init: deps-jar: compile-single: run-single: Salut BUILD SUCCESSFUL (total time: 0 seconds) 1.5.3.2. Appletul SalutAp 1.5.3.2.1. Sursa appletului Se lanseaza aplicatia NetBeans 6.1. Din meniul pop-up File se alege New Project. La primul pas la categorie se alege Java, iar la proiect Java Class Library. In pasul al doilea se da un nume la proiect (ex: lab1b) si o locatie (ex: E:\My Documents\goldis\anul 20082009\teh avns\sapt1). Si astfel se finalizeaza crearea proiectului. Dupa creare in partea stanga apare proiectul lab1b. Se da click dreapta pe lab1b si se alege New->Other. In primul pas la categorie se alege Java, iar la tipul fisierului se alege Applet. In pasul al doilea se da un nume la clasa (ex: SalutAp) si se termina. Dupa finalizare se deschide automat fisierul SalutAp.java cu urmatorul continut: /* * To change this template, choose Tools | Templates * and open the template in the editor. */ import java.applet.Applet; /** * * @author user */ public class SalutAp extends Applet { /** * Initialization method that will be called after the applet is loaded * into the browser. */ public void init() { // TODO start asynchronous download of heavy resources }

13

// TODO overwrite start(), stop() and destroy() methods } Se modifica continutul astfel: /* * To change this template, choose Tools | Templates * and open the template in the editor. */ import java.applet.Applet; import java.awt.Graphics; /** * * @author user */ public class SalutAp extends Applet { /** * Initialization method that will be called after the applet is loaded * into the browser. */ public void init() { // TODO start asynchronous download of heavy resources } public void paint(Graphics g){ g.drawString("Salut", 10, 50); } } 1.5.3.2.2.Compilarea i rularea programului Compilarea se poate realiza din meniul Run->Run File->Debug SalutAp.java, iar rularea Run->Run File-> Run SalutAp.java. Ca efect, in fereastra output se va afia: init: deps-jar: Compiling 1 source file to E:\My Documents\goldis\anul 2008-2009\teh avns\sapt 1\lab1b\build\classes compile-single: si totodata se deschide se fereastra appletviewer astfel :

14

15

CURS 2 2.Prezentarea Java 2.1. Structura lexicala a limbajului Java 2.1.1 Setul de caractere Limbajului Java lucreaza in mod nativ folosind setul de caractere Unicode. Acesta este un standard international care inlocuieste vechiul set de caractere ASCII si care foloseste pentru reprezentarea caracterelor 2 octeti, ceea ce nseamna ca se pot reprezenta 65536 de semne, spre deosebire de ASCII, unde era posibila reprezentarea a doar 256 de caractere. Primele 256 caractere Unicode corespund celor ASCII, referirea la celelalte facandu-se prin \uxxxx, unde xxxx reprezinta codul caracterului. O alta caracteristica a setului de caractere Unicode este faptul ca ntreg intervalul de reprezentare a simbolurilor este divizat n subintervale numite blocuri, cateva exemple de blocuri fiind: Basic Latin, Greek, Arabic, Gothic, Currency, Mathematical, Arrows, Musical, etc. Mai jos sunt oferite cateva exemple de caractere Unicode. \u0030 - \u0039 : cifre ISO-Latin 0 - 9 \u0660 - \u0669 : cifre arabic-indic 0 - 9 \u03B1 - \u03C9 : simboluri grecesti _ ! \u2200 - \u22FF : simboluri matematice \u4e00 - \u9fff : litere din alfabetul Han (Chinez, Japonez, Coreean) Mai multe informatii legate de reprezentarea Unicode pot fi obtinute la adresa http://www.unicode.org. 2.1.2 Cuvinte cheie Cuvintele rezervate in Java sunt, cu cateva exceptii, cele din C++ si au fost enumerate n tabelul de mai jos. Acestea nu pot fi folosite ca nume de clase, interfete, variabile sau metode. true, false, null nu sunt cuvinte cheie, dar nu pot fi nici ele folosite ca nume n aplicatii. Cuvintele marcate prin * sunt rezervate, dar nu sunt folosite. Java utilizeaz urmtoarele cuvinte cheie:
abstract catch default final if interface private static this void boolean char do finally implements long protected strictfp throw volatile Break Class Double Float Import Native Public Super Throws While byte const* else for instanceof new return switch transient case continue extends goto* int package short synchronized try

ncepand cu versiunea 1.5, mai exista si cuvantul cheie enum.

2.1.3 Identificatori Sunt secvente nelimitate de litere i cifre Unicode, ncepand cu o litera. Identificatorii nu au voie sa fie identici cu cuvintele rezervate. 2.1.4 Literali Literalii pot fi de urmatoarele tipuri: ntregi Sunt acceptate 3 baze de numeratie : baza 10, baza 16 (ncep cu caracterele 0x) i baza 8 (ncep cu cifra 0) i pot fi de doua tipuri: normali - se reprezinta pe 4 octeti (32 biti) lungi - se reprezinta pe 8 octeti (64 biti) i se termina cu caracterul L (sau l). Flotanti Pentru ca un literal sa fie considerat flotant el trebuie sa aiba cel putin o zecimala dupa virgula, sa fie n notatie exponentiala sau sa aiba sufixul F sau f pentru valorile normale reprezentate pe 32 biti, respectiv D sau d pentru valorile duble - reprezentate pe 64 biti. Exemple: 1.0, 2e2, 3f, 4D. Logici Sunt reprezentati de true - valoarea logica de adevar, respectiv false - valoarea logica de fals. Observatie: Spre deosebire de C++, literalii ntregi 1 si 0 nu mai au semnificatia de adevarat, respectiv fals. Caracter Un literal de tip caracter este utilizat pentru a exprima caracterele codului Unicode. Reprezentarea se face fie folosind o litera, fie o secventa escape scrisa ntre apostrofuri. Secventele escape permit specificarea caracterelor care nu au reprezentare grafica si reprezentarea unor caractere speciale precum backslash, apostrof, etc. Secventele escape predefinite n Java sunt: \b : Backspace (BS) \t : Tab orizontal (HT) \n : Linie noua (LF) \f : Pagina noua (FF) \r : nceput de rand (CR) \" : Ghilimele \ : Apostrof \\ : Backslash Siruri de caractere Un literal sir de caractere este format din zero sau mai multe caractere ntre ghilimele. Caracterele care formeaza sirul pot fi caractere grafice sau secvente escape. Daca sirul este prea lung el poate fi scris ca o concatenare de subsiruri de dimensiune mai mica, concatenarea sirurilor realizandu-se cu operatorul +, ca n exemplul: "Ana " + " are " + " mere ". Sirul vid este "". Dupa cum vom vedea, orice sir este de fapt o instanta a clasei String, definita n pachetul java.lang.

2.1.5 Separatori Un separator este un caracter care indica sfarsitul unei unitati lexicale si nceputul alteia. n Java separatorii sunt urmatorii: ( ) [ ] ; , . . Instructiunile unui program se separa cu punct si virgula. 2.1.6 Operatori Operatorii Java sunt, cu mici deosebiri, cei din C++: atribuirea: = operatori matematici: +, -, *, /, %, ++, -- . Este permisa notatia prescurtata de forma lval op= rval: x += 2 n-= 3 Exista operatori pentru autoincrementare si autodecrementare (post i pre): x++, ++x, n--, --n Evaluarea expresiilor logice se face prin metoda scurtcircuitului: evaluarea se opreste n momentul n care valoarea de adevar a expresiei este sigur determinata. operatori logici: &&(and), ||(or), !(not) operatori relationali: <, <=, >, <=, ==, != operatori pe biti: &(and), |(or), ^ (xor), ~ (not) operatori de translatie: <<, >>, >>> (shift la dreapta fara semn) operatorul if-else: expresie-logica ? val-true : val-false operatorul , (virgula) folosit pentru evaluarea secventiala a operatiilor: int x=0, y=1, z=2; operatorul + pentru concatenarea sirurilor: String s1="Ana"; String s2="mere"; int x=10; System.out.println(s1 + " are " + x + " " + s2); operatori pentru conversii (cast) : (tip-de-data) int a = (int)a; char c = (char)96; int i = 200; long l = (long)i; //widening conversion long l2 = (long)200; int i2 = (int)l2; //narrowing conversion operatorul instanceof : Acesta ntoarce true dac obiectul din stnga lui este o instaniere a clasei specificate n dreapta i false n caz contrar. Totusi fa de C, operatorii Java sunt puin diferii. Astfel, au fost eliminai operatorii * (indirectare) & (adresa), sizeof, ->. Perechea de paranteze [ i ] precum i . (punct) nu sunt operatori. Operatorul +, dup cum am mai artat, se mai folosete si la concatenare de stringuri. S-a introdus operatorul instanceOf.. Operatorul >> efectueaz deplasarea spre dreapta a configuraiei unui ntreg cu propagarea bitului de semn n poziiile eliberate.

S-a introdus operatorul >>>, care deplaseaz spre dreapta cu completarea bii zero n poziiile eliberate. Reamintim c n Java toi ntregii sunt reprezentai cu semn. Operatorii & i | au ca operanzi ntregi i dau ca rezultat ntreg. n acelai timp, operatorii && i || au ca operanzi booleeni i dau ca rezultat un boolean. 2.1.7 Comentarii n Java exista trei feluri de comentarii: Comentarii pe mai multe linii, nchise ntre /* si */. Comentarii pe mai multe linii care tin de documentatie, nchise ntre /** si */. Textul dintre cele doua secvente este automat mutat n documentatia aplicatiei de catre generatorul automat de documentatie javadoc. Comentarii pe o singura linie, care incep cu //. Observatii: 1. Nu putem scrie comentarii n interiorul altor comentarii. 2. Nu putem introduce comentarii n interiorul literalilor caracter sau sir de caractere. 3. Secventele /* si */ pot sa apara pe o linie dupa secventa // dar si pierd semnificatia. La fel se ntampla cu secventa // n comentarii care incep cu /* sau */. 2.2. Tipuri de date n Java 2.2.1. Tipuri de date primitive Unicode: codificarea i evitarea caracterelor. Java este unul dintre puinele limbaje de programare care ncalc un principiu care prea statuat de facto: caracterele Java i stringurile sunt codificate n codul Unicode pe 16 bii. Asta face ca setul de caractere s fie potrivit i pentru alte caractere, neexistente n alfabetul englez. Setul Unicode este efectiv un supraset al lui ASCII, deci textele ASCII au aceeai reprezentare, dar fiecare octet ASCII este completat cu cte un octet semnificativ cu valoarea 0 (neinterpretat de mainile ce vd doar ASCII). Studenii care doresc s cunoasc ntregul set de caractere Unicode, pot consulta http://unicode.org. Specificarea caracterelor ASCII tipribile se face ca i n C. Mecanismul de evitare a caracterelor din C se pstreaz i se mai introduce un mod suplimentar de specificare, astfel: \uxxxx \xxx \n \r \t \f \b \ \ \\ unde xxxx sunt patru cifre hexa; unde xxx sunt trei cifre octale. sunt cele cunoscute din C.

Tipul char se reprezint pe doi octei n Unicode i respect conveniile de conversie la ntregi din C. Stringurile se scriu ca i n C (ntre ghilimele). Spre deosebire de C, n Java nu exist continuare (linie terminat cu \ n C sau C++) pentru stringurile lungi. n schimb, operatorul + Java este extins i pentru concatenarea de stringuri. Deci irurile lungi se scriu folosindu-se operatorul + de concatenare. Exist tipul de date String.

Tipul Boolean este nou introdus n Java (nu este n C). n schimb dispare convenia C cu 0 avnd valoarea false i diferit de 0 avnd valoarea true. Un tip Boolean nu este un ntreg i nici nu poate fi convertit la acesta. Tipurile ntregi. La tipurile ntregi, mprirea cu 0 activeaz excepia numit ArithmeticException. Tipurile flotante se pot specifica plasnd la sfritul scrierii numrului litera f sau F pentru simpl precizie, respectiv cu d sau D pentru dubl precizie. Pentru aceste tipuri de date exist constantele predefinite: POSITIVE_INFINITY, NEGATIVE_INFINITY, NaN (Not a Number). La tipurile flotante depirile nu se semnaleaz, ci rezultatul poate fi unul dintre constantele de mai sus. Exist, de asemenea, zero negativ i zero pozitiv. Tabelul urmtor descrie tipurile de date primitive.
Tip Boolean Char Byte Short Int Long Float Double Coninut true sau false caracter Unicode ntreg cu semn ntreg cu semn ntreg cu semn ntreg cu semn standard IEEE simpl precizie standard IEEE dubl precizie Valoare implicit false \u0000 0 0 0 0 0.0 0.0 Lungime 1 bit 16 bii 8 bii 16 bii 32 bii 64 bii 32 bii 64 bii

2.2.2. Tipul referin obiect Tipurile de date neprimitive sunt obiecte i tablouri. Ele sunt numite n Java tipuri referin, deoarece sunt manevrate prin adres: compilatorul pune adresa unui obiect sau tablou ntr-o variabil i aa este transmis ctre metode. Prin contrast, tipurile primitive sunt manevrate prin valoare. ntr-o manier simplificat, un obiect este similar unei variabile de tip structur din C. Din punct de vedere semantic, obiectele Java coincid cu obiectele C++. n seciunea urmtoare vom detalia partea sintactic privitoare la obiecte i clase. Acum tratm doar principalele operaii posibile asupra obiectelor Java. n limbajele C i C++, obiectele referin sunt tratate prin operatorii * & ->. Java nu conine aceti operatori!. Deoarece obiectele sunt transmise prin referin, este posibil ca dou variabile diferite s se refere la acelai obiect. De exemplu:
Button p, q; p = new Button(); q = p; p.setLabel(Ok); String s = q.getLabel(); Aici, s va avea valoarea Ok.

int i = 3; int j = i; i = 2; Aici, i este 2 i j este 3 (deci nu e valabil acelai lucru la datele primitive!).

Copierea obiectelor i compararea lor. Din cauza referinei, atribuirea ntre obiecte nu face copiere. De exemplu,

Button a = new Button(Ok); Button b = new Button(Cancel); a = b; Aici, a i b puncteaz ambele la butonul Cancel, iar butonul Ok este pierdut. Pentru a se face o atribuire veritabil, trebuie executat o operaie de copiere a componentelor de la surs la destinaie. Majoritatea tipurilor de date standard au definit o metod clone(), care execut efectiv copierea, component cu component. O astfel de atribuire funcioneaz ca n exemplul urmtor, n care variabila c se va referi la un duplicat al obiectului b: Vector b = new Vector; c = b.clone(); Pentru copierea de tablouri, se folosete metoda: System.arraycopy(sursa,inceput,destinatie,inceput,lungime). Obiectele nu pot fi comparate nici mcar cu egalitate. Utilizatorul i poate defini proceduri proprii de comparare. Unele clase au, n acest scop, o metod numit equals(). Din raiuni de portabilitate, de independen de platform i de siguran, nu exist pointeri! Deci, nu se pune problema referirii, dereferirii, conversiei referinelor la tablouri n ntreg etc. Constanta null indic inexistena unui obiect sau a unui tablou. Garbage collection. Obiectele Java i ocup memoria necesar n mod dinamic, n faza de execuie. Alocarea de memorie este fcut automat, deci lipsesc apelurile similare lui malloc. De asemenea, nu se face eliberarea explicit a spaiului ocupat, deci nu exist apeluri similare lui free din C i C++. Distrugerea obiectelor se face automat, printr-un mecanism clasic de garbage collection . Eliberarea spaiului ocupat de un obiect se face, fr tirea utilizatorului, dup ce obiectul nu mai este vizibil i nici n via. 2.2.3. Tipul referin tablou Principiile enunate la tipul referin obiect sunt valabile i la tipul referin tablou. Astfel: tablourile sunt manevrate prin referin; tablourile sunt create dinamic, prin new; dup ce nu se mai folosesc, sunt eliberate prin mecanismul garbage collection. Crearea unui tablou, se poate face n dou moduri: 1) specificarea unei dimensiuni maxime, ca mai jos: byte octet_buffer[ ] = new byte[1024]; Button butoane[ ] = new Button[10];

2)

prin iniializator static:

int tabel[ ] = {1,2,4,8,16,32,64,128}; Un tablou multidimensional se implementeaz ca i un tablou de tablouri. Este posibil, eventual, ca ultimii indici s nu aib limitele precizate: byte T2[ ][ ] = new byte[256][16]; int T3[ ][ ][ ] = new int[10][ ] [ ]; String multi[ ][ ][ ] = new String[5][3][ ]; Tablourile multidimensionale se pot iniializa i static, la fel ca i n C: String S[][] = { { , , }, { , , } } De regul, tablourile multidimensionale nu sunt neaprat rectangulare. Iat, de exemplu, construcia ctorva tablouri triunghiulare i nu numai: int T[][] = { {1, 2}, {3, 4, 5}, {6, 7, 8, 9}}; short triunghi[ ][ ] = new short[10][ ]; for (int i=0; i < triunghi.length; i++) { triunghi[i] = new short[i+1]; for (int j=0; j<i+1; j++) triunghi[i][j] = (short) i * j; } Accesul la tablouri i la elementele de tablou se face ca i n C. n Java se face automat controlul de indici, generndu-se la depire IndexOutOfBoundsException. Tipul de date String. n Java, un String este privit ca un tablou de caractere reprezentate n Unicode. Deci stringurile Java NU sunt terminate prin octet de valoare 0! Operaiile posibile sunt descrise n clasele java.lang.String i java.lang.StringBuffer. Precizm aici faptul c pentru stringuri exist operatorul de concatenare +. Printre cele mai importante metode din clasa String amintim (i numele sugereaz la ce se refer): length(), charAt(), compareTo(), indexOf(), lastIndexOf(), substring(). 2.3. Vectori 2.3.1. Crearea unui vector Crearea unui vector presupune realizarea urmatoarelor etape: Declararea vectorului - Pentru a putea utiliza un vector trebuie, nainte de toate, sa-l declaram. Acest lucru se face prin expresii de forma: Tip[] numeVector; sau

Tip numeVector[]; ca n exemplele de mai jos: int[] intregi; String adrese[]; Instantierea Declararea unui vector nu implica si alocarea memoriei necesare pentru retinerea elementelor. Operatiunea de alocare a memoriei, numita si instantierea vectorului, se realizeaza ntotdeauna prin intermediul operatorului new. Instantierea unui vector se va face printr-o expresie de genul: numeVector = new Tip[nrElemente]; unde nrElemente reprezinta numarul maxim de elemente pe care le poate avea vectorul. n urma instantierii vor fi alocati: nrElemente*dimensiune(Tip) octeti necesari memorarii elementelor din vector, unde prin dimensiune(Tip) am notat numarul de octeti pe care se reprezinta tipul respectiv. v = new int[10]; //aloca spatiu pentru 10 intregi: 40 octeti c = new char[10]; //aloca spatiu pentru 10 caractere: 20 octeti Declararea si instantierea unui vector pot fi facute simultan astfel: Tip[] numeVector = new Tip[nrElemente]; Initializarea (optional) Dupa declararea unui vector, acesta poate fi initializat, adica elementele sale pot primi niste valori initiale, evident daca este cazul pentru asa ceva. n acest caz instantierea nu mai trebuie facuta explicit, alocarea memoriei facandu-se automat n functie de numarul de elemente cu care se initializeaza vectorul. String culori[] = {"Rosu", "Galben", "Verde"}; int[] factorial = {1, 1, 2, 6, 24, 120}; Primul indice al unui vector este 0, deci pozitiile unui vector cu n elemente vor fi cuprinse ntre 0 si n-1. Nu sunt permise constructii de genul Tip numeVector[nrElemente], alocarea memoriei facandu-se doar prin intermediul operatorului new. int v[10]; //ilegal int v[] = new int[10]; //corect 2.3.2 Tablouri multidimensionale

n Java tablourile multidimensionale sunt de fapt vectori de vectori. De exemplu, crearea si instantierea unei matrici vor fi realizate astfel: Tip matrice[][] = new Tip[nrLinii][nrColoane]; matrice[i] este linia i a matricii si reprezinta un vector cu nrColoane elemente iar matrice[i][j] este elementul de pe linia i si coloana j. 2.3.3 Dimensiunea unui vector Cu ajutorul variabilei length se poate afla numarul de elemente al unui vector. int []a = new int[5]; // a.length are valoarea 5 int m[][] = new int[5][10]; // m[0].length are valoarea 10 Pentru a ntelege modalitatea de folosire a lui length trebuie mentionat ca fiecare vector este de fapt o instanta a unei clase iar length este o variabila publica a acelei clase, n care este retinut numarul maxim de elemente al vectorului. 2.3.4 Copierea vectorilor Copierea elementelor unui vector a ntr-un alt vector b se poate face, fie element cu element, fie cu ajutorul metodei System.arraycopy, ca n exemplele de mai jos. Dupa cum vom vedea, o atribuire de genul b = a are alta semnificatie decat copierea elementelor lui a n b si nu poate fi folosita n acest scop. int a[] = {1, 2, 3, 4}; int b[] = new int[4]; // Varianta 1 for(int i=0; i<a.length; i++) b[i] = a[i]; // Varianta 2 System.arraycopy(a, 0, b, 0, a.length); // Nu are efectul dorit b = a; 2.3.5 Sortarea vectorilor - clasa Arrays n Java s-a pus un accent deosebit pe implementarea unor structuri de date i algoritmi care sa simplifice proceseul de crearea a unui algoritm, programatorul trebuind sa se concentreze pe aspectele specifice problemei abordate. Clasa java.util.Arrays ofera diverse metode foarte utile n lucrul cu vectori cum ar fi:

sort - sorteaza ascendent un vector, folosind un algoritm de tip Quick-Sort performant, de complexitate O(n log(n)). int v[]={3, 1, 4, 2}; java.util.Arrays.sort(v); // Sorteaza vectorul v // Acesta va deveni {1, 2, 3, 4} binarySearch - cautarea binara a unei anumite valori ntr-un vector sortat; equals - testarea egalitatii valorilor a doi vectori (au aceleai numar de elemente si pentru fiecare indice valorile corespunzatoare din cei doi vectori sunt egale) fill - atribuie fiecarui element din vector o valoare specificata. 2.3.6 Vectori cu dimensiune variabila si eterogeni Implementari ale vectorilor cu numar variabil de elemente sunt oferite de clase specializate cum ar fi Vector sau ArrayList din pachetul java.util. Astfel de obiecte descriu vectori eterogeni, ale caror elemente au tipul Object. 2.4. Siruri de caractere n Java, un sir de caractere poate fi reprezentat printr-un vector format din elemente de tip char, un obiect de tip String sau un obiect de tip StringBuffer. Daca un sir de caractere este constant (nu se doreste schimbarea continutului sau pe parcursul executiei programului) atunci el va fi declarat de tipul String, altfel va fi declarat de tip StringBuffer. Diferenta principala ntre aceste clase este ca StringBuffer pune la dispozitie metode pentru modificarea continutului sirului, cum ar fi: append, insert, delete, reverse. Uzual, cea mai folosita modalitate de a lucra cu siruri este prin intermediul clasei String, care are si unele particularitati fata de restul claselor menite sa simplifice cat mai mult folosirea sirurilor de caractere. Clasa StringBuffer va fi utilizata predominant n aplicatii dedicate procesarii textelor cum ar fi editoarele de texte. Exemple echivalente de declarare a unui sir: String s = "abc"; String s = new String("abc"); char data[] = {a, b, c}; String s = new String(data); Observati prima varianta de declarare a sirului s din exemplul de mai sus - de altfel, cea mai folosita - care prezinta o particularitate a clasei String fata de restul claselor Java referitoare la instantierea obiectelor sale. Concatenarea sirurilor de caractere se face prin intermediul operatorului + sau, n cazul sirurilor de tip StringBuffer, folosind metoda append. String s1 = "abc" + "xyz";

10

String s2 = "123"; String s3 = s1 + s2; n Java, operatorul de concatenare + este extrem de flexibil, n sensul ca permite concatenarea sirurilor cu obiecte de orice tip care au o reprezentare de tip sir de caractere. Mai jos, sunt cateva exemple: System.out.print("Vectorul v are" + v.length + " elemente"); String x = "a" + 1 + "b" Pentru a lamuri putin lucrurile, ceea ce executa compilatorul atunci cand ntalneste o secventa de genul String x = "a" + 1 + "b" este: String x = new StringBuffer().append("a").append(1).append("b").toString() Atentie nsa la ordinea de efectuare a operatiilor. Sirul s=1+2+"a"+1+2 va avea valoarea "3a12", primul + fiind operatorul matematic de adunare iar al doilea +, cel de concatenare a sirurilor. 2.5. Variabile Variabilele reprezint un loc unde poate fi pstrat informaia ntr-un program aflat n execuie . Valoarea poate fi modificat oricnd n program de aici i numele . Pentru a crea o variabil trebuie s-i dai un nume i s stabilii ce tip de informaie va stoca . De asemenea , n momentul crerii se poate atribui i o valoare iniial variabilei . Exist trei tipuri de variabile n Java : variabile de instan , variabile de clas i variabile locale . Variabilele de instan , aa cum s-a mai spus sunt folosite pentru a defini atributele unui obiect . Variabilele de clas definesc atributele unei ntregi clase de obiecte i se aplic tuturor instanelor acesteia . Variabilele locale sunt folosite n interiorul definiiilor metodelor , sau chiar al blocurilor de instruciuni mai mici din cadrul unei metode . Ele pot fi folosite doar atunci cnd metoda sau blocul este executat de interpretorul Java , dup care i nceteaz existena . Spre deosebire de alte limbaje , Java nu are variabile globale (care pot fi folosite n orice parte a unui program ) . Variabilele de clas i de instan sunt folosite pentru a comunica informaii despre un obiect sau altul i pot nlocui nevoia de variabile globale . 2.5.1. Variabile locale 2.5.1.1. Crearea variabilelor nainte de a putea folosi o variabil ntr-un program Java , trebuie s o declarai prin indicarea numelui i a tipului de informaie pe care l va stoca . Mai nti se indic tipul de informaie , urmat de numele variabilei . De exemplu :
int scorMaxim;

11

String numeutilizator;

Variabilele locale pot fi declarate n orice loc n interiorul unei metode , la fel ca oricare alt instruciune Java , ns trebuie declarate nainte de a fi folosite . n mod normal , declararea variabilelor urmeaz imediat dup instruciunea care definete metoda . Dac dorii s creai mai multe variabile de acelai tip , le putei declara pe toate n aceeai instruciune , separate prin virgul ca i n C/C++ . Variabilelor li se poate atribui o valoare atunci cnd sunt create , folosind semnul egal (=) , urmat de o valoare . Variabilelor locale trebuie s li se atribuie valori nainte de a fi folosite n program , altfel acesta nu se va compila . Din acest motiv este bine s se atribuie valori iniiale tuturor variabilelor locale . Definiiile variabilelor de instan i de clas primesc o valoare iniial n funcie de tipul informaiei pe care o stocheaz : Variabilele numerice : 0 Caracterele : \0 Variabilele booleene : false Obiectele : null 2.5.1.2. Denumirea variabilelor Numele variabilelor Java trebuie s nceap cu o liter , cu caracterul underscore (_) sau dolar ($) ; ele nu pot nceap cu o cifr . Dup primul caracter , numele variabilelor pot conine orice combinaie de cifre i litere . Atunci cnd denumii o variabil i o folosii n program , este bine s retinei c Java este case sensitive i c denumirile trebuie s fie identice peste tot . Din aceast cauz , poate avea dou variabile diferite una denumit X i alta x sau , dac avei o variabil cu numele numr , atunci nu trebuie s o referii n alt parte sub numele Numr sau NUMR . 2.5.1.3. Atribuirea de valori variabilelor Dup ce variabila a fost declarat , i se poate da o valoare folosind operatorul de atribuire semnul egal (=) . Urmtoarele exemple sunt instruciuni de atribuire :
idCod=6786573; Mancat=false;

2.5.2.Variabile de instan Variabilele de clas i de instan se comport n acelai fel ca variabilele locale . Trebuie numai s v referii la ele ntr-o modalitate uor diferit fa de celelalte variabile din codul dumneavoastr . Pentru a obine valoarea unei variabile de instan , se folosete notaia cu punct . n aceast notaie , variabila de clas sau de instan este format din dou pri :obiectul , n partea stng a punctului , i variabila , n partea dreapt a punctului . Notaia cu punct reprezint o modalitate de a referi variabilele i metodele unui obiect folosind operatorul punct (.) .

12

De exemplu , dac avei un obiect atribuit variabilei cerc i acel obiect posed o variabil denumit raza , v vei referi la acea variabil n felul urmtor : cerc.raza; Aceast form de accesare a variabilelor este o expresie (deoarece ntoarce o valoare) n care de ambele pri ale punctului se afl tot expresii . Acest lucru nseamn c putei insera mai multe variabile de instan . Dac variabila de instan raza refer ea nsi un obiect care posed propria variabil de instan denumit unitatemasura , putei s v referii la aceasta n felul urmtor : cerc.raza.unitatemasura; Expresiile cu punct sunt evaluate de la stnga la dreapta , aa nct se va ncepe cu variabila din cerc , raza , care refer un alt obiect cu variabila unitatemasura . n final vei obine valoarea variabilei unitatemasura . Atribuirea unei valori acestei variabile se face la fel de uor se mai adaug un operator de atribuire n partea dreapt a expresiei : cerc.raza.unitatemasura=cm; 2.5.3. Variabile de clas Variabilele de clas , aa cum s-a mai spus , sunt variabile care sunt definite i memorate chiar n clas . Valorile lor se aplic clasei i tuturor instanelor sale . n cazul variabilelor de instan , fiecare nou instan a clasei primea o copie a variabilelor de instan definite n clas . Fiecare instan poate apoi modifica valorile acestor variabile de instan , fr a afecta alte instane . n cazul variabilelor de clas , exist o singur copie a variabilei . Modificarea valorii variabilei este vizibil n toate instanele clasei . Variabilele de clas se definesc prin inserarea cuvntului cheie static naintea numelui variabilei.

13

Curs 3
2.6. Instruciuni Instruciunile n Java sunt grupate n blocuri . nceputul i sfritul unui bloc sunt notate cu acolade o acolad deschis ({) pentru nceput i o acolad nchis (}) pentru sfrit . Ai folosit deja blocuri n programele prezentate n urmtoarele scopuri : pentru a memora variabilele i metodele dintr-o definiie de clas pentru a defini instruciunile care aparin unei metode Blocurile mai sunt denumite i instruciuni bloc , deoarece un bloc poate fi folosit oriunde poate fi folosit o instruciune simpl . Fiecare instruciune din cadrul blocului este executat de sus n jos. Blocurile pot fi plasate i n cadrul altor blocuri, aa cum procedai atunci cnd introducei o metod n cadrul unei definiii de clas. Un lucru important de reinut referitor la blocuri este acela c se creeaz un domeniu de vizibilitate (scope) pentru variabilele locale create n cadrul blocului. Domeniul de vizibilitate este acea parte a programului n care o variabil exist i poate fi folosit. Dac programul prsete domeniul de vizibilitate al unei variabile, aceasta nu mai exist i ncercarea de a o accesa va da natere unei erori. Domeniul de vizibilitate al unei variabile este blocul n care a fost creat. Atunci cnd creai i folosii variabile locale n cadrul unui bloc, aceste variabile i nceteaz existena dup ce blocul i termin execuia. De exemplu , metoda testBloc() conine un bloc :
void testBloc() { int x=10; { //nceputul blocului int y=40; y=y+x; } // sfarsitul blocului }

Exist dou variabile definite n cadrul acestei metode : x i y. Domeniul de vizibilitate al variabilei y este blocul n care se afl ; ea poate fi folosit doar n cadrul acestui bloc. Dac ai ncerca s o folosii oriunde n alt parte a metodei testBloc(), vei obine o eroare. Variabila x a fost creat n interiorul metodei, ns n afara blocului interior, deci poate fi folosit n oricare alt parte a metodei. Putei modifica valoarea lui x oriunde n cadrul metodei ; acest lucru este corect. De obicei , instruciunile bloc nu sunt folosite singure n cadrul unei definiii de metod, ca n exemplul anterior. Ele pot fi folosite n cadrul definiiilor de clase i metode, precum i n structuri de ciclare i de condiionare, despre care vei nva n continuare . 2.6.1. Instruciuni condiionate O instruciune condiionat reprezint o instruciune executat doar n cazul ndeplinirii unei anumite condiii. 2.6.1.1. Instruciunea if

Cea mai utilizat instruciune condiionat este cea introdus prin cuvntul cheie if (dac). Aceasta folosete o expresie boolean pentru a decide dac o instruciune va fi sau nu executat. Dac expresia ntoarce valoarea true, instruciunea va fi executat. Un exemplu simplu ar fi un program care afieaz mesajul Esti major cu o singur condiie : dac variabila vrsta este mai mare sau egal cu 18 :
if (varsta >= 18) System.out.println(Esti major);

Dac dorii s se ntmple altceva atunci cnd expresia if ntoarce valoarea false, folosii cuvntul cheie opional else (altfel). Urmtorul exemplu folosete att if ct i else :
if (varsta >= 18) System.out.println(Esti major); else System.out.println(Esti minor);

Expresia if execut instruciuni diferite n funcie de rezultatul unei singure testri booleene. Diferena dintre instruciunile condiionale if din Java i cele din C i C++ este aceea c n Java testul trebuie s returneze o variabil boolean (true sau false). n C/C++, testul returneaza un ntreg . Folosind if, n codul care se execut dup test putei include o singur instruciune. Totui, n Java un bloc poate fi folosit oriunde poate fi folosit o instruciune simpl. Dac dorii s facei mai multe lucruri ca rezultat al unei instruciuni if, putei ncadra instruciunile corespunztoare ntre acolade. Privii acest extras de cod :
if (atitudine==furios) { System.out.println(Monstrul este furios); System.out.println(V-ati scris testamentul?); } else { System.out.println(Monstrul este in toane bune); if (flamand) System.out.println(Totusi este inca flamand); else System.out.println(Pleaca.); }

Acest exemplu folosete testul (atitudine==furios) pentru a determina dac s se afieze c monstrul este furios sau linitit . Dac este linitit , testul (flamand) este folosit pentru a determina dac monstrul nu este cumva flmnd presupunnd c un monstru flmnd trebuie evitat chiar dac este linitit. Condiionalul if (flamand)este o alt modalitate de a spune if(flamand==true) . Pentru testele booleene de acest tip, eliminarea ultimei pri a expresiei reprezint o prescurtare destul de des folosit. 2.6.1.2. Operatorul condiional Alt alternativ este folosirea ntr-o instruciune condiionat , n locul cuvintelor cheie if i else , a operatorului condiional, denumit uneori i operator ternar. Operatorul condiional este denumit operator ternar deoarece are trei termeni. Operatorul condiional este o expresie, ceea ce nseamn c ntoarce o valoare, spre deosebire de mai generalul if, care are ca rezultat doar executarea unei instruciuni sau a

unui bloc. Operatorul condiional este mai util pentru instruciuni condiionale scurte sau simple, care arat cam aa :
Test ? rezultat_adevarat : rezultat_fals;

Test este o expresie care ntoarce true sau false, la fel ca testul din instruciunea if. Dac testul este adevrat (true), operatorul condiional ntoarce valoarea rezultat_adevarat. Dac testul este fals (false), operatorul condiional ntoarce valoarea rezultat_fals. De exemplu, urmtorul condiional testeaz valorile scorulMeu i scorulTau, ntorcnd cea mai mare dintre cel dou valori, care este atribuit variabilei celMaiBunScor :
int celMaiBunScor = scorulMeu>scorulTau ? scorulMeu : scorulTau;

Folosirea operatorului condiional este echivalentul urmtorului cod ifelse :


int celMaiBunScor ; if(scorulMeu>scorulTau) CelMaiBunScor=scorulMeu; else CelMaiBunScor=scorulTau;

Operatorul condiional are o preceden foarte sczut este, de obicei, evaluat dup toate subexpresiile sale. Singurii operatori care au o preceden mai mic sunt cei de atribuire. 2.6.1.3. Instruciunea switch O operaie des ntlnit n programarea n orice limbaj este compararea unei variabile cu o anumit valoare , apoi cu o alt valoare , n caz c nu se potrivete cu prima valoare i aa mai departe . Folosirea instruciunilor if n acest caz este o imbricare , deoarece fiecare instruciune else contine o alt instruciune if , pn cnd se fac toate testele posibile . Un mecanism prescurtat pentru aceste instruciuni if imbricate , care poate fi folosit n unele limbaje de programare , este gruparea testelor i aciunilor ntr-o singur instruciune. n Java , putei grupa aciunile folosind instruciunea switch , care se comport la fel ca n C . Un exemplu de folosire a instruciunii switch este :
switch(nota) { case 10 : System.out.println(Foarte bine nota 10!); break; case 8 : System.out.println(Bine nota 8!); break; case 5 : System.out.println(Ati primit nota 5!); break; default : System.out.println(4 incercati sa invatati!); }

Instruciunea switch este bazat pe un test ; n exemplul anterior se testeaz variabila nota . Variabila testat , care poate fi de orice tip primitiv (byte, char, short sau int) , este comparat pe rnd cu fiecare dintre valorile case . Dac se gsete o potrivire , se execut instruciunea sau instruciunile specificate dup test . Dac nu se gsete nici o potrivire , se execut instruciunea sau instruciunile default (predefinite) . Instruciunea default este opional ; dac este omis i nu se gsete nici o potrivire n nici o instruciune case , instruciunea condiional switch se ncheie fr a executa nimic . Implementarea Java a instruciunii switch este limitat testele i valorile pot fi doar tipuri primitive simple care pot fi convertite n int . ntr-o asemenea instruciune nu se pot folosi tipuri primitive de dimensiuni mari , cum ar fi large sau float , iruri sau alte obiecte i nici nu se pot testa alte relaii n afar de cea de egalitate . Aceste restricii limiteaz folosirea switch la cazurile mai simple . n schimb , instruciunile if imbricate pot fi folosite pentru orice tip de testare . Exist dou lucruri la care trebuie s fii ateni : Primul este c dup fiecare instruciune case putei include o singur instruciune sau mai multe . Spre deosebire de if , nu trebuie s ncadrai instruciunile ntre acolade . Al doilea lucru de reinut sunt instruciunile break coninute de fiecare seciune case . Dac nu ar exista instruciunea break , chiar i dup gsirea unei potriviri ntr-o seciune case s-ar executa mai departe instruciunile pn s-ar ntlni o instruciune break sau pn la sfritul instruciunii switch . n unele cazuri , s-ar putea s fie exact ce dorii . Totui n majoritatea cazurilor trebuie s includei instruciuni break pentru a v asigura c va fi executat doar codul corespunztor . Instruciunea break ntrerupe execuia n punctul curent i face un salt la codul aflat dincolo de urmtoarea acolad nchis (}) . Avantajul nefolosirii break ntr-o instruciune switch apare atunci cnd se dorete executarea acelorai instruciuni pentru mai multe valori . 2.6.2. Instruciuni repetitive Ciclurile for , while i do..while sunt identice cu cele din C i C++ , cu excepia faptului c testul pentru while i dowhile trebuie s foloseasc o condiie boolean . 2.6.2.1. Cicluri for Ciclurile for repet o instruciune de un numr specificat de ori ,pn n momentul cnd se ntlnete o condiie . Chiar dac sunt folosite de obicei pentru simple iteraii , n care o instruciune este repetat de un anumit numr de ori , ciclurile for pot fi folosite pentru aproape orice tip de operaii repetitive . Ciclul for are n Java sintaxa :
for (initializare; test; incrementare) { Instructiune; }

nceputul ciclului for conine trei pri :

initializare este o expresie care iniializeaz pornirea ciclului . Dac folosii o variabil index a ciclului , aceast expresie o poate declara i iniializa , de exemplu , int i=0.Variabilele pe care le declarai n aceast parte a ciclului for sunt locale ciclului n sine ; ele i nceteaz existena dup terminarea execuiei ciclului . n aceast seciune putei iniializa mai multe variabile , separnd fiecare expresie printr-o virgul . Instruciunea int i=0,int j=10 din aceast seciune , declar variabilele i i j , care vor fi ambele locale ciclului. test este testul care se face dup fiecare parcurgere a ciclului . Testul trebuie s fie o expresie boolean sau o funcie care returneaz o valoare boolean , cum ar fi i<10 . Dac testul este true , ciclul i continu execuia . O dat ntoars valoarea false , ciclul i nceteaz execuia . incrementare este o expresie sau un apel de funcie . De obicei , incrementarea este folosit pentru a modifica valoarea indexului ciclului , pentru a aduce starea ciclului mai aproape de final . Asemntor seciunii initializare , putei specifica aici mai multe expresii , separate prin virgule . Partea denumit instructiune a ciclului for reprezint instruciunea care este executat la fiecare iteraie a ciclului . Ca i n cazul instruciunii condiionate if , putei specifica o instruciune simpl sau un bloc de instruciuni ; n exemplul anterior s-a folosit un bloc pentru c situaia este mai des ntlnit . Urmtorul exemplu este un ciclu for care atribuie tuturor poziiilor unui tablou String valoarea Dl. :
String [] formulaSalut = new String[10]; int i; //variabila index a ciclului for (i=0; i<formulaSalut.length; i++)// length da dimensiunea tabloului formulaSalut[i]=Dl.;

n acest exemplu , variabila i servete drept index al ciclului numr de cte ori se execut acesta . nainte de fiecare parcurgere a ciclului , valoarea index este comparat cu valoarea formulaSalut.length , deci cu numrul de elemente din tabloul formulaSalut . Atunci cnd indexul este mai mare sau egal cu valoarea formulaSalut.length , ciclul se termin . Elementul final al instruciunii for este expresia i++ . Aceasta face ca indexul irului s fie incrementat cu 1 la fiecare parcurgere a ciclului . Fr aceast instruciune , ciclul nu s-ar termina niciodat . Instruciunea din cadrul ciclului atribuie unui element al tabloului formulaSalut valoarea Dl. . Indexul ciclului este folosit pentru a determina poziia elementului din tablou care este modificat . Orice parte a ciclului for poate fi reprezentat printr-o instruciune vid , deci putei introduce doar punctul i virgula corespunztoare seciunii respective a ciclului , care va fi ignorat . Reinei c dac totui folosii o instruciune vid n cadrul ciclului for , va trebui s facei iniializarea sau incrementarea varibilelor ciclului sau a indexurilor acestuia n alt parte a programului . De asemenea , putei folosi o instruciune vid n corpul ciclului for dac aciunile pe care dorii s le executai se realizeaz n prima parte a acestuia . De exemplu ,urmtorul ciclu for gsete primul numr prim mai mare ca 4000 . (Este apelat o metod

denumit nePrim() , care se presupune c folosete un algoritm pentru stabilirea acestui lucru .)
for (i=4001; neprim(i);i+=2) ;

O greeal frecvent ntlnit n ciclurile for este introducerea semnului punct i virgul (;) la sfritul liniei care conine instruciunea for :
for (i=0;i<10;i++); x=x*i; // aceasta linie nu face parte din ciclu!

n acest exemplu , primul semn punct i virgul ncheie ciclul fr a executa instruciunea x=x*i ca parte a sa . Linia x=x*i va fi executat o singur dat , deoarece se afl complet n afara ciclului . Avei grij s nu facei astfel de greeli n programele voastre Java . 2.6.2.2. Cicluri while Ciclul while este folosit pentru a repeta o instruciune att timp ct o anumit condiie este adevarat (true) . Ciclul while are n Java sintaxa: while (conditie) instructiune; conditie este o expresie boolean sau o funcie care returneaz o valoare boolean . Dac conditie este true , ciclul i continu execuia . O dat ntoars valoarea false , ciclul i nceteaz execuia . Partea denumit instructiune este la fel ca n cazul ciclului for . Iat un exemplu de folosire a unui ciclu while :
while (i<10) { x=x*i++; //corpul ciclului }

n exemplu precedent , condiia este i<10 . Chiar dac n exemplu s-au figurat acolade pentru a defini o instructiune bloc , ele nu sunt necesare deoarece ciclul conine o singur instruciune : x=x*i . Folosirea acoladelor nu creeaz nici o problem , n schimb , acoladele devin obligatorii dac mai trziu se mai adaug n ciclu o instruciune . 2.6.2.3. Cicluri dowhile Ciclul dowhile este foarte asemntor cu ciclul while , ns cu o diferen major : locul unde se face testarea condiiei n ciclu . Un ciclu while testeaz condiia nainte de ciclu , deci dac aceasta are valoarea false prima dat cnd este testat ,corpul ciclului nu se va executa niciodat . Un ciclu dowhile execut corpul unui ciclu cel puin o

dat nainte de a testa condiia , deci dac aceasta are valoarea false la prima testare , corpul ciclului a fost executat deja o dat . Ciclurile dowhile au n Java sintaxa :
do instructiune; while (conditie) ;

Corpul ciclului este executat o dat nainte de evaluarea condiiei ; deci dac testul o evalueaz ca true , ciclul continu . Dac valoarea este false , ciclul se termin . Retinei deci c , n cazul ciclurilor dowhile , corpul acestora se execut cel puin o dat . Un exemplu ar fi :
do { x=x*i++; }while(i<10);

2.6.2.4. Ieirea forat din cicluri n toate tipurile de cicluri , acestea i termin execuia cnd se ndeplinete condiia testat . Pot fi cazuri cnd apare ceva n execuie i dorii s iesii mai repede din el . Pentru aceasta pot fi folosite cuvintele cheie break i continue . Ai ntlnit deja instruciunea break , folosit ntr-un exemplu cu condiionalul switch ; break oprete execuia instruciunii switch , iar programul continu . Cuvntul cheie break , atunci cnd este folosit ntr-un ciclu , face acelai lucru nceteaz imediat execuia ciclului curent . Dac exist cicluri imbricate n cadrul altor cicluri , execuia continu cu urmtoarea iteraie a ciclului din exterior . Astfel , programul continu execuia urmatoarei instruciuni aflat dup ciclu . Un exemplu este un ciclu while care copiaz elementele dintr-un tablou de ntregi ntrun tablou de numere n virgul mobil pn cnd se ntlnete sfritul tabloului sau o valoare 1 . Se poate astfel testa ultima condiie n cadrul corpului ciclului while , dup care se folosete instruciunea break pentru a prsi ciclul : int index = 0; while (index < tablou1.length){ if (tablou1[index] == 1) break; tablou2[index] = (float) tablou1[index++]; } Cuvntul cheie continue ncepe ciclul de la o nou iteraie . Pentru ciclurile do i while aceasta nseamn c se ncepe din nou cu execuia corpului ciclului ; pentru ciclurile for , se evalueaz expresia de incrementare i apoi se execut blocul de instruciuni . Instruciunea continue este folositoare atunci cand dorii s tratai ntr-un anume fel elementele ntr-un ciclu . Folosind exemplul anterior , de copiere a unui tablou n altul , putei s testai dac valoarea elementului curent este egal cu 1 i s folosii continue pentru a rencepe ciclul dup fiecare 1 intlnit , aa nct tabloul rezultat s

nu conin niciodat unu . Retinei totui c , deoarece srii unele elemente din primul tablou , acum trebuie s pstrai dou valori index pentru cele dou tablouri : int index = 0; int index2 = 0; while (index++ <= tablou1.length){ if (tablou1[index] == 1) continue; tablou2[index2++] = (float) tablou1[index];} 2.6.2.5. Cicluri etichetate Instruciunea break i continue pot avea etichete opionale care s indice locul de unde se va continua execuia programului . Fr etichet , break sare n afara celui mai apropiat ciclu sau la urmtoarea instruciune aflat dup ciclu . Instruciunea continue sare la urmtoarea iteraie a ciclului care o conine . Cu ajutorul etichetelor , putei folosi break pentru a sri ntr-un punct aflat n afara unui ciclu imbricat sau continue pentru a sri ntr-un ciclu aflat n afara ciclului curent . Pentru a folosi un ciclu cu etichete , se introduce eticheta nainte de partea de nceput a ciclului , urmat de semnul dou puncte . Apoi , dup numele instruciunii break sau continue introducei numele etichetei , ca n exemplul urmtor : afara: for (int i=0;i<10;i++) { while (x<50) { if (i*x++ > 400) break afara; //ciclul interior } //ciclul exterior } n acest exemplu de cod , eticheta afara marcheaz ciclul exterior . n cadrul ciclurilor for i while , atunci cnd este ndeplinit o anumit condiie , instruciunea break cu etichet are ca rezultat terminarea ambelor bucle . Fr folosirea etichetei afara , instruciunea break ar fi terminat execuia ciclului interior i ar fi continuat execuia cu cel exterior . 2.7. Folosirea argumentelor de la linia de comanda 2.7.1 Transmiterea argumentelor O aplicatie Java poate primi oricate argumente de la linia de comanda n momentul lansarii ei. Aceste argumente sunt utile pentru a permite utilizatorului sa specifice diverse optiuni legate de functionarea aplicatiei sau sa furnizeze anumite date initiale programului. Programele care folosesc argumente de la linia de comanda nu sunt 100% pure Java, deoarece unele sisteme de operare, cum ar fi Mac OS, nu au n mod normal linie de comanda.

Argumentele de la linia de comanda sunt introduse la lansarea unei aplicatii, fiind specificate dupa numele aplicatiei si separate prin spatiu. De exemplu, sa presupunem ca aplicatia Sortare ordoneaza lexicografic (alfabetic) liniile unui fisier si primeste ca argument de intrare numele fisierului pe care sa l sorteze. Pentru a ordona fisierul "persoane.txt", aplicatia va fi lansata astfel: java Sortare persoane.txt Asadar, formatul general pentru lansarea unei aplicatii care primeste argumente de la linia de comanda este: java NumeAplicatie [arg0 arg1 . . . argn] In cazul n care sunt mai multe, argumentele trebuie separate prin spatii iar daca unul dintre argumente contine spatii, atunci el trebuie pus ntre ghilimele. Evident, o aplicatie poate sa nu primeasca nici un argument sau poate sa ignore argumentele primite de la linia de comanda. 2.7.2 Primirea argumentelor In momentul lansarii unei aplicatii interpretorul parcurge linia de comanda cu care a fost lansata aplicatia si, n cazul n care exista, transmite programului argumentele specificate sub forma unui vector de stringuri. Acesta este primit de aplicatie ca parametru al metodei main. Reamintim ca formatul metodei main din clasa principala este: public static void main (String args[]) Vectorul args primit ca parametru de metoda main va contine toate argumentele transmise programului de la linia de comanda. In cazul apelului java Sortare persoane.txt vectorul args va contine un singur element pe prima sa pozitie: args[0]="persoane.txt". Vectorul args este instantiat cu un numar de elemente egal cu numarul argumentelor primite de la linia de comanda. Asadar, pentru a afla numarul de argumente primite de program este suficient sa aflam dimensiunea vectorului args prin intermediul atributului length: public static void main (String args[]) { int numarArgumente = args.length ; } In cazul n care aplicatia presupune existenta unor argumente de la linia de comanda, nsa acestea nu au fost transmise programului la lansarea sa, vor aparea exceptii (erori) de tipul ArrayIndexOutOfBoundsException. Din acest motiv, este necesar sa testam daca programul a primit argumentele de la linia de comanda necesare pentru functionarea sa si, n caz contrar, sa afiseze un mesaj de avertizare sau sa foloseasca niste valori implicite, ca n exemplul de mai jos: public class Salut { public static void main (String args[]) { if (args.length == 0) { System.out.println("Numar insuficient de argumente!");

System.exit(-1); //termina aplicatia } String nume = args[0]; //exista sigur String prenume; if (args.length > 1) prenume = args[1]; else prenume = ""; //valoare implicita System.out.println("Salut " + nume + " " + prenume); } } (pachetul sal) Spre deosebire de limbajul C, vectorul primit de metoda main nu contine pe prima pozitie numele aplicatiei, ntrucat n Java numele aplicatiei este chiar numele clasei principale, adica a clasei n care se gaseste metoda main. 2.7.3 Argumente numerice Argumentele de la linia de comanda sunt primite sub forma unui vector de siruri (obiecte de tip String). In cazul n care unele dintre acestea reprezinta valori numerice ele vor trebui convertite din siruri n numere. Acest lucru se realizeaza cu metode de tipul parseTipNumeric aflate n clasa corespunzatoare tipului n care vrem sa facem conversia: Integer, Float, Double, etc. Sa consideram, de exemplu, ca aplicatia Power ridica un numar real la o putere ntreaga, argumentele fiind trimise de la linia de comanda sub forma: java Power "1.5" "2" //ridica 1.5 la puterea 2 Conversia celor doua argumente n numere se va face astfel: public class Power { public static void main(String args[]) { double numar = Double.parseDouble(args[0]); int putere = Integer.parseInt(args[1]); System.out.println("Rezultat=" + Math.pow(numar, putere)); } } (pachetul pow) Metodele de tipul parseTipNumeric pot produce exceptii (erori) de tipul NumberFormatException n cazul n care sirul primit ca parametru nu reprezinta un numar de tipul respectiv.

10

CURS 4

2.8. Obiecte si clase 2.8.1. Ciclul de viata al unui obiect 2.8.1.1 Crearea obiectelor In Java, ca n orice limbaj de programare orientat-obiect, crearea obiectelor se realizeaza prin instantierea unei clase si implica urmatoarele lucruri: Declararea Presupune specificarea tipului acelui obiect, cu alte cuvinte specificarea clasei acestuia (vom vedea ca tipul unui obiect poate fi si o interfata). NumeClasa numeObiect; Instantierea Se realizeaza prin intermediul operatorului new si are ca efect crearea efectiva a obiectului cu alocarea spatiului de memorie corespunzator. numeObiect = new NumeClasa(); Initializarea Se realizeaza prin intermediul constructorilor clasei respective. Initializarea este de fapt parte integranta a procesului de instantiere, n sensul ca imediat dupa alocarea memoriei ca efect al operatorului new este apelat constructorul specificat. Parantezele rotunde de dupa numele clasei indica faptul ca acolo este de fapt un apel la unul din constructorii clasei si nu simpla specificare a numelui clasei. Mai general, instantierea si initializarea apar sub forma: numeObiect = new NumeClasa([argumente constructor]); Sa consideram urmatorul exemplu, n care declaram si instantiem doua obiecte din clasa Rectangle, clasa ce descrie suprafete grafice rectangulare, definite de coordonatele coltului stanga sus (originea) si latimea, respectiv naltimea. Rectangle r1, r2; r1 = new Rectangle(); r2 = new Rectangle(0, 0, 100, 200); In primul caz Rectangle() este un apel catre constructorul clasei Rectangle care este responsabil cu initializarea obiectului cu valorile implicite. Dupa cum observam n al doilea caz, initializarea se poate face si cu anumiti parametri, cu conditia sa existe un constructor al clasei respective care sa accepte parametrii respectivi. Fiecare clasa are un set de constructori care se ocupa cu initializarea obiectelor nou create. De exemplu, clasa Rectangle are urmatorii constructori: public Rectangle() public Rectangle(int latime, int inaltime) public Rectangle(int x, int y, int latime, int inaltime) public Rectangle(Point origine) public Rectangle(Point origine, int latime, int inaltime) public Rectangle(Point origine, Dimension dimensiune) Declararea, instantierea si initializarea obiectului pot aparea pe aceeasi linie (cazul cel mai uzual):
1

Rectangle patrat = new Rectangle(0, 0, 100, 100); Obiecte anonime Este posibila si crearea unor obiecte anonime care servesc doar pentru initializarea altor obiecte, caz n care etapa de declarare a referintei obiectului nu mai este prezenta: Rectangle patrat = new Rectangle(new Point(0,0), new Dimension(100, 100)); Spatiul de memorie nu este pre-alocat Declararea unui obiect nu implica sub nici o forma alocarea de spatiu de memorie pentru acel obiect. Alocarea memoriei se face doar la apelul operatorului new. Rectangle patrat; patrat.x = 10; //Eroare - lipseste instantierea 2.8.1.2 Folosirea obiectelor Odata un obiect creat, el poate fi folosit n urmatoarele sensuri: aflarea unor informatii despre obiect, schimbarea starii sale sau executarea unor actiuni. Aceste lucruri se realizeaza prin aflarea sau schimbarea valorilor variabilelor sale, respectiv prin apelarea metodelor sale. Referirea valorii unei variabile se face prin obiect.variabila De exemplu clasa Rectangle are variabilele publice x, y, width, height, origin. Aflarea valorilor acestor variabile sau schimbarea lor se face prin constructii de genul: Rectangle patrat = new Rectangle(0, 0, 100, 200); System.out.println(patrat.width); //afiseaza 100 patrat.x = 10; patrat.y = 20; //schimba originea patrat.origin = new Point(10, 20); //schimba originea Accesul la variabilele unui obiect se face n conformitate cu drepturile de acces pe care le ofera variabilele respective celorlalte clase. Apelul unei metode se face prin obiect.metoda([parametri]). Rectangle patrat = new Rectangle(0, 0, 100, 200); patrat.setLocation(10, 20); //schimba originea patrat.setSize(200, 300); //schimba dimensiunea Se observa ca valorile variabilelor pot fi modificate indirect prin intermediul metodelor sale. Programarea orientata obiect descurajeaza folosirea directa a variabilelor unui obiect deoarece acesta poate fi adus n stari inconsistente (ireale). In schimb, pentru fiecare variabila care descrie starea obiectului trebuie sa existe metode care sa permita schimbarea/aflarea valorilor variabilelor sale. Acestea se numesc metode de accesare, sau metode setter - getter si au numele de forma setVariabila, respectiv getVariabila. patrat.width = -100; //stare inconsistenta patrat.setSize(-100, -200); //metoda setter //metoda setSize poate sa testeze daca noile valori sunt //corecte si sa valideze sau nu schimbarea lor

2.8.1.3. Distrugerea obiectelor Multe limbaje de programare impun ca programatorul sa tina evidenta obiectelor create si sa le distruga n mod explicit atunci cand nu mai este nevoie de ele, cu alte cuvinte sa administreze singur memoria ocupata de obiectele sale. Practica a demonstrat ca aceasta tehnica este una din principalele furnizoare de erori ce duc la functionarea defectuoasa a programelor. In Java programatorul nu mai are responsabilitatea distrugerii obiectelor sale ntrucat, n momentul rularii unui program, simultan cu interpretorul Java, ruleaza si un proces care se ocupa cu distrugerea obiectelor care nu mai sunt folosite. Acest proces pus la dispozitie de platforma Java de lucru se numeste garbage collector (colector de gunoi), prescurtat gc. Un obiect este eliminat din memorie de procesul de colectare atunci cand nu mai exista nici o referinta la acesta. Referintele (care sunt de fapt variabile) sunt distruse in doua moduri: natural, atunci cand variabila respectiva iese din domeniul sau de vizibilitate, de exemplu la terminarea metodei n care ea a fost declarata; explicit, daca atribuim variabilei respective valoarea null. Cum functioneaza colectorul de gunoaie ? Colectorul de gunoaie este un proces de prioritate scazuta care se executa periodic, scaneaza dinamic memoria ocupata de programul Java aflat n executie si marcheaza acele obiecte care au referinte directe sau indirecte. Dupa ce toate obiectele au fost parcurse, cele care au ramas nemarcate sunt eliminate automat din memorie. Apelul metodei gc din clasa System sugereaza masinii virtuale Java sa depuna eforturi n recuperarea memoriei ocupate de obiecte care nu mai sunt folosite, fara a forta nsa pornirea procesului. Finalizare Inainte ca un obiect sa fie eliminat din memorie, procesul gc da acelui obiect posibilitatea sa curete dupa el, apeland metoda de finalizare a obiectului respectiv. Uzual, n timpul finalizarii un obiect si inchide fisierele si socket-urile folosite, distruge referintele catre alte obiecte (pentru a usura sarcina colectorului de gunoaie), etc. Codul pentru finalizarea unui obiect trebuie scris ntr-o metoda speciala numita finalize a clasei ce descrie obiectul respectiv. (vezi Clasa Object) Observatie.Nu confundati metoda finalize din Java cu destructorii din C++. Metoda finalize nu are rolul de a distruge obiectul ci este apelata automat nainte de eliminarea obiectului respectiv din memorie. 2.8.2. Crearea claselor 2.8.2.1. Declararea claselor Clasele reprezinta o modalitate de a introduce noi tipuri de date ntr-o aplicatie Java, cealalta modalitate fiind prin intermediul interfetelor. Declararea unei clase respecta urmatorul format general: [public][abstract][final]class NumeClasa [extends NumeSuperclasa] [implements Interfata1 [, Interfata2 ... ]]

{ // Corpul clasei } Asadar, prima parte a declaratiei o ocupa modificatorii clasei. Acestia sunt: public Implicit, o clasa poate fi folosita doar de clasele aflate n acelasi pachet(librarie) cu clasa respectiva (daca nu se specifica un anume pachet, toate clasele din directorul curent sunt considerate a fi n acelasi pachet). O clasa declarata cu public poate fi folosita din orice alta clasa, indiferent de pachetul n care se gaseste. abstract Declara o clasa abstracta (sablon). O clasa abstracta nu poate fi instantiata, fiind folosita doar pentru a crea un model comun pentru o serie de subclase. final Declara ca respectiva clasa nu poate avea subclase. Declarare claselor finale are doua scopuri: securitate: unele metode pot astepta ca parametru un obiect al unei anumite clase si nu al unei subclase, dar tipul exact al unui obiect nu poate fi aflat cu exactitate decat n momentul executiei;n felul acesta nu s-ar mai putea realiza obiectivul limbajului Java ca un program care a trecut compilarea sa nu mai fie susceptibil de nici o eroare. programare n spririt orientat-obiect: O clasa perfecta nu trebuie sa mai aiba subclase. Dupa numele clasei putem specifica, daca este cazul, faptul ca respectiva clasa este subclasa a unei alte clase cu numele NumeSuperclasa sau/si ca implementeaza una sau mai multe interfete, ale caror nume trebuie separate prin virgula. 2.8.2.2 Extinderea claselor Spre deosebire de alte limbaje de programare orientate-obiect, Java permite doar mostenirea simpla, ceea ce neamna ca o clasa poate avea un singur parinte (superclasa). Evident, o clasa poate avea oricati mostenitori (subclase), de unde rezulta ca multimea tuturor claselor definite n Java poate fi vazuta ca un arbore, radacina acestuia fiind clasa Object. Asadar, Object este singura clasa care nu are parinte, fiind foarte importanta n modul de lucru cu obiecte si structuri de date n Java. Extinderea unei clase se realizeaza folosind cuvantul cheie extends: class B extends A {...} // A este superclasa clasei B // B este o subclasa a clasei A O subclasa mosteneste de la parintele sau toate variabilele si metodele care nu sunt private. 2.8.2.3. Corpul unei clase Corpul unei clase urmeaza imediat dupa declararea clasei si este cuprins ntre acolade. Continutul acestuia este format din:

Declararea si, eventual, initializarea variabilelor de instanta si de clasa (cunoscute mpreuna ca variabile membre). Declararea si implementarea constructorilor. Declararea si implementarea metodelor de instanta si de clasa (cunoscute mpreuna ca metode membre). Declararea unor clase imbricate (interne). Spre deosebire de C++, nu este permisa doar declararea metodei n corpul clasei, urmand ca implementarea sa fie facuta n afara ei. Implementarea metodelor unei clase trebuie sa se faca obligatoriu n corpul clasei. // C++ class A { void metoda1(); int metoda2() { // Implementare } } A::metoda1() { // Implementare } // Java class A { void metoda1(){ // Implementare } void metoda2(){ // Implementare } } Variabilele unei clase pot avea acelasi nume cu metodele clasei, care poate fi chiar numele clasei, fara a exista posibilitatea aparitiei vreunei ambiguitati din punctul de vedere al compilatorului. Acest lucru este nsa total nerecomandat daca ne gandim din perspectiva lizibilitatii (claritatii) codului, dovedind un stil ineficient de programare. class A { int A; void A() {}; // Corect pentru compilator // Nerecomandat ca stil de programare } Observatie. Variabilele si metodele nu pot avea ca nume un cuvant cheie Java. 2.8.2.4. Constructorii unei clase Constructorii unei clase sunt metode speciale care au acelasi nume cu cel al clasei, nu returneaza nici o valoare si sunt folositi pentru initializarea obiectelor acelei clase n momentul instantierii lor.

class NumeClasa { [modificatori] NumeClasa([argumente]) { // Constructor } } O clasa poate avea unul sau mai multi constructori care trebuie nsa sa difere prin lista de argumente primite. In felul acesta sunt permise diverse tipuri de initializari ale obiectelor la crearea lor, n functie de numarul parametrilor cu care este apelat constructorul. Sa consideram ca exemplu declararea unei clase care descrie notiunea de dreptunghi si trei posibili constructori pentru aceasta clasa. class Dreptunghi { double x, y, w, h; Dreptunghi(double x1, double y1, double w1, double h1) { // Cel mai general constructor x=x1; y=y1; w=w1; h=h1; System.out.println("Instantiere dreptunghi"); } Dreptunghi(double w1, double h1) { // Constructor cu doua argumente x=0; y=0; w=w1; h=h1; System.out.println("Instantiere dreptunghi"); } Dreptunghi() { // Constructor fara argumente x=0; y=0; w=0; h=0; System.out.println("Instantiere dreptunghi"); } } Constructorii sunt apelati automat la instantierea unui obiect. In cazul n care dorim sa apelam explicit constructorul unei clase folosim expresia this( argumente ) care apeleaza constructorul corespunzator (cu argumente) al clasei respective. Aceasta metoda este folosita atunci cand sunt implementati mai multi constructori pentru o clasa, pentru a nu repeta secventele de cod scrise deja la constructorii cu mai multe argumente (mai generali). Mai eficient, fara a repeta aceleasi secvente de cod n toti constructorii (cum ar fi afisarea mesajului Instantiere dreptunghi), clasa de mai sus poate fi rescrisa astfel: class Dreptunghi { double x, y, w, h; Dreptunghi(double x1, double y1, double w1, double h1) { // Implementam doar constructorul cel mai general x=x1; y=y1; w=w1; h=h1; System.out.println("Instantiere dreptunghi"); } Dreptunghi(double w1, double h1) { this(0, 0, w1, h1);

// Apelam constructorul cu 4 argumente } Dreptunghi() { this(0, 0); // Apelam constructorul cu 2 argumente } } Dintr-o subclasa putem apela explicit constructorii superclasei cu expresia super( argumente ) Sa presupunem ca dorim sa cream clasa Patrat, derivata din clasa Dreptunghi: class Patrat extends Dreptunghi { Patrat(double x, double y, double d) { super(x, y, d, d); // Apelam constructorul superclasei } } Apelul explicit al unui constructor nu poate aparea decat ntr-un alt constructor si trebuie sa fie prima instructiune din constructorul respectiv. Constructorul implicit Constructorii sunt apelati automat la instantierea unui obiect. In cazul n care scriem o clasa care nu are declarat nici un constructor, sistemul i creeaza automat un constructor implicit, care nu primeste nici un argument si care nu face nimic. Deci prezenta constructorilor n corpul unei clase nu este obligatorie. Daca nsa scriem un constructor pentru o clasa, care are mai mult de un argument, atunci constructorul implicit (fara nici un argument) nu va mai fi furnizat implicit de catre sistem. Sa consideram, ca exemplu, urmatoarele declaratii de clase: class Dreptunghi { double x, y, w, h; // Nici un constructor } class Cerc { double x, y, r; // Constructor cu 3 argumente Cerc(double x, double y, double r) { ... }; } Sa consideram acum doua instantieri ale claselor de mai sus: Dreptunghi d = new Dreptunghi(); // Corect (a fost generat constructorul implicit) Cerc c; c = new Cerc(); // Eroare la compilare ! c = new Cerc(0, 0, 100); // Varianta corecta In cazul mostenirii unei clase, instantierea unui obiect din clasa extinsa implica instantierea unui obiect din clasa parinte. Din acest motiv, fiecare constructor al clasei fiu va trebui sa aiba un constructor cu aceeasi signatura n parinte sau sa apeleze explicit un

constructor al clasei extinse folosind expresia super([argumente]), n caz contrar fiind semnalata o eroare la compilare. class A { int x=1; A(int x) { this.x = x;} } class B extends A { // Corect B() {super(2);} B(int x) {super(x);} } class C extends A { // Eroare la compilare ! C() {this.x = 2;} C(int x) {super(x);} } Constructorii unei clase pot avea urmatorii modificatori de acces: public, protected, private si cel implicit. public In orice alta clasa se pot crea instante ale clasei respective. protected Doar n subclase pot fi create obiecte de tipul clasei respective. private In nici o alta clasa nu se pot instantia obiecte ale acestei clase. O astfel de clasa poate contine metode publice (numite factory methods) care sa fie responsabile cu crearea obiectelor, controland n felul acesta diverse aspecte legate de instantierea clasei respective. implicit Doar n clasele din acelasi pachet se pot crea instante ale clasei respective. 2.8.2.5. Declararea variabilelor Variabilele membre ale unei clase se declara de obicei naintea metodelor, desi acest lucru nu este impus de catre compilator. class NumeClasa { // Declararea variabilelor // Declararea metodelor } Variabilele membre ale unei clase se declara n corpul clasei si nu n corpul unei metode, fiind vizibile n toate metodele respectivei clase. Variabilele declarate n cadrul unei metode sunt locale metodei respective. Declararea unei variabile presupune specificarea urmatoarelor lucruri: numele variabilei tipul de date al acesteia nivelul de acces la acea variabila din alte clase daca este constanta sau nu daca este variabila de instanta sau de clasa
8

alti modificatori Generic, o variabila se declara astfel: [modificatori] Tip numeVariabila [ = valoareInitiala ]; unde un modificator poate fi : un modificator de acces : public, protected, private unul din cuvintele rezervate: static, final, transient, volatile Exemple de declaratii de variabile membre: class Exemplu { double x; protected static int n; public String s = "abcd"; private Point p = new Point(10, 10); final static long MAX = 100000L; } Sa analizam modificatorii care pot fi specificati pentru o variabila, altii decat cei de acces care sunt tratati ntr-o sectiune separata: Specificatori de acces pentru membrii unei clase. static Prezenta lui declara ca o variabila este variabila de clasa si nu de instanta. int variabilaInstanta ; static int variabilaClasa; final Indica faptul ca valoarea variabilei nu mai poate fi schimbata, cu alte cuvinte este folosit pentru declararea constantelor. final double PI = 3.14 ; ... PI = 3.141; // Eroare la compilare ! Prin conventie, numele variabilelor finale se scriu cu litere mari. Folosirea lui final aduce o flexibilitate sporita n lucrul cu constante, n sensul ca valoarea unei variabile nu trebuie specificata neaparat la declararea ei (ca n exemplul de mai sus), ci poate fi specificata si ulterior ntr-un constructor, dupa care ea nu va mai putea fi modificata. class Test { final int MAX; Test() { MAX = 100; // Corect MAX = 200; // Eroare la compilare ! } } transient Este folosit la serializarea obiectelor, pentru a specifica ce variabile membre ale unui obiect nu participa la serializare. volatile Este folosit pentru a semnala compilatorului sa nu execute anumite optimizari asupra membrilor unei clase. Este o facilitate avansata a limbajului Java. 2.8.2.6. this si super

Sunt variabile predefinite care fac referinta, n cadrul unui obiect, la obiectul propriu-zis (this), respectiv la instanta parintelui (super). Sunt folosite n general pentru a rezolva conflicte de nume prin referirea explicita a unei variabile sau metode membre. Dupa cum am vazut, utilizate sub forma de metode au rolul de a apela constructorii corespunzatori ca argumente ai clasei curente, respectiv ai superclasei class A { int x; A() { this(0); } A(int x) { this.x = x; } void metoda() { x ++; } } class B extends A { B() { this(0); } B(int x) { super(x); System.out.println(x); } void metoda() { super.metoda(); System.out.println(x); } } 2.8.3. Implementarea metodelor 2.8.3.1. Declararea metodelor Metodele sunt responsabile cu descrierea comportamentului unui obiect. Intrucat Java este un limbaj de programare complet orientat-obiect, metodele se pot gasi doar n cadrul claselor. Generic, o metoda se declara astfel: [modificatori] TipReturnat numeMetoda ( [argumente] ) [throws TipExceptie1, TipExceptie2, ...] { // Corpul metodei } unde un modificator poate fi : un specificator de acces : public, protected, private unul din cuvintele rezervate: static, abstract, final, native, synchronized Sa analizam modificatorii care pot fi specificati pentru o metoda, altii decat cei de acces care sunt tratati ntr-o sectiune separata.

10

static Prezenta lui declara ca o metoda este de clasa si nu de instanta. void metodaInstanta(); static void metodaClasa(); abstract Permite declararea metodelor abstracte. O metoda abstracta este o metoda care nu are implementare si trebuie obligatoriu sa faca parte dintr-o clasa abstracta. final Specifica faptul ca acea metoda nu mai poate fi supradefinita n subclasele clasei n care ea este definita ca fiind finala. Acest lucru este util daca respectiva metoda are o implementare care nu trebuie schimbata sub nici o forma n subclasele ei, fiind critica pentru consistenta starii unui obiect. De exemplu, studentilor unei universitati trebuie sa li se calculeze media finala, n functie de notele obtinute la examene, n aceeasi maniera, indiferent de facultatea la care sunt. class Student { ... final float calcMedie(float note[], float ponderi[]) { ... } ... } class StudentInformatica extends Student { float calcMedie(float note[], float ponderi[]) { return 10.00; } }// Eroare la compilare ! native In cazul n care avem o librarie importanta de functii scrise n alt limbaj de programare, cum ar fi C, C++ si limbajul de asamblare, acestea pot fi refolosite din programele Java. Tehnologia care permite acest lucru se numeste JNI (Java Native Interface) si permite asocierea dintre metode Java declarate cu native si metode native scrise n limbajele de programare mentionate. synchronized Este folosit n cazul n care se lucreaza cu mai multe fire de executie iar metoda respectiva gestioneaza resurse comune. Are ca efect construirea unui monitor care nu permite executarea metodei, la un moment dat, decat unui singur fir de executie. 2.8.3.2. Tipul returnat de o metoda Metodele pot sau nu sa returneze o valoare la terminarea lor. Tipul returnat poate fi atat un tip primitiv de date sau o referinta la un obiect al unei clase. In cazul n care o metoda nu returneaza nimic atunci trebuie obligatoriu specificat cuvantul cheie void ca tip returnat: public void afisareRezultat() { System.out.println("rezultat"); } private void deseneaza(Shape s) {

11

... return; } Daca o metoda trebuie sa returneze o valoare acest lucru se realizeaza prin intermediul instructiunii return, care trebuie sa apara n toate situatiile de terminare a functiei. double radical(double x) { if (x >= 0) return Math.sqrt(x); else { System.out.println("Argument negativ !"); // Eroare la compilare // Lipseste return pe aceasta ramura } } In cazul n care n declaratia functiei tipul returnat este un tip primitiv de date, valoarea returnata la terminarea functiei trebuie sa aiba obligatoriu acel tip sau un subtip al sau, altfel va fi furnizata o eroare la compilare. In general, orice atribuire care implica pierderi de date este tratata de compilator ca eroare. int metoda() { return 1.2; // Eroare } int metoda() { return (int)1.2; // Corect } double metoda() { return (float)1; // Corect } Daca valoarea returnata este o referinta la un obiect al unei clase, atunci clasa obiectului returnat trebuie sa coincida sau sa fie o subclasa a clasei specificate la declararea metodei. De exemplu, fie clasa Poligon si subclasa acesteia Patrat. Poligon metoda1( ) { Poligon p = new Poligon(); Patrat t = new Patrat(); if (...) return p; // Corect else return t; // Corect } Patrat metoda2( ) { Poligon p = new Poligon(); Patrat t = new Patrat(); if (...) return p; // Eroare else return t; // Corect }

12

2.8.3.3. Trimiterea parametrilor catre o metoda Signatura unei metode este data de numarul si tipul argumentelor primite de acea metoda. Tipul de date al unui argument poate fi orice tip valid al limbajului Java, atat tip primitiv cat si tip referinta. TipReturnat metoda([Tip1 arg1, Tip2 arg2, ...]) Exemplu:
void adaugarePersoana(String nume, int varsta, float salariu) // String este tip referinta // int si float sunt tipuri primitive

Spre deosebire de alte limbaje, n Java nu pot fi trimise ca parametri ai unei metode referinte la alte metode (functii), nsa pot fi trimise referinte la obiecte care sa contina implementarea acelor metode, pentru a fi apelate. Pana la aparitia versiunii 1.5, n Java o metoda nu putea primi un numar variabil de argumente, ceea ce nseamna ca apelul unei metode trebuia sa se faca cu specificarea exacta a numarului si tipurilor argumentelor. Vom analiza ntr-o sectiune separata modalitate de specificare a unui numar variabil de argumente pentru o metoda. Numele argumentelor primite trebuie sa difere ntre ele si nu trebuie sa coincida cu numele nici uneia din variabilele locale ale metodei. Pot nsa sa coincida cu numele variabilelor membre ale clasei, caz n care diferentierea dintre ele se va face prin intermediul variabilei this. class Cerc { int x, y, raza; public Cerc(int x, int y, int raza) { this.x = x; this.y = y; this.raza = raza; } } In Java argumentele sunt trimise doar prin valoare (pass-by-value). Acest lucru nseamna ca metoda receptioneaza doar valorile variabilelor primite ca parametri. Cand argumentul are tip primitiv de date, metoda nu-i poate schimba valoarea decat local (n cadrul metodei); la revenirea din metoda variabila are aceeasi valoare ca naintea apelului, modificarile facute n cadrul metodei fiind pierdute. Cand argumentul este de tip referinta, metoda nu poate schimba valoarea referintei obiectului, nsa poate apela metodele acelui obiect si poate modifica orice variabila membra accesibila. Asadar, daca dorim ca o metoda sa schimbe starea (valoarea) unui argument primit, atunci el trebuie sa fie neaparat de tip referinta. De exemplu, sa consideram clasa Cerc descrisa anterior n care dorim sa implementam o metoda care sa returneze parametrii cercului. // Varianta incorecta: class Cerc { private int x, y, raza; public void aflaParametri(int valx, int valy, int valr) { // Metoda nu are efectul dorit! valx = x;

13

valy = y; valr = raza; } } Aceasta metoda nu va realiza lucrul propus ntrucat ea primeste doar valorile variabilelor valx, valy si valr si nu referinte la ele (adresele lor de memorie), astfel ncat sa le poata modifica valorile. In concluzie, metoda nu realizeaza nimic pentru ca nu poate schimba valorile variabilelor primite ca argumente. Pentru a rezolva lucrul propus trebuie sa definim o clasa suplimentara care sa descrie parametrii pe care dorim sa-i aflam: // Varianta corecta class Param { public int x, y, raza; } class Cerc { private int x, y, raza; public void aflaParametri(Param param) { param.x = x; param.y = y; param.raza = raza; } } Argumentul param are tip referinta si, desi nu i schimbam valoarea (valoarea sa este adresa de memorie la care se gaseste si nu poate fi schimbata), putem schimba starea obiectului, adica informatia propriu-zisa continuta de acesta. Varianta de mai sus a fost data pentru a clarifica modul de trimitere a argumentelor unei metode. Pentru a afla nsa valorile variabilelor care descriu starea unui obiect se folosesc metode de tip getter nsotite de metode setter care sa permita schimbarea starii obiectului: class Cerc { private int x, y, raza; public int getX() { return x; } public void setX(int x) { this.x = x; } ... } 2.8.3.4. Metode cu numar variabil de argumente Incepand cu versiunea 1.5 a limbajului Java, exista posibilitate de a declara metode care sa primeasca un numar variabil de argumente. Noutatea consta in folosirea simbolului ..., sintaxa unei astfel de metode fiind: [modificatori] TipReturnat metoda(TipArgumente ... args)

14

args reprezinta un vector avand tipul specificat si instantiat cu un numar variabil de argumente, n functie de apelul metodei. Tipul argumentelor poate fi referinta sau primitiv. Metoda de mai jos afiseaza argumentele primite, care pot fi de orice tip: void metoda(Object ... args) { for(int i=0; i<args.length; i++) System.out.println(args[i]); } ... metoda("Hello"); metoda("Hello", "Java", 1.5); 2.8.3.5. Suprancarcarea si supradefinirea metodelor Suprancarcarea si supradefinirea metodelor sunt doua concepte extrem de utile ale programarii orientate obiect, cunoscute si sub denumirea de polimorfism, si se refera la: suprancarcarea (overloading) : n cadrul unei clase pot exista metode cu acelasi nume cu conditia ca signaturile lor sa fie diferite (lista de argumente primite sa difere fie prin numarul argumentelor, fie prin tipul lor) astfel ncat la apelul functiei cu acel nume sa se poata stabili n mod unic care dintre ele se executa. supradefinirea (overriding): o subclasa poate rescrie o metoda a clasei parinte prin implementarea unei metode cu acelasi nume si aceeasi signatura ca ale superclasei. class A { void metoda() { System.out.println("A: metoda fara parametru"); } // Supraincarcare void metoda(int arg) { System.out.println("A: metoda cu un parametru"); } } class B extends A { // Supradefinire void metoda() { System.out.println("B: metoda fara parametru"); } } O metoda supradefinita poate sa: ignore complet codul metodei corespunzatoare din superclasa (cazul de mai sus): B b = new B(); b.metoda(); // Afiseaza "B: metoda fara parametru" extinda codul metodei parinte, executand nainte de codul propriu si functia parintelui: class B extends A { // Supradefinire prin extensie void metoda() { super.metoda();

15

System.out.println("B: metoda fara parametru"); } } . . . B b = new B(); b.metoda(); /* Afiseaza ambele mesaje: "A: metoda fara parametru" "B: metoda fara parametru" */ O metoda nu poate supradefini o metoda declarata finala n clasa parinte. Orice clasa care nu este abstracta trebuie obligatoriu sa supradefineasca metodele abstracte ale superclasei (daca este cazul). In cazul n care o clasa nu supradefineste toate metodele abstracte ale parintelui, ea nsasi este abstracta si va trebui declarata ca atare. In Java nu este posibila suprancarcarea operatorilor. 2.8.4. Modificatori de acces Modificatorii de acces sunt cuvinte rezervate ce controleaza accesul celorlate clase la membrii unei clase. Specificatorii de acces pentru variabilele si metodele unei clase sunt: public, protected, private si cel implicit (la nivel de pachet), iar nivelul lor de acces este dat n tabelul de mai jos: Specificator private protected public implicit Clasa X X X X Sublasa X* X Pachet X X X Oriunde

Asadar, daca nu este specificat nici un modificator de acces, implicit nivelul de acces este la nivelul pachetului. In cazul n care declaram un membru protected atunci accesul la acel membru este permis din subclasele clasei n care a fost declarat dar depinde si de pachetul n care se gaseste subclasa: daca sunt n acelasi pachet accesul este permis, daca nu sunt n acelasi pachet accesul nu este permis decat pentru obiecte de tipul subclasei. Exemple de declaratii: private int secretPersonal; protected String secretDeFamilie; public Vector pentruToti; long doarIntrePrieteni; private void metodaInterna(); public String informatii(); 2.8.5. Membri de instanta si membri de clasa O clasa Java poate contine doua tipuri de variabile si metode :

16

de instanta: declarate fara modificatorul static, specifice fiecarei instante create dintr-o clasa si de clasa: declarate cu modificatorul static, specifice clasei. 2.8.5.1. Variabile de instanta si de clasa Cand declaram o variabila membra fara modificatorul static, cum ar fi x n exemplul de mai jos: class Exemplu { int x ; //variabila de instanta } se declara de fapt o variabila de instanta, ceea ce nseamna ca la fiecare creare a unui obiect al clasei Exemplu sistemul aloca o zona de memorie separata pentru memorarea valorii lui x. Exemplu o1 = new Exemplu(); o1.x = 100; Exemplu o2 = new Exemplu(); o2.x = 200; System.out.println(o1.x); // Afiseaza 100 System.out.println(o2.x); // Afiseaza 200 Asadar, fiecare obiect nou creat va putea memora valori diferite pentru variabilele sale de instanta. Pentru variabilele de clasa (statice) sistemul aloca o singura zona de memorie la care au acces toate instantele clasei respective, ceea ce nseamna ca daca un obiect modifica valoarea unei variabile statice ea se va modifica si pentru toate celelalte obiecte. Deoarece nu depind de o anumita instanta a unei clase, variabilele statice pot fi referite si sub forma: NumeClasa.numeVariabilaStatica class Exemplu { int x ; // Variabila de instanta static long n; // Variabila de clasa } . . . Exemplu o1 = new Exemplu(); Exemplu o2 = new Exemplu(); o1.n = 100; System.out.println(o2.n); // Afiseaza 100 o2.n = 200; System.out.println(o1.n); // Afiseaza 200 System.out.println(Exemplu.n); // Afiseaza 200 //o1.n, o2.n si Exemplu.n sunt referinte la aceeasi valoare Initializarea variabilelor de clasa se face o singura data, la ncarcarea n memorie a clasei respective, si este realizata prin atribuiri obisnuite: class Exemplu { static final double PI = 3.14; static long nrInstante = 0; static Point p = new Point(0,0);

17

} 2.8.5.2. Metode de instanta si de clasa Similar ca la variabile, metodele declarate fara modificatorul static sunt metode de instanta iar cele declarate cu static sunt metode de clasa (statice). Diferenta ntre cele doua tipuri de metode este urmatoarea: metodele de instanta opereaza atat pe variabilele de instanta cat si pe cele statice ale clasei; metodele de clasa opereaza doar pe variabilele statice ale clasei. class Exemplu { int x ; // Variabila de instanta static long n; // Variabila de clasa void metodaDeInstanta() { n ++; // Corect x --; // Corect } static void metodaStatica() { n ++; // Corect x --; // Eroare la compilare ! } } Intocmai ca si la variabilele statice, ntrucat metodele de clasa nu depind de starea obiectelor clasei respective, apelul lor se poate face si sub forma: NumeClasa.numeMetodaStatica Exemplu.metodaStatica(); // Corect, echivalent cu Exemplu obj = new Exemplu(); obj.metodaStatica(); // Corect, de asemenea Metodele de instanta nu pot fi apelate decat pentru un obiect al clasei respective: Exemplu.metodaDeInstanta(); // Eroare la compilare ! Exemplu obj = new Exemplu(); obj.metodaDeInstanta(); // Corect 2.8.5.3. Utilitatea membrilor de clasa Membrii de clasa sunt folositi pentru a pune la dispozitie valori si metode independente de starea obiectelor dintr-o anumita clasa. Declararea eficienta a constantelor Sa consideram situatia cand dorim sa declaram o constanta. class Exemplu { final double PI = 3.14; // Variabila finala de instanta } La fiecare instantiere a clasei Exemplu va fi rezervata o zona de memorie pentru variabilele finale ale obiectului respectiv, ceea ce este o risipa ntrucat aceste constante au aceleasi valori pentru toate instantele clasei. Declararea corecta a constantelor trebuie

18

asadar facuta cu modificatorii static si final, pentru a le rezerva o singura zona de memorie, comuna tuturor obiectelor: class Exemplu { static final double PI = 3.14; // Variabila finala de clasa } Numararea obiectelor unei clase Numararea obiectelor unei clase poate fi facuta extrem de simplu folosind o variabila statica si este utila n situatiile cand trebuie sa controlam diversi parametri legati de crearea obiectelor unei clase. class Exemplu { static long nrInstante = 0; Exemplu() { // Constructorul este apelat la fiecare instantiere nrInstante ++; } } Implementarea functiilor globale Spre deosebire de limbajele de programare procedurale, n Java nu putem avea functii globale definite ca atare, ntrucat orice este un obiect. Din acest motiv chiar si metodele care au o functionalitate globala trebuie implementate n cadrul unor clase. Acest lucru se va face prin intermediul metodelor de clasa (globale), deoarece acestea nu depind de starea particulara a obiectelor din clasa respectiva. De exemplu, sa consideram functia sqrt care extrage radicalul unui numar si care se gaseste n clasa Math. Daca nu ar fi fost functie de clasa, apelul ei ar fi trebuit facut astfel (incorect, de altfel): // Incorect ! Math obj = new Math(); double rad = obj.sqrt(121); ceea ce ar fi fost extrem de neplacut... Fiind nsa metoda statica ea poate fi apelata prin: Math.sqrt(121) . Asadar, functiile globale necesare unei aplicatii vor fi grupate corespunzator n diverse clase si implementate ca metode statice. 2.8.5.4. Blocuri statice de initializare Variabilele statice ale unei clase sunt initializate la un moment care precede prima utilizare activa a clasei respective. Momentul efectiv depinde de implementarea masinii virtuale Java si poarta numele de initializarea clasei. Pe langa setarea valorilor variabilelor statice, n aceasta etapa sunt executate si blocurile statice de initializare ale clasei. Acestea sunt secvente de cod de forma: static { // Bloc static de initializare; ... } care se comporta ca o metoda statica apelata automat de catre masina virtuala. Variabilele referite ntr-un bloc static de initializare trebuie sa fie obligatoriu de clasa sau locale blocului:
19

public class Test { // Declaratii de variabile statice static int x = 0, y, z; // Bloc static de initializare static { System.out.println("Initializam..."); int t=1; y = 2; z = x + y + t; } Test() { /* La executia constructorului variabilele de clasa sunt deja initializate si toate blocurile statice de initializare au fost obligatoriu executate in prealabil. */ ... } } 2.8.6. Clasa Object 2.8.6.1. Orice clasa are o superclasa Dupa cum am vazut n sectiunea dedicata modalitatii de creare a unei clase, clauza extends specifica faptul ca acea clasa extinde (mosteneste) o alta clasa, numita superclasa. O clasa poate avea o singura superclasa (Java nu suporta mostenirea multipla) si chiar daca nu specificam clauza extends la crearea unei clase ea totusi va avea o superclasa. Cu alte cuvinte, n Java orice clasa are o superclasa si numai una. Evident, trebuie sa existe o exceptie de la aceasta regula si anume clasa care reprezinta radacina ierarhiei formata de relatiile de mostenire dintre clase. Aceasta este clasa Object. Clasa Object este si superclasa implicita a claselor care nu specifica o anumita superclasa. Declaratiile de mai jos sunt echivalente: class Exemplu {} class Exemplu extends Object {} 2.8.6.2. Clasa Object Clasa Object este cea mai generala dintre clase, orice obiect fiind, direct sau indirect, descendent al acestei clase. Fiind parintele tuturor, Object defineste si implementeaza comportamentul comun al tuturor celorlalte clase Java, cum ar fi: posibilitatea testarii egalitatii valorilor obiectelor, specificarea unei reprezentari ca sir de caractere a unui obiect , returnarea clasei din care face parte un obiect, notificarea altor obiecte ca o variabila de conditie s-a schimbat, etc. Fiind subclasa a lui Object, orice clasa ii poate supradefini metodele care nu sunt finale. Metodele cel mai uzual supradefinite sunt: clone, equals/hashCode, finalize, toString. clone

20

Aceasta metoda este folosita pentru duplicarea obiectelor (crearea unor clone). Clonarea unui obiect presupune crearea unui nou obiect de acelasi tip si care sa aiba aceeasi stare (aceleasi valori pentru variabilele sale). equals, hashCode Acestea sunt, de obicei, supradefinite mpreuna. In metoda equals este scris codul pentru compararea egalitatii continutului a doua obiecte. Implicit (implementarea din clasa Object), aceasta metoda compara referintele obiectelor. Uzual este redefinita pentru a testa daca starile obiectelor coincid sau daca doar o parte din variabilele lor coincid. Metoda hashCode returneaza un cod ntreg pentru fiecare obiect, pentru a testa consistenta obiectelor: acelasi obiect trebuie sa returneze acelasi cod pe durata executiei programului. Daca doua obiecte sunt egale conform metodei equals, atunci apelul metodei hashCode pentru fiecare din cele doua obiecte ar trebui sa returneze acelasi intreg. finalize In aceasta metoda se scrie codul care curata dupa un obiect nainte de a fi eliminat din memorie de colectorul de gunoaie. toString Este folosita pentru a returna o reprezentare ca sir de caractere a unui obiect. Este utila pentru concatenarea sirurilor cu diverse obiecte n vederea afisarii, fiind apelata automat atunci cand este necesara transformarea unui obiect n sir de caractere. Exemplu obj = new Exemplu(); System.out.println("Obiect=" + obj); //echivalent cu System.out.println("Obiect=" + obj.toString()); Sa consideram urmatorul exemplu, n care implementam partial clasa numerelor complexe, si n care vom supradefini metode ale clasei Object. De asemenea, vom scrie un mic program TestComplex n care vom testa metodele clasei definite. Clasa numerelor complexe (lab3b) class Complex { private double a; // partea reala private double b; // partea imaginara public Complex ( double a, double b) { this .a = a; this .b = b; } public Complex () { this (1, 0); } public boolean equals ( Object obj) { if (obj == null ) return false ; if (!( obj instanceof Complex )) return false ; Complex comp = ( Complex ) obj; return ( comp .a==a && comp .b==b); } public Object clone () { return new Complex (a, b); }

21

public String toString () { String semn = (b > 0 ? "+" : "-"); return a + semn + b + "i"; } public Complex aduna ( Complex comp ) { Complex suma = new Complex (0, 0); suma .a = this .a + comp .a; suma .b = this .b + comp .b; return suma ; } } public class TestComplex { public static void main ( String c[]) { Complex c1 = new Complex (1 ,2); Complex c2 = new Complex (2 ,3); Complex c3 = ( Complex ) c1. clone (); System . out. println (c1. aduna (c2)); // 3.0 + 5.0i System . out. println (c1. equals (c2)); // false System . out. println (c1. equals (c3)); // true } } 2.8.7. Conversii automate intre tipuri Dupa cum am vazut tipurile Java de date pot fi mpartite n primitive si referinta. Pentru fiecare tip primitiv exista o clasa corespunzatoare care permite lucrul orientat obiect cu tipul respectiv. byte short int long float double char boolean Byte Short Integer Long Float Double Character Boolean

Fiecare din aceste clase are un constructor ce permite initializarea unui obiect avand o anumita valoare primitiva si metode specializate pentru conversia unui obiect n tipul primitiv corespunzator, de genul tipPrimitivValue: Integer obi = new Integer(1); int i = obi.intValue(); Boolean obb = new Boolean(true); boolean b = obb.booleanValue(); Incepand cu versiunea 1.5 a limbajului Java, atribuirile explicite ntre tipuri primitive si referinta sunt posibile, acest mecanism purtand numele de autoboxing, respectiv auto-unboxing. Conversia explicita va fi facuta de catre compilator.
22

// Doar Integer int i = Boolean boolean

de la versiunea 1.5 ! obi = 1; obi; obb = true; b = obb;

2.8.8. Tipul de date enumerare Incepand cu versiunea 1.5 a limbajului Java, exista posibilitatea de a defini tipuri de date enumerare prin folosirea cuvantului cheie enum. Acesta solutie simplifica manevrarea grupurilor de constante, dupa cum reiese din urmatorul exemplu: public class CuloriSemafor { public static final int ROSU = -1; public static final int GALBEN = 0; public static final int VERDE = 1; } ... // Exemplu de utilizare if (semafor.culoare = CuloriSemafor.ROSU) semafor.culoare = CuloriSemafor.GALBEN); ... Clasa de mai sus poate fi rescrisa astfel: public enum CuloriSemafor { ROSU, GALBEN, VERDE }; ... // Utilizarea structurii se face la fel ... if (semafor.culoare = CuloriSemafor.ROSU) semafor.culoare = CuloriSemafor.GALBEN); ... Compilatorul este responsabil cu transformarea unei astfel de structuri ntr-o clasa corespunzatoare.

23

CURS 5
2.9. Exceptii 2.9.1. Ce sunt exceptiile? Termenul exceptie este o prescurtare pentru "eveniment exceptional" si poate fi definit ca un eveniment ce se produce in timpul executiei unui program si care provoaca intreruperea cursului normal al executiei. Exceptiile pot aparea din diverse cauze si pot avea nivele diferite de gravitate: de la erori fatale cauzate de echipamentul hardware pana la erori ce tin strict de codul programului, cum ar fi accesarea unui element din afara spatiului alocat unui vector. In momentul cand o asemenea eroare se produce in timpul executiei sistemul genereaza automat un obiect de tip exceptie ce contine: informatii despre exceptia respectiva starea programului in momentul producerii acelei exceptii
public class Exceptii { public static void main(String argsst) { int v[] = new int[10]; v[10] = 0;//exceptie,vectorul are elementele v[0]...v[9] System.out.println("Aici nu se mai ajunge..."); } }

La rularea programului va fi generata o exceptie si se va afisa mesajul : Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException :10 at Exceptii.main (Exceptii.java:4) Crearea unui obiect de tip exceptie se numeste aruncarea unei exceptii ("throwing an exception"). In momentul in care o metoda genereaza o exceptie (arunca o exceptie) sistemul de executie este responsabil cu gasirea unei secvente de cod dintr-o metoda care sa trateze acea exceptie. Cautarea se face recursiv, incepand cu metoda care a generat exceptia si mergand inapoi pe linia apelurilor catre acea metoda. Secventa de cod dintr-o metoda care trateaza o anumita exceptie se numeste analizor de exceptie ("exception handler") iar interceptarea si tratarea exceptie se numeste prinderea exceptiei ("catch the exception"). Cu alte cuvinte la aparitia unei erori este "aruncata" o exceptie iar cineva trebuie sa o "prinda" pentru a o trata. Daca sistemul nu gaseste nici un analizor pentru o anumita exceptie atunci programul Java se opreste cu un mesaj de eroare (in cazul exemplului de mai sus mesajul "Aici nu se mai ajunge..." nu va fi tiparit). Observatie: In Java tratarea erorilor nu mai este o optiune ci o constrangere. Orice cod care poate provoca exceptii trebui sa specifice modalitatea de tratare a acestora. 2.9.2. Avantajele exceptiilor Prin modalitatea sa de tratare a exceptiilor Java are urmatoarele avantaje fata de mecanismul traditional de tratare a erorilor: 1. Separarea codului pentru tratarea unei erori de codul in care ea poate sa apara 2. Propagarea unei erori pana la un analizor de exceptii corespunzator 3. Gruparea erorilor dupa tipul lor 2.9.2.1.Separarea codului pentru tratarea erorilor In programarea traditionala tratarea erorilor se combina cu codul ce poate produce aparitia lor conducand la asa numitul "cod spaghetti". Sa consideram urmatorul exemplu: o functie care incarca un fisier in memorie:

citesteFisier { deschide fisierul; determina dimensiunea fisierului; aloca memorie; citeste fisierul in memorie; inchide fisierul; } Problemele care pot aparea la aceasta functie, aparent simpla sunt de genul: "Ce se intampla daca: ... ?" fisierul nu poate fi deschis nu se poate determina dimensiunea fisierului nu poate fi alocata suficienta memorie nu se poate face citirea din fisier fisierul nu poate fi inchis Un cod traditional care sa trateze aceste erori ar arata astfel: int citesteFisier { int codEroare = 0; deschide fisier; if (fisierul s-a deschis) { determina dimensiunea fisierului; if (s-a determinat dimensiunea) { aloca memorie; if (s-a alocat memorie) { citeste fisierul in memorie; if (nu se poate citi din fisier) { codEroare = -1; } } else { codEroare = -2; } } else { codEroare = -3; } inchide fisierul; if (fisierul nu s-a inchis && codEroare == 0) { codEroare = -4; } else { codEroare = codEroare & -4; } } else { codEroare = -5; } return codEroare; }//cod "spaghetti" Acest stil de programare este extrem de susceptibil la erori si ingreuneaza extrem de mult intelegerea sa. In Java, folosind mecanismul exceptiilor, codul ar arata astfel: int citesteFisier { try { deschide fisierul; determina dimensiunea fisierului; aloca memorie;

citeste fisierul in memorie; inchide fisierul; } catch catch catch catch catch } 2.9.2.2. Propagarea erorilor Propagarea unei erori se face pana la un analizor de exceptii corespunzator. Sa presupunem ca apelul la metoda citesteFisier este consecinta unor apeluri imbricate de metode: int metoda1 { apel metoda2; . . . } int metoda2 { apel metoda3; . . . } int metoda3 { apel citesteFisier; . . . } Sa presupunem de asemenea ca dorim sa facem tratarea erorilor doar in metoda1. Traditional, acest lucru ar trebui facut prin propagarea erorii intoarse de metoda citesteFisier pina la metoda1. int metoda1 { int codEroare = apel metoda2; if (codEroare != 0) proceseazaEroare; . . . } int metoda2 { int codEroare = apel metoda3; if (codEroare != 0) return codEroare; . . . } int metoda3 { int codEroare = apel citesteFisier; if (codEroare != 0) return codEroare; . . . } Java permite unei metode sa arunce exceptiile aparute in cadrul ei la un nivel superior, adica functiilor care o apeleaza sau sistemului. Cu alte cuvinte o metoda poate sa nu isi asume responsabilitatea tratarii exceptiilor aparute in cadrul ei: (fisierul nu s-a deschis) {trateaza eroarea;} (nu s-a determinat dimensiunea) {trateaza eroarea;} (nu s-a alocat memorie) {trateaza eroarea } (nu se poate citi dun fisier) {trateaza eroarea;} (nu se poate inchide fisierul) {trateaza eroarea;}

metoda1 { try { apel metoda2; } catch (exceptie) { proceseazaEroare; } . . . } metoda2 throws exceptie{ apel metoda3; . . . } metoda3 throws exceptie{ apel citesteFisier; . . . } 2.9.2.3. Gruparea erorilor dupa tipul lor In Java exista clase corespunzatoare tuturor exceptiilor care pot aparea la executia unui program. Acestea sunt grupate in functie de similaritatile lor intr-o ierarhie de clase. De exemplu, clasa IOException se ocupa cu exceptiile ce pot aparea la operatii de intrare/iesire si diferentiaza la randul ei alte tipuri de exceptii, cum ar fi FileNotFoundException, EOFException, etc. La randul ei clasa IOException se incadreaza intr-o categorie mai larga de exceptii si anume clasa Exception. Radacina acestei ierarhii este clasa Throwable. Interceptarea unei exceptii se poate face fie la nivelul clasei specifice pentru acea exceptie fie la nivelul uneia din superclasele sale, in functie de necesitatile programului:
try { FileReader f = new FileReader("input.dat"); /*acest apel poate genera exceptie de tipul FileNotFoundException tratarea ei poate fi facuta in unul din modurile de mai jos*/ } catch (FileNotFoundException e) { //exceptie specifica provocata de absenta fisierului 'input.dat' } //sau catch (IOException e) { //exceptie generica provocata de o operatie de intrare/iesire } //sau catch (Exception e) { //cea mai generica exceptie - NERECOMANDATA! }

2.9.3. "Prinderea" si tratarea exceptiilor Tratarea exceptiilor se realizeaza prin intermediul blocurilor de instructiuni try, catch si finally. O secventa de cod care trateaza anumite exceptii trebuie sa arate astfel: try { Instructiuni care pot genera o exceptie

} catch (TipExceptie1 ) { Prelucrarea exceptiei de tipul 1 } catch (TipExceptie2 ) { Prelucrarea exceptiei de tipul 2 } . . . finally { Cod care se executa indiferent daca apar sau nu exceptii } Sa consideram urmatorul exemplu : citirea unui fisier si afisarea lui pe ecran. Fara a folosi tratarea exceptiilor codul programului ar arata astfel: //ERONAT! import java.io.*; public class CitireFisier { public static void citesteFisier() { FileInputStream sursa = null;//s este flux de intrare int octet; sursa = new FileInputStream("fisier.txt"); octet = 0; //citesc fisierul caracter cu caracter while (octet != -1) { octet = sursa.read(); System.out.print((char)octet); } sursa.close(); } public static void main(String args[]) { citesteFisier(); } } Acest cod va furniza erori la compilare deoarece in Java tratarea erorilor este obligatorie. Folosind mecanismul exceptiilor metoda citesteFisier isi poate trata singura erorile pe care le poate provoca: //CORECT import java.io.*; public class CitireFisier { public static void citesteFisier() { FileInputStream sursa = null; //s este flux de intrare int octet; try { sursa = new FileInputStream("fisier.txt"); octet = 0; //citesc fisierul caracter cu caracter while (octet != -1) { octet = sursa.read(); System.out.print((char)octet); } } catch (FileNotFoundException e) {

System.out.println("Fisierul nu a fost gasit !"); System.out.println("Exceptie: " + e.getMessage()); System.exit(1); } catch (IOException e) { System.out.println("Eroare de intrare/iesire"); System.out.println("Exceptie: " + e.getMessage()); System.exit(2); } finally { if (sursa != null) { System.out.println("Inchidem fisierul..."); try { sursa.close(); } catch (IOException e) { System.out.println("Fisierul nu poate fi inchis!"); System.out.println("Exceptie: " + e.getMessage()); System.exit(3); } } } } public static void main(String args[]) { citesteFisier(); } } Blocul "try" contine instructiunile de deschidere a unui fisier si de citire dintr-un fisier ambele putand produce exceptii. Exceptiile provocate de aceste instructiuni sunt tratate in cele doua blocuri "catch", cate unul pentru fiecare tip de exceptie. Inchiderea fisierului se face in blocul "finally", deoarece acesta este sigur ca se va executa. Fara a folosi blocul "finally" inchiderea fisierului ar fi trebuit facuta in fiecare situatie in care fisierul ar fi fost deschis, ceea ce ar fi dus la scrierea de cod redundant: try { . . . sursa.close(); } . . . catch (IOException e) { . . . sursa.close(); //cod redundant } Observatie: Obligatoriu un bloc de instructiuni "try" trebuie sa fie urmat de unul sau mai multe blocuri "catch", in functie de exceptiile provocate de acele instructiuni sau (optional) de un bloc "finally" 2.9.4. "Aruncarea" exceptiilor In cazul in care o metoda nu isi asuma responsabilitatea tratarii uneia sau mai multor exceptii pe care le pot provoca anumite instructiuni din codul sau atunci ea poate sa "arunce" aceste exceptii catre metodele care o apeleaza, urmand ca acestea sa implementeze tratarea lor

sau, la randul lor, sa "arunce" mai departe exceptiile respective. Acest lucru se realizeaza prin specificarea in declaratia metodei a clauzei throws: metoda throws TipExceptie1, TipExceptie2, ... { . . . } Observatie: O metoda care nu trateaza o anumita exceptie trebuie obligatoriu sa o "arunce". In exemplul de mai sus daca nu facem tratarea exceptiilor in cadrul metodei citesteFisier atunci metoda apelanta (main) va trebui sa faca acest lucru: import java.io.*; public class CitireFisier { public static void citesteFisier() throws FileNotFoundException, IOException { FileInputStream sursa = null; //s este flux de intrare int octet; sursa = new FileInputStream("fisier.txt"); octet = 0; //citesc fisierul caracter cu caracter while (octet != -1) { octet = sursa.read(); System.out.print((char)octet); } sursa.close(); } public static void main(String args[]) { try { citesteFisier(); } catch (FileNotFoundException e) { System.out.println("Fisierul nu a fost gasit !"); System.out.println("Exceptie: " + e.getMessage()); System.exit(1); } catch (IOException e) { System.out.println("Eroare de intrare/iesire"); System.out.println("Exceptie: " + e.getMessage()); System.exit(2); } } } Observati ca, in acest caz, nu mai putem diferentia exceptiile provocate de citirea din fisier si de inchiderea fisierului ambele fiind de tipul IOException. Aruncarea unei exceptii se poate face si implicit prin instructiunea throw ce are formatul: throw obiect_de_tip_Exceptie . Exemple: throw new IOException(); if (index >= vector.length) throw new ArrayIndexOutOfBoundsException(); catch(Exception e) { System.out.println("A aparut o exceptie); throw e; }

Aceasta instructune este folosita mai ales la aruncarea exceptiilor proprii care, evident, nu sunt detectate de catre mediul de executie. 2.9.5. Ierarhia claselor ce descriu exceptii Radacina claselor ce descriu exceptii este clasa Thowable iar cele mai importante subclase ale sale sunt Error, Exception(cu subclasa RuntimeException), care sunt la randul lor superclase pentru o serie intreaga de tipuri de exceptii.

Clasa Error Erorile (obiecte de tip Error) sunt cazuri speciale de exceptii generate de functionarea anormala a echipamentului hard pe care ruleaza un program Java si sunt invizibile programatorilor. Un program Java nu trebuie sa trateze aparitia acestor erori si este improbabil ca o metoda Java sa provoace asemenea erori. Clasa Exception Obiectele de acest tip sunt exceptiile standard care trebuie tratate de catre programele Java. In Java, tratarea exceptiilor nu este o optiune ci o constrangere. Exceptiile care pot "scapa" netratate sunt incadrate in subclasa RuntimeException si se numesc exceptii la executie. In general metodele care pot fi apelate pentru un obiect exceptie sunt definite in clasa Throwable si sunt publice, astfel incat pot fi apelate pentru orice tip de exceptie. Cele mai uzuale sunt: String getMessage( ) tipareste detaliul unei exceptii void printStackTrace( ) tipareste informatii despre localizarea exceptiei metoda din clasa Object, da reprezentarea ca sir de caractere a String toString( ) exceptiei 2.9.6. Exceptii la executie (RuntimeException) In general tratarea exceptiilor este obligatorie in Java. De la acest principu se sustrag insa asa numitele exceptii la executie sau, cu alte cuvinte, exceptiile care pot proveni strict din vina programatorului si nu generate de o cauza externa.

Aceste exceptii au o superclasa comuna si anume RuntimeException si in aceasta categorie sunt incluse: operatii aritmetice (impartire la zero) accesarea membrilor unui obiect ce are valoarea null operatii cu elementele unui vector (accesare unui index din afara domeniului,etc) Aceste exceptii pot aparea oriunde in program si pot fi extrem de numeroare iar incercarea de "prindere" a lor ar fi extrem de anevoioasa. Din acest motiv compilatorul permite ca aceste exceptii sa ramana netratate, tratarea lor nefiind insa ilegala. int v[] = new int[10]; try { v[10] = 0; } catch (ArrayIndexOutOfBoundsException e) { System.out.println("Atentie la indecsi!"); e.printStackTrace(); }//legal 2.9.7. Crearea propriilor exceptii Adeseori poate aparea necesitatea crearii unor exceptii proprii pentru a pune in evidenta cazuri speciale de erori provocate de clasele unei librarii, cazuri care nu au fost prevazute in ierarhia exceptiilor standard Java. O exceptie proprie trebuie sa se incadreze in ierarhia exceptiilor Java, cu alte cuvinte clasa care o implementeaza trebuie sa fie subclasa a unei clase deja existente in aceasta ierarhie, preferabil una apropiata ca semnificatie sau superclasa Exception. class MyException extends Exception { public MyException() {} public MyException(String msg) { super(msg); //apeleaza constructorul superclasei Exception } } Un exemplu de folosire a exceptiei nou create: public class TestMyException { public static void f() throws MyException { System.out.println("Exceptie in f()"); throw new MyException(); } public static void g() throws MyException { System.out.println("Exceptie in g()"); throw new MyException("aruncata din g()"); } public static void main(String[] args) { try { f(); } catch(MyException e) {e.printStackTrace();} try { g(); } catch(MyException e) {e.printStackTrace();} } }

Fraza cheie este extends Exception care specifica faptul ca noua clasa MyEception este subclasa a clasei Exception si deci implementeaza obiecte ce reprezinta exceptii. In general codul adaugat claselor pentru exceptii proprii este nesemnificativ: unul sau doi constructori care afiseaza un mesaj de eroare la iesirea standard. Rularea programului de mai sus va produce urmatorul rezultat:
Exceptie in f() lab5b.MyException Exceptie in g() at lab5b.TestMyException.f(TestMyException.java:20) at lab5b.TestMyException.main(TestMyException.java:29) lab5b.MyException: aruncata din g() at lab5b.TestMyException.g(TestMyException.java:24) at lab5b.TestMyException.main(TestMyException.java:32)

Procesul de creare a unei noi exceptii poate fi dus mai departe prin adaugarea unor noi metode clasei ce descrie acea exceptie, insa aceasta dezvoltare nu isi are rostul in majoritatea cazurilor. In general, exceptiile proprii sunt descrise de clase foarte simple chiar fara nici un cod in ele, cum ar fi: class SimpleException extends Exception { } Aceasta clasa se bazeaza pe constructorul implicit creat de compilator insa nu are constructorul SimpleException(String), care in practica nici nu este prea des folosit. 2.9.8. Excepii si suprancrcare La suprancrcarea unei metode n clasa derivata se pot arunca doar excepii specificate n metoda din clasa de baza. Prin aceasta restricie de fapt Java va asigura n mod automat realizarea operaiei de upcast, n sensul ca un cod care funcioneaz cu tipul de baza va funciona automat si cu orice tip derivat. 2.9.9. Excepii si constructori Constructorii asigura crearea obiectelor si aducerea acestora n stare valid. De aceea, la scrierea constructorilor trebuie s fim foarte ateni cum tratam excepiile. Se recomanda s nu existe excepii n interiorul constructorilor. La constructori, nu se recomanda utilizarea finally n conjuncie cu blocul try-catch daca totusi exista excepii. Deoarece finally se executa si daca constructorul reuseste, si astfel, ar aduce obiectul nou creat n stare invalid. Se recomanda realizarea unei metode speciale pentru clean-up care s se execute fie n contextul superior fie la eliberarea memoriei obiectului.
//Cleanup.java // Atentie la exceptii din constructori import utilities.simpletest.*; import java.io.*; class InputFile { private BufferedReader in; public InputFile(String fname) throws Exception { try { in = new BufferedReader(new FileReader(fname)); // Other code that might throw exceptions } catch(FileNotFoundException e) { System.err.println("Could not open " + fname); // Wasn't open, so don't close it throw e;

} catch(Exception e) { // All other exceptions must close it try { in.close(); } catch(IOException e2) { System.err.println("in.close() unsuccessful"); } throw e; // Rethrow } finally { // aici nu se pune cod! Nu trebuie inchis fisierul aici } } public String getLine() { String s; try { s = in.readLine(); } catch(IOException e) { throw new RuntimeException("readLine() failed"); } return s; } public void dispose() { try { in.close(); // aici se inchide fisierul System.out.println("dispose() successful"); } catch(IOException e2) { throw new RuntimeException("in.close() failed"); } } } public class Cleanup { public static void main(String[] args) { try { InputFile in = new InputFile("Cleanup.java"); String s; int i = 1; while((s = in.getLine()) != null) System.out.println(s); // Perform line-by-line processing here... in.dispose(); } catch(Exception e) { System.err.println("Caught Exception in main"); e.printStackTrace(); } } }

La aruncarea unei excepii, compilatorul caut s gseasc cel mai apropiat handler de excepie pentru a rezolva o excepie aprut(adic cel mai apropiat bloc catch pe care s se potriveasc tipul de excepie).

CURS 6
3. Fluxuri(Intrari/Iesiri) 3.1. Ce sunt fluxurile? Adeseori programele necesita citirea unor informatii care se gasesc pe o sursa externa sau trimiterea unor informatii catre o destinatie externa. Informatia se poate gasi oriunde : intr-un fisier pe disc, in retea, in memorie sau in alt program si poate fi de orice tip: date primitive, obiecte, imagini, sunete, etc. Pentru a aduce informatii dintr-un mediu extern, un program Java trebui sa deschida un canal de comunicatie (flux) catre sursa informatiilor (fisier, memorie, socket,etc) si sa citeasca serial informatiile respective:

Similar, un program poate trimite informatii catre o destinatie externa deaschizand un canal de comunicatie (flux) catre acea destinatie si scriind serial informatiile respective:

Indiferent de tipul informatiilor, citirea/scrierea informatiilor de pe/catre un mediu extern respecta urmatorii algoritmi: Citirea Scrierea

deschide canal comunicatie deschide canal comunicatie while (mai sunt informatii) { while (mai sunt informatii) { citeste informatie scrie informatie } } inchide canal comunicati; inchide canal comunicati;

Pentru a generaliza, atat sursa externa a unor informatii cat si destinatia lor sunt vazute ca fiind niste procese care produc, respectiv consuma informatii: Definitii: Un flux este un canal de comunicatie unidirectional intre doua procese. Un proces care descrie o sursa externa de date se numeste proces producator. Un proces care descrie o destinatie externa pentru date se numeste proces consumator. Un flux care citeste date se numeste flux de intrare. Un flux care scrie date se numeste flux de iesire. Observatii: Fluxurile sunt canale de comunicatie seriale pe 8 sau 16 biti. Fluxurile sunt unidirectionale, de la producator la consumator Fiecare flux are un singur proces producator si un singur proces consumator

Intre doua procese pot exista oricate fluxuri, orice proces putand fi atat producator si consumator in acelasi timp, dar pe fluxuri diferite Consumatorul si producatorul nu comunica direct printr-o interfata de flux ci prin intermediul codului Java de tratare a fluxurilor Clasele si interfetele standard pentru lucru cu fluxuri se gasesc in pachetul java.io. Deci orice program care necesita operatii de intrare/iesire trebuie sa contina instructiunea de import a pachetului java.io:
import java.io.*;

3.2.Clasificarea fluxurilor Exista trei tipuri de clasificare a fluxurilor: 1. Dupa "directia" canalului de comunicatie deschis fluxurile se impart in: o fluxuri de intrare (pentru citirea datelor) o fluxuri de iesire (pentru scrierea datelor) 2. Dupa tipul de date pe care opereaza: o fluxuri de octeti (comunicare seriala se realizeaza pe 8 biti) o fluxuri de caractere (comunicare seriala se realizeaza pe 16 biti) 3. Dupa actiunea lor: o fluxuri primare de citire/scriere a datelor (se ocupa efectiv cu citirea/scrierea datelor) o fluxuri pentru procesarea datelor 3.3.Ierarhia claselor pentru lucrul cu fluxuri 3.3.1.Fluxuri de caractere Clasele radacina pentru ierarhia claselor ce se ocupa cu fluxurile de caractere sunt Reader (pentru fluxuri de intrare) si Writer (pentru fluxuri de iesire). Acestea sunt superclase abstracte pentru clase ce implementeaza fluxuri specializate pentru citirea/scrierea datelor pe 16 biti. Ierarhia claselor pentru fluxuri de intrare pe caractere:

Ierarhia claselor pentru fluxuri de iesire pe caractere:

Au fost puse in evidenta (colorate cu gri) fluxurile care intra in categoria fluxurilor pentru procesarea datelor. 3.3.2.Fluxuri de octeti Clasele radacina pentru ierarhia claselor ce se ocupa cu fluxurile de octeti sunt InputStream (pentru fluxuri de intrare) si OutputStream (pentru fluxuri de iesire). Acestea sunt superclase abstracte pentru clase ce implementeaza fluxuri specializate pentru citirea/scrierea datelor pe 8 biti. Ierarhia claselor pentru fluxuri de intrare pe octeti:

Ierarhia claselor pentru fluxuri de iesire pe octeti:

Au fost puse in evidenta (colorate cu gri) fluxurile care intra in categoria fluxurilor pentru procesarea datelor. Observatie: Pentru majoritatea programelor scrierea si citirea datelor se vor face prin intermediul fluxurilor de caractere deoarece acestea permit manipularea caracterelor Unicode (16-biti), in timp ce fluxurile de octeti permit doar lucrul pe 8 biti - caractere ASCII.

3.4.Metode comune fluxurilor Superclasele abstracte Reader si InputStream definesc metode similare pentru citirea datelor. Reader
int read() int read(char buf[]) int read(char buf[], offset,int length)

InputStream
int read() int read(byte buf[]) int int read(byte buf[], offset,int length) int

De asemenea ambele clase pun la dispozitie metode pentru marcarea unei locatii intrun flux, saltul peste un numar de pozitii, resetarea pozitiei curente, etc. Superclasele abstracte Writer si OutputStream sunt de asemenea paralele, definind metode similare pentru scrierea datelor. Writer
int write() int write(char buf[]) int write(char buf[], offset,int length)

OutputStream
int write() int write(byte buf[]) int int write(byte buf[], offset,int length) int

Inchiderea oricarui flux se realizeaza prin metoda close. In cazul in care aceasta nu este apelata explicit fluxul va fi automat inchis de catre colectorul de gunoaie atunci cand nu va mai exista nici o referinta la el. Metodele referitoare la fluxuri pot genera exceptii de tipul IOException. 3.5.Folosirea fluxurilor Asa cum am vazut fluxurile pot fi impartite in functie de activitatea lor, in fluxuri care se ocupa efectiv cu citirea/scrierea datelor si fluxuri pentru procesarea datelor. In continuare vom vedea care sunt cele mai importante clase din cele doua categorii si la ce folosesc acestea: 3.5.1.Fluxuri pentru citirea/scrierea efectiva a datelor Clasele ce descriu fluxuri pentru citirea/scrierea efectiva a datelor pot fi impartite in functie de tipul sursei datelor astfel: Tip sursa Fluxuri caractere
CharArrayReader, CharArrayWriter

Fluxuri octeti
ByteArrayInputStream, ByteArrayOutputStream

Memorie

Aceste fluxuri folosesc pentru scrierea/citirea informatiilor in memorie si sunt create pe un vector existent deja. Cu alte cuvinte permit tratarea vectorilor ca sursa/destinatie pentru crearea unor fluxuri de intrare/iesire. StringReader, StringWriter StringBufferInputStream

Permit tratarea sirurilor de caractere aflate in memorie ca sursa/destinatie pentru crearea

unor fluxuri de intrare/iesire. StringReader si StringWriter sunt folosite cu obiecte de tip String iar StringBufferInputStream cu obiecte de tip StringBuffer. PipedReader, PipedWriter PipedInputStream, PipedOutputStream Implementeaza componentele de intrare/iesire ale unei conducte de date (pipe). Pipe-urile sunt folosite pentru a canaliza iesirea unui program sau fir de executie catre intrarea altui program sau fir de executie FileReader, FileWriter FileInputStream, FileOutputStream Numite si fluxuri fisier, acestea sunt folosite pentru citirea datelor dintr-un fisier, respectiv scrierea datelor intr-un fisier

Pipe

Fisier

3.5.2.Fluxuri pentru procesarea datelor Clasele ce descriu fluxuri pentru procesarea datelor pot fi impartite in functie de tipul de procesare pe care il efectueaza: Tip procesare Fluxuri caractere Fluxuri octeti

BufferedReader,BufferedWriter BufferedInputStream,BufferedOutputStream

"Bufferizare" Sunt folosite pentru a introduce un buffer in procesul de scriere/citire a informatiilor, reducind astfel
numarul de accese la dispozitivul ce reprezinta sursa originala de date. Sunt mult mai eficiente decit fluxurile fara buffer si din acest motiv se recomanda folosirea lor ori de cite ori este posibil FilterReader, FilterWriter InputStreamReader, OutputStreamWriter FilterInputStream, FilterOutputStream Sunt clase abstracte ce definesc o interfata pentru fluxuri care filtreaza automat datele citite sau scrise

Filtrare

Conversie octeticaractere

Formeaza o punte de legatura intre fluxurile de caractere si fluxurile de octeti. Un flux InputStreamReader citeste octeti dintr-un flux InputStream si ii converteste la caractere folosind codificarea standard a caracterelor sau o codificare specificata de program. Similar, un flux OutputStreamWriter converteste caractere in octeti si trimite rezutatul catre un flux de tipul OutputStream. SequenceInputStream Concateneaza mai multe fluxuri de intrare intr-unul singur. ObjectInputStream, ObjectOutputStream Folosite pentru serializarea obiectelor. DataInputStream, DataOutputStream

Concatenare Serializare

Conversie tipuri de date Folosite .la scrierea/citirea datelor de tip primitiv intr-un format independent de masina pe care se lucreaza Numarare Citire avans Afisare in
LineNumberReader Numara liniile citite de la un flux de intrare. PushbackReader PushbackInputStream Fluxuri de intrare care au un buffer de 1-caracter(octet) in care este citit in avans si caracterul (octetul) care urmeaza celui curent citit. PrintWriter PrintStream Metode convenabile pentru afisarea informatiilor. LineNumberInputStream

3.5.3.Crearea unui flux

Orice flux este un obiect al clasei ce implementeaza fluxul respectiv. Crearea unui flux se realizeaza asadar similar cu crearea obiectelor prin instructiunea new().
Exemple: //crearea unui flux de intrare pe caractere FileReader in = new FileReader("fisier_intrare.txt"); //crearea unui flux de iesire pe caractere FileWriter out = new FileWriter("fisier_iesire.txt"); //crearea unui flux de intrare pe octeti FileInputStream in = new FileInputStream("fisier_intrare.txt"); //crearea unui flux de iesire pe octeti FileOutputStrem out = new FileOutputStream("fisier_iesire.txt");

Asadar, crearea unui flux primitiv de date care scrie/citeste informatii de la un dispozitiv extern are formatul general:
FluxPrimitiv numeFlux = new FluxPrimitiv( dispozitiv extern )

Fluxurile de procesare nu pot exista de sine statatoare ci se suprapun pe un flux primitiv de citire/scriere a datelor. Din acest motiv constructorii claselor pentru fluxurile de procesare nu primesc ca argument un dispozitiv extern de memorare a datelor ci o referinta la un flux primitiv responsabil cu citirea/scrierea efectiva a datelor:
Exemple: //crearea unui flux de intrare printr-un buffer BufferedReader in = new BufferedReader(new FileReader("fisier.in")); //echivalent cu FileReader fr = new FileReader("fisier.in"); BufferedReader in = new BufferedReader(fr); //crearea unui flux de iesire printr-un buffer BufferedWriter out = new BufferedWriter(new FileWriter("fisier.out"))); //echivalent cu FileWriter fo = new FileWriter("fisier.out"); BufferedWriter out = new BufferedWriter(fo);

Asadar, crearea unui flux pentru procesarea datelor are formatul general:
FluxProcesare numeFlux = new FluxProcesare( referintaFluxPrimitiv )

In general, fluxurile pot fi grupate in succesiuni oricit de lungi:


DataInputStream in = new DataInputStream( new BufferedInputStream( new FileInputStream("fisier.in")));

3.6.Fluxuri pentru lucrul cu fisiere (fluxuri de tip "File") Fluxurile pentru lucrul cu fisiere sunt cele mai usor de inteles. Clasele care implementeaza aceste fluxuri sunt urmatoarele:
FileReader, FileWriter FileInputStream, FileOutputStream - caractere - octeti

Constructorii acestor clase accepta ca argument un obiect care sa specifice un anume fisier. Acesta poate fi un sir de caractere, un obiect de tip File sau un obiect de tip FileDescriptor . Constructorii clasei FileReader:
public FileReader( String fileName ) throws FileNotFoundException public FileReader( File file ) throws FileNotFoundException public FileReader( FileDescriptor fd )

Constructorii clasei FileWriter:


public public public public FileWriter( String fileName ) throws IOException FileWriter( File file ) throws IOException FileWriter( FileDescriptor fd ) FileWriter( String fileName, Boolean append ) throws IOException

Cei mai uzuali constructori sunt cei care primesc ca argument numele fisierului. Acestia pot provoca exceptii de tipul FileNotFoundException in cazul in care fisierul cu numele specificat nu exista. Din acest motiv orice creare a unui flux de acest tip trebuie facuta intr-un bloc try sau metoda in care sunt create fluxurile respective trebuie sa arunce exceptiile de tipul FileNotFoundException sau de tipul superclasei IOException.
Exemplu: un program care copieaza continutul unui fisier in alt fisier: import java.io.*; public class Copy { public static void main(String[] args) throws IOException { FileReader in = new FileReader("in.txt"); FileWriter out = new FileWriter("out.txt"); int c; while ((c = in.read()) != -1) out.write(c); in.close(); out.close(); } } Obs: metoda main arunca exceptii IOException care este superclasa FileNotFoundException. Aceste exceptii nu vor "prinse" decat de interpretor si va

pentru fi afisat

un mesaj de eroare la aparitia lor. 3.7.Citirea si scrierea cu zona tampon Clasele pentru citirea/scrierea cu zona tampon sunt:
BufferedReader, BufferedWriter BufferedInputStream, BufferedOutputStream - caractere - octeti

Sunt folosite pentru a introduce un buffer in procesul de scriere/citire a informatiilor, reducand astfel numarul de accese la dispozitivul ce reprezinta sursa originala de date. Sunt mult mai eficiente decat fluxurile fara buffer si din acest motiv se recomanda folosirea lor ori de cate ori este posibil. Clasele BufferedReader si BufferedInputStream citesc in avans date si le memoreaza intr-o zona tampon (buffer). Atunci cand se executa o operatie read(), octetul citit va fi preluat din buffer. In cazul in care buffer-ul este gol citirea se face direct din flux si, odata cu citirea octetului, vor fi memorati in buffer si octetii care ii urmeaza. Similar, se lucreaza si cu clasele BufferedWriter si BufferedOutputStream. Fluxurile de citire/scriere cu buffer sunt fluxuri de procesare si sunt folosite prin suprapunere cu alte fluxuri.
Exemplu: BufferedOutputStream out = new BufferedOutputStream( new FileOutputStream("out.dat"), 1024)

Constructorii acestor clase sunt urmatorii:


BufferedReader BufferedWriter BufferedReader( Reader in ) BufferedReader( Reader in, int dimbuffer ) BufferedWriter( Writer out ) BufferedWriter( Writer out, int dim_buffer ) BufferedInputStream( InputStream in ) BufferedInputStream BufferedInputStream( dimbuffer ) InputStream in, int

BufferedOutputStream( OutputStream out ) BufferedOutputStream BufferedOutputStream( OutputStream out, int dim_buffer )

In cazul constructorilor in care dimensiunea buffer-ului nu este specificata, aceasta primeste valoarea implicita de 512 octeti. Metodele acestor clase sunt cele uzuale de tipul read si write. Pe langa acestea, clasele pentru scriere prin buffer mai au si metoda flush care goleste explicit zona tampon chiar daca aceasta nu este plina.
Exemplu: BufferedWriter out = new BufferedWriter( new FileWriter("out.dat"), 1024) //am creat un flux cu buffer de 1024 octeti for(int i=0; i<1024; i++) out.write(i); //bufferul nu este plin -> in fisier nu s-a scris nimic out.flush(); //bufferul este golit -> datele se scriu in fisier

Metoda readLine
BufferedReader br = new BufferedReader(new FileReader("in")) String input; while ((input = br.readLine()) != null) { . . . //readLine metoda specifica care citeste o linie } Metoda readLine permite citirea unui flux linie cu linie.

3.8. Concatenarea fisierelor Clasa SequenceInputStream permite unei aplicatii sa combine serial mai multe fluxuri de intrare astfel incat acestea sa apara ca un singur flux de intrare. Citirea datelor dintrun astfel de flux se face astfel: se citeste din primul flux de intrare specificat pana cand se ajunge la sfarsitul acestuia, dupa care primul flux de intrare este inchis si se deschide automat urmatorul flux de intrare din care se vor citi in continuare datele, dupa care procesul se repeta pana la terminarea tuturor fluxurilor de intrare. Constructorii acestei clase sunt: Construieste un flux secvential dintr-o multime de fluxuri de intrare. Fiecare SequenceInputStream(Enumeration e ) obiect in enumerarea primita ca parametru trebuie sa fie de tipul InputStream.
SequenceInputStream( s1, InputStream s2 ) InputStream

Construieste un flux de intrare care combina doua fluxuri s1 si s2. Primul flux citit va fi s1.

Exemplul cel mai elocvent de folosirea a acestei clase este concatenarea a doua fisiere:
//Concatenarea a 2 fisiere ale caror nume sunt primite //comanda //Rezultatul concatenarii este afisat pe ecran import java.io.*; public class Concatenare1 { public static void main(String args[]) throws IOException { FileInputStream f1 = new FileInputStream(args[0]); FileInputStream f2 = new FileInputStream(args[1]); la linia de

SequenceInputStream s = new SequenceInputStream(f1, f2); int c; while ((c = s.read()) != -1) System.out.write(c); s.close(); System.out.flush(); //f1 si f2 sunt inchise automat }//main }//class

Pentru concatenarea mai multor fisiere exista doua variante o folosirea unei enumerari - primul constructor o concatenarea pe rand a acestora folosind al 2-lea constructor; concatenarea a 3 fisiere va construi un flux de intrare astfel:
FileInputStream f1 = new FileInputStream(args[0]); FileInputStream f2 = new FileInputStream(args[1]); FileInputStream f3 = new FileInputStream(args[2]); SequenceInputStream s = new SequenceInputStream( f1, new SequenceInputStream(f2, f3));

3.9.Fluxuri pentru filtrarea datelor Un flux de filtrare se ataseaza altui flux pentru a filtra datele care sunt citite/scrise de catre acel flux. Clasele pentru fluxuri de filtrare au ca superclase clasele abstracte FilterInputStream (pentru filtrarea fluxurilor de intrare) si FilterOutputStream (pentru filtrarea fluxurilor de iesire). Clasele pentru filtrarea datelor sunt:
DataInputStream, DataOutputStream BufferedInputStream, BufferedOutputStream LineNumberInputStream PushbackInputStream PrintStream (flux de iesire)

Observati ca toate aceste clase descriu fluxuri de octeti. Filtrarea datelor nu trebuie vazuta ca o metoda de a elimina anumiti octeti dintr-un flux ci de a transforma acesti octeti in date care sa poata fi interpretate sub alta forma. Asa cum am vazut la citirea/scrierea cu zona tampon clasele de filtrare BufferedInputStream si BufferedOutputStream grupeaza datele unui flux intr-un buffer, urmand ca citirea/scrierea sa se faca prin intermediu acelui buffer. Asadar fluxurile de filtrare nu elimina date citite sau scrise de un anumit flux, ci introduc o noua modalitate de manipulare a lor. Din acest motiv fluxurile de filtrare vor contine anumite metode specializate pentru citirea/scrierea datelor, altele decat cele comune tuturor fluxurilor (metode de tip read/write). Folosirea fluxurilor de filtrare se face prin atasarea lor de un flux care se ocupa efectiv de citirea/scrierea datelor:
FluxFiltrare numeFlux = new FluxFiltrare ( referintaAltFlux )

Cele mai importante clase din aceasta categorie sunt DataInputStream si DataOutputStream 3.9.1.Clasele DataInputStream si DataOutputStream Aceste clase ofera metode prin care un flux nu mai este vazut ca o insiruire de octeti, ci ca o sursa de date primitive. Prin urmare vor furniza metode pentru citirea si scrierea datelor la nivel de tip de data si nu la nivel de octet. Constructorii si metodele cele mai importante (altele decat read/write) sunt date in tabelul de mai jos :

DataInputStream

DataOuputStream

//Constructor //Constructor DataInputStream(InputStream in) DataOutputStream(OutputStream out) readBoolean( ) readByte( ) readChar( ) readDouble( ) readFloat( ) readInt( ) readLong( ) readShort( ) readUnsignedByte( ) readUnsignedShort( ) String readUTF( ) writeBoolean( boolean v ) writeByte( int v ) writeChar( int v ) writeDouble( double v ) writeFloat( float v ) writeInt( int v ) writeLong( long v ) writeShort( int v ) writeBytes( String s ) writeChars( String s ) writeUTF( String str )

Aceste metode au denumirile generice de readXXX si writeXXX specificate de interfetele DataInput si DataOutput. Pot provoca exceptii de tipul IOException. Observatie: Un fisier in care au fost scrise informatii folosind metode writeXXX nu va putea fi citit decit prin metode readXXX. 3.10. Fluxuri standard de intrare/iesire Mergand pe linia introdusa de sistemul de operare UNIX orice program Java are : o o intrare standard o o iesire standard o o iesire standard pentru erori In general intrarea standard este tastatura iar iesirea standard este ecranul. Intrarea si iesirea standard sunt de fapt niste obiecte pre-create ce descriu fluxuri de date pentru citirea respectiv scrierea la dispozitivele standard ale sistemului. Aceste obiecte sunt definite publice in clasa System si sunt: Variabila
System.in System.out System.err

Semnificatie flux standard de intrare flux standard de iesire

Tip flux
InputStream PrintStream

flux standard pentru afisarea erorilor PrintStream

3.10.l.Afisarea informatiilor pe ecran Am vazut deja numeroase exemple de folosire a fluxului standard de iesire, el fiind folosit la afisarea oricaror rezultate pe ecran (in modul consola):System.out.println("mesaj"). Fluxul standard pentru afisarea erorilor se foloseste similar:
catch (IOException e) { System.err.println("Eroare de intrare/iesire!") }

Fluxurile de iesire pot fi folosite asadar fara probleme deoarece tipul lor este a datelor. In schimb fluxul standard de o clasa abstracta, deci pentru a-l putea utiliza va trebui sa-l folosim impreuna cu un flux de procesare a datelor sau cu orice alt flux ce permite citirea efectiva a datelor.
PrintStream, clasa primitiva pentru scrierea efectiva intrare System.in este de tip InputStream care este

3.10.2.Citirea datelor de la tastatura Uzual vom dori sa folosim metoda readLine pentru citirea datelor de la tastatura si din acest motiv vom folosi intrarea standard impreuna cu o clasa de procesare care implementeaza metoda readLine. Exemplul tipic este:
BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); System.out.print("Introduceti o linie:"); String linie = stdin.readLine() System.out.println(linie);

Exemplu: un program care afiseaza liniile introduse de la tastatura


import java.io.*; public class Echo { public static void main(String[] args) { BufferedReader stdin = new BufferedReader( new InputStreamReader(System.in)); String s; try { while((s = stdin.readLine()).length() != 0) System.out.println(s); //Programul se opreste cu o linie vida } catch(IOException e) {e.printStackTrace();} } }//lab6c Observatie: Metoda readLine poate provoca exceptii de tipul IOException.

3.10.3.Redirectarea intrarii/iesirii standard Incepind cu Java 1.1 au fost introduse in clasa System metode statice pentru a redirecta fluxurile de intrare si iesire standard. Aceste metode sunt:
setIn(InputStream) setOut(PrintStream) setErr(PrintStream) - redirectare intrare - redirectare iesire - redirectare erori

Redirectarea iesirii este utila in special atunci cand sunt afisate foarte multe date pe ecran si acestea se deruleaza mai repede decat putem citi. Putem redirecta afisarea catre un fisier pe care sa-l citim dupa executia programului. Secventa clasica de redirectare a iesirii este:
PrintStream out = new PrintStream(new BufferedOutputStream( new FileOutputStream("rezultate.out"))); System.setOut (out);

Redirectarea erorilor intr-un fisier poate fi de asemenea utila.


PrintStream err = new PrintStream(new BufferedOutputStream( new FileOutputStream("erori.err"))); System.setErr (err);

Redirectarea intrarii poate fi utila pentru un program consola care primeste niste valori de intrare. Pentru a nu le scrie de la tastatura de fiecare data in timpul testarii programului ele pot fi puse intr-un fisier, redirectand intrarea standard. In momentul cand testarea programului a luat sfarsit redirectarea poate fi eliminata, datele fiind cerute din nou de la tastatura.
Exemplu de folosire a redirectarii: import java.io.*; class Redirectare { public static void main(String[] args) { try { BufferedInputStream in = new BufferedInputStream( new FileInputStream("Redirectare.java"));

PrintStream out = new PrintStream(new BufferedOutputStream( new FileOutputStream("test.out"))); System.setIn(in); System.setOut(out); System.setErr(out); BufferedReader br = new BufferedReader( new InputStreamReader(System.in)); String s; while((s = br.readLine()) != null) System.out.println(s); out.close(); } catch(IOException e) { e.printStackTrace(); } } }//lab6d

3.11. Analiza lexicala pe fluxuri (clasa StreamTokenizer) Clasa StreamTokenizer parcurge un flux de intrare de orice tip si il imparte in "atomi lexicali". Rezultatul va consta in faptul ca in loc sa se citeasca octeti sau caractere se vor citi, pe rand, atomii lexicali ai fluxului respectiv. Printr-un atom lexical se intelege in general: o un identificator (un sir care nu este intre ghilimele) o un numar o un sir de caractere o un comentariu o un separator Atomii lexicali sunt despartiti intre ei de separatori. Implicit acesti separatori sunt cei obisnuti( spatiu, tab, virgula, punct si virgula), insa pot fi schimbati prin diverse metode ale clasei. Constructorii acestei clase sunt:
public StreamTokenizer( Reader nr ) public StreamTokenizer( InputStream is )

Identificarea tipului si valorii unui atom lexical se face prin intermediul variabilelor:
TT_EOF - atom ce marcheaza sfirsitul fluxului TT_EOL - atom ce marcheaza sfirsitul unei linii TT_NUMBER - atom de tip numar TT_WORD - atom de tip cuvant nval - valoarea unui atom numeric sval - sirul continut de un atom de tip cuvant ttype - tipul ultimului atom citit din flux Citirea atomilor din flux se face cu metoda nextToken(), care returneza tipul atomului lexical citit si scrie in variabilele nval sau sval valoarea corespunzatoare atomului.

Exemplul tipic de folosire a unui analizor lexical este citirea unei secvente de numere si siruri aflate intr-un fisier sau primite de la tastatura:
//Citirea unei secvente de numere si siruri import java.io.*; public class TestTokenizer { public static void main(String args[]) throws IOException{ FileInputStream fis = new FileInputStream("test.dat"); BufferedReader br = new BufferedReader(new InputStreamReader(fis)); StreamTokenizer st = new StreamTokenizer(br); int tip = st.nextToken(); //citesc primul atom lexical while (tip != StreamTokenizer.TT_EOF) { switch (tip) {

case StreamTokenizer.TT_WORD : //cuvant System.out.println(st.sval); break; case StreamTokenizer.TT_NUMBER : //numar System.out.println(st.nval); } tip = st.nextToken();//urmatorul atom } } }//lab6e

Asadar, modul de utilizare tipic pentru un analizor lexical este intr-o bucla "while" in care se citesc atomii unul cate unul cu metoda nextToken pana se ajunge la sfarsitul fluxului (TT_EOF). In cadrul buclei "while" se afla tipul atomului curent (intors de metoda nextToken) si apoi se afla valoarea numerica sau sirul de caractere corespunzator atomului respectiv. Un exemplu mai simplu de folosire (dar nepractic) ar fi citirea unui intreg sau a unui sir de caractere de la tastatura:
//Citirea unui intreg de la tastatura import java.io.*; public class TestReadIn { public static void main(String args[]) { try{ Reader r = new InputStreamReader(System.in); StreamTokenizer st = new StreamTokenizer(r); System.out.print("n="); int tip = st.nextToken(); System.out.println("Valoarea lui n este " + (int)st.nval); } catch (IOException e) {} } }//lab6e

3.12.Alte clase pentru lucrul cu fisiere 3.12.1.Clasa RandomAccesFile (fisiere cu acces direct) Fluxurile sunt, asa cum am vazut procese secventiale de intrare/iesire. Acestea sunt adecvate pentru scrierea/citirea de pe medii secventiale de memorare a datelor cum ar fi banda magnetica,etc. desi sunt foarte utile si pentru dispozitive in care informatia poate fi accesata direct. Clasa RandomAccesFile: o permite accesul nesecvential (direct) la continutul unui fisier. o este o clasa de sine statatoare, subclasa directa a clasei Object. o se gaseste in pachetul java.io. o implementeaza interfetele DataInput si DataOutput, ceea ce inseamna ca sunt disponibile metode de tipul readXXX, writeXXX o permite atat citirea cat si scriere din/in fisiere cu acces direct o permite specificarea modului de acces al unui fisier (read-only, read-write) Constructorii acestei clase sunt:
RandomAccessFile(String numeFisier,String mod_acces) throws IOException RandomAccessFile(File fisier,String mod_acces) throws IOException unde mod_acces poate fi: "r" - fisierul este deschis numai pentru citire (read-only) "rw" - fisierul este deschis pentru citire si scriere (read-write)

Exemple:
RandomAccesFile f1 = new RandomAccessFile("fisier.txt", "r"); //deschide un fisier pentru citire RandomAccesFile f2 = new RandomAccessFile("fisier.txt", "rw");

//deschide un fisier pentru scriere si citire Clasa RandomAccesFile suporta notiunea de pointer

de fisier. Acesta este un indicator ce specifica pozitia curenta in fisier. La deschiderea unui fisier pointerul are valoarea 0, indicand inceputul fisierului. Apeluri la metode readXXX sau writeXXX deplaseaza pointerul fisierului cu numarul de octeti cititi sau scrisi de metodele respective.

In plus fata de metodele de citire/scriere clasa pune la dispozitie si metode pentru controlul pozitiei pointerului de fisier. Acestea sunt:
int skipBytes ( int n ) void seek pozitie) (long

Muta pointerul fisierului inainte cu un numar specificat de octeti Pozitioneaza specificat. pointerului fisierului inaintea octetului

long getFilePointer ( )

Returneaza pozitia pointerului de fisier (pozitia de la care se citeste/la care se scrie)

3.12.2.Clasa File Clasa File are un nume inselator, intrucat ea nu se refera doar la un fisier ci poate reprezenta fie un fisier anume, fie multimea fisierelor dintr-un director. O instanta a acestei clase poate sa reprezinte asadar: un fisier sau un director. Specificarea unui fisier/director se face prin specificare caii absolute spre acel fisier sau a caii relative fata de directorul curent. Acestea trebuie sa respecte conventiile de specificare a cailor si numelor fisierelor de pe masina gazda. Utilitate clasei File consta in furnizarea unei modalitati de a abstractiza dependentele cailor si numelor fisierelor fata de masina gazda precum si punerea la dispozitie a unor metode pentru lucrul cu fisiere si directoare la nivelul sistemului de operare. Astfel, in aceasta clasa vom gasi metode pentru testarea existentei, stergerea, redenumirea unui fisier sau director, crearea unui director, listarea fisierelor dintr-un director, etc. Trebuie mentionat si faptul ca majoritatea constructorilor fluxurilor care permit accesul la fisiere accepta ca argument un obiect de tip File in locul unui sir ce reprezinta numele fisierului accesat.
File f_in = new File("fisier.txt"); FileInputStream st_in = new FileInputStream(f_in) Cel mai uzual constructor al clasei File este: public File( String Metodele mai importante ale clasei File sunt: boolean isDirectory( ) boolean isFile( ) String String String String getName( ) getPath( ) getAbsolutePath() getParent() fisier).

Testeaza daca un obiect File>/tt> reprezinta


un fisier sau un director

Afla numele (fara cale), calea fisierului sau directorului reprezentat de obiectul respectiv

boolean boolean boolean boolean boolean dest)

exists( ) delete( ) mkdir( ) mkdirs( ) renameTo(File

Testeaza daca exista un anumit fisier/director Sterge fisierul/directorul reprezentat de obiect Creeaza un director Creeaza o succesiune de directoare Redenumeste un fisier/director Creeaza o lista cu numele fisierelor dintr-un director Creeaza o lista cu numele fisierelor dintr-un director filtrate dupa un anumit criteriu specificat. Testeaza daca un anumit fisier poate fi folosit pentru citire, respectiv scriere Afla lungimea si data ultimei modificari a unui fisier.

String[] list( ) String[] list (FilenameFilter filter ) boolean canRead( ) boolean canWrite( ) long length( ) long lastModified( )

CURS 7 4. Interfete
4.1. Introducere 4.1.1.Ce este o interfata ? Interfetele duc conceptul de clasa abstracta cu un pas inainte prin eliminarea oricarei implementari a metodelor, punand in practica unul din conceptele POO de separare a modelului unui obiect (interfata) de implementarea sa. Asadar, o interfata poate fi privita ca un protocol de comunicare intre obiecte. O interfata Java defineste un set de metode dar nu specifica nici o implementare pentru ele. O clasa care implementeaza o interfata trebuie obligatoriu sa specifice implementari pentru toate metodele interfetei, supunandu-se asadar unui anumit comportament. Definitie O interfata este o colectie de metode fara implementare si declaratii de constante 4.1.2.Definirea unei interfete Definirea unei interfete se face prin intermediul cuvantului cheie interface: [public] interface NumeInterfata [extends SuperInterfata1 [,extends SuperInterfata2...]] { //corpul interfetei:constante si metode abstracte } O interfata poate avea un singur modificator: public. O interfata publica este accesibila tuturor claselor indiferent de pachetul din care fac parte. O interfata care nu este publica este accesibila doar claselor din pachetul din care face parte interfata. O clasa poate extinde oricate interfete. Acestea se numesc superinterfete si sunt separate prin virgula. Corpul unei interfete contine: constante: acestea pot fi sau nu declarate cu modificatorii public, static si final care sunt impliciti; nici un alt modificator nu poate aparea in declaratia unei variabile a unei interfete. Constantele dintr-o interfata trebuie obligatoriu initializate.
interface NumeInterfata { int MAX = 100; //echivalent cu public static final int MAX = 100; int MAX; //ilegal - fara initializare private int x = 1; //ilegal }

metode fara implementare: acestea pot fi sau nu declarate cu modificatorul public care este implicit; nici un alt modificator nu poate aparea in declaratia unei metode a unei interfete.
interface NumeInterfata { void metoda(); public void metoda(); protected void metoda2(); //echivalent cu //ilegal

Observatii: Variabilele unei interfete sunt implicit publice chiar daca nu sunt declarate cu modificatorul public. Variabilele unei interfete sunt implicit constante chiar daca nu sunt declarate cu modificatorii static si final. Metodele unei interfete sunt implicit publice chiar daca nu sunt declarate cu modificatorul public.

In variantele mai vechi de Java era permis si modificatorul abstract in declaratia interfetei si in declaratia metodelor, insa a fost eliminat deoarece atit interfata cit si metodele sale sunt implicit abstracte. 4.1.3.Implementarea unei interfete Se face prin intermediul cuvintului cheie implements: class NumeClasa implements NumeInterfata sau class NumeClasa implements Interfata1, Interfata2... O clasa poate implementa oricate interfete. O clasa care implementeaza o interfata trebuie obligatoriu sa specifice cod pentru toate metodele interfetei. Din acest motiv, odata creata si folosita la implementarea unor clase, o interfata nu mai trebuie modificata, in sensul ca adaugarea unor metode noi sau schimbarea signaturii metodelor existente va duce la erori in compilarea claselor care o implementeaza. Modificarea unei interfete implica modificarea tuturor claselor care implementeaza acea interfata! Implementarea unei interfete poate sa fie si o clasa abstracta. 4.1.4.Exemplu de interfata
interface Instrument { //defineste o metoda fara implementare void play(); } class Pian implements Instrument { //clasa care implementeaza interfata //trebuie obligatoriu sa implementeze metoda play public void play() { System.out.println("Pian.play()"); } } class Vioara implements Instrument { //clasa care implementeaza interfata //trebuie obligatoriu sa implementeze metoda play public void play() { System.out.println("Vioara.play()"); } } public class Muzica { //clasa principala static void play(Instrument i) { //metoda statica care porneste un instrument generic //ce implementeaza interfata Instrument i.play(); } static void playAll(Instrument[] e) { for(int i = 0; i < e.length; i++) play(e[i]); } public static void main(String[] args) { Instrument[] orchestra = new Instrument[2]; int i = 0; orchestra[i++] = new Pian(); orchestra[i++] = new Vioara(); playAll(orchestra); } }

Se observa ca folosind interfata Instrument putem adauga noi clase de instrumente fara a schimba codul metodelor play si playAll din clasa principala intrucat acestea primesc ca parametru un instrument generic. Observatie : O interfata nu este o clasa, dar orice referinta la un obiect de tip interfata poate primi ca valoare o referinta la un obiect al unei clase ce implementeaza interfata respectiva (upcast). Din acest motiv interfetele pot fi privite ca tipuri de date. 4.2. Diferente intre o interfata si o clasa abstracta La prima vedere o interfata nu este altceva decat o clasa abstacta in care toate metodele sunt abstracte (nu au nici o implementare). Asadar o clasa abstracta nu ar putea inlocui o interfata ? Raspunsul la intrebare este Nu. Deosebirea consta in faptul ca unele clase sunt fortate sa extinda o anumita clasa (de exemplu orice applet trebuie sa fie subclasa a clasei Applet) si nu ar mai putea sa extinda o clasa abstracta deoarece in Java nu exista decat mostenire simpla. Fara folosirea interfetelor nu am putea forta clasa respectiva sa respecte un anumit protocol. La nivel conceptual diferenta consta in: o extinderea unei clase abstracte forteaza o relatie intre clase o implementarea unei interfete specifica doar necesitatea implementarii unor anumite metode 4.3. Mostenire multipla prin intermediul interfetelor Interfetele nu au nici o implementare si nu ocupa spatiu de memorie la instantierea lor. Din acest motiv nu reprezinta nici o problema ca anumite clase sa implementeze mai multe interfete sau ca o interfata sa extinda mai multe interfete (sa aiba mai multe superinterfete)
class NumeClasa implements Interfata1, Interfata2, ... interface NumeInterfata extends Interfata1, Interfata2, ...

O interfata mosteneste atat constantele cat si declaratiile de metode de la superinterfetele sale. O clasa mosteneste doar constantele unei interfete. Exemplu de clasa care implementeaza mai multe interfete:
interface Inotator { void inoata(); } interface Zburator { void zboara(); } class Luptator { public void lupta() {} } class Erou extends Luptator implements Inotator, Zburator { public void inoata() {} public void zboara() {} }

Exemplu de interfata care extinde mai multe interfete :


interface Monstru { void ameninta(); } interface MonstruPericulos extends Monstru { void distruge(); } interface Mortal { void omoara(); } interface Vampir extends MonstruPericulos, Mortal { void beaSange();

} class Dracula implements Vampir { public void ameninta() {} public void distruge() {} public void omoara(); public void beaSange() {} }

Observatii: O clasa nu poate avea decat o superclasa O clasa poate implementa oricate interfete O clasa mosteneste doar constantele unei interfete O clasa nu poate mosteni implementari de metode dintr-o interfata Ierarhia interfetelor este independenta de ierarhia claselor care le implementeaza 4.4.Utilitatea interfetelor O interfata defineste un protocol ce poate fi implementat de orice clasa, indiferent de ierarhia de clase din care face parte. Interfetele sunt utile pentru: o definirea unor similaritati intre clase independente fara a forta artificial o legatura intre ele. o asigura ca toate clasele care implementeaza o interfata pun la dipozitie metodele specificate in interfata; de aici rezulta posibilitatea implementarii unitare a unor clase prin mai multe modalitati. o specificarea metodelor unui obiect fara a deconspira implementarea lor (aceste obiecte se numesc anonime si sunt folosite la livrarea unor pachete cu clase catre alti programatori: acestia pot folosi clasele respective dar nu pot vedea implementarile lor efective) o definirea unor grupuri de constante o transmiterea metodelor ca parametri (tehnica Call-Back). 4.4.1.Crearea grupurilor de constante Deoarece orice variabila a unei interfete este implicit declarata cu public, static si final interfetele reprezinta o metoda convenabila de creare a unor grupuri de constante, similar cu enum din C++.
public interface Luni { int IAN=1, FEB=2, ..., DEC=12; }

Folosirea acestor constante se face prin expresii de genul NumeInterfata.constanta :


if (luna < Luni.DEC) luna ++ else luna = Luni.IAN;

4.4.2.Transmiterea metodelor ca parametri (call-back) Transmiterea metodelor ca parametri se face in C++ cu ajutorul pointerilor. In Java aceasta tehnica este implementata prin intermediul interfetelor. Vom ilustra acest lucru prin intermediul unui exemplu. Explorarea unui graf

In fiecare nod trebuie sa se execute prelucrarea informatiei din el prin intermediul unei functii primite ca parametru.
interface functie { public int executie(int arg); } class Graf { //... void explorare(functie f) { //... if explorarea a ajuns in nodul v f.executie(v.valoare); //... } } //Definim doua functii class f1 implements functie { public int executie(int arg) { return arg+1; } } class f2 implements functie { public int executie(int arg) { return arg*arg; } } public class TestCallBack { public static void main(String args[]) { Graf G = new Graf(); G.explorare(new f1()); G.explorare(new f2()); } }

4.5. Interfata FilenameFilter Instantele claselor ce implementeaza aceasta interfata sunt folosite pentru a crea filtre pentru fisiere si sunt primite ca argumente de metode care listeaza continutul unui director, cum ar fi metoda list a clasei File. Aceasta interfata are o singura metoda accept care specifica criteriul de filtrare si anume, testeaza daca numele fisierului primit ca parametru indeplineste conditiile dorite de noi. Definitia interfetei:
public interface FilenameFilter { // Metode public boolean accept( File dir, String numeFisier ); }

Asadar orice clasa de specificare a unui filtru care implementeza interfata FilenameFilter trebuie sa implementeze metoda accept a acestei interfete. Aceste clase mai pot avea si alte metode, de exemplu un constructor care sa primeasca criteriul de filtrare, adica masca dupa care se filtreaza fisierele. In general, o clasa de specificare a unui filtru are urmatorul format:
class DirFilter implements FilenameFilter { String filtru; //constructorul DirFilter(String filtru) { this.filtru = filtru; } //implementarea metodei accept public boolean accept(File dir, String nume) { //elimin informatiile despre calea fisierului

String f = new File(nume).getName(); if (filtrul este indeplinit) return true; else return false; } }

Metodele cele mai uzuale ale clasei String folosite pentru filtrarea fisierelor sunt: boolean endsWith(String s) //testeaza daca un sir se termina cu sirul specificat s int indexOf(String s) //testeaza daca un sirul are ca subsir sirul specificat s //returneaza 0=nu este subsir, >0=pozitia subsirului Instantele claselor pentru filtrare sunt primite ca argumente de metode de listare a continutului unui director. O astfel de metoda este metoda list a clasei File:
String[] list (FilenameFilterifiltru )

Observati ca aici interfata este folosita ca un tip de date, ea fiind substituita cu orice clasa care o implementeaza. Acesta este un exemplu tipic de transmitere a unei functii (functia de filtrare accept) ca argument al unei metode. Listarea fisierelor din directorul curent care au extensia .java
import java.io.*; public class DirList2 { public static void main(String[] args) { try { File director = new File("."); String[] list; list = director.list(new FiltruExtensie("java")); for(int i = 0; i < list.length; i++) System.out.println(list[i]); } catch(Exception e) { e.printStackTrace(); } } } class FiltruExtensie implements FilenameFilter { String extensie; FiltruExtensie (String extensie) { this.extensie = extensie; } public boolean accept (File dir, String nume) { return ( nume.endsWith("." + extensie) ); } }

Exemplu de folosire a claselor anonime In cazul in care nu avem nevoie de filtrarea fisierelor dintr-un director decat o singura data, pentru a evita crearea unei noi clase care sa fie folosita pentru filtrare putem apela la o clasa interna anonima, aceasta situatie fiind un exemplu tipic de folosire a acestora.
import java.io.*; public class DirList3 { public static void main(String[] args) { try { File director = new File("."); String[] list; //folosim o clasa anonima pentru specificarea filtrului list = director.list(new FilenameFilter() {

public boolean accept (File dir,String nume) return ( nume.endsWith(".java")); } } ); for(int i = 0; i < list.length; i++) System.out.println(list[i]); } catch(Exception e) { e.printStackTrace(); } } }

4.6.Adaptori In cazul n care o interfa conine mai multe metode i, la un moment dat, avem nevoie de un obiect care implementeaz interfaa respectiva dar nu specific cod dect pentru o singur metod, el trebui totui s implementeze toate metodele interfeei, chiar dac nu specific nici un cod.
interface X { void metoda_1(); void metoda_2(); ... void metoda_n(); } ... // Avem nevoie de un obiect de tip X // ca argument al unei functii functie(new X() { public void metoda_1() { // Singura metoda care ne intereseaza ... } // Trebuie sa apara si celelalte metode // chiar daca nu au implementare efectiva public void metoda_2() {} public void metoda_3() {} ... public void metoda_n() {} });

Aceast abordare poate fi neplcut dac avem frecvent nevoie de obiecte ale unor clase ce implementeaz interfaa X. Soluia la aceast problem este folosirea adaptorilor. Definiie: Un adaptor este o clas abstract care implementeaz o anumit interfa fr a specifica cod nici unei metode a interfeei.
public public public ... public } abstract class XAdapter implements X { void metoda_1() {} void metoda_2() {} void metoda_n() {}

In situaia cnd avem nevoie de un obiect de tip X vom folosi clasa abstract, supradefinind doar metoda care ne intereseaz:
functie(new XAdapter() { public void metoda_1() { // Singura metoda care ne intereseaza ... } });

Mai multe exemple de folosire a adaptorilor vor fi date n capitolul Interfaa grafic cu utilizatorul. 5. Organizarea claselor 5.1 Pachete Definiie:Un pachet este o colecie de clase i interfee nrudite din punctul de vedere al funcionalitii lor. Sunt folosite pentru gsirea i utilizarea mai uoar a claselor, pentru a evita conflictele de nume i pentru a controla accesul la anumite clase. In alte limbaje de programare pachetele se mai numesc librrii sau bibilioteci. 5.1.1 Pachetele standard (J2SDK) Platforma standard de lucru Java se bazeaz pe o serie de pachete cu ajutorul crora se pot construi ntr-o manier simplificat aplicaiile. Exist deci un set de clase deja implementate care modeleaz structuri de date, algoritmi sau diverse noiuni eseniale n dezvoltarea unui program. Cele mai importante pachete i suportul oferit lor sunt: java.lang - clasele de baz ale limbajului Java java.io - intrri/ieiri, lucrul cu fiiere java.util - clase i interfee utile java.applet - dezvoltarea de appleturi java.awt - interfaa grafic cu utilizatorul java.awt.event - mecanismele de tratare e evenimentelor generate de utilizator java.beans - scrierea de componente reutilizabile java.net - programare de reea java.sql - lucrul cu baze de date java.rmi - execuie la distan Remote Message Interface java.security - mecanisme de securitate: criptare, autentificare java.math - operaii matematice cu numere mari java.text - lucrul cu texte, date i numere independent de limb java.lang.reflect - introspecie javax.swing - interfaa grafic cu utilizatorul, mult mbogit fa de AWT. ... 5.1.2 Folosirea membrilor unui pachet Conform specificaiilor de acces ale unei clase i ale membrilor ei, doar clasele publice i membrii declarai publici ai unei clase sunt accesibili n afara pachetului n care se gsesc. Dup cum am vzut n seciunea Specificatori de acces pentru membrii unei clase, accesul implicit n Java este la nivel de pachet. Pentru a folosi o clas public dintr-un anumit pachet, sau pentru a apela o metod public a unei clase publice a unui pachet, exist trei soluii: specificarea numelui complet al clasei importul clasei respective importul ntregului pachet n care se gsete clasa. Specificarea numelui complet al clasei se face prin prefixarea numelui scurt al clasei cu numele pachetului din care face parte: numePachet.NumeClasa. Button - numele scurt al clasei java.awt - pachetul din care face parte java.awt.Button - numele complet al clasei

Aceast metod este recomandat doar pentru cazul n care folosirea acelei clase se face o singur dat sau foarte rar. De exemplu, ar fi extrem de neplcut s scriem de fiecare dat cnd vrem s declarm un obiect grafic secvene de genul:
java.awt.Button b1 java.awt.Button b2 java.awt.TextField java.awt.TextField = new = new tf1 = tf2 = java.awt.Button("OK"); java.awt.Button("Cancel"); new java.awt.TextField("Neplacut"); new java.awt.TextField("Tot neplacut");

In aceste situaii, vom importa n aplicaia noastr clasa respectiv, sau ntreg pachetul din care face parte. Acest lucru se realizeaz prin instruciunea import, care trebuie s apar la nceputul fiierelor surs, nainte de declararea vreunei clase sau interfee. 5.1.3 Importul unei clase sau interfee Se face prin instruciunea import n care specificm numele complet al clasei sau interfeei pe care dorim s o folosim dintr-un anumit pachet:
import numePachet.numeClasa; //Pentru exemplul nostru: import java.awt.Button; import java.awt.TextField;

Din acest moment, vom putea folosi n clasele fiierului n care am plasat instruciunea de import numele scurt al claselor Button i TextField:
Button b1 Button b2 TextField TextField = new = new tf1 = tf2 = Button("OK"); Button("Cancel"); new TextField("Placut"); new TextField("Foarte placut");

Aceast abordare este eficient i recomandat n cazul n care nu avem nevoie dect de cteva clase din pachetul respectiv. Dac n exemplul nostru am avea nevoie i de clasele Line, Point, Rectangle, Polygon, ar trebui s avem cte o instruciune de import pentru fiecare dintre ele:
import import import import import import java.awt.Button; java.awt.TextField; java.awt.Rectangle; java.awt.Line; java.awt.Point; java.awt.Polygon;

In aceast situaie ar fi mai simplu s folosim importul la cerere din ntregul pachet i nu al fiecrei clase n parte. 5.1.4 Importul la cerere dintr-un pachet Importul la cerere dintr-un anumit pachet se face printr-o instruciune import n care specificm numele pachetului ale crui clase i interfee dorim s le folosim, urmat de simbolul *. Se numete import la cerere deoarece ncrcarea claselor se face dinamic, n momentul apelrii lor.
import numePachet.*; //Pentru exemplul nostru: import java.awt.*;

Din acest moment, vom putea folosi n clasele fiierului n care am plasat instruciunea de import numele scurt al tuturor claselor pachetului importat:
Button b = new Button("OK"); Point p = new Point(0, 0);

Observaie: * nu are semnificaia uzual de la fiiere de wildcard (masc) i nu poate fi folosit dect ca atare. O expresie de genul import java.awt.C*; va produce

o eroare de compilare. In cazul n care sunt importate dou sau mai multe pachete care conin clase (interfee) cu acelai nume, atunci referirea la ele trebuie fcut doar folosind numele complet, n caz contrar fiind semnalat o ambiguitate de ctre compilator.
import java.awt.*; // Contine clasa List import java.util.*; // Contine interfata List ... List x; //Declaratie ambigua java.awt.List a = new java.awt.List(); //corect java.util.List b = new ArrayList(); //corect

Sunt considerate importate automat, pentru orice fiier surs, urmtoarele pachete: pachetul java.lang
import java.lang.*; // Poate sau nu sa apara // Mai bine nu...

pachetul curent pachetul implicit (fr nume) 5.1.5 Importul static Aceast facilitate, introdus ncepnd cu versiunea 1.5, permite referirea constantelor statice ale unei clase fr a mai specifica numele complet al acesteia i este implementat prin adugarea cuvntului cheie static dup cel de import:
import static numePachet.NumeClasa.*;

Astfel, n loc s ne referim la constantele clasei cu expresii de tipul NumeClasa.CONSTANTA, putem folosi doar numele constantei.
// Inainte de versiuna 1.5 import java.awt.BorderLayout.*; ... fereastra.add(new Button(), BorderLayout.CENTER); // Incepand cu versiunea 1.5 import java.awt.BorderLayout.*; import static java.awt.BorderLayout.*; ... fereastra.add(new Button(), CENTER);

Observaie: Importul static nu import dect constantele statice ale unei clase, nu i clasa n sine. 5.1.6 Crearea unui pachet Toate clasele i interfeele Java apartin la diverse pachete, grupate dup funcionalitatea lor. Dup cum am vzut clasele de baz se gsesc n pachetul java.lang, clasele pentru intrri/ieiri sunt n java.io, clasele pentru interfaa grafic n java.awt, etc. Crearea unui pachet se realizeaz prin scriere la nceputul fiierelor surs ce conin clasele i interfeele pe care dorim s le grupm ntr-un pachet a instruciunii: package numePachet; S considerm un exemplu: presupunem c avem dou fiiere surs Graf.java i Arbore.java.
//Fisierul Graf.java package grafuri; class Graf {...} class GrafPerfect extends Graf {...} //Fisierul Arbore.java package grafuri;

class Arbore {...} class ArboreBinar extends Arbore {...}

Clasele Graf, GrafPerfect, Arbore, ArboreBinar vor face parte din acelai pachet grafuri. Instruciunea package acioneaz asupra ntregului fiier surs la nceputul cruia apare. Cu alte cuvinte nu putem specifica faptul c anumite clase dintr-un fiier surs aparin unui pachet, iar altele altui pachet. Dac nu este specificat un anumit pachet, clasele unui fiier surs vor face parte din pachetul implicit (care nu are nici un nume). In general, pachetul implicit este format din toate clasele i intefeele directorului curent de lucru. Este recomandat ns ca toate clasele i intefetele s fie plasate n pachete, pachetul implicit fiind folosit doar pentru aplicaii mici sau prototipuri. 5.1.7 Denumirea unui pachet Exist posibilitatea ca doi programatori care lucreaz la un proiect comun s foloseasc acelai nume pentru unele din clasele lor. De asemenea, se poate ca una din clasele unei aplicaii s aib acelai nume cu o clas a mediului Java. Acest lucru este posibil att timp ct clasele cu acelai nume se gasesc n pachete diferite, ele fiind difereniate prin prefixarea lor cu numele pachetelor. Ce se ntmpl ns cnd doi programatori care lucreaz la un proiect comun folosesc clase cu acelai nume, ce se gasesc n pachete cu acelai nume ? Pentru a evita acest lucru, companiile folosesc inversul domeniului lor Internet n denumirea pachetelor implementate n cadrul companiei, cum ar fi ro.companie.numePachet. In cadrul aceleiasi companii, conflictele de nume vor fi rezolvate prin diverse convenii de uz intern, cum ar fi folosirea numelui de cont al programatorilor n denumirea pachetelor create de acetia. De exemplu, programatorul cu numele Ion al companiei XSoft, avnd contul ion@xsoft.ro, i va prefixa pachetele cu ro.xsoft.ion, pentru a permite identificarea n mod unic a claselor sale, indiferent de contextul n care acestea vor fi integrate. 5.2 Organizarea fiierelor 5.2.1 Organizarea fiierelor surs Orice aplicaie nebanal trebuie s fie construit folosind o organizare ierarhic a componentelor sale. Este recomandat ca strategia de organizare a fiierelor surs s respecte urmtoarele convenii: Codul surs al claselor i interfeelor s se gaseasc n fiiere ale cror nume s fie chiar numele lor scurt i care s aib extensia .java. Observaie: Este obligatoriu ca o clas/interfa public s se gaseasc ntr-un fiier avnd numele clasei(interfeei) i extenisa .java, sau compilatorul va furniza o eroare. Din acest motiv, ntr-un fiier surs nu pot exista dou clase sau interfee publice. Pentru clasele care nu sunt publice acest lucru nu este obligatoriu, ci doar recomandat. Intr-un fiier surs pot exista oricte clase sau interfee care nu sunt publice. Fiierele surs trebuie s se gseasc n directoare care s reflecte numele pachetelor n care se gsesc clasele i interfeele din acele fiiere. Cu alte cuvinte, un director va conine surse pentru clase i interfee din acelai pachet iar numele directorului va fi chiar numele pachetului. Dac numele pachetelor sunt formate din mai multe uniti lexicale separate prin punct, atunci acestea trebuie de asemenea s corespund unor directoare ce vor descrie calea spre fiierele surs ale cror clase i interfee fac parte din pachetele respective. Vom clarifica modalitatea de organizare a fiierelor surs ale unei aplicatii printr-un exemplu concret. S presupunem c dorim crearea unor componente care s reprezinte diverse noiuni matematice din domenii diferite, cum ar fi geometrie, algebr, analiz, etc. Pentru a simplifica lucrurile, s presupunem c dorim s crem clase care s descrie urmtoarele notiuni:poligon, cerc, poliedru, sfer, grup, funcie.

O prim variant ar fi s construim cte o clas pentru fiecare i s le plasm n acelai director mpreuna cu un program care s le foloseasca, ns, avnd n vedere posibila extindere a aplicaiei cu noi reprezentri de noiuni matematice, aceast abordare ar fi ineficient. O abordare elegant ar fi aceea n care clasele care descriu noiuni din acelai domeniu sa se gaseasca n pachete separate i directoare separate. Ierarhia fiierelor sursa ar fi:
/matematica /surse /geometrie /plan Poligon.java Cerc.java /spatiu Poliedru.java Sfera.java /algebra Grup.java /analiza Functie.java Matematica.java

Clasele descrise n fiierele de mai sus trebuie declarate n pachete denumite corespunzator cu numele directoarelor n care se gasesc:
// Poligon.java package geometrie.plan; public class Poligon { . . . } // Cerc.java package geometrie.plan; public class Cerc { . . . } // Poliedru.java package geometrie.spatiu; public class Poliedru { . . . } // Sfera.java package geometrie.spatiu; public class Sfera { . . . } // Grup.java package algebra; public class Grup { . . . } // Functie.java package analiza; public class Functie { . . . }

Matematica.java este clasa principal a aplicaiei. Dup cum se observ, numele lung al unei clase trebuie s descrie calea spre acea clas n cadrul fiierelor surs, relativ la directorul n care se gsete aplicaia. 5.2.2 Organizarea unitilor de compilare (.class) In urma compilrii fiierelor surs vor fi generate uniti de compilare pentru fiecare clas i interfa din fiierele surs. Dup cum tim acestea au extensia .class i numele scurt al clasei sau interfeei respective. Spre deosebire de organizarea surselor, un fiier .class trebuie s se gaseasca ntr-o ierarhie de directoare care s reflecte numele pachetului din care face parte clasa respectiv. Implicit, n urma compilrii fiierele surs i unitile de compilare se gsesc n acelai director, ns ele pot fi apoi organizate separat. Este recomandat ns ca aceast separare s fie fcut automat la compilare. Revenind la exemplul de mai sus, vom avea urmtoarea organizare:
/matematica

/clase /geometrie /plan Poligon.class Cerc.class /spatiu Poliedru.class Sfera.class /algebra Grup.class /analiza Functie.class Matematica.class

Crearea acestei structuri ierarhice este facut automat de ctre compilator. In directorul aplicatiei (matematica) crem subdirectorul clase i dm comanda:
javac -sourcepath surse surse/Matematica.java -d clase

sau
javac -classpath surse surse/Matematica.java -d clase

Opiunea -d specific directorul rdcin al ierarhiei de clase. In lipsa lui, fiecare unitate de compilare va fi plasat n acelai director cu fiierul su surs. Deoarece compilm clasa principal a aplicaiei, vor fi compilate n cascad toate clasele referite de aceasta, dar numai acestea. In cazul n care dorim s compilm explicit toate fiierele java dintr-un anumit director, de exemplu surse/geometrie/plan, putem folosi expresia:
javac surse/geometrie/plan/*.java -d clase

5.2.3 Necesitatea organizrii fiierelor Organizarea fiierelor surs este necesar deoarece n momentul cnd compilatorul ntlneste un nume de clas el trebuie s poat identifica acea clas, ceea ce nseamna c trebuie s gaseasc fiierul surs care o conine. Similar, unitile de compilare sunt organizate astfel pentru a da posibilitatea interpretorului s gaseasc i s ncarce n memorie o anumit clas n timpul execuiei programului. Ins aceast organizare nu este suficient deoarece specific numai partea final din calea ctre fiierele .java i .class, de exemplu /matematica/clase/geometrie/plan/Poligon.class. Pentru aceasta, att la compilare ct i la interpretare trebuie specificat lista de directoare rdcin n care se gsesc fiierele aplicaiei. Aceast list se numete cale de cautare (classpath). Definiie: O cale de cutare este o list de directoare sau arhive n care vor fi cutate fiierele necesare unei aplicaii. Fiecare director din calea de cautare este directorul imediat superior structurii de directoare corespunztoare numelor pachetelor n care se gsesc clasele din directorul respectiv, astfel nct compilatorul i interpretorul s poat construi calea complet spre clasele aplicaiei. Implicit, calea de cutare este format doar din directorul curent. S considerm clasa principal a aplicaiei Matematica.java:
import geometrie.plan.*; import algebra.Grup; import analiza.Functie; public class Matematica { public static void main(String args[]) { Poligon a = new Poligon(); geometrie.spatiu.Sfera s= new geometrie.spatiu.Sfera(); //... } }

Identificarea unei clase referite n program se face n felul urmtor: La directoarele aflate n calea de cutare se adaug subdirectoarele specificate n import sau n numele lung al clasei In directoarele formate este cutat un fiier cu numele clasei. In cazul n care nu este gsit nici unul sau sunt gsite mai multe va fi semnalat eroare.

5.2.4 Setarea cii de cutare (CLASSPATH) Setarea cii de cutare se poate face n dou modaliti: Setarea variabilei de mediu CLASSPATH - folosind aceast variant toate aplicaiile Java de pe maina respectiv vor cuta clasele necesare n directoarele specificate n variabila CLASSPATH.
UNIX: SET CLASSPATH = cale1:cale2:... DOS shell (Windows 95/NT/...): SET CLASSPATH = cale1;cale2;...

Folosirea opiunii -classpath la compilarea i interpretarea programelor directoarele specificate astfel vor fi valabile doar pentru comanda curent:
javac - classpath <cale de cautare> <surse java> java - classpath <cale de cautare> <clasa principala>

Lansarea n execuie a aplicatiei noastre, din directorul matematica, se va face astfel:


java -classpath clase Matematica

In concluzie, o organizare eficient a fiierelor aplicaiei ar arta astfel:


/matematica /surse /clase compile.bat (javac -sourcepath surse surse/Matematica.java -d clase) run.bat (java -classpath clase Matematica)

5.3. Arhive JAR Fiierele JAR (Java Archive) sunt arhive n format ZIP folosite pentru mpachetarea aplicaiilor Java. Ele pot fi folosite i pentru comprimri obinuite, diferena fa de o arhiv ZIP obinuit fiind doar existena unui director denumit META-INF, ce conine diverse informaii auxiliare legate de aplicaia sau clasele arhivate. Un fiier JAR poate fi creat folosind utilitarul jar aflat n distribuia J2SDK, sau metode ale claselor suport din pachetul java.util.jar. Dintre beneficiile oferite de arhivele JAR amintim: portabilitate - este un format de arhivare independent de platform; compresare - dimensiunea unei aplicaii n forma sa final este redus; minimizarea timpului de ncarcare a unui applet: dac appletul (fiiere class, resurse, etc) este compresat ntr-o arhiv JAR, el poate fi ncrcat ntr-o singur tranzacie HTTP, fr a fi deci nevoie de a deschide cte o conexiune nou pentru fiecare fiier; securitate - arhivele JAR pot fi semnate electronic mecanismul pentru lucrul cu fiiere JAR este parte integrata a platformei Java. 5.3.1 Folosirea utilitarului jar Arhivatorul jar se gsete n subdirectorul bin al directorului n care este instalat kitul J2SDK. Mai jos sunt prezentate pe scurt operaiile uzuale:

Crearea unei arhive


jar cf arhiva.jar fiier(e)-intrare

Vizualizare coninutului
jar tf nume-arhiva

Extragerea coninutului
jar xf arhiva.jar

Extragerea doar a unor fiiere


jar xf arhiva.jar fiier(e)-arhivate

Executarea unei aplicaii


java -jar arhiva.jar

Deschiderea unui applet arhivat


<applet code=A.class archive="arhiva.jar" ...>

Exemple: Arhivarea a dou fiiere class:


jar cf classes.jar A.class B.class

arhivarea tuturor fiierelor din directorul curent:


jar cvf allfiles.jar *

5.3.2. Executarea aplicaiilor arhivate Pentru a rula o aplicaie mpachetat ntr-o arhiv JAR trebuie s facem cunoscut interpretorului numele clasei principale a aplicaiei. S considerm urmtorul exemplu, n care dorim s arhivm clasele aplicaiei descrise mai sus, n care clasa principal era Matematica.java. Din directorul clase vom lansa comanda:
jar cvf mate.jar geometrie analiza algebra Matematica.class In urma acestei comenzi vom obtine arhiva mate.jar. Dac vom ncerca s lansm n execuie aceast arhiv prin comanda java -jar mate.jar vom obine urmtoarea eroare:

Failed to load Main-Class manifest from mate.jar. Aceasta nseamna c n fisierul Manifest.mf ce se gasete n directorul META-INF trebuie s nregistrm clasa principal a aplicaiei. Acest lucru l vom face n doi pai: se creeaz un fiier cu un nume oarecare, de exemplu manifest.txt, n care vom scrie:
Main-Class: Matematica

adaugm aceast informaie la fiierul manifest al arhivei mate.jar:


jar uvfm mate.jar manifest.txt

Ambele operaii puteau fi executate ntr-un singur pas:


jar cvfm mate.jar manifest.txt geometrie analiza algebra Matematica.class

Pe sistemele Win32, platforma Java 2 va asocia extensiile .jar cu interpretorul Java, ceea ce nseamn c facnd dublu-click pe o arhiv JAR va fi lansat n execuie aplicaia mpachetat n acea arhiv (dac exist o clas principal).

CURS 8 6. Interfaa grafic cu utilizatorul 6.1 Introducere Interfaa grafic cu utilizatorul (GUI), este un termen cu neles larg care se refer la toate tipurile de comunicare vizual ntre un program i utilizatorii si. Aceasta este o particularizare a interfeei cu utilizatorul (UI), prin care vom ntelege conceptul generic de interaciune dintre program i utilizatori. Limbajul Java pune la dispoziie numeroase clase pentru implementarea diverselor funcionalitati UI, ns ne vom ocupa n continuare de cele care permit realizarea intefeei grafice cu utilizatorul (GUI). De la apariia limbajului Java, bibliotecile de clase care ofer servicii grafice au suferit probabil cele mai mari schimbri n trecerea de la o versiune la alta. Acest lucru se datoreaz, pe de o parte dificultii legate de implementarea noiunii de portabilitate, pe de alt parte nevoii de a integra mecanismele GUI cu tehnologii aprute i dezvoltate ulterior, cum ar fi Java Beans. In momentul actual, exist dou modaliti de a crea o aplicaie cu interfa grafic i anume: AWT(Abstract Windowing Toolkit) - este API-ul iniial pus la dispoziie ncepnd cu primele versiuni de Java; Swing - parte dintr-un proiect mai amplu numit JFC (Java Foundation Classes) creat n urma colaborrii dintre Sun, Netscape i IBM, Swing se bazeaz pe modelul AWT, extinznd funcionalitatea acestuia i adugnd sau nlocuind componente pentru dezvoltarea aplicaiilor GUI. Aadar, este de preferat ca aplicaiile Java s fie create folosind tehnologia Swing, aceasta punnd la dispoziie o palet mult mai larg de faciliti, ns nu vom renuna complet la AWT deoarece aici exist clase eseniale, reutilizate n Swing. In acest capitol vom prezenta clasele de baz i mecanismul de tratare a evenimentelor din AWT, deoarece va fi simplificat procesul de nelegere a dezvoltrii unei aplicaii GUI, dup care vom face trecerea la Swing. In principiu, crearea unei aplicaii grafice presupune urmtoarele lucruri: Design Crearea unei suprafee de afiare (cum ar fi o fereastr) pe care vor fi aezate obiectele grafice (componente) care servesc la comunicarea cu utilizatorul (butoane, controale pentru editarea textelor, liste, etc); Crearea i aezarea componentelor pe suprafaa de afiare la poziiile corespunztoare; Funcionalitate Definirea unor aciuni care trebuie s se execute n momentul cnd utilizatorul interacioneaz cu obiectele grafice ale aplicaiei; Ascultarea evenimentelor generate de obiecte n momentul interaciunii cu utilizatorul i executarea aciunilor corespunztoare, aa cum au fost ele definite. 6.2 Modelul AWT Pachetul care ofer componente AWT este java.awt.

Obiectele grafice sunt derivate din Component, cu excepia meniurilor care descind din clasa MenuComponent. Aadar, prin noiunea de component vom ntelege n continuare orice obiect care poate avea o reprezentare grafic i care poate interactiona cu utilizatorul. Exemple de componente sunt ferestrele, butoanele, listele, bare de defilare, etc. Toate componentele AWT sunt definite de clase proprii ce se gasesc n pachetul java.awt, clasa Component fiind superclasa abstract a tuturor acestor clase. Crearea obiectelor grafice nu realizeaz automat i afiarea lor pe ecran. Mai nti ele trebuie aezate pe o suprafata de afiare, care poate fi o fereastr sau un applet, i vor deveni vizibile n momentul n care suprafaa pe care sunt afiate va fi vizibil. O astfel de suprafa pe care sunt plasate componente se mai numete container i reprezint o instan a unei clase derivate din Container. Clasa Container este o subclas aparte a lui Component, fiind la rndul ei superclasa tuturor suprafetelor de afiare Java. Aa cum am vzut, interfaa grafic servete interaciunii cu utilizatorul. De cele mai multe ori programul trebuie s fac o anumit prelucrare n momentul n care utilizatorul a efectuat o aciune i, prin urmare, componentele trebuie s genereze evenimente n funcie de aciunea pe care au suferit-o (aciune transmis de la tastatur, mouse, etc.). Incepnd cu versiunea 1.1 a limbajului Java, evenimentele sunt instane ale claselor derivate din AWTEvent. Aadar, un eveniment este produs de o aciune a utilizatorului asupra unui obiect grafic, deci evenimentele nu trebuie generate de programator. In schimb, ntr-un program trebuie specificat codul care se execut la apariia unui eveniment. Tratarea evenimentelor se realizeaz prin intermediul unor clase de tip listener (asculttor, consumator de evenimente), clase care sunt definite n pachetul java.awt.event. In Java, orice component poate consuma evenimentele generate de o alt component (vezi Tratarea evenimentelor). S considerm un mic exemplu, n care crem o fereastr ce conine dou butoane. O fereastr cu dou butoane
import java . awt .*; public class ExempluAWT1 { public static void main ( String args []) { // Crearea ferestrei - un obiect de tip Frame Frame f = new Frame ("O fereastra "); // Setarea modului de dipunere a componentelor f. setLayout (new FlowLayout ()); // Crearea celor doua butoane Button b1 = new Button ("OK"); Button b2 = new Button (" Cancel "); // Adaugarea butoanelor f.add(b1); f.add(b2); f. pack (); // Afisarea fereastrei f.setVisible(true); } }

Dup cum vei observa la execuia acestui program, att butoanele adugate de noi ct i butonul de nchidere a ferestrei sunt funcionale, adic pot fi apasate, dar nu

realizeaz nimic. Acest lucru se ntmpl deoarece nu am specificat nicieri codul care trebuie s se execute la apsarea acestor butoane. De asemenea, mai trebuie remarcat c nu am specificat nicieri dimensiunile ferestrei sau ale butoanelor i nici pozitiile n care s fie plasate acestea. Cu toate acestea ele sunt plasate unul lnga celalalt, fr s se suprapun iar suprafaa fereastrei este suficient de mare ct s cuprind ambele obiecte. Aceste fenomene sunt provocate de un obiect special de tip FlowLayout pe care l-am specificat i care se ocup cu gestionarea ferestrei i cu plasarea componentelor ntr-o anumit ordine pe suprafaa ei. Aadar, modul de aranjare nu este o caracteristic a suprafeei de afiare ci, fiecare container are asociat un obiect care se ocup cu dimensionarea i dispunerea componentelor pe suprafaa de afiare i care se numeste gestionar de poziionare (layout manager) (vezi Gestionarea poziionrii). 6.2.1 Componentele AWT Dup cum am spus deja, toate componentele AWT sunt definite de clase proprii ce se gasesc n pachetul java.awt, clasa Component fiind superclasa abstracta a tuturor acestor clase. Button - butoane cu eticheta format dintr-un text pe o singur linie; Canvas - suprafa pentru desenare; Checkbox - component ce poate avea dou stri; mai multe obiecte de acest tip pot fi grupate folosind clasa CheckBoxGroup; Choice - liste n care doar elementul selectat este vizibil i care se deschid la apsarea lor; Container - superclasa tuturor suprafeelor de afiare (vezi Suprafee de afiare); Label - etichete simple ce pot conine o singur linie de text needitabil; List - liste cu selecie simpl sau multipl; Scrollbar - bare de defilare orizontale sau verticale; TextComponent - superclasa componentelor pentru editarea textului: TextField (pe o singur linie) i TextArea (pe mai multe linii). Mai multe informaii legate de aceste clase vor fi prezentate n seciunea Folosirea componentelor AWT. Din cauza unor diferene esentiale n implementarea meniurilor pe diferite platforme de operare, acestea nu au putut fi integrate ca obiecte de tip Component, superclasa care descrie meniuri fiind MenuComponent (vezi Meniuri). Componentele AWT au peste 100 de metode comune, motenite din clasa Component. Acestea servesc uzual pentru aflarea sau setarea atributelor obiectelor, cum ar fi: dimensiune, poziie, culoare, font, etc. i au formatul general getProprietate, respectiv setProprietate. Cele mai folosite, grupate pe tipul proprietii gestionate sunt: Poziie
getLocation, getX, getY, getLocationOnScreen setLocation, setX, setY

Dimensiuni
getSize, getHeight, getWidth setSize, setHeight, setWidth

Dimensiuni i poziie

getBounds setBounds

Culoare (text i fundal)


getForeground, getBackground setForeground, setBackground

Font
getFont setFont

Vizibilitate
setVisible isVisible

Interactivitate
setEnabled isEnabled

6.2.2 Suprafee de afiare (Clasa Container) Crearea obiectelor grafice nu realizeaz automat i afiarea lor pe ecran. Mai nti ele trebuie aezate pe o suprafa, care poate fi o fereastr sau suprafaa unui applet, i vor deveni vizibile n momentul n care suprafaa respectiv va fi vizibil. O astfel de suprafaa pe care sunt plasate componentele se numete suprafa de afiare sau container i reprezint o instana a unei clase derivat din Container. O parte din clasele a cror printe este Container este prezentat mai jos: Window - este superclasa tututor ferestrelor. Din aceast clas sunt derivate: Frame - ferestre standard; Dialog - ferestre de dialog modale sau nemodale; Panel - o suprafa fr reprezentare grafic folosit pentru gruparea altor componente. Din aceast clas deriv Applet, folosit pentru crearea appleturilor. ScrollPane - container folosit pentru implementarea automat a derulrii pe orizontal sau vertical a unei componente. Aadar, un container este folosit pentru a aduga componente pe suprafaa lui. Componentele adugate sunt memorate ntr-o list iar poziiile lor din aceast list vor defini ordinea de traversare front-to-back a acestora n cadrul containerului. Dac nu este specificat nici un index la adugarea unei componente, atunci ea va fi adaugat pe ultima poziie a listei. Clasa Container conine metodele comune tututor suprafeelor de afiare. Dintre cele mai folosite, amintim: add - permite adugarea unei componente pe suprafaa de afiare. O component nu poate aparine dect unui singur container, ceea ce nseamn c pentru a muta un obiect dintr-un container n altul trebuie sa-l eliminam mai nti de pe containerul initial. remove - elimin o component de pe container; setLayout - stabilete gestionarul de poziionare al containerului (vezi Gestionarea poziionrii); getInsets - determin distana rezervat pentru marginile suprafeei de afiare; validate - foreaz containerul s reaeze toate componentele sale. Aceast metod trebuie apelat explicit atunci cnd adugm sau eliminm componente pe suprafaa de afiare dup ce aceasta a devenit vizibil. Exemplu:

Frame f = new Frame("O fereastra"); // Adaugam un buton direct pe fereastra Button b = new Button("Hello"); f.add(b); // Adaugam doua componente pe un panel Label et = new Label("Nume:"); TextField text = new TextField(); Panel panel = new Panel(); panel.add(et); panel.add(text); // Adaugam panel-ul pe fereastra // si, indirect, cele doua componente f.add(panel);

6.3 Gestionarea poziionrii S considerm mai nti un exemplu de program Java care afieaz 5 butoane pe o fereastr:
Poziionarea a 5 butoane import java . awt .*; public class TestLayout { public static void main ( String args []) { Frame f = new Frame (" Grid Layout ");//* f. setLayout (new GridLayout (3, 2)); //* Button b1 = new Button (" Button 1"); Button b2 = new Button ("2"); Button b3 = new Button (" Button 3"); Button b4 = new Button ("Long - Named Button 4"); Button b5 = new Button (" Button 5"); f.add(b1); f.add (b2); f. add(b3); f.add(b4); f.add(b5); f. pack (); f.setVisible(true); } }

Fereastra afiata de acest program va arta astfel:

S modificm acum liniile marcate cu * ca mai jos, lsnd neschimbat restul programului:
Frame f = new Frame("Flow Layout"); f.setLayout(new FlowLayout());

Fereastra afiat dup aceast modificare va avea o cu totul altfel de dispunere a componentelor sale:

Motivul pentru care cele dou ferestre arat att de diferit este c folosesc gestionari de poziionare diferii: GridLayout, respectiv FlowLayout. Definiie: Un gestionar de poziionare (layout manager) este un obiect care controleaz dimensiunea i aranjarea (poziia) componentelor unui container. Aadar, modul de aranjare a componentelor pe o suprafaa de afiare nu este o caracteristic a containerului. Fiecare obiect de tip Container (Applet, Frame, Panel, etc.) are asociat un obiect care se ocup cu dispunerea componentelor pe suprafaa sa i anume gestionarul su de poziionare. Toate clasele care instaniaza obiecte pentru gestionarea poziionrii implementeaz interfaa LayoutManager. La instanierea unui container se creeaz implicit un gestionar de poziionare asociat acestuia. De exemplu, pentru o fereastr gestionarul implicit este de tip BorderLayout, n timp ce pentru un panel este de tip FlowLayout. 6.3.1 Folosirea gestionarilor de poziionare Aa cum am vzut, orice container are un gestionar implicit de poziionare - un obiect care implementeaz interfaa LayoutManager, acesta fiindu-i ataat automat la crearea sa. In cazul n care acesta nu corespunde necesitilor noastre, el poate fi schimbat cu uurin. Cei mai utilizai gestionari din pachetul java.awt sunt: FlowLayout BorderLayout GridLayout CardLayout GridBagLayout Pe lng acetia, mai exist i cei din modelul Swing care vor fi prezentai n capitolul dedicat dezvoltrii de aplicaii GUI folosind Swing. Ataarea explicit a unui gestionar de poziionare la un container se face cu metoda setLayout a clasei Container. Metoda poate primi ca parametru orice instan a unei clase care implementeaz interfa LayoutManager. Secvena de ataare a unui gestionar pentru un container, particularizat pentru FlowLayout, este:
FlowLayout gestionar = new FlowLayout(); container.setLayout(gestionar);

// sau, mai uzual:


container.setLayout(new FlowLayout());

Programele nu apeleaz n general metode ale gestionarilor de poziionare, dar n cazul cnd avem nevoie de obiectul gestionar l putem obine cu metoda getLayout din clasa Container. Una din facilitile cele mai utile oferite de gestionarii de poziionare este rearanjarea componentele unui container atunci cnd acesta este redimesionat. Poziiile i dimensiunile componentelor nu sunt fixe, ele fiind ajustate automat de ctre gestionar la fiecare redimensionare astfel nct s ocupe ct mai estetic suprafaa de afiare. Cum sunt determinate ns dimensiunile implicite ale componentelor ? Fiecare clas derivat din Component poate implementa metodele getPreferredSize, getMinimumSize i getMaximumSize care s returneze dimensiunea implicit a componentei respective i limitele n afara crora componenta nu mai poate fi

desenat. Gestionarii de poziionare vor apela aceste metode pentru a calcula dimensiunea la care vor afia o component. Sunt ns situaii cnd dorim s plasm componentele la anumite poziii fixe iar acestea s ramna acolo chiar dac redimensionm containerul. Folosind un gestionar aceast poziionare absolut a componentelor nu este posibil i deci trebuie cumva s renunm la gestionarea automat a containerul. Acest lucru se realizeaz prin trimitera argumentului null metodei setLayout:
// pozitionare absoluta a componentelor in container container.setLayout(null);

Folosind poziionarea absolut, nu va mai fi ns suficient s adugam cu metoda add componentele n container, ci va trebui s specificm poziia i dimensiunea lor acest lucru era fcut automat de gestionarul de poziionare.
container.setLayout(null); Button b = new Button("Buton"); b.setSize(10, 10); b.setLocation (0, 0); container.add(b);

In general, se recomand folosirea gestionarilor de poziionare n toate situaiile cnd acest lucru este posibil, deoarece permit programului s aib aceeai nfatisare indiferent de platforma i rezoluia pe care este rulat. Poziionarea absolut poate ridica diverse probleme n acest sens. S analizam n continuare pe fiecare din gestionarii amintii anterior. 6.3.2 Gestionarul FlowLayout Acest gestionar aeaz componentele pe suprafaa de afiare n flux liniar, mai precis, componentele sunt adugate una dup alta pe linii, n limita spaiului disponibil. In momentul cnd o component nu mai ncape pe linia curent se trece la urmtoarea linie, de sus n jos. Adugarea componentelor se face de la stnga la dreapta pe linie, iar alinierea obiectelor n cadrul unei linii poate fi de trei feluri: la stnga, la dreapta i pe centru. Implicit, componentele sunt centrate pe fiecare linie iar distana implicit ntre componente este de 5 pixeli pe vertical i 5 pe orizontal. Este gestionarul implicit al containerelor derivate din clasa Panel deci i al appleturilor.
Gestionarul FlowLayout import java . awt .*; public class TestFlowLayout { public static void main ( String args []) { Frame f = new Frame (" Flow Layout "); f. setLayout (new FlowLayout ()); Button b1 = new Button (" Button 1"); Button b2 = new Button ("2"); Button b3 = new Button (" Button 3"); Button b4 = new Button ("Long - Named Button 4"); Button b5 = new Button (" Button 5"); f.add(b1); f.add (b2); f. add(b3); f.add(b4); f.add(b5); f. pack (); f.setVisible(true); } }

Componentele ferestrei vor fi afiate astfel:

Redimensionnd fereastra astfel nct cele cinci butoane s nu mai ncap pe o linie, ultimele dintre ele vor fi trecute pe linia urmtoare:

6.3.3 Gestionarul BorderLayout Gestionarul BorderLayout mparte suprafaa de afiare n cinci regiuni, corespunztoare celor patru puncte cardinale i centrului. O component poate fi plasat n oricare din aceste regiuni, dimeniunea componentei fiind calculat astfel nct s ocupe ntreg spaiul de afiare oferit de regiunea respectiv. Pentru a aduga mai multe obiecte grafice ntr-una din cele cinci zone, ele trebuie grupate n prealabil ntr-un panel, care va fi amplasat apoi n regiunea dorit (vezi Gruparea componentelor - clasa Panel). Aadar, la adugarea unei componente pe o suprafa gestionat de BorderLayout, metoda add va mai primi pe lnga referina componentei i zona n care aceasta va fi amplasat, care va fi specificat prin una din constantele clasei: NORTH, SOUTH, EAST, WEST, CENTER. BorderLayout este gestionarul implicit pentru toate containerele care descend din clasa Window, deci al tuturor tipurilor de ferestre.
Gestionarul BorderLayout import java . awt .*; public class TestBorderLayout { public static void main ( String args []) { Frame f = new Frame (" Border Layout "); // Apelul de mai jos poate sa lipseasca f. setLayout (new BorderLayout ()); f.add(new Button (" Nord "), BorderLayout . NORTH ); f.add(new Button (" Sud"), BorderLayout . SOUTH ); f.add(new Button (" Est"), BorderLayout . EAST ); f.add(new Button (" Vest "), BorderLayout . WEST ); f.add(new Button (" Centru "), BorderLayout . CENTER ); f. pack (); f.setVisible(true); } }

Cele cinci butoane ale ferestrei vor fi afiate astfel:

La redimensionarea ferestrei se pot observa urmtoarele lucruri: nordul i sudul se redimensioneaz doar pe orizontal, estul i vestul doar pe vertical, n timp ce centrul se redimensioneaz att pe orizontal ct i pe vertical. Redimensionarea componentelor din fiecare zon se face astfel nct ele ocup toat zona containerului din care fac parte. 6.3.4 Gestionarul GridLayout Gestionarul GridLayout organizeaz containerul ca un tabel cu rnduri i coloane, componentele fiind plasate n celulele tabelului de la stnga la dreapta, ncepnd cu primul rnd. Celulele tabelului au dimensiuni egale iar o component poate ocupa doar o singur celul. Numrul de linii i coloane vor fi specificate n constructorul gestionarului, dar pot fi modificate i ulterior prin metodele setRows, respectiv setCols. Dac numrul de linii sau coloane este 0 (dar nu ambele n acelai timp), atunci componentele vor fi plasate ntr-o singur coloan sau linie. De asemenea, distana ntre componente pe orizontal i distanta ntre rndurile tabelului pot fi specificate n constructor sau stabilite ulterior.
Gestionarul GridLayout import java . awt .*; public class TestGridLayout { public static void main ( String args []) { Frame f = new Frame (" Grid Layout "); f. setLayout (new GridLayout (3, 2)); f.add(new Button ("1")); f.add(new Button ("2")); f.add(new Button ("3")); f.add(new Button ("4")); f.add(new Button ("5")); f.add(new Button ("6")); f. pack (); f.setVisible(true); } }

Cele ase butoane ale ferestrei vor fi plasate pe trei rnduri i dou coloane, astfel:

Redimensionarea ferestrei va determina redimensionarea tuturor celulelor i deci a tuturor componentelor, att pe orizontal ct i pe vertical.

6.3.5 Gestionarul CardLayout Gestionarul CardLayout trateaz componentele adugate pe suprafaa sa ntr-o manier similar cu cea a dispunerii crilor de joc ntr-un pachet. Suprafaa de afiare poate fi asemnat cu pachetul de cri iar fiecare component este o carte din pachet. La un moment dat, numai o singur component este vizibil (cea de deasupra). Clasa dispune de metode prin care s poat fi afiat o anumit component din pachet, sau s se poat parcurge secvenial pachetul, ordinea componentelor fiind intern gestionarului. Principala utilitate a acestui gestionar este utilizarea mai eficient a spaiului disponibil n situaii n care componentele pot fi grupate n aa fel nct utilizatorul s interacioneze la un moment dat doar cu un anumit grup (o carte din pachet), celelalte fiind ascunse. O clas Swing care implementeaz un mecansim similar este JTabbedPane.
Gestionarul CardLayout import java . awt .*; import java . awt. event .*; public class TestCardLayout extends Frame implements ActionListener { Panel tab; public TestCardLayout () { super (" Test CardLayout "); Button card1 = new Button (" Card 1"); Button card2 = new Button (" Card 2"); Panel butoane = new Panel (); butoane . add( card1 ); butoane . add( card2 ); tab = new Panel (); tab . setLayout ( new CardLayout ()); TextField tf = new TextField (" Text Field "); Button btn = new Button (" Button "); tab .add (" Card 1", tf); tab .add (" Card 2", btn); add ( butoane , BorderLayout . NORTH ); add (tab , BorderLayout . CENTER ); pack (); show (); card1 . addActionListener ( this ); card2 . addActionListener ( this ); } public void actionPerformed ( ActionEvent e) { CardLayout gestionar = ( CardLayout ) tab. getLayout (); gestionar . show (tab , e. getActionCommand ()); } public static void main ( String args []) { TestCardLayout f = new TestCardLayout (); f.setVisible(true); } }

Prima carte este vizibil

A doua carte este vizibil

6.3.6 Gestionarul GridBagLayout Este cel mai complex i flexibil gestionar de poziionare din Java. La fel ca n cazul gestionarului GridLayout, suprafaa de afiare este considerat ca fiind un tabel ns, spre deosebire de acesta, numrul de linii i de coloane sunt determinate automat, n funcie de componentele amplasate pe suprafaa de afiare. De asemenea, n funcie de componentele gestionate, dimensiunile celulelor pot fi diferite cu singurele restricii ca pe aceeai linie s aib aceeai nalime, iar pe coloan s aib aceeai lime. Spre deosebire de GridLayout, o component poate ocupa mai multe celule adiacente, chiar de dimensiuni diferite, zona ocupat fiind referit prin regiunea de afiare a componentei respective. Pentru a specifica modul de afiare a unei componente, acesteia i este asociat un obiect de tip GridBagConstraints, n care se specific diferite proprieti ale componentei referitoare la regiunea sa de afiare i la modul n care va fi plasat n aceast regiune. Legtura dintre o component i un obiect GridBagConstraints se realizeaz prin metoda setConstraints:
GridBagLayout gridBag = new GridBagLayout(); container.setLayout(gridBag); GridBagConstraints c = new GridBagConstraints(); //Specificam restrictiile referitoare la afisarea componentei . . . gridBag.setConstraints(componenta, c); container.add(componenta);

Aadar, nainte de a aduga o component pe suprafaa unui container care are un gestionar de tip GridBagLayout, va trebui s specificm anumii parametri (constrngeri) referitori la cum va fi plasat componenta respectiv. Aceste constrngeri vor fi specificate prin intermediul unui obiect de tip GridBagConstraints, care poate fi refolosit pentru mai multe componente care au aceleai constrngeri de afiare:
gridBag.setConstraints(componenta1, c); gridBag.setConstraints(componenta2, c); . . .

Cele mai utilizate tipuri de constrngeri pot fi specificate prin intermediul urmtoarelor variabile din clasa GridBagConstraints: gridx, gridy - celula ce reprezint colul stnga sus al componentei; gridwidth, gridheight - numrul de celule pe linie i coloan pe care va fi afiat componenta; fill - folosit pentru a specifica dac o component va ocupa ntreg spaiul pe care l are destinat; valorile posibile sunt HORIZONTAL, VERTICAL, BOTH, NONE; insets - distanele dintre component i marginile suprafeei sale de afiare;

- folosit atunci cnd componenta este mai mic dect suprafaa sa de afiare pentru a fora o anumit dispunere a sa: nord, sud, est, vest, etc. weigthx, weighty - folosite pentru distribuia spaiului liber; uzual au valoarea 1; Ca exemplu, s realizm o fereastr ca n figura de mai jos. Pentru a simplifica codul, a fost creat o metod responsabil cu setarea valorilor gridx, gridy, gridwidth, gridheight i adugarea unei componente cu restriciile stabilite pe fereastr.
anchor

Gestionarul GridBagLayout import java . awt .*; public class TestGridBagLayout { static Frame f; static GridBagLayout gridBag ; static GridBagConstraints gbc ; static void adauga ( Component comp ,int x, int y, int w, int h) { gbc.gridx = x; gbc.gridy = y; gbc.gridwidth = w; gbc.gridheight = h; gridBag.setConstraints (comp , gbc); f.add(comp); } public static void main ( String args []) { f = new Frame (" Test GridBagLayout "); gridBag = new GridBagLayout (); gbc = new GridBagConstraints (); gbc . weightx = 1.0; gbc . weighty = 1.0; gbc . insets = new Insets (5, 5, 5, 5); f. setLayout ( gridBag ); Label mesaj = new Label (" Evidenta persoane ", Label.CENTER); mesaj . setFont (new Font (" Arial ", Font .BOLD , 24)); mesaj . setBackground ( Color . yellow ); gbc . fill = GridBagConstraints . BOTH ; adauga (mesaj , 0, 0, 4, 2); Label etNume = new Label (" Nume :"); gbc . fill = GridBagConstraints . NONE ; gbc . anchor = GridBagConstraints . EAST ; adauga ( etNume , 0, 2, 1, 1); Label etSalariu = new Label (" Salariu :"); adauga ( etSalariu , 0, 3, 1, 1); TextField nume = new TextField ("", 30) ; gbc . fill = GridBagConstraints . HORIZONTAL ;

gbc . anchor = GridBagConstraints . CENTER ; adauga (nume , 1, 2, 2, 1); TextField salariu = new TextField ("", 30) ; adauga ( salariu , 1, 3, 2, 1); Button adaugare = new Button (" Adaugare "); gbc . fill = GridBagConstraints . NONE ; adauga ( adaugare , 3, 2, 1, 2); Button salvare = new Button (" Salvare "); gbc . fill = GridBagConstraints . HORIZONTAL ; adauga ( salvare , 1, 4, 1, 1); Button iesire = new Button (" Iesire "); adauga ( iesire , 2, 4, 1, 1); f. pack (); f.setVisible(true); } }

6.3.7 Gruparea componentelor (Clasa Panel) Plasarea componentelor direct pe suprafaa de afiare poate deveni incomod n cazul n care avem multe obiecte grafice. Din acest motiv, se recomand gruparea componentelor nrudite ca funcii astfel nct s putem fi siguri c, indiferent de gestionarul de poziionare al suprafeei de afiare, ele se vor gsi mpreun. Gruparea componentelor se face n panel-uri. Un panel este cel mai simplu model de container. El nu are o reprezentare vizibil, rolul su fiind de a oferi o suprafa de afiare pentru componente grafice, inclusiv pentru alte panel-uri. Clasa care instaniaza aceste obiecte este Panel, extensie a superclasei Container. Pentru a aranja corespunztor componentele grupate ntr-un panel, acestuia i se poate specifica un gestionar de poziionare anume, folosind metoda setLayout. Gestionarul implicit pentru containerele de tip Panel este FlowLayout. Aadar, o aranjare eficient a componentelor unei ferestre nseamn: gruparea componentelor nfraite (care nu trebuie s fie desparite de gestionarul de poziionare al ferestrei) n panel-uri; aranjarea componentelor unui panel, prin specificarea unui gestionar de poziionare corespunztor; aranjarea panel-urilor pe suprafaa ferestrei, prin specificarea gestionarului de poziionare al ferestrei.
Gruparea componentelor import java . awt .*; public class TestPanel { public static void main ( String args []) { Frame f = new Frame (" Test Panel "); Panel intro = new Panel (); intro . setLayout (new GridLayout (1, 3)); intro .add(new Label (" Text :")); intro .add(new TextField ("", 20) ); intro .add(new Button (" Adaugare ")); Panel lista = new Panel (); lista . setLayout (new FlowLayout ()); lista .add(new List (10) ); lista .add(new Button (" Stergere ")); Panel control = new Panel ();

control . add( new Button (" Salvare ")); control . add( new Button (" Iesire ")); f.add(intro , BorderLayout . NORTH ); f.add(lista , BorderLayout . CENTER ); f.add( control , BorderLayout . SOUTH ); f. pack (); f.setVisible(true); } }

6.4 Tratarea evenimentelor Un eveniment este produs de o aciune a utilizatorului asupra unei componente grafice i reprezint mecanismul prin care utilizatorul comunic efectiv cu programul. Exemple de evenimente sunt: apsarea unui buton, modificarea textului ntr-un control de editare, nchiderea sau redimensionarea unei ferestre, etc. Componentele care genereaz anumite evenimente se mai numesc i surse de evenimente. Interceptarea evenimentelor generate de componentele unui program se realizeaz prin intermediul unor clase de tip listener (asculttor, consumator de evenimente). In Java, orice obiect poate consuma evenimentele generate de o anumit component grafic. Aadar, pentru a scrie cod care s se execute n momentul n care utilizatorul interactioneaz cu o component grafic trebuie s facem urmtoarele lucruri: s scriem o clas de tip listener care s asculte evenimentele produse de acea component i n cadrul acestei clase s implementm metode specifice pentru tratarea lor; s comunicm componentei surs c respectiva clasa i ascult evenimentele pe care le genereaz, cu alte cuvinte s nregistrm acea clas drept consumator al evenimentelor produse de componenta respectiv. Evenimentele sunt, ca orice altceva n Java, obiecte. Clasele care descriu aceste obiecte se mpart n mai multe tipuri n funcie de componenta care le genereaz, mai precis n funcie de aciunea utilizatorului asupra acesteia. Pentru fiecare tip de eveniment exist o clas care instaniaz obiecte de acel tip. De exemplu, evenimentul generat de acionarea unui buton este descris de clasa ActionEvent, cel generat de modificarea unui text de clasa TextEvent, etc. Toate aceste clase sunt derivate din superclasa AWTEvent, lista lor complet fiind prezentat ulterior. O clas consumatoare de evenimente (listener) poate fi orice clas care specifica n declaraia sa c dorete s asculte evenimente de un anumit tip. Acest lucru se realizeaz prin implementarea unei interfee specifice fiecrui tip de eveniment. Astfel, pentru ascultarea evenimentelor de tip ActionEvent clasa respectiv trebuie s implementeze interfaa ActionListener, pentru TextEvent interfa care trebuie implementata este TextListener, etc. Toate aceste interfee sunt derivate din EventListener. Fiecare interfa definete una sau mai multe metode care vor fi apelate automat la apariia unui eveniment:
class AscultaButoane implements ActionListener { public void actionPerformed(ActionEvent e) { // Metoda interfetei ActionListener ...

} } class AscultaTexte implements TextListener { public void textValueChanged(TextEvent e) { // Metoda interfetei TextListener ... } }

Intruct o clas poate implementa oricte interfee, ea va putea s asculte evenimente de mai multe tipuri:
class Ascultator implements ActionListener, TextListener { public void actionPerformed(ActionEvent e) { ... } public void textValueChanged(TextEvent e) { ... } }

Vom vedea n continuare metodele fiecrei interfee pentru a ti ce trebuie s implementeze o clas consumatoare de evenimente. Aa cum am spus mai devreme, pentru ca evenimentele unei componente s fie interceptate de ctre o instan a unei clase asculttor, aceast clas trebuie nregistrata n lista asculttorilor componentei respective. Am spus lista, deoarece evenimentele unei componente pot fi ascultate de oricte clase, cu condiia ca acestea s fie nregistrate la componenta respectiv. Inregistrarea unei clase n lista asculttorilor unei componente se face cu metode din clasa Component de tipul addTipEvenimentListener, iar eliminarea ei din aceast list cu removeTipEvenimentListener. Sumariznd, tratarea evenimentelor n Java se desfoar astfel: Componentele genereaz evenimente cnd ceva interesant se ntmpl; Sursele evenimentelor permit oricrei clase s asculte evenimentele sale prin metode de tip addXXXListener, unde XXX este un tip de eveniment; clasa care ascult evenimente trebuie s implementeze interfee specifice fiecrui tip de eveniment - acestea descriu metode ce vor fi apelate automat la apariia evenimentelor. 6.4.1 Exemplu de tratare a evenimentelor Inainte de a detalia aspectele prezentate mai sus, s considerm un exemplu de tratare a evenimentelor. Vom crea o fereastr care s conin dou butoane cu numele OK, repectiv Cancel. La apsarea fiecrui buton vom scrie pe bara de titlu a ferestrei mesajul Ati apasat butonul ....
Ascultarea evenimentelor a dou butoane import java . awt .*; import java . awt. event .*; class Fereastra extends Frame { public Fereastra ( String titlu ) { super ( titlu ); setLayout (new FlowLayout ()); setSize (200 , 100) ; Button b1 = new Button ("OK"); Button b2 = new Button (" Cancel "); add (b1); add (b2); Ascultator listener = new Ascultator ( this ); b1. addActionListener ( listener );

b2. addActionListener ( listener ); // Ambele butoane sunt ascultate de obiectul listener , // instanta a clasei Ascultator , definita mai jos } } class Ascultator implements ActionListener { private Fereastra f; public Ascultator ( Fereastra f) { this .f = f; } // Metoda interfetei ActionListener public void actionPerformed ( ActionEvent e) { f. setTitle ("Ati apasat " + e. getActionCommand ()); } } public class TestEvent1 { public static void main ( String args []) { Fereastra f = new Fereastra (" Test Event "); f.setVisible(true); } }

Nu este obligatoriu s definim clase speciale pentru ascultarea evenimentelor. In exemplul de mai sus am definit clasa Ascultator pentru a intercepta evenimentele produse de cele dou butoane i din acest motiv a trebuit s trimitem ca parametru constructorului clasei o referina la fereastra noastr. Mai simplu ar fi fost s folosim chiar clasa Fereastra pentru a trata evenimentele produse de componentele sale. Vom modifica puin i aplicaia pentru a pune n evidena o alt modalitate de a determina componenta generatoare a unui eveniment - metoda getSource.
Tratarea evenimentelor n ferestr import java . awt .*; import java . awt. event .*; class Fereastra extends Frame implements ActionListener { Button ok = new Button ("OK"); Button exit = new Button (" Exit "); int n=0; public Fereastra ( String titlu ) { super ( titlu ); setLayout (new FlowLayout ()); setSize (200 , 100) ; add (ok); add ( exit ); ok. addActionListener ( this ); exit . addActionListener ( this ); // Ambele butoane sunt ascultate in clasa Fereastra // deci ascultatorul este instanta curenta : this } // Metoda interfetei ActionListener public void actionPerformed ( ActionEvent e) { if (e. getSource () == exit ) System . exit (0); // Terminam aplicatia if (e. getSource () == ok) { n ++; this . setTitle ("Ati apasat OK de " + n + " ori"); } }

} public class TestEvent2 { public static void main ( String args []) { Fereastra f = new Fereastra (" Test Event "); f.setVisible(true); } }

Aadar, orice clas poate asculta evenimente de orice tip cu condiia s implementeze interfeele specifice acelor tipuri de evenimente. 6.4.2 Tipuri de evenimente Evenimentele se mpart n dou categorii: de nivel jos i semantice. Evenimentele de nivel jos reprezint o interaciune de nivel jos cum ar fi o apsare de tast, micarea mouse-ului, sau o operaie asupra unei ferestre. In tabelul de mai jos sunt enumerate clasele ce descriu aceste evenimente i operaiunile efectuate (asupra unei componente) care le genereaz:
ComponentEvent ContainerEvent FocusEvent KeyEvent MouseEvent WindowEvent

Ascundere,deplasare,redimensionare,afiare Adugare pe container, eliminare Obinere, pierdere focus Apsare, eliberare taste, tastare Operaiuni cu mouse-ul: click, drag, etc. Operaiuni asupra ferestrelor: minimizare, maximizare,etc.

O anumit aciune a utilizatorului poate genera mai multe evenimente. De exemplu, tastarea literei A va genera trei evenimente: unul pentru apsare, unul pentru eliberare i unul pentru tastare. In funcie de necesitile aplicaie putem scrie cod pentru tratarea fiecrui eveniment n parte. Evenimentele semantice reprezint interaciunea cu o component GUI: apsarea unui buton, selectarea unui articol dintr-o list, etc. Clasele care descriu aceste tipuri de evenimente sunt:
ActionEvent AdjustmentEvent ItemEvent TextEvent Acionare Ajustarea unei valori Schimbarea strii Schimbarea textului

Urmtorul tabel prezint componentele AWT i tipurile de evenimente generate, prezentate sub forma interfeelor corespunztoare. Evident, evenimentele generate de o superclas, cum ar fi Component, se vor regsi i pentru toate subclasele sale.

Component

Container Window Button List MenuItem TextField Choice Checkbox List CheckboxMenuItem Scrollbar TextField TextArea

ComponentListener FocusListener KeyListener MouseListener MouseMotionListener ContainerListener WindowListener ActionListener

ItemListener AdjustmentListener TextListener

Observai c dei exist o singur clas MouseEvent, exist dou interfee asociate MouseListener i MouseMotionListener. Acest lucru a fost fcut deoarece evenimentele legate de deplasarea mouse-ului sunt generate foarte frecvent i recepionarea lor poate avea un impact negativ asupra vitezei de execuie, n situaia cnd tratarea acestora nu ne intereseaz i dorim s tratm doar evenimente de tip click, de exemplu. Orice clas care trateaz evenimente trebuie s implementeze obligatoriu metodele interfeelor corespunztoare. Tabelul de mai jos prezint, pentru fiecare interfa, metodele puse la dispozitie i care trebuie implementate de ctre clasa asculttor.
Interfa Metode

ActionListener AdjustmentListener ComponentListener

ContainerListener FocusListener ItemListener KeyListener

MouseListener

actionPerformed(ActionEvent e) adjustmentValueChanged(AdjustmentEvent e) componentHidden(ComponentEvent e) componentMoved(ComponentEvent e) componentResized(ComponentEvent e) componentShown(ComponentEvent e) componentAdded(ContainerEvent e) componentRemoved(ContainerEvent e) focusGained(FocusEvent e) focusLost(FocusEvent e) itemStateChanged(ItemEvent e) keyPressed(KeyEvent e) keyReleased(KeyEvent e) keyTyped(KeyEvent e) mouseClicked(MouseEvent e) mouseEntered(MouseEvent e)

mouseExited(MouseEvent e) mousePressed(MouseEvent e) mouseReleased(MouseEvent e) MouseMotionListener mouseDragged(MouseEvent e) mouseMoved(MouseEvent e) TextListener textValueChanged(TextEvent e) WindowListener windowActivated(WindowEvent e) windowClosed(WindowEvent e) windowClosing(WindowEvent e) windowDeactivated(WindowEvent e) windowDeiconified(WindowEvent e) windowIconified(WindowEvent e) windowOpened(WindowEvent e) In cazul n care un obiect listener trateaz evenimente de acelai tip provocate de componente diferite, este necesar s putem afla, n cadrul uneia din metodele de mai sus, care este sursa evenimentului pe care l tratm pentru a putea reaciona n consecin. Toate tipurile de evenimente motenesc metoda getSource care returneaz obiectul responsabil cu generarea evenimentului. In cazul n care dorim s difereniem doar tipul componentei surs, putem folosi operatorul instanceof.
public void actionPerformed(ActionEvent e) { Object sursa = e.getSource(); if (sursa instanceof Button) { // A fost apasat un buton Button btn = (Button) sursa; if (btn == ok) { // A fost apasat butonul ok } ... } if (sursa instanceof TextField) { // S-a apasat Enter dupa editarea textului TextField tf = (TextField) sursa; if (tf == nume) { // A fost editata componenta nume } ... } }

Pe lng getSource, obiectele ce descriu evenimente pot pune la dispoziie i alte metode specifice care permit aflarea de informaii legate de evenimentul generat. De exemplu, ActionEvent conine metoda getActionCommand care, implicit, returneaz eticheta butonului care a fost apsat. Astfel de particulariti vor fi prezentate mai detaliat n seciunile dedicate fiecrei componente n parte. 6.4.3 Folosirea adaptorilor i a claselor anonime Am vazut c o clas care trateaz evenimente de un anumit tip trebuie s implementeze interfaa corespunztoare acelui tip. Aceasta nseamn c trebuie s implementeze obligatoriu toate metodele definite de acea interfa, chiar dac nu

specific nici un cod pentru unele dintre ele. Sunt ns situaii cnd acest lucru poate deveni suprator, mai ales atunci cnd nu ne intereseaz dect o singura metod a interfeei. Un exemplu sugestiv este urmtorul: o fereastr care nu are specificat cod pentru tratarea evenimentelor sale nu poate fi nchis cu butonul standard marcat cu x din colul dreapta sus i nici cu combinaia de taste Alt+F4. Pentru a realiza acest lucru trebuie interceptat evenimentul de nchidere a ferestrei n metoda windowClosing i apelat metoda dispose de nchidere a ferestrei, sau System.exit pentru terminarea programului, n cazul cnd este vorba de fereastra principal a aplicaiei. Aceasta nseamn c trebuie s implementm interfaa WindowListener care are nu mai puin de apte metode.
Implementarea interfeei WindowListener import java . awt .*; import java . awt. event .*; class Fereastra extends Frame implements WindowListener { public Fereastra ( String titlu ) { super ( titlu ); this . addWindowListener ( this ); } // Metodele interfetei WindowListener public void windowOpened ( WindowEvent e) {} public void windowClosing ( WindowEvent e) { // Terminare program System . exit (0); } public void windowClosed ( WindowEvent e) {} public void windowIconified ( WindowEvent e) {} public void windowDeiconified ( WindowEvent e) {} public void windowActivated ( WindowEvent e) {} public void windowDeactivated ( WindowEvent e) {} } public class TestWindowListener { public static void main ( String args []) { Fereastra f = new Fereastra (" Test WindowListener "); f.setVisible(true); } }

Observai c trebuie s implementm toate metodele interfeei, chiar dac nu scriem nici un cod pentru unele dintre ele. Singura metod care ne intereseaz este windowClosing, n care specificm ce trebuie fcut atunci cnd utilizatorul doreste s nchid fereastra. Pentru a evita scrierea inutil a acestor metode, exist o serie de clase care implementeaz interfeele de tip listener fr a specifica nici un cod pentru metodele lor. Aceste clase se numesc adaptori. Un adaptor este o clas abstract care implementeaz o anumit interfa fr a specifica cod nici unei metode a interfeei. Scopul unei astfel de clase este ca la crearea unui asculttor de evenimente, n loc s implementm o anumit interfa i implicit toate metodele sale, s extindem adaptorul corespunztor interfeei respective (dac are!) i s supradefinim doar metodele care ne intereseaz (cele n care vrem s scriem o anumit secven de cod). De exemplu, adaptorul interfeei WindowListener este WindowAdapter iar folosirea acestuia este dat n exemplul de mai jos:
Extinderea clasei WindowAdapter

import java . awt .*; import java . awt. event .*; class Fereastra extends Frame { public Fereastra ( String titlu ) { super ( titlu ); this . addWindowListener (new Ascultator ()); } } class Ascultator extends WindowAdapter { // Suprdefinim metodele care ne intereseaza public void windowClosing ( WindowEvent e) { System . exit (0); } } public class TestWindowAdapter { public static void main ( String args []) { Fereastra f = new Fereastra (" Test WindowAdapter "); f.setVisible(true); } }

Avantajul clar al acestei modaliti de tratare a evenimentelor este reducerea codului programului, acesta devenind mult mai lizibil. Ins exist i dou dezavantaje majore. Dup cum ai observat fa de exemplul anterior, clasa Fereastra nu poate extinde WindowAdapter deoarece ea extinde deja clasa Frame i din acest motiv am construit o nou clas numit Ascultator. Vom vedea ns c acest dezavantaj poate fi eliminat prin folosirea unei clase anonime. Un alt dezavantaj este c orice greeal de sintax n declararea unei metode a interfeei nu va produce o eroare de compilare dar nici nu va supradefini metoda interfeei ci, pur i simplu, va crea o metod a clasei respective.
class Ascultator extends WindowAdapter { // In loc de windowClosing scriem WindowClosing // Nu supradefinim vreo metoda a clasei WindowAdapter // Nu da nici o eroare // Nu face nimic ! public void WindowClosing(WindowEvent e) { System.exit(0); } }

In tabelul de mai jos sunt dai toi adaptorii interfeelor de tip listener - se oberv c o interfa XXXListener are un adaptor de tipul XXXAdapter. Interfeele care nu au un adaptor sunt cele care definesc o singur metod i prin urmare crearea unei clase adaptor nu si are rostul.
Interfaa ActionListener AdjustemnrListener ComponentListener ContainerListener FocusListener ItemListener KeyListener MouseListener MouseMotionListener Adaptor nu are nu are ComponentAdapter ContainerAdapter FocusAdapter nu are KeyAdapter MouseAdapter MouseMotionAdapter

TextListener WindowListener

nu are WindowAdapter

Stim c o clas intern este o clas declarat n cadrul altei clase, iar clasele anonime sunt clase interne folosite pentru instanierea unui singur obiect de un anumit tip. Un exemplu tipic de folosire a lor este instanierea adaptorilor direct n corpul unei clase care conine componente ale cror evenimente trebuie tratate.
Folosirea adaptorilor i a claselor anonime import java . awt .*; import java . awt. event .*; class Fereastra extends Frame { public Fereastra ( String titlu ) { super ( titlu ); setSize (400 , 400) ; this.addWindowListener (new WindowAdapter () { public void windowClosing ( WindowEvent e) { // Terminam aplicatia System.exit (0); } }); final Label label = new Label ("", Label . CENTER ); label . setBackground ( Color . yellow ); add (label , BorderLayout . NORTH ); this . addMouseListener (new MouseAdapter () { public void mouseClicked ( MouseEvent e) { // Desenam un cerc la fiecare click de mouse label . setText (" Click ... "); Graphics g = Fereastra . this . getGraphics (); g. setColor ( Color . blue ); int raza = ( int )( Math . random () * 50); g. fillOval (e. getX () , e. getY () , raza , raza ); } }); this.addMouseMotionListener ( new MouseMotionAdapter () { public void mouseMoved ( MouseEvent e) { // Desenam un punct la coordonatele mouse - ului Graphics g = Fereastra . this . getGraphics (); g. drawOval (e. getX () , e. getY () , 1, 1); } }); this . addKeyListener (new KeyAdapter () { public void keyTyped ( KeyEvent e) { // Afisam caracterul tastat label . setText ("Ati tastat : " + e. getKeyChar () + ""); } }); } } public class TestAdapters { public static void main ( String args []) { Fereastra f = new Fereastra (" Test adaptori "); f.setVisible(true); } }

CURS 9 6.5 Folosirea ferestrelor Dup cum am vzut suprafeele de afiare ale componentelor sunt extensii ale clasei Container. O categorie aparte a acestor containere o reprezint ferestrele. Acestea sunt descrise de clase derivate din Window, cele mai utilizate fiind Frame i Dialog. O aplicaie Java cu intefa grafic va fi format din una sau mai multe ferestre, una dintre ele fiind numit fereastra principal. 6.5.1 Clasa Window Clasa Window este rar utilizat n mod direct deoarece permite doar crearea unor ferestre care nu au chenar i nici bar de meniuri. Este util atunci cnd dorim s afiam ferestre care nu interacioneaz cu utilizatorul ci doar ofer anumite informaii. Metodele mai importante ale clasei Window, care sunt de altfel motenite de toate subclasele sale, sunt date de mai jos: setVisible - face vizibil fereastra daca are parametrul true, sau invizibila cu parametrul false. Implicit, o fereastr nou creat nu este vizibil; isShowing - testeaz dac fereastra este vizibil sau nu; dispose - nchide fereastra i elibereaz toate resursele acesteia; pack - redimensioneaz automat fereastra la o suprafaa optim care s cuprind toate componentele sale; trebuie apelat n general dup adugarea tuturor componentelor pe suprafaa ferestrei. getFocusOwner - returneaz componenta ferestrei care are focus-ul (dac fereastra este activ). 6.5.2 Clasa Frame Este derivat a clasei Window i este folosit pentru crearea de ferestre independente i funcionale, eventual continnd o bar de meniuri. Orice aplicaie cu interfa grafic conine cel puin o fereastr, cea mai important fiind numit i fereastra principal. Constructorii uzuali ai clasei Frame permit crearea unei ferestre cu sau fr titlu, iniial invizibil. Pentru ca o fereastr s devin vizibil se va apela metoda setVisible definit n superclasa Window.
import java.awt.*; public class TestFrame { public static void main(String args[]) { Frame f = new Frame("Titlul ferestrei"); f.setVisible(true); } }

Crearea ferestrelor prin instanierea direct a obiectelor de tip Frame este mai puin folosit. De obicei, ferestrele unui program vor fi definite n clase separate care extind clasa Frame, ca n exemplul de mai jos:
import java.awt.*; class Fereastra extends Frame{

// Constructorul public Fereastra(String titlu) { super(titlu); ... } } public class TestFrame { public static void main(String args[]) { Fereastra f = new Fereastra("Titlul ferestrei"); f.setVisible(true); } }

Gestionarul de poziionare implicit al clasei Frame este BorderLayout. Din acest motiv, n momentul n care fereastra este creat dar nici o component grafic nu este adugat, suprafaa de afiare a ferestrei va fi determinat automat de gestionarul de poziionare i va oferi doar spaiul necesar afirii barei ferestrei i grupului de butoane pentru minimizare, maximizare i nchidere. Acelai efect l vom obine dac o redimenionam i apelm apoi metoda pack care determin dimeniunea suprafeei de afiare n funcie de componentele adugate. Se observ de asemenea c butonul de nchidere a ferestrei nu este funcional. Tratarea evenimentelor ferestrei se face prin implementarea interfeei WindowListener sau, mai uzual, prin folosirea unui adaptor de tip WindowAdapter. Structura general a unei ferestre este descris de clasa Fereastra din exemplul de mai jos:
Structura general a unei ferestre import java . awt .*; import java . awt. event .*; class Fereastra extends Frame implements ActionListener { // Constructorul public Fereastra ( String titlu ) { super ( titlu ); // Tratam evenimentul de inchidere a ferestrei this . addWindowListener (new WindowAdapter () { public void windowClosing ( WindowEvent e) { dispose (); // inchidem fereastra // sau terminam aplicatia System . exit (0); } }); // Eventual , schimbam gestionarul de pozitionare setLayout (new FlowLayout ()); // Adaugam componentele pe suprafata ferestrei Button exit = new Button (" Exit "); add ( exit ); // Facem inregistrarea claselor listener exit . addActionListener ( this ); // Stabilim dimensiunile pack (); // implicit // sau explicit // setSize (200 , 200) ; } // Implementam metodele interfetelor de tip listener public void actionPerformed ( ActionEvent e) { System . exit (0);

} } public class TestFrame { public static void main ( String args []) { // Cream fereastra Fereastra f = new Fereastra ("O fereastra "); // O facem vizibila f. setVisible(true); } }//lab9a

Pe lng metodele motenite din clasa Window, exist o serie de metode specifice clasei Frame. Dintre cele mai folosite amintim: getFrames - metod static ce returneaz lista tuturor ferestrelor deschise ale unei aplicaii; setIconImage - seteaz iconia ferestrei; setMenuBar - seteaz bara de meniuri a ferestrei (vezi Folosirea meniurilor); setTitle - seteaz titlul ferestrei; setResizable - stabilete dac fereastra poate fi redimenionat de utilizator; 6.5.3 Clasa Dialog Toate interfeele grafice ofer un tip special de ferestre destinate prelurii unor informaii sau a unor date de la utilizator. Acestea se numesc ferestre de dialog sau casete de dialog i sunt implementate prin intermediul clasei Dialog, subclas direct a clasei Window. Diferena major dintre ferestrele de dialog i ferestrele de tip Frame const n faptul c o fereastr de dialog este dependent de o alt fereastra (normal sau tot fereastr de dialog), numit i fereastra printe. Cu alte cuvinte, ferestrele de dialog nu au o existen de sine stttoare. Cnd fereastra printe este distrus sunt distruse i ferestrele sale de dialog, cnd este minimizat ferestrele sale de dialog sunt fcute invizibile iar cnd este restaurant acestea sunt aduse la starea n care se gseau n momentul minimizrii ferestrei printe. Ferestrele de dialog pot fi de dou tipuri: modale: care blocheaz accesul la fereastra parinte n momentul deschiderii lor, cum ar fi ferestrele de introducere a unor date, de alegere a unui fiier, de selectare a unei opiuni, mesaje de avertizare, etc; nemodale: care nu blocheaz fluxul de intrare ctre fereastra printe - de exemplu, dialogul de cutare a unui cuvnt ntr-un fiier, etc. Implicit, o fereastr de dialog este nemodal i invizibil, ns exist constructori care s specifice i aceti parametri. Constructorii clasei Dialog sunt:
Dialog(Frame parinte) Dialog(Frame parinte, String titlu) Dialog(Frame parinte, String titlu, boolean modala) Dialog(Frame parinte, boolean modala) Dialog(Dialog parinte) Dialog(Dialog parinte, String titlu) Dialog(Dialog parinte, String titlu, boolean modala)

Parametrul printe reprezint referina la fereastra printe, titlu reprezint titlul ferestrei iar prin argumentul modal specificm dac fereastra de dialog creat va fi modal (true) sau nemodal (false valoarea implicit). Crearea unei ferestre de dialog este relativ simpla i se realizeaz prin derivarea clasei Dialog. Comunicarea dintre fereastra de dialog i fereastra sa printe, pentru ca aceasta din urm s poat folosi datele introduse (sau opiunea specificata) n caseta de dialog, se poate realiza folosind una din urmtoarele abordri generale: obiectul care reprezint dialogul poate s trateze evenimentele generate de componentele de pe suprafaa sa i s seteze valorile unor variabile accesibile ale ferestrei printe n momentul n care dialogul este ncheiat; obiectul care creeaz dialogul (fereastra printe) s se nregistreze ca asculttor al evenimentelor de la butoanele care determin ncheierea dialogului, iar fereastra de dialog s ofere metode publice prin care datele introduse s fie preluate din exterior; S crem, de exemplu, o fereastr de dialog modal pentru introducerea unui ir de caractere. Fereastra principal a aplicatiei va fi printele casetei de dialog, va primi irul de caractere introdus i si va modifica titlul ca fiind acesta. Deschiderea ferestrei de dialog se va face la apsarea unui buton al ferestrei principale numit Schimba titlul. Cele dou ferestre vor arta ca n imaginile de mai jos: Fereastra principal Fereastra de dialog

Folosirea unei ferestre de dialog import java . awt .*; import java . awt. event .*; // Fereastra principala class FerPrinc extends Frame implements ActionListener { public FerPrinc ( String titlu ) { super ( titlu ); this . addWindowListener (new WindowAdapter () { public void windowClosing ( WindowEvent e) { System . exit (0); } }); setLayout (new FlowLayout ()); setSize (300 , 80); Button b = new Button (" Schimba titlul "); add (b); b. addActionListener ( this ); } public void actionPerformed ( ActionEvent e) { FerDialog d = new FerDialog (this , " Dati titlul ", true ); String titlu = d. raspuns ; if ( titlu == null ) return ; setTitle ( titlu );

} } // Fereastra de dialog class FerDialog extends Dialog implements ActionListener { public String raspuns = null ; private TextField text ; private Button ok , cancel ; public FerDialog(Frame parinte,String titlu,Boolean modala ) { super ( parinte , titlu , modala ); this . addWindowListener (new WindowAdapter () { public void windowClosing ( WindowEvent e) { raspuns = null ; dispose (); } }); text = new TextField ("", 30) ; add (text , BorderLayout . CENTER ); Panel panel = new Panel (); ok = new Button ("OK"); cancel = new Button (" Cancel "); panel .add(ok); panel .add( cancel ); add (panel , BorderLayout . SOUTH ); pack (); text . addActionListener ( this ); ok. addActionListener ( this ); cancel . addActionListener ( this ); setVisible(true); } public void actionPerformed ( ActionEvent e) { Object sursa = e. getSource (); if ( sursa == ok || sursa == text ) raspuns = text . getText (); else raspuns = null ; dispose (); } } // Clasa principala public class TestDialog { public static void main ( String args []) { FerPrinc f = new FerPrinc (" Fereastra principala "); f.setVisible(true); } }//lab9b //rectificat lab9_1

6.5.4 Clasa FileDialog Pachetul java.awt pune la dispozitie i un tip de fereastr de dialog folosit pentru selectarea unui nume de fiier n vederea ncrcrii sau salvrii unui fiier: clasa FileDialog, derivat din Dialog. Instanele acestei clase au un comportament comun dialogurilor de acest tip de pe majoritatea platformelor de lucru, dar forma n care vor fi afiate este specific platformei pe care ruleaz aplicaia. Constructorii clasei sunt:

FileDialog(Frame parinte) FileDialog(Frame parinte, String titlu) FileDialog(Frame parinte, String titlu, boolean mod)

Parametrul printe reprezint referina ferestrei printe, titlu reprezint titlul ferestrei iar prin argumentul mod specificm dac ncrcm sau salvm un fiier; valorile pe care le poate lua acest argument sunt: FileDialog.LOAD - pentru ncrcare, respectiv FileDialog.SAVE - pentru salvare.
// Dialog pentru incarcarea unui fisier new FileDialog(parinte, "Alegere fisier", FileDialog.LOAD); // Dialog pentru salvarea unui fisier new FileDialog(parinte, "Salvare fisier", FileDialog.SAVE);

Pe lng metodele motenite de la superclasa Dialog clasa FileDialog mai conine metode pentru obinerea numelui fiierului sau directorului selectat getFile, getDirectory, pentru stabilirea unui criteriu de filtrare setFilenameFilter, etc. S considerm un exemplu n care vom alege, prin intermediul unui obiect FileDialog, un fiier cu extensia java. Directorul iniial este directorul curent, iar numele implicit este TestFileDialog.java. Numele fiierului ales va fi afiat la consol.
Folosirea unei ferestre de dialog import java . awt .*; import java . awt. event .*; import java .io .*; class FerPrinc extends Frame implements ActionListener { public FerPrinc ( String titlu ) { super ( titlu ); this . addWindowListener (new WindowAdapter () { public void windowClosing ( WindowEvent e) { System . exit (0); } }); Button b = new Button (" Alege fisier "); add (b, BorderLayout . CENTER ); pack (); b. addActionListener ( this ); } public void actionPerformed ( ActionEvent e) { FileDialog fd = new FileDialog(this," Alegeti un fisier ", FileDialog.LOAD); // Stabilim directorul curent fd. setDirectory ("."); // Stabilim numele implicit fd. setFile (" TestFileDialog . java "); // Specificam filtrul fd. setFilenameFilter ( new FilenameFilter () { public boolean accept ( File dir , String numeFis ) { return ( numeFis . endsWith (". java ")); } }); // Afisam fereastra de dialog ( modala ) fd. setVisible(true); System . out. println (" Fisierul ales este :" + fd. getFile ()); } } public class TestFileDialog {

public static void main ( String args []) { FerPrinc f = new FerPrinc (" Fereastra principala "); f. setVisible(true); } }//lab9c //lab9_2

Clasa FileDialog este folosit mai rar deoarece n Swing exist clasa JFileChooser care ofer mai multe faciliti i prin urmare va constitui prima opiune ntr-o aplicaie cu intefa grafic. 6.6 Folosirea meniurilor Spre deosebire de celelalte obiecte grafice care deriv din clasa Component, componentele unui meniu reprezint instane ale unor clase derivate din superclasa abstract MenuComponent. Aceast excepie este facut deoarece unele platforme grafice limiteaz capabilitile unui meniu. Meniurile pot fi grupate n dou categorii: Meniuri fixe (vizibile permanent): sunt grupate ntr-o bar de meniuri ce conine cte un meniu pentru fiecare intrare a sa. La rndul lor, aceste meniuri conin articole ce pot fi selectate, comutatoare sau alte meniuri (submeniuri). O fereastr poate avea un singur meniu fix. Meniuri de context (popup): sunt meniuri invizibile asociate unei ferestre i care se activeaz uzual prin apsarea butonului drept al mouse-ului. O alt diferen fa de meniurile fixe const n faptul c meniurile de context nu sunt grupate ntro bar de meniuri. In figura de mai jos este pus n eviden alctuirea unui meniu fix:

Exemplul de mai sus conine o bar de meniuri format din dou meniuri principale File i Edit. Meniul Edit conine la rndul lui alt meniu (submeniu) Options, articolul Undo i dou comutatoare Bold i Italic. Prin abuz de limbaj, vom referi uneori bara de meniuri a unei ferestre ca fiind meniul ferestrei. In modelul AWT obiectele care reprezint bare de meniuri sunt reprezentate ca instane ale clasei MenuBar. Un obiect de tip MenuBar conine obiecte de tip Menu, care sunt de fapt meniurile derulante propriu-zise. La rndul lor, acestea pot conine obiecte de tip MenuItem, CheckBoxMenuItem, dar i alte obiecte de tip Menu (submeniuri). Pentru a putea conine un meniu, o component trebuie s implementeze interfaa MenuContainer. Cel mai adesea, meniurile sunt ataate ferestrelor, mai precis obiectelor

de tip Frame, acestea implementnd interfa MenuContainer. Ataarea unei bare de meniuri la o fereastr se face prin metoda addMenuBar a clasei Frame. 6.6.1 Ierarhia claselor ce descriu meniuri S vedem n continuare care este ierarhia claselor folosite n lucrul cu meniuri i s analizm pe rnd aceste clase:

Clasa MenuComponent este o clasa abstract din care sunt extinse toate celelalte clase folosite la crearea de meniuri, fiind similar celeilalte superclase abstracte Component. MenuComponent conine metode cu caracter general, dintre care amintim getName, setName, getFont, setFont, cu sintaxa i semnificaiile uzuale. Clasa MenuBar permite crearea barelor de meniuri asociate unei ferestre cadru de tip Frame, adaptnd conceptul de bar de meniuri la platforma curent de lucru. Dup cum am mai spus, pentru a lega bara de meniuri la o anumit fereastra trebuie apelat metoda setMenuBar din clasa Frame.
// Crearea barei de meniuri MenuBar mb = new MenuBar(); // Adaugarea meniurilor derulante la bara de meniuri ... // Atasarea barei de meniuri la o fereastra Frame f = new Frame("Fereastra cu meniu"); f.addMenuBar(mb);

Orice articol al unui meniu trebuie s fie o instana a clasei MenuItem. Obiectele acestei clase descriu aadar opiunile individuale ale meniurilor derulante, cum sunt Open, Close, Exit, etc. O instan a clasei MenuItem reprezint de fapt un buton sau un comutator, cu o anumit etichet care va aprea n meniu, nsoit eventual de un accelerator (obiect de tip MenuShortcut) ce reprezint combinaia de taste cu care articolul poate fi apelat rapid (vezi Acceleratori). Clasa Menu permite crearea unui meniu derulant ntr-o bar de meniuri. Opional, un meniu poate fi declarat ca fiind tear-off, ceea ce nseamn c poate fi deschis i deplasat cu mouse-ul (dragged) ntr-o alt poziie dect cea original (rupt din poziia sa). Acest mecanism este dependent de platform i poate fi ignorat pe unele dintre ele. Fiecare meniu are o etichet, care este de fapt numele su ce va fi afiat pe bara de meniuri. Articolele dintr-un meniu trebuie s aparin clasei MenuItem, ceea ce nseamn c pot fi instane ale uneia din clasele MenuItem, Menu sau CheckboxMenuItem.

Clasa CheckboxMenuItem implementeaz ntr-un meniu articole de tip comutator - care au dou stri logice (validat/nevalidat), acionarea articolului determinnd trecerea sa dintr-o stare n alta. La validarea unui comutator n dreptul etichetei sale va fi afiat un simbol grafic care indic acest lucru; la invalidarea sa, simbolul grafic respectiv va disprea. Clasa CheckboxMenuItem are aceeai funcionalitate cu cea a casetelor de validare de tip Checkbox, ambele implementnd interfaa ItemSelectable. S vedem n continuare cum ar arta un program care construiete un meniu ca n figura prezentat anterior:
Crearea unui meniu import java . awt .*; import java . awt. event .*; public class TestMenu { public static void main ( String args []) { Frame f = new Frame (" Test Menu "); MenuBar mb = new MenuBar (); Menu fisier = new Menu (" File "); fisier . add( new MenuItem (" Open ")); fisier . add( new MenuItem (" Close ")); fisier . addSeparator (); fisier . add( new MenuItem (" Exit ")); Menu optiuni = new Menu (" Options "); optiuni . add( new MenuItem (" Copy ")); optiuni . add( new MenuItem ("Cut")); optiuni . add( new MenuItem (" Paste ")); Menu editare = new Menu (" Edit "); editare . add( new MenuItem (" Undo ")); editare . add( optiuni ); editare . addSeparator (); editare . add( new CheckboxMenuItem (" Bold ")); editare . add( new CheckboxMenuItem (" Italic ")); mb. add( fisier ); mb. add( editare ); f. setMenuBar (mb); f. setSize (200 , 100) ; f. setVisible(true); } }//lab9d //lab9_3

6.6.2 Tratarea evenimentelor generate de meniuri La alegerea unei opiuni dintr-un meniu se genereaz fie un eveniment de tip ActionEvent dac articolul respectiv este de tip MenuItem, fie ItemEvent pentru comutatoarele CheckboxMenuItem. Aadar, pentru a activa opiunile unui meniu trebuie implementate interfaele ActionListener sau/i ItemListener n cadrul obiectelor care trebuie s specifice codul ce va fi executat la alegerea unei opiuni i implementate metodele actionPerformed, respectiv itemStateChanged. Fiecrui meniu i putem asocia un obiect receptor diferit, ceea ce uureaz munca n cazul n care ierarhia de meniuri este complex. Pentru a realiza legtura ntre obiectul meniu i obiectul de tip listener trebuie s adaugm receptorul n lista de asculttori a meniului respectiv, ntocmai ca pe orice component, folosind metodele addActionListener, respectiv addItemListener.

Aadar, tratarea evenimentelor generate de obiecte de tip MenuItem este identic cu tratarea butoanelor, ceea ce face posibil ca unui buton de pe suprafaa de afiare s i corespund o opiune dintr-un meniu, ambele cu acelai nume, tratarea evenimentului corespunztor apsarii butonului, sau alegerii opiunii, fcndu-se o singur dat ntr-o clas care este nregistrat ca receptor att la buton ct i la meniu. Obiectele de tip CheckboxMenuItem tip se gsesc ntr-o categorie comun cu List, Choice, CheckBox, toate implementnd interfaa ItemSelectable i deci tratarea lor va fi fcut la fel. Tipul de operatie selectare / deselectare este codificat n evenimentul generat de cmpurile statice ItemEvent.SELECTED i ItemEvent.DESELECTED.
Tratarea evenimentelor unui meniu import java . awt .*; import java . awt. event .*; public class TestMenuEvent extends Frame implements ActionListener , ItemListener { public TestMenuEvent ( String titlu ) { super ( titlu ); MenuBar mb = new MenuBar (); Menu test = new Menu (" Test "); CheckboxMenuItem check = new CheckboxMenuItem (" Check me"); test . add( check ); test . addSeparator (); test . add( new MenuItem (" Exit ")); mb. add( test ); setMenuBar (mb); Button btnExit = new Button (" Exit "); add ( btnExit , BorderLayout . SOUTH ); setSize (300 , 200) ; setVisible(true); test . addActionListener ( this ); check . addItemListener ( this ); btnExit . addActionListener ( this ); } public void actionPerformed ( ActionEvent e) { // Valabila si pentru meniu si pentru buton String command = e. getActionCommand (); if ( command . equals (" Exit ")) System . exit (0); } public void itemStateChanged ( ItemEvent e) { if (e. getStateChange () == ItemEvent . SELECTED ) setTitle (" Checked !"); else setTitle ("Not checked !"); } public static void main ( String args []) { TestMenuEvent f=new TestMenuEvent(" Tratare evenimente meniuri "); f. setVisible(true); } }//lab9e //lab9_4

6.6.3 Meniuri de context (popup)

Au fost introduce ncepnd cu AWT 1.1 i sunt implementate prin intermediul clasei PopupMenu, subclas direct a clasei Menu. Sunt meniuri invizibile care sunt activate uzual prin apsarea butonului drept al mouse-ului, fiind afiate la poziia la care se gsea mouse-ul n momentul apsrii butonului su drept. Metodele de adugare a articolelor unui meniu de context sunt motenite ntocmai de la meniurile fixe.
PopupMenu popup = new PopupMenu("Options"); popup.add(new MenuItem("New")); popup.add(new MenuItem("Edit")); popup.addSeparator(); popup.add(new MenuItem("Exit"));

Afiarea meniului de context se face prin metoda show:


popup.show(Component origine, int x, int y)

i este de obicei rezultatul apsarii unui buton al mouse-ului, pentru a avea acces rapid la meniu. Argumentul origine reprezint componenta fa de originile creia se va calcula poziia de afiare a meniului popup. De obicei, reprezint instana ferestrei n care se va afia meniul. Deoarece interaciunea cu mouse-ul este dependent de platforma de lucru, exist o metod care determin dac un eveniment de tip MouseEvent poate fi responsabil cu deschiderea unui meniu de context. Aceasta este isPopupTrigger i este definit n clasa MouseEvent. Poziionarea i afiarea meniului este ns responsabilitatea programatorului. Meniurile de context nu se adaug la un alt meniu (bar sau sub-meniu) ci se ataeaz la o component (de obicei la o fereastr) prin metoda add a acesteia. In cazul cnd avem mai multe meniuri popup pe care vrem s le folosim ntr-o fereastr, trebuie s le definim pe toate i, la un moment dat, vom aduga ferestrei meniul corespunztor dup care l vom face vizibil. Dup nchiderea acestuia, vom rupe legtura ntre fereastr i meniu prin instruciunea remove:
fereastra.add(popup1); ... fereastra.remove(popup1); fereastra.add(popup2);

In exemplul de mai jos, vom crea un meniu de context pe care l vom activa la apsarea butonului drept al mouse-ului pe suprafaa ferestrei principale. Tratarea evenimentelor generate de un meniu popup se realizeaz identic ca pentru meniurile fixe.
Folosirea unui meniu de context (popup) import java . awt .*; import java . awt. event .*; class Fereastra extends Frame implements ActionListener { // Definim meniul popup al ferestrei private PopupMenu popup ; // Pozitia meniului va fi relativa la fereastra private Component origin ; public Fereastra ( String titlu ) { super ( titlu ); origin = this ; this . addWindowListener (new WindowAdapter () { public void windowClosing ( WindowEvent e) { System . exit (0); } }); this . addMouseListener (new MouseAdapter () { public void mousePressed ( MouseEvent e) { if (e. isPopupTrigger ())

popup . show (origin , e. getX () , e. getY ()); } public void mouseReleased ( MouseEvent e) { if (e. isPopupTrigger ()) popup . show (origin , e. getX () , e. getY ()); } }); setSize (300 , 300) ; // Cream meniul popup popup = new PopupMenu (" Options "); popup .add(new MenuItem ("New")); popup .add(new MenuItem (" Edit ")); popup . addSeparator (); popup .add(new MenuItem (" Exit ")); add ( popup ); // atasam meniul popup ferestrei popup . addActionListener ( this ); } public void actionPerformed ( ActionEvent e) { String command = e. getActionCommand (); if ( command . equals (" Exit ")) System . exit (0); } } public class TestPopupMenu { public static void main ( String args []) { Fereastra f = new Fereastra (" PopupMenu "); f. setVisible(true); } }//lab9f

6.6.4 Acceleratori (Clasa MenuShortcut) Pentru articolele unui meniu este posibil specificarea unor combinaii de taste numite acceleratori (shortcuts) care s permit accesarea direct, prin intermediul tastaturii, a opiunilor dintr-un meniu. Astfel, oricrui obiect de tip MenuItem i poate fi asociat un obiect de tip accelerator, definit prin intermediul clasei MenuShortcut. Singurele combinaii de taste care pot juca rolul acceleratorilor sunt: Ctrl + Tasta sau Ctrl + Shift + Tasta. Atribuirea unui accelerator la un articol al unui meniu poate fi realizat prin constructorul obiectelor de tip MenuItem n forma: MenuItem(String eticheta, MenuShortcut accelerator), ca n exemplele de mai jos:
// Ctrl+O new MenuItem("Open", new MenuShortcut(KeyEvent.VK_O)); // Ctrl+P new MenuItem("Print", new MenuShortcut(p)); // Ctrl+Shift+P new MenuItem("Preview", new MenuShortcut(p), true); //lab9_3,lab9_4

6.7 Folosirea componentelor AWT

In continuare vor fi date exemple de folosire ale componentelor AWT, n care s fie puse n eviden ct mai multe din particularitile acestora, precum i modul de tratare a evenimentelor generate. 6.7.1 Clasa Label Un obiect de tip Label (etichet) reprezint o component pentru plasarea unui text pe o suprafaa de afiare. O etichet este format dintr-o singur linie de text static ce nu poate fi modificat de ctre utilizator, dar poate fi modificat din program.
Folosirea clasei Label import java . awt .*; public class TestLabel { public static void main ( String args []) { Frame f = new Frame (" Label "); Label nord , sud , est , vest , centru ; nord = new Label (" Nord ", Label . CENTER ); nord . setForeground ( Color . blue ); sud = new Label ("Sud ", Label . CENTER ); sud . setForeground ( Color .red); vest = new Label (" Vest ", Label . LEFT ); vest . setFont ( new Font (" Dialog ", Font .ITALIC , 14)); est = new Label ("Est ", Label . RIGHT ); est . setFont ( new Font (" Dialog ", Font .ITALIC , 14)); centru = new Label (" Centru ", Label . CENTER ); centru . setBackground ( Color . yellow ); centru . setFont ( new Font (" Arial ", Font .BOLD , 20)); f.add(nord , BorderLayout . NORTH ); f.add(sud , BorderLayout . SOUTH ); f.add(est , BorderLayout . EAST ); f.add(vest , BorderLayout . WEST ); f.add(centru , BorderLayout . CENTER ); f. pack (); f. setVisible(true); } }

6.7.2 Clasa Button Un obiect de tip Button reprezint o component pentru plasarea unui buton etichetat pe o suprafaa de afiare. Textul etichetei este format dintr-o singur linie.
Folosirea clasei Button import java . awt .*; import java . awt. event .*; class Fereastra extends Frame implements ActionListener { public Fereastra ( String titlu ) { super ( titlu ); this . addWindowListener (new WindowAdapter () { public void windowClosing ( WindowEvent e) { System . exit (0); } }); setLayout ( null ); setSize (200 , 120) ; Button b1 = new Button ("OK");

b1. setBounds (30 , 30, 50, 70); b1. setFont ( new Font (" Arial ", Font .BOLD , 14)); b1. setBackground ( Color . orange ); add (b1); Button b2 = new Button (" Cancel "); b2. setBounds (100 , 30, 70, 50); b2. setForeground ( Color . blue ); add (b2); b1. addActionListener ( this ); b2. addActionListener ( this ); } // Metoda interfetei ActionListener public void actionPerformed ( ActionEvent e) { String command = e. getActionCommand (); System . out. println (e); if ( command . equals ("OK")) setTitle (" Confirmare !"); else if ( command . equals (" Cancel ")) setTitle (" Anulare !"); } } public class TestButton { public static void main ( String args []) { Fereastra f = new Fereastra (" Button "); f. setVisible(true); } }

6.7.3 Clasa Checkbox Un obiect de tip Checkbox (comutator) reprezint o component care se poate gsi n dou stri: selectat sau neselectat (on/off). Aciunea utilizatorului asupra unui comutator l trece pe acesta n starea complementar celei n care se gsea. Este folosit pentru a prelua o anumit opiune de la utilizator.
Folosirea clasei Checkbox import java . awt .*; import java . awt. event .*; class Fereastra extends Frame implements ItemListener { private Label label1 , label2 ; private Checkbox cbx1 , cbx2 , cbx3 ; public Fereastra ( String titlu ) { super ( titlu ); this . addWindowListener (new WindowAdapter () { public void windowClosing ( WindowEvent e) { System . exit (0); } }); setLayout (new GridLayout (5, 1)); label1 = new Label (" Ingrediente Pizza :", Label . CENTER ); label1 . setBackground ( Color . orange ); label2 = new Label (""); label2 . setBackground ( Color . lightGray ); cbx1 = new Checkbox (" cascaval "); cbx2 = new Checkbox (" sunca ");

cbx3 = new Checkbox (" add ( label1 ); add ( label2 ); add ( cbx1 ); add ( cbx2 ); add ( cbx3 ); setSize (200 , 200) ; cbx1 . addItemListener cbx2 . addItemListener cbx3 . addItemListener

ardei ");

( this ); ( this ); ( this );

} // Metoda interfetei ItemListener public void itemStateChanged ( ItemEvent e) { StringBuffer ingrediente = new StringBuffer (); if ( cbx1 . getState () == true ) ingrediente . append (" cascaval "); if ( cbx2 . getState () == true ) ingrediente . append (" sunca "); if ( cbx3 . getState () == true ) ingrediente . append (" ardei "); label2 . setText ( ingrediente . toString ()); } } public class TestCheckbox { public static void main ( String args []) { Fereastra f = new Fereastra (" Checkbox "); f. setVisible(true); } }

6.7.4 Clasa CheckboxGroup Un obiect de tip CheckboxGroup definete un grup de comutatoare din care doar unul poate fi selectat. Uzual, aceste componente se mai numesc butoane radio. Aceast clas nu este derivat din Component, oferind doar o modalitate de grupare a componentelor de tip Checkbox.
Folosirea clasei CheckboxGroup import java . awt .*; import java . awt. event .*; class Fereastra extends Frame implements ItemListener { private Label label1 , label2 ; private Checkbox cbx1 , cbx2 , cbx3 ; private CheckboxGroup cbg ; public Fereastra ( String titlu ) { super ( titlu ); this . addWindowListener (new WindowAdapter () { public void windowClosing ( WindowEvent e) { System . exit (0); } }); setLayout (new GridLayout (5, 1)); label1 = new Label (" Alegeti postul TV", Label . CENTER ); label1 . setBackground ( Color . orange ); label2 = new Label ("", Label . CENTER ); label2 . setBackground ( Color . lightGray );

cbg = new CheckboxGroup (); cbx1 = new Checkbox ("HBO", cbg , false ); cbx2 = new Checkbox (" Discovery ", cbg , false ); cbx3 = new Checkbox ("MTV", cbg , false ); add ( label1 ); add ( label2 ); add ( cbx1 ); add ( cbx2 ); add ( cbx3 ); setSize (200 , 200) ; cbx1 . addItemListener ( this ); cbx2 . addItemListener ( this ); cbx3 . addItemListener ( this ); } // Metoda interfetei ItemListener public void itemStateChanged ( ItemEvent e) { Checkbox cbx = cbg. getSelectedCheckbox (); if (cbx != null ) label2 . setText (cbx. getLabel ()); } } public class TestCheckboxGroup { public static void main ( String args []) { Fereastra f = new Fereastra (" CheckboxGroup "); f. setVisible(true); } }

6.7.5 Clasa Choice Un obiect de tip Choice definete o list de opiuni din care utilizatorul poate selecta una singur. La un moment dat, din ntreaga list doar o singur opiune este vizibil, cea selectat n momentul curent. O component Choice este nsoit de un buton etichetat cu o sageat vertical la apsarea cruia este afiat ntreaga sa list de elemente, pentru ca utilizatorul s poat selecta o anumit opiune.
Folosirea clasei Choice import java . awt .*; import java . awt. event .*; class Fereastra extends Frame implements ItemListener { private Label label ; private Choice culori ; public Fereastra ( String titlu ) { super ( titlu ); this . addWindowListener (new WindowAdapter () { public void windowClosing ( WindowEvent e) { System . exit (0); } }); setLayout (new GridLayout (4, 1)); label = new Label (" Alegeti culoarea "); label . setBackground ( Color .red); culori = new Choice (); culori . add(" Rosu "); culori . add(" Verde "); culori . add(" Albastru ");

culori . select (" Rosu "); add ( label ); add ( culori ); setSize (200 , 100) ; culori . addItemListener ( this ); } // Metoda interfetei ItemListener public void itemStateChanged ( ItemEvent e) { switch ( culori . getSelectedIndex ()) { case 0: label . setBackground ( Color .red); break ; case 1: label . setBackground ( Color . green ); break ; case 2: label . setBackground ( Color . blue ); } } } public class TestChoice { public static void main ( String args []) { Fereastra f = new Fereastra (" Choice "); f. setVisible(true); } }

6.7.6 Clasa List Un obiect de tip List definete o list de opiuni care poate fi setat astfel nct utilizatorul s poat selecta o singur opiune sau mai multe. Toate elementele listei sunt vizibile n limita dimensiunilor grafice ale componentei.
Folosirea clasei List import java . awt .*; import java . awt. event .*; class Fereastra extends Frame implements ItemListener { private Label label ; private List culori ; public Fereastra ( String titlu ) { super ( titlu ); this . addWindowListener (new WindowAdapter () { public void windowClosing ( WindowEvent e) { System . exit (0); } }); setLayout (new GridLayout (2, 1)); label = new Label (" Alegeti culoarea ", Label . CENTER ); label . setBackground ( Color .red); culori = new List (3); culori . add(" Rosu "); culori . add(" Verde "); culori . add(" Albastru "); culori . select (3); add ( label ); add ( culori ); setSize (200 , 200) ; culori . addItemListener ( this ); }

// Metoda interfetei ItemListener public void itemStateChanged ( ItemEvent e) { switch ( culori . getSelectedIndex ()) { case 0: label . setBackground ( Color .red); break ; case 1: label . setBackground ( Color . green ); break ; case 2: label . setBackground ( Color . blue ); } } } public class TestList { public static void main ( String args []) { Fereastra f = new Fereastra (" List "); f. setVisible(true); } }

6.7.7 Clasa ScrollBar Un obiect de tip Scrollbar definete o bar de defilare pe vertical sau orizontal. Este util pentru punerea la dispoziia utilizatorului a unei modaliti sugestive de a alege o anumit valoare dintr-un interval.
Folosirea clasei ScrollBar import java . awt .*; import java . awt. event .*; class Fereastra extends Frame implements AdjustmentListener { private Scrollbar scroll ; private Label valoare ; public Fereastra ( String titlu ) { super ( titlu ); this . addWindowListener (new WindowAdapter () { public void windowClosing ( WindowEvent e) { System . exit (0); } }); setLayout (new GridLayout (2, 1)); valoare = new Label ("", Label . CENTER ); valoare . setBackground ( Color . lightGray ); scroll=new Scrollbar ( Scrollbar . HORIZONTAL , 0, 1, 0,101) ; add ( valoare ); add ( scroll ); setSize (200 , 80); scroll . addAdjustmentListener ( this ); } // Metoda interfetei AdjustmentListener public void adjustmentValueChanged ( AdjustmentEvent e) { valoare . setText ( scroll . getValue () + " %"); } } public class TestScrollbar { public static void main ( String args []) { Fereastra f = new Fereastra (" Scrollbar "); f. setVisible(true); }

6.7.8 Clasa ScrollPane Un obiect de tip ScrollPane permite ataarea unor bare de defilare (orizontal i/sau vertical) oricrei componente grafice. Acest lucru este util pentru acele componente care nu au implementat funcionalitatea de defilare automat, cum ar fi listele (obiecte din clasa List).
Folosirea clasei ScrollPane import java . awt .*; import java . awt. event .*; class Fereastra extends Frame { private ScrollPane sp; private List list ; public Fereastra ( String titlu ) { super ( titlu ); this . addWindowListener (new WindowAdapter () { public void windowClosing ( WindowEvent e) { System . exit (0); } }); list = new List (7); list . add(" Luni "); list . add(" Marti "); list . add(" Miercuri "); list . add(" Joi"); list . add(" Vineri "); list . add(" Sambata "); list . add(" Duminica "); list . select (1); sp = new ScrollPane ( ScrollPane . SCROLLBARS_ALWAYS ); sp. add( list ); add (sp , BorderLayout . CENTER ); setSize (200 , 200) ; } } public class TestScrollPane { public static void main ( String args []) { Fereastra f = new Fereastra (" ScrollPane "); f. setVisible(true); } }

6.7.9 Clasa TextField Un obiect de tip TextField definete un control de editare a textului pe o singur linie. Este util pentru interogarea utilizatorului asupra unor valori.
Folosirea clasei TextField import java . awt .*; import java . awt. event .*; class Fereastra extends Frame implements TextListener { private TextField nume , parola ; private Label acces ; private static final String UID="Adina", PWD="java" ;

public Fereastra ( String titlu ) { super ( titlu ); this . addWindowListener (new WindowAdapter () { public void windowClosing ( WindowEvent e) { System . exit (0); } }); setLayout (new GridLayout (3, 1)); setBackground ( Color . lightGray ); nume = new TextField ("", 30) ; parola = new TextField ("", 10) ; parola . setEchoChar (*); Panel p1 = new Panel (); p1. setLayout ( new FlowLayout ( FlowLayout . LEFT )); p1. add( new Label (" Nume :")); p1. add( nume ); Panel p2 = new Panel (); p2. setLayout ( new FlowLayout ( FlowLayout . LEFT )); p2. add( new Label (" Parola :")); p2. add( parola ); acces=new Label(" Introduceti numele si parola !",Label.CENTER ); add (p1); add (p2); add ( acces ); setSize (350 , 100) ; nume . addTextListener ( this ); parola . addTextListener ( this ); } // Metoda interfetei TextListener public void textValueChanged ( TextEvent e) { if ( nume . getText (). length () == 0 || parola . getText (). length () == 0) { acces . setText (""); return ; } if ( nume . getText (). equals ( UID) && parola . getText (). equals (PWD)) acces . setText (" Acces permis !"); else acces . setText (" Acces interzis !"); } } public class TestTextField { public static void main ( String args []) { Fereastra f = new Fereastra (" TextField "); f. setVisible(true); } }

6.7.10 Clasa TextArea Un obiect de tip TextArea definete un control de editare a textului pe mai multe linii. Este util pentru editarea de texte, introducerea unor comentarii, etc .
Folosirea clasei TextArea import java . awt .*; import java . awt. event .*;

import java .io .*; class Fereastra extends Frame implements TextListener,ActionListener { private TextArea text ; private TextField nume ; private Button salvare ; public Fereastra ( String titlu ) { super ( titlu ); this . addWindowListener (new WindowAdapter () { public void windowClosing ( WindowEvent e) { System . exit (0); } }); setBackground ( Color . lightGray ); text = new TextArea ("",30,10,TextArea.SCROLLBARS_VERTICAL_ONLY); nume = new TextField ("", 12) ; salvare = new Button (" Salveaza text "); salvare . setEnabled ( false ); Panel fisier = new Panel (); fisier . add( new Label (" Fisier :")); fisier . add( nume ); add (fisier , BorderLayout . NORTH ); add (text , BorderLayout . CENTER ); add ( salvare , BorderLayout . SOUTH ); setSize (300 , 200) ; text . addTextListener ( this ); salvare . addActionListener ( this ); } // Metoda interfetei TextListener public void textValueChanged ( TextEvent e) { if ( text . getText (). length () == 0 || nume . getText (). length () == 0) salvare . setEnabled ( false ); else salvare . setEnabled ( true ); } // Metoda interfetei ActionListener public void actionPerformed ( ActionEvent e) { String continut = text . getText (); try { PrintWriter out = new PrintWriter ( new FileWriter ( nume . getText ())); out . print ( continut ); out . close (); text . requestFocus (); } catch ( IOException ex) { ex. printStackTrace (); } } } public class TestTextArea { public static void main ( String args []) { Fereastra f = new Fereastra (" TextArea "); f. setVisible(true); } }

CURS 10 7.Swing 7.1 Introducere 7.1.1 JFC Tehnologia Swing face parte dintr-un proiect mai amplu numit JFC (Java Foundation Classes) care pune la dispoziie o serie ntreag de faciliti pentru scrierea de aplicaii cu o interfa grafic mult mbogit funcional i estetic fa de vechiul model AWT. In JFC sunt incluse urmtoarele: Componente Swing Sunt componente ce nlocuiesc i n acelai timp extind vechiul set oferit de modelul AWT. Look-and-Feel Permite schimbarea nfirii i a modului de interaciune cu aplicaia n funcie de preferinele fiecruia. Acelai program poate utiliza diverse moduri Look-andFeel, cum ar fi cele standard Windows, Mac, Java, Motif sau altele oferite de diveri dezvoltatori, acestea putnd fi interschimbate de ctre utilizator chiar la momentul execuiei . Accessibility API Permite dezvoltarea de aplicaii care s comunice cu dispozitive utilizate de ctre persoane cu diverse tipuri de handicap, cum ar fi cititoare de ecran, dispozitive de recunoatere a vocii, ecrane Braille, etc. Java 2D API Folosind Java 2D pot fi create aplicaii care utilizeaz grafic la un nivel avansat. Clasele puse la dispoziie permit crearea de desene complexe, efectuarea de operaii geometrice (rotiri, scalri, translaii, etc.), prelucrarea de imagini, tiprire, etc. Drag-and-Drop Ofer posibilitatea de a efectua operaii drag-and-drop ntre aplicaii Java i aplicaii native. Internaionalizare Internaionalizarea i localizarea aplicaiilor sunt dou faciliti extrem de importante care permit dezvoltarea de aplicaii care s poat fi configurate pentru exploatarea lor n diverse zone ale globului, utiliznd limba i particularitile legate de formatarea datei, numerelor sau a monedei din zona respectiv. In acest capitol vom face o prezentare scurt a componentelor Swing, deoarece prezentarea detaliata a tuturor facilitilor oferite de JFC ar oferi suficient material pentru un curs de sine stttor. 7.1.2 Swing API Unul din principalele deziderate ale tehnologiei Swing a fost s pun la dispoziie un set de componente GUI extensibile care s permit dezvoltarea rapid de aplicaii Java cu interfa grafic competitiv din punct de vedere comercial. Pentru a realiza acest lucru, API-ul oferit de Swing este deosebit de complex avnd 17 pachete n care se

gsesc sute de clase i interfee. Lista complet a pachetelor din distribuia standard 1.4 este dat n tabelul de mai jos:
javax.accessibility javax.swing.text.html javax.swing.plaf.basic javax.swing.border javax.swing.text.rtf javax.swing.plaf.multi javax.swing.event javax.swing.undo javax.swing.text javax.swing.plaf javax.swing javax.swing.text.parser javax.swing.plaf.metal javax.swing.colorchooser javax.swing.tree javax.swing.table javax.swing.filechooser

Evident, nu toate aceste pachete sunt necesare la dezvolatarea unei aplicaii, cel mai important i care conine componentele de baz fiind javax.swing. Componentele folosite pentru crearea interfeelor grafice Swing pot fi grupate astfel: Componente atomice
JLabel, JButton, JCheckBox, JRadioButton, JScrollBar, JSlider, JProgressBar, JSeparator JToggleButton,

Componente complexe
JTable, JTree, JComboBox, JColorChooser, JOptionPane JSpinner, JList, JFileChooser,

Componente pentru editare de text


JTextField, JFormattedTextField, JEditorPane, JTextPane JPasswordField, JTextArea,

Meniuri
JMenuBar, JMenu, JPopupMenu, JRadioButtonMenuItem JMenuItem, JCheckboxMenuItem,

Containere intermediare
JPanel, JToolBar JScrollPane, JSplitPane, JTabbedPane, JDesktopPane,

Containere de nivel nalt


JFrame, JDialog, JWindow, JInternalFrame, JApplet

7.1.3 Asemnri i deosebiri cu AWT Nu se poate spune c Swing nlocuiete modelul AWT ci l extinde pe acesta din urm adugndu-i noi componente care fie nlocuiesc unele vechi fie sunt cu totul noi. O convenie n general respectat este prefixarea numelui unei clase AWT cu litera J pentru a denumi clasa corespondent din Swing. Astfel, n locul clasei java.awt.Button putem folosi javax.swing.JButton, n loc de java.awt.Label putem folosi javax.swing.JLabel, etc. Este recomandat ca o aplicaie cu interfa grafic s foloseasc fie componente AWT, fie Swing, amestecarea lor fiind mai puin uzual. Aplicaiile GUI vor avea n continuare nevoie de pachetul java.awt deoarece aici sunt definite unele clase utilitare cum ar fi Color, Font, Dimension, etc. care nu au fost rescrise n Swing. De asemenea, pachetul java.awt.event rmne n continuare esenial pentru tratarea evenimentelor generate att de componente AWT ct i de cele din Swing. Pe lng acesta mai poate fi necesar i javax.swing.event care descrie tipuri de evenimente 2

specifice unor componente Swing, mecanismul de tratare a lor fiind ns acelai ca n AWT. Poziionarea componentelor este preluat din AWT, fiind adugate ns noi clase care descriu gestionari de poziionare n completarea celor existente, cum ar fi BoxLayout i SpringLayout. Difer ns modul de lucru cu containere, dup cum vom vedea n seciunea dedicat acestora. Majoritatea componentelor Swing care permit afiarea unui text ca parte a reprezentrii lor GUI pot specifica acel text fie n mod normal folosind un anumit font i o anumit culoare ce pot fi setate cu metodele setFont i setColor, fie prin intermediul limbajului HTML. Folosirea HTML aduce o flexibilitatea deosebit n realizarea interfeei grafice, ntruct putem aplica formatri multiple unui text, descompunerea acestuia pe mai multe linii, etc., singurul dezavantaj fiind ncetinirea etapei de afiare a componentelor.
JButton simplu = new JButton("Text simplu"); JButton html = new JButton( "<html><u>Text</u> <i>formatat</i></html>");

S descriem o aplicaie simpl folosind AWT i apoi Swing, pentru a ne crea o prim impresie asupra diferenelor i asemnrilor dintre cele dou modele.
O aplicaie simpl AWT import java . awt .*; import java . awt. event .*; public class ExempluAWT extends Frame implements ActionListener { public ExempluAWT ( String titlu ) { super ( titlu ); setLayout (new FlowLayout ()); add (new Label (" Hello AWT ")); Button b = new Button (" Close "); b. addActionListener ( this ); add (b); pack (); setVisible(true); } public void actionPerformed ( ActionEvent e) { System . exit (0); } public static void main ( String args []) { new ExempluAWT (" Hello "); } } Aplicaia rescris folosind Swing import javax . swing .*; import java . awt .*; import java . awt. event .*; public class ExempluSwing extends JFrame implements ActionListener { public ExempluSwing ( String titlu ) { super ( titlu ); // Metoda setLayout nu se aplica direct ferestrei getContentPane (). setLayout (new FlowLayout ()); // Componentele au denumiri ce incep cu litera J // Textul poate fi si in format HTML getContentPane ().add( new JLabel (

"<html ><u>Hello </u> <i>Swing </i ></ html >")); JButton b = new JButton (" Close "); b. addActionListener ( this ); // Metoda add nu se aplica direct ferestrei getContentPane ().add(b); pack (); setVisible(true); } public void actionPerformed ( ActionEvent e) { // Tratarea evenimentelor se face ca in AWT System . exit (0); } public static void main ( String args []) { new ExempluSwing (" Hello "); } }

7.2 Folosirea ferestrelor Pentru a fi afiate pe ecran componentele grafice ale unei aplicaii trebuie plasate pe o suprafa de afiare (container). Fiecare component poate fi coninut doar ntr-un singur container, adugarea ei pe o supraf nou de afiare determinnd eliminarea ei de pe vechiul container pe care fusese plasat. Intruct containerele pot fi ncapsulate n alte containere, o component va face parte la un moment dat dintr-o ierarhie. Rdcina acestei ierarhii trebuie s fie un aa numit container de nivel nalt, care este reprezentat de una din clasele JFrame, JDialog sau JApplet. Intruct de appleturi ne vom ocupa separat, vom analiza n continuare primele dou clase. In general orice aplicaie Java independent bazat pe Swing conine cel puin un container de nivel nalt reprezentat de fereastra principal a programului, instan a clasei JFrame. Simplificat, un obiect care reprezint o fereastr Swing conine o zon care este rezervat barei de meniuri i care este situat de obieci n partea sa superioar i corpul ferestrei pe care vor fi plasate componentele. Corpul ferestrei este o instan a clasei Container ce poate fi obinut cu metoda getContentPane. Plasarea i aranjarea componentelor pe suprafaa ferestrei se va face deci folosind obiectul de tip Container i nu direct fereastra. Aadar, dei este derivat din Frame, clasa JFrame este folosit ntr-un mod diferit fa de printele su:
Frame f = new Frame(); f.setLayout(new FlowLayout()); f.add(new Button("OK")); JFrame jf = new JFrame(); jf.getContentPane().setLayout(new FlowLayout()); jf.getContentPane().add(new JButton("OK"));

Spre deosebire de Frame, un obiect JFrame are un comportament implicit la nchiderea ferestrei care const n ascunderea ferestrei atunci cnd utilizatorul apas butonul de nchidere. Acest comportament poate fi modificat prin apelarea metodei setDefaultCloseOperation care primete ca argument diverse constante ce se gsesc fie n clasa WindowConstants, fie chiar n JFrame.
jf.setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE); jf.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

Adugarea unei bare de meniuri se realizeaz cu metoda setJMenuBar, care primete o instan de tip JMenuBar. Crearea meniurilor este similar cu modelul AWT. 7.2.1 Ferestre interne Din punctul de vedere al folosirii ferestrelor, aplicaiile pot fi mprite n dou categorii: SDI (Single Document Interface) MDI (Multiple Document Interface) Programele din prima categorie gestioneaz la un moment dat o singur fereastr n care se gsesc componentele cu care interacioneaz utilizatorul. In a doua categorie, fereastra principal a aplicaiei nglobeaz la rndul ei alte ferestre, uzual cu funcionaliti similare, ce permit lucrul concurent pe mai multe planuri. In Swing, clasa JInternalFrame pune la dispoziie o modalitate de a crea ferestre n cadrul altor ferestre. Ferestrele interne au aproximativ aceeai nfiare i funcionalitate cu ferestrele de tip JFrame, singura diferen fiind modul de gestionare a acestora. Uzual, obiectele de tip JInternalFrame vor fi plasate pe un container de tip DesktopPane, care va fi apoi plasat pe o fereastr de tip JFrame. Folosirea clasei DesktopPane este necesar deoarece aceasta tie cum s gestioneze ferestrele interne, avnd n vedere c acestea se pot suprapune i la un moment dat doar una singur este activ. Exemplul urmtor pune n eviden modelul general de creare i afiare a ferestrelor interne:
Folosirea ferestrelor interne import javax . swing .*; import java . awt .*; class FereastraPrincipala extends JFrame { public FereastraPrincipala ( String titlu ) { super ( titlu ); setSize (300 , 200) ; setDefaultCloseOperation ( JFrame . EXIT_ON_CLOSE ); FereastraInterna fin1 = new FereastraInterna (); fin1 . setVisible ( true ); FereastraInterna fin2 = new FereastraInterna (); fin2 . setVisible ( true ); JDesktopPane desktop = new JDesktopPane (); desktop .add( fin1 ); desktop .add( fin2 ); setContentPane ( desktop ); fin2 . moveToFront (); } } class FereastraInterna extends JInternalFrame { static int n = 0; // nr. de ferestre interne static final int x = 30, y = 30; public FereastraInterna () { super (" Document #" + (++ n), true , // resizable true , // closable true , // maximizable

true );// iconifiable setLocation (x*n, y*n); setSize ( new Dimension (200 , 100) ); } } public class TestInternalFrame { public static void main ( String args []) { new FereastraPrincipala("Test ferestre interne").setVisible(true); } } //lab10b,lab10_3

Ferestrele create de acest program vor arta ca n figura de mai jos:

7.3 Clasa JComponent JComponent este superclasa tuturor componentelor Swing, mai puin a celor care descriu containere de nivel nalt JFrame, JDialog, JApplet. Deoarece JComponent extinde clasa Container, deci i Component, ea motenete funcionalitatea general a containerelor i componentelor AWT, furniznd bineneles i o serie ntreag de noi faciliti. Dintre noutile oferite de JComponent amintim: ToolTips Folosind metoda setToolTip poate fi ataat unei componente un text cu explicaii legate de componenta respectiv. Cnd utilizatorul trece cu mouse-ul deasupra componentei va fi afiat, pentru o perioad de timp, textul ajuttor specificat. Chenare Orice component Swing poate avea unul sau mai multe chenare. Specificarea unui chenar se realizeaz cu metoda setBorder. Suport pentru plasare i dimensionare Folosind metodele setPreferredSize, setMinimumSize, setMaximumSize, setAlignmentX, setAlignmentY pot fi controlai parametrii folosii de gestionarii de poziionare pentru plasarea i dimensionarea automat a componentelor n cadrul unui container. Controlul opacitii Folosind metoda setOpaque vom specifica dac o component trebuie sau nu s deseneze toi pixelii din interiorul su. Implicit, valoarea proprietii de opacitate

este false, ceea ce nseamn c este posibil s nu fie desenai unii sau chiar toi pixelii, permind pixelilor de sub component s rmn vizibili (componenta nu este opac). Valoarea proprietii pentru clasele derivate din JComponent depinde n general de Look-and-Feel-ul folosit. Asocierea de aciuni tastelor Pentru componentele Swing exist posibilitatea de a specifica anumite aciuni care s se execute atunci cnd utilizatorul apas o anumit combinaie de taste i componenta respectiv este activ (are focusul). Aceast facilitate simplific varianta iniial de lucru, i anume tratarea evenimentelor de tip KeyEvent printrun obiect KeyListener. Double-Buffering Tehnica de double-buffering, care implic desenarea componentei n memorie i apoi transferul ntregului desen pe ecran, este implementat automat de componentele Swing, spre deosebire de cele AWT unde trebuia realizat manual dac era cazul. Exemplul urmtor ilustreaz modul de folosire a ctorva dintre facilitile amintite mai sus:
Faciliti oferite de clasa JComponent import javax . swing .*; import javax . swing . border .*; import java . awt .*; import java . awt. event .*; class Fereastra extends JFrame { public Fereastra ( String titlu ) { super ( titlu ); getContentPane (). setLayout (new FlowLayout ()); setDefaultCloseOperation ( JFrame . EXIT_ON_CLOSE ); // Folosirea chenarelor Border lowered , raised ; TitledBorder title ; lowered = BorderFactory . createLoweredBevelBorder (); raised = BorderFactory . createRaisedBevelBorder (); title = BorderFactory . createTitledBorder (" Borders "); final JPanel panel = new JPanel (); panel . setPreferredSize (new Dimension (400 ,200) ); panel . setBackground ( Color . blue ); panel . setBorder ( title ); getContentPane ().add( panel ); JLabel label1 = new JLabel (" Lowered "); label1 . setBorder ( lowered ); panel .add( label1 ); JLabel label2 = new JLabel (" Raised "); label2 . setBorder ( raised ); panel .add( label2 ); // Controlul opacitatii JButton btn1 = new JButton (" Opaque "); btn1 . setOpaque ( true ); // implicit panel .add( btn1 ); JButton btn2 = new JButton (" Transparent "); btn2 . setOpaque ( false ); panel .add( btn2 ); // ToolTips label1 . setToolTipText (" Eticheta coborata ");

label2 . setToolTipText (" Eticheta ridicata "); btn1 . setToolTipText (" Buton opac "); // Textul poate fi HTML btn2 . setToolTipText ("<html ><b> Apasati <font color =red >F2 </ font > " + " cand butonul are <u> focusul </u>"); // Asocierea unor actiuni ( KeyBindings ) /* Apasarea tastei F2 cand focusul este pe butonul al doilea va determina schimbarea culorii panelului */ btn2 . getInputMap ().put( KeyStroke . getKeyStroke ("F2"), " schimbaCuloare "); btn2 . getActionMap ().put(" schimbaCuloare ", new AbstractAction () { private Color color = Color .red ; public void actionPerformed ( ActionEvent e) { panel . setBackground ( color ); color = ( color == Color . red ? Color . blue : Color .red); } }); pack (); } } public class TestJComponent { public static void main ( String args []) { new Fereastra (" Facilitati JComponent "). show (); } }//lab10c

7.4 Arhitectura modelului Swing Modelul Swing este bazat pe o arhitectur asemntoare cu MVC (model-viewcontroller). Arhitectura MVC specific descompunerea unei aplicaii vizuale n trei pri separate: Modelul - care va reprezenta datele aplicaiei. Prezentarea - modul de reprezentare vizual a datelor. Controlul - transformarea aciunilor utilizatorului asupra componentelor vizuale n evenimente care s actualizeze automat modelul acestora (datele). Din motive practice, n Swing prile de prezentare i control au fost cuplate deoarece exista o legtur prea strns ntre ele pentru a fi concepute ca entiti separate. Aadar, arhitectura Swing este de fapt o arhitectur cu model separabil, n care datele componentelor (modelul) sunt separate de reprezentarea lor vizual. Aceast abordare este logic i din perspectiva faptului c, n general, modul de concepere a unei aplicaii trebuie s fie orientat asupra reprezentrii i manipulrii informaiilor i nu asupra interfeei grafice cu utilizatorul. Pentru a realiza separarea modelului de prezentare, fiecrui obiect corespunztor unei clase ce descrie o component Swing i este asociat un obiect care gestioneaz datele sale i care implementeaz o interfa care reprezint modelul componentei respective. Dup cum se observ din tabelul de mai jos, componente cu reprezentri diferite pot avea acelai tip de model, dar exist i componente care au asociate mai multe modele: Model ButtonModel Component JButton, JToggleButton, JCheckBox,

JRadioButton, JMenu, JMenuItem, JCheckBoxMenuItem, JRadioButtomMenuItem ComboBoxModel JComboBox BoundedRangeModel JProgressBar, JScrollBarm, JSlider SingleSelectionModel JTabbedPane ListModel JList ListSelectionModel JList TableModel JTable TableColumnModel JTable TreeModel JTree TreeSelectionModel JTree Document JEditorPane, JTextPane, JTextArea, JTextField, JPasswordField Fiecare component are un model iniial implicit, ns are posibilitatea de a-l nlocui cu unul nou atunci cnd este cazul. Metodele care acceseaz modelul unui obiect sunt: setModel, respectiv getModel, cu argumente specifice fiecrei componente n parte. Crearea unei clase care s reprezinte un model se va face extinznd interfaa corespunztoare i implementnd metodele definite de aceasta sau extinznd clasa implicit oferit de API-ul Swing i supradefinind metodele care ne intereseaz. Pentru modelele mai complexe, cum ar fi cele asociate claselor JTable, JTree sau JList exist clase abstracte care implementeaz interfaa ce descrie modelul respectiv De exemplu, interfaa model a clasei JList este ListModel care este implementat de clasele DefaultListModel i AbstractListModel. In funcie de necesiti, oricare din aceste clase poate fi extins pentru a crea un nou model.
Folosirea mai multor modele pentru o componenta import javax . swing .*; import java . awt .*; import java . awt. event .*; class Fereastra extends JFrame implements ActionListener { String data1 [] = {" rosu ", " galben ", " albastru "}; String data2 [] = {"red", " yellow ", " blue "}; int tipModel = 1; JList lst; ListModel model1 , model2 ; public Fereastra ( String titlu ) { super ( titlu ); setDefaultCloseOperation ( JFrame . EXIT_ON_CLOSE ); // Lista initiala nu are nici un model lst = new JList (); getContentPane ().add(lst , BorderLayout . CENTER ); // La apasara butonului schimbam modelul JButton btn = new JButton (" Schimba modelul "); getContentPane ().add(btn , BorderLayout . SOUTH ); btn . addActionListener ( this ); // Cream obiectele corespunzatoare celor doua modele model1 = new Model1 (); model2 = new Model2 (); lst . setModel ( model1 ); pack (); }

public void actionPerformed ( ActionEvent e) { if ( tipModel == 1) { lst . setModel ( model2 ); tipModel = 2; } else { lst . setModel ( model1 ); tipModel = 1; } } // Clasele corespunzatoare celor doua modele class Model1 extends AbstractListModel { public int getSize () { return data1 . length ; } public Object getElementAt ( int index ) { return data1 [ index ]; } } class Model2 extends AbstractListModel { public int getSize () { return data2 . length ; } public Object getElementAt ( int index ) { return data2 [ index ]; } } } public class TestModel { public static void main ( String args []) { new Fereastra (" Test Model "). setVisible (true); } }//lab10d, lab10_5

Multe componente Swing furnizeaz metode care s obin starea obiectului fr a mai fi nevoie s obinem instana modelului i s apelm metodele acesteia. Un exemplu este metoda getValue a clasei JSlider care este de fapt un apel de genul getModel().getValue(). In multe situaii ns, mai ales pentru clase cum ar fi JTable sau JTree, folosirea modelelor aduce flexibilitate sporit programului i este recomandat utilizarea lor. 7.4.1 Tratarea evenimentelor Modelele componentelor trebuie s notifice apariia unor schimbri ale datelor gestionate astfel nct s poat fi reactualizat prezentarea lor sau s fie executat un anumit cod n cadrul unui obiect de tip listener. In Swing, aceast notificare este realizat n dou moduri: 1. Informativ (lightweight) - Modelele trimit un eveniment prin care sunt informai asculttorii c a survenit o anumit schimbare a datelor, fr a include n eveniment detalii legate de schimbarea survenit. Obiectele de tip listener vor trebui s apeleze metode specifice componentelor pentru a afla ce anume s-a schimbat. Acest lucru se realizeaz prin interfaa ChangeListener iar evenimentele sunt de tip ChangeEvent,

10

modelele care suport aceast abordare fiind BoundedRangeModel, ButtonModel i SingleSelectionModel.


Model BoundedRangeModel ButtonModel SingleSelectionModelModel Listener ChangeListener ChangeListener ChangeListener Tip Eveniment ChangeEvent ChangeEvent ChangeEvent

Interfaa ChangeListener are o singur metod: public void stateChanged(ChangeEvent e), singura informaie coninut n eveniment fiind componenta surs. Inregistrarea i eliminarea obiectelor de tip listener se realizeaz cu metodele addChangeListener, respectiv removeChangeListener.
JSlider slider = new JSlider(); BoundedRangeModel model = slider.getModel(); model.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { // Sursa este de tip BoundedRangeModel BoundedRangeModel m = (BoundedRangeModel)e.getSource(); // Trebuie sa interogam sursa asupra schimbarii System.out.println("Schimbare model: " + m.getValue()); } });

Pentru uurina programrii, pentru a nu lucra direct cu instana modelului, unele clase permit nregistrarea asculttorilor direct pentru componenta n sine, singura diferen fa de varianta anterioar constnd n faptul c sursa evenimentului este acum de tipul componentei i nu de tipul modelului. Secvena de cod de mai sus poate fi rescris astfel:
JSlider slider = new JSlider(); slider.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { // Sursa este de tip JSlider JSlider s = (JSlider)e.getSource(); System.out.println("Valoare noua: " + s.getValue()); } });

2. Consistent(statefull) - Modele pun la dispoziie interfee specializate i tipuri de evenimente specifice ce includ toate informaiile legate de schimbarea datelor.
Model ListModel ListSelectionModel ComboBoxModel TreeModel TreeSelectionModel TableModel TableColumnModel Document Document Listener ListDataListener ListSelectionListener ListDataListener TreeModelListener TreeSelectionListener TableModelListener TableColumnModelListener DocumentListener UndoableEditListener TipEveniment ListDataEvent ListSelectionEvent ListDataEvent TreeModelEvent TreeSelectionEvent TableModelEvent TableColumnModelEvent DocumentEvent UndoableEditEvent

Folosirea acestor interfee nu difer cu nimic de cazul general:


String culori[] = {"rosu", "galben", "albastru"); JList list = new JList(culori); ListSelectionModel sModel = list.getSelectionModel();

11

sModel.addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent e) { // Schimbarea este continuta in eveniment if (!e.getValueIsAdjusting()) { System.out.println("Selectie curenta: " + e.getFirstIndex()); } } });

7.5 Folosirea componentelor Datorit complexitii modelului Swing, n aceast seciune nu vom ncerca o abordare exhaustiv a modului de utilizare a tuturor componentelor, ci vom pune n eviden doar aspectele specifice acestui model, subliniind diferenele i mbuntirile fa AWT. 7.5.1 Componente atomice In categoria componentelor atomice includem componentele Swing cu funcionalitate simpl, a cror folosire este n general asemntoare cu a echivalentelor din AWT. Aici includem: Etichete: JLabel Butoane simple sau cu dou stri: JButton, JCheckBox, JRadioButton, JToggleButton; mai multe butoane radio pot fi grupate folosind clasa ButtonGroup, pentru a permite selectarea doar a unuia dintre ele. Componente pentru progres i derulare: JSlider, JProgressBar, JScrollBar Separatori: JSeparator Deoarece utilizarea acestora este n general facil, nu vom analiza n parte aceste componente. 7.5.2 Componente pentru editare de text Componentele Swing pentru afiarea i editarea textelor sunt grupate ntr-o ierarhie ce are ca rdcin clasa JTextComponent din pachetul javax.swing.text. JTextComponent

JTextField

JTextArea
Text simplu pe mai multe linii

JEditorPane

JPasswordField

JFormattedTextField

JTextPane
Text cu stil imbogatit pe mai multe linii

Text simplu pe o singura linie

12

Dup cum se observ din imaginea de mai sus, clasele pot fi mprite n trei categorii, corespunztoare tipului textului editat: Text simplu pe o singur linie JTextField - Permite editarea unui text simplu, pe o singur linie. JPasswordField - Permite editarea de parole. Textul acestora va fi ascuns, n locul caracterelor introduse fiind afiat un caracter simbolic, cum ar fi *. JFormattedTextField - Permite introducerea unui text care s respecte un anumit format, fiind foarte util pentru citirea de numere, date calendaristice, etc. Este folosit mpreun cu clase utilitare pentru formatarea textelor, cum ar fi NumberFormatter, DateFormatter, MaskFormatter, etc. Valoarea coninut de o astfel de component va fi obinut/setat cu metodele getValue, respectiv setValue i nu cu cele uzuale getText, setText. Text simplu pe mai multe linii JTextArea - Permite editarea unui text simplu, pe mai multe linii. Orice atribut legat de stil, cum ar fi culoarea sau fontul, se aplic ntregului text i nu poate fi specificat doar unei anumite poriuni. Uzual, o component de acest tip va fi inclus ntr-un container JScrollPane, pentru a permite navigarea pe vertical i orizontal dac textul introdus nu ncape n suprafaa alocat obiectului. Acest lucru este valabil pentru toate componentele Swing pentru care are sens noiunea de navigare pe orizontal sau vertical, nici una neoferind suport intrinsec pentru aceast operaiune. Text cu stil mbogit pe mai multe linii JEditorPane - Permite afiarea i editarea de texte scrise cu stiluri multiple i care pot include imagini sau chiar diverse alte componente. Implicit, urmtoarele tipuri de texte sunt recunoscute: text/plain, text/html i text/rtf. Una din utilizrile cele mai simple ale acestei clase este setarea documentului ce va fi afiat cu metoda setPage, ce primete ca argument un URL care poate referi un fiier text, HTML sau RTF. JTextPane - Aceast clas extinde JEditorPane, oferind diverse faciliti suplimentare pentru lucrul cu stiluri i paragrafe. Clasa JTextComponent ncearc s pstreze ct mai multe similitudini cu clasa TextComponent din AWT,ns exist diferene notabile ntre cele dou, componenta Swing avnd caracteristici mult mai complexe cum ar fi suport pentru operaii de undo i redo, tratarea evenimentelor generate de cursor (caret), etc. Orice obiect derivat din JTextComponent este format din: Un model, referit sub denumirea de document, care gestioneaz starea componentei. O referin la model poate fi obinut cu metoda getDocument, ce returneaz un obiect de tip Document. O reprezentare, care este responsabil cu afiarea textului.

13

Un controller, cunoscut sub numele de editor kit care permite scrierea i citirea textului i care permite definirea de aciuni necesare editrii. Exist diferena fa de AWT i la nivelul tratrii evenimentelor generate de componentele pentru editarea de texte. Dintre evenimentele ce pot fi generate amintim: ActionEvent - Componentele derivate din JTextField vor genera un eveniment de acest tip la apsarea tastei Enter n csua de editare a textului. Interfaa care trebuie implementat este ActionListener. CaretEvent - Este evenimentul generat la deplasarea cursorului ce gestioneaz poziia curent n text. Interfaa corespunztoare CaretListener conine o singur metod: caretUpdate ce va fi apelat ori de cte ori apare o schimbare. DocumentEvent - Evenimentele de acest tip sunt generate la orice schimbare a textului, sursa lor fiind documentul (modelul) componentei i nu componenta n sine. Interfaa corespunztoare este DocumentListener, ce conine metodele: insertUpdate - apelat la adugarea de noi caractere; removeUpdate - apelat dup o operaiune de tergere; changedUpdate - apelat la schimbarea unor atribute legate de stilul textului. PropertyChangeEvent - Este un eveniment comun tuturor componentelor de tip JavaBean, fiind generat la orice schimbare a unei proprieti a componentei. Interfaa corespunztoare este Property-ChangeListener, ce conine metoda propertyChange.

14

CURS 11 7.5.3 Componente pentru selectarea unor elemente In aceast categorie vom include clasele care permit selectarea unor valori (elemente) dintr-o serie prestabilit. Acestea sunt: JList, JComboBox i JSpinner. Clasa JList Clasa JList descrie o list de elemente dispuse pe una sau mai multe coloane, din care utilizatorul poate selecta unul sau mai multe. Uzual un obiect de acest tip va fi inclus ntr-un container de tip JScrollPane. Iniializarea unei liste se realizeaz n mai multe modaliti: Folosind unul din constructorii care primesc ca argument un vector de elemente.
Object elemente[]={"Unu", "Doi", new Integer(3), new Double(4)}; JList lista = new JList(elemente);

Folosind constructorul fr argumente i adugnd apoi elemente modelului implicit listei:


DefaultListModel model = new DefaultListModel(); model.addElement("Unu"); model.addElement("Doi"); model.addElement(new Integer(3)); model.addElement(new Double(4)); JList lista = new JList(model);

Folosind un model propriu, responsabil cu furnizarea elementelor listei. Acesta este un obiect dintr-o clas ce trebuie s implementeze interfaa ListModel, uzual fiind folosit extinderea clasei predefinite AbstractListModel i supradefinirea metodelor: getElementAt care furnizeaz elementul de pe o anumit poziie din list, respectiv getSize care trebuie s returneze numrul total de elemente din list. Evident, aceast variant este mai complex, oferind flexibilitate sporit n lucrul cu liste.

ModelLista model = new ModelLista(); JList lista = new JList(model); ... class ModelLista extends AbstractListModel { Object elemente[] = {"Unu", "Doi", new Integer(3), new Double(4)}; public int getSize() { return elemente.length; } public Object getElementAt(int index) { return elemente[index]; } }

Gestiunea articolelor selectate dintr-o list se realizeaz prin intermediul unui model, acesta fiind un obiect de tip ListSelectionModel. Obiectele de tip JList genereaz evenimente de tip ListSelectionEvent, interfaa corespunztoare fiind ListSelectionListener ce conine metoda valueChanged apelat ori de cte ori va fi schimbat selecia elementelor din list.
class Test implements ListSelectionListener { ...

public Test() { ... // Stabilim modul de selectie list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); /* sau SINGLE_INTERVAL_SELECTION MULTIPLE_INTERVAL_SELECTION */ // Adaugam un ascultator ListSelectionModel model = list.getSelectionModel(); model.addListSelectionListener(this); ... } public void valueChanged(ListSelectionEvent e) { if (e.getValueIsAdjusting()) return; int index = list.getSelectedIndex(); ... } }

Evident, clasa ofer metode pentru selectarea unor elemente din cadrul programului setSelectedIndex, setSelectedIndices, etc. i pentru obinerea celor selectate la un moment dat getSelectedIndex, getSelectedIndices, etc.. O facilitate extrem de important pe care o au listele este posibilitatea de a stabili un renderer pentru fiecare articol n parte. Implicit toate elementele listei sunt afiate n acelai fel, ns acest lucru poate fi schimbat prin crearea unei clase ce implementeaz interfaa ListCellRenderer i personalizeaz reprezentarea elementelor listei n funcie de diveri parametri. Interfaa ListCellRenderer conine o singur metod getListCellRendererComponent ce returneaz un obiect de tip Component. Metoda va fi apelat n parte pentru reprezentarea fiecrui element al listei.
class MyCellRenderer extends JLabel implements ListCellRenderer { public MyCellRenderer() { setOpaque(true); } public Component getListCellRendererComponent( JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { setText(value.toString()); setBackground(isSelected ? Color.red : Color.white); setForeground(isSelected ? Color.white : Color.black); return this; } }

Setarea unui anumit renderer pentru o list se realizeaz cu metoda setCellRenderer. Clasa JComboBox Clasa JComboBox este similar cu JList, cu deosebirea c permite doar selectarea unui singur articol, acesta fiind i singurul permanent vizibil. Lista celorlalte elemente este afiat doar la apsarea unui buton marcat cu o sgeat, ce face parte integrant din component. JComboBox funcioneaz dup aceleai principii ca i clasa JList. Iniializarea se face dintr-un vector sau folosind un model de tipul ComboBoxModel, fiecare element

putnd fi de asemenea reprezentat diferit prin intermediul unui obiect ce implementeaz aceeai intefa ca i n cazul listelor:ListCellRenderer. O diferen notabil const n modul de selectare a unui articol, deoarece JComboBox permite i editarea explicit a valorii elementului, acest lucru fiind controlat de metoda setEditable. Evenimentele generate de obiectele JComboBox sunt de tip ItemEvent generate la navigarea prin list, respectiv ActionEvent generate la selectarea efectiv a unui articol. Clasa JSpinner Clasa JSpinner ofer posibilitatea de a selecta o anumit valoare (element) dintrun domeniu prestabilit, lista elementelor nefiind ns vizibil. Este folosit atunci cnd domeniul din care poate fi fcut selecia este foarte mare sau chiar nemrginit; de exemplu: numere intregi intre 1950 si 2050. Componenta conine dou butoane cu care poate fi selectat urmtorul, respectiv predecesorul element din domeniu. JSpiner se bazeaz exclusiv pe folosirea unui model. Acesta este un obiect de tip SpinnerModel, existnd o serie de clase predefinite ce implementeaz aceast interfa cum ar fi SpinnerListModel, SpinnerNumberModel sau SpinnerDateModel ce pot fi utilizate. Componentele de acest tip permit i specificarea unui anumit tip de editor pentru valorile elementelor sale. Acesta este instalat automat pentru fiecare din modelele standard amintite mai sus, fiind reprezentat de una din clasele JSpinner.ListEditor, JSpinner.NumberEditor, respectiv JSpinner.DateEditor, toate derivate din JSpinner.DefaultEditor. Fiecare din editoarele amintite permite diverse formatri specifice. Evenimentele generate de obiectele de tip JSpinner sunt de tip ChangeEvent, generate la schimbarea strii componentei. 7.5.4 Tabele Clasa JTable permite crearea de componente care s afieze o serie de elemente ntr-un format tabelar, articolele fiind dispuse pe linii i coloane. Un tabel poate fi folosit doar pentru afiarea formatat a unor date, dar este posibil i editarea informaiei din celulele sale. De asemenea, liniile tabelului pot fi marcate ca selectate, tipul seleciei fiind simplu sau compus, tabelele extinznd astfel funcionalitatea listelor. Dei clasa JTable se gsete n pachetul javax.swing, o serie de clase i interfee necesare lucrului cu tabele se gsesc n pachetul javax.swing.table, acesta trebuind aadar importat. Iniializarea unui tabel poate fi fcut n mai multe moduri. Cea mai simpl variant este s folosim unul din constructorii care primesc ca argumente elementele tabelului sub forma unei matrici sau a unei colecii de tip Vector i denumirile capurilor de coloan:
String[] coloane = {"Nume", "Varsta", "Student"}; Object[][] elemente = { {"Ionescu", new Integer(20), Boolean.TRUE}, {"Popescu", new Integer(80), Boolean.FALSE}}; JTable tabel = new JTable(elemente, coloane);

Dup cum se observ, tipul de date al elementelor de pe o coloan este de tip referin i poate fi oricare. In cazul n care celulele tabelului sunt editabile trebuie s existe un editor potrivit pentru tipul elementului din celula respectiv. Din motive de eficien, implementarea acestei clase este orientat la nivel de coloan, ceea ce nseamn c articole de pe o coloan vor fi reprezentate la fel i vor avea acelai tip de editor. A doua variant de creare a unui tabel este prin implementarea modelului acestuia ntr-o clas separat i folosirea constructorului corespunztor. Interfaa care descrie modelul clasei JTable este TableModel i conine metodele care vor fi interogate pentru obinerea informaiei din tabel. Uzual, crearea unui model se face prin extinderea clasei predefinite AbstractTableModel, care implementeaz deja TableModel. Tot ceea ce trebuie s facem este s supradefinim metodele care ne intereseaz, cele mai utilizate fiind (primele trei trebuie obligatoriu supradefinite, ele fiind declarate abstracte n clasa de baz): getRowCount - returneaz numrul de linii ale tabelului; getColumnCount - returneaz numrul de coloane ale tabelului; getValueAt - returneaz elementul de la o anumit linie i coloan; getColumnName - returneaz denumirea fiecrei coloane; isCellEditable - specific dac o anumit celul este editabil. Modelul mai conine i metoda setValueAt care poate fi folosit pentru setarea explicit a valorii unei celule.
ModelTabel model = new ModelTabel(); JTable tabel = new JTable(model); ... class ModelTabel extends AbstractTableModel { String[] coloane = {"Nume", "Varsta", "Student"}; Object[][] elemente = { {"Ionescu", new Integer(20), Boolean.TRUE}, {"Popescu", new Integer(80), Boolean.FALSE}}; public int getColumnCount() { return coloane.length; } public int getRowCount() { return elemente.length; } public Object getValueAt(int row, int col) { return elemente[row][col]; } public String getColumnName(int col) { return coloane[col]; } public boolean isCellEditable(int row, int col) { // Doar numele este editabil return (col == 0); } }

Orice schimbare a datelor tabelului va genera un eveniment de tip TableModelEvent. Pentru a trata aceste evenimente va trebui s implementm interfaa TableModelListener ce conine metoda tableChanged. Inregistrarea unui listener va fi fcut pentru modelul tabelului:
public class Test implements TableModelListener { ...

public Test() { ... tabel.getModel().addTableModelListener(this); ... } public void tableChanged(TableModelEvent e) { // Aflam celula care a fost modificata int row = e.getFirstRow(); int col = e.getColumn(); TableModel model = (TableModel)e.getSource(); Object data = model.getValueAt(row, col); ... } }

Tabelele ofer posibilitatea de a selecta una sau mai multe linii, nu neaprat consecutive, gestiunea liniilor selectate fiind realizat prin intermediul unui model. Acesta este o instan ce implementeaz, ntocmai ca la liste, interfaa ListSelectionModel. Tratarea evenimentelor generate de schimbarea seleciei n tabel se realizeaz prin nregistrarea unui asculttor de tip ListSelectionListener:
class Test implements ListSelectionListener { ... public Test() { ... // Stabilim modul de selectie tabel.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); // Adaugam un ascultator ListSelectionModel model = tabel.getSelectionModel(); model.addListSelectionListener(this); ... } public void valueChanged(ListSelectionEvent e) { if (e.getValueIsAdjusting()) return; ListSelectionModel model =(ListSelectionModel)e.getSource(); if (model.isSelectionEmpty()) { // Nu este nici o linie selectata ... } else { int index = model.getMinSelectionIndex(); // Linia cu numarul index este prima selectata ... } } }

Dup cum am spus, celulele unei coloane vor fi reprezentare la fel, fiecare coloan avnd asociat un obiect renderer responsabil cu crearea componentei ce descrie celulele sale. Un astfel de obiect implementeaz interfaa TableCellRenderer, care are o singur metod getTableCellRendererComponent, aceasta fiind responsabil cu crearea componentelor ce vor fi afiate n celulele unei coloane. Implicit, exist o serie de tipuri de date cu reprezentri specifice, cum ar fi: Boolean, Number, Double, Float, Date, ImageIcon, Icon, restul tipurilor avnd o reprezentare standard ce const ntr-o etichet cu reprezentarea obiectului ca ir de caractere. Specificarea unui renderer propriu se realizeaz cu metoda setDefaultRenderer, ce asociaz un anumit tip de date cu un obiect de tip TableRenderer.

public class MyRenderer extends JLabel implements TableCellRenderer { public Component getTableCellRendererComponent(...) { ... return this; } }

O situaie similar o regsim la nivelul editorului asociat celulelor dintr-o anumit coloan. Acesta este un obiect ce implementeaz interfaa TreeCellEditor, ce extinde interfaa CellEditor care generalizeaz conceptul de celul editabil pe care l vom mai regsi la arbori. Implicit, exist o serie de editoare standard pentru tipurile de date menionate anterior, dar este posibil specificarea unui editor propriu cu metoda setDefaultEditor. Crearea unui editor propriu se realizeaz cel mai simplu prin extinderea clasei utilitare AbstractCellEditor, care implementeaz CellEditor, plus implementarea metodei specifice din TreeCellEditor.
public class MyEditor extends AbstractCellEditor implements TableCellEditor { // Singura metoda abstracta a parintelui public Object getCellEditorValue() { // Returneaza valoarea editata ... } // Metoda definita de TableCellEditor public Component getTableCellEditorComponent(...) { // Returneaza componenta de tip editor ... } }

7.5.5 Arbori Clasa JTree permite afiarea unor elemente ntr-o manier ierarhic. Ca orice component Swing netrivial, un obiect JTree reprezint doar o imagine a datelor, informaia n sine fiind manipulat prin intermediul unui model. La nivel structural, un arbore este format dintr-o rdcin, noduri interne care au cel puin un fiu i noduri frunz - care nu mai au nici un descendent. Dei clasa JTree se gsete n pachetul javax.swing, o serie de clase i interfee necesare lucrului cu arbori se gsesc n pachetul javax.swing.tree. Clasa care modeleaz noiunea de nod al arborelui este DefaultMutableTreeNode, aceasta fiind folosit pentru toate tipurile de noduri. Crearea unui arbore presupune aadar crearea unui nod (rdcina), instanierea unui obiect de tip JTree cu rdcina creat i adugarea apoi de noduri frunz ca fii ai unor noduri existente.
String text = "<html><b>Radacina</b></html>"; DefaultMutableTreeNode root = new DefaultMutableTreeNode(text); DefaultMutableTreeNode numere = new DefaultMutableTreeNode("Numere"); DefaultMutableTreeNode siruri = new DefaultMutableTreeNode("Siruri"); for(int i=0; i<3; i++) { numere.add(new DefaultMutableTreeNode(new Integer(i))); siruri.add(new DefaultMutableTreeNode("Sirul " + i)); } root.add(numere); root.add(siruri);

JTree tree = new JTree(root);

Dup cum se observ, nodurile arborelui pot fi de tipuri diferite, reprezentarea lor implicit fiind obinut prin apelarea metodei toString. De asemenea, este posibil specificarea unui text n format HTML ca valoare a unui nod, acesta fiind reprezentat ca atare. Dac varianta adugrii explicite a nodurilor nu este potrivit, se poate implementa o clas care s descrie modelul arborelui. Aceasta trebuie s implementeze intefaa TreeModel. Scopul unei componente de tip arbore este n general selectarea unui nod al ierarhiei. Ca i n cazul listelor sau a tabelelor, gestiunea elementelor selectate se realizeaz printr-un model, n aceast situaie interfaa corespunztoare fiind TreeSelectionModel. Arborii permit nregistrarea unor obiecte listener, de tip TreeSelectionListener, care s trateze evenimentele generate la schimbarea seleciei n arbore.
class Test implements TreeSelectionListener { ... public Test() { ... // Stabilim modul de selectie tree.getSelectionModel().setSelectionMode( TreeSelectionModel.SINGLE_TREE_SELECTION); // Adaugam un ascultator tree.addTreeSelectionListener(this); ... } public void valueChanged(TreeSelectionEvent e) { // Obtinem nodul selectat DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent(); if (node == null) return; // Obtinem informatia din nod Object nodeInfo = node.getUserObject(); ... } }

Fiecare nod al arborelui este reprezentar prin intermediul unei clase renderer. Aceasta implementeaz interfaa TreeCellRenderer, cea folosit implicit fiind DefaultTreeCellRenderer. Prin implementarea interfeei sau extinderea clasei implicite pot fi create modaliti de personalizare a nodurilor arborelui n funcie de tipul sau valoarea acestora. Exist ns i diverse metode de a schimba nfiarea unui arbore fr s crem noi clase de tip TreeCellRenderer. Acestea sunt: setRootVisible - Specific dac rdcina e vizibil sau nu; setShowsRootHandles - Specific dac nodurile de pe primul nivel au simboluri care s permit expandarea sau restrngerea lor. putClientProperty - Stabilete diverse proprieti, cum ar fi modul de reprezentare a relaiilor (liniilor) dintre nodurile printe i fiu:
tree.putClientProperty("JTree.lineStyle", "Angled"); // sau "Horizontal", "None"

Specificarea unei iconie pentru nodurile frunz sau interne:

ImageIcon leaf = createImageIcon("img/leaf.gif"); ImageIcon open = createImageIcon("img/open.gif"); ImageIcon closed = createImageIcon("img/closed.gif"); DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer(); renderer.setLeafIcon(leaf); renderer.setOpenIcon(open); renderer.setClosedIcon(closed); tree.setCellRenderer(renderer);

7.5.6 Containere Dup cum tim, containerele reprezint suprafee de afiare pe care pot fi plasate alte componente, eventual chiar alte containere. Superclasa componentelor de acest tip este Container, clas despre care am mai discutat n capitolul dedicat modelului AWT. Containerele pot fi mprite n dou categorii: 1. Containere de nivel nalt - Acestea sunt JFrame, JDialog, JApplet i reprezint rdcinile ierarhiilor de componente ale unei aplicaii. 2. Containere intermediare - Reprezint suprafee de afiare cu ajutorul crora pot fi organizate mai eficient componentele aplicaiei, putnd fi imbricate. Cele mai importante clase care descriu astfel de containere sunt:
JPanel JScrollPane JTabbedPane JSplitPane JLayeredPane JDesktopPane JRootPane

JPanel are aceeai funcionalitate ca i clasa Panel din AWT, fiind folosit pentru gruparea mai multor componente Swing i plasarea lor mpreun pe o alt suprafa de afiare. Gestionarul de poziionare implicit este FlowLayout, acesta putnd fi schimbat chiar n momentul construirii obiectului JPanel sau ulterior cu metoda setLayout. Adugarea de componente se realizeaz ca pentru orice container, folosind metoda add.
JPanel p = new JPanel(new BorderLayout()); /* Preferabil, deoarece nu mai este construit si un obiect de tip FlowLayout (implicit) */ p.add(new JLabel("Hello")); p.add(new JButton("OK")); ...

JScrollPane este o clas foarte important n arhitectura modelului Swing, deoarece ofer suport pentru derularea pe orizontal i vertical a componentelor a cror reprezentare complet nu ncape n suprafaa asociat, nici o component Swing neoferind suport intrinsec pentru aceast operaie.
String elemente[] = new String[100]; for(int i=0; i<100; i++) elemente[i] = "Elementul " + i; JList lista = new JList(elemente); JScrollPane sp = new JScrollPane(lista); frame.getContentPane().add(sp);

JTabbedPane este util pentru suprapunerea mai multor containere, uzual panouri (obiecte de tip JPanel), pe acelai spaiu de afiare, selectarea unuia sau altui panou

realizndu-se prin intermediul unor butoane dispuse pe partea superioar a componentei, fiecare panou avnd un astfel de buton corespunztor. Ca funcionalitate, ofer o implementare asemntoare gestionarului de poziionare CardLayout.
JTabbedPane tabbedPane = new JTabbedPane(); ImageIcon icon = new ImageIcon("smiley.gif"); JComponent panel1 = new JPanel(); panel1.setOpaque(true); panel1.add(new JLabel("Hello")); tabbedPane.addTab("Tab 1", icon, panel1, "Aici avem o eticheta"); tabbedPane.setMnemonicAt(0, KeyEvent.VK_1); JComponent panel2 = new JPanel(); panel2.setOpaque(true); panel2.add(new JButton("OK")); tabbedPane.addTab("Tab 2", icon, panel2, "Aici avem un buton"); tabbedPane.setMnemonicAt(1, KeyEvent.VK_2);

JSplitPane permite crearea unui container care conine dou componente dispuse fie una lng cealalt, fie una sub alta i separarea acestora prin intermediul unei bare care s permit configurarea suprafeei alocate fiecrei componente.
String elem[] = {"Unu", "Doi", "Trei" }; JList list = new JList(elem); JPanel panel = new JPanel(new GridLayout(3, 1)); panel.add(new JButton("Adauga")); panel.add(new JButton("Sterge")); panel.add(new JButton("Salveaza")); JTextArea text = new JTextArea( "Mai multe componente separate prin\n" + "intermediul containerelor JSplitPane"); // Separam lista de grupul celor trei butoane JSplitPane sp1 = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, list, panel); // Separam containerul cu lista si butoanele // de componenta pentru editare de text JSplitPane sp2 = new JSplitPane( JSplitPane.VERTICAL_SPLIT, sp1, text); frame.getContentPane().add(sp2);

7.5.7 Dialoguri Clasa care descrie ferestre de dialog este JDialog, crearea unui dialog realiznduse prin extinderea acesteia, ntocmai ca n modelul AWT. In Swing exist ns o serie de clase predefinite ce descriu anumite tipuri de dialoguri, extrem de utile n majoritatea aplicaiilor. Acestea sunt: JOptionPane - Permite crearea unor dialoguri simple, folosite pentru afiarea unor mesaje, realizarea unor interogri de confirmare/renunare, etc. sau chiar pentru introducerea unor valori, clasa fiind extrem de configurabil. Mai jos, sunt exemplificate dou modaliti de utilizare a clasei:
JOptionPane.showMessageDialog(frame, "Eroare de sistem !", "Eroare", JOptionPane.ERROR_MESSAGE); JOptionPane.showConfirmDialog(frame, "Doriti inchiderea aplicatiei ? ", "Intrebare",

JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);

JFileChooser - Dialog standard care permite navigarea prin sistemul de fiiere i selectarea unui anumit fiier pentru operaii de deschidere, respectiv salvare. JColorChooser - Dialog standard pentru selectarea ntr-o manier facil a unei culori. ProgressMonitor - Clas utilizat pentru monitorizarea progresului unei operaii consumatoare de timp.

7.6 Desenarea 7.6.1 Metode specifice Dup cum tim, desenarea unei componente este un proces care se executa automat ori de cte ori este necesar. Procesul n sine este asemntor celui din modelul AWT, ns exist unele diferene care trebuie menionate. Orice component se gsete ntr-o ierarhie format de containere, rdcina acesteia fiind un container de nivel nalt, cum ar fi o fereastr sau suprafaa unui applet. Cu alte cuvinte, componenta este plasat pe o suprafa de afiare, care la rndul ei poate fi plasat pe alt suprafa i aa mai departe. Cnd este necesar desenarea componentei respective, fie la prima sa afiare, fie ca urmare a unor aciuni externe sau interne programului, operaia de desenare va fi executat pentru toate containerele, ncepnd cu cel de la nivelul superior. Desenarea se bazeaz pe modelul AWT, metoda cea mai important fiind paint, apelat automat ori de cte ori este necesar. Pentru componentele Swing, aceast metod are ns o implementare specific i nu trebuie supradefinit. Aceasta este responsabil cu apelul metodelor Swing ce deseneaz componenta i anume: paintComponent - Este principala metod pentru desenare ce este supradefinit pentru fiecare component Swing n parte pentru a descrie reprezentarea sa grafic. Implicit, n cazul n care componenta este opac metoda deseneaz suprafaa sa cu culoarea de fundal, dup care va executa desenarea propriu-zis. paintBorder - Deseneaz chenarele componentei (dac exist). Nu trebuie supradefinit. paintChildren - Solicit desenarea componentelor coninute de aceast component (dac exist). Nu trebuie supradefinit. Metoda paint este responsabil cu apelul metodelor amintite mai sus i realizarea unor optimizri legate de procesul de desenare, cum ar fi implementarea mecanismului de double-buffering. Dei este posibil supradefinirea ei, acest lucru nu este recomandat, din motivele amintite mai sus. Ca i n AWT, dac se dorete redesenarea explicit a unei componente se va apela metoda repaint. In cazul n care dimensiunea sau poziia componentei s-au schimbat, apelul metodei revalidate va precede apelul lui repaint. Observaie : Intocmai ca n AWT, desenarea este realizat de firul de execuie care se ocup cu transmiterea evenimentelor. Pe perioada n care acesta este ocupat cu transmiterea unui mesaj nu va fi fcut nici o desenare. De asemenea, dac acesta este blocat ntr-o operaiune de desenare ce consum mult timp, pe perioada respectiv nu va fi transmis nici un mesaj.

7.6.2 Consideraii generale In continuare vom prezenta cteva consideraii generale legate de diferite aspecte ale desenrii n cadrul modelului Swing. Afiarea imaginilor In AWT afiarea unei imagini era realizat uzual prin supradefinirea clasei Canvas i desenarea imaginii n metoda paint a acesteia. In Swing, exist cteva soluii mai simple pentru afiarea unei imagini, cea mai utilizat fiind crearea unei etichete (JLabel) sau a unui buton (JButton) care s aib setat o anumit imagine pe suprafaa sa. Imaginea respectiv trebuie creat folosind clasa ImageIcon.
ImageIcon img = new ImageIcon("smiley.gif"); JLabel label = new JLabel(img);

Transparena Cu ajutorul metodei setOpaque poate fi controlat opacitatea componentelor Swing. Aceasta este o facilitate extrem de important deoarece permite crearea de componente care nu au form rectangular. De exemplu, un buton circular va fi construit ca fiind transparent (setOpaque(false)) i va desena n interiorul su o elips umplut cu o anumit culoare. Evident, este necesar implementarea de cod specific pentru a trata apsarea acestui tip de buton. Transparena ns vine cu un anumit pre, deoarece pentru componentele transparente vor trebui redesenate containerele pe care se gsete aceasta, ncetinind astfel procesul de afiare. Din acest motiv, de fiecare dat cnd este cazul, se recomand setarea componentelor ca fiind opace (setOpaque(true)). Dimensiunile componentelor Dup cum tim, orice component este definit de o suprafa rectangular. Dimensiunile acesteia pot fi obinute cu metodele getSize, getWidth, getHeight. Acestea includ ns i dimensiunile chenarelor, evident dac acestea exist. Suprafaa ocupat de acestea poate fi aflat cu metoda getInsets ce va returna un obiect de tip Insets ce specific numrul de pixeli ocupai cu chenare n jurul componentei.
public void paintComponent(Graphics g) { ... Insets insets = getInsets(); int currentWidth = getWidth() - insets.left - insets.right; int currentHeight = getHeight() - insets.top - insets.bottom; ... }

Contexte grafice Argumentul metodei paintComponent este de tip Graphics ce ofer primitivele standard de desenare. In majoritatea cazurilor ns, argumentul este de fapt de tip Graphics2D, clas ce extinde Graphics i pune la dispoziie metode mai sofisticate de desenare cunoscute sub numele de Java2D. Pentru a avea acces la API-ul Java2D, este suficient s facem conversia argumentului ce descrie contextul grafic:
public void paintComponent(Graphics g) { Graphics2D g2d = (Graphics2D)g; // Desenam apoi cu g2d

... }

In Swing, pentru a eficientiza desenarea, obiectul de tip Graphics primit ca argument de metoda paintComponent este refolosit pentru desenarea componentei, a chenarelor i a fiilor si. Din acest motiv este foarte important ca atunci cnd supradefinim metoda paintComponent s ne asigurm c la terminarea metodei starea obiectului Graphics este aceeai ca la nceput. Acest lucru poate fi realizat fie explicit, fie folosind o copie a contextului grafic primit ca argument:
// 1.Explicit Graphics2D g2d = (Graphics2D)g; g2d.translate(x, y); // modificam contexul ... g2d.translate(-x, -y); // revenim la starea initiala // 2. Folosirea unei copii Graphics2D g2d = (Graphics2D)g.create(); g2d.translate(x, y); ... g2d.dispose();

7.7 Look and Feel Prin sintagma Look and Feel (L&F) vom nelege modul n care sunt desenate componentele Swing i felul n care acestea interacioneaz cu utilizatorul. Posibilitatea de a alege ntre diferite moduri L&F are avantajul de a oferi prezentarea unei aplicaii ntr-o form grafic care s corespund preferinelor utilizatorilor. In principiu, variantele originale de L&F furnizate n distribuia standard ofereau modalitatea ca o interfa Swing fie s se ncadreze n ansamblul grafic al sistemului de operare folosit, fie s aib un aspect specific Java. Orice L&F este descris de o clas derivat din LookAndFeel. Distribuia standard Java include urmtoarele clase ce pot fi utilizate pentru selectarea unui L&F:
javax.swing.plaf.metal.MetalLookAndFeel com.sun.java.swing.plaf.windows.WindowsLookAndFeel

Este varianta implicit de L&F i are un aspect specific Java. Varianta specific sistemelor de operare Windows. Incepnd cu versiunea 1.4.2 exist i implementarea pentru Windows XP .
com.sun.java.swing.plaf.mac.MacLookAndFeel com.sun.java.swing.plaf.motif.MotifLookAndFeel com.sun.java.swing.plaf.gtk.GTKLookAndFeel

Varianta specific sistemelor de operare Mac. Specific interfaa CDE/Motif. GTK+ reprezint un standard de creare a interfeelor grafice dezvoltat independent de limbajul Java. (GTK este acronimul de la GNU Image Manipulation Program Toolkit). Folosind acest L&F este posibil i specificarea unei anumite teme prin intermediul unui fiier de resurse sau folosind variabila swing.gtkthemefile, ca n exemplul de mai jos:
java -Dswing.gtkthemefile=temaSpecifica/gtkrc App

Specificare unei anumite interfee L&F poate fi realizat prin mai multe modaliti.

Folosirea clasei UImanager Clasa UIManager pune la dispoziie o serie de metode statice pentru selectarea la momentul execuiei a unui anumit L&F, precum i pentru obinerea unor variante specifice: getLookAndFeel - Obine varianta curent, returnnd un obiect de tip LookAndFeel. setLookAndFeel - Seteaz modul curent L&F. Metoda primete ca argument un obiect dintr-o clas derivat din LookAndFeel, fie un ir de caractere cu numele complet al clasei L&F. getSystemLookAndFeelClassName - Obine variant specific sistemului de operare folosit. In cazul n care nu exist nici o astfel de clas, returneaz varianta standard. getCrossPlatformLookAndFeelClassName - Returneaz interfaa grafic standard Java (JLF).
// Exemple: UIManager.setLookAndFeel( "com.sun.java.swing.plaf.motif.MotifLookAndFeel"); UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName());

Setarea proprietii swing.defaultlaf Exist posibilitatea de a specifica varianta de L&F a aplicaie direct de la linia de comand prin setarea proprietaii swing.defaultlaf:
java -Dswing.defaultlaf= com.sun.java.swing.plaf.gtk.GTKLookAndFeel App java -Dswing.defaultlaf= com.sun.java.swing.plaf.windows.WindowsLookAndFeel App

O alt variant de a seta aceast proprietate este schimbarea ei direct n fiierul swing.properties situat n subdirectorul lib al distribuiei Java.
# Swing properties swing.defaultlaf= com.sun.java.swing.plaf.windows.WindowsLookAndFeel

Ordinea n care este aleas clasa L&F este urmtoarea: 1. Apelul explicit al metodei UIManager.setLookAndFeel naintea crerii unei componente Swing. 2. Proprietatea swing.defaultlaf specificat de la linia de comand. 3. Proprietatea swing.defaultlaf specificat n fiierul swing.properties. 4. Clasa standard Java (JLF). Exist posibilitatea de a schimba varianta de L&F chiar i dup afiarea componentelor. Acesta este un proces care trebuie s actualizeze ierarhiile de componente, ncepnd cu containerele de nivel nalt i va fi realizat prin apelul metodei SwingUtilities.updateComponentTreeUI ce va primi ca argument rdcina unei ierarhii. Secvena care efectueaz aceast operaie pentru o fereastr f este:
UIManager.setLookAndFeel(numeClasaLF); SwingUtilities.updateComponentTreeUI(f); f.pack();

CURS 12 8. Appleturi 8.1 Introducere Definiie Un applet reprezint un program Java de dimensiuni reduse ce gestioneaz o suprafa de afiare (container) care poate fi inclus ntr-o pagin Web. Un astfel de program se mai numete miniaplicatie. Ca orice alt aplicaie Java, codul unui applet poate fi format din una sau mai multe clase. Una dintre acestea este principal i extinde clasa Applet, aceasta fiind clasa ce trebuie specificat n documentul HTML ce descrie pagina Web n care dorim s includem appletul. Diferena fundamental dintre un applet i o aplicaie const n faptul c un applet nu poate fi executat independent, ci va fi executat de browserul n care este ncrcat pagina Web ce conine appletul respectiv. O aplicaie independent este executat prin apelul interpretorului java, avnd ca argument numele clasei principale a aplicaiei, clasa principal fiind cea care conine metoda main. Ciclul de viat al unui applet este complet diferit, fiind dictat de evenimentele generate de ctre browser la vizualizarea documentului HTML ce conine appletul. Pachetul care ofer suport pentru crearea de appleturi este java.applet, cea mai important clas fiind Applet. In pachetul javax.swing exist i clasa JApplet, care extinde Applet, oferind suport pentru crearea de appleturi pe arhitectura de componente JFC/Swing. Ierarhia claselor din care deriv appleturile este prezentata n figura de mai jos: java.lang.Object java.awt.Component java.awt.Container java.awt.Panel java.applet.Applet javax.swing.JApplet Fiind derivat din clasa Container, clasa Applet descrie de fapt suprafee de afiare, asemenea claselor Frame sau Panel. 8.2 Crearea unui applet simplu Crearea structurii de fiiere i compilarea applet-urilor sunt identice ca n cazul aplicaiilor. Difer n schimb structura programului i modul de rulare a acestuia. S

parcurgem n continuare aceti pai pentru a realiza un applet extrem de simplu, care afieaz o imagine i un ir de caractere. 1. Scrierea codului sursa
import java.awt.* ; import java.applet.* ; public class FirstApplet extends Applet { Image img; public void init() { img = getImage(getCodeBase(), "taz.gif"); } public void paint (Graphics g) { g.drawImage(img, 0, 0, this); g.drawOval(100,0,150,50); g.drawString("Hello! My name is Taz!", 110, 25); } }

Pentru a putea fi executat de browser, clasa principal a appletului trebuie s fie public.

2. Salvarea fisierelor surs Ca orice clas public, clasa principala a appletului va fi salvat ntr-un fiier cu acelai nume i extensia .java. Aadar, vom salva clasa de mai sus ntr-un fiier FirstApplet.java. 3. Compilarea Compilarea se face la fel ca i la aplicaiile independente, folosind compilatorul javac apelat pentru fiierul ce conine appletul.
javac FirstApplet.java

In cazul n care compilarea a reuit va fi generat fisierul FirstApplet.class. 4. Rularea appletului Applet-urile nu ruleaza independent. Ele pot fi rulate doar prin intermediul unui browser: Internet Explorer, Netscape, Mozilla, Opera, etc. Sau printr-un program special cum ar fi appletviewer din kitul de dezvoltare J2SDK. Pentru a executa un applet trebuie s facem dou operaii: Crearea unui fiier HTML n care vom include applet-ul. S considerm fiierul simplu.html, avnd coninutul de mai jos:
<html> <head> <title>Primul applet Java</title> </head> <body> <applet code=FirstApplet.class width=400 height=400> </applet>

</body> </html>

Vizualizarea appletului: se deschide fisierul simplu.html folosind unul din browser-ele amintite sau efectund apelul:
appletviewer simplu.html.

8.3 Ciclul de via al unui applet Execuia unui applet ncepe n momentul n care un browser afieaz o pagin Web n care este inclus appletul respectiv i poate trece prin mai multe etape. Fiecare etap este strns legat de un eveniment generat de ctre browser i determin apelarea unei metode specifice din clasa ce implementeaz appletul. Incrcarea n memorie Este creat o instana a clasei principale a appletului i ncarcat n memorie. Iniializarea Este apelat metoda init ce permite iniializarea diverselor variabile, citirea unor parametri de intrare, etc. Pornirea Este apelat metoda start Execuia propriu-zis Const n interaciunea dintre utilizator i componentele afiate pe suprafaa appletului sau n executarea unui anumit cod ntr-un fir de execuie. In unele situaii ntreaga execuie a appletului se consum la etapele de iniializare i pornire. Oprirea temporar In cazul n care utilizatorul prsete pagina Web n care ruleaz appletul este apelat metoda stop a acestuia, dndu-i astfel posibilitatea s opreasca temporar execuia sa pe perioada n care nu este vizibil, pentru a nu consuma inutil din timpul procesorului. Acelai lucru se ntmpl dac fereastra browserului este minimizat. In momentul cnd pagina Web ce contine appletul devine din nou activ, va fi reapelat metoda start. Oprirea definitiv La nchiderea tuturor instanelor browserului folosit pentru vizualizare, appletul va fi eliminat din memorie i va fi apelat metoda destroy a acestuia, pentru a-i permite s elibereze resursele deinute. Apelul metodei destroy este ntotdeauna precedat de apelul lui stop. Metodele specifice appleturilor Aadar, exist o serie de metode specifice appleturilor ce sunt apelate automat la diverse evenimente generate de ctre browser. Acestea sunt definite n clasa Applet i sunt enumerate n tabelul de mai jos: Metoda Init Situaia n care este apelat La iniializarea appletului. Teoretic, aceast

Start

Stop

Destroy

metod ar trebui s se apeleze o singur dat, la prima afiare a appletului n pagin, ns, la unele browsere, este posibil ca ea s se apeleze de mai multe ori. Imediat dup iniializare i de fiecare dat cnd appletul redevine activ, dup o oprire temporar. De fiecare dat cnd appletul nu mai este vizibil (pagina Web nu mai este vizibil, fereastra browserului este minimizat, etc) i nainte de destroy. La nchiderea ultimei instane a browserului care a ncrcat n memorie clasa principal a appletului.

Observaie : Aceste metode sunt apelate automat de browser i nu trebuie apelate explicit din program ! Structura general a unui applet
import java.applet.Applet; import java.awt.*; import java.awt.event.*; public class StructuraApplet extends Applet { public void init() { } public void start() { } public void stop() { } public void destroy() { } }

8.4. Interfaa grafic cu utilizatorul Dup cum am vzut, clasa Applet este o extensie a superclasei Container, ceea ce nseamn c appleturile sunt, nainte de toate, suprafee de afiare. Plasarea componentelor, gestionarea poziionrii lor i tratarea evenimentelor generate se realizeaz la fel ca i n cazul aplicaiilor. Uzual, adugarea componentelor pe suprafaa appletului precum i stabilirea obiectelor responsabile cu tratarea evenimentelor generate sunt operaiuni ce vor fi realizate n metoda init. Gestionarul de poziionare implicit este FlowLayout, ns acesta poate fi schimbat prin metoda setLayout. Desenarea pe suprafaa unui applet Exist o categorie ntreag de appleturi ce nu comunic cu utilizatorul prin intermediul componentelor ci, execuia lor se rezum la diverse operaiuni de desenare

realizate n metoda paint. Reamintim c metoda paint este responsabil cu definirea aspectului grafic al oricrei componente. Implicit, metoda paint din clasa Applet nu realizeaz nimic, deci, n cazul n care dorim s desenm direct pe suprafaa unui applet va fi nevoie s supradefinim aceast metod.
public void paint(Graphics g) { // Desenare ... }

In cazul n care este aleas aceast soluie, evenimentele tratate uzual vor fi cele generate de mouse sau tastatur. 8.5 Definirea i folosirea parametrilor Parametrii sunt pentru appleturi ceea ce argumentele de la linia de comand sunt pentru aplicaiile independente. Ei permit utilizatorului s personalizeze aspectul sau comportarea unui applet fr a-i schimba codul i recompila clasele. Definirea parametrilor se face n cadrul tagului APPLET din documentul HTML ce conine appletul i sunt identificai prin atributul PARAM. Fiecare parametru are un nume, specificat prin NAME i o valoare, specificat prin VALUE, ca n exemplul de mai jos:
<APPLET CODE="TestParametri.class" WIDTH=100 HEIGHT=50> <PARAM NAME=textAfisat VALUE="Salut"> <PARAM NAME=numeFont VALUE="Times New Roman"> <PARAM NAME=dimFont VALUE=20> </APPLET>

Ca i n cazul argumentelor trimise aplicaiilor de la linia de comand, tipul parametrilor este ntotdeauna ir de caractere, indiferent dac valoarea este ntre ghilimele sau nu. Fiecare applet are i un set de parametri prestabilii ale cror nume nu vor putea fi folosite pentru definirea de noi parametri folosind metoda de mai sus. Acetia apar direct n corpul tagului APPLET i definesc informaii generale despre applet. Exemple de astfel de parametri sunt CODE, WIDTH sau HEIGHT. Lista lor complet va fi prezentata la descrierea tagului APPLET. Folosirea parametrilor primii de ctre un applet se face prin intermediul metodei getParameter care primete ca argument numele unui parametru i returneaz valoarea acestuia. In cazul n care nu exist nici un parametru cu numele specificat, metoda ntoarce null, caz n care programul trebuie s atribuie o valoare implicit variabilei n care se dorea citirea respectivului parametru. Orice applet poate pune la dispoziie o documentaie referitoare la parametrii pe care i suport, pentru a veni n ajutorul utilizatorilor care doresc s includ appletul ntro pagin Web. Aceasta se realizeaz prin supradefinirea metodei getParameterInfo, care returneaz un vector format din triplete de iruri. Fiecare element al vectorului este de fapt un vector cu trei elemente de tip String, cele trei iruri reprezentnd numele parametrului, tipul su i o descriere a sa. Informaiile furnizate de un applet pot fi citite din browserul folosit pentru vizualizare prin metode specifice acestuia. De exemplu, n appletviewer informaiile despre parametri pot fi vizualizate la rubrica Info din meniul Applet, n Netscape se folosete opiunea Page info din meniul View, etc.

S scriem un applet care s afieze un text primit ca parametru, folosind un font cu numele i dimensiunea specificate de asemenea ca parametri.
Folosirea parametrilor import java . applet . Applet ; import java . awt .*; public class TestParametri extends Applet { String text , numeFont ; int dimFont ; public void init () { text = getParameter (" textAfisat "); if ( text == null ) text = " Hello "; // valoare implicita numeFont = getParameter (" numeFont "); if ( numeFont == null ) numeFont = " Arial "; try { dimFont = Integer . parseInt ( getParameter (" dimFont ")); } catch ( NumberFormatException e) { dimFont = 16; } } public void paint ( Graphics g) { g. setFont (new Font ( numeFont , Font .BOLD , dimFont )); g. drawString (text , 20, 20); } public String [][] getParameterInfo () { String [][] info = { // Nume Tip Descriere {" textAfisat ", " String ", " Sirul ce va fi afisat "}, {" numeFont ", " String ", " Numele fontului "}, {" dimFont ", "int ", " Dimensiunea fontului "} }; return info ; } }

8.6 Tag-ul APPLET Sintaxa complet a tagului APPLET, cu ajutorul cruia pot fi incluse appleturi n cadrul paginilor Web este:
<APPLET CODE = clasaApplet WIDTH = latimeInPixeli HEIGHT = inaltimeInPixeli [ARCHIVE = arhiva.jar] [CODEBASE = URLApplet] [ALT = textAlternativ] [NAME = numeInstantaApplet] [ALIGN = aliniere] [VSPACE = spatiuVertical] [HSPACE = spatiuOrizontal] > [< PARAM NAME = parametru1 VALUE = valoare1 >] [< PARAM NAME = parametru2 VALUE = valoare2 >] ... [text HTML alternativ]

</APPLET>

Atributele puse ntre paranteze ptrate sunt opionale. CODE = clasaApplet Numele fiierului ce conine clasa principal a appletului. Acesta va fi cutat n directorul specificat de CODEBASE. Nu poate fi absolut i trebuie obligatoriu specificat. Extensia .class poate sau nu s apar. WIDTH =latimeInPixeli, HEIGHT =inaltimeInPixeli Specific limea i nlimea suprafeei n care va fi afiat appletul. Sunt obligatorii. ARCHIVE = arhiva.jar Specific arhiva n care se gsesc clasele appletului. CODEBASE = directorApplet Specific URL-ul la care se gsete clasa appletului. Uzual se exprim relativ la directorul documentului HTML. In cazul n care lipsete, se consider implicit URL-ul documentului. ALT = textAlternativ Specific textul ce trebuie afiat dac browserul nelege tagul APPLET dar nu poate rula appleturi Java. NAME =numeInstantaApplet Ofer posibilitatea de a da un nume respectivei instane a appletului, astfel nct mai multe appleturi aflate pe aceeai pagin s poat comunica ntre ele folosindu-se de numele lor. ALIGN =aliniere Semnific modalitatea de aliniere a appletului n pagina Web. Acest atribut poate primi una din urmtoarele valori: left, right, top, texttop, middle, absmiddle, baseline, bottom, absbottom , seminificaiile lor fiind aceleai ca i la tagul IMG. VSPACE =spatiuVertical, HSPACE = spatiuOrizontal Specific numarul de pixeli dintre applet i marginile suprafetei de afiare. PARAM Tag-urile PARAM sunt folosite pentru specificarea parametrilor unui applet . text HTML alternativ Este textul ce va fi afiat n cazul n care browserul nu ntelege tagul APPLET. Browserele Java-enabled vor ignora acest text. 8.7. Alte metode oferite de clasa Applet Pe lng metodele de baz: init, start, stop, destroy, clasa Applet ofer metode specifice applet-urilor cum ar fi: Punerea la dispozitie a unor informaii despre applet Similar cu metoda getParameterInfo ce oferea o documentaie despre parametrii pe care i accept un applet, exist metoda getAppletInfo ce permite specificarea unor informaii legate de applet cum ar fi numele, autorul, versiunea, etc. Metoda returneaz un sir de caractere continnd informaiile respective.
public String getAppletInfo() { return "Applet simplist, autor necunoscut, ver 1.0";

Aflarea adreselor URL referitoare la applet se realizeaz cu metodele: getCodeBase - ce returneaz URL-ul directorului ce conine clasa appletului; getDocumentBase - returneaz URL-ul directorului ce conine documentul HTML n care este inclus appletul respectiv. Aceste metode sunt foarte utile deoarece permit specificarea relativ a unor fiiere folosite de un applet, cum ar fi imagini sau sunete. Afiarea unor mesaje n bara de stare a browserului Acest lucru se realizeaz cu metoda showStatus public void init() { showStatus("Initializare applet..."); } Afiarea imaginilor Afiarea imaginilor ntr-un applet se face fie prin intermediul unei componente ce permite acest lucru, cum ar fi o suprafa de desenare de tip Canvas, fie direct n metoda paint a applet-ului, folosind metoda drawImage a clasei Graphics. In ambele cazuri, obinerea unei referine la imaginea respectiv se va face cu ajutorul metodei getImage din clasa Applet. Aceasta poate primi ca argument fie adresa URL absolut a fiierului ce reprezint imaginea, fie calea relativ la o anumit adres URL, cum ar fi cea a directorului n care se gsete documentul HTML ce conine appletul (getDocumentBase) sau a directorului n care se gsete clasa appletului (getCodeBase).
Afiarea imaginilor import java . applet . Applet ; import java . awt .*; public class Imagini extends Applet { Image img = null ; public void init () { img = getImage ( getCodeBase () , "taz.gif"); } public void paint ( Graphics g) { g. drawImage (img , 0, 0, this ); } }

Aflarea contextului de execuie Contextul de execuie al unui applet se refer la pagina n care acesta ruleaz, eventual mpreun cu alte appleturi, i este descris de interfaa AppletContext. Crearea unui obiect ce implementeaz aceast interfa se realizeaz de ctre browser, la apelul metodei getAppletContext a clasei Applet. Prin intermediul acestei interfee un applet poate vedea n jurul sau, putnd comunica cu alte applet-uri aflate pe aceeasi pagin sau cere browser-ului s deschid diverse documente.

AppletContext contex = getAppletContext();

Afiarea unor documente n browser Se face cu metoda showDocument ce primete adresa URL a fiierului ce conine documentul pe care dorim sa-l deschidem (text, html, imagine, etc). Aceast metod este accesat prin intermediul contextului de execuie al appletului.
try { URL doc = new URL("http://www.uvvgsm.ro"); getAppletContext().showDocument(doc); } catch(MalformedURLException e) { System.err.println("URL invalid! \n" + e); }

Comunicarea cu alte applet-uri Aceast comunicare implic de fapt identificarea unui applet aflat pe aceeai pagina i apelarea unei metode sau setarea unei variabile publice a acestuia. Identificarea se face prin intermediu numelui pe care orice instana a unui applet l poate specifica prin atributul NAME. Obinerea unei referine la un applet al crui nume l cunoatem sau obinerea unei enumerri a tuturor applet-urilor din pagin se fac prin intermediul contextului de execuie, folosind metodele getApplet, respectiv getApplets. Redarea sunetelor Clasa Applet ofer i posibilitatea redrii de sunete n format .au. Acestea sunt descrise prin intermediul unor obiecte ce implementeaz interfaa AudioClip din pachetul java.applet. Pentru a reda un sunet aflat ntr-un fiier .au la un anumit URL exist dou posibiliti: Folosirea metodei play din clasa Applet care primete ca argument URL-ul la care se afl sunetul; acesta poate fi specificat absolut sau relativ la URL-ul appletului Crearea unui obiect de tip AudioClip cu metoda getAudioClip apoi apelarea metodelor start, loop i stop pentru acesta.
Redarea sunetelor import java . applet .*; import java . awt .*; import java . awt. event .*; public class Sunete extends Applet implements ActionListener { Button play = new Button (" Play "); Button loop = new Button (" Loop "); Button stop = new Button (" Stop "); AudioClip clip = null ; public void init () { // Fisierul cu sunetul trebuie sa fie in acelasi // director cu appletul clip = getAudioClip ( getCodeBase () , " sunet .au"); add ( play ); add ( loop ); add ( stop );

play . addActionListener ( this ); loop . addActionListener ( this ); stop . addActionListener ( this ); } public void actionPerformed ( ActionEvent e) { Object src = e. getSource (); if (src == play ) clip . play (); else if (src == loop ) clip . loop (); else if (src == stop ) clip . stop (); } }

In cazul n care appletul folosete mai multe tipuri de sunete, este recomandat ca ncrcarea acestora s fie fcut ntr-un fir de execuie separat, pentru a nu bloca temporar activitatea fireasc a programului. 8.8. Arhivarea appleturilor Dup cum am vzut, pentru ca un applet aflat pe o pagin Web s poat fi executat codul su va fi transferat de pe serverul care gzduiete pagina Web solicitat pe maina clientului. Deoarece transferul datelor prin reea este un proces lent, cu ct dimensiunea fiierelor care formeaz appletul este mai redus, cu att ncrcarea acestuia se va face mai repede. Mai mult, dac appletul conine i alte clase n afar de cea principal sau diverse resurse (imagini, sunete, etc), acestea vor fi transferate prin reea abia n momentul n care va fi nevoie de ele, oprind temporar activitatea appletului pn la ncrcarea lor. Din aceste motive, cea mai eficient modalitate de a distribui un applet este s arhivm toate fiierele necesare acestuia. Arhivarea fiierelor unui applet se face cu utilitarul jar, oferit n distribuia J2SDK. // Exemplu
jar cvf arhiva.jar ClasaPrincipala.class AltaClasa.class imagine.jpg sunet.au

// sau
jar cvf arhiva.jar *.class *.jpg *.au

Includerea unui applet arhivat ntr-o pagin Web se realizeaz specificand pe lng numele clasei principale i numele arhivei care o conine:
<applet archive=arhiva.jar code=ClasaPrincipala width=400 height=200 />

8.9. Restricii de securitate Deoarece un applet se execut pe maina utilizatorului care a solicitat pagina Web ce conine appletul respectiv, este foarte important s existe anumite restricii de securitate care s controleze activitatea acestuia, pentru a preveni aciuni ru intenionate, cum ar fi tergeri de fiiere, etc., care s aduc prejudicii utilizatorului. Pentru a realiza acest lucru, procesul care ruleaz appleturi instaleaz un manager de securitate, adic un obiect de tip SecurityManager care va superviza activitatea metodelor appletului, aruncnd excepii de tip Security Exception n cazul n care una din acestea ncearc s efectueze o operaie nepermis. Un applet nu poate s:

Citeasc sau s scrie fiiere pe calculatorul pe care a fost ncarcat (client). Deschid conexiuni cu alte maini n afar de cea de pe care provine (host). Porneasc programe pe maina client. Citeasc diverse proprieti ale sistemului de operare al clientului. Ferestrele folosite de un applet, altele dect cea a browserului, vor arta altfel dect ntr-o aplicaie obinuit, indicnd faptul c au fost create de un applet. 8.10. Appleturi care sunt i aplicaii Deoarece clasa Applet este derivat din Container, deci i din Component, ea descrie o suprafa de afiare care poate fi inclus ca orice alt component ntr-un alt container, cum ar fi o fereastr. Un applet poate funciona i ca o aplicaie independent astfel: Adugm metoda main clasei care descrie appletul, n care vom face operaiunile urmtoare. Crem o instan a appletului i o adugm pe suprafaa unei ferestre. Apelm metodele init i start, care ar fi fost apelate automat de ctre browser. Facem fereastra vizibil.
Applet import import public i aplicaie java . applet . Applet ; java . awt .*; class AppletAplicatie extends Applet { public void init () { add (new Label (" Applet si aplicatie ")); } public static void main ( String args []) { AppletAplicatie applet = new AppletAplicatie (); Frame f = new Frame (" Applet si aplicatie "); f. setSize (200 , 200) ; f.add(applet , BorderLayout . CENTER ); applet . init (); applet . start (); f. setVisible (true); }