Sunteți pe pagina 1din 116

LUCA DAN ERBNAI

CRENGUA BOGDAN

PROGRAMAREA ORIENTAT SPRE OBIECTE

NOTE DE CURS

2006

CONINUT 1. INTRODUCERE IN PROGRAMAREA ORIENTATA SPRE OBIECTE...3


OBIECTE .....................................................................................................................................3 CLASE DE OBIECTE ......................................................................................................................6

2. RELATII DE ASOCIERE INTRE CLASE ................................................9


CARACTERISTICILE ABORDARII ORIENTATE PE OBIECTE ...............................................................14

3. RELAIA DE GENERALIZARE/SPECIALIZARE NTRE CLASE .........15


MOTENIREA N JAVA ................................................................................................................16

4. ARRAY-URI ..........................................................................................22
INIIALIZAREA UNUI ARRAY .........................................................................................................22 ARRAY-URI MULTIDIMENSIONALE ................................................................................................23 LUCRUL CU ARRAY-URI ..............................................................................................................24 ARRAY N METODE .....................................................................................................................25

5. CLASE ABSTRACTE............................................................................27 6. INTERFETE ..........................................................................................31 7. CLASE INTERNE .................................................................................35


DEFINIREA CLASELOR INTERNE ..................................................................................................35 CLASE INTERNE STATICE ...........................................................................................................36 CLASE INTERNE I MOTENIREA .................................................................................................37 UTILIZAREA CLASELOR INTERNEN APLICAII OO.........................................................................38

8. INPUT/OUTPUT N JAVA.....................................................................41 9. GESTIUNEA EXCEPIILOR ................................................................53 10. COLECTII .............................................................................................60


STRUCTURI DE DATE DINAMICE ..................................................................................................60 TIPOLOGII DE COLECII ..............................................................................................................60 COLECII N JAVA ......................................................................................................................74

11. APPLET ................................................................................................90 12. INTERFETE GRAFICE .........................................................................98 13. EVENIMENTE.....................................................................................104 14. PROGRAMAREA INTERFETELOR GRAFICE CU SWING ...............105
FERESTRE INTERNE.................................................................................................................109 CLASA JVIEWPORT..................................................................................................................110 CLASA JSCROLLPANE ...........................................................................................................112

15. BIBLIOGRAFIE ...................................................................................116

1. INTRODUCERE IN PROGRAMAREA ORIENTATA SPRE OBIECTE


OBIECTE D. Un obiect este un un mod simplificat de a identifica ntr-un program un lucru, o entitate din lumea real sau imaginat. Din punctul de vedere al paradigmei pe obiecte, un obiecte este o combinatie de: - informatii de structura, descrise de o multime de atribute ale obiectului, si - functionalitate descrisa de o multime de operatii ce actioneaza asupra atributelor obiectului si eventual, asupra altor obiecte. D. Un atribut este o abstractizare a unei proprietati a unui obiect din lumea reala. Un atribut se caracterizeaza prin: nume, tip, valoare si eventual constrangeri. De exp, magazinul Tomis, ca orice magazin se caraterizeaza prin urmatoarele proprietati: denumire, numele proprietarului, ora de deschidere si ora de inchidere. In plus, am putea avea si un numar de identificare care sa diferentieze unic magazinul Tomis de orice alt magazin. D. Valorile curente ale tuturor atributelor unui obiect formeaza starea obiectului. De exemplu, starea magazinului Tomis ar putea fi urmatoarea:
numar de identificare= 10 denumire= Tomis numele proprietarului= Ionescu Pop ora de deschidere= 10 ora de inchidere= 18

Atributele unui obiect sunt descrise in momentul analizei si proiectarii programului OO folosind limbajul UML si apoi sunt implementate cu ajutorul variabilelor intr-un limbaj de programare (in particular, Java): Nivelul specificarii (limbajul UML) Nivelul implementarii (limbajul Java) - nrIdentificare: Integer = 10 {valoare unica private int nrIdentificare; pentru fiecare obiect} - denumire: String private String denumire; - numeProprietar: String private String numeProprietar; - oraDeschidere: Integer = 9 private int oraDeschidere= 9; - oraInchidere: Integer = 18 private int oraInchidere= 18; D. O operatie este un algoritm privat al obiectului, adica se executa in mediul su si care opereaza asupra valorilor atributelor sale sau ale altor obiecte pentru a furniza un serviciu unui alt obiect numit client. Operatiile se deduc din responsabilitatile obiectului pe care trebuie sa le indeplineasca. De exemplu, obiectul magazinul 10 trebuie sa furnizeze acces la ora de inchidere a magazinului, adica sa furnizeze informatii de stare a obiectului, deoarece proprietarul magazinului vrea sa stie la ce ora se inchide magazinul. In plus, proprietarul magazinului (ca orice client al obiectului) poate sa modifice ora de inchidere a magazinului, modificand astfel starea obiectului Magazin. Sau proprietarul ar vrea sa stie care este intregul orar al magazinului. Nivelul specificarii (limbajul UML) Nivelul implementarii (limbajul Java) public int getOraInchidere(){ + obtineOraInchidere(): Integer + modificaOraInchidere(nouaOra: Integer)
return oraInchidere; } public void setOraInchidere(int oraNoua){ oraInchidere=oraNoua; }

Nivelul specificarii (limbajul UML) + obtineOrar(): String

Nivelul implementarii (limbajul Java)


public String getOrar(){ return oraDeschidere+:00- +oraInchidere+:00;}

D. Implementarea unei operatii in limbajul Java se numeste metoda. O metoda se caracterizeaza prin urmatoarele elemente: - prototipul metodei = contine elementele de declarare a metodei - semnatura metodei = combinatie intre numele metodei si tipul parametrilor in ordinea declararii lor - definitia metodei = corpul metodei ce contine instructiuni ce implementeaza algoritmul operatiei. Elementele de structura si functionalitate ale unui obiect pot fi proiectate pentru a fi accesibile din afara obiectului. Pana acum, orice client (inclusiv proprietarul) are acces la operatiile obiectului 10 deoarece operatiile respective sunt publice. D. Totalitatea elementelor ce pot fi accesate din exteriorul obiectului formeaza interfata acestuia. Rezulta ca starea unui obiect poate fi modificata numai prin intermediul interfetei lui. Observatie. Desi obiectele se diferentiaza prin stare, aceasta din urma nu asigura identitatea obiectelelor. Adica, puteam avea doua obiecte cu aceeasi stare, dar care sa fie diferite. In cazul obiectului 10, identitatea acestuia este data de valoarea atributului numar de identificare. In acest caz, spunem ca atributul (proprietatea) numar de identificare furnizeaza un criteriu de identitate pentru obiectele de acelasi tip. Principiul OO care sta la baza definirii interfetei unui obiect este cel al incapsularii informatiilor (information hiding). Conform acestui principiu, trebuie sa ascundem in interiorul obiectului ( folosind modificatorul de acces private) toate elementele (atribute sau operatii) care nu sunt utile altor obiecte (numite obiecte client: se afla in exteriorul obiectului si comunica cu el prin mesaje) si sa lasam numai acele informatii in care clientii sunt interesati. De exemplu, interfata obiectului 10 este formata din metodele publice fara sa dam acces direct la variabilele instanta. In acest caz ele sunt variable private. Un alt exemplu il constituie cazul in care proprietarul, ca orice client al obiectului 10, vrea sa stie daca magazinul cu numarul de identificare 10 este deschis sau nu. Solutia este ca obiectul 10 sa aiba o metoda publica care sa-i spuna proprietarului ca este deschis sau nu in functie de momentul apelarii metodei esteDeschis(): Nivelul specificarii Nivelul implementarii (limbajul Java) (limbajul UML) public String getMesaj(){ + obtineRaspuns(): String
} private boolean esteDeschis(){ Calendar c=Calendar.getInstance(); int oraCurenta=c.get(Calendar.HOUR_OF_DAY); if (oraCurenta>=oraDeschidere && oraCurenta<=oraInchidere) return true; return false; } if (esteDeschis()) return Este deschis!; else return Este inchis!;

CONCEPTE Un obiect este o instanta (sau exemplificare) a unui concept. D. Un concept este o idee sau o notiune care se aplica: - unor entitati concrete: lucruri care ne inconjoara sau fapte care se petrec de-a lungul timpului; sau
4

- unor entitati abstracte cum ar fi constructiile noastre mentale. Un concept se caracterizeaza prin trei elemente: - nume: cuvantul pe care-l folosim cand ne referin la acel concept; - semantica: ideea sau notiunea la care se refera numele; - o extensie data de multimea instantelor conceptului. Conceptele pot fi clasificate in mai multe categorii: Categorie Exemple de concepte tangibil persoana, masina, scaun intangibil fiinta din lumea reala lucru din lumea reala descriere a unui alt obiect organizatie loc rol in scenarii reale sau imaginare relational tranzactie elementele ce compun o tranzactie eveniment proces agregat entitate continuta intr-un agregat dispozitiv sistem extern timp, firma persoana, pisica, caine artefact, masina, casa, copac marca de masina, specificatia unei aplicatii OO, documentatie de proiect firma, agentie de voiaj, banca, fundatie magazin, port, oras pilot, administrator, profesor, medic, proprietar, profesor, autor, student, angajat casatorie, asociatie familiala vanzare, rezervare, cumparare, contractare, inchiriere articol dintr-o vanzare de mai multe produse, rezervarea pentru o persoana in rezervarea unei excursii in grup trimitere mesaj, revizie, vizita medicala, inregistrare automobil achizitie on-line a unor produse, nscriere la universitate, admitere clasa de elevi, fereastra de componente grafice, masina, masa, roi de albine elev intr-o clasa, buton intr-o fereastra, motor, picior de masa, albina vitezometru, modem, inregistrator de casa sistemul informatic al serviciului personal, sistemul de contabilitate, sistemul de autorizare a utilizarii unui card bancar factura, log-are, memorarea sosirii unui mesaj in sistem, comanda de
5

Instante de concepte colegul Ionescu, masina mea 17:23, Torent Computers colegul Ionescu, Azor Mercedes Fundatia Oamenilor de afaceri Magazinul Tomis, portul Constanta

inregistrari de contracte sau evenimente

Exemple de concepte Instante de concepte achizitie concepte abstracte calendar gregorian, integrala, multime, ecuatie Observatie. Categoriile de concepte nu sunt ortogonale (adica, independente intre ele), un concept putand sa apartina mai multor categorii. CLASE DE OBIECTE D. O clas este o descriere a unei mulimi de obiecte care au aceleai atribute, aceleai operaii, aceleai relaii cu alte clase i aceeai semantic. Unitatea de baza a limbajului Java (ca orice limbaj orientat spre obiecte) este clasa. Din acest motiv, un program Java contine cel putin o clasa. O clas descrie instantele unui concept. Nivelul conceptual Magazin Nivelul specificarii (limbajul UML)
Magazin
nrIdentificare : Integer denumire : String numeProprietar : String oraDeschidere : Integer oraInchidere : Integer obtineOraInchidere() : Integer obtineOraDeschidere() : Integer modificaOraDeschidere(nouaOra : Integer) modificaOraInchidere(nouaOra : Integer) obtineOrar() : String obtineRaspuns() : String

Categorie

Nivelul implementarii (limbajul Java)


public class Magazin{ private int nrIdentificare; private String denumire, numeProprietar; private int oraDeschidere, oraInchidere; public int getOraInchidere(){ return oraInchidere; } public int getOraDeschidere(){ return oraDeschidere; } public String getMesaj(){ if (esteDeschis()) return Este deschis!; else return Este inchis!; } private boolean esteDeschis(){ Calendar c=Calendar.getInstance(); int oraCurenta=c.get(Calendar.HOUR_OF_DAY); if (oraCurenta>=oraDeschidere && oraCurenta<=oraInchidere) return true; return false; } }

Observatie. Atributele si operatiile obiectelor sunt implementate in Java ca variabile instanta, respectiv metode instanta. O clasa poate defini variabile si metode de clasa. O variabila de clasa implementeaza un atribut al clasei si nu al obiectelor sale. Asadar, valoarea unei variabile de clasa este partajata de toate obiectele clasei respective. De exemplu, pentru a implementa in Java constrangerea ca valoarea variabilei nrIdentificare este unica avem nevoie de o variabila statica care sa numere instantele (obiectele) clasei Magazin: private static int idCurent=1. Valoarea reprezinta numarul de identificare al noului obiect. O metoda de clasa este o metoda care apartine clasei si din acest motiv este definita ca fiind statica si la care au acces toate obiectele clasei.
6

Se pot proiecta si implementa clase care au numai metode statice. Se numesc clase utilitare si furnizeaza servicii globale. De exemplu, clasa Arrays contine metode de sortare a elementelor unui array de numere intregi, numere reale, caractere, inclusiv obiecte dupa diferite criterii. O clasa este un model pentru obiectele sale. De exemplu, toate obiectele clasei Magazin, vor avea aceeasi structura: atribute si operatii. O clasa este o fabrica pentru obiectele sale, deoarece orice clasa are cel putin un constructor. D. Un constructor este o metoda cu ajutorul careia sunt create obiecte din care clasa in care este definit constructorul si initializeaza variabilele instanta ale noului obiect. Alte caracteristici ale unui constructor: - are acelasi nume ca numele clasei - nu are tip al rezultatului - este apelat prefixandu-l cu operatorul new. Folosirea acestui operator determina crearea unei zone de memorie in Heap in care se aloca spatiu pentru fiecare variabila de instanta a obiectului nou creat. Asadar, clasa Magazin are un constructor. Se numeste constructor implicit deoarece este furnizat de Java. Acesta nu are parametri si initializeaza cu valori implicite sau cu valorile definite in sectiunea de declarare a variabilelor instanta. O clasa poate defini explicit unul sau mai multi constructori care sa realizeze initializarea variabilelor instanta si eventual modificarea variabilelor de clasa, daca este necesar. In cazul in care o clasa are mai multi constructori, acestia vor fi spuraincarcati, adica au acelasi nume si difera prin numarul si/sau tipul parametrilor. Sau altfel supus, semnatura lor difera numai prin numarul si/sau tipul parametrilor. De exemplu, clasa Magazin ar putea avea doi constructori:
public Magazin(String numeM, String numeP, int oraD, int oraI) { //Constructor nrIdentificare=idCurent++ ; denumire=numeM; numeProprietar=numeP; oraDeschidere=oraD; oraInchidere=oraI; } public Magazin(String numeM, String numeP) { //Constructor nrIdentificare=idCurent++ ; denumire=numeM; numeProprietar=numeP; oraDeschidere=10; oraInchidere=18; }

this = Cuvnt cheie care se utilizeaz n interiorul corpului unei metode instan i care furnizeaz referina la obiectul pentru care a fost apelat metoda. Intr-un constructor se poate apela un alt constructor al aceleai clase. De exemplu, al doilea constructor ar putea fi definit astfel:
public Magazin(String numeM, String numeP) { this(numeM, numeP, 10, 18); }

n UML reprezentm relaia de instaniere dintre o clas i un obiect al su ca o dependen


clas
instan a Magazin Tomis: Magazin

obiect

Diagrama 1. Relaia de instaniere

O clasa furnizeaza un tip de date cu care putem declara variabile referinta de acest tip. De exemplu, vom scrie o alta clasa TestMagazin care, in metoda main(), sunt create dou obiecte din clasa Magazin i se memoreaza referinele la ele n variabile de acelai tip:
Magazin m1 = new Magazin(Tomis Mall, Ionescu Pop); Magazin m2 = new Magazin(Constanta, Popescu,Ion);

Accesarea variabilelor Variabilele m1 si m2 ar putea fi folosite pentru a accesa valorile variabilelor instan, daca ne dau voie. In cazul in care o variabila instanta furnizeaza acces, atunci puteam folosi operatorul punct pentru a accesa valorile acestora. In cazul variabilelor de clasa, daca aceastea furnizeaza acces, ele sunt modificate sau folosite cu NumeClasa.numeVariabilaClasa. Apelul de metod D. Apel de metoda = mecanism oferit de un limbaj de programare prin care o entitate din program (in cazul nostru un obiect) cere executia unei metode. Aceasta metoda poate sa apartina obiectului apelant (apel intern) sau, in cazul general, poate sa apartina unui alt obiect. Pentru a putea apela o metoda M a unui obiect B, un obiect A trebuie sa aiba acces la metoda M. Accesul la o metoda este stabilit de regulile de vizibilitate din Java. De obicei un apel de metoda are loc in momentul in care obiectul apelant executa o metoda a sa. Apelul metodei intrerupe executia metodei curente si trece controlul metodei apelate. La sfarsitul executiei metodei apelate, controlul revine la metoda intrerupta, exact in punctul de intrerupere. Daca metoda apelata restituie (intoarce) o valoare metodei apelante, aceasta valoare poate participa la calculul unei expresii devenind un operand in acea expresie. Este cazul in care apelul de metoda apare in interiorul unei expresii sau in locul unei expresii. Apelul unei metode poate fi vazut si ca un mesaj pe care obiectul apelant il trimite obiectului apelat. In acest sens putem spune ca obiectele comunic ntre ele prin intermediul metodelor. Apelarea unei metode se face cu ajutorul operatorului binar .. Primul operand al apelului trebuie sa fie o variabila-reference sau o expresie a carui valoare sa fie de tip reference catre un obiect in memorie. Al doilea operand este chiar numele metodei urmat de lista parametrilor efectivi. De exemplu, m1.getMesaj(). In cazul apelurilor de metode ale clasei (este cazul metodelor declarate static), regula de construire a apelului este aceeasi doar ca primul operand trebuie sa fie chiar numele clasei. Nota. Ca si in cazul variabilelor-membru, apelul unei metode apartinand unui obiect din interiorul unei metode che apartine aceluiasi obiect se face fara a utiliza operatorul . si fara a utiliza referinta la obiectul destinatie. Acest obiect este subinteles a fi obiectul curent in care ne aflam cu executia. De exemplu, clasa Magazin are metoda getMesaj() care intoarce un sir care indica daca magazinul este deschis (Este deschis!) sau inchis (Este inchis!) in momentul apelarii metodei esteDeschis().

2. RELATII DE ASOCIERE INTRE CLASE


Pe parcursul acestui curs vom trata problema de a gestiune a facturilor dintr-un magazin a carei descriere este prezentata in cele ce urmeaza. Specificatia proiectului Magazinul Tomis emite facturi pe baza produselor vandute clientilor. Pentru a gestiona automat facturile emise de magazin, proprietarul magazinului a decis sa cumpere de la o firma de software o aplicatie care se realizeze acest lucru. Cand este executata, aplicatia afiseaza fereastra principala:

Pentru a vizualiza date despre magazin, clientul (sau oricine este interesat) actioneaza butonul Date despre magazin, iar aplicatia va afisa urmatoarea interfata grafica:

Pentru a realiza o vanzare, clientul sau casiera trebuie sa actioneze butonul Comandati produse din ferestra principal. In acest moment, aplicatia va afisa urmatoarea interfata grafica:

Datele clientilor sunt memorate intr-un fisier numit clienti.txt, a.i. la urmatoarele operatii, acestia vor fi recunoscuti. Daca este vorba de un client vechi, dupa introducerea numelui si prenumelui su, si actionarea tastei Enter, adresa acestuia este citita din fisier si afisata in campul de text: Adresa. Daca este vorba de un client nou, aplicatia atentioneaza clientul ca este nou si trebuie sa introduca adresa.

Clientul nu poate efectua o vanzare, daca nu a fost apasat butonul Submit. In acel moment, in cazul unui client nou, datele acestuia (adica, nume, prenume si adresa) vor fi memorate in fisierul client.txt. In plus, butonul Adauga este activat si clientul isi poate alege produse (pe rand, dintr-o lista de produse) si trebuie sa specifice cantitatea. Daca uit sa adauge cantitatea, atunci programul afiseaza un mesaj de eroare. Aceasta operatie poate fi efectuata si de catre casier, la sugestiile clientului. Actionarea butonului Adauga determina afisarea informatiilor despre produsul comandat: nume, cantitate si pretul unitar al acestuia, in tabelul aflat pe interfata sistemului. Aceste informatii (numele si pretul unitar al produsului) sunt preluate dintr-un fisier numit produse.txt. Dupa ce au fost alese toate produsele ce vor fi cumparate, se actioneaza butonul Executa care determina crearea si vizualizarea facturii, al carei continut va fi afisat in fereastra Factura. Dupa cum se observa, atributele facturii sunt numar factura (care este unic) si data la care s-a emis factura. Pentru fiecare articol al facturii, se afiseaza numele, pretul unitar, cantitatea comandata si pretul articolului. La sfarsit, se face totalul (=suma pretului articolelor) din care se scade 5% din total daca cumpararea s-a facut intr-o zi de lucru (luni-vineri), la care se apoi adauga un tva de 20% din suma obtinuta si se obtine totalul general. Factura poate fi tiparita la imprimanta, daca se actioneaza butonul Print, poate fi memorata intr-un fisier (butonul PrintToFile), respectiv poate fi arhivata (butonul Arhivare). In ultimul caz, factura memorata in fisierul arhiva.txt ce contine toate facturile furnizate de magazin. Operatia de vanzare este anulata daca se actioneaza butonul Cancel.

10

Pas 1. Identificarea conceptelor Magazin Vanzare Produs Interfata grafica Proprietar Fisier Data Vanzatoare Factura Lista de produse Client Program Fereastra Articol Buton Imprimanta Pasul 2. Identificarea claselor prin analizarea conceptelor obtinute la pasul anterior. Pasul 3. Identificarea atributelor obiectelor claselor Magazin: denumire, oraDeschidere, oraInchidere Factura: numar (unic), dataEmiterii SpecificatieProdus: denumire, pretUnitar Client: nume, prenume, adresa Proprietar: nume, prenume Articol (sau ElementVanzare): specificatieProdus, cantitate Vanzare: tva, total Pasul 4. Construirea diagramei de clase Identificarea relatiilor dintre clase Relatia de asociere intre clase In general, o legtur reprezint un mod de a conecta, asocia sau raporta ntre ele dou sau mai multe entitati. Legturile ne ofer capacitatea de a reuni elementele n ansambluri, configuraii sau grupuri. Putem clasifica legturile n mai multe categorii: fizice, conceptuale, semiotice, logice i semantice. Legturile fizice, concrete ntre entiti sunt identificate n lumea real. n unele cazuri, identificarea se realizeaz prin experimente fizice n urma crora se deduce faptul c mobilitatea entitilor respective este limitat, prin transmiterea de fore sau micri de la o entitate la alta. Legturile conceptuale sau mentale sunt deduse din observarea lumii reale i aplicarea unui proces de raionare asupra ei. In cazul nostru, procesul de rationare este realizat prin aplicarea principiilor paradigmei OO. Legturile semiotice sunt deduse din descrierea n limbaj natural a elementelor din lumea real. Ele se mpart n legturi sintactice, semantice i morfologice (gramaticale). Dintre aceste categorii, ne intereseaz numai primele dou. Legturile semantice au loc ntre semne i nelesul lor pentru cei care le utilizeaz. Legturile sintactice ntre semne sunt induse de relaiile dintre nelesul semnelor ce furnizeaz semantica limbajului natural folosit. Astfel avem relaii de contrarietate (bazate pe antonime), de similaritate (bazate pe sinonime), de generalizare (este_un) i mereologice (constructii sintactice: este compus din, contine, este format din, face parte din). Dintre acestea ne intereseaza numai ultimele doua tipuri de legaturi sintactice. Legturile logice sunt deduse din descrierea n limbaj natural a elementelor din lumea real, asupra creia aplicm un raionament. In cazul analizei, este vorba de descrierea problemei si specificatia proiectului.

11

D. O legatura (link) in abordarea orientata spre obiecte este o conectare fizica, conceptuala, sintactica (semantica sau sintactica) sau logica intre doua obiecte. Daca un obiect care partine unei clase trebuie sa trimita un mesaj unui obiect ce apartine unei altei clase, atunci intre cele doua obiecte trebuie sa existe un link. Link-ul poate fi: - unilateral (primul obiect il cunoaste pe al doilea, dar al doilea nu) - bilateral (cele doua obiecte se cunoasc intre ele) D. O asociere este o relatie intre doua clase ce descrie o multime de link-uri cu o structura si o semantica comune intre obiectele claselor implicate. O asociere intre doua clase poate indica: - o cale de comunicare intre obiectele celor doua clase; - o cunoastere unilaterala sau bilaterala, - un raport de tip client-furnizor intre obiectele celor doua clase; - obiectele unei clase partajeaza cu alte obiecte obiectele celei de-a doua clase. Orice clasa are implicit o relatie de asociere cu ea insasi, de aceea exista intotdeauna posibilitatea ca un obiect sa-si trimita siei un mesaj. Relatiile de asociere (ca orice tip de relatie) se identifica din analiza verbelor din descrierea problemei sau/si specificatia de proiect sau/si raspunzand la urmatoarele intrebari: - Un obiect trimite mesaje unui alt obiect, cerandu-i acestuia din urma sa-si modifice starea? - Un obiect foloseste un alt obiect, fiindca are nevoie de informatii de la acesta din urma? - Un obiect anunta un alt obiect? O asociere se caracterizeaza prin urmatoarele elemente: nume, directia de folosire, multiplicitate, numarul de obiecte care participa in relatia de asociere si roluri.
ElementVanzare
cantitate : Integer ElementVanzare(p : SpecificatieProdus, c : Integer) getProdus() : SpecificatieProdus getCantitate() : Integer calculeazaCost() : Long foloseste

SpecificatieProdus produs 1
denumire : String pretUnitar : Integer SpecificatieProdus() getDenumire() getPret()

Vanzare
tva : Integer addElementVanzare(a : ElementVanzare) getElementeVanzare() : Collection getClient() : Client calculeazaTotal() : Long areLoc

Client
adresa : String

1..*

getAdresa()

estePentru

Factura
nrFactura : Integer data : Calendar formatare(sir : String, latime : Integer) : String

12

Nivelul de implementare Orice asociere va fi implementata cu ajutorul unui atribut de tip clasa B, in clasa A. Numele atributului este dat de rolul asocierii, daca acesta a fost specificat.
public class SpecificatieProdus{ private String denumire; private int pretUnitar;
Magazin
nrIdentificare : Integer denumire : String oraDeschidere : Integer oraInchidere : Integer esteCondus

Persoana +proprietar
nume : String prenume : String create() getNume() getPrenume()

} public class ElementVanzare{ private SpecificatieProdus produs; private int cantitate;

public SpecificatieProdus(String denumire, int pret){ this.denumire=denumire; this.pretUnitar=pret; } public String getDenumire(){ return denumire; } public int getPret(){ return pretUnitar; }

} public class TestArticol{ public static void main(String[] args){ ElementVanzare a1=new ElementVanzare(new SpecificatieProdus("tastatura", 1000), 3); System.out.println(a1.calculeazaCost()); } }

public ElementVanzare(SpecificatieProdus p, int c){ produs=p; cantitate=c; } public SpecificatieProdus getProdus(){ return produs; } public int getCantitate(){ return cantitate; } public long calculeazaCost(){ return produs.getPret()*cantitate; }

Principiile paradigmei orientarii spre obiecte Orice aplicaie orientat pe obiecte trebuie s fie construit folosind patru mecanisme conceptuale: 1.Abstractizare. Proces care capteaza caracteristicile esentiale ale unui obiect, caracteristici ce diferentiaza acest obiect de toate celelalte tipuri de obiecte.
13

2.Incapsulare. Proces mental executat pe o abstractizare n care elementele structurale ale abstractizarii sunt izolate de cele ce constituie comportamentul sau. Serveste la separarea interfetei vizibile a unei abstractizari de implementarea sa. Din faptul ca clasele si obiectele derivate din clase incapsuleaza ntr-un singur pachet datele si operatiile, deriva avantaje importante: Detaliile interne de implementare si ale procedurilor sunt invizibile in exterior (information hiding). Aceasta reduce propagarea efectelor in cazul modificarilor. Structurile de date si operatiile sunt definite intr-o entitate cu nume: clasa. Aceasta faciliteaza reutilizarea componentelor. Interfetele intre obiecte sunt simplificate. Un obiect care trimite un mesaj nu trebuie sa se preocupe de structurile interne de date ale obiectului destinatar. Se reduce astfel incarcarea sistemului. 3.Modularitate. Proprietatea unei aplicaii care a fost descompus ntr-un ansamblu de module (pachete) cu o mare coeziune interna si cu legaturi slabe intre ele. 4.Ierarhie. Este o relaie de ordine ntre abstractizari care sunt tipuri abstracte de date. Exist dou tipuri de ierarhii: bazate pe relaia de generalizare/specializare i cele bazate pe relaia de agregare. Alte dou concepte de importanta mai mica caracterizeaza obiectele intr-o modelare pe obiecte: 1.Typing. Este o constrngere pentru clasele de obiecte care le obliga sa schimbe ntre ele obiecte de tipuri diferite sau sa le schimbe dar ntr-un mod controlat (este cazul polimorfismului de exemplu). n general, polimorfismul este un concept in teoria tipurilor in care un unic identificator poate denumi obiecte ce apartin unor clase diferite si care sunt inrudite la o superclasa. 1. Persistenta (persistence). Reprezinta proprietatea unui obiect de a continua sa existe dupa ce creatorul su a incetat sa mai existe sau de a fi mutat din locul n care a fost creat n altul. Caracteristicile abordarii orientate pe obiecte
Proprietatilor obiectelor si a mecanismelor de structurare a universului OO au drept consecinte urmatoarele caracteristici ale abordarii OO:

1. Identitate. Proprietate a unui obiect care il diferentiaza de alte obiecte. Toate obiectele au o identitate proprie: obiectele sunt distincte intre ele. 2. Clasificare. Metoda utilizata pentru ordonarea cunostintelor despre obiecte. Cunostintele sunt descrise n termeni de clase, instante, atribute, operatii. 3. Polimorfism. Proprietatea unei operatii de a putea fi aplicata n moduri diferite mai multor clase. Polimorfismul este dou tipuri: static (prin supraincarcarea metodelor) i dinamic (prin redefinirea metodelor). 4. Generalizare/Specializare. Specializarea este o relatie ntre clase n care o clasa (superclasa) si transmite structura si functionalitatea uneia sau mai multor clase (subclase). Generalizarea este o relatie intre clase in care structura si comportamentul comun a doua sau mai multor clase este incapsulat intr-o singura clasa. Aceasta din urma va fi supraclasa pentru primele clase. Generalizarea/specializarea reprezinta un al doilea mecanism de clasificare: obiectele se clasifica n clase, iar clasele se clasifica prin intermediul superclaselor.

14

3. RELAIA DE GENERALIZARE/SPECIALIZARE NTRE CLASE


Am vzut c a program spre obiecte nseamn a raiona n termeni de concepte. De exemplu, in aplicatia Magazin clientul este o persoana care are o adresa. Mai general, vom spune c Y este un tip de X care , unde X i Y sunt concepte. Aceast relaie particular dintre concepte se numete relaia de generalizare/specializare i indic faptul c toate instanele lui Y sunt i instane ale lui X, dar au ceva n plus (sau ceva specific) fa de X. n aceast relaie, X este conceptul de baz, iar Y este conceptul derivat. Se mai spune c X este generalizarea lui Y, iar Y este specializarea lui X. Specializarea tipului client determina aparitia a inca 3 concepte: Angajat, Somer, Sef. Relaia de generalizare/specializare se pstreaz i ntre clasele care reprezint cele dou concepte. n UML, aceast relaie ntre clase este artat astfel:
X

X se mai numete superclas (sau supraclas), iar Y subclas.

ntr-o relaie de generalizare/specializare un obiect al unei subclase este i obiect al supraclasei clasei respective, avnd aceeai structur i aceleai operaii cu cele ale obiectelor din supraclas, dar au ceva diferit sau n plus. Dar, ce poate fi diferit n subclas fa de supraclas? Una sau mai multe proprieti (variabile) specifice subclasei respective. De exp, clasa Angajat.
Persoana
nume : String prenume : String

Client
adresa : String

Angajat
salariu : Double costOra : Double catVechime : Integer calculeazaSalariu(nrOreLucrate : Integer)

Somer
procentCalcul : Integer calculeazaAjutorSomaj()

Sef
sporDeConducere : Double

15

Apoi, subclasa poate aduga unul sau mai multe comportamente specifice sau s le modifice pe cele motenite din supraclas. De exp,. MOTENIREA N JAVA Relaia de generalizare/specializare dintre concepte sau clase induce ideea unei moteniri pe care o subclas o primete de la supraclasa sa. Aceast motenire are dou aspecte: structura obiectelor i modul lor de comportament; i aproape ntotdeauna n aceste situaii, subclasele pot aduga ceva specific. Pentru a reprezenta relaia de generalizare/specializare n limbajele de programare spre obiecte, precum Java, se propune un mecanism numit motenire. Acest mecanism permite unei noi clase s beneficieze de structura i comportamentul definite ntr-o clas deja existent prin declararea c motenim acea clas. In Java, mecanismul de motenire se numete extensia clasei existente i cere subclasei s declare ce clas extinde. Apoi, subclasa respectiv trebuie s defineasc propriile variabile i metode. Declararea c o clas extinde o alt clas este indicat n Java prin cuvntul cheie extends n declaraia clasei respective: class Identificator extends NumeSuperClasa { //definim variabile i metode specifice subclasei } unde Identificator este numele subclasei, iar NumeSuperClasa este superclasa sa. Regul. n Java, o clas poate extinde o singur clas. Aadar, motenirea este simpl. n aplicaia noastr, clasa Manager este o subclas a clasei Angajat. Iat structura celor dou clase:
public class Persoana{ private String nume, prenume; public String getNume(){return nume;} public String getPrenume(){return prenume;} } public class Client extends Persoana{ private String adresa; public void setAdresa(String n){adresa=n; } public String getAdresa(){return adresa; } } public class Angajat extends Client{ private double costOra, salariu; private int catVechime; public void setCostOra(double c){ costOra=c;} public void setCatVechime(int c){ catVechime=c;} public void calculeazaSalariu(int nr){ salariu=nr*costOra; if(catVechime<3) salariu+=5*salariu/100; else if(3<=catVechime && catVechime<7) salariu+=7*salariu/100; else if (7<=catVechime && catVechime<10) salariu+=10*salariu/100; else salariu+=15*salariu/100; } public double getSalariu(){return salariu;} } public class Somer extends Client{ private int procentDeCalcul;

16

public void setProcent(int p){procentDeCalcul=p;} public double calculeazaAjutor(double salariuMediu){ return salariuMediu*procentDeCalcul/100.0; }

Vizibilitatea membrilor n subclase

Variabilele instan private ale unei supraclase nu sunt motenite n subclasele ei. De aici putem concluziona c: O subclas moteneste toate variabilele i metodele neprivate ale supraclasei pe care o extinde. Rmne posibilitatea accesrii variabile private prin intermediul metodelor set i get.
Redefinirea membrilor n subclase

O subclas care doreste sa se deosebeasca de superclasa sa (pentru ca altfel ce rost ar avea sa o introducem?) are dou posibiliti: - s adauge membri noi si/sau - s redefineasc membrii superclasei. Dac o metod este redefinit n subclas, trebuie s ndeplineasc urmtoarele condiii: - metoda redefinit trebuie sa aib exact aceeai semntur; - metoda redefinit trebuie s aib acelai tip al rezultatului ntors; - dac metoda redefinit i schimb modificatorul de acces, acesta trebuie s dea cel puin la fel de mult acces ca metoda motenit din supraclas. Exemplu. super = Cuvnt cheie care se utilizeaz n interiorul corpului unei metode a unei instane a unei clase pentru a indica obiectul superclasei ce intra in structura instantei curente. Nota. Un obiect al unei subclase este alocat in memorie intr-o zona care include atat spatiul alocat obiectului superclasei, cat si spatiul necesar variabilelor declarate in subclasa. Variabila salariu este protected in Angajat.
public class Sef extends Angajat{ private double sporConducere; public void setSporConducere(double s){ sporConducere=s;} public void calculeazaSalariu(int nr){ salariu=super.calculeazaSalariu(nr); salariu+=sporConducere; } }

n cazul variabilelor instan, redefinirea este folosit mai puin i este vorba de fapt de ascunderea variabilelor din supraclase.
Ierarhia claselor Java

n Java, clasele formeaz o structur de arbore n care rdcina este clasa Object, a crei definiie apare n pachetul java.lang. Orice clas extinde direct (implicit sau explicit) sau indirect clasa Object. Aadar, toate clasele definite de programator care nu extind o alt clas sunt automat subclase ale clasei Object. Dac dorete, o clas poate redefini una sau mai multe metode motenite din clasa Object. Structura clasei Object este urmtoarea:
public class Object { public java.lang.Object();

17

public java.lang.String toString(); protected native java.lang.Object clone() throws CloneNotSupportedException; public boolean equals(java.lang.Object); public native int hashCode(); protected void finalize() throws Throwable; public final native java.lang.Class getClass(); public final native void notify(); public final native void notifyAll(); public final void wait() throws InterruptedException; public final native void wait(long) throws InterruptedException; public final native void wait(long, int) throws InterruptedException;

Datorit ierarhiei claselor Java, metodele clasei Object sunt motenite de toate clasele Java. n consecin, oricare din aceste metode poate fi apelat asupra oricrui obiect. Cunoatem deja unele metode din clasa Object, cum ar fi de exemplu toString() sau equals(). Metoda toString() furnizeaz o reprezentare sub form de ir a unui obiect. Dac aceast metod nu este redefinit, atunci va fi afiat numele clasei din care face parte obiectul respectiv mpreun cu un ir ce reprezinta codul hash al obiectului n memoria heap. De aceea, oridecte ori se dorete afiarea unor informaii despre un obiect (cum ar fi starea obiectului) se va rescrie metoda toString(). Metoda equals() permite compararea oricror dou obiecte. Rezultatul este true numai dac cele dou obiecte sunt de fapt acelai obiect. Dar, se poate redefi aceast metod dac dorim ca metoda s realizeze un alt tip de comparare. De exemplu, clasa String redefinete aceast metod pentru a compara lexicografic irurile coninute n cele dou obiecte care se compar.
Constructori i motenirea

Dup cum tim, constructorii ncapsuleaz algoritmi de iniializare a obiectelor ce vor fi create. Cnd este vorba de un obiect al unei subclase este important s tim cum va fi iniializat partea obiectului ce aparine structurii supraclasei, mai ales cnd variabilele instan ale supraclasei nu sunt motenite, deoarece sunt private. Presupunem c clasa Persoana contine urmtorul constructor:
public Persoana(String n, String prenume){ nume=n; this.prenume=prenume; }

Datorit observaiei anterioare, nu putem scrie un constructor n clasa Client care s iniializeze direct variabilele nume i prenume. O soluie ar fi s apelm metode setNume() i setPrenume() care sunt motenite de clasa Client i am avea urmtorul constructor:
public Client (String nume, String prenume, String adresa){ setNume(nume); setPrenume(prenume); this.adresa=adresa; }

Codul este corect, dar la compilare vom avea eroare: nu cunoate constructorul fr parametri al supraclasei Persoana. Chiar dac schimbm modificatorul de vizibilitate al variabilelor nume i prenume, vom avea aceeai eroare de compilare. O soluie bun ar fi s folosim cuvntul cheie super i apelm constructorul cu doi parametri din clasa Persoana:
public Client (String nume, String prenume, String adresa){ super(nume, prenume); this.adresa=adresa;

18

Regul. Dac intr-un constructor al unei subclase se apeleaz un constructor al supraclasei sale, atunci acest apel (folosindu-se super) se face pe prima linie a corpului constrcutorului respectiv. Mecanismul de iniializare a obiectelor Apelul unui constructor nu este un apel al unei metode oarecare, deoarece nainte de a executa algoritmul respectiv, mediul Java apeleaz automat constructorul fr parametri al supraclasei dac acesta poate fi apelat. Dac supraclasa nu are un constructor fr parametri, atunci caut constructorul fr parametri al supraclasei clasei respectiv. i tot aa, pn cnd clasa Object este supraclasa clasei respective. Aceasta are un singur constructor, care nu are parametri. Cu aceast clas este creat obiectul i apoi este iniializat pe drumul invers al apelului cu executarea
Constructor Object()
Clasa Object 4: Object() 5: initializeaza obiect

.
Constructor predefinit A()

Clasa A 2: A() 6: algoritmul lui A()

.
Constructor X()

Clasa X 7: algoritmul lui X()

1: X() new X()

Crearea unui obiect n Java

algoritmilor din constructorii supraclaselor pn la clasa respectiv (Figura 6-2). Aadar avem dou soluii: - folosim super i apelm un anumit constructor din supraclas - n supraclasa Angajat introducem nc un constructor, fr parametri.
Utilizarea obiectelor ale subclaselor

Avnd clasa Sef definit ca subclas a clasei Angajat, putem crea obiecte ale clasei Sef i apela metodele lor astfel:
Sef s1=new Sef("Ionescu", Pop, Aleea rozelor, 7);//constructorul s1.setSporConducere(100);//metoda instanta definita in clasa Sef s1.setCatVechime(25);//metoda mostenita din Angajat s1.calculeazaSalariu(200);//se apeleaza metoda definita in clasa Sef

Apelurile de metode sunt n regul pentru c un obiect al clasei Sef este automat un obiect al clasei Angajat i din aceast cauz pot fi apelate metodele motenite din supraclasa Angajat. Din acelai motiv, putem memora ntr-o variabil de tip Angajat o referin la un obiect al clasei Sef:

19

Angajat s2=new Sef("Marinescu", Marin, Aleea stejarilor, 10); s2.setNume("Georgescu");//metoda mostenita din Persoana s2.calculeazaSalariu(160);//se apeleaza metoda definita in clasa Sef s2.setSporConducere(150);//eroare la compilare!

Dup cum se observ, dac apelm o metod ce aparine numai clasei Sef i nu clasei Angajat, compilatorul va genera o eroare pentru c variabila s2 a fost declarat de tip Angajat, adic de tip supraclas. Regul. Dac ntr-o variabil de tip supraclasa unei clase va fi memorat o referin la un obiect al subclasei respective, atunci obiectul accesat prin intermediul varibilei referin, pierde temporar specificul subclasei, comportndu-se ca un obiect al supraclasei. Atunci, dac avem o variabil de tip supraclas nu suntem siguri c obiectul referit de variabil este de tip supraclas. n acest caz, putem folosi operatorul instanceof pentru a accesa variabilele i metodele obiectului referit de variabil. De exemplu, expresia s2 instanceof Sef are valoarea true deoarece referina memorat n variabila s2 indic un obiect al clasei Sef. Altfel, valoarea expresiei ar fi fost false. Aadar, dac vrem s folosim pe deplin obiectul respectiv (adic, conform clasei din care face parte) folosim operatorul instanceof mpreun cu operatorul cast la clasa original:
if (s2 instanceof Sef){ Sef s3=(Sef) s2; }

Mecanismul apelarii metodelor ntr-o ierarhie de clase Am vzut c n cazul motenirii, un obiect al unei subclase poate fi folosit pentru a apela metode definite n clasa respectiv, dar i metode definite n supraclasa sa direct sau n supraclasele sale ndirecte i motenite de clasa sa. n plus, subclasele pot redefini aceeai metod de mai multe ori, n funcie de propriile necesiti. Atunci ar trebui s vedem cum va fi rezolvat un apel de metod aplicat unui obiect dintr-o subclas. Astfel presupunem c un obiect a apeleaz o metod a obiectului b din Clasa5 din figura urmtoare. Dup cum se observ avem dou cazuri: - metoda respectiv este motenit din clasa Clasa1 i nu a fost redefinit n ierarhia sa direct: Clasa5 i Clasa3. Atunci metoda care va fi executat va fi metoda din Clasa1 (Figura 6-3 a). metoda este definit iniial n clasa Clasa1 i redefinit n Clasa3. Atunci metoda care va fi executat, va fi metoda din Clasa3.

20

Definiia metodei Definiia iniial a metodei Clasa1 4 Clasa2 3 Clasa3 3 Clasa1 Metoda redefinit

Clasa2

Clasa3

Clasa4

Clasa5 2

Clasa4

Clasa5 2

Obiect a

Obiect b

Obiect a

Obiect b Obiect

Observm c, apelul unei metode a unui obiect aparinnd unei subclase, dac metoda apelat nu este definit in subclas, este transmis n sus n ierarhia de clase pn cnd este gsit o prim definiie a metodei apelate.

21

4. ARRAY-URI
Array = O colecie liniar de elemente n care fiecare element este accesibil prin intermediul unui indice. Un array furnizeaz spaiu pentru valorile de tip primitiv sau referin la obiectele de un acelai tip. Aceste valori se numesc elementele array-ului. Elementele unui array sunt ordonate dupa unul sau mai multe criterii numite dimensiuni. O dimensiune a unui array este indicata printr-o pereche de []. Dupa numarul de dimensiuni, un array este uni- sau multidimensional. Referina la un array va fi memorat ntr-o variabil array. Sintaxa declararii unei variabile array unidimensional este urmatoarea: TipDeDate[] id; sau TipDeDate id[]; De exemplu, putem declara dou variabile array numere i personal astfel:
int[] numere; Persoana personal[];

Nota. Dupa executarea acestor declaratii, array-urile propriu-zise nu exista in memorie, ci numai variabilele array asociate. Pentru a exista ntr-un program, un array trebuie s fie creat (alocat) cu new. Sintaxa alocarii memoriei unui array este:
id = new tip[expresie]

unde tip este tipul de date al variabilei array cu identificatorul id, iar expresie este fie un literal intreg, fie o expresie cu valoare dreapta un numar intreg. De exemplu,
numere = new int[5]; personal = new Persoana[1000];

In acest moment, toate elementele array-ului numere sunt initializate cu 0, iar cele ale array-ului personal cu valoarea null. Dup creare, elementele array-ului se pot umple cu valori, cu observatia ca indicele unui array ncepe de la 0. Astfel un array cu 10 elemente va avea indicele de la 0 la 9. De exemplu, daca arrayul numere contine primele 5 numere pare naturale, umplerea array-ul cu aceste valori se face astfel:
for (int i=0; i<5;i++) numere[i]=2*i;

In cazul array-ului de tip referinta personal, valorile lui sunt referinte catre obiecte de tip Persoana, care trebuia sa fie create. Astfel,
for (int i=0; i<1000;i++) personal[i]=new Persoana();

Grafic, cele doua array-uri arata astfel:


array-ul personal array-ul numere 0 2 4 6 8 4 0 1 2 999 obiecte Persoana

0 array unidimensional de 53 1 2 ntregi

array unidimensional de 1000 obiecte Persoana

Prin definitie, lungimea unui array este egala cu numrul de elemente ale array-ului. Pentru a determina lungimea unui array se foloseste variabila length. De exemplu, valoarea expresiei personal.length este 1000. INIIALIZAREA UNUI ARRAY Am vazut ca la momentul crerii unui array, elementelor sale le sunt atribuite valoarea zero (tipuri primitive numerice), \u0000 (tipul char), false (tipul boolean) sau null (tipuri referin). Elementele unui array pot fi initializate in declararea variabilei array printr-o lista de initializatori cuprinsa intre {} ce le contine si care este atribuita variabilei array asociata. Sintaxa este urmatoarea:
TipDeDate[] id={listaDeInitializatori}

22

Aceasta este de fapt o forma prescurtata pentru


TipDeDate[] id=new TipDedate[]{listaDeInitializatori};

unde listaInitializatori este o multime de elemente de acelasi tip cu tipul array-ului, ce sunt valorile elementelor array-ului id. Numarul de elemente din lista de initializatori funrizeaza valoarea variabilei length pe variabila array asociata. De exemplu, elementele array-ul indicat prin variabila numere pot fi initializate de la declararea variabilei numere astfel:
int[] numere={0,2,4,6,8};

ARRAY-URI MULTIDIMENSIONALE Array-urile multidimensionale sunt declarate prin adaugarea dimensiunilor. De exemplu, declararea unei matrici m cu elemente de tip intreg se realizeaza astfel:
int[][] m;

Alocarea memoriei necesare memorarii matricii m se face astfel:


m=new[3][3];

In memorie, elementele lui m nu vor fi memorate ca intr-o matrice ci liniar adica, un array multidimensional este memorat ca un array de array-uri (si la randul lor pot fi de array-uri), astfel ca fiecare dimensiune este memorata ca un array diferit. De aceea, putem declara si construi array-uri multidimensionale de dimensiuni diferite. De exemplu, int[][] b=new int[2][]; //b are 2 linii b[0]=new int[3];// prima linie are 3 coloane sau elemente b[1]=new int[4];// a doua linie are 4 elemente Nota: Daca numarul coloanelor poate sa difere, tipul elementelor trebuie sa fie acelasi. In cazul array-urilor multidimensionale variabila length are valori diferite. De exemplu, b.length furnizeaza numarul de linii ale lui b, adic 2, pe cand b[1].length=4. Similar, un array multidimensional poate fi initializat si la declarare folosind o list ce contine un numar de liste de initializatori egal cu numarul de dimensiuni ale array-ului, liste separate prin virgula. De exemplu, int[][] a={{1,0}, {0,1}} memoreaza matricea unitate bidimensionala. Exemplu. Urmtorul exemplu arat cum pot fi create, iniializate i afiate diferite array-uri multidimesionale:
import java.util.*; public class ArrayMultiDimensionale{ static Random aleator= new Random(); static int pRand(int mod) { return Math.abs(aleator.nextInt())%mod; } public static void main(String[] args){ //array 3-D cu dimensiuni fixe: int[][][] a2 = new int[2][2][4]; for(int i = 0; i < a2.length; i++) for(int j = 0; j< a2[i].length; j++) for(int k=0; k<a2[i][j].length;k++) afiseaza("a2[ + i+"]["+j+"]["+k+"] = " + a2[i][j][k]); //array 3-D cu vectori de lungime diferit pentru cele trei dimensiuni int[][][] a3 = new int[pRand(7)][][]; for(int i = 0; i<a3.length; i++){ a3[i] = new int[pRand(5)][]; for(int j=0; j<a3[i].length; j++)a3[i][j] = new int[pRand(5)]; } for(int i=0; i<a3.length; i++) for(int j=0; j<a3[i].length; j++) for(int k=0; k<a3[i][j].length; k++) afiseaza("a3["+i+ "]["+j+"]["+k+"]= "

23

+a3[i][j][k]); //array 3x2 de obiecte Integer Integer[][] a4={{new Integer(1), new Integer(2)}, {new Integer(3), new Integer(4)}, {new Integer(5), new Integer(6)}}; for(int i = 0; i < a4.length; i++) for(int j = 0; j < a4[i].length; j++) afiseaza("a4[" + i + "][" + j + "] = + a4[i][j]); } static void afiseaza(String s){ System.out.println(s); }}

LUCRUL CU ARRAY-URI Cand lucram cu array-uri putem folosi urmatoarea metod static a clasei System ce permite copierea unui numr de elemente consecutive ale unui array ntr-un alt array:
static void arrraycopy(arraySurs, pozSurs, arrayDest, pozDest, nrElemente)

In mod obisnuit, array-urile sunt folosite in probleme de sortare si de cautare. De exemplu, sortarea elementelor unui array folosind metoda QuickSort se face astfel in Java:
public class Ordonare{ static int[] a; public static void initializeaza(){ a=new int[20]; int nr; for(int i=0; i<a.length;i++){ nr=(int)(Math.random()*30); a[i]=nr; } afiseaza(); } public static void quickSort(int p, int u){ int i=p, j=u; int temp=a[(p+u)/2]; do{ while(a[i]<temp)i++; while(a[j]>temp)j--; if (i<j){ int t=a[i]; a[i]=a[j]; a[j]=t; } if (i<=j) {i++;j--;} }while (i<j); if(p<j) quickSort(p,j); if(i<u) quickSort(i,u); } public static void afiseaza(){ for(int i=0;i<a.length;i++) System.out.print(a[i]+" "); System.out.println(); } public static void main(String[] args){ initializeaza(); quickSort(0,19); afiseaza(); } }

Cautarea unei valori intr-un array folosind metoda Divide et Impera se realizeaza astfel:
24

public class Cautare{ static int[] a; public static void initializeaza(){ a=new int[20]; int nr; for(int i=0; i<a.length;i++){ nr=(int)(Math.random()*30); a[i]=nr; } afiseaza(); } public static boolean cauta(int val){ int p=0, u=a.length-1, m=(p+u)/2; while(p<u && val!=a[m]){ if(val<a[m]) u=m-1; else p=m+1; m=(p+u)/2; } return a[m]==val; } public static void afiseaza(){ for(int i=0;i<a.length;i++) System.out.print(a[i]+" "); System.out.println(); } public static void main(String[] args){ initializeaza(); int nr=(int)(Math.random()*30); if(cauta(nr)) System.out.println("A gasit="+nr); else System.out.println("Nu a gasit="+nr); } }

ARRAY N METODE Daca parametrul unei metode este o variabila array, atunci transferul se face prin referinta, adica orice modificare efectuata asupra elementelor array-ului respectiv se memoreaza. Elementele unui array de tip primitiv se transmit prin valoare, exact ca niste variabile simple. De exemplu, daca in programul Ordonare anterior am fi avut metoda
public static void schimba(int i, int j){ int t=i; i=j; j=t; }

apelul acestei metode schimba(a[i], a[j]) nu ar fi realizat operatia respectiva. Pentru a realiza ntr-adevr schimbarea dou valori transmise prin valoare, metoda schimba() trebuie s fie scris astfel:
public static int[] schimba(int i, int j){ Integer n1=new Integer(i); Integer n2=new Integer(j); int[] n=new int[2]; Integer n3=n1; n1=n2; n2=n3;

25

n[0]=n1.intValue(); n[1]=n2.intValue(); return n;

In acest caz, metoda quickSort ar putea apela metoda schimba() astfel: public static void quickSort(int p, int u){ int i=p, j=u; int temp=a[(p+u)/2]; do{ while(a[i]<temp)i++; while(a[j]>temp)j--; if (i<j){ int[] n=schimba(a[i],a[j]); a[i]=n[0]; a[j]=n[1]; } if (i<=j) {i++;j--;} }while (i<j); if(p<j) quickSort(p,j); if(i<u) quickSort(i,u); }

Lucrul cu colectii de obiecte legate intre ele prin relatia de motenire

Presupunem ca vrem sa completam programul Angajai cu o clas de test a crei metod main contine un array de doi angajai pentru a memora un angajat i un manager. Apoi, afim date despre cei doi angajai, dup care le mrim salariul cu 2% i le afim din nou datele pentru a verifica creterea salariului.
public class TestAngajati { static Angajat[] personal; public static void main(String[] args) .... // creaza si memoreaza 1 angajat si un // afiseaza date despre fiecare membru // creste salariul cu 2% // afiseaza date despre fiecare membru } } { manager ca personal al intreprinderii al personalului al personalului

Cum afim de dou ori date despre angajai, ar trebui s scriem algoritmul de afiare ntr-o metoda static i s-o apelm din metoda main, cnd avem nevoie.
public static void afiseazaDate() { System.out.println("\nLISTA PERSONAL"); for (int i = 0; i < personal.length; i++) System.out.println(personal[i]); } public static void main(String[] args) { personal= new Angajat[2]; personal[0] = new Angajat(" ", 2500.00); personal[1] = new Manager(" ", 3000.00, " "); afiseazaDate(); for (int i = 0; i < personal.length; i++) personal[i].maresteSalariu(0.02); afiseazaDate(); } n metoda main, am utilizat o variabil array personal pentru a crea un array de doi angajai, dintre

care unul este Manager. Putem s facem acest lucru, datorit relaiei de generalizare/specializare dintre Angajat i Manager.

26

5. CLASE ABSTRACTE
O clasa abstract este o clas fr instane directe, dar are subclase care sunt clase concrete, adic pot fi instaniate direct. O clas abstract este declarat cu modificatorul abstract. Sintaxa declarrii unei clase abstracte: ClasAbstract ::= [modificator de vizibilitate] abstract class Identificator{} unde Identificator este numele clasei abstracte. Fiind fr instane directe, constructorul unei clase abstracte nu poate fi apelat. De aceea, chiar dac o clas abstract conine unul sau mai muli constructori, dac incercm s-I apelm vom avea eroare de compilare. n schimb, putem declara variabile de tip o supraclas abstract care s conin referine la obiectele subclaselor concrete ale clasei respective. Aadar, rolul unei clase abstracte este de a facilita elaborrile polimorfice asupra obiectelor subclaselor sale. Atunci, metodele abstracte dintr-o clasa abstract ofer o interfa comun tuturor subclaselor clasei abstracte. O clas abstract trebuie s conin cel puin o metod abstract adic metod care nu definete algoritmul de implementare. Sintaxa declarrii unei metode abstracte este urmtoarea: MetodaAbstract::=[Modificator de vizibilitate] abstract Tip numeMetoda([parametri formali]); Exemple:
abstract void metoda(); public abstract int read() throws IOException;

Aadar, o clas abstract poate avea metode concrete, adic declarate i definite n clasa respectiv. n plus, o clas abstract poate avea variabile ce pot fi motenite de subclasele clasei respective. Cum comportamentul obiectelor unei clase este dat de mulimea tuturor metodelor clasei, atunci obiectele unei clase abstracte au un comportament parial definit, deoarece el difer n funcie de fiecare subclas a clasei respective. O subclas a unei clase abstracte are obligaia de a defini (implementa) metodele abstracte ale supraclasei. n caz contrar, subclasa respectiv trebuie s fie declarat abstract i este responsabilitatea subclaselor ei s implementeze metodele care au rmas abstracte din supraclas.
5.1.1 Dezvoltarea unei aplicatii pe obiecte Aplicaia Cont bancar

Se consider definirea unei clase care descrie comportamentul unui cont bancar. 1. Definirea numelui clasei: ContBancar. 2. Determinarea proprietilor clasei, care caracterizeaz obiectele clasei. Se insereaz variabilele: sold de tip long i proprietar de tip String. 3. nelegerea modului n care se comport obiectele clasei. Care sunt operaiile care se pot face asupra unui cont bancar? Responsabilitatea clasei ContBancar: Depune o sum de bani depune(suma:long)
Scoate o sum de bani scoate(suma:long)

Cere soldul curent getSold():long

Cere numele proprietarului getProprietar():String

4. Definirea modurilor in care vor fi create obiecte ContBancar. Un cont bancar poate fi creat vid, numai cu numele proprietarului ContBancar(numeProp: String)

27

Un cont bancar poate fi creat iniializnd soldul i numele proprietarului ContBancar(sold: Long sold, numeProp:String) Un cont bancar este de dou tipuri: cont de economii sau cont curent. Un cont de economii este un cont bancar caracterizat de o dobnd ce poate fi vizualizat la cerere. Dobnda este utilizat la anumite intervale de timp, cnd trebuie s fie calculat i adugat la soldul curent. Aceast operaie este realizat de metoda aplicDobnda(). Un cont curent este un cont bancar caracterizat de un numr de operaii sau tranzacii efectuate asupra contului ntr-o anumit perioad de timp.Fiecare tranzacie efectuat are un cost constant exprimat n euro. Costul unei tranzacii este constant, este iniializat la crearea unui cont curent i memorat n constanta COST_TRANZACTIE. Un cont curent are un numr de tranzacii gratuite. Acest numr este memorat n constanta NR_TRANZACTII_GRATUITE, iniializat la crearea contului curent. Dup efectuarea acestui numr de tranzacii, restul tranzaciilor trebuie s fie pltit. La anumite intervale de timp, costul tranzaciilor va fi extras din cont i numrul tranzaciilor pornete de la zero. Orice persoan care vrea s-i deschid un cont bancar trebuie s specifice tipul contului: de economii sau curent. Tinnd cont de aceast cerin, clasa ConBancar este o clas abstract cu metodele abstracte depune i scoate. Dup ce am analizat problema, obinem urmtoarea diagram de clase n UML:
ContBancar
sold : Long proprietar : String ContBancar(numeProp : String) ContBancar(sold : Long, numeProp : String) depune(suma : Long) scoate(suma : Long) getSold() : Long getProprietar() : String

ContEconomii
rataDobanda : Double ContEconomii(prop : String, rata : Double) ContEconomii(prop : String, sold : Long, rata : Double) aplicaDobanda()

ContCurent
nrTranzactii : Integer NR_TRANZACTII_GRATIS : Integer COST_TRANZACTII : Integer ContCurent(prop : String, suma : Long, ntg : Integer, ct : Integer) ContCurent(prop : String, ntg : Integer, ct : Integer) descarcaCheltuieli()

Implementarea n Java
public abstract class ContBancar{ protected long sold; protected String proprietar; public ContBancar(String numeProp){ proprietar=numeProp; } public ContBancar(long sold, String numeProp){ this.sold=sold; proprietar=numeProp; } public abstract void depune(long suma);

28

public abstract void scoate(long suma); public long getSold(){ return sold; } public String getProprietar(){ return proprietar; } public String toString(){ return "Cont cu proprietarul: "+proprietar+" si suma curenta: "+sold; } } public class ContEconomii extends ContBancar{ private double rataDobanda; public ContEconomii(String prop, double rata){ super(prop); rataDobanda=rata; } public ContEconomii(String prop, long sold, double rata){ super(sold, prop); rataDobanda=rata; } public void depune(long suma){ sold+=suma; } public void scoate(long suma){ if (suma<=sold) sold-=suma; } public void aplicaDobanda(){ sold+=sold*rataDobanda; } public String toString(){ return super.toString()+", dobanda: "+rataDobanda; } } public class ContCurent extends ContBancar{ private int nrTranzactii; private final int NR_TRANZACTII_GRATIS; private final int COST_TRANZACTIE; public ContCurent(String prop, long suma, int ntg, int ct){ super(suma, prop); NR_TRANZACTII_GRATIS=ntg; COST_TRANZACTIE=ct; } public ContCurent(String prop, int ntg, int ct){ this(prop, 0, ntg, ct); } public void depune(long s){ sold+=s; nrTranzactii++; } public void scoate(long s){

29

if(s<=sold){ sold-=s; nrTranzactii++; } } private void descarcaCheltuieli(){ if (nrTranzactii>NR_TRANZACTII_GRATIS){ scoate((nrTranzactii-NR_TRANZACTII_GRATIS)*COST_TRANZACTIE); nrTranzactii=0; } } public String toString(){ return super.toString()+", numar de tranzactii gratis: "+ NR_TRANZACTII_GRATIS+", cost tranzactie: "+COST_TRANZACTIE; } }

Pentru a testa ierarhia de clase construit vom scrie clasa TestContBancar care creaz un cont de economii i un cont curent, executm 2-3 tranzacii pentru fiecare cont i vizualizm situaia, la nceput i dup efectuarea tranzaciilor.
public class TestContBancar{ public static void main(String[] args){ ContEconomii ce=new ContEconomii("Ionescu",10000, 0.15); ContCurent cc=new ContCurent("Popescu", 20000, 5, 2000); ce.depune(5000); System.out.println(ce); cc.depune(15000); System.out.println(cc); cc.scoate(2000); System.out.println(cc); ce.scoate(12000); System.out.println(ce); } }

Exerciiu. S se mbogeasc ierarhia clasei ContBancar cu o nou clas ContDepozitTemporar, un tip particular de ContEconomii. n acest cont, titularul se oblig s lase banii un anumit numr de luni, probabil n schimbul unei dobnzi mai mari. Odat ce s-a ndeplinit termenul de scaden a contului, nu exist nici o penalizare pentru operaia de extragere. n schimb, dac suma este scoas nainte de scaden, ea va fi eliberat fr dobnd. Apoi, s se modifice clasa TestContBancar, modificnd un cont de economii ntr-un cont de perioad limitat (utilizai polimorfismul metodelor).

30

6. INTERFETE
Conceptul de interfa

Presupunem c avem urmtoarele dou probleme: 1. S se ordoneze conturile de economii dup dobnda pentru a decide care dintre ele este mai bun pentru a depune o sum de bani disponbila. 2. S se ordoneze angajaii unei ntreprinderi dup salariu pentru a putea face o statistic legat de taxele de pltit. Pentru rezolvarea acestor probleme avem dou soluii: 1. ContEconomii sau Angajat au obiecte care nu sunt comparabile. Ordonarea se poate face n mod personalizat, pentru fiecare clas. 2. Cele dou clase implementeaz interfaa Comparable care are o metod compareTo(Object). Fiecare clas trebuie s implementeze n mod personalizat metoda:
public class ContEconomii implements Comparable { . . . . public in compareTo(Object o) { return (this.dobanda > o.dobanda)?1:(this.dobanda < o.dobanda)?-1:0; } }

Atunci, se poate scrie simplu, avnd dou conturi cont122 i cont304:


if(cont122.compareTo(cont304)>0) then . . .

Interfee n Java

Interfa = List de metode publice i abstracte. O interfa este o colecie de comportamente abstracte care pot fi implementate de o clas pentru adugarea unui comportament care nu este furnizat de superclasa clasei respective. Interfeele reprezint, ca i clasele, tipuri de date, numai c aceste tipuri, n loc s prezinte date+servicii, prezint numai servicii. Interfaa n Java este o entitate distinct de clase i array-uri. O interfa poate conine i membri-date constante. O interfa poate moteni de la o alt interfa. Interfeele n Java trebuie s fie declarate. Declaraia unei interfee:
[Modificator] interface Identificator [extends NumeInterfata...] { Tip Identificator= . . . // date-membru [Modificator] SemnaturaMetoda; . . . // metode abstracte } Exemplu. public interface Comparable {public int compareTo (Comparable b);}

Pentru fiecare declaraie de interfa compilatorul creaz un fiier .class.


Implementarea unei interfee

O clas care decide s implementeze o interfa trebuie s declare acest lucru n definiie. Sintaxa:
class Identificator implements NumeInterfata,...{ CorpClasa }

O clas care dorete s implementeze o interfa, trebuie s implementeze toate metodele interfeei. Exemplu. Dac vrem sa ordonm angajaii unei ntreprinderi dup salariu pentru a putea face o statistic legat de taxele de pltit, clasa Angajat va implementa interfaa Comparable care are o metod compareTo(Object). Clasa trebuie s implementeze n mod personalizat metoda:
public class Angajat implements Comparable { . . . .

31

public int compareTo(Object o) { return (int)(getSalariu() ((Angajat)o).getSalariu()); } . . . . }

O clas poate implementa mai multe interfee. O interfa poate fi implementat de mai multe clase.
Variabile-interfa

Intr-un program se pot declara variabile de tip interfa, ca de exemplu: Comparable s; O variabil interfa poate memora referina la o instan a oricrei clase care implementeaz acea interfa, la fel cum face i o variabil a unei clase.
s = new Angajat(. . . ); Angajat d = new Angajat(. . .);

O variabil interfa poate participa n calcule la fel ca orice variabil referin.


if (s.compareTo(d) < 0) . . .

Variabilele interfa sunt n special utilizate ca parametri n metode pentru a permite upcasting al obiectelor ce provin din clase diferite ntre ele.
if (s.compareTo(d) < 0) . . //Angajat promovat ca tip Comparable

O variabil interfa poate fi accesat numai cu metodele interfeei.


String nume = s.getNume(); // Eroare!!

Cum utilizm interfeele

1. Utilizai o interfa pentru a separa un comportament care este implementat n orice clasefurnizor ale claselor client care le utilizeaz. 2. Utilizai interfeele ca parametri ai metodelor. n acest caz: 2.1. n interiorul unei astfel de metode putem invoca orice metod a interfeei; 2.2. la execuie, se poate transmite ca argument orice obiect al unei clase care implementeaz interfaa 2.3. la invocarea unei metode pentru acel obiect determin executarea unei implementri particulare a metodei ce aparine clasei obiectului; 2.4. transmind unui alt apel un obiect al unei alte clase care implementeaz interfaa se detrmin o execuie care poate fi complet diferit de prima.
Interfee Java standard

Interfaa Cloneable trebuie s fie implementat de toate clasele care se cloneaz.


protected native Object clone() //clone restituie un Object generic throws CloneNotSupportedException; . . . . . . Vector v = new Vector(); Vector v2; //Pentru a-l putea utiliza, rezultatul v2 = (Vector) v.clone(); // va fi convertit la tipul dorit

Interfaa Serializable nu are metode:


package java.io; public interface Serializable {};

Exemplu.
public interface OperatiiObiecte{ public void scrieObiect(Object o); public Object citesteObiect(String cheie); } import java.io.*; import java.util.*; public class OperatiiSpecificatiiProdus implements OperatiiObiecte{ private PrintWriter pw; public OperatiiSpecificatiiProdus(){ try{

32

} public void scrieObiect(Object o){ if (!(o instanceof SpecificatieProdus)) { System.out.println("instanta invalida"); return; }else { SpecificatieProdus p=(SpecificatieProdus)o; pw.println(p.getDenumire()+"_"+p.getPret()); pw.flush(); } } public Object citesteObiect(String cheie){ SpecificatieProdus sp=null; try{ BufferedReader br=new BufferedReader(new FileReader("produse.txt")); StringTokenizer st; String linie; while((linie=br.readLine())!=null){ st=new StringTokenizer(linie, "_"); if(st.nextToken().equals(cheie)) { sp=new SpecificatieProdus(cheie, Integer.parseInt(st.nextToken())); break; } } }catch(IOException io){io.printStackTrace();} return sp; } } import java.io.*; import java.util.*; public class OperatiiClient implements OperatiiObiecte{ private ObjectOutputStream oos; private ObjectInputStream ois; public OperatiiClient(){ try{ oos=new ObjectOutputStream(new FileOutputStream("clienti.txt")); ois=new ObjectInputStream(new FileInputStream("clienti.txt")); }catch(IOException io){} } public void scrieObiect(Object o){ if (!(o instanceof Client)) {System.out.println("instanta invalida");return;} else {try{oos.writeObject(o);}catch(IOException io){io.printStackTrace();}} } public Object citesteObiect(String cheie){ Client c; try{ c=(Client)ois.readObject(); while (c!=null){ if (cheie.equals(c.getNume()+" "+c.getPrenume()+" "+c.getAdresa()))return c; c=(Client)ois.readObject(); } }catch(IOException io){io.printStackTrace();} catch(ClassNotFoundException io){io.printStackTrace();} return null;

pw=new PrintWriter(new FileWriter("produse.txt"), true); }catch(IOException io){io.printStackTrace();}

33

} } public class TestOperatii{ public static void main(String args[]){ OperatiiObiecte oo=new OperatiiSpecificatiiProdus(); oo.scrieObiect(new SpecificatieProdus("branza", 120000)); oo.scrieObiect(new SpecificatieProdus("miere", 150000)); SpecificatieProdus sp=(SpecificatieProdus)oo.citesteObiect("miere"); System.out.println("pret= "+sp.getPret()); oo=new OperatiiClient(); oo.scrieObiect(new Client("Ionescu", "Pop", "alea rozelor")); oo.scrieObiect(new Client("Popescu", "Ion", "alea stejarilor")); oo.scrieObiect(new Client("Marin", "Pop", "alea crizantemelor")); Client c=(Client)oo.citesteObiect("Marin Pop alea crizantemelor"); System.out.println("date client= "+c.getNume()+" "+c.getPrenume()); }

34

7. CLASE INTERNE
DEFINIREA CLASELOR INTERNE ntr-un program Java este posibil s plasm o definiie a unei clase n spaiul de nume al altei clase. n acest caz, spunem c am definit clasa intern celei de-a doua clase, care este clas extern pentru aceasta. Clasele interne ne permit s grupm clasele care sunt conectate logic ntre ele i s controlm vizibilitatea acestora. Exemplu. Continund aplicaia GestiuneAngajai din ultimele dou cursuri, presupunem c clasa Manager are o clas intern numit Secretara:
public class Manager extends Angajat{ private int vechime; public Manager(String nume, long salariu, int v){ super(nume, salariu); vechime=v; } public class Secretara{ private String nume; public Secretara(String nume){ this.nume=nume; } String getNume(){ return nume; } }

Dintr-o clas extern putem crea fr probleme obiecte ale oricrei clase intern a sa. Din afara clasei externe, instanierea clasei interner depinde de modificatorul de vizibilitate a acesteia din urm. Astfel, dac clasa intern ofer acces, putem crea obiecte din aceast clas, cu ajutorul unei variabile instan de tip clasa extern i tipul noii variabile instan este un tip compus: NumeClasaExterna.NumeClasaInterna, ca n exemplul urmtor:
public static void main(String[] args){//in clasa Manager Manager m=new Manager("Ionescu", 500, 7); Manager.Secretara s=m.new Secretara("Maria"); System.out.println(s.getNume()); }

Dac clasa intern este privat i vrem s dm acces clienilor clasei externe la obiectele primei clase, clasa extern trebuie s conin o metod ce returneaz o referin la un nou obiect al clasei interne:
public Secretara obtineObiectSecretara(String nume){//in clasa Manager return new Secretara(nume); }

Not. O clas intern privat furnizeaz o modalitate de a ascunde informaii despre implementarea realizat de clasa extern. Orice obiect al unei clase interne este legat automat de un obiect din clasa extern din care face parte i din acest motiv, acesta poate accesa orice variabil i pot apela orice metod (indiferent ce modificator de vizibilitate au) ale obiectului nconjurtor. De exemplu, n clasa Secretara putem defini urmtoarea metod:
35

public int getVechime(){return vechime;}

care poate fi apelat din metoda main:


System.out.println(vechime manager= + s.getVechime());

ntr-o clas intern putem scrie o metod care s returneze o referin la obiectul nconjurtor. Acest obiect poate fi folosit pentru a acesa, respectiv apela, toate variabilele, respectiv metodele, neprivate ale clasei externe:
public Manager getManager(){return Manager.this;}

Clasele interne pot fi definite ntr-o metod sau chiar ntr-un bloc arbitrar clasei din care fac parte. O astfel de decizie apare din dou motive: - clasa intern extinde o clas abstract sau implementeaz o interfa i astfel putem crea i returna o referin la aceasta - este o decizie de proiectare sau chiar de implementare, deoarece clasa extern rezolv o problem mai grea i avem nevoie de o clas ajuttoare pe care s o folosim local. De exemplu, putem defini clasa SecretaraE n corpul metodei obtineObiectSecretara(String): public Secretara obtineObiectSecretara(String nume){ class SecretaraE extends Secretara{ private String nume; private SecretaraE(String nume){ this.nume=nume; } public String getNume(){return nume;} }//clasa interna return new SecretaraE(nume); } Mai mult, o clas intern definit n corpul unei metode poate fi facut clas anonim n urmtoarele condiii: - clasa intern anonim nu definete un constructor propriu - putem declara variabile instan i le putem iniializa cu valorile transmise prin parametrii metodei, numai c acetia trebuie s fie declarai finali:
public Secretara obtineObiectSecretara(final String n){ return new Secretara(){ private String nume=n; public String getNume(){return n;} }; }

Iniializarea variabilelor instan ale clasei interne poate fi facut ntr-un bloc de iniializare:
public Secretara obtineObiectSecretara(final String n){ return new Secretara(){ private String nume; { nume=n; } public String getNume(){ return n; } }; }

CLASE INTERNE STATICE O clas intern static se declar folosind modificatorul static:
36

private static class SecretaraE extends Secretara{//in clasa Manager private String nume; private SecretaraE(String nume){ this.nume=nume; } public String getNume(){ return nume; } }//clasa interna

Clasele interne statice ndeplinesc urmtoarele condiii: 1. Pentru a crea un obiect al clasei interne statice nu avem nevoie de un obiect al clasei externe 2. Fiind static, dintr-un obiect al unei astfel de clase nu putem accesa un obiect al clasei nconjurtoare i astfel nu putem accesa, respectiv apela nici o variabil, respectiv metod instan a clasei nconjurtoare, numai variabile i metode statice. De exemplu, putem crea n metoda main un obiect al clasei SecretaraE astfel:
Secretara s=new SecretaraE("Maria");//in main System.out.println(s.getNume());

Mai departe, clasele interne statice pot fi incorporate n interfee:


interface ISecretara{ public String getNume(); static class SecretaraEI implements ISecretara{ private String nume; public SecretaraEI(String nume){ this.nume=nume; } public String getNume(){ return nume; } }//clasa interna }//interfata public static void main(String[] args){//din Manager ISecretara s=new ISecretara.SecretaraEI("Maria"); System.out.println(s.getNume()); }

CLASE INTERNE I MOTENIREA Un motiv pentru care putem folosi clase interne este de a obine n Java motenirea multipl: o clas intern extinde o clas concret sau abstract sau implementeaz o interfa. De exp, putem declara urmtoarea clasa abstract:
abstract class Secretara{ public abstract String getNume(); }

n acest caz, putem declara clasa intern SecretaraE privat i atunci este o clas ascuns oricrui client al clasei externe, Manager. n schimb, se poate obine o referin la clasa de baz Secretara (sau la interfaa implementat) care furnizeaz funcionalitatea declarat.
private class SecretaraE extends Secretara{ ... private SecretaraE(String nume) }

public Secretara obtineObiectSecretara(String nume){...}

In metoda main, de exemplu, putem obine un obiect din clasa SecretaraE astfel:
37

Secretara s=m.obtineObiectSecretara("Maria");//in main

O clas intern poate extinde orice clas concret sau abstract. Mai mult, o clas A intern clasei B poate extinde o clas intern a supraclasei lui B. De exemplu, clasa ManagerE extinde clasa Manager:
public class ManagerE extends Manager{ public ManagerE(String nume, long salariu, int v){ super(nume, salariu, v); } public class SecretaraE extends Manager.Secretara{ public SecretaraE(String nume){ (ManagerE.this).super(nume); } } public static void main(String[] args){ Manager m=new ManagerE("Ionescu", 500, 7); Manager.Secretara s=m.obtineObiectSecretara("Maria"); System.out.println(s.getNume()); } }

O alt soluie ar fi ca constructorul clasei interne SecretaraE s conin o variabil referin la clasa nconjurtoare a clasei externe extins. Cu acest constructor putem apela constructorul supraclasei extinse:
public class ManagerE extends Manager{ public ManagerE(String nume, long salariu, int v){ super(nume, salariu, v); } public class SecretaraE extends Manager.Secretara{ public SecretaraE(Manager m, String nume){ m.super(nume); } }

n acest caz putem introduce o nou metod (overloaded cu cea motenit) care s returneze un obiect al subclasei interne SecretaraE:
public SecretaraE obtineObiectSecretara(ManagerE m, String nume){ return new SecretaraE(m,nume); } public static void main(String[] args){ ManagerE m=new ManagerE("Ionescu", 500, 7); ManagerE.SecretaraE s=m.obtineObiectSecretara(m,"Maria"); System.out.println(s.getNume()); }

UTILIZAREA CLASELOR INTERNE N APLICAII OO Clasele interne au fost introduse pentru a trata evenimentele gestionate de aplicaiile programate orientat spre obiecte. Un eveniment este o entitate conceptual care spune c ceva are loc n timp i spaiu i are consecine asupra unei aplicaii. Cu alte cuvinte, n momentul n care apare un eveniment, aplicaia noastr trebuie s execute o aciune. Aciunea depinde de tipul evenimentului aprut. Evenimentele sunt n general de dou tipuri: - evenimente externe, cele generate de utilizator n interaciunea sa cu aplicaia noastr i
38

evenimente interne, cele generate n interiorul aplicaiei.

Atunci putem defini o clas abstract Eveniment ca o clas generic de evenimente:


public abstract class Eveniment{ private long moment; public Eveniment(long mT){ moment=mT; } public boolean aAparut(){ return System.currentTimeMillis()>=moment; } public abstract void executaActiune(); public abstract String descriere(); } i un gestor generic de evenimente: public class Controller{ private Eveniment e; public void setEveniment(Eveniment e){ this.e=e; } public void gestioneaza(){ while(true) if (e.aAparut()){ e.executaActiune(); System.out.println(e.descriere()); e=null; break; } } }

Exemplu. S scriem de exemplu o aplicaie care simuleaz funcionarea unui semafor de circulaie. Vom avea clasa Semafor care conine o variabil instan privat culoare, ce reprezint culoarea curent aratat de semafor:
public class Semafor{ private String culoare; public void setCuloare(String c){culoare=c;} public String getCuloare(){return culoare;} }

Semaforul este controlat de clasa GestorSemafor care extinde clasa Controller i trateaz fiecare eveniment produs de schimbarea culorii la semafor. Aadar, toate evenimentele tratate de clasa GestorSemafor sunt de acelai tip SchimbareCuloare:
public class GestorSemafor extends Controller{ private Semafor s; public GestorSemafor(Semafor s){ this.s=s; } public class SchimbareCuloare extends Eveniment{ int culoare; public SchimbareCuloare(long timp, int culoare){ super(timp); this.culoare=culoare; }

39

public void executaActiune(){ switch(culoare){ case 1: s.setCuloare("rosu");break; case 2: s.setCuloare("galben");break; case 3: s.setCuloare("verde"); } } public String descriere(){ return "Culoarea aratata de semafor este "+s.getCuloare(); } } }

Observm c clasa SchimbareCuloare este o clas intern i este o subclas a clasei Eveniment. Clasa Test creaz un obiect Semafor n metoda main i produce la intervale scurte de timp evenimente generate de schimbarea culorii la semafor:
public class Test{ public static void main(String[] args){ Semafor s=new Semafor(); GestorSemafor gs=new GestorSemafor(s); for (int i=1; i<=10; i++){ long timp=System.currentTimeMillis(); gs.setEveniment(gs.new SchimbareCuloare(timp+1000*i, 1)); gs.gestioneaza(); gs.setEveniment(gs.new SchimbareCuloare(timp+2000*i+1000, 2)); gs.gestioneaza(); gs.setEveniment(gs.new SchimbareCuloare(timp+3000*i+2000, 3)); gs.gestioneaza(); } } }

40

8. INPUT/OUTPUT N JAVA
Pachetul java.io

Furnizeaz suport pentru citirea i scrierea datelor de la i la dispozitive diferite. Conine 4 categorii de clase: - clase de fluxuri de intrare i clase de citire - clase de fluxuri de ieire i clase de scriere - clase de gestiune a fiierelor - clasa StreamTokenizer 1. Clase de fluxuri de octei: BufferedInputStream, DataInputStream, FileInputStream i StringBufferInputStream. Derivate din clasa abstract InputStream. Clase de citire a caracterelor Unicode: Reader, BufferedReader, FileReader i StringReader sunt derivate din clasa abstract Reader. 2. Clase de fluxuri de ieire: OutputStream, FileOutputStream, BufferedOutputStream, PrintStream i StringBufferOutputStream. Sunt derivate din clasa OutputStream. Clase de scriere a caracterelor n Unicode: Writer, BufferedWriter, FileWriter i PrintWriter. Sunt derivate de clasa abstract Writer. 3. Claselor FileInputStream i FileOutputStream se adaug alte dou clase destinate gestiunii fiierelor: File i RandomAccessFile. 4. Clasa StreamTokenizer permite convertirea unui flux de intrare a datelor ntr-un flux de token-i i conine metode pentru definirea sintaxei token-ilor.

41

Ierarhia claselor I/O


DataInput Serializable Externalizable InputStream ObjectInputValidation ObjectInput ObjectOutput File FileDescriptor

ByteArrayInputStream FileInputStream FilterInputStream ObjectInputStream PipedInputStream SequenceInputStream StringBufferInputStream

BufferedInputStream DataInputStream LineNumberInputStream

Object
OutputStream DataOutput Throwable RandomAccessFile Writer FilenameFilter StreamTokenizer Reader ByteArrayOutputStream FileOuptputStream FilterOutputStream ObjectOutputStream PipedOutputStream

BufferedReader CharArrayReader InputStreamReader FilterReader PipedReader StringReader BufferedWriter CharArrayWriter FilterWriter OutputStreamWriter PipedWriter PrintWriter StringWriter

LineNumberReader FileReader PushbackReader BufferedOutputStream DataOutputStream PrintStream

FileWriter

Exception ObjectInputValidation InvalidClassException InvalidObjectException NotActiveException NotSerializableException OptionalDataException StreamCorruptedException

IOException

ObjectStreamException

EOFException FileNotFoundException InterruptedIOException SyncFailedException UTFDataFormatException CharConversionException UnsupportedEncodingException WriteAbortedException

42

Clasa InputStream

InputStream = clas abstract din care deriveaz toate clasele fluxului de intrare. Metodele clasei InputStream sunt prezentate n urmtorul tabel:
Semntura metodei abstract int read() throws IOEXception Semnificaie Valoarea returnat returneaz un octet citit de pe fluxul de intrare. Dac se detecteaz sfritul fluxului atunci metoda intoarce 1. citete octei de pe fluxul de intrare i i memoreaz n array-ul b. Dac b este mai mic dect numrul de octei citii, se lanseaz o exceptie. Metoda returneaz numrul de octei citii efectiv. citete maxim nr octei de pe fluxul de intrare i i memoreaz n array-ul b, de la poziia poz. Dac b este mai mic dect numrul de octei citii, se lanseaz o exceptie. Metoda returneaz numrul de octei citii efectiv. ignor maxim n octei din fluxul de intrare i ntoarce numrul de octei cu care s-a avansat in flux. returneaz numrul de octei disponibili pentru citire fr blocare. marcheaz poziia poz n flux pentru ca ulterior s se poat reveni la ea. Nu toate fluxurile de intrare ofer aceast operaie. repoziioneaz fluxul la ultima poziie marcat. ntoarce true dac fluxul suport operaia de marcare i revenire la poziia marcat. nchide fluxul de intrare i elibereaz resursa alocat.

int read(byte[] b) throws IOEXception

int read(byte[] b, int poz, int nr) throws IOEXception

long skip(long n) throws IOException

int available() throws IOException void mark(int poz)

void reset() throws IOException boolean markSupported() void close() throws IOException

Clasa Reader

Aceeai structur are clasa abstract Reader, specializat n citirea caracterelor. De aceea, sintaxa metodelor read() a fost modificat astfel:
Semntura metodei int read() throws IOEXception Semnificaie Valoarea returnat citete un caracter de pe fluxul de intrare i returneaz codul su Unicode. Dac se detecteaz sfritul fluxului atunci metoda intoarce 1. citete caractere de pe fluxul de intrare i i memoreaz n array-ul b. Dac b este mai mic dect numrul de caractere citite, se lanseaz o exceptie. Metoda returneaz numrul de caractere citite efectiv. citete maxim nr caractere de pe fluxul de intrare i i memoreaz n array-ul b, de la poziia poz. Dac b este mai mic dect numrul de caractere citite, se lanseaz o exceptie. Metoda returneaz numrul de caractere citite efectiv.

int read(char[] b) throws IOEXception

abstract int read(char[] b, int poz, int nr) throws IOEXception

System.in = variabil static a clasei System care memoreaz o instan a clasei InputStream. De obicei, aceast instan reprezint fluxul standard de intrare (tastatura), dar poate fi setat cu System.setIn(InputStream) astfel:
FileInputStream fi = new FileInputStream(input.txt); System.setIn(fi);

Crearea unui flux de date de intrare

43

Crearea unui flux de date de intrare respect modelul pipeline Unix: face parte dintr-o surs de date cu interfaa InputStream i se creaz succesiv cu filtri ai aceleai interfee. Caracteristicile citirii: - este un flux continuu. - cnd nu mai sunt date disponibile, instana clasei se blocheaz n ateptarea ca datele s devin disponibile. Pentru a citi date n Java procedura este ntotdeauna aceeai: 1. Se creaz o instan a unei clase de flux de intrare. 2. Se indic locul din care vor fi citite datele.
FileInputStream BufferedInputStream DataInputStream byte int File File system (Surs date) Bytes Buffer de bytes Date formatate char float long Memoria

Exemplu. Metoda urmatoare citete un caracter de la tastatur i-l returneaz:


public char citeste(){ char c='0'; try{ c=(char)System.in.read(); System.in.skip(2);//nu se citete caracterul generat de apsarea lui Enter }catch(IOException e){System.out.println(e.getMessage());} return c; } Clase de flux de octei de intrare 1. DataInputStream (InputStream in):

utilizat pentru citirea datelor primitive (int, char, long etc.);


motenete att interfaa DataInput ct i clasa abstract FilterInputStream;

la metodele furnizate de InputStream se adaug metodele interfeei DataInput readxxx() (xxx = Boolean, Byte, Short, UnsignedShort, Char, Int, Long, Float sau Double) care citesc un numr de octei din fluxul de intrare necesar pentru a obine o valoare de tip primitiv specificat n numele metodei. De exemplu, metoda readInt() citete patru octei din fluxul de intrare i ntoarce o valoare de tip int. 2. BufferedInputStream (InputStream in): - furnizeaz un flux de intrare buffer-izat permind astfel o citire mult mai rapid; - include numai metodele furnizate de InputStream; - are unele variabile membru: byte buf[], int count, int pos, int markpos i int marklimit, utile dac se extinde clasa BufferedStream.
3. FileInputStream (String nume):

execut operaii de intrare simple asupra fiierelor (pentru operaii mai avansate se utilizeaz RandomAccessFile). - construiete fluxul i cu un obiect File sau FileDescriptor. - funcioneaz ca un InputStream, dar opereaz asupra unui fiier. 4. PushBackInputStream (InputStream in) - construiete un flux cu un caracter lookahead. - are o metod unread(int ch). - funcioneaz ca InputStream.

44

Clasa abstract Reader are subclase asemntoare cu cele ale clasei abstracte InputStream: BufferedReader, FileReader, StringReader, PushBackReader. BufferedReader are o metoda String readLine(). In plus, exist clasa InputStreamReader care face legtura dintre o clasa de tip InputSream i un Reader. Urmtorul exemplu arat mai multe modalitai de a face o citire folosind clasele derivate din InputStream i Reader:
import java.io.*; public class FluxDeIntrareIesire{ public static void main(String[] args) { try { //1. Citirea unei linii de la tastatura BufferedReader in1 = new BufferedReader( new InputStreamReader(System.in)); String s=in1.readLine(); in1.close(); //2. Citirea dintr-un fisier BufferedReader in2 = new BufferedReader( new FileReader("intrare.txt")); String s1, s2 = new String(); while((s1 = in2.readLine())!= null) s2 += s1 + "\n"; in2.close(); //3. Citirea din memorie StringReader in3 = new StringReader(s2); int c; while((c = in3.read() ) != -1) System.out.print((char)c); in3.close(); //4. Citirea din memorie formatata DataInputStream in4 = new DataInputStream( new FileInputStream("intrare.txt")); while(true) System.out.print((char)in4.readByte()); } catch(EOFException e){ System.out.println("Am ajuns la sfarsitul fisierului"); } catch (FileNotFoundException e){ System.out.println("Fisier inexistent"); } catch (IOException e){ System.out.println("Exceptie IO"); } } }

Clasa OutputStream

OutputStream = clas abstract din care deriveaz toate clasele fluxului de ieire. Metodele clasei OutputStream sunt prezentate n urmtorul tabel:
Semntura metodei abstract void write(int n) throws IOEXception void write(byte[] b) throws IOEXception void write(byte[] b, int poz, int nr) throws IOEXception void flush() throws IOException void close() throws IOException Semnificaie Valoarea returnat scrie valoarea lui n pe fluxul de ieire. scrie pe fluxul de ieire octeii din array-ul b scrie nr octei pe fluxul de ieire ncepnd de la poziia poz a array-ului b. golete fluxul de ieire nchide fluxul de intrare i elibereaz resursa alocat.

Clasa Writer

Clasa Writer specializat n scrierea fluxurilor de caractere are o ierarhie similar cu ierarhia lui OutputStream. Semntura metodelor write() se modific i apar dou forme noi ale acestei metode:
Semntura metodei Semnificaie Valoarea returnat

void write(int IOEXception void write(char[]

n) b)

throws scrie valoarea lui n pe fluxul de ieire. throws scrie pe fluxul de ieire caracterele din array-ul b 45

Semntura metodei

Semnificaie Valoarea returnat

IOEXception abstract void write(char[] b, int scrie nr caractere pe fluxul de ieire ncepnd de la poz, int nr) throws IOEXception poziia poz a array-ului b. public void write(String str) scrie irul str pe fluxul de ieire. throws IOException public void write(String str, int scrie pe fluxul de ieire subirul de lungime nr pe care-l extrage de la poziia poz a irului str. poz, int nr) throws IOException

System.out = variabil static a clasei System care memoreaz o instan a clasei PrintStream ce reprezint de obicei ecranul monitorului. Este setat cu System.setOut(OutputStream):
FileOutputStream fs = new FileOutputStream(log.txt); System.setOut(new printStream(fs));

Caracteristicile scrierii: - este un flux continuu. - instana clasei de flux trimite date ct timp acestea sunt disponibile. Procedura de scriere a datelor cu o clas de fluxuri de ieire este ntotdeauna aceeai: 1. Se creaz o instan a clasei fluxului de ieire specificnd fluxul final, la destinaie. Instana se poate crea plecnd de la destinaie i compunnd fluxul din obiecte-flux ncuibate, deoarece obiectul obinut are caracteristicile dorite: buffer-izat, n stare s scrie date primitive etc. 2. Se indic locul unde vor fi scrise datele.
byte DataInputStream BufferedInputStream int char float long Memoria Buffer de bytes FileInputStream File Bytes File system Flux de bytes (Surs date)

Date formatate

Clase de flux de caractere n ieire

1. -

PrintWriter deriveaz din Writer afieaz date-text (iruri sau numere). metodele sale, altele dect cele furnizate de Write, include: print(tip) i println(tip) unde tip ia una din valorile: Object, String, boolean, char, char[], int, long, float i double. BufferedWriter deriveaz din Writer, furnizeaz un flux de ieire buffer-izat, constructorul are ca argument un obiect Writer, nu conine alte metode n afar de cele furnizate de Writer, are dou variabile membru utile: byte buf[] i int count.

PrintWriter out= PrintWriter(new FileWriter(personale.txt), true);

2. -

3. FileWriter

execut operaii simple de ieire de caractere pe fiiere (pentru operaii mai avansate pe fiiere se utilizeaz RandomAccessFile), construiete un obiect numai cu un ir, un obiect File sau un FileDescriptor, funcioneaz ca Write, dar opereaz pe fiiere.

Scrierea cu clasele Output Stream i Writer

Primul exemplu din aceast subseciune arat cum se poate determina numrul de linii ale unui fiier i scrierea fiecrei linii citite ntr-un alt fiier, mpreun cu numrul liniei curente.

46

Observaie. Pentru a afla numrul liniei curente vom folosi un cititor buffer-izat ce pstreaz numrul liniei citite. Adic vom folosi o instan a clasei LineNumberReader, subclas a lui BufferedReader.
try{ LineNumberReader lnr = new LineNumberReader(new FileReader("intrare.txt")); PrintWriter out=new PrintWriter(new BufferedWriter( new FileWriter("iesire.txt"))); String s=""; while((s = lnr.readLine()) != null) out.println("Linia " +lnr.getLineNumber()+ " "+ s); lnr.close(); out.close(); }catch(EOFException e){System.out.println("Sfarsitul fisierului");} catch(IOException ioe){System.out.println("Eroare de intrare/iesire");}

Urmtorul exemplu arat cum scriem i citim date formatate ntr-un/dintr-un fiier. Vom folosi instane ale claselor DataOutputStream i DataInputStream pentru a scrie numrul 3.14159 i irul Valoarea lui PI:
try{ DataOutputStream out=new DataOutputStream(new BufferedOutputStream( new FileOutputStream("Data.txt"))); out.writeDouble(3.14159); out.writeBytes("Valoarea lui PI"); out.close(); DataInputStream in = new DataInputStream(new BufferedInputStream( new FileInputStream("Data.txt"))); BufferedReader inbr = new BufferedReader(new InputStreamReader(in)); System.out.println(in.readDouble()); System.out.println(inbr.readLine()); }catch(EOFException e) {System.out.println("Sfarsitul fluxului");} catch(IOException ioe){System.out.println("Eroare de intrare/iesire");}

Clasa urmtoare furnizeaz dou metode care citesc, respectiv scriu date formatate pe linii de lungime fix:
import java.io.*; public class DataIO{ public static String citesteSirFix(int size, DataInput in)throws IOException{ StringBuffer buffer=new StringBuffer(size); int i=0; boolean more=true; while(more&& i<size){ char c=in.readChar(); i++; if(c==0) more=false; else buffer.append(c); } in.skipBytes(2*(size-i)); return buffer.toString(); } public static void scrieSirFix(String s, int size, DataOutput out) throws IOException{ for(int i=0;i<size;i++){ char c=0; if(i<s.length()) c=s.charAt(i); out.writeChar(c); } } }

47

Aceast clas poate fi folosit de exemplu, pentru a scrie un scrie un program care salveaza intr-un fisier datele (id, nume, salariu) a trei angajati ai unei companii i apoi le afieaza n ordinea invers scrierii lor:
import java.io.*; class Angajat{ public static final int SIZE_NUME=40; public static final int RECORD_SIZE=2*SIZE_NUME+4+8; private String nume; private int id; private double salariu; public Angajat(){} public Angajat(int id, String nume, double salariu){ this.id=id; this.nume=nume; this.salariu=salariu; } public void writeData(DataOutput out) throws IOException{ out.writeInt(id); DataIO.scrieSirFix(nume, SIZE_NUME,out); out.writeDouble(salariu); } public void readData(DataInput in)throws IOException{ id=in.readInt(); nume=DataIO.citesteSirFix(SIZE_NUME,in); salariu=in.readDouble(); } public String toString(){ return id+" "+nume+" "+salariu; } } public class TestAngajat{ public static void main(String[] arg){ Angajat[] a=new Angajat[3]; a[0]=new Angajat(1, "popescu ion", 45.899); a[1]=new Angajat(2, "ionescu pop", 435.877); a[2]=new Angajat(2, "marinescu marin", 235.877); try{ DataOutputStream out=new DataOutputStream(new FileOutputStream("angajat.dat")); a[0].writeData(out); a[1].writeData(out); a[2].writeData(out); out.close(); }catch(IOException ioe){} try{ RandomAccessFile in=new RandomAccessFile("angajat.dat", "r"); int n=(int)(in.length()/Angajat.RECORD_SIZE); System.out.println("n="+n); Angajat[] an=new Angajat[n]; for(int i=n-1; i>=0;i--){ an[i]=new Angajat(); in.seek(i*Angajat.RECORD_SIZE);

48

an[i].readData(in); System.out.println(an[i]); } } } } catch(IOException e){System.out.println(e.getMessage());}

Clasa File

Clasa File prezint o vedere abstract a numelor fiierelor i a directoarelor, precum si locaiilor unde se gsesc acestea ntr-un sistem de fiiere. Locaia unui fiier reprezint calea n sistemul de fiiere unde este memorat acesta. Calea poate fi absolut sau relativ la directorul n care se gsesc class-urile programului. Separatorul unei ci depinde de sistemul de operare pe care ruleaz programul si anume: - \\ pentru sistemele Windows - / pentru sistemele Unix. Acesta este memorat n constantele String separator i char separatorChar, vzut ca un String, respectiv ca un caracter. Constructori:
File(String cale)//creaz un obiect File ce contine o cale absolut sau relativ i care poate conine numele fiierului File(String cale, String nume)//creaz un obiect File ce conine separat numele fiierului i calea directorului n care se afl fiierul File(File dir, String nume)//calea directorului printe este dat ca un obiect File

Metodele mai importante ale clasei File sunt prezentate n urmtorul tabel:
Semntura metodei String getName() String getPath() String getAbsolutePath() String getParent() boolean exists() boolean canWrite() boolean canRead() boolean isFile() boolean isDirectory() long lastModified() long length() boolean mkdir() boolean mkdirs() boolean renameTo(File dest) boolean delete() String[] list() String[] list(FilenameFilter filtru) Semnificaie Valoarea returnat returneaz numele fiierului sau directorului curent returneaz calea unde se afl fiierul sau directorul curent pe disc returneaz calea absolut unde se afl fiierul sau directorul curent pe disc ntoarce directorul printe a directorului sau n care se gsete fiierul curent returneaz true dac fiierul indicat in constructor exist pe disc. returneaz true dac fiierul respectiv poate fi modificat returneaz true dac fiierul respectiv poate fi citit returneaz true dac irul indicat ca fiier exist pe disc i este un fiier returneaz true dac irul indicat ca director exist pe disc i este un director returneaz data i ora ultimei modificri returneaz mrimea fiierului, n bii returneaz true dac a fost creat directorul specificat in cale returneaz true dac au fost create directoarele specificate in cale redenumete fiierul cu curent cu numele dest i returneaz true terge fiierul sau directorul curent ntoarce ntr-un array de iruri numele fiierelor i directoarelor din directorul curent. ntoarce ntr-un array de iruri numele fiierelor i directoarelor din directorul curent care ndeplinesc criteriul filtru

49

De exemplu, pentru a crea un filtru trebuie s scriem o clas care implementeaz interfaa FilenameFilter. De exemplu, urmtoarea clasa filtreaza fiierele dintr-un director si le accept numai pe cele care sunt programe Java: import java.io.*; public class Filtru implements FilenameFilter{ public boolean accept(File dir, String nume){ String sufix=""; int i=nume.lastIndexOf('.'); if(i>0 && i<nume.length()-1) sufix=nume.substring(i+1); return sufix.equals("java"); } public String getDescription(){ return "fisiere java(*.java)"; } }

Urmtorul exemplu citete numele unui fiier/director de la tastatur i-l scrie informaii despre el, cum ar fi: dac este fiier sau director, locaia sa pe disc, data ultimei modificri, etc, n fiierul analiza.txt:
import java.io.*; public class Fisier{ BufferedReader br; PrintWriter pw; public Fisier(){ try{ br=new BufferedReader(new InputStreamReader(System.in)); pw=new PrintWriter(new FileWriter("analiza.txt"), true); scrie(analizeaza(citeste())); }catch(IOException ioe){} } public String citeste()throws IOException{ System.out.println("Dati numele fisierului/directorului"); return br.readLine(); } public String analizeaza(String sir){ File nume=new File(sir); StringBuffer buffer=new StringBuffer(); if(nume.exists()){ buffer.append(nume.getName()+" exista\r\n"); if(nume.isFile()) buffer.append("este un fisier\r\n"); if(nume.isDirectory())buffer.append("este un director\r\n"); if(nume.isAbsolute())buffer.append("este o cale absoluta\r\n"); else buffer.append("nu este o cale absoluta\r\n"); buffer.append("data ultimei modificari "+nume.lastModified()+"\r\n"); buffer.append("lungimea "+nume.length()+"\r\n"); buffer.append("calea "+nume.getPath()+"\r\n"); buffer.append("calea absoluta "+nume.getAbsolutePath()+"\r\n"); buffer.append("parinte "+nume.getParent()+"\r\n"); if(nume.isFile()){

50

buffer.append("Continutul fisierului\r\n"); try{ RandomAccessFile in=new RandomAccessFile(nume, "r"); String s=""; while((s=in.readLine())!=null) buffer.append(s+"\r\n"); in.close(); }catch(IOException ioe){} } else if(nume.isDirectory()){ buffer.append("Continutul directorului\r\n"); String[] dir=nume.list(); for(int i=0;i<dir.length; i++) buffer.append(dir[i]+"\r\n"); } } else buffer.append("acest nume nu exista"); return buffer.toString(); } public void scrie(String sir) throws IOException { pw.print(sir); pw.close(); } public static void main(String[] a){ new Fisier(); } } Programul 1. Fisier: Lucrul cu clasa File

Clasa StreamTokenizer
Ca i StringTokenizer, aceast clas imparte un flux in token-i, dar spre deosebire de prima clas, difereniaz ntre tipuri de token-i: iruri, numere, sfritul unei linii, sfritul fiierului, etc. Constructorul clasei: public StreamTokenizer(Reader r)//creaza un tokenizer care imparte fluxul de intrare r ntr-un ir de token-i. Pentru a sti daca s-a ajuns la sfarsitul liniei curente se foloseste constanta: public static finale int TT_EOL //token-ul citit conine sfaritul liniei curente (\r sau \n) dac acesta este tratat ca un token, adic a fost apelat metoda void eolIsSignificant(boolean val) cu val=true. iar pentru a trata sfarsitul fluxului de intrare folosim constanta public static finale int TT_EOF //token-ul citit conine sfritul fluxului de intrare Deosebirea fa de clasa StringTokenizer este ca aceasta clas difereniaza token-ii obtinuti din fragmentare. Astfel, clasa ofera urmatoarele constante: public static finale int TT_NUMBER //token-ul citit este un numr public static finale int TT_WORD //token-ul citit este un cuvnt Pentru a obtine numrul, respectiv cuvntul citit se folosesc urmtoarele variabile instan: public double nval //conine valoarea numrului ntors ca token public String sval //conine caracterele cuvntului ntors ca token Pentru a obtine un token din fluxul analizat se apeleaz metoda instan:
public int nextToken()

care returneaz tipul token-ului citit ca un numar intreg. Acesta este memorat dupa apelul metodei si n variabila instan public int ttype. Clasa ofer si alte metode utile n analizarea unui flux de intrare specializat: public void parseNumbers()//sunt analizate numerele si caracterele . si . public int lineno()//ntoarce numrul liniei curente. 51

public void ordinaryChar(int ch) //trateaza caracterul dat la apelul metodei ca unul

oarecare, fara sa mai verifice tipul sau si-l intoarce ca un token de tip TT_WORD.
public void ordinaryChars(int min, int max) //toate caracterele ce au codul Unicod in

intervalul [min, max] sunt tratate ca oarecare.


public void commentChar(int ch) //caracterul ch indica inceputul unui comentariu. In acest

caz, token-ii fluxului de intrare aflati pana la sfarsitul liniei vor fi ignorai.
public void quoteChar(int ch) //caracterele gasite intre dou apariii a lui ch sunt tratate ca

un literal String si intoarse ca un token de tip TT_WORD. Dac a doua apariie a caracterului ch nu este gsit pana la sfaritul liniei, se iau caracterele pana la acesta. Daca ch apare o singur dat in fluxul de intrare, se iau caracterele de la ch pana la sfarsitul fisierului. public void whitespaceChars(int min, int max) // toate caracterele ce au codul Unicod in intervalul [min, max] sunt tratate ca spatii. public void wordChars(int min, int max) // toate caracterele ce au codul Unicod in intervalul [min, max] sunt tratate ca parte din cuvinte. public void pushBack()//token-ul curent va fi obtinut si la urmatorul apel al metodei nextToken() Exemplu. Sa scriem un program care citeste continutul fisierului intrare.txt si afiseaza tipul fiecarui token si valoarea sa, precum i numarul de cuvinte, respectiv numere, din fisierul respectiv.
import java.io.*; public class Tokenizer{ private StreamTokenizer st; private int w, n; public Tokenizer(){ String linie; try{ st=new StreamTokenizer(new BufferedReader(new FileReader("intrare.txt"))); }catch(FileNotFoundException nf){System.out.println(nf.getMessage());} catch(IOException io){System.out.println(io.getMessage());} } public void imparte(){ if(st==null) System.exit(0); try{ while(st.nextToken()!=StreamTokenizer.TT_EOF){ switch(st.ttype){ case StreamTokenizer.TT_WORD: System.out.print("cuvant= "+st.sval+" "); w++; break; case StreamTokenizer.TT_NUMBER: System.out.print("numar= "+st.nval+" "); n++; break; } System.out.println(); } System.out.println("Total cuvinte= "+w); System.out.println("Total numere= "+n); }catch(IOException io){System.out.println(io.getMessage());} } public static void main(String[] args){ Tokenizer t=new Tokenizer(); t.imparte(); } }

52

9. GESTIUNEA EXCEPIILOR
O excepie este o condiie exceptional care ntrerupe execuia unui program i care poate fi: - condiie de eroare provocat de erori interne sau lipsa resurselor mediului de executie Java, - situaie particular aprut n timpul execuiei programului care poate fi de unul din urmtoarele tipuri: - excepii necontrolate cauzate de erori de programare: cast greit, cast care depete limita unui array, referin la un obiect null, - excepii controlate: erori de intrare/ieire precum continuarea operaiei de citire dup ce s-a ajuns la sfritul fiierului, ncercarea de a deschide un URL greit. Cnd apare o excepie este important s captm cauza ce a dus la apariia ei, mpreun cu alte informaii, cum ar fi valoarea variabilelor folosite, ce vor ajuta la tratarea exceptiei. De aceea, toate excepiile n Java sunt reprezentate de obiecte ale subclaselor clasei Throwable din pachetul java.lang:
public class Throwable{ public Throwable(); public Throwable(String mesaj); public String getMessage(); public String toString(); public void printStackTrace(); public void printStackTrace(java.io.PrintStream ps); public void printStackTrace(java.io.PrintWriter pw); public Throwable fillInStackTrace(); }

Dup cum observm, clasa Throwable implementeaz mai multe metode printre care i metoda getMessage() care returneaz un ir care descrie situaia care a cauzat excepia. De exemplu, clasa RunTimeException conine tipuri de excepii lansate automat de JVM. Dac nu sunt tratate de programator, dac apare o astfel de excepie se va apela metoda printStackTrace() a clasei Throwable. De exemplu, executarea urmtorului program
public class Exceptie{ static void metoda1(int[] a){ metoda2(a); } static void metoda2(int[] b){ System.out.println(b[0]); } public static void main(String[] args){ metoda1(null); } }

determin afiarea mesajului:


java.lang.NullPointerException at Exceptie.metoda2(Exceptie.java:6) at Exceptie.metoda1(Exceptie.java:3) at Exceptie.main(Exceptie.java:9)

Mesajul afiat conine urmtoarele informaii: - tipul de exceptie aruncat, - stiva apelurilor metodelor, fiecare cu clasa i unitatea de compilare de care aparine, mpreuna cu numrul liniei pe care se gsete declaraia metodei. Metoda din vrful stivei este cea care a aruncat excepia respectiv. Toate excepiile ce pot fi generate sunt mprite n dou clase: Exception i Error, ambele derivate din clasa Throwable. Subclasele lui Exception, cu excepia lui RuntimeException i a subclaselor sale, indic situaii particulare care nu sunt erori. Error, RuntimeException i subclasele lor indic condiii care n general nu sunt corecte i care de obicei genereaz terminarea unui program. Toate

53

pachetele incluse n JDK genereaz diferite tipuri de excepii. O parte din acestea sunt prezentate n figurile de mai jos i unele din acestea sunt explicate n urmtorul tabel:
Exceptie ArithmeticException ArrayIndexOutOfBoundsException ArrayStoreException ClassNotFoundException FileNotFoundException IOException NullPointerException NumberFormatException OutOfMemoryException SecurityException StackOverflowException StringIndexOutOfBoundsException Cauzat de Erori matematice cum ar fi imparirea la zero. Indicele unui array este n afara array-ului. Se memoreaz ntr-un array o valoare de tip diferit de tipul de date al array-ului. Se ncearc folosirea unei clase pe care compilatorul nu o cunoate. Clasa respectiv trebuie s fie importat sau scris de ctre programator. Se acceseaz un fiier care nu exist n locaia specificat de program. Erori generale de I/O, cum ar fi incapacitatea de citi dintr-un fiier. Referirea unui obiect null. O conversie euat ntre iruri i numere. Memorie insuficient crerii unui obiect nou. Un applet nacearc s realizeze o aciune care nu este permis de browser. Depirea stivei de execuie. Programul incearc s acceseze un caracter de pe o poziie care nu exist n ir.

54

Excepii i erori
ClassNotFoundException CloneNotSupportedException Object Throwable Exception IllegalAccessException InstantiationException InterruptedException NoSuchMethodException NoSuchFieldException RunTimeException IOException ClassCircularityError ClassFormatError ArithmeticException ArrayStoreException ClassCastException IllegalArgumentException IllegalStateException IllegalMonitorStateException IndexOutOfBoundsException NegativeArraySizeException NullPointerException SecurityException AbstractMethodError IllegalAccessError InstantiationError NoSuchFieldError NoSuchMethodError ArrayIndexOutOfBoundsException StringIndexOutOfBoundsException IllegalThreadStateException NumberFormatException

ExeptionInInitializerError LinkageError IncompatibleClassChangeError NoClassDefFoundError Object Throwable Error UnsatisfiedLinkError ThreadDeathError VerifyError

InternalError VirtualMachineError OutOfMemoryError StackOverflowError UnknownError

55

Cum utilizm excepiile? Exist mai multe alternative pentru programator: - corectarea problemei i apelarea metodei care a cauzat excepia; - se ncearc repararea unei greeli i se continu fr s se reapeleze metoda; - elaborarea unui rezultat alternativ raportat la cel produs n mod normal de metod; - se face tot ce se poate n contextul curent i se relanseaz aceeai excepie n contextul superior; - se face tot ce se poate n contextul curent i se relanseaz o excepie diferit n contextul superior; - se termin programul. Tratarea excepiilor prezint urmtoarele avantaje: - simplific dac schema de elaborare a excepiilor aleas complic lucrurile, - face mai fiabile programul i librriile utilizate. Aceasta e desigur o investiie bun pe termen scurt (pentru debugging) i pe termen lung (pentru robusteea programului). Mecanismul de gestiune a excepiilor furnizeaz reguli care impun cine este capabil s genereze excepii (throws) i cnd (throw), cine va ncerca excepiile (try..catch) i ce trebuie s fac pentru a mpiedica apariia unei excepii. Interceptarea i tratarea excepiilor Interceptarea i tratarea excepiilor se realizeaz de ctre gestorii de excepii (exception handler). Cnd n interiorul unei metode va fi lansat o excepie sau apelul unei metode lanseaz o excepie, n mod normal, controlul abandoneaz metoda. Dac nu se dorete ca metoda respectiv s fie abandonat, instruciunile ce pot genera cel puin o excepie se includ ntr-un bloc try care ncearc s le execute. Blocul creaz un mediu (spaiu de nume) n interiorul metodei. Dac apare o excepie ca rezultat al executrii uneia din instruciunile blocului, ea poate fi prins (catch) de gestorul excepiei respective. Gestorii excepiilor pentru un bloc try sunt introdui cu cuvntul cheie catch i urmeaz blocul try. Fiecare gestor de excepii este ca o metod care primete un unic argument care are tipul unei excepii i va fi executat n cazul n care apare o excepie de tipil respectiv. Argumentul metodei poate s nu fie utilizat n codul gestorului, iar alegerea gestorului este n ntregime bazat pe tipul excepiei. Pentru acelai bloc try putem avea mai muli gestori. In acest caz este important ordinea gestorilor, deoarece n cazul apariiei unei excepii, se verific tipul excepiei cu fiecare gestor n ordinea n care apar dupa blocul try. Se va executa primul gestor care verific excepia, iar restul se ignor. In exemplul urmtor, acest lucru nseamn c al doilea gestor niciodat nu va trata nici o excepie, deoarece primul este mai general i va trata i excepiile de intrare/ieire (deoarece IOException este o subclas a lui Exception). Aceast situaie va fi detectat de compilatorul Java i va reporta o eroare.
void metoda1(){ try{ //cod care poate produce o exceptie }catch(IOException ioe){ //cod care gestioneaza exceptia ioe } catch(Exception e){ //cod care gestioneaza exceptia e } }

Un bloc try poate fi urmat eventual i de un bloc declarat cu finally. Un bloc finally conine instruciuni ce vor fi executate ntotdeauna, chiar dac apare o excepie i furnizeaz un spaiu util de a scrie cod care s fie executat indiferent ce se ntmpl. De exemplu, urmtoarea metod gestioneaz interceptarea unei excepii i a unei erori i indiferent dac acestea apar sau nu, se va executa codul din blocul finally:
void metoda2(){ try{ //cod care poate produce o exceptie }catch(Exception e){

56

//cod care gestioneaza exceptia e } catch(Error er){ //cod care gestioneaza eroarea er } finally{ //cod ce va fi executat indiferent daca apar sau nu exceptia e sau eroarea er } }

Gestorul poate prinde o excepie de tip: - Exception pentru orice excepie din bibliotecile Java; - specializat pentru un pachet Java (de exemplu IOException); - definit de programator. Declaraii throws Dac o metod nu trateaz toate excepiile ce pot apare atunci cnd este executat corpul su, atunci ea trebuie s declare n header-ul su toate tipurile de excepii care pot s apar i nu le trateaz. Pentru aceasta se insereaz o declaraie throws dup parametrii metodei i nainte de corpul su:
modificatori numeTip numeMetoda(listaParametri) throws listaNumeTip{ //lista de instructiuni }

unde listaNumeTip::=numeTip [, numeTip]* Excepiile declarate cu throws se vor propaga metodei superioare n stiv, aceleia care a apelat-o. In acest caz, metoda apelant trebuie s se afle n una din urmtoarele situaii: - metoda este apelat dintr-un bloc try care are gestori capabili s prind toate tipurile de excepii ce pot fi aruncate de metoda apelat. - metoda este apelat dintr-un bloc try care are gestori capabili s prind numai unele din tipurile de excepii ce pot fi aruncate de metoda apelat. Pentru celelalte tipuri de excepii, metoda apelant trebuie s le declare cu throws i ele vor fi propagate mai departe. - metoda este apelat din afara unui bloc try i atunci toate tipurile de excepii ce pot fi aruncate trebuie s apar n declaraia throw a metodei apelante. Not: Excepiile de tip Error, RuntimeException i a subclaselor sale nu trebuie s fie declarate cu throws. Urmtoarea metod returneaz un caracter citit de la tastatur:
public char citesteCaracter() throws IOException{ return (char)System.in.read(); }

Lansarea excepiilor n timpul proiectrii programului sau n timpul depanrii, dac se consider necesar ca o metod s lanseze o excepie, se execut urmtorii pai: - cutarea clasei de excepii corespunztoare; - dac metoda nu trateaz excepia aprut, se declar c apelul metodei va lansa o excepie (cu ajutorul lui throws i clasa de exceptie gsit la pasul anterior); - crearea unui obiect al acelei clase; - lansarea obiectului creat imediat dup punctul n care se verific excepia, folosind instruciunea throw; Exemplu. Metoda urmtoare citete caracter cu caracter o linie de la tastatur pe care o returneaz metodei apelante care trebuie s trateze excepia de tip IOException sau s-o arunce mai departe metodei apelante:

57

import java.io.*; public class Linie{ StringBuffer sb=new StringBuffer(); void readLine() throws IOException{ char c; while(true){ c=(char)System.in.read(); if (c==13) throw new IOException("Caracterul citit este CR"); sb.append(c); } } public static void main(String[] args){ Linie f=new Linie(); try{ f.readLine(); }catch(IOException e){System.out.println(e.getMessage());} System.out.println(f.sb.toString()); } }

Procesul de reportare a unei excepiei n sus continu pn cnd excepia va fi interceptat de o metod activ care se angajeaz s o rezolve sau pn cnd ajunge n vrful stivei i aplicaia se termin. Urmtorul exemplu arat cum se poate citi coninutul unui fiier i s detectm sfritul fiierului aruncndu-se o excepie de tip EOFException:
String readData(BufferedReader in){ StringBuffer sb=new StringBuffer(); String s; try{ while(true){ s=in.readLine(); if (s==null){ in.close(); throw new EOFException("Am ajuns la sfarsitul fisierului"); } sb.append(s); } }catch(IOException ioe){ System.out.println("Exceptie de citire: "+ioe.getMessage()); } finally{ return sb.toString(); } }

Observaie: Cum EOFException este o subclas a lui IOException, metoda readData() trateaz excepia aprut, deci ea nu va fi aruncat metodei apelante. Important: lansnd o excepie, metoda nu o returneaz apelului. Se pot crea clase de excepii noi. Trebuie s avem o clas care extinde clasa Exception sau un alt tip apropiat ca semantic cu excepia noastr, n care s redefinim constructorii. De exemplu, ne definim o clas excepie numit FileFormatException:
public class FileFormatException extends IOException{ public FileFormatException(){} public FileFormatException(String mesaj){ super(mesaj); } }

Atunci, metoda readData() de mai sus ar putea fi rescris astfel:


58

String readData(BufferedReader in){ StringBuffer sb=new StringBuffer(); String s; try{ while(true){ s=in.readLine(); if (s==null){ in.close(); throw new FileFormatException("Am ajuns la sfarsitul fisierului"); } sb.append(s); } }catch(IOException ioe){ System.out.println("Exceptie de citire: "+ioe.getMessage()); } finally{ return sb.toString(); } }

O excepie poate fi rearuncat i dintr-un bloc catch. Atunci putem avea mai multe metode din lanul de metode active care s trateze excepia, poate fiecare din acestea indeplinindu-si partea sa din restaurarea strii programului astfel nct acesta din urm s-i poat continua execuia dup ce excepia a fost tratat.

59

10. COLECTII
STRUCTURI DE DATE DINAMICE Presupunem c avem nevoie s utilizm grupuri de obiecte care au unele proprieti comune, cum ar fi personalul unei ntreprinderi, conturile bancare ale clienilor unei bnci sau comenzile fcute n ultima perioad. Numrul componentelor din grup nu este cunoscut de obicei cunoscut de la nceput i poate varia dup necesitile aplicaiei. Utilizarea unui astfel de grup este necesar din urmtoarele motive: - verificarea c un anumit obiect exist n grup, - adugarea unui nou obiect la grup, - eliminarea unui obiect existent din grup. Deseori trebuie s executm operaii care privesc ntregul grup, cum ar fi: - coninutul obiectelor coninute, - verificarea dac grupul este vid sau conine cel puin un obiect, - adugarea la grup sau eliminarea din grup a unui grup de obiecte, - eliminarea tuturor obiectelor din grup. Astfel de grupuri de obiecte se numesc colecii i pentru a le putea elabora, trebuie s proiectm algoritmi i structuri de date corespunztoare. TIPOLOGII DE COLECII Pentru a gsi soluii standard la problema coleciilor este mai nti necesar s identificm tipurile de colecii dup care modul n care se dorete elaborarea coleciei. Pentru fiecare tip de colecie, pot fi oferite servicii care satisfac exigenele programatorilor. Diferenele dintre colecii se datoreaz fie din exigenele ce privesc navigarea ntr-o colecie, fie din natura sa: colecia de obiecte sau relaii de tipuri funcionale ntre dou colecii, care formeaz ntodeauna o colecie. De exemplu, programatorul poate fi interesat de o colecie n care fiecare component se gsete ntr-o poziie bine stabilit n raport cu alte componente sau colecia nu impune nici o ordine poziional, dar atunci cnd este navigat se pot ntlni duplicate care pot crea confuzie. n primul caz avem tipul list (List) de colecie, n schimb, n al doilea caz, avem tipul mulime (Set). n schimb, nu este unica posibilitate de a gsi un element fie prin navigarea componentelor sau prin identificarea lui prin intermediul un numr de ordine. n anumite aplicaii poate fi util s gsim o component prin intermediul proprietilor ei, sintetizate de o dat cheie. Este cazul relaiilor care sunt colecii de legturi ntre o cheie i componenta asociat (tipul Map). n alte situaii, mult mai complexe, relaiile dintre componentele unei colecii nu mai sunt de ordine total, ca n cazul listelor, ci de oridne parial. Este cazul arborilor i a grafurilor care necesit modaliti sofisticate de abordare. Tabelul 10-1 reamintete principalele structuri de date, cu avantajele i dezavantajele lor de utilizare.
Structura de date Array Array ordonat List nlnuit Stiv Coad Arbore binar Arbore binar de Avantaje Inserare rapid, acces rapid dac indexul este cunoscut Cutare mai rapid dect ntr-un array neordonat Inserare i eliminare rapide Acces last-in, first-out Acces first-in, first-out Cutare, inserare i eliminare rapid (dac arborele rmne balansat) Cutare, inserare i eliminare rapid. Arborele Dezavantaje Cutare lent, eliminare lent, capacitate limitat Cutare lent, eliminare lent, capacitate limitat Cutare lent Acces lent la componentele care nu sunt n vrf Acces lent la componentele care nu sunt n vrf Algoritm de eliminare complex pentru ca arborele s rmn balansat Este complex.

60

Structura de date cutare Arbore rosu-negru Tabel hash Heap Graf

Avantaje este ntotdeauna balansat. Poate fi utilizat pentru file systems Cutare, inserare i eliminare rapid. Arborele este ntotdeauna balansat. Acces foarte rapid dac se cunoate cheia. Inserare rapid. Inserare i eliminare rapide Modeleaz situaii frecvente n lumea real

Dezavantaje

Este complex. Eliminare lent, acces lent dac cheia nu este cunoscut, utilizeaz ineficient memoria. Acces rapid la componente mai mari. Acces lent la alte componente. Orice algoritm este complex i lent

Tabelul 10-1. Principalele structuri de date 10.1.1 Structura de date list

O list este o secvena finit de zero sau mai multe elemente. Dac toate elementele sunt de acelai tip T, spunem c lista este de tip T. Notatie. De obicei, o lista este este scris specificandu-se elementele sale ai: (a1, a2, , an) Exemple: Lista numerelor prime 10 numere prime naturale: (2,3,5, 7,11, 13, 17, 19, 23, 29) O linie de text este o lista de caractere. Un document este o lista de linii de text. Lungimea unei liste este numrul de apariii a elementelor listei. Daca numarul este zero, atunci lista este vid. Notatie () sau . Daca o lista este nevid, atunci primul element se numeste capul listei, iar restul listei formeaz coada listei. Daca L=(a1, a2, , an) este o list, atunci pentru orice i i j a.i. 1ijn, (ai, ai+1, , aj) este o sublista a lui L. Exp. Prefixul unei liste este orice sublista care incepe la inceputul unei liste. Sufixul unei liste este o sublista care se termin la sfaritul listei. Exp. fiecare element din list are asociat o poziie. Dac L=(a1, a2, , an) i n1 atunci a1 este primul element, a2 al doilea, samd, an este ultimul element in lista. De asemenea, putem spune c aI apare la poziia i in lista. Asadar, numarul de poziii ale unei liste formeaza lungimea listei.
Operaii asupra listelor

1. Inserarea unui element x ntr-o list L. In principiu x ar putea s apar oriunde in list i nu conteaz dac x apare de mai multe ori. Ca un caz special, putem insera pe x la inceputul listei i atunci x va fi capul noii liste, iar lista initiala va deveni coada, L=(x, a1, a2, , an). 2. Stergerea unui element din list. Se va sterge prima apariie a elementului x n list. Daca x nu apare in lista, atunci operatia de stergere nu are nici un efect. 3. Stergerea tuturor elementelor din lista. 4. Putem cauta un element intr-o lista L. Aceasta operatie este logic, returnand true daca x se gaseste in lista. 5. prim(L) intoarce primul element al listei i ultim(L) intoarce ultimul element al listei . Ambele genereaza o eroare daca lista este vida. 6. elementAt(i, L) returneaza elementul de pe pozitia i a listei L. Avem eroare daca L este de lungime mai mica decat i. 7. lungime(L) returneaza lungimea listei L. 8. esteVida(L) returneaz true daca L nu contine nici un element. 9. concateneaza(L1, L2) dou liste L1 i L2.
Implementarea listelor

Modul cel mai uor de a implementa o lista este s folosim o lista de noduri legate ntre ele. Fiecare nod contine doua campuri: primul contine un element al listei, al doilea contine o referinta la urmatorul nod al listei. Implementarea in Java a unui nod al listei este:
61

public class Nod{ private Object element; private Nod next; public Nod(Object o){ element=o; } public Nod(Object o, Nod n){ element=o; next=n; } }

Atunci, pentru fiecare element al listei avem cate un nod; elementul ai apare n campul element al nodului i. Variabila next din nodul i contine o referint la nodul (i+1), pt i=1, n-1. Variabila next al ultimul nod este null, indicnd sfaritul listei. De exemplu: lista L=(a1, a2, , an) este reprezentata ca o list linked-itata astfel: a1 a2 an

Implementarea n Java a operaiilor asupra listelor linked-itate este realizat n urmtorul program:
public class Lista{ private Nod cap; private Lista coada; private int nr; public boolean esteVida(){ return lungime()<=0; } public int lungime(){ return nr; } //adauga un element la sfarsitul listei public void adaugaElement(Object o){ Nod n=new Nod(o); if (esteVida()){cap=n;nr++;} else insereazaElement(o, nr); } //inserarea unui element la o anumita pozitie public void insereazaElement(Object o, int index){ if (esteVida() && index==0){adaugaElement(o); return;} if (verificaPozitie(index)){ Nod n=new Nod(o); if(index==0){ n.next=cap; cap=n; } else { Nod curent=nodLa(index-1); n.next=curent.next; curent.next=n; } nr++; } } //verificarea pozitiei unui element private boolean verificaPozitie(int index){ if (index>lungime() || index<0) return false; 62

return true; } //returneaza nodul de la o anumita pozitie public Nod nodLa(int index){ if (verificaPozitie(index)){ if (index==0) return cap; Nod n=cap; for(int i=0; i<index;i++) n=n.next; return n; } return null; } //returneaza elementul de la o anumita pozitie public Object elementulDeLa(int index){ Nod n; if ((n=nodLa(index))!=null) return n.element; return null; } //cauta un element in lista public int cauta(Object o){ Nod n=cap; for (int i=0;i<nr;i++){ if (n.element.equals(o)) return i; else n=n.next; } return -1; } //returneaza primul element din lista public Object prim(){ return cap.element; } //returneaza ultimul element din lista public Object ultim(){ return nodLa(nr-1).element; } //sterge un element din lista daca acesta exista public boolean stergeElement(Object o){ int poz=cauta(o); if(poz==-1) return -1; Nod curent=nodLa(poz); if(poz==0) cap=curent.next; else{ Nod anterior=nodLa(poz-1); anterior.next=curent.next; } curent=null; nr--; return true; } //sterge toate elementele listei public void stergeToateElementele(){ if (!esteVida()){ cap=null; coada=null; nr=0; 63

} } //afiseaza lista sub forma (o1, o2, ..., on) public String toString(){ StringBuffer sb=new StringBuffer(); sb.append("["); IteratorLista it=new IteratorLista(cap); while (it.hasNext()){ sb.append(it.next().toString()); if (it.hasNext()) sb.append(", "); } sb.append("]"); return sb.toString(); } //converteste lista la un array public Object[] getListaArray{ Object[] o=new Object[lungime()]; int poz=0; IteratorLista it=new IteratorLista(cap); while(it.hasNext()){ o[poz]=it.next(); poz++; } return o; } //concateneaza lista curenta cu o alta lista public Lista concateneaza(Lista l){ Lista rez=this; IteratorLista it=new IteratorLista(new Nod(l.prim())); while (it.hasNext()) rez.adaugaElement(it.next()); return rez; } }//clasa Lista public class IteratorLista{ private Nod curent; public IteratorLista(Nod c){ curent=c; } public boolean hasNext(){ return curent!=null; } public Object next(){ Object ret=curent.element; curent=curent.next; return ret; } } public class TestLista{ public static void main(String[] args){ Lista l=new Lista(); Lista p=new Lista(); Student[] s=new Student[3]; s[0]=new Student(Ionescu, Ion, Informatica); s[1]=new Student(Popescu, Mircea, Matematica-Informatica); 64

s[2]=new Student(Marinescu, "Ciorica", Informatoca); l.adaugaElement(s[0]); l.adaugaElement(s[1]); System.out.println(l); l.stergeElement(s[0]); System.out.println("sterge= "+l); l.insereazaElement(s[2],0); System.out.println(l); System.out.println("primul element= "+l.prim()); System.out.println("ultimul element= "+l.ultim()); if(l.cauta(s[0])) System.out.println("elementul se gaseste in lista"); else System.out.println("elementul nu se gaseste in lista"); p.adaugaElement(s[1]); Lista rez=l.concateneaza(p); System.out.println(rez); Object o=rez.elementulDeLa(1); if (o!=null) { ((Student)o).setMedie(9.35); System.out.println(o); } System.out.println(rez); l.stergeToateElementele(); System.out.println(l); } } 10.1.2 Structura de date stiv

O stiv este un model de date bazat pe modelul list n care toate operaiile sunt realizate la un capt al listei, care se numete vrful stivei. Stiva este o structur de date LIFO adic last-in first-out (ultimul intrat, primul ieit). Modelul abstract al unei stivei este acelai cu cel al unei liste adic o secven de elemente a1, a2,, an de un anumit tip. Ceea ce deosebete o stiv de o list este setul de operaii permise aupra unei stive.
Operaii asupra unei stive

Inserarea unui element x ntr-o stiv S, push(x, S), determin punerea elementului x n vrful stivei S. Dac stiva are vrful captul stng al stivei, operaia push(x) aplicat listei (a1, a2,, an) genereaz lista (x, a1, a2,, an). Stergerea elementului din vrful stivei este realizat de metoda pop(S). Aceasta va sterge elementul din vrful stivei i va fi returnat de ctre metod. Dac stiva este vid, metoda va genera o eroare. Stergerea tuturor elementelor din stiv va fi realizat de metoda stergeToateElementele(S). Metoda lungime(S) va returna lungimea stivei S, iar metoda esteVida(S) returneaz true dac S nu contine nici un element.
Implementarea stivelor

Pentru a implementa static o stiv vom folosi un array de 10 obiecte:


public class StivaArray{ private Object[] lista; private Object varf; 65

private static int nr=10; private int poz; public StivaArray(){ lista=new Object[nr]; } public void push(Object x){ if (esteVida()) lista[0]=x; else { System.arraycopy(lista, 0, lista, 1, poz); lista[0]=x; } varf=lista[0]; poz++; } public Object pop() throws ListaException{ if (esteVida()) throw new ListaException("Stiva este vida"); Object o=varf; System.arraycopy(lista, 1, lista, 0, poz-1); poz--; return o; } public void stergeToateElementele(){ for (int i=0; i<poz; i++) lista[i]=null; varf=null; poz=0; } //verifica daca stiva este vida public boolean esteVida(){ return lungime()<=0; } //returneaza lungimea stivei public int lungime(){ return poz; } public String toString(){ String s="("; if(poz!=0){ for (int i=0; i<poz-1; i++) s+=lista[i]+", "; s+=lista[poz-1]+")"; } else s+=")"; return s; } }

In continuare, vom implementa dinamic o stiv cu ajutorul listelor simplu nlnuite.


public class Stiva{ private Lista l; private Object varf; private int nr; public Stiva(){ l=new Lista(); } public void push(Object x){ if (esteVida()) l.adaugaElement(x); 66

else l.insereazaElement(x, 0); try{ varf=l.prim(); }catch(ListaException e){} nr++; } public Object pop() throws ListaException{ if (esteVida()) throw new ListaException("Stiva este vida"); Object o=varf; try{ varf=l.elementulDeLa(1); }catch(ListaException le){varf=null;} l.stergeElement(l.elementulDeLa(0)); nr--; return o; } public void stergeToateElementele(){ l.stergeToateElementele(); varf=null; nr=0; } //verifica daca stiva este vida public boolean esteVida(){ return lungime()<=0; } //returneaza lungimea stivei public int lungime(){ return nr; } public String toString(){ return l.toString(); }
}

10.1.3 Structura de date coad

O coad este un model de date bazat pe modelul list n care elementele sunt inserate pe la un capt al listei, numit sfrit, i terse pe la cellalt capt al listei numit nceput. Mai precis, o coad este o structur de elemente n care putem insera i sterge elemente dup politica FIFO: first-in, first-out. Dac coada ncepe din captul stng al listei, operaia extrage() aplicat listei (a1, a2,, an) genereaz lista (a2,, an), iar operaia introduce(x) genereaz lista (a1, a2,, an, x).
Operaii asupra unei cozi

introduce(C, x) adaug elementul x la sfritul cozii. extrage(C) extrage elementul de la nceputul cozii. Dac coada este vid, atunci operaia va genera o eroare. stergerea tuturor elementelor din coad, stergeToateElementele(C). lungime(C) returneaza lungimea coad C. esteVida(C) returneaz true dac C nu contine nici un element

Implementarea unei cozi

Vom implementa operaiilor ce pot fi executate asupra unei cozi cu ajutorul unei liste simplu nlnuit.
public class Coada{ private Lista l; 67

private Object inceput, sfarsit; private int nr; public Coada(){ l=new Lista(); } public void introduce(Object x){ l.adaugaElement(x); nr++; try{ if (nr==1) inceput=l.prim(); sfarsit=l.ultim(); }catch(ListaException e){} } public Object extrage() throws ListaException{ if (esteVida()) throw new ListaException("Stiva este vida"); Object o=inceput; inceput=l.elementulDeLa(1); l.stergeElement(l.elementulDeLa(0)); nr--; return o; } public void stergeToateElementele(){ l.stergeToateElementele(); inceput=null; sfarsit=null; nr=0; } //verifica daca stiva este vida public boolean esteVida(){ return lungime()<=0; } //returneaza lungimea stivei public int lungime(){ return nr; } public String toString(){ return l.toString(); } } public class TestStivaSiCoada{ public static void main(String[] args) throws ListaException{ Student[] s=new Student[3]; s[0]=new Student(Ionescu, Ion, Informatica); s[1]=new Student(Popescu, Mircea, Matematica-Informatica); s[2]=new Student(Marinescu, "Viorica", Informatica); Stiva st=new Stiva(); st.push(s[0]); st.push(s[1]); System.out.println(st); try{ Student o=(Student)st.pop(); System.out.println("scoate= "+o); st.push(s[2]); System.out.println(st); 68

st.stergeToateElementele(); System.out.println(st); }catch(ListaException e){System.out.println(e.getMessage());} Coada c=new Coada(); c.introduce(s[0]); c.introduce(s[1]); System.out.println(c); try{ Student o=(Student)c.extrage(); System.out.println("scoate= "+o); c.introduce(s[2]); System.out.println(c); c.stergeToateElementele(); System.out.println(c); }catch(ListaException e){System.out.println(e.getMessage());} } } 10.1.4 Structura de date arbore

Un arbore este format dintr-o mulime de noduri legate prin muchii ce ndeplinesc urmtoarele condiii: - conine un nod special, numit nod rdcin. De aceea, un arbore A se poate defini ca fiind format dintr-un nod rdcin de care este legat o mulime finit de arbori. Acetia sunt numii subarborii lui A, datorit relaiei de subordonare fa de rdcin. orice muchie leag dou noduri distincte. O muchie este indicat prin perechea de noduri pe care le leag. orice nod c diferit de rdcin este legat de un alt nod p al arborelui printr-o muchie. In acest caz, nodul c este printele lui p, iar p este un fiu al lui c. Aadar, orice nod, cu excepia nodului rdcin, are un singur nod printe i poate avea mai muli fii. In cazul n care un nod nu are noduri fii, se numete nod frunz (sau terminal).

un arbore este conectat, n sensul c accesul de la rdcina unui (sub)arbore nevid la oricare al nod presupune parcurgerea unei ci formate din a muchii (a0) pe care se gsesc n noduri (n=a+1). Valoarea n reprezint nivelul pe care se gsete nodul fa de rdcin, al crei nivel este, prin convenie, 1. Aadar, o cale ntr-un arbore este o succesiune de muchii adiacente dou cate dou, n sensul c orice dou muchii succesive din cale au un nod comun. In plus, putem defini nlimea unui arbore ca fiind maximul dintre nivelurile nodurilor frunz. De exemplu, putem caracteriza urmtorul arbore astfel:
n1 n2 n3 n4

n5

n6 n7

rdcina arborelui este n1, are trei subarbori, fiecare cu rdcina n2, n3 i n4, nodul n3 este printe pentru nodurile n5 i n6 i fiu pentru rdcin, nodurile n2, n5, n7 i n4 sunt noduri frunz, (n1, n3),(n3, n6) este calea de la rdcin la nodul n6,
69

- arborele este de nivel 4, - adncimea arborelui este egal cu 4. In continuare, vom lucra numai cu arbori binari, adic cu arbori ai cror noduri au cel mult doi fii (direci). In acest caz, cei doi poteniali subarbori ai unui arbore nevid se numesc subarbore stng i subarbore drept. Similar, cei doi poteniali fii ai unui nod al unui arbore binar se numesc fiu stng, respectiv fiu drept. Implementarea in Java a unui nod al unui arbore binar este dat n continuare:
public class Nod{ private int info; private Nod stang, drept; public Nod(int inf){ info=inf; } public Nod(int inf, Nod l, Nod r){ info=inf; stang=l; drept=r; } public void setInformatie(int info){ this.info=info; } public int getInformatie(){ return info; } public void setNodStang(Nod s){ stang=s; } public Nod getNodStang(){ return stang; } public void setNodDrept(Nod s){ drept=s; } public Nod getNodDrept(){ return drept; } } Operaii asupra aborilor binari

Asupra unui arbore binar putem executa urmtoarele operaii: 1. modificarea informaiei memorat n rdcina arborelui; 2. inserarea unui element n arbore; 3. cutarea unui element n arbore. Operaia va ncepe cu rdcina arborelui i va returna valoarea false dac elementul nu a fost gsit. 4. stergerea unui element din arbore cu returnarea unei valori logice care ia valoarea true dac elementul exist n arbore. 5. tergerea ntregului arbore. 6. afiarea arborelui. Dup cum tim, informaia din nodurile unui arbore va fi afiat n funcie de ordinea n care arborele binar a fost parcurs, ncepnd cu rdcina arborelui: - preordine, adic vizitarea nodului curent si apoi a subarborelui stng, respectiv drept al acestuia, - inordine presupune parcurgerea subarborelui stng al nodului curent, apoi a acestuia din urm i pe urm subarborele drept, - postordine, adic nodul curent este vizitat dup ce au fost parcuri cei doi subarbori.
70

In continuare vom exemplifica implementarea operaiilor de inserare, cautare i tergere a unui element in/dintr-un arbore binar ce ndeplinete urmtoarea proprietate: informaiile nodurilor sunt ordonate astfel nct informaia unui nod oarecare este mai mare dect informaia oricrui nod al subarborelui stng al su i este mai mic dect informaia oricrui nod al subarborelui drept al su. Ordonarea este cea obinuit dac informaiile sunt numerice sau este de tip lexicografic dac avem de-a face cu caractere sau iruri de caractere. Inserarea unui element ntr-un arbore binar de cutare Urmtorul algoritm recursiv descrie paii necesari pentru ca un element x s fie inserat n arbore A: Baza. Dac A este vid, atunci se creaz un nod ce conine elementul x i acesta va fi rdcina arborelui. Altfel, dac un nod conine o informaie egal cu x, atunci x este deja n arbore i operaia se termin. Pas recursiv. Dac A nu este vid i x nu se gsete ca nformaie a unui nod oarecare al arborelui, atunci se insereaz x n subarborele stng al rdcinii dac x este mai mic dect informaia rdcinii sau se insereaz n subarborele drept al rdcinii dac x este mai mare dect informaia coninut n rdcin. Dac unul din subarbori nu exist i ne aflm pe un nivel nou al arborelui, atunci nlimea arborelui este incrementat cu o unitate. Pentru aceasta, avem nevoie s tim nodul printe al nodului curent. Metoda urmtoare implementeaz n Java acest algoritm:
private void insereaza(int element, Nod n, Nod p, boolean nou){ if (esteVid()){ rad=new Nod(element); inaltime=1; nou=false; } else { if(n.getInformatie()==element) return; else if(element<n.getInformatie()) { Nod n1=n.getNodStang(); if (n1!=null) insereaza(element, n1, n, false); else { n.setNodStang(new Nod(element, null, null)); if (p==null || p.getNodDrept()==null) nou=true; } } else{ Nod n1=n.getNodDrept(); if (n1!=null) insereaza(element, n1, n, false); else { n.setNodDrept(new Nod(element, null, null)); if (p==null || p.getNodStang()==null) nou=true; } } if (nou) inaltime++; } }

Cutarea unui element ntr-un arbore binar de cutare Urmtorul algoritm recursiv descrie paii necesari cutrii unui element x n arborele A, ncepnd bineneles cu rdcina acestuia: Baza. Dac A este vid, adic nodul curent (care iniial va fi rdcina) analizat este null atunci x nu se gsete n arbore.
71

Pas recursiv. Dac nu suntem n condiiile bazei, fie y informaia nodului curent. Dac x<y, atunci cutm x numai n subarborele stng al nodului curent. Altfel, l cutm n subarborele drept. Metoda urmtoare implementeaz n Java acest algoritm:
private boolean cauta(int element, Nod n){ if (n==null) return false; else if (n.getInformatie()==element) return true; else if(element<n.getInformatie()) return n.getNodStang()); else return cauta(element, n.getNodDrept()); }

cauta(element,

Stergerea unui element ntr-un arbore binar de cutare Urmtorul algoritm descrie paii necesari tergerii unui element x n arborele A: 1. Dac A nu contine nici un nod ce conine x, atunci algoritmul se termin cu valoarea false. 2. Altfel, ne aflm n unul din urmtoarele cazuri: dac nodul curent este nod frunz, atunci acesta se terge i referina nodului printe la nodul respectiv este setat la null. De aceea, trebuie s tim ce tip de fiu era pentru nodul printe: stng sau drept. dac nodul curent are un singur nod fiu, atunci primul este nlocuit cu al doilea nod. dac nodul curent este un nod interior, atunci se caut nodul y ce conine cea mai mic informaie din subarborele drept al nodului curent, informaia mai mare dect x. Apoi nodul y se terge din arbore, dup ce informaia coninut de el este memorat n nodul curent.

Metoda ce determin nodul cu informaia cea mai mic, dar mai mare dect x este:
int stergeMinim(Nod n, Nod p, String poz){ int min; if(n.getNodStang()==null){ min=n.getInformatie(); n=n.getNodDrept(); if (poz=="s") p.setNodStang(n); else p.setNodDrept(n); return min; } else return stergeMinim(n.getNodStang(), n, "s"); }

iar metoda urmtoare implementeaz ntregul algoritm descris mai sus:


private boolean sterge(int element, Nod n, Nod p, String poz){ if(n!=null){ if(element<n.getInformatie()) return sterge(element, n.getNodStang(), n, "s"); else if(element>n.getInformatie()) return sterge(element,n.getNodDrept(),n,"d"); else //nodul este un nod frunza if(n.getNodStang()==null && n.getNodDrept()==null) { if (poz=="s") p.setNodStang(null); else p.setNodDrept(null); if (p.getNodStang()==null && p.getNodDrept()==null) inaltime--; } else if(n.getNodStang()==null) n=n.getNodDrept(); else if(n.getNodDrept()==null) n=n.getNodStang(); else //aici ambele noduri fii nu sunt null 72

n.setInformatie(stergeMinim(n.getNodDrept(),n, "d")); return true; } return false; } Afiarea informaiilor unui arbore binar de cutare

Urmtoarele metode recursive arat diferite modaliti de a afia informaiile unui arbore binar de cutare prin parcurgerea acestuia din urm n preordine, inordine sau postordine.
public void afiseaza(String forma){ if (forma.equals("preordine")) preordine(rad); else if (forma.equals("inordine")) inordine(rad); else if (forma.equals("postordine")) postordine(rad); else afiseaza(rad, 0); } private void preordine(Nod n){ if (n==null) return; System.out.println(n.getInformatie()); preordine(n.getNodStang()); preordine(n.getNodDrept()); } private void inordine(Nod n){ if (n==null) return; inordine(n.getNodStang()); System.out.println(n.getInformatie()); inordine(n.getNodDrept()); } private void postordine(Nod n){ if (n==null) return; postordine(n.getNodStang()); postordine(n.getNodDrept()); System.out.println(n.getInformatie()); } }

Celelalte operaii nu necesit explicaii, iar metodele asociate furnizeaz interfaa clasei Arbore:
public class Arbore{ private Nod rad; private int inaltime; public Arbore(){} public Arbore(int inf, Nod st, Nod dr){ rad=new Nod(inf, st, dr); inaltime=1; } public void modificaInformatie(int info){ rad.setInformatie(info); } public boolean esteVid(){ return rad==null; } public void stergeArbore(){ rad=null; } public Nod getRadacina(){ return rad; 73

} public int getInaltime(){ return inaltime; } public void insereaza(int element){ insereaza(element, rad, null, false); } public boolean cauta(int element){ return cauta(element, rad); } public boolean sterge(int element){ return sterge(element, rad, null, null); } public void afiseaza(String forma){ if (forma.equals("preordine")) preordine(rad); else if (forma.equals("inordine")) inordine(rad); else if (forma.equals("postordine")) postordine(rad); else afiseaza(rad, 0); } }

COLECII N JAVA Java furnizeaz o structur de clase i interfee numit Collections Framework specializat n memorarea i elaborarea coleciilor de obiecte. Collections Framework furnizeaz un API convenabil oricror tipuri de date abstracte utilizate frecvent n informatoc: relaii, mulimi, liste, arbori, array, etc. Datorit orientrii spre obiecte, clasele din Collections Framework ncapsuleaz att structura de date ct i algoritmii asociai acestor abstractizri.
10.1.5 Teoria de baz a coleciilor

La baza teoriei coleciilor st conceptul matematic de mulime, chiar dac colecia a fost definit avnd o semnificaie mai general, de grup de elemente, fr nici o legtur ntre ele. n schimb, n Collections Framework o mulime este o colecie de elemente unice, adic o colecie fr elemente duplicat. Exemple de mulimi sunt numeroase. Iat unele: - mulimea literelor mari de la 'A' la 'Z' - mulimea numerelor nenegative: {0, 1, 2 ...} - mulimea cuvintelor cheie din Java: {'import', 'class', 'public', 'protected'...} - mulimea angajailor unei ntreprinderi - mulimea obiectelor Component dintr-un Container - mulimea vid {} Un caz particular de mulime este relaia funcional sau maparea (n englez, mapping). Este o mulime de legturi n care fiecare legtur reprezint o conexiune de la un element la un altul. Exemple de mapri sunt: - maparea adreselor IP la nume dintr-un domeniu de nume DNS, - dicionar (maparea cuvintelor la nelesurile lor), - conversia unui sistem de numeraie la un alt sistem de numeraie (sistemul arabic la cel roman).

74

O mapare (Figura 10-1) poate servi la navigarea de la un element al unei legturi la un alt element. Pentru mapare, biblioteca Java conine clase ce furnizeaz rapid obiectele Cheie1 Cheie2 Cheie3 Cheie4 Cheie5 legatura1 legatura2 legatura3 legatura4 legatura5 Valoare1 Valoare2 Valoare3 Valoare4 Valoare5

cutate indicnd numai cheia asociat.


Figura 10-1. Maparea ntre chei i valori 10.1.6 Collections Framework

Collections Framework este furnizat n pachetul java.util i conine interfee care se gsesc n relaii de generalizare/specializare ca cea prezentat n Figura 10-2. Unele interfee sunt implementate de clase Java ce aparin aceluiai pachet java.util. Aceste
Collection Map

Set

List

SortedMap

SortedSet

clase reprezint colecii de obiecte sau relaii ntre obiecte i sunt prezentate n Tabelul 10-2.
Figura 10-2. Interfete ale Collections Framework
Interfaa Set SortedSet List Map SortedMap HashMap TreeMap ArrayList HashSet TreeSet LinkedList Vector Stack Hashtable Properties Implementare Precedeni istorici

Tabelul 10-2. Interfee de colecii i implementrile lor

75

Schema complet a lui Collections Framework este prezentat n Figura 10-3. Schema prezint n diferite nuane de gri interfeele, clasele abstracte i clasele concrete din Collections Framework i relaiile dintre ele. n plus, sunt marcate clasele care provin din versiuni mai vechi cum ar fi Vector, Stack, Hashtable i Properties. Collections Framework mai conine i alte interfee cum ar fi Iterator, ListIterator, Comparator i Comparable care permit navigarea coleciilor i compararea elementelor dintr-o colecie.
<interface> Iterator produce <interface> Collection produce <interface> Map <abstract> Dictionary

<interface> ListIterator

<interface> List

<interface> Set

<abstract> AbstractMap

<interface> SortedMap

Hashtable

<interface> Comparator

<abstract> AbstractCollection

HashMap

TreeMap

Properties

<interface> Comparable

<abstract> AbstractList

<abstract> AbstractSet

<interface> SortedSet Legenda Hashtable Clase din versiunile 1.0, 1.1 Interfee fundamentale Clase concrete utile

HashSet

TreeSet
<interface> Map

Vector

ArrayList

<abstract> AbstractSequentialList

HashMap

Stack LinkedList

Figura 10-3. Collections Framework Interfaa Collection

java.util.Collection este o interfa standard ce reprezint un grup de elemente, numite elementele coleciei. Biblioteca Java nu conine o implementare direct a interfeei Collection. Aceast interfa este utilizat ca numitor comun al altor interfee, pentru a permite transferul coleciilor de la un tip de colecie la un alt tip i elaborarea lui cu generalitate maxim. Operaiile interfeei Collection sunt prezentate n tabelul urmtor.

76

Declaraie metod Operaii de baz boolean add(Object o)

Semnificaie Verific dac colecia conine elementul o. n caz pozitiv, nu mai adaug elementul o i ntoarce false. n caz negativ, adaug elementul al colecie i returneaz true. Dac elementul o se gsete in colecie, este eliminat i meoda returneaz true. Altfel, metoda returneaz false. Returneaz true dac colecia conine elementul o ntoarce un obiect de tip Iterator care se poate utiliza pentru navigarea coleciei. ntoarce numrul de elemente ale coleciei Returneaz true dac colecia nu are elemente. Adaug toate elementele coleciei c. Dac operaia are loc cu succes, metoda ntoarce true. Elimin toate elementele coleciei c. Dac operaia are loc cu succes, metoda ntoarce true. Elimin toate elementele care nu fac parte din colecia transmis ca argument. Golete colecia Returneaz un array ce conine toate elementele coleciei. Returneaz un array ce conine toate elementele coleciei. Array-ul returnat este de aceli tip cu array-ul transmis ca parametru.

boolean remove(Object o) boolean contains(Object o) Iterator iterator() int size() boolean isEmpty() Operaii pe grupuri de obiecte boolean addAll(Collection c) boolean removeAll(Collection c) boolean retainAll(Collection c) void clear() Operaii cu array Object[] toArray() Object[] toArray( Object [])

Iterfaa Iterator

Iterator este o interfa implementat de un obiect obinut prin invocarea metodei iterator() a unui obiect din clasa Collection. Interfaa conine trei metode:
boolean hasNext()//verific dac colecia mai mai are elemente de parcurs Object next() //returneaz urmtorul element al coleciei void remove() //poate fi apelat numai o singur pentru fiecare obiect //obinut cu metoda next()

Iteratorul ne permite s navigm ntr-o colecie pn la terminarea elementelor coninute. n timpul navigrii putem, de exemplu, s filtrm o colecie, adic s eliminm din colecie acele elemente care nu ndeplinesc o anumit condiie. Presupunem c avem o metod verificaEliminare(Object o) care ntoarce true dac obiectul transmis ca parametru va fi efectiv eliminat. Folosind interfaa Iterator, filtrul va fi implementat astfel:
Collection colectie = ...; Iterator iterator = colectie.iterator(); while (iterator.hasNext()) { Object element = iterator.next(); if (verificaEliminare(element)) { iterator.remove(); } } Interfaa Set

Collections Framework include o interfa Set i numeroase clase concrete care implementeaz Set. Interfaa Set extinde interfaa Collection i mpiedic crearea de elemente duplicat n colecie. Nu introduce alte metode diferite de cele din Collection. Verificarea claselor de implementare se
77

bazeaz pe metoda equals() a obiectului care este adugat la colecie. Interfaa Set este implementat de dou clase concrete Java: java.util.HashSet i java.util.TreeSet. Obiectele din clasa HashSet sunt utilizate pentru memorarea coleciilor fr duplicate. Obiectele ce vor fi adugate la un HashSet trebuie s implementeze metoda hashCode() astfel nct obiectele vor fi egal distribuite n mod uniform cu ajutorul codurilor hash. Majoritatea claselor standard redefinesc implementarea predefinit de clasa Object. Clasa TreeSet este utilizat cnd vrem s lucrm cu elementele unei colecii ordonate. Obiectele care se adaug la un TreeSet trebuie s fie ordonabile, adic s poat fi comparate ntre ele dup o relaie de ordine total.
Clasa HashSet

Clasa implementeaz interfaa Set i este construit intern de un hash table. Figura 10-4 prezint schematic ideea care st la baza unei structuri de de date de tip hash table. n centrul structurii se gsete un array ale crui elemente conin indicatori la lista nlnuit ale crei noduri indic elemente ale coleciei. Indexul tabelului variaz ntre 0 i un k-1. Cutarea ntr-o astfel de structur ncepe cu calculul indicelui hash al obiectului care este cutat. Acest cod este un numr ntreg calculat dup un algoritm particular care implic toate cmpurile obiectului vzute ca nite combinaii de bii. Odat gsit codul, el va fi folosit ca indice al array-ului central. Elementul identificat poate conine null, i atunci obiectul cutat nu se gsete n colecie i, adc este necesar, se poate aduga, sau este vorba de un indicator la o list bucket n care obiectul va fi cutat secvenial. Dac nu este gsit n list, nseamn c nu se gsete n colecie i poate fi adugat la lista de bucket. ntr-o tabel hash nu se poate prevede care va fi ordinea de navigare ntre elemente, dar aceast ordine rmne ntotdeauna aceeai. Clasa permite utilizarea unui element null n colecie.

Figura 10-4. Structura unui hash table

Constructorii clasei HashSet sunt:


HashSet() //creaza o colectie HashSet vida HashSet (Collection c) //creaza o colectie de tip HashSet ce contine //elementele lui c HashSet(int capacitate)//creaza o colectie HashSet de capacitate initiala //transmisa ca argument HashSet(int capacitate, int incr)//creaza o colectie HashSet de capacitate //initiala i factor de ncrcare transmise ca argumente

Exemplu. Vom scrie un program care preia cuvinte din linia de comand i vizualizeaz cuvintele duplicat, numrul de cuvinte distincte, avnd ntr-o list cuvintele unice:
import java.util.*; public class Duplicate { 78

public static void main(String args[]) { Set s = new HashSet(); for (int i=0; i<args.length; i++) if (!s.add(args[i])) System.out.println("Duplicat: "+args[i]); System.out.println(s.size()+" cuvinte distincte identificate: "+s); } }

Exemplu. Presupunem c vrem s tim care din cuvintele din linia de comand au aprut o singur dat i care au aprut de mai multe ori, dar le afim numai o singur dat. Putem utiliza dou obiecte din clasa Set. ntr-un obiect memorm cuvintele liniei de comand i n al doilea obiect memorm numai cuvintele duplicat. Cuvintele care apar numai o singur dat se deduc din diferena celor dou mulimi.
import java.util.*; public class Duplicate1 { public static void main(String args[]) { Set unice = new HashSet(); Set dupl = new HashSet(); for (int i=0; i<args.length; i++) if (!unice.add(args[i])) dupl.add(args[i]); unice.removeAll(dupl); // Diferenta dintre multimi System.out.println("Cuvinte unice: " + unice); System.out.println("Cuvinte duplicat: " + dupl); } } Clasa TreeSet

Clasa implementeaz SortedSet care este o subinterfa a lui Set i garanteaz c mulimea este ordonat n ordine cresctoare. Ordonarea este cea natural ntre elemente (care trebuie s implementeze Comparable) sau va fi specificat prin intermediul unui obiect comparator (face parte dintr-o interfa Comparator) la crearea lui TreeSet. Constructorii clasei TreeSet sunt:
TreeSet() TreeSet (Collection c) TreeSet(Comparator comp) TreeSet(SortedSet ss)

Al doilea constructor va fi utilizat n urmtorul program n care transmit elementele unei colecii HashSet unui TreeSet:
import java.util.*; public class ExempluSet { public static void main(String args[]) { Set set = new HashSet(); set.add("Andreea"); set.add("Maria"); set.add("George"); set.add("Maria"); set.add("Clara"); System.out.println(set); Set sortedSet = new TreeSet(set); System.out.println(sortedSet); } }

Un alt exemplu de utilizare a clasei TreeSet este prezentat n continuare i ilustreaz utilizarea elementelor ce pot fi comparate (Comparable) i pot fi pstrate ordonate n
79

interiorul unui TreeSet. Fiind i un Set, un TreeSet poate fi configurat la creare pentru accesarea obiectelor care respect o anumit relaie ntre ele:
import java.util.*; class ComparatorArticole implements Comparator { public int compare(Object a, Object b){ Articol articolA = (Articol)a; Articol articolB = (Articol)b; String descrA=articolA.getDescriere(); String descrB=articolB.getDescriere(); return descrA.compareTo(descrB); } } class Articol implements Comparable{ private String descriere; private int numarParte; public Articol(String oDescriere,int unNumarParte){ descriere = oDescriere; numarParte = unNumarParte; } public String getDescriere(){ return descriere; } public String toString(){ return "[descriere=" + descriere + ", numarParte=" + numarParte + "]"; } public boolean equals(Object alt){ if (alt instanceof Articol){ Articol altArticol = (Articol)alt; return descriere.equals(altArticol.descriere) && numarParte == altArticol.numarParte; } else return false; } public int hashCode() { return 13 * descriere.hashCode() + 17 * numarParte; } public int compareTo(Object alt){ Articol altArticol = (Articol)alt; return numarParte - altArticol.numarParte; } } public class TestTreeSet { public static void main(String[] args) { SortedSet parti = new TreeSet(); parti.add(new Articol("Monitor", 1234)); parti.add(new Articol("Imprimanta", 4562)); parti.add(new Articol("Modem", 9912)); System.out.println(parti); SortedSet ordoneazaDupaDescriere = new TreeSet(new ComparatorArticole()); ordoneazaDupaDescriere.addAll(parti); System.out.println(ordoneazaDupaDescriere); } } 80

Interfaa List

List este o interfa care reprezint o colecie ordonat (numit i secven). Prin intermediul acestei interfee, utilizatorul are un control exact al locului n care este inserat fiecare element. Utilizatorul poate accesa elementele prin intermediul iteratorilor i a indicilor ntregi care reprezint poziia n list. n acest mod cutm mai uor n lista. Listele accept elemente duplicat (adic, elemente e1 i e2 care verific e1.equals(e2)) i accept i elemente null. n afara declaraiilor de metode din interfaa Collection, List are urmtoarele metode:
Declaraie metod Acces dup poziie Semnificaie ntoarce obiectul de la indicele transmis ca parametru Insereaz obiectul o la poziia indice Elimin obiectul de la poziia indice nlocuiete obiectul de la poziia indice cu obiectul o Insereaz ncepnd cu poziia indice elementele colectiei c Returneaz poziia obiectului o din list. Dac nu-l gsete, returneaz -1. Returneaz poziia ultimei apariii a obiectului o din list. Dac nu-l gsete, returneaz -1. Returneaz un obiect de tip ListIterator al lui List Returneaz un obiect de tip ListIterator al lui List. Cei doi iteratori sunt folosii de LinkedList. Creaz o sublist format din elementele listei ntre cei doi indici transmii ca parametri.

Object get(int indice) boolean add(int indice, Object o) Object remove(int indice) void set(int indice, Object o) boolean addAll(int indice, Collection c)
Cutarea unui obiect

int indexOf(Object o) int lastIndexOf(Object o)


Iterare

ListIterator listIterator() ListIterator listIterator(int indice)


Operaie global

List subList(int in, int sf)

Ca ntotdeauna cnd este vorba de o interfa, putem implementa n mod polimorfic algoritmi valizi pentru toate obiectele claselor care implementeaz interfaa. De exemplu, pentru a schimba locul ntre dou elemente ale unei liste poate fi utilizat urmtoarea metod:
private void schimba(List a, int i, int j) { Object t = a.get(i); a.set(i, a.get(j)); a.set(j, t); }

Vom utiliza metoda schimba() pentru a permuta elementele unei liste. Algoritmul polimorfic utilizat parcurge lista i genereaz numere aleatoare pentru a identifica locuri noi din care putem lua elementul cu care nlocuim elementul curent:
public void permuta(List list, Random rnd) { for (int i=list.size(); i>1; i--) schimba(list, i-1, rnd.nextInt(i)); }

O variabil de tip List poate conine referine la obiecte ArrayList sau LinkedList care sunt implementri ale interfeei. Aceti algoritmi sunt independeni de clasa utilizat pentru implementarea listei.
Interfaa ListIterator 81

Interfaa List furnizeaz un iterator mai bogat: ListIterator, care ne permite s traversm lista n ambele direcii, s o modificm n timpul traversrii i s obinem poziia curent a iteratorului. Interfaa ListIterator este prezentat n continuare:
interface ListIterator extends Iterator { void add(Object elem); // adaug un element n poziia curent Object previous(); //poziioneaz cursorul i returneaz elementul //precendent boolean hasPrevious(); // verifica dac exist un element precedent void set(Object elem); // suprascrie elementul curent cu elementul transmis // ca parametru int nextIndex(); // returneaz indicele elementului succesiv int previousIndex(); // returneaz indicele elementului succesiv }

Spre deosebire de metoda Collection.add, metoda ListIterator.add nu returneaz o valoarea de tip boolean. Metoda nextIndex() returneaz ntotdeauna elementul care va fi restituit de un apel succesiv al lui next(), n schimb previousIndex() returneaz poziia elementului ntors la un apel al lui previous(). n consecin, nextIndex() == previous()+1. Apoi, un alt fapt: la primul apel al lui previous() dup o secevn de apeluri next() ntoarce acelai element al ultimului apel al lui next. n mod similar, primul apel al lui next() dup o serie de apeluri ale lui previous() returneaz acelai element al utlimului apel al lui previous() . Exemplu urmtor este cel al unei metode statice care implementeaz un algoritm polimorfic care nlocuiete ntr-o list oarecare toate apariiile unui obiect val cu un obiect nou:
public static void replace(List l, Object val, Object nou) { for (ListIterator i = l.listIterator(); i.hasNext(); ) if (val==null ? i.next()==null : val.equals(i.next())) i.set(nou); }

In schimb, metoda urmtoare implementeaz un algoritm polimorfic care returneaz toate apariiile valorii val specificat ca parametru, cu o secven de valori noi coninute ntr-o list:
public static void replace(List l, Object val, List valoriNoi) { for (ListIterator i = l.listIterator(); i.hasNext(); ) { if (val==null ? i.next()==null : val.equals(i.next())) { i.remove(); for (Iterator j = nuoviValori.iterator(); j.hasNext(); i.add(j.next()); } } } Clasa ArrayList

ArrayList este o clas concret care implementeaz interfaa List i se sprijin pe un array fr limite de cretere. Modeleaz o list cu elemente enumerate, deoarece are un acces obinuit, direct, relativ rapid. La metodele interfeei List, clasa ArrayList adaug urmtoarele metode:
ArrayList(Collection)//construiete un ArrayList dintr-un Collection Object clone() //cloneaz obiectul ArrayList void ensureCapacity(int) //garanteaz un numr minim pentru list void trimToSize() //Elimin spaiile libere din array

82

n continuare, prezentm un program care extrage virtual dintr-un pachet de cri reprezentat ca o list - n cri pentru un juctor i le furnizeaz ntotdeauna ca o list:
public static List furnizeazCarte(List pachet, int n) { int dimPachet = pachet.size(); List listaNoua = pachet.subList(dimPachet-n, dimPachet); List cartiJucator = new ArrayList(listaNoua); listaNoua.clear(); return cartiJucator; } Clasa LinkedList

LinkedList este o clas concret care furnizeaz un acces secvenial optim cu operaii economice de eliminare i inserare n interiorul listei. Are un acces aleator relativ lent (dac accesul aleator este frecvent trebuie s fie utilizat ArrayList). Cu un obiect LinkedList putem implementa cod deoarece garanteaz o politic FIFO n elaborarea listei. LinkedList aadaug urmtoarele metode la cele declarate de interfaa List :
void addFirst( Object o) //adaug o la nceputul listei void addLast(Object o) //adaug o la sfritul listei Object getFirst( ) //furnizeaz primul element din list Object getLast( ) //furnizeaz ultimul element al listei Object removeFirst( ) //elimin primul element al listei Object removeLast( ) //elimin ultimul element al listei

Urmtorul program ilustreaz ilustreaz trasferul uor de la o implementare a unei liste al o alta i modul diferit n care cele dou tipologii de liste i gestioneaz elementele:
import java.util.*; public class ExempluLista { public static void main(String[] args) { List lista = new ArrayList(); lista.add("Andreea"); lista.add("Eliza"); lista.add("George"); lista.add("Eliza"); lista.add("Clara"); System.out.println(lista); System.out.println("2: " + lista.get(2)); System.out.println("0: " + lista.get(0)); LinkedList coada = new LinkedList(); coada.addFirst("Andreea"); coada.addFirst("Eliza"); coada.addFirst("George"); coada.addFirst("Eliza"); coada.addFirst("Clara"); System.out.println(coada); coada.removeLast(); coada.removeLast(); System.out.println(coada); } }

Rezultat:
[Andreea, Eliza, George, Eliza, Clara] 2: George 0: Andreea [Clara, Eliza, George, Eliza, Andreea] [Clara, Eliza, George] 83

Cum utilizm interfaa Collection

1. tim c utilizarea interfeelor este obligatorie atunci cnd obiectele client nu trebuie s tie proveniena obiectului (clasa care l-a generat) i n general orice detalii de implementare care su fost utilizate. n acest mod, pentru un client, dac dou obiecte a i b implementeaz aceiai interfa, se poate utiliza obiectul b n locul obiectului a, fr s necesite nici o modificare din parte clientului. Este de ajuns s utilizeze o variabil interfa n care s memoreze referina la unul din cele dou obiecte (Figura 10-5). n consecin, nu conteaz ce obiect Java este utilizat pentru a reprezenta o colecie i dac n mod succesiv, acest obiect este nlocuit cu un altul care implementeaz aceeai interfa. 2. Implementrile coleciilor (ArrayList, LinkedList, HashSet, TreeSet) au toate un constructor cu un parametru de tip Collection. Acest parametru este un obiect dintr-o clas care implementeaz interfaa Collection i care va fi utilizat pentru a iniializa noua colecie. n acest mod, noua colecie va fi iniializat cu elementele coleciei utilizat ca parametru, dar va avea un comportament diferit. n continuare, va fi prezentat un scenariu posibil de utilizare a varaibilelor de tip Collection: 1. Declarm o variabil colectie de tip Collection (poate fi un List sau un Set):
Collection colectie;

2. colectie memoreaz o referin la un obiect care implementeaz o colecie, precum un LinkedList, ArrayList, HashSet sau TreeSet:
colectie = new HashSet();

3. Se adaug obiecte la colectie cu metoda add():


colectie.add(o1); colectie.add(o2); . . .

4. Se creaz o lista de tip List ce se bazeaz pe un array, construit pe baza lui colecie:
List lista = new ArrayList(colectie); 3. lista conine elementele din colecie memorate n HashSet, schimbnd numai

punctul de vedere. ntr-un List, elementele unice ale lui HashSet pot fi cutate n ordine i poate accepta duplicate. Variabil de tip Collection a implementare a lui Collection b- o alt implementare a lui Collection

b
Client

a
nlocuirea unei implementri a lui Collection cu o alta
Figura 10-5. Utilizarea variabilelor interfa

Interfaa Map

Map este o interfa care pstreaz o asociere chei-valoare i care permite cutri bazate pe chei.
Declaraie metod Operaii de baz Semnificaie ntoarce obiectul cu cheia transmis ca parametru Insereaz o legtur cheie-valoare Elimin legtura indicat de cheie Verific existena cheii cheie n Map

Object get(Object cheie) void put(Object cheie, Object o) Object remove(Object cheie) Boolean containsKey(Object cheie)

84

Declaraie metod

Semnificaie Verific existena valorii o n Map Returneaz numrul de legturi Verific dac mulimea legturilor este vid sau nu Adaug legturile gsite n m Golete un Map Furnizeaz Set-ul tuturor legturilor cheie-valoare Furnizeaza un Set compus din chei Furnizeaz o colecie a tuturor valorilor din Map

Boolean containsValue(Object o) Int size() Boolean isEmpty()


Operaii globale

Boolean putAll(Map m) Void clear()


Vederi ca colecii

Set entrySet() Set keySet() Collection values()

Vederile (views) ale unui Map ne permit s utilizm interfetele Collection (pentru valori) sau Set (pentru chei) pentru eleborarea ntregului Map:
for (Iterator i=map.keySet().iterator(); i.hasNext(); ) { Object cheie = i.next(); System.out.println(cheie + ": " + map.get(cheie)); }

Map.Entry este o interfa static intern a lui Map care reprezint toate legturile cheievaloare din Map. Map.Entry are urmtoarele trei metode:
Object getKey() Object getValue() Object setValue(Object val)

Fiecare element din Set-ul de legturi returnat de metoda entrySet()este vzut ca un element de tip Map.Entry. De aceea, putem parcurge o astfel de mulime i s afim fie cheia, fie valoarea fiecrei legturi. Acest lucru este realizat de urmtoarea secven de cod:
Map m=//crearea unui obiect al unei clase ce implementeaz interfaa Map for (Iterator i=m.entrySet().iterator(); i.hasNext(); ) { Map.Entry e = (Map.Entry) i.next(); System.out.println(e.getKey() + ": " + e.getValue()); }

Interfaa Map are dou implementri principale: HashMap i TreeMap i una motenit din prima versiune de Java: Hashtable.
Clasa HashMap

Urmtorul exemplu verific numerele aleatoare furnizate de metoda Math.random().


import java.util.*; class Counter { //Obiectele acestei clase vor fi folosite ca numrtori int i = 1; public String toString() { return Integer.toString(i); } } public class FreqHashMap { public static void main(String[] args) { HashMap ht = new HashMap(); for(int i = 0; i < 10000; i++) { Integer r = new Integer((int)(Math.random()*20)); //Produce un numr ntre //0 i 19 inclusiv 85

if(ht.containsKey(r)) ((Counter)ht.get(r)).i++; else ht.put(r, new Counter()); } System.out.println(ht); } } Clasa TreeMap

Clasa TreeMap furnizeaz o implementare a interfeei Map n care colecia de legturi chei-valoare este ordonat dup chei, implementnd i interfaa SortedMap. Implicit, ordonarea este cresctoare (conform interfeei Comparable), dar criteriul de comparare poate fi specificat prin constructor:
TreeMap (Comparator c)

Ali constructori:
TreeMap () TreeMap (Map m) TreeMap (SortedMap m)

Exemplu. Urmtorul program ilustreaz diferenele dintre HashMap i TreeMap:


import java.util.*; public class FreqTreeMap { public static void main(String args[]) { Map map=new HashMap(); Integer unu=new Integer(1); for (int i=0, n=args.length; i<n; i++) { String cheie=args[i]; Integer frecventa=(Integer)map.get(cheie); if (frecventa==null) frecventa = unu; else { int valoare = frecventa.intValue(); frecventa = new Integer(valoare + 1); } map.put(cheie, frecventa); } System.out.println(map.size()+" cuvinte distincte gasite:"); System.out.println(map); Map mapSortat = new TreeMap(map); System.out.println(mapSortat); } }

Clasa Properties Furnizeaz o colecie persistent de legturi chei-valori in care cheile i valorile sunt String-uri. Din acest motiv, valorile se numesc proprieti. O legtur cheie-proprietate este adugat la un Properties cu metoda Object setProperty(String key, String value) i se poate obine cu metoda overloaded getProperty():
String getProperty(String cheie) String getProperty(String cheie, String proprietateImplicita)

Persistena coleciei permite memorarea i ncrcarea pe i de pe suport persistent (sistem de fiiere). n acest sens, clasa Properties furnizeaz urmtoarele metode instan:
public public public public void void void void store(OutputStream out, String header) list(PrintStream out) list(PrintWriter out) load(InputStream in)

De exemplu, memorarea ntr-un fiier a coninutului unui obiect Properties se realizeaz prin urmtoarea secven de cod:
86

Properties p=new Properties(); p.setProperty("1", "Ioana"); p.setProperty("4", "Maria"); try{ p.store(new FileOutputStream("proprietati.txt"), " Colectie de proprietati"); }catch(IOException e){System.out.println(e.getMessage());}

Ieire: # Colectie de proprietati #Tue Jan 04 10:03:53 EET 2005 4=Maria 1=Ioana Colecia de legturi i proprieti memorat ntr-un obiect Properties poate fi afiat i pe ecran prin apelarea metodei list, astfel: p.list(System.out);, unde p este variabila referin din exemplul anterior. Exemplu.
import java.util.*; public class Catalog extends TreeSet{ private static Catalog c; private OperatiiSpecificatiiProdus osp; private Catalog(){osp=new OperatiiSpecificatiiProdus(); public static Catalog getInstanta(){ if(c==null) c=new Catalog(); return c; } public void add(SpecificatieProdus sp){super.add(sp);} public SpecificatieProdus getProdus(String nume){ Iterator it=iterator(); SpecificatieProdus sp=null; while(it.hasNext()){ sp=(SpecificatieProdus)it.next(); if(sp.getDenumire().equals(nume)) return sp; } sp=(SpecificatieProdus)osp.citesteObiect(nume); if (sp!=null) add(sp); return sp; } public void descarca(){ Iterator it=iterator(); while(it.hasNext()) osp.scrieObiect(it.next()); } }

} public class TestCatalog{ public static void main(String[] args){ Catalog c=Catalog.getInstanta(); c.add(new SpecificatieProdus("Imprimanta", 250)); c.add(new SpecificatieProdus("Calculator", 1300)); SpecificatieProdus sp=c.getProdus("miere"); System.out.println(sp); sp=c.getProdus("Imprimanta"); System.out.println(sp); } } import java.util.*;

87

public class Vanzare extends ArrayList{ private Client c; public static int tva=20; private double total; public Vanzare(Client c){this.c=c;} public Client getClient(){return c;} public void addProdus(ElementVanzare ev){super.add(ev);} public double calculeazaTotal(){ ListIterator li=listIterator(); ElementVanzare ev; while(li.hasNext()) { ev=(ElementVanzare)li.next(); total+=ev.calculeazaCost(); } Calendar cl=Calendar.getInstance(); if(cl.get(Calendar.DAY_OF_WEEK)>=2&&cl.get(Calendar.DAY_OF_WEEK)<=6)total=5*total/100.0; return total+calculeazaTVA(); } public ArrayList getProduse(){return this; }

public double calculeazaTVA(){return total*tva/100.0; } } import java.util.*;import java.text.*; public class Factura{ private private private private private private static int id=1; int nrFactura; Calendar data; Vanzare v; Client c; ArrayList articole;

} public String formatare(String sir, int latime) { String temp=sir; for (int i=latime-sir.length(); i>0; --i) temp += " "; return temp; } public String toString(){ String sir="Factura: "+nrFactura+"\r\n"; sir+="Data emiterii: "+ DateFormat.getDateInstance(DateFormat.LONG).format(data.getTime())+"\r\n" sir+="-----------------------------------------------------------------------\r\n\r\n"; sir+="Cumparator: "+c.getNume()+" "+c.getPrenume()+"\r\n"; sir+="Adresa: "+c.getAdresa()+"\r\n"; sir+="-----------------------------------------------------------------------\r\n\r\n"; sir+=formatare("Denumire", 15)+ formatare("Pret unitar", 15)+formatare("Cantitate", 20)+formatare("Pret/articol", 25)+"\r\n"; Iterator it=articole.iterator(); ElementVanzare el; double t=v.calculeazaTotal(); while(it.hasNext()){

public Factura(Vanzare v){ nrFactura=id++; data=Calendar.getInstance(); this.v=v; c=v.getClient(); articole=v.getProduse();

88

el=(ElementVanzare)it.next(); sir+=formatare(""+el.getProdus().getDenumire(), 15)+formatare(""+el.getProdus().getPret(), 15)+formatare(""+el.getCantitate(), 20)+formatare(""+el.calculeazaCost(), 25)+"\r\n";} sir+="-----------------------------------------------------------------------\r\n\r\n"; sir+="TOTAL\t\t"+t+" lei \r\n"; sir+="Din care TVA 20%\t"+v.calculeazaTVA()+" lei \r\n"; sir+="\r\n\r\nTOTAL GENERAL\t"+t+" lei \r\n"; return sir; } public class TestVanzare{ public static void main(String[] args){ Vanzare v=new Vanzare(new Client("Ionescu", "Pop", "aleea stejarilor")); v.addProdus(new ElementVanzare(new SpecificatieProdus("Calculator", 123), 6)); Factura f=new Factura(v); System.out.println(f); }}

89

11. APPLET
Browser program cu urmatoarele functiuni:

vizualizeaz resursele codificate n HTML. Suport pentru orice mecanisme de scripting. Context pentru executarea applet-urilor Java. Suport plug-ins. Cere resurse de la server-ele din reea. Utilizeaz protocolul HTTP. Identific resursele utiliznd adrese unice - URI (Uniform Resource Identifier) sau URL.

Pagini Web

Paginile Web sunt resurse Web care au o adres URL (Uniform Resource Locator). Pagin Web = Document de text cu extensia .html sau .htm al crui coninut va fi citit i interpretat de un browser. Documentul poate fi scris cu word processor oarecare, este de ajuns s fie salvat n format text cu extensia .html sau .htm. HTML = Limbaj de comenzi cu care se scriu paginile Web. Utilizeaz tag-uri (comenzi ntre < i >) care au un neles bine precizat pentru browser.
Un fiier HTML simplu

Un tag poate avea modificatori. Modificatorii sunt atribute, de obicei perechi nume=valoare: <BODY BGCOLOR=yellow>
<HTML> <HEAD> <TITLE>Arhitectura Internet</TITLE> </HEAD>

Structura unei pagini Web: Header + Corp


<HTML> <HEAD> Header </HEAD> <BODY> Corp </BODY>

Structura header-ului:
<HEAD> <TITLE>text </TITLE> </HEAD>

Structura corpului:
<BODY TEXT= LINK= ALINK= VLINK= BACKGROUND= > tag-uri +text </BODY>

</HTML> <BODY BACKGROUND="" BGCOLOR="#ffffff" VLINK="#800080" ALINK="#ff0000"> <P>Bine ati venit n site-ul nostru!</P> </BODY> </HTML>

TEXT="#000000"

LINK="#0000ff"

Tag-uri de formatare a textelor

Titluri de seciune: <H1>text</H1>, <H2>text</H2>,. . ., <H6>text</H6> Alinearea textului: <CENTER>text</CENTER> sau ca atribut: <H1 ALIGN=CENTER>text</H1> Trecerea pe linia urmtoare n paragraful curent: <BR> Text afisat asa cum este scris n pagin: <pre>text</pre> Separarea paragrafelor: <P>text</P> sau cu un atribut: <P ALIGN=LEFT> Liste ale cror elementele sunt prefixate de un punct:
<UL> <LI> text <LI> text </UL> <OL> <LI> text introduce o lista introduce un element n list termin lista

Liste ale cror elemente sunt numerotate:


introduce un element n list

90

<LI> text </OL>

termin lista

Linie de separare: <HR>


Tag-ul APPLET
<APPLET [ALT=TEXT] CODE=NUMEAPPLET.CLASS [CODEBASE=URL-UL FIIERULUI .CLASS] HEIGHT=NLIMEA N PIXELI [HSPACE=SPAIUL ORIZONTAL DINTRE APPLET I TEXTUL CARE-L NCONJOAR] WIDTH=LRGIMEA N PIXELI [VSPACE=SPAIUL VERTICAL NTRE APPLET I TEXTUL CARE-L NCONJOAR] [NAME=NUMELE APPLET-ULUI] > [<PARAM NAME=PARAMETRU1 VALUE=VALOARE PARAMETRU1>] [<PARAM NAME=PARAMETRU2 VALUE=VALOARE PARAMETRU2>] </APPLET>

Clasa Applet

Applet-urile sunt programe Java care se pot descarca din internet; aceasta descarcare este realizata de browser; apare intr-o fereastra a broser-ului ca un dreptunghi (panel-panou) in care avem o prezentare grafica cu un fond (background), putem desena caractere de un anumit font si o anumita culoare, precum si alte forme precum dreptunghiuri, linii poligonale, elipse, cercuri. Asadar, un applet are urmatoarele proprietati: - funcioneaza ca parte integrant a unui browser; - prezinta utilizatorului o interfa grafic i poate capta evenimente declanate de utilizatori. Orice applet este un obiect al unei clase definit de utilizator care extinde clasa Applet a pachetului java.applet sau clasa JApplet a pachetului javax.swing. Clasa Applet este un Container (component grafic Java utilizat pentru a include, gestiona i vizualiza alte componente grafice) care utilizeaz metoda paint pentru vizualizarea desenelor i componentelor grafice pe o suprafa dreptunghiular. Exemplu:
import java.awt.*; import java.applet.Applet; public class PrimulApplet extends Applet { public void init(){setBackground(Color.magenta);} public void paint(Graphics g){ g.drawString(Buna ziua!,20,30); } }

n pagina HTML:
<applet name=primul applet" width=100 height="60> </applet> code=PrimulApplet.class codebase=classes"

Cnd ntlnete tag-ul APPLET, browser-ul execut urmtorii pai: 1. Incarc fiierul PrimulApplet.class din directorul classes al directorului curent. 2. Aloc aria n care se vizualizeaz applet-ul. 3. Instaniaz clasa PrimulApplet. 4. Cere executarea metodelor standard implementate n applet: init, paint etc. Structura unui applet:

91

import public public public public public public }

java.applet.Applet; class NumeApplet extends Applet{ void init(){} void start(){} void stop(){} void destroy(){} void paint(Graphics g){}//mostenita din supraclasa Container

Browser 1. Acceseaz pagina care conine un applet

Applet

Cere ncrcarea applet-ului Applet-ul este ncrcat n sistem Pentru a-l iniializa, browser-ul cheam 2. Applet-ul a fost ncrcat n sistem i iniializat Browser-ul cheam

init()

start() applet-ul ruleaz paint()

apoi cheam 3. ... vizualizeaz ntreaga pagin

4. Browser-ul lanseaz pagina i cheam

stop() applet-ul se oprete din rulare

5. Browser-ul revine n pagina applet-ului sau browser-ul elibereaz definitiv pagina coninut 6. ... va fi apelat metoda destroy()

Desenarea cu paint()

- paint(Graphics g), repaint() i update(Graphics g) sunt utilizate pentru desenarea pe un Container, n particular ntr-un applet vizualizat n pagina HTML. n aceste metode trebuie s descriem cum trasm n dreptunghiul applet-ului un text, o linie, un fond de o anumit culoare sau o imagine. - pentru a vizualiza orice lucru avem nevoie s redefinim metoda paint mostenita de clasa Applet din clasa Container:
public void paint(Graphics g){ //cod pentru desenat }

- parametrul g este iniializat cu un obiect al clasei Graphics care este creat i transmis lui paint() de ctre browser. Acest obiectul reprezint contextul grafic al applet-ului. Pentru a putea utiliza metoda paint() trebuie importat clasa Graphics din pachetul java.awt.

92

Metoda paint() va fi apelat automat de ctre browser cnd se deseneaz n applet. Cnd acelai applet trebuie s fie redesenat (de exemplu cnd am schimbat culoarea fondului cu setBackground()), se utilizeaz repaint().
Un applet care deseneaz
import java.applet.Applet; import java.awt.Graphics; import java.awt.Color; public class Dreptunghiuri extends Applet{ public void paint(Graphics g) { g.drawRect (10, 15, 20, 30); g.translate(20, 35); g.setColor(new Color(0, 0, 255)); g.fillRect (10, 15, 40, 65); } }

Graphics

Graphics = Clas abstract, baz pentru toate contextele grafice care aparin unei aplicaii de desenat. Informaiile de stare necesare pentru desenarea n Java sunt: - obiectul Component pe care se deseneaz (un applet, de exemplu); - coordonatele originii translatrii pentru desenat i pentru operaia de clipping; - clip-ul curent; - culoarea curent; - font-ul curent; - funcia logic curent a operaiei n pixeli (XOR sau Paint). Cine furnizeaz obiecte Graphics? Obiectele Graphics sunt ntoarse de metodele getGraphics() existente n clasele Component, Image i PrintJob. Cele mai importante metode ale clasei Graphics sunt prezentate n tabelul urm. Metoda
dispose() getColor() setColor(Color) getFont() setFont(Font) getFontMetrics() getFontMetrics(Font) translate(int, int) draw3DRect(int, int, int, int, boolean) drawArc(int, int, int, int, int, int) drawImage(Image, int, int, Color, ImgObs) drawLine(int, int, int, int) drawOval(int, int, int, int) drawPolygon(int[], int[], int) drawPolyline(int[], int[], int)

Semnificaie Elimin contextul grafic. ntoarce culoarea curent. Seteaz culoarea curent ca fiind culoarea specificat. ntoarce font-ul curent. Seteaz font-ul contextului curent ca fiind font-ul specificat. ntoarce dimensiunile tipului curent de font. ntoarce dimensiunilr tipului de font specificat. Pune originea contextului grafic n punctul (x, y) al sistemului curent de coordonate. Deseneaz un dreptunghi n 3-D. Deseneaz un arc nscris n dreptunghiul specificat. Deseneaz atta ct din imagine specificat este disponibil. Deseneaz o linie ntre dou puncte ale sistemului de coordonate al contextului grafic. Traseaz o elips n interiorul dreptunghiului specificat. Traseaz un poligon definit de doua array-uri de puncte x i y. Traseaz o secven de linii conexe specificate de array-urile de coordonate x si y. Fiecare pereche
93

Metoda

Semnificaie (x[i], y[i]) definete un punct. drawRect(int, int, int, int) Traseaz dreptunghiul specificat. drawRoundRect(int, int, int, int, Traseaz un dreptunghi cu colurile rotunjite int, int) specificate. drawString(String, int, int) Deseneaz irul specificat cu culoarea contextului grafic curent. fill3DRect(int, int, int, int, Coloreaz interiorul dreptunghiului 3D cu culoarea boolean) curent. fillArc(int, int, int, int, int, Umple un sector de cerc continut in dreptunghiul int) specificat cu culoarea curenta. fillOval(int, int, int, int) Umple cu culoarea curent o elips continut n dreptunghiul specificat. fillPolygon(int[], int[], int) Umple cu culoarea curent un poligon definit de dou array-uri de coordonate x i y. fillRect(int, int, int, int) Umple dreptunghiul specificat cu culoarea curent. fillRoundRect(int, int, int, int, Umple dreptunghiul cu coluri rotunde specificat cu int, int) culoarea curent. Shape getClip() ntoarce aria de lucru curent ca un obiect de tip interfata Shape getClipBounds() Intoarce dreptunghiul circumscris ariei de lucru. setClip(int, int, int, int) Seteaz clip-ul curent dreptunghiul specificat cu coordonatele date ca parametri actuali ai metodei.
Color

Color este o clas care reprezint o culoare. Culorile pot fi construite cu constructori ca:
Color Color Color Color (xxx (xxx (int (int r, xxx g, xxx b) r, xxx g, xxx b, xxx alpha) rgb) rgb, boolean hasAlpha) Color.blue, xxx=int sau float

Clasa Color conine cmpuri constante iniializate cu culori fundamentale:


Color.red, Color.yellow, Color.magenta etc Color.cyan,

Color.white,

Color.green,

Font
static Font getFont(String nm)//returneaza un obiect de tip Font cu numele specificat static Font getFont(String nm, Font f) int getSize() int getStyle() boolean isBold() boolean isItalic() boolean isPlain() static final int BOLD=1; static final int ITALIC=2; static final int PLAIN=0;

Exemple de font-uri din JDK 1.4.1: Dialog, SansSerif, Serif, Monospaced, Helvetica, TimesRoman, DialogInput. Dimensiunile sunt specificate n puncte tipografice (1/72):
Font (String nume, int stil, int dim) Font f=new Font(SansSerif,Font.BOLD,12);

Se poate impune unui context grafic un font nou astfel:


void Graphics.setFont(Font f)

Applet pentru ora exact

94

import java.awt.*; import java.util.*; public class Ceas extends java.applet.Applet { private Color beige=new Color(255, 204, 102); private String oraPrec=; public void init() { setBackground(Color.black); } public void paint(Graphics g) { Graphics2D g2D = (Graphics2D) g; Font tip=new Font (Monospaced, Font.BOLD, 20); g2D.setFont(tip); GregorianCalendar azi=new GregorianCalendar(); g2D.setColor(Color.black); g2D.drawString(oraPrec, 5, 25); g2D.setColor(beige); String ora=azi.getTime().toString(); g2D.drawString(ora, 5, 25); try {Thread.sleep(1000); }catch(InterruptedException e){ } oraPrec = ora; repaint(); <html> } <applet code="CeasNou" width=350 } height=50> Applet pentru ora exact cu parametri <param name="fond" value="#996633"> </applet> import java.awt.*; </html> import java.util.*; public class CeasNou extends java.applet.Applet{ private Color beige = new Color(255, 204, 102); private String oraPrec = ; Color culoareFond; public void init() { String in=getParameter(fond); culoareFond=Color.black; if (in != null) { try{ culoareFond=Color.decode(in); }catch(NumberFormatException e) {showStatus(Parametru eronat + in);} } setBackground(Color.black); } public void paint(Graphics g) { Graphics2D g2D=(Graphics2D) g; Font tip=new Font(Monospaced, Font.BOLD, 20); g2D.setFont(tip); GregorianCalendar azi=new GregorianCalendar(); g2D.setColor(culoareFond); g2D.drawString(oraPrec, 5, 25); g2D.setColor(beige); String ora=azi.getTime().toString(); g2D.drawString(ora, 5, 25); try {Thread.sleep(1000); }catch(InterruptedException e) {} oraPrec=ora; repaint(); } }

FontMetrics

95

FontMetrics Component.getFontMetrics(Font) FontMetrics Graphics.getFontMetrics() FontMetrics Graphics.getFontMetrics(Font) FontMetrics Toolkit.getFontMetrics(Font) int charsWidth(char data[],int off,int len) int bytesWidth(byte data[],int off,int len) int charWidth(char ch) int charWidth(int ch) int getAscent() getDescent() getLeading() getHeight() getMaxAscent() getMaxDescent() int stringWidth(String s)

Cum se determin lungimea unui ir pe ecran?


Font f=new Font(SansSerif, Font.BOLD+Font.ITALIC, 12); FontMetrics fm=g.getFontMetrics(f); cx=fm.stringWidth(Un ir lung de 31 de caractere.);

Programarea cu obiecte Font

Exercitiu. Cum s scriem textul: Acesta este un program pentru testarea font-urilor poziionat n mijlocul unui frame utiliznd dou font-uri diferite? Solutia o gasiti n Programul 2. public class TestFont2 extends Frame{ private Font f; private Font fi; private FontMetrics fm; private FontMetrics fim; private boolean fontsSet = false; public void setFonts(Graphics g){ if (fontsSet) return; f=new Font("SansSerif",Font.BOLD, 14); fi=new Font("SansSerif",Font.BOLD + Font.ITALIC,14); fm=g.getFontMetrics(f); fim=g.getFontMetrics(fi); fontsSet = true; } public void paint(Graphics g){ setFonts(g); String s1 = "Acesta este"; String s2 = " un program pentru"; String s3 = " testarea font-urilor."; int w1 = fm.stringWidth(s1); int w2 = fim.stringWidth(s2); int w3 = fm.stringWidth(s3); Dimension d = getSize(); Insets in = getInsets(); int clientWidth=d.width-in.right-in.left; int clientHeight =d.height-in.bottom-in.top; int cx=(clientWidth-w1-w2-w3)/2 + in.left; int cy=clientHeight/2+in.top; g.drawRect(in.left,in.top,clientWidth-1, clientHeight-1); g.setFont(f); g.drawString(s1, cx, cy); cx += w1;
96

g.setFont(fi); g.drawString(s2, cx, cy); cx += w2; g.setFont(f); g.drawString(s3, cx, cy); } public static void main(String args[]){ Frame f = new TestFont2(); f.show(); } }

Programul 2. TestFont2: Utilizarea lui Font i FontMetrics

97

12. INTERFETE GRAFICE


AWT-Abstract Window Toolkit

Serie complet de componente ale interfeei grafice utilizator (GUI) Suport pntru container-e de componente grafice. Fiecare component are ciclul su de via, independent de al altora. Un mecanism de evenimente care gestioneaz evenimentele sistemului i evenimentele utilizatorului. Mecanisme pentru aranjare a componentelor ntr-un mod care permite obinerea unui GUI independent de platform. Gestioneaz ferestrele, menu-urile i ferestrele de dialog. Grafica - Deseneaz figuri n 2D - Controleaz culorile - Controleaz font-urile
Java 2D API

Posibilitatea de grafic mai laborioas - Deseneaz figuri n 2D personalizate - Umple figurile cu culori i modele

Container-e

Ideea fundamental: O fereastr Java este un container care conine o colecie de componente ncuibate. Container-ele sunt gestori ai componentelor coninute. Ierarhia de container-e poate avea orice nivel de complexitate. Frame = Fereastra de nivel cel mai nalt ntr-o aplicaie. Applet = Container de componente grafice care poate fi executat de un browser.
Ierarhia claselor AWT
Object Component

Canvas Container

List Button

TextComponent

CheckBox ScrollBar

Label

Choice

Panel

Window

TextField

TextArea

Applet Frame

Dialog FileDialog

java.awt.Component

java.awt.Component = Clas abstract care generalizeaz toate componentele AWT, exceptnd menu-urile. Unei componente i se asociaz urmtoarele elemente: - un obiect Graphics - localizare - dimensiune - un peer nativ - un container printe - font i dimensiunile font-ului (font metrics)
98

culori pentru foreground i background specific lingvistic dimensiuni maxime i minime

ComponentContainer WindowFrame
java.awt.Component boolean isVisible() <<Interface>> void setVisible(boolean b) ImageObserver boolean isShowing() boolean isEnabled() void setEnabled(boolean b) Font getFont() void setFont(Font f) Font Point getLocation() void setLocation(int x, int y) 1 void setLocation(Point p) +fg, bg Point getLocationOnScreen() Color 2 Graphics getGraphics() void setBackground(Color c) Graphics void setForeground(Color c) 1 Dimension getSize() void setSize(int w, int h) * void setSize(Dimension d) java.awt.Container Component add(Component c) Component add(String name, Component c) Component getComponentAt(int x, int y) Component getComponentAt(Point p) Window Component[] getComponents() LayoutManager getLayout() void setLayout(LayoutManager mgr) Insets getInsets() Frame void paint(Graphics g) void print(Graphics g) java.awt.Window void toFront() void toBack() Toolkit getToolkit() void show() java.awt.Frame void setResizable(boolean b) void setTitle(String s)

<<Interface>> MenuContainer

<<Interface> Serializable

Component vizible : boolean enabled : boolean valid : boolean x : int y : int width : int height : int +peer ComponentPeer

+parinte Container 1 <<Interface>> LayoutManager +panelLayout

Panel

FlowLayout

Applet

Adugarea componentelor grafice


import java.applet.Applet; import java.awt.*;// importa toate clasele AWT public class Primul extends Applet { TextField text;//declara campul de text ca TextField Button buton1, buton2;//declara doua Button public void init(){ text = new TextField(20);//creaza un TextField add(text);//adauga TextField-ul la fereastra buton1=new Button ("Apasa");//creaza un Button add(buton1);//adauga Button-ul la fereastra buton2=new Button("Cancel"); //creaza un Button add(buton2); //adauga Button-ul la fereastra } }

99

TextArea, TextField i Checkbox


import java.applet.Applet; import java.applet.Applet; import java.awt.*; import java.awt.*; public class ContainerX extends Applet{ public class Container2 extends Applet{ //declaratii/alocari de componente TextArea tArea; O arie de text public void init() { //declaratii/alocari de componente public void init() { //adaugarea componentelor in applet tArea=new TextArea(10,20); } add(tArea); } } } import java.applet.Applet; import java.applet.Applet; import java.awt.*; import java.awt.*; public class Container1 extends Applet{ public class Container3 extends Applet{ TextField text1; CheckboxGroup cBG=new CheckboxGroup(); un grup de TextField text2; Checkbox c1, c2: public void init() { public void init() { butoane radio text1=new TextField(20); c1=new Checkbox(Primul,cBG, true); add(text1); add(c1); text2=new TextField(Buna,10); c2=new Checkbox(AlDoilea); add(text2); c2.setCheckboxGroup(cBG); } c2.setState(false); } add(c2); } }

List, Scrollbar, Canvas i Label


import java.applet.Applet; import java.awt.*; public class Container4 extends Applet{ List list1; Lista public void init(){ list1=new List(2, true); list1.addItem(Rosu); list1.addItem(Verde); list1.addItem(Albastru); add(list1); } } import java.applet.Applet; import java.awt.*; public class Container7 extends Applet{ Canvas c; Canvas public void init() { c=new Canvas(); c.resize(40,40); c.setBackground(Color.black); add(c); } } import java.applet.Applet; import java.awt.*; public class Container5 extends Applet { Scrollbar hSB, vSB; Bare de defilare public void init(){ vertical i orizontal hSB=new Scrollbar(Scrollbar.HORIZONTAL,0,1, 1,100); add(hSB); vSB=new Scrollbar(Scrollbar.VERTICAL,0,1,1, 100); add(vSB); } } import java.applet.Applet; import java.awt.*; public class Container6 extends Applet{ Label etic=new Label(Nume si Prenume); text1=new TextField(Ion Pop,20); public void init(){ Etichet add(etic); add(text1); } }

Menu In
Diagrama 1 se prezinta conceptele principale pe care trebuie sa le cunoastem pentru a programa

menu-uri cu java.awt .
MenuComponent MenuBar MenuItem Menu PopupMenu

CheckboxMenuItem

100

Diagrama 2. Ierarhia componentelor de menu

Din Programul 3 se poate vedea care este n esenta modalitatea de programare a menu-urilor.
import java.awt.*; public class MenuFrame extends Frame { MenuItem fileNew=new MenuItem(Nou); MenuItem fileOpen=new MenuItem(Deschide); MenuItem fileSave=new MenuItem(Salveaza); MenuItem fileExit=new MenuItem(Iesire); MenuItem editUndo=new MenuItem(Cancel); MenuItem editCut=new MenuItem(Cut); MenuItem editCopy=new MenuItem(Copy); MenuItem editPaste=new MenuItem(Paste); MenuItem helpContents=new MenuItem(Rezumat); MenuItem helpAbout=new MenuItem(Info...); public MenuFrame() { super(Exemplu de menu); MenuBar menubar=new MenuBar(); Menu fileMenu=new Menu(Fisier); Menu editMenu=new Menu(Modifica); Menu helpMenu=new Menu(?); fileMenu.add(fileNew); fileMenu.add(fileOpen); fileSave.setEnabled(false); fileMenu.add(fileSave); fileMenu.addSeparator(); fileMenu.add(fileExit); editUndo.setEnabled(false); editMenu.add(editUndo); editMenu.addSeparator(); editCut.setEnabled(false); editMenu.add(editCut); editCopy.setEnabled(false); editMenu.add(editCopy); editPaste.setEnabled(false); editMenu.add(editPaste); helpMenu.add(helpContents); helpMenu.addSeparator(); helpMenu.add(helpAbout); menubar.add(fileMenu); menubar.add(editMenu); menubar.add(helpMenu); menubar.setHelpMenu(helpMenu); setMenuBar(menubar); setSize(new Dimension(400,300)); show(); } public static void main(String[] args){ MenuFrame meu=new MenuFrame(); } }

Programul 3. MenuFrame: Programarea menu-urilor Grafica cu LayoutManager

Layout Manager = Interfa utilizat pentru asezarea diferitelor componente ntr-un container dup un ablon de aranjare. LayoutManager2 extinde LayoutManager i este folosit pentru asocierea de constrngeri aezrii componentelor.

101

Cele mai folosite clase de gestori de layout care implementeaz interfaa LayoutManager sunt: FlowLayout, BorderLayout, GridLayout, GridBagLayout, CardLayout. setLayout(new FlowLayout());
AppletViewer: GestoreLayout Applet

setLayout(new BorderLayout());
AppletViewer: GestoreLayout Applet

setLayout(new GridLayout(3,2));
AppletViewer: GestoreLayout Applet

North W e s t Center South E a s t

Clasa GridBagLayout este un gestor flexibil care aliniaz componentele pe vertical i orizontal, fr s fie nevoie ca componetele s aib aceleai dimensiuni. Fiecare obiect GridBagLayout pstreaz o gril dreptunghiular dinamic de celule n care fiecare component ocup una sau mai multe celule, care formeaz aria de vizualizare a componentei. Exemplu.
import java.awt.*; public class FacturaFrame extends Frame {Button print, cancel,printF,arhivare; TextArea arie; Panel panel; private Factura factura; private GridBagLayout gb; private GridBagConstraints gbc; public FacturaFrame(Factura f) {super("Factura"); factura=f; gb=new GridBagLayout(); gbc=new GridBagConstraints(); gbc.fill=GridBagConstraints.HORIZONTAL; gbc.anchor=GridBagConstraints.NORTH; panel=new Panel(); panel.setLayout(gb); arie=new TextArea(factura.toString(),20, 50); arie.setEditable(false); addComponent(arie,0,0,1,5); print=new Button("Print"); addComponent(print,1,1,1,1); printF=new Button("PrintToFile"); addComponent(printF,2,1,1,1); arhivare=new Button("Arhivare"); addComponent(arhivare,3,1,1,1); cancel=new Button("Cancel"); addComponent(cancel,4,1,1,1);

CardLayout aeaz componentele (de obicei paneluri) n straturi, precum crile ntr-un pachet de crti. n orice moment, este vizibil numai o component, dar componentele pot fi rsfoite i s controlm care din ele s devin vizibil. Acest layout este util cn o aceeai suprafa trebuie partajat de mai multe paneluri care trebuie s fie vizualizate n momente diferite de timp.

102

add(panel); } void addComponent(Component c, int linie,int col, int lat, int inal) { gbc.gridx=col; gbc.gridy=linie; gbc.gridwidth=lat; gbc.gridheight=inal; gb.setConstraints(c,gbc); panel.add(c); } public static void main(String[] args){ Vanzare v=new Vanzare(new Client("Ionescu", "Pop", "alea rozelor")); v.addProdus(new ElementVanzare(new SpecificatieProdus("mousepad", 11), 2)); v.addProdus(new ElementVanzare(new SpecificatieProdus("mouse", 50), 3)); Frame f=new FacturaFrame(new Factura(v)); f.setSize(480, 400); f.setVisible(true);}}

103

13. EVENIMENTE
class Controller implements ActionListener{ private PrintWriter out; public void actionPerformed(ActionEvent e){ if (e.getSource()==print){ PrinterJob imprimanta=PrinterJob.getPrinterJob(); Book bk=new Book(); bk.append(new ContinutPanel(), imprimanta.defaultPage()); imprimanta.setPageable(bk); if(imprimanta.printDialog()){ try{imprimanta.print();} catch (PrinterException pe){arie.append("Imprimanta nu exista");arie.repaint();} catch(ArrayIndexOutOfBoundsException ae){System.out.println("Ce se printeaza???");} } } else if (e.getSource()==printF){ try{ out=new PrintWriter(new FileOutputStream("factura.dat")); out.write(factura.toString()); out.flush(); out.close(); }catch(FileNotFoundException fe){} catch(IOException ioe){} } else if (e.getSource()==arhivare){ facturi.adaugaFactura(factura); } else if (e.getSource()==cancel) setVisible(false);} } class ContinutPanel extends Panel implements Printable { private BufferedReader br; private String sir=""; public int print(Graphics g, PageFormat pf,int pageIndex) throws PrinterException{ g.setColor(Color.black); try{ StringReader continut=new StringReader(arie.getText()); br=new BufferedReader(continut); int i=0; while((sir=br.readLine())!=null) { if (sir.length()==0) sir=" "; g.drawString(sir,100,100+i);i+= 20; } }catch(IOException io){} catch (IllegalArgumentException ie){} return Printable.PAGE_EXISTS; } }

104

14.

PROGRAMAREA INTERFETELOR GRAFICE CU SWING

Swing este un tehnologie API care extinde AWT-ul pentru construirea interfetelor grafice. Swing este o multime de componente usoare aflate in pachetul javax.swing.*. Spre deosebire de componentele grele nu sunt incadrate intr-o fereastra (window) proprie, opaca, nativa (1), ci in fereastra container-ului lor greu (2). Din (1) rezulta ca, componentele usoare pot avea background-uri transparente. Aproape toate componentele Swing-ului sunt usoare; exceptiile sunt container-ele de nivel inalt: - JFrame implementeaza o fereastra principala, - JApplet- implementeaza o arie dreptunghiulara in fereastra browser-ului - JWindow o fereastra externa, - JDialog implementeaza o fereastra secundara Din (2) rezulta ca componentele usoare trebuie sa stea in ultima instanta intr-un container greu, adica o subclasa a clasei java.awt.Container.
JFrame
public class Fereastra extends JFrame{ public Fereastra(){ Container container=getContentPane(); JPanel panel=new JPanel(); panel.add(new JButton(Buton)); panel.add(new JLabel(Label)); container.add(panel, BorderLayout.NORTH); } }

Content pane

JPanel

JButton

JLabel

Container-e usoare: 1. JPanel succesorul lui Panel si Canvas. De aceea, are un rol dublu: este un simplu container si un canvas pentru afisarea graficelor. 2. JRootPane este continut in orice container greu. - furnizeaza o ierarhizare a continutului: Panel radacina stratPanel continutPanel menuBar sticlaPanel
Componenta stratPanel continutPanel menuBar sticlaPanel Clasa Descriere

JLayeredPane contine continutPanel si menuBar JPanel contine componentele aplicatiei sau applet JMenuBar sta deasupra lui continutPanel JPanel capteaza evenimentele mouse-ului si poate fi transparent

105

Exemplu. Sa se scrie un program care contine un buton care determina afisarea/ascunderea unui panel de sticla ce afiseaza textul Buna ziua pe toata suprafata sa.
import javax.swing.*; import java.awt.event.*; import java.awt.*; public class Prob1 extends ActionListener { private Component panelSticla; private JButton buton; public Prob1(){ panelSticla=new PanelSticla(); setGlassPane(panelSticla); buton=new JButton("", new ImageIcon("swing.small.gif")); buton.addActionListener(this); Container content=getContentPane(); content.add(buton); } public void actionPerformed(ActionEvent e){ panelSticla.setVisible(true); } public static void main(String[] arg){ JFrame f=new Prob1(); f.setSize(200,200); f.setVisible(true); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); }} JFrame implements class PanelSticla extends JPanel{ public PanelSticla(){ setOpaque(false); addMouseListener(new MouseAdapter(){ public void mousePressed(MouseEvent e){ setVisible(false); }}); } public void paintComponent(Graphics g){ String sir="Buna ziua"; Dimension d= getSize(); FontMetrics f=g.getFontMetrics(); int l=f.stringWidth(sir); int i=f.getHeight(); g.setColor(Color.blue); for (int li=i; li<d.height; li+=i) for (int c=0; c<d.width; c+=l) g.drawString(sir, c, li); } }

3. JLayeredPane nu are un layout manager implicit si permite plasarea componentelor pe diferite straturi: Strat Valoare Descriere FRAME_CONTENT_LAYER -3000 Stratul de baza, unde bar menu-ul si content pane sunt asezate DEFAULT_LAYER 0 Implicit, pe acest strat sunt plasate componentele PALETTE_LAYER 100 Folosit pentru palete si toolbar-uri MODAL_LAYER 200 Folosit de catre ferestrele de dialog POPUP_LAYER 300 Pentru menu-urile popup DRAG_LAYER 400 Util in deplasarea componentelor sau a celor care trebuie sa stea deasupra tuturor celorlalt Obs. Straturile cu valori mai mari sunt plasate deasupra straturilor cu valori mai mici. Plasarea componentelor poate fi controlata si in cadrul unui acelasi strat prin urmatoarele

106

proprietati: Proprietate Index -getIndexOf(comp) Strat -getLayer(comp) Pozitie -getPosition(comp) Exemplu2.


import javax.swing.*; import java.awt.event.*;

Descriere Indexul intr-un vector de componente pastrat de panelul stratificat. Indicele are legatura cu ordinea componentelor: cele cu indice mai mic sunt plasate deasupra celor cu indice mai mare. Stratul pe care se afla componenta respectiva. Componentele de pe un strat cu numar mai mic sunt afisate sub componentele ce se afla pe straturi cu numar mai mare. Pozitia unei componente relativa la celelalte componente din acelasi strat. Componentele cu pozitii mai mici sunt afisate deasupra celor cu pozitii mai mari.

public Prob2(){ lp=new JLayeredPane(); setContentPane(lp); for(int i=0; i<butoane.length; i++){ lp.setLayer(butoane[i], straturi[i].intValue()); lp.add(butoane[i]); } for(int i=0; i<butoane.length; i++){ String sir=butoane[i].getText(); if (sir.equals("Default0")) lp.setPosition(butoane[i], 1); else if (sir.equals("Default1")) lp.setPosition(butoane[i], 0); sir=butoane[i].getText()+"-"+lp.getPosition(butoane[i]); butoane[i].setText(sir); butoane[i].setBounds(i*50, i*50, 350, 75); } } public static void main(String[] arg){ JFrame f=new Prob2(); f.setSize(600,480); f.setVisible(true); f.addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e){System.exit(0);}});}}

public class Prob2 extends JFrame{ private JLayeredPane lp; private Integer[] straturi={ JLayeredPane.FRAME_CONTENT_LAYER, JLayeredPane.DEFAULT_LAYER, JLayeredPane.DEFAULT_LAYER, JLayeredPane.PALETTE_LAYER, JLayeredPane.MODAL_LAYER, JLayeredPane.POPUP_LAYER, JLayeredPane.DRAG_LAYER }; private JButton[] butoane={ new JButton("Frame content"), new JButton("Default0"), new JButton("Default1"), new JButton("Palette"), new JButton("Modal"), new JButton("Popup"), new JButton("Drag") };

4. JTabbedPane panel ce contine pagini (tab-uri) de paneluri. Exemplu3. Fereastra cu 2 pagini de panel-uri de contin cate un buton.
import javax.swing.*; import java.awt.event.*; import java.awt.*; public class Prob3 extends JFrame{ private JTabbedPane tp; public Prob3(){ tp=new JTabbedPane(); JPanel panel1=new JPanel(); panel1.add(new JButton("buton in panelul 1")); JPanel panel2=new JPanel(); panel2.add(new JButton("buton in panelul 2")); tp.add(panel1, "Primul panel"); tp.addTab("Al doilea panel", "Panelul 2"); new ImageIcon("ok.gif"), panel2,

Container contentPane=getContentPane(); contentPane.add(tp);

107

5. JSplitPane afiseaza doua componente (initial, butoane) separate de un despartitor (divider). Componentele pot fi orientate vertical sau orizontal (JSplitPane.HORIZONTAL_SPLIT sau VERTICAL_SPLIT). Metoda: setOrientation(constanta). Panelul foloseste doua proprietati booleene: - layout continuu controleaza daca componentele continute sunt incontinuu actualizate in timp ce separatorul este deplasat. Metoda: setContinuousLayout(boolean) - redimensionare la comanda (one-touch expandable) determina daca afiseaza un control in separator. Controlul permite marirea sau micsorarea componentelor cand este click-at. Metoda: setOneTouchExpandable(boolean) Exemplu 4.
public class Prob4 extends JFrame{ private JSplitPane sp; public Prob4(){ sp=new JSplitPane(); sp.setContinuousLayout(true); //sp.setOneTouchExpandable(true); sp.setDividerSize(15); sp.setOrientation(JSplitPane.HORIZONTAL_SPLIT); Container contentPane=getContentPane(); contentPane.add(sp); }

108

FERESTRE INTERNE

Swing ofera functionalitate MDI (Multiple Documente Interface) prin ferestre interne- clasa JInternalFrame, care stau pe desktop -clasa JDesktopPane. Ferestrele interne sunt: - ferestre deoarece furnizeaza multe din caracteristicile unei ferestre (inchidere, deschidere, maximizare, minimizare, iconificare, redimensionare), - interne deoarece stau, fiind componente usoare, intr-un alt container Swing, de obicei un desktop pane. Proprietati: Nume Proprietate Tip de data Acc Valoarea Descriere es implicita closable boolean C3S false Indica daca fereastra interna poate 1 G fi inchisa de catre utilizator closed boolean SG false indica daca fereastra este inchisa la momentul respectiv contentPane Container SG instanta de JPanel container-ul ce contine componentele din fereastra defaultCloseOper int SG WindowConstant indica operatia care are loc cand fereastra este inchisa ation s.HIDE_ON_CL OSE desktopIcon JDesktopIcon SG L&F Icon-ul afisat pe desktop cand fereastra este redusa la icon desktopPane JDesktopPan G O instanta a lui JDesktopPane ce e contine una sau mai multe ferestre interne frameIcon Icon SG L&F Icon-ul afisat in bara de titlu al ferestrei glassPane Component SG instanta JPanel Panelul de sticla asociat cu panelul radacina al unei ferestre interne icon boolean SG false Determina daca fereastra interna este (poate fi) redusa la icon setIcon(boolean) iconifiable boolean C5S false Determina daca fereastra interna G poate fi redusa la un icon prin apelul metodei setIcon(boolean) layer Integer SG DEFAULT_LAY Stratul pe care sta fereastra interna. ER Implicit este DEFAULT_LAYER layeredPane JLayeredPan SG JLayeredPane Panelul stratificat asociat panelului e radacina al ferestrei interne maximizable boolean C4S false Indica daca fereastra poate fi G maximizata printr-un clic pe butonul corespunzator maximum boolean SG false Determina daca fereastra este maximizata jMenuBar JMenuBar SG null Bara de menu asociata panelului radacina al ferestrei interne resizable boolean C2S false Determina daca fereastra poate fi G redimensionata. Daca este maximizata nu poate fi redimensionata rootPane JRootPane SG JRootPane Panelul radacina asociat ferestrei
1

C-poate apare in constructor, S-setter, G-getter

109

selected

Selecteaza sau deselecteaza fereastra interna title String C1S null Titlul afisat in bara de titlu al G ferestrei Exemplul 1. Sa cream o fereastra care la actiunea unui buton vor fi create ferestre interne (ce vor contine o eticheta)
public class Prob1 extends JFrame implements ActionListener{ private JDesktopPane dp; private JInternalFrame fi; private JButton buton; public Prob1(){ Container contentPane=getContentPane(); buton=new JButton("creaza Frame"); buton.addActionListener(this); contentPane.add(buton, BorderLayout.NORTH); dp=new JDesktopPane(); dp.setLayout(new FlowLayout()); contentPane.add(dp, BorderLayout.CENTER); } public void actionPerformed(ActionEvent e){ fi=new JInternalFrame("O noua fereastra interna", true,true, true, true); fi.setPreferredSize(new Dimension(250,150)); //fi.setFrameIcon(new ImageIcon("ok.gif")); /*Container content=fi.getContentPane(); JPanel p=new JPanel(); p.add(new JLabel(new ImageIcon("swing.small.gif"))); content.add(p);*/ dp.add(fi); fi.setVisible(true); dp.revalidate();}

boolean

SG

false

Scroll-area componentelor Este necesara in cazul in care o componenta (tabele, texte, trees, imagini, liste) este mai mare decat spatiul de afisare. Pentru aceasta putem folosi urmatoarele clase: - container-ele usoare JViewport si JScrollPane (inlocuieste si imbogateste componenta grea AWT ScrollPane) - interfata Scrollable - JScrollBar folosit pentru implementarea manuala a barelor de scroll-are
CLASA JVIEWPORT

instantele sale furnizeaza un obiectiv (porthole) prin care se afiseaza o anumita regiune a vederii. Pozitia vederii poate fi manevrata pentru a afisa regiuni diferite ale vederii astfel: - pentru a muta vederea in sus: crestem coordonata Y a vederii - pentru a muta vederea in jos: descrestem coordonata Y a vederii - pentru a muta vederea la stanga: crestem coordonata X a vederii - pentru a muta vederea la dreapta: descrestem coordonata X a vederii Proprietati Nume Proprietate Tip de Acc Valoarea Descriere data es implicita scrollMode int SG SIMPLE moduri de a realiza scroll-area: _SCROL BLIT_SCROLL_MODE, L_MOD BACKINGSTORE_SCROLL_MODE, SIMPLE_SCROLL_MODE E extentSize Dimension SG Este o instanta a clasei Dimension care reprezinta partea vizibila a vederii view Componen SG Componenta afisata in viewport
110

Este un punct ce reprezinta coordonatele vederii din coltul stanga sus al obiectivului viewRect Rectangle G O instanta a lui Rectangle care reprezinta dimensiunea si pozitia partii vizibile a vederii. Latimea si inaltimea dreptunghiului sunt egale cu extent viewSize Dimension SG O instanta a lui Dimension care reprezinta dimensiunea vederii. Daca nu este setata explicit, este egala cu dimensiunea preferred a vederii Exemplul 3. Sa se creeze o fereastra care afiseaza o imagine si o deplaseaza cu ajutorul a patru butoane: sus, jos, stanga, dreapta . Exemplul 4. (glisarea unei imagini)
public class Prob3 extends JFrame implements ActionListener{ public class Prob4 extends JFrame { private JViewport obiectiv; private JViewport obiectiv; private DragListener listener; private JButton sus, jos, stanga, dreapta; public Prob4(){ public Prob3(){ Container contentPane=getContentPane(); Container contentPane=getContentPane(); JPanel p=new JPanel(); JPanel p=new JPanel(); obiectiv=new JViewport(); sus=new JButton("Sus"); sus.addActionListener(this); obiectiv.setScrollMode(JViewport.BACKINGSTORE_SCROLL_MOD p.add(sus); E); //BLIT_SCROLL_MODE jos=new JButton("Jos"); p.add(new JLabel(new ImageIcon("setup.gif"))); jos.addActionListener(this); obiectiv.setView(p); p.add(jos); listener=new DragListener(obiectiv); obiectiv.addMouseListener(listener); stanga=new JButton("Stanga"); obiectiv.addMouseMotionListener(listener); stanga.addActionListener(this); contentPane.add(obiectiv, BorderLayout.CENTER); p.add(stanga); } //main dreapta=new JButton("Dreapta"); dreapta.addActionListener(this); class DragListener extends MouseAdapter implements p.add(dreapta); MouseMotionListener{ contentPane.add(p, BorderLayout.NORTH); private JViewport v; private Point ultim, nou; obiectiv=new JViewport(); JPanel p1=new JPanel(); public DragListener(JViewport o){ p1.add(new JLabel(new ImageIcon("setup.gif"))); v=o; obiectiv.setView(p1); ultim=new Point(); //obiectiv.add(new JLabel(new ImageIcon("setup.gif"))); nou=new Point(); contentPane.add(obiectiv, BorderLayout.CENTER); } } public void mousePressed(MouseEvent e){ public void actionPerformed(ActionEvent e){ ultim.x=e.getPoint().x; Point punct=obiectiv.getViewPosition(); ultim.y=e.getPoint().y; } if (e.getSource()==sus){punct.y+=5;} public void mouseDragged(MouseEvent e){ if (e.getSource()==jos){punct.y-=5;} Point drag=e.getPoint(); if (e.getSource()==stanga){punct.x+=5;} Point dist=new Point(drag.x-ultim.x, drag.y-ultim.y); if (e.getSource()==dreapta){punct.x-=5;} ultim.x=drag.x; obiectiv.setViewPosition(punct);} ultim.y=drag.y; Point pozViewport=v.getViewPosition(); if(v.contains(drag)){ nou.x=pozViewport.x-dist.x; nou.y=pozViewport.y-dist.y; v.setViewPosition(nou); }}

viewPosition

t Point

SG

111

JSCROLLPANE

- container uor ce contine un viewport cu scrollbar-uri si header-e de coloane si linie optionale. Elementele unui JScrollPane: Proprietati

Nume Proprietate columnHeader

Tip de data JViewport

Acc es SG S SG

Valoarea implicita null null null

Descriere o instanta a lui JViewport pentru header-ul de coloane o instanta a lui Component folosita ca header de coloane pentru vederea viewport-ului o componenta care este afisata in unul din cele patru colturi: ScrollPaneConstants.UPPER_LEFT_CORNE R ScrollPaneConstants.LOWER_LEFT_CORN ER ScrollPaneConstants.UPPER_RIGHT_CORN ER ScrollPaneConstants.LOWER_RIGHT_COR NER Scrollbar-ul orizontal folosit de panel Politica folosita pentru detrminaea circumstantelor in care scrollbar-ul orizontal este afisat. Constante: ScrollPaneConstants.HORIZONTAL_SCRO LLBAR_AS_NEEDED ScrollPaneConstants.HORIZONTAL_SCRO LLBAR_NEVER ScrollPaneConstants.HORIZONTAL_SCRO LLBAR_ALWAYS o instanta a lui JViewport pentru header-ul de linii o instanta a lui Component folosita ca header de linii pentru vederea viewport-ului

columnHeaderVie Component w corner Component

horizontalScrollb ar horizontalScrollb arPolicy

JScrollBar int

SG CSG

JScrollPa ne.HORI ZONTA L_SCRO LLBAR_ AS_NEE DED null null

rowHeader rowHeaderView verticalScrollbar verticalScrollbarP olicy

JViewport Component JScrollBar int

SG G SG CSG

JScrollPa ScrollPaneConstants.VERTICAL_SCROLLB ne.HORI AR_AS_NEEDED ZONTA ScrollPaneConstants.VERTICAL_SCROLLB


112

viewport viewportBorder viewportView Exemplul 5.

JViewport Border Component

SG SG CSG

L_SCRO LLBAR_ AS_NEE DED JViewpo rt null null

AR_NEVER ScrollPaneConstants.VERTICAL_SCROLLB AR_ALWAYS O instanta a lui JViewport folosita pentru afisarea componentei scroll-ata de panel O bordura pentru viewport componenta afisata in viewport-ul panelului

public Prob5(){ //prob 4 modificata Container contentPane=getContentPane(); JPanel p=new JPanel(); obiectiv=new JViewport(); obiectiv.setScrollMode(JViewport.BACKINGSTORE_SCROLL_MODE); p.add(new JLabel(new ImageIcon("setup.gif"))); obiectiv.setView(p); sp=new JScrollPane(obiectiv); sp.setColumnHeaderView(new JLabel(new ImageIcon("sus.gif"))); sp.setCorner(ScrollPaneConstants.UPPER_RIGHT_CORNER, new JLabel(new ImageIcon("palette_hand.gif"))); listener=new DragListener(obiectiv); obiectiv.addMouseListener(listener); obiectiv.addMouseMotionListener(listener); contentPane.add(sp, BorderLayout.CENTER); }

Borduri - pachetul javax.swing.border.* Toate componentele (de tip JComponent) cu exceptia lui JViewport, pot fi incadrate cu o bordura prin executarea a doi pasi: - construim tipul de bordura dorit, - il transmitem cu metoda JComponent.setBorder(Border) Tipuri de bordura Tip de bordura Descriere Opaca Constante asociate Bevel O Bordura 3D da RAISED, LOWERED Compound contine o burdura variaza interioara si una exterioara Empty O bordura nu transparenta Etched bordura formata da dintr-o linie colorata a carei grosime poate fi setata Matte O bordura ce da afiseaza o culoare solida sau incadreaza o imagine cu margini SoftBevel nu RAISED, LOWERED Titled O bordura cu nu DEFAULT_POSITION, titlu. Pozitia ABOVE_TOP, TOP,
113

titlului poate fi setata

BELOW_TOP, ABOVE_BOTTOM, BOTTOM, BELLOW_BOTTOM, DEFAULT_JUSTIFICATION, LEFT, CENTER, RIGHT

Ierarhia claselor Border


<<Interface>>

Border

AbstractBorder

BevelBorder

CompoundBorder

EmptyBorder

EtchedBorder

MatteBorder

LineBorder

TitledBorder

114

Exemplul 6.
import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.border.*; public class Prob6 extends JPanel { static JPanel showBorder(Border b) { JPanel jp = new JPanel(); jp.setLayout(new BorderLayout()); String nm = b.getClass().toString(); nm=nm.substring(nm.lastIndexOf(".")+1); jp.add(new JLabel( nm, JLabel.CENTER), BorderLayout.CENTER); jp.setBorder(b); return jp; } public Prob6() { setLayout(new GridLayout(2, 4)); add(showBorder(new TitledBorder("Titlul meu"))); add(showBorder(new EtchedBorder())); add(showBorder(new LineBorder(Color.blue))); add(showBorder(new MatteBorder(5,5,30,30,Color.magenta))); add(showBorder(new BevelBorder(BevelBorder.RAISED))); add(showBorder(new SoftBevelBorder(BevelBorder.LOWERED))); add(showBorder(new CompoundBorder( new EtchedBorder(), new LineBorder(Color.red)))); } public static void main(String args[]) { JPanel p=new Prob6(); JFrame f=new JFrame(); f.getContentPane().add(p); f.setSize(300,300); f.setVisible(true); f.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); }}

Clasa BorderFactory - este in pachetul javax.swing.* - contine metode statice de construire a bordurilor ce vor fi partajate de componente, deci utilizarea este mai eficienta. De exp: Border b1=BorderFactory.createRaisedBevelBorder(); Border b2=BorderFactory.createRaisedBevelBorder(); atunci conditia (b1= =b2) intoarce true.

115

15. BIBLIOGRAFIE
I. Athanasiu si colectiv, Limbajul Java. O perspectiv pragmatic. Editura Teora, 1998 B. Eckel, Thinking in Java. Prentice Hall, 1998 C. S. Horstmann, Computing Concepts with Java 2 Essentials, Second Edition. John Wiley&Sons, 2000 L. D. Serbnai, C. Bogdan, Programare orientat spe obiecte (Limbajul Java), note de curs, 2006 S. Tnas, C. Olaru, S. Andrei, Java de la 0 la expert. Editura Polirom, 2003

116

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